]> source.dussan.org Git - jackcess.git/commitdiff
improve date handling, handle more binary/character input types
authorJames Ahlborn <jtahlborn@yahoo.com>
Sat, 5 Dec 2009 14:56:47 +0000 (14:56 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Sat, 5 Dec 2009 14:56:47 +0000 (14:56 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@420 f203690c-595d-4dc9-a70b-905162fa7fd2

src/changes/changes.xml
src/java/com/healthmarketscience/jackcess/Column.java

index 3865030b89e2d1fecf3d4dfc008940be654786c5..0760dc499b67e959c1cdd19cb0ebdb7d9b91320a 100644 (file)
@@ -4,6 +4,15 @@
     <author email="javajedi@users.sf.net">Tim McCune</author>
   </properties>
   <body>
+    <release version="1.1.21" date="TBD">
+      <action dev="jahlborn" type="fix" issue="2899605">
+        Further improvements to date handling.
+      </action>
+      <action dev="jahlborn" type="update">
+        Handler more binary/character input types (Blob, Clob, InputStream,
+        Reader), based on user submitted patch.
+      </action>
+    </release>
     <release version="1.1.20" date="2009-11-18">
       <action dev="jahlborn" type="fix" issue="2884599">
         Add support for updating GUID indexes and for auto-number GUID
index 35cab9b50041b23e1d91c0ae139c5eccb1413c4e..2290ebbf99b69b167b35cb1c702936f15ab197d8 100644 (file)
@@ -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<Column> {
     // 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<Column> {
       
     } 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<Column> {
                                    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<Column> {
     }    
 
     // create long value buffer
-    return writeLongValue((byte[]) obj, remainingRowLength);
+    return writeLongValue(toByteArray(obj), remainingRowLength);
   }
 
   /**
@@ -1153,7 +1177,7 @@ public class Column implements Comparable<Column> {
     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<Column> {
    * @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)
    */