From 1302a37c91dd9c8fe5d308125f77f2540b7bc4f9 Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Sat, 5 Dec 2009 14:56:47 +0000 Subject: [PATCH] improve date handling, handle more binary/character input types git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@420 f203690c-595d-4dc9-a70b-905162fa7fd2 --- src/changes/changes.xml | 9 ++ .../healthmarketscience/jackcess/Column.java | 104 ++++++++++++++++-- 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3865030..0760dc4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -4,6 +4,15 @@ Tim McCune + + + Further improvements to date handling. + + + Handler more binary/character input types (Blob, Clob, InputStream, + Reader), based on user submitted patch. + + Add support for updating GUID indexes and for auto-number GUID diff --git a/src/java/com/healthmarketscience/jackcess/Column.java b/src/java/com/healthmarketscience/jackcess/Column.java index 35cab9b..2290ebb 100644 --- a/src/java/com/healthmarketscience/jackcess/Column.java +++ b/src/java/com/healthmarketscience/jackcess/Column.java @@ -27,14 +27,20 @@ King of Prussia, PA 19406 package com.healthmarketscience.jackcess; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectOutputStream; import java.io.ObjectStreamException; +import java.io.Reader; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; +import java.sql.Blob; +import java.sql.Clob; import java.sql.SQLException; import java.util.Calendar; import java.util.Date; @@ -719,13 +725,21 @@ public class Column implements Comparable { // seems access stores dates in the local timezone. guess you just hope // you read it in the same timezone in which it was written! long dateBits = buffer.getLong(); - long time = (long)(Double.longBitsToDouble(dateBits) - * MILLISECONDS_PER_DAY); - time -= MILLIS_BETWEEN_EPOCH_AND_1900; - time -= getTimeZoneOffset(time); + long time = fromDateDouble(Double.longBitsToDouble(dateBits)); return new DateExt(time, dateBits); } + /** + * Returns a java long time value converted from an access date double. + */ + private static long fromDateDouble(double value) + { + long time = Math.round(value * MILLISECONDS_PER_DAY); + time -= MILLIS_BETWEEN_EPOCH_AND_1900; + time -= getTimeZoneOffset(time); + return time; + } + /** * Writes a date value. */ @@ -741,16 +755,26 @@ public class Column implements Comparable { } else { + buffer.putDouble(toDateDouble(value)); + } + } + + /** + * Returns an access date double converted from a java Date/Calendar/Number + * time value. + */ + private static double toDateDouble(Object value) + { // seems access stores dates in the local timezone. guess you just // hope you read it in the same timezone in which it was written! long time = ((value instanceof Date) ? ((Date)value).getTime() : - ((Number)value).longValue()); + ((value instanceof Calendar) ? + ((Calendar)value).getTimeInMillis() : + ((Number)value).longValue())); time += getTimeZoneOffset(time); time += MILLIS_BETWEEN_EPOCH_AND_1900; - double dTime = time / MILLISECONDS_PER_DAY; - buffer.putDouble(dTime); - } + return time / MILLISECONDS_PER_DAY; } /** @@ -1069,7 +1093,7 @@ public class Column implements Comparable { getType()); } - ByteBuffer buffer = ByteBuffer.wrap((byte[])obj); + ByteBuffer buffer = ByteBuffer.wrap(toByteArray(obj)); buffer.order(order); return buffer; } @@ -1089,7 +1113,7 @@ public class Column implements Comparable { } // create long value buffer - return writeLongValue((byte[]) obj, remainingRowLength); + return writeLongValue(toByteArray(obj), remainingRowLength); } /** @@ -1153,7 +1177,7 @@ public class Column implements Comparable { case BINARY: case UNKNOWN_0D: case UNKNOWN_11: - byte[] bytes = (byte[])obj; + byte[] bytes = toByteArray(obj); if(bytes.length != getLength()) { throw new IOException("Invalid fixed size binary data, size " + getLength() + ", got " + bytes.length); @@ -1439,15 +1463,73 @@ public class Column implements Comparable { * @return an appropriate CharSequence representation of the given object. */ public static CharSequence toCharSequence(Object value) + throws IOException { if(value == null) { return null; } else if(value instanceof CharSequence) { return (CharSequence)value; + } else if(value instanceof Clob) { + try { + Clob c = (Clob)value; + // note, start pos is 1-based + return c.getSubString(1L, (int)c.length()); + } catch(SQLException e) { + throw (IOException)(new IOException(e.getMessage())).initCause(e); + } + } else if(value instanceof Reader) { + char[] buf = new char[8 * 1024]; + StringBuilder sout = new StringBuilder(); + Reader in = (Reader)value; + int read = 0; + while((read = in.read(buf)) != -1) { + sout.append(buf, 0, read); + } + return sout; } + return value.toString(); } + /** + * @return an appropriate byte[] representation of the given object. + */ + public static byte[] toByteArray(Object value) + throws IOException + { + if(value == null) { + return null; + } else if(value instanceof byte[]) { + return (byte[])value; + } else if(value instanceof Blob) { + try { + Blob b = (Blob)value; + // note, start pos is 1-based + return b.getBytes(1L, (int)b.length()); + } catch(SQLException e) { + throw (IOException)(new IOException(e.getMessage())).initCause(e); + } + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + if(value instanceof InputStream) { + byte[] buf = new byte[8 * 1024]; + InputStream in = (InputStream)value; + int read = 0; + while((read = in.read(buf)) != -1) { + bout.write(buf, 0, read); + } + } else { + // if all else fails, serialize it + ObjectOutputStream oos = new ObjectOutputStream(bout); + oos.writeObject(value); + oos.close(); + } + + return bout.toByteArray(); + } + /** * Interpret a boolean value (null == false) */ -- 2.39.5