From: James Ahlborn Date: Wed, 22 Jun 2016 01:19:39 +0000 (+0000) Subject: populate new index data after creation X-Git-Tag: jackcess-2.1.5~7^2~29 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4dddf8bcbea7b4b977ba085a11d8bff20fd66909;p=jackcess.git populate new index data after creation git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@999 f203690c-595d-4dc9-a70b-905162fa7fd2 --- diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java index 62093c1..cdd1a93 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java @@ -1125,109 +1125,121 @@ public class TableImpl implements Table ByteBuffer tableBuffer = loadCompleteTableDefinitionBufferForUpdate( mutator); - //// - // update various bits of the table def - ByteUtil.forward(tableBuffer, 29); - tableBuffer.putShort((short)(_maxColumnCount + 1)); - short varColCount = (short)(_varColumns.size() + (isVarCol ? 1 : 0)); - tableBuffer.putShort(varColCount); - tableBuffer.putShort((short)(_columns.size() + 1)); - - // move to end of column def blocks - tableBuffer.position(format.SIZE_TDEF_HEADER + - (_indexCount * format.SIZE_INDEX_DEFINITION) + - (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK)); - - // figure out the data offsets for the new column - int fixedOffset = 0; - int varOffset = 0; - if(column.isVariableLength()) { - // find the variable offset - for(ColumnImpl col : _varColumns) { - if(col.getVarLenTableIndex() >= varOffset) { - varOffset = col.getVarLenTableIndex() + 1; + ColumnImpl newCol = null; + int umapPos = -1; + boolean success = false; + try { + + //// + // update various bits of the table def + ByteUtil.forward(tableBuffer, 29); + tableBuffer.putShort((short)(_maxColumnCount + 1)); + short varColCount = (short)(_varColumns.size() + (isVarCol ? 1 : 0)); + tableBuffer.putShort(varColCount); + tableBuffer.putShort((short)(_columns.size() + 1)); + + // move to end of column def blocks + tableBuffer.position(format.SIZE_TDEF_HEADER + + (_indexCount * format.SIZE_INDEX_DEFINITION) + + (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK)); + + // figure out the data offsets for the new column + int fixedOffset = 0; + int varOffset = 0; + if(column.isVariableLength()) { + // find the variable offset + for(ColumnImpl col : _varColumns) { + if(col.getVarLenTableIndex() >= varOffset) { + varOffset = col.getVarLenTableIndex() + 1; + } } - } - } else { - // find the fixed offset - for(ColumnImpl col : _columns) { - if(!col.isVariableLength() && - (col.getFixedDataOffset() >= fixedOffset)) { - fixedOffset = col.getFixedDataOffset() + - col.getType().getFixedSize(col.getLength()); + } else { + // find the fixed offset + for(ColumnImpl col : _columns) { + if(!col.isVariableLength() && + (col.getFixedDataOffset() >= fixedOffset)) { + fixedOffset = col.getFixedDataOffset() + + col.getType().getFixedSize(col.getLength()); + } } } - } - - mutator.setColumnOffsets(fixedOffset, varOffset, varOffset); - - // insert space for the column definition and write it - int colDefPos = tableBuffer.position(); - ByteUtil.insertEmptyData(tableBuffer, format.SIZE_COLUMN_DEF_BLOCK); - ColumnImpl.writeDefinition(mutator, column, tableBuffer); - - // skip existing column names and write new name - skipNames(tableBuffer, _columns.size()); - ByteUtil.insertEmptyData(tableBuffer, nameByteLen); - System.out.println("FOO pre name " + tableBuffer.position()); - writeName(tableBuffer, column.getName(), mutator.getCharset()); - System.out.println("FOO post name " + tableBuffer.position()); - int umapPos = -1; - if(isLongVal) { - - // allocate usage maps for the long value col - Map.Entry umapInfo = addUsageMaps(2, null); - System.out.println("FOO created umap " + umapInfo); - DBMutator.ColumnState colState = mutator.getColumnState(column); - colState.setUmapPageNumber(umapInfo.getKey()); - byte rowNum = umapInfo.getValue().byteValue(); - colState.setUmapOwnedRowNumber(rowNum); - colState.setUmapFreeRowNumber((byte)(rowNum + 1)); - - // skip past index defs - System.out.println("FOO pre move " + tableBuffer.position()); - ByteUtil.forward(tableBuffer, (_indexCount * - format.SIZE_INDEX_COLUMN_BLOCK)); - System.out.println("FOO moved to " + tableBuffer.position()); - ByteUtil.forward(tableBuffer, - (_logicalIndexCount * format.SIZE_INDEX_INFO_BLOCK)); - System.out.println("FOO moved to " + tableBuffer.position()); - skipNames(tableBuffer, _logicalIndexCount); + mutator.setColumnOffsets(fixedOffset, varOffset, varOffset); + + // insert space for the column definition and write it + int colDefPos = tableBuffer.position(); + ByteUtil.insertEmptyData(tableBuffer, format.SIZE_COLUMN_DEF_BLOCK); + ColumnImpl.writeDefinition(mutator, column, tableBuffer); + + // skip existing column names and write new name + skipNames(tableBuffer, _columns.size()); + ByteUtil.insertEmptyData(tableBuffer, nameByteLen); + System.out.println("FOO pre name " + tableBuffer.position()); + writeName(tableBuffer, column.getName(), mutator.getCharset()); + System.out.println("FOO post name " + tableBuffer.position()); + + if(isLongVal) { + + // allocate usage maps for the long value col + Map.Entry umapInfo = addUsageMaps(2, null); + System.out.println("FOO created umap " + umapInfo); + DBMutator.ColumnState colState = mutator.getColumnState(column); + colState.setUmapPageNumber(umapInfo.getKey()); + byte rowNum = umapInfo.getValue().byteValue(); + colState.setUmapOwnedRowNumber(rowNum); + colState.setUmapFreeRowNumber((byte)(rowNum + 1)); + + // skip past index defs + System.out.println("FOO pre move " + tableBuffer.position()); + ByteUtil.forward(tableBuffer, (_indexCount * + format.SIZE_INDEX_COLUMN_BLOCK)); + System.out.println("FOO moved to " + tableBuffer.position()); + ByteUtil.forward(tableBuffer, + (_logicalIndexCount * format.SIZE_INDEX_INFO_BLOCK)); + System.out.println("FOO moved to " + tableBuffer.position()); + skipNames(tableBuffer, _logicalIndexCount); + + // skip existing usage maps + while(tableBuffer.remaining() >= 2) { + if(tableBuffer.getShort() == IndexData.COLUMN_UNUSED) { + // found end of tdef, we want to insert before this + ByteUtil.forward(tableBuffer, -2); + break; + } + + ByteUtil.forward(tableBuffer, 8); - // skip existing usage maps - while(tableBuffer.remaining() >= 2) { - if(tableBuffer.getShort() == IndexData.COLUMN_UNUSED) { - // found end of tdef, we want to insert before this - ByteUtil.forward(tableBuffer, -2); - break; + // keep reading ... } - - ByteUtil.forward(tableBuffer, 8); - // keep reading ... + // write new column usage map info + System.out.println("FOO about to write " + tableBuffer.position()); + umapPos = tableBuffer.position(); + ByteUtil.insertEmptyData(tableBuffer, 10); + ColumnImpl.writeColUsageMapDefinition( + mutator, column, tableBuffer); } - // write new column usage map info - System.out.println("FOO about to write " + tableBuffer.position()); - umapPos = tableBuffer.position(); - ByteUtil.insertEmptyData(tableBuffer, 10); - ColumnImpl.writeColUsageMapDefinition( - mutator, column, tableBuffer); - } + // sanity check the updates + validateTableDefUpdate(mutator, tableBuffer); - // sanity check the updates - validateTableDefUpdate(mutator, tableBuffer); + // before writing the new table def, create the column + newCol = ColumnImpl.create(this, tableBuffer, colDefPos, + column.getName(), _columns.size()); + newCol.setColumnIndex(_columns.size()); - // before writing the new table def, create the column - ColumnImpl newCol = ColumnImpl.create(this, tableBuffer, colDefPos, - column.getName(), _columns.size()); - newCol.setColumnIndex(_columns.size()); + //// + // write updated table def back to the database + writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator, + mutator.getNextPages()); + success = true; - //// - // write updated table def back to the database - writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator, - mutator.getNextPages()); + } finally { + if(!success) { + // need to discard modified table buffer + _tableDefBufferH.invalidate(); + } + } //// // now, update current TableImpl @@ -1287,56 +1299,68 @@ public class TableImpl implements Table ByteBuffer tableBuffer = loadCompleteTableDefinitionBufferForUpdate( mutator); - //// - // update various bits of the table def - ByteUtil.forward(tableBuffer, 39); - tableBuffer.putInt(_indexCount + 1); - - // move to end of index data def blocks - tableBuffer.position(format.SIZE_TDEF_HEADER + - (_indexCount * format.SIZE_INDEX_DEFINITION)); - - // write index row count definition (empty initially) - ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_DEFINITION); - IndexData.writeRowCountDefinitions(mutator, tableBuffer, 1); - - // skip columns and column names - ByteUtil.forward(tableBuffer, - (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK)); - skipNames(tableBuffer, _columns.size()); - - // move to end of current index datas - ByteUtil.forward(tableBuffer, (_indexCount * - format.SIZE_INDEX_COLUMN_BLOCK)); - - // allocate usage maps and root page - DBMutator.IndexDataState idxDataState = mutator.getIndexDataState(index); - int rootPageNumber = getPageChannel().allocateNewPage(); - Map.Entry umapInfo = addUsageMaps(1, rootPageNumber); - System.out.println("FOO created umap " + umapInfo); - idxDataState.setRootPageNumber(rootPageNumber); - idxDataState.setUmapPageNumber(umapInfo.getKey()); - idxDataState.setUmapRowNumber(umapInfo.getValue().byteValue()); - - // write index data def - int idxDataDefPos = tableBuffer.position(); - ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_COLUMN_BLOCK); - IndexData.writeDefinition(mutator, tableBuffer, idxDataState, null); - - // sanity check the updates - validateTableDefUpdate(mutator, tableBuffer); - - // before writing the new table def, create the index data - tableBuffer.position(0); - IndexData newIdxData = IndexData.create( - this, tableBuffer, idxDataState.getIndexDataNumber(), format); - tableBuffer.position(idxDataDefPos); - newIdxData.read(tableBuffer, _columns); + IndexData newIdxData = null; + boolean success = false; + try { + + //// + // update various bits of the table def + ByteUtil.forward(tableBuffer, 39); + tableBuffer.putInt(_indexCount + 1); - //// - // write updated table def back to the database - writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator, - mutator.getNextPages()); + // move to end of index data def blocks + tableBuffer.position(format.SIZE_TDEF_HEADER + + (_indexCount * format.SIZE_INDEX_DEFINITION)); + + // write index row count definition (empty initially) + ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_DEFINITION); + IndexData.writeRowCountDefinitions(mutator, tableBuffer, 1); + + // skip columns and column names + ByteUtil.forward(tableBuffer, + (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK)); + skipNames(tableBuffer, _columns.size()); + + // move to end of current index datas + ByteUtil.forward(tableBuffer, (_indexCount * + format.SIZE_INDEX_COLUMN_BLOCK)); + + // allocate usage maps and root page + DBMutator.IndexDataState idxDataState = mutator.getIndexDataState(index); + int rootPageNumber = getPageChannel().allocateNewPage(); + Map.Entry umapInfo = addUsageMaps(1, rootPageNumber); + System.out.println("FOO created umap " + umapInfo); + idxDataState.setRootPageNumber(rootPageNumber); + idxDataState.setUmapPageNumber(umapInfo.getKey()); + idxDataState.setUmapRowNumber(umapInfo.getValue().byteValue()); + + // write index data def + int idxDataDefPos = tableBuffer.position(); + ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_COLUMN_BLOCK); + IndexData.writeDefinition(mutator, tableBuffer, idxDataState, null); + + // sanity check the updates + validateTableDefUpdate(mutator, tableBuffer); + + // before writing the new table def, create the index data + tableBuffer.position(0); + newIdxData = IndexData.create( + this, tableBuffer, idxDataState.getIndexDataNumber(), format); + tableBuffer.position(idxDataDefPos); + newIdxData.read(tableBuffer, _columns); + + //// + // write updated table def back to the database + writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator, + mutator.getNextPages()); + success = true; + + } finally { + if(!success) { + // need to discard modified table buffer + _tableDefBufferH.invalidate(); + } + } //// // now, update current TableImpl @@ -1350,9 +1374,35 @@ public class TableImpl implements Table completeTableMutation(tableBuffer); + // don't forget to populate the new index + populateIndexData(newIdxData); + return newIdxData; } + private void populateIndexData(IndexData idxData) + throws IOException + { + // grab the columns involved in this index + List idxCols = new ArrayList(); + for(IndexData.ColumnDescriptor col : idxData.getColumns()) { + idxCols.add(col.getColumn()); + } + + // iterate through all the rows and add them to the index + Object[] rowVals = new Object[_columns.size()]; + for(Row row : getDefaultCursor().newIterable().addColumns(idxCols)) { + for(Column col : idxCols) { + col.setRowValue(rowVals, col.getRowValue(row)); + } + + IndexData.commitAll( + idxData.prepareAddRow(rowVals, (RowIdImpl)row.getId(), null)); + } + + updateTableDefinition(0); + } + /** * Writes a index defined by the given TableMutator to this table. * @usage _advanced_method_ @@ -1374,48 +1424,60 @@ public class TableImpl implements Table ByteBuffer tableBuffer = loadCompleteTableDefinitionBufferForUpdate( mutator); - //// - // update various bits of the table def - ByteUtil.forward(tableBuffer, 35); - tableBuffer.putInt(_logicalIndexCount + 1); - - // move to end of index data def blocks - tableBuffer.position(format.SIZE_TDEF_HEADER + - (_indexCount * format.SIZE_INDEX_DEFINITION)); - - // skip columns and column names - ByteUtil.forward(tableBuffer, - (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK)); - skipNames(tableBuffer, _columns.size()); - - // move to end of current index datas - ByteUtil.forward(tableBuffer, (_indexCount * - format.SIZE_INDEX_COLUMN_BLOCK)); - // move to end of current indexes - ByteUtil.forward(tableBuffer, (_logicalIndexCount * - format.SIZE_INDEX_INFO_BLOCK)); - - int idxDefPos = tableBuffer.position(); - ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_INFO_BLOCK); - IndexImpl.writeDefinition(mutator, index, tableBuffer); - - // skip existing index names and write new name - skipNames(tableBuffer, _logicalIndexCount); - ByteUtil.insertEmptyData(tableBuffer, nameByteLen); - writeName(tableBuffer, index.getName(), mutator.getCharset()); - - // sanity check the updates - validateTableDefUpdate(mutator, tableBuffer); - - // before writing the new table def, create the index - tableBuffer.position(idxDefPos); - IndexImpl newIdx = new IndexImpl(tableBuffer, _indexDatas, format); - newIdx.setName(index.getName()); + IndexImpl newIdx = null; + boolean success = false; + try { + + //// + // update various bits of the table def + ByteUtil.forward(tableBuffer, 35); + tableBuffer.putInt(_logicalIndexCount + 1); + + // move to end of index data def blocks + tableBuffer.position(format.SIZE_TDEF_HEADER + + (_indexCount * format.SIZE_INDEX_DEFINITION)); + + // skip columns and column names + ByteUtil.forward(tableBuffer, + (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK)); + skipNames(tableBuffer, _columns.size()); + + // move to end of current index datas + ByteUtil.forward(tableBuffer, (_indexCount * + format.SIZE_INDEX_COLUMN_BLOCK)); + // move to end of current indexes + ByteUtil.forward(tableBuffer, (_logicalIndexCount * + format.SIZE_INDEX_INFO_BLOCK)); + + int idxDefPos = tableBuffer.position(); + ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_INFO_BLOCK); + IndexImpl.writeDefinition(mutator, index, tableBuffer); + + // skip existing index names and write new name + skipNames(tableBuffer, _logicalIndexCount); + ByteUtil.insertEmptyData(tableBuffer, nameByteLen); + writeName(tableBuffer, index.getName(), mutator.getCharset()); + + // sanity check the updates + validateTableDefUpdate(mutator, tableBuffer); + + // before writing the new table def, create the index + tableBuffer.position(idxDefPos); + newIdx = new IndexImpl(tableBuffer, _indexDatas, format); + newIdx.setName(index.getName()); - //// - // write updated table def back to the database - writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator, - mutator.getNextPages()); + //// + // write updated table def back to the database + writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator, + mutator.getNextPages()); + success = true; + + } finally { + if(!success) { + // need to discard modified table buffer + _tableDefBufferH.invalidate(); + } + } //// // now, update current TableImpl @@ -3213,9 +3275,10 @@ public class TableImpl implements Table reset(); _headerRowBufferH.invalidate(); _overflowRowBufferH.invalidate(); - if(TableImpl.this._maxColumnCount != _rowValues.length) { + int colCount = TableImpl.this.getColumnCount(); + if(colCount != _rowValues.length) { // columns added or removed from table - _rowValues = new Object[TableImpl.this._maxColumnCount]; + _rowValues = new Object[colCount]; } _lastModCount = TableImpl.this._modCount; } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java index 478b55c..8c9ba28 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java @@ -153,13 +153,13 @@ public class TableMutator extends DBMutator if(_idxDataState.getIndexDataNumber() == _table.getIndexCount()) { // we need a new backing index data _table.mutateAddIndexData(this); + + // we need to modify the table def again when adding the Index, so reset resetTdefInfo(); } return _table.mutateAddIndex(this); - // FIXME, need to add data to index!!! - } finally { getPageChannel().finishWrite(); }