]> source.dussan.org Git - jackcess.git/commitdiff
first attempt at reading with deleted columns
authorJames Ahlborn <jtahlborn@yahoo.com>
Mon, 24 Jul 2006 18:57:11 +0000 (18:57 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Mon, 24 Jul 2006 18:57:11 +0000 (18:57 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@67 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/Column.java
src/java/com/healthmarketscience/jackcess/JetFormat.java
src/java/com/healthmarketscience/jackcess/Table.java
test/data/delColTest.mdb [new file with mode: 0644]
test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java

index 4db8b8022031c2db01389281f95dbfdb7be9da7b..cb6619c247c79e215bc6061ba585a5f9a510122b 100644 (file)
@@ -97,6 +97,10 @@ public class Column implements Comparable<Column> {
   private short _columnNumber;
   /** Column name */
   private String _name;
+  /** the offset of the fixed data in the row */
+  private int _fixedDataOffset;
+  /** the index of the variable length data in the var len offset table */
+  private int _varLenTableIndex;
   
   public Column() {
     this(JetFormat.VERSION_4);
@@ -131,6 +135,12 @@ public class Column implements Comparable<Column> {
         & 1) != 1);
     _compressedUnicode = ((buffer.get(offset +
         format.OFFSET_COLUMN_COMPRESSED_UNICODE) & 1) == 1);
+
+    if(_variableLength) {
+      _varLenTableIndex = buffer.getShort(offset + format.OFFSET_COLUMN_VARIABLE_TABLE_INDEX);
+    } else {
+      _fixedDataOffset = buffer.getShort(offset + format.OFFSET_COLUMN_FIXED_DATA_OFFSET);
+    }
   }
   
   public String getName() {
@@ -189,6 +199,14 @@ public class Column implements Comparable<Column> {
   public short getLength() {
     return _columnLength;
   }
+
+  public int getVarLenTableIndex() {
+    return _varLenTableIndex;
+  }
+
+  public int getFixedDataOffset() {
+    return _fixedDataOffset;
+  }
   
   /**
    * Deserialize a raw byte value for this column into an Object
index 9ddf4a235c8c6384eb815e15150fcf33bc52361f..dc127b1f972ac52f371452af2dc94ccd64f8d092 100644 (file)
@@ -82,6 +82,8 @@ public abstract class JetFormat {
   public final int OFFSET_COLUMN_VARIABLE;
   public final int OFFSET_COLUMN_COMPRESSED_UNICODE;
   public final int OFFSET_COLUMN_LENGTH;
+  public final int OFFSET_COLUMN_VARIABLE_TABLE_INDEX;
+  public final int OFFSET_COLUMN_FIXED_DATA_OFFSET;
   
   public final int OFFSET_TABLE_DEF_LOCATION;
   public final int OFFSET_NUM_ROWS_ON_PAGE;
@@ -163,6 +165,8 @@ public abstract class JetFormat {
     OFFSET_COLUMN_VARIABLE = defineOffsetColumnVariable();
     OFFSET_COLUMN_COMPRESSED_UNICODE = defineOffsetColumnCompressedUnicode();
     OFFSET_COLUMN_LENGTH = defineOffsetColumnLength();
+    OFFSET_COLUMN_VARIABLE_TABLE_INDEX = defineOffsetColumnVariableTableIndex();
+    OFFSET_COLUMN_FIXED_DATA_OFFSET = defineOffsetColumnFixedDataOffset();
     
     OFFSET_TABLE_DEF_LOCATION = defineOffsetTableDefLocation();
     OFFSET_NUM_ROWS_ON_PAGE = defineOffsetNumRowsOnPage();
@@ -223,7 +227,9 @@ public abstract class JetFormat {
   protected abstract int defineOffsetColumnVariable();
   protected abstract int defineOffsetColumnCompressedUnicode();
   protected abstract int defineOffsetColumnLength();
-
+  protected abstract int defineOffsetColumnVariableTableIndex();
+  protected abstract int defineOffsetColumnFixedDataOffset();
+  
   protected abstract int defineOffsetTableDefLocation();
   protected abstract int defineOffsetNumRowsOnPage();
   protected abstract int defineOffsetRowLocationBlock();
@@ -284,6 +290,8 @@ public abstract class JetFormat {
     protected int defineOffsetColumnVariable() { return 15; }
     protected int defineOffsetColumnCompressedUnicode() { return 16; }
     protected int defineOffsetColumnLength() { return 23; }
+    protected int defineOffsetColumnVariableTableIndex() { return 7; }
+    protected int defineOffsetColumnFixedDataOffset() { return 21; }
   
     protected int defineOffsetTableDefLocation() { return 4; }
     protected int defineOffsetNumRowsOnPage() { return 12; }
index 35b66a9f4bf966b2277ff68ec8e120f51966e65d..b141862c793393274af37a2239a36d8d49be8ec5 100644 (file)
@@ -75,6 +75,8 @@ public class Table {
   /** max Number of columns in the table (includes previous deletions) */
   private short _maxColumnCount;
   /** max Number of variable columns in the table */
+  private short _maxVarColumnCount;
+  /** Number of variable columns in the table */
   private short _varColumnCount;
   /** Number of fixed columns in the table */
   private short _fixedColumnCount;
@@ -208,48 +210,47 @@ public class Table {
           _buffer.limit() - _buffer.position()));
     }
     short columnCount = _buffer.getShort(); //Number of columns in this row
-
+    
     Map<String, Object> rtn = new LinkedHashMap<String, Object>(columnCount);
     NullMask nullMask = new NullMask(columnCount);
     _buffer.position(_buffer.limit() - nullMask.byteSize());  //Null mask at end
     nullMask.read(_buffer);
 
-    short varColumnCount = 0;
+    short rowVarColumnCount = 0;
     byte[][] varColumnData = null;
     short[] varColumnOffsets = null;
     short lastVarColumnStart = 0;
-    // if table varColumnCount is 0, then row info does not include varcol
-    // info
-    if(_varColumnCount > 0) {
+    // if _maxVarColumnCount is 0, then row info does not include varcol info
+    if(_maxVarColumnCount > 0) {
       _buffer.position(_buffer.limit() - nullMask.byteSize() - 2);
-      varColumnCount = _buffer.getShort();  // actual number of variable length columns in this row
-      varColumnData = new byte[varColumnCount][];  //Holds variable length column data
+      rowVarColumnCount = _buffer.getShort();  // number of variable length columns in this row
+      varColumnData = new byte[rowVarColumnCount][];  //Holds variable length column data
 
       //Read in the offsets of each of the variable length columns
-      varColumnOffsets = new short[varColumnCount];
-      _buffer.position(_buffer.position() - 2 - (varColumnCount * 2) - 2);
+      varColumnOffsets = new short[rowVarColumnCount];
+      _buffer.position(_buffer.position() - 2 - (rowVarColumnCount * 2) - 2);
       lastVarColumnStart = _buffer.getShort();
-      for (short i = 0; i < varColumnCount; i++) {
+      for (short i = 0; i < rowVarColumnCount; i++) {
         varColumnOffsets[i] = _buffer.getShort();
       }
     }
       
     
     //Read in the actual data for each of the variable length columns
-    for (short i = 0; i < varColumnCount; i++) {
+    for (short i = 0; i < rowVarColumnCount; i++) {
       _buffer.position(_rowStart + varColumnOffsets[i]);
       varColumnData[i] = new byte[lastVarColumnStart - varColumnOffsets[i]];
       _buffer.get(varColumnData[i]);
       lastVarColumnStart = varColumnOffsets[i];
     }
-    int columnNumber = 0;
-    int varColumnDataIndex = varColumnCount - 1;
-    
-    _buffer.position(_rowStart + 2);  //Move back to the front of the buffer
+
+    // compute start of fixed data
+    int dataStart = _rowStart + 2;
     
     //Now read in the fixed length columns and populate the columnData array
     //with the combination of fixed length and variable length data.
     byte[] columnData = null;
+    int columnNumber = 0;
     for (Iterator iter = _columns.iterator(); iter.hasNext(); columnNumber++) {
       Column column = (Column) iter.next();
       boolean isNull = nullMask.isNull(columnNumber);
@@ -261,16 +262,18 @@ public class Table {
         {
           //Read in fixed length column data
           columnData = new byte[column.getLength()];
+          _buffer.position(dataStart + column.getFixedDataOffset());
           _buffer.get(columnData);
         } 
         else
         {
            if (!isNull) 
            {
-             //Refer to already-read-in variable length data
-             columnData = varColumnData[varColumnDataIndex];
+             // Refer to already-read-in variable length data.  note,
+             // varLenTableIndex is from the *end* of the array...
+             columnData = varColumnData[rowVarColumnCount -
+                                        column.getVarLenTableIndex() - 1];
            }
-           --varColumnDataIndex;
         }
         if (!isNull && columnData != null &&
             (columnNames == null || columnNames.contains(column.getName())))
@@ -334,7 +337,7 @@ public class Table {
     _rowCount = _buffer.getInt(_format.OFFSET_NUM_ROWS);
     _tableType = _buffer.get(_format.OFFSET_TABLE_TYPE);
     _maxColumnCount = _buffer.getShort(_format.OFFSET_MAX_COLS);
-    _varColumnCount = _buffer.getShort(_format.OFFSET_NUM_VAR_COLS);
+    _maxVarColumnCount = _buffer.getShort(_format.OFFSET_NUM_VAR_COLS);
     _columnCount = _buffer.getShort(_format.OFFSET_NUM_COLS);
     _indexCount = _buffer.getInt(_format.OFFSET_NUM_INDEXES);
     
@@ -358,7 +361,9 @@ public class Table {
     for (int i = 0; i < _columnCount; i++) {
       column = new Column(_buffer,
           offset + i * _format.SIZE_COLUMN_HEADER, _pageChannel, _format);
-      if(!column.isVariableLength()) {
+      if(column.isVariableLength()) {
+        _varColumnCount++;
+      } else {
         _fixedColumnCount++;
       }
       _columns.add(column);
diff --git a/test/data/delColTest.mdb b/test/data/delColTest.mdb
new file mode 100644 (file)
index 0000000..b931b0d
Binary files /dev/null and b/test/data/delColTest.mdb differ
index 2dba4485c843f74a70d41aa60823f5b70ca7a9c8..86f1bdd9196466f2eacc994cc73ae09b8c13ff58 100644 (file)
@@ -258,6 +258,35 @@ public class DatabaseTest extends TestCase {
     return rtn;
   }
 
+  public void testReadWithDeletedCols() throws Exception {
+    Table table = Database.open(new File("test/data/delColTest.mdb")).getTable("Table1");
+
+    Map<String, Object> expectedRow0 = new HashMap<String, Object>();
+    expectedRow0.put("id", 0);
+    expectedRow0.put("id2", 2);
+    expectedRow0.put("data", "foo");
+    expectedRow0.put("data2", "foo2");
+
+    Map<String, Object> expectedRow1 = new HashMap<String, Object>();
+    expectedRow1.put("id", 3);
+    expectedRow1.put("id2", 5);
+    expectedRow1.put("data", "bar");
+    expectedRow1.put("data2", "bar2");
+
+    int rowNum = 0;
+    Map<String, Object> row = null;
+    while ((row = table.getNextRow()) != null) {
+      if(rowNum == 0) {
+        assertEquals(expectedRow0, row);
+      } else if(rowNum == 1) {
+        assertEquals(expectedRow1, row);
+      } else if(rowNum >= 2) {
+        fail("should only have 2 rows");
+      }
+      rowNum++;
+    }
+  }
+
   private Object[] createTestRow() {
     return new Object[] {"Tim", "R", "McCune", 1234, (byte) 0xad, 555.66d,
         777.88f, (short) 999, new Date()};