]> source.dussan.org Git - jackcess.git/commitdiff
Reuse previously written memo/ole values when updating other values in a row in order...
authorJames Ahlborn <jtahlborn@yahoo.com>
Tue, 15 Nov 2011 03:04:11 +0000 (03:04 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Tue, 15 Nov 2011 03:04:11 +0000 (03:04 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@595 f203690c-595d-4dc9-a70b-905162fa7fd2

TODO.txt
src/changes/changes.xml
src/java/com/healthmarketscience/jackcess/Table.java
test/src/java/com/healthmarketscience/jackcess/TableTest.java

index 7c9802e545155098d106b2c775ea7b48a4368148..225fc0ffca11b716afa99533c8a2d12196538a75 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,7 +1,5 @@
 Missing pieces:
 
-- re-use memo/ole data in "other page(s)" when updating rows
-  * MEDIUM
 - fix long text index entries (for new general sort order)
   * ???
 - implement foreign key index creation & relationship creation
index df417516699b82842d2a0277efaab85914d2ad47..17dacb243851febf3dabba456b1a53f42dcc8d01 100644 (file)
       <action dev="jahlborn" type="fix" issue="3435774">
         Fix problem with reading row from table with deleted/added columns.
       </action>
+      <action dev="jahlborn" type="update">
+        Reuse previously written memo/ole values when updating other values in
+        a row in order to reduce unnecessary data duplication.
+      </action>
     </release>
     <release version="1.2.5" date="2011-10-19">
       <action dev="jahlborn" type="update">
index a868317311eebb22b0e5dcfdf420d91e6b13ff19..e11c7f9b91c0da7899e72753a3fc9b071e409f77 100644 (file)
@@ -35,6 +35,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -598,7 +599,7 @@ public class Table
     ByteBuffer rowBuffer = positionAtRowData(rowState, rowId);
     requireNonDeletedRow(rowState, rowId);
     
-    return getRowColumn(getFormat(), rowBuffer, column, rowState);
+    return getRowColumn(getFormat(), rowBuffer, column, rowState, null);
   }
 
   /**
@@ -638,7 +639,7 @@ public class Table
       if((columnNames == null) || (columnNames.contains(column.getName()))) {
         // Add the value to the row data
         column.setRowValue(
-            rtn, getRowColumn(format, rowBuffer, column, rowState));
+            rtn, getRowColumn(format, rowBuffer, column, rowState, null));
       }
     }
     return rtn;
@@ -651,7 +652,8 @@ public class Table
   private static Object getRowColumn(JetFormat format,
                                      ByteBuffer rowBuffer,
                                      Column column,
-                                     RowState rowState)
+                                     RowState rowState,
+                                     Map<Column,byte[]> rawVarValues)
     throws IOException
   {
     byte[] columnData = null;
@@ -716,6 +718,11 @@ public class Table
       rowBuffer.position(colDataPos);
       rowBuffer.get(columnData);
 
+      if((rawVarValues != null) && column.isVariableLength()) {
+        // caller wants raw value as well
+        rawVarValues.put(column, columnData);
+      }
+
       // parse the column data.  we cache the row values in order to be able
       // to update the index on row deletion.  note, most of the returned
       // values are immutable, except for binary data (returned as byte[]),
@@ -1453,9 +1460,7 @@ public class Table
       handleAutoNumbersForAdd(row);
       
       // write the row of data to a temporary buffer
-      rowData[i] = createRow(row, getFormat().MAX_ROW_SIZE,
-                             writeRowBufferH.getPageBuffer(getPageChannel()),
-                             0);
+      rowData[i] = createRow(row, writeRowBufferH.getPageBuffer(getPageChannel()));
       
       if (rowData[i].limit() > getFormat().MAX_ROW_SIZE) {
         throw new IOException("Row size " + rowData[i].limit() +
@@ -1532,30 +1537,38 @@ public class Table
     // modified)
     handleAutoNumbersForUpdate(row, rowBuffer, rowState);
     
+    // hang on to the raw values of var length columns we are "keeping".  this
+    // will allow us to re-use pre-written var length data, which can save
+    // space for things like long value columns.
+    Map<Column,byte[]> rawVarValues = 
+      (!_varColumns.isEmpty() ? new HashMap<Column,byte[]>() : null);
+
     // fill in any "keep value" fields
     for(Column column : _columns) {
       if(column.getRowValue(row) == Column.KEEP_VALUE) {
         column.setRowValue(
-            row, getRowColumn(getFormat(), rowBuffer, column, rowState));
+            row, getRowColumn(getFormat(), rowBuffer, column, rowState,
+                              rawVarValues));
       }
     }
 
     // generate new row bytes
     ByteBuffer newRowData = createRow(
-        row, getFormat().MAX_ROW_SIZE,
-        _singleRowBufferH.getPageBuffer(getPageChannel()), oldRowSize);
+        row, _singleRowBufferH.getPageBuffer(getPageChannel()), oldRowSize,
+        rawVarValues);
 
     if (newRowData.limit() > getFormat().MAX_ROW_SIZE) {
       throw new IOException("Row size " + newRowData.limit() + 
                             " is too large");
     }
 
-    Object[] oldRowValues = (!_indexDatas.isEmpty() ?
-                             rowState.getRowValues() : null);
+    if(!_indexDatas.isEmpty()) {
+      Object[] oldRowValues = rowState.getRowValues();
 
-    // delete old values from indexes
-    for(IndexData indexData : _indexDatas) {
-      indexData.deleteRow(oldRowValues, rowId);
+      // delete old values from indexes
+      for(IndexData indexData : _indexDatas) {
+        indexData.deleteRow(oldRowValues, rowId);
+      }
     }
     
     // see if we can squeeze the new row data into the existing row
@@ -1724,19 +1737,24 @@ public class Table
     return dataPage;
   }
   
+  ByteBuffer createRow(Object[] rowArray, ByteBuffer buffer)
+    throws IOException
+  {
+    return createRow(rowArray, buffer, 0, Collections.<Column,byte[]>emptyMap());
+  }
+
   /**
    * Serialize a row of Objects into a byte buffer.
-   * <p>
-   * Note, if this table has an auto-number column, the value written will be
-   * put back into the given row array.
    * 
    * @param rowArray row data, expected to be correct length for this table
-   * @param maxRowSize max size the data can be for this row
    * @param buffer buffer to which to write the row data
+   * @param minRowSize min size for result row
+   * @param rawVarValues optional, pre-written values for var length columns
+   *                     (enables re-use of previously written values).
    * @return the given buffer, filled with the row data
    */
-  ByteBuffer createRow(Object[] rowArray, int maxRowSize, ByteBuffer buffer,
-                       int minRowSize)
+  private ByteBuffer createRow(Object[] rowArray, ByteBuffer buffer,
+                               int minRowSize, Map<Column,byte[]> rawVarValues)
     throws IOException
   {
     buffer.putShort(_maxColumnCount);
@@ -1791,6 +1809,8 @@ public class Table
     // only need this info if this table contains any var length data
     if(_maxVarColumnCount > 0) {
 
+      int maxRowSize = getFormat().MAX_ROW_SIZE;
+
       // figure out how much space remains for var length data.  first,
       // account for already written space
       maxRowSize -= buffer.position();
@@ -1818,7 +1838,17 @@ public class Table
           // we have a value
           nullMask.markNotNull(varCol);
 
-          ByteBuffer varDataBuf = varCol.write(rowValue, maxRowSize);
+          byte[] rawValue = null;
+          ByteBuffer varDataBuf = null;
+          if(((rawValue = rawVarValues.get(varCol)) != null) && 
+             (rawValue.length <= maxRowSize)) {
+            // save time and potentially db space, re-use raw value
+            varDataBuf = ByteBuffer.wrap(rawValue);
+          } else {
+            // write column value
+            varDataBuf = varCol.write(rowValue, maxRowSize);
+          }
+
           maxRowSize -= varDataBuf.remaining();
           if(varCol.getType().isLongValue()) {
             // we already accounted for some amount of the long value data
@@ -1880,7 +1910,8 @@ public class Table
     }
 
     for(Column col : _autoNumColumns) {
-      col.setRowValue(row, getRowColumn(getFormat(), rowBuffer, col, rowState));
+      col.setRowValue(row, getRowColumn(getFormat(), rowBuffer, col, rowState, 
+                                        null));
     }
   }
 
index 7672e96972021bf6e9c01b91caf056f5befc30d1..43f092f360e6ca121509a291863e33747bf329a9 100644 (file)
@@ -120,8 +120,7 @@ public class TableTest extends TestCase {
     throws IOException
   {
     return _testTable.createRow(
-        row, _testTable.getFormat().MAX_ROW_SIZE,
-        _testTable.getPageChannel().createPageBuffer(), 0);
+        row, _testTable.getPageChannel().createPageBuffer());
   }
 
   private ByteBuffer[] encodeColumns(Object... row)