aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2016-06-16 02:32:43 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2016-06-16 02:32:43 +0000
commit8f482230a1bc1a459e20dabc42649e0adff27107 (patch)
tree2cd875bfd585454f1c40095efaa7662a2fa1baa3
parenta45ac7fc22c133a110ae54a6261857f96491bff8 (diff)
downloadjackcess-8f482230a1bc1a459e20dabc42649e0adff27107.tar.gz
jackcess-8f482230a1bc1a459e20dabc42649e0adff27107.zip
implement most of the dirty work for adding indexes
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@996 f203690c-595d-4dc9-a70b-905162fa7fd2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java26
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java102
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java22
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java73
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java32
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java97
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java217
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java22
8 files changed, 349 insertions, 242 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java
index 596bc35..8950248 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java
@@ -1660,6 +1660,32 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> {
}
}
+ protected static void writeColUsageMapDefinitions(
+ TableCreator creator, ByteBuffer buffer)
+ throws IOException
+ {
+ // write long value column usage map references
+ for(ColumnBuilder lvalCol : creator.getLongValueColumns()) {
+ writeColUsageMapDefinition(creator, lvalCol, buffer);
+ }
+ }
+
+ protected static void writeColUsageMapDefinition(
+ DBMutator creator, ColumnBuilder lvalCol, ByteBuffer buffer)
+ throws IOException
+ {
+ DBMutator.ColumnState colState = creator.getColumnState(lvalCol);
+
+ buffer.putShort(lvalCol.getColumnNumber());
+
+ // owned pages umap (both are on same page)
+ buffer.put(colState.getUmapOwnedRowNumber());
+ ByteUtil.put3ByteInt(buffer, colState.getUmapPageNumber());
+ // free space pages umap
+ buffer.put(colState.getUmapFreeRowNumber());
+ ByteUtil.put3ByteInt(buffer, colState.getUmapPageNumber());
+ }
+
/**
* Reads the sort order info from the given buffer from the given position.
*/
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java b/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java
index 8abc390..e599191 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java
@@ -18,6 +18,8 @@ package com.healthmarketscience.jackcess.impl;
import java.io.IOException;
import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import com.healthmarketscience.jackcess.ColumnBuilder;
@@ -139,6 +141,10 @@ abstract class DBMutator
abstract short getColumnNumber(String colName);
+ public abstract ColumnState getColumnState(ColumnBuilder col);
+
+ public abstract IndexDataState getIndexDataState(IndexBuilder idx);
+
/**
* Maintains additional state used during column writing.
* @usage _advanced_class_
@@ -168,4 +174,100 @@ abstract class DBMutator
return offset;
}
}
+
+ /**
+ * Maintains additional state used during column creation.
+ * @usage _advanced_class_
+ */
+ static final class ColumnState
+ {
+ private byte _umapOwnedRowNumber;
+ private byte _umapFreeRowNumber;
+ // we always put both usage maps on the same page
+ private int _umapPageNumber;
+
+ public byte getUmapOwnedRowNumber() {
+ return _umapOwnedRowNumber;
+ }
+
+ public void setUmapOwnedRowNumber(byte newUmapOwnedRowNumber) {
+ _umapOwnedRowNumber = newUmapOwnedRowNumber;
+ }
+
+ public byte getUmapFreeRowNumber() {
+ return _umapFreeRowNumber;
+ }
+
+ public void setUmapFreeRowNumber(byte newUmapFreeRowNumber) {
+ _umapFreeRowNumber = newUmapFreeRowNumber;
+ }
+
+ public int getUmapPageNumber() {
+ return _umapPageNumber;
+ }
+
+ public void setUmapPageNumber(int newUmapPageNumber) {
+ _umapPageNumber = newUmapPageNumber;
+ }
+ }
+
+ /**
+ * Maintains additional state used during index data creation.
+ * @usage _advanced_class_
+ */
+ static final class IndexDataState
+ {
+ private final List<IndexBuilder> _indexes = new ArrayList<IndexBuilder>();
+ private int _indexDataNumber;
+ private byte _umapRowNumber;
+ private int _umapPageNumber;
+ private int _rootPageNumber;
+
+ public IndexBuilder getFirstIndex() {
+ // all indexes which have the same backing IndexDataState will have
+ // equivalent columns and flags.
+ return _indexes.get(0);
+ }
+
+ public List<IndexBuilder> getIndexes() {
+ return _indexes;
+ }
+
+ public void addIndex(IndexBuilder idx) {
+ _indexes.add(idx);
+ }
+
+ public int getIndexDataNumber() {
+ return _indexDataNumber;
+ }
+
+ public void setIndexDataNumber(int newIndexDataNumber) {
+ _indexDataNumber = newIndexDataNumber;
+ }
+
+ public byte getUmapRowNumber() {
+ return _umapRowNumber;
+ }
+
+ public void setUmapRowNumber(byte newUmapRowNumber) {
+ _umapRowNumber = newUmapRowNumber;
+ }
+
+ public int getUmapPageNumber() {
+ return _umapPageNumber;
+ }
+
+ public void setUmapPageNumber(int newUmapPageNumber) {
+ _umapPageNumber = newUmapPageNumber;
+ }
+
+ public int getRootPageNumber() {
+ return _rootPageNumber;
+ }
+
+ public void setRootPageNumber(int newRootPageNumber) {
+ _rootPageNumber = newRootPageNumber;
+ }
+ }
+
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java b/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
index d2d4c50..d29836a 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
@@ -50,7 +50,7 @@ final class FKEnforcer
CaseInsensitiveColumnMatcher.INSTANCE;
private final TableImpl _table;
- private final List<ColumnImpl> _cols;
+ private List<ColumnImpl> _cols;
private List<Joiner> _primaryJoinersChkUp;
private List<Joiner> _primaryJoinersChkDel;
private List<Joiner> _primaryJoinersDoUp;
@@ -62,6 +62,10 @@ final class FKEnforcer
_table = table;
// at this point, only init the index columns
+ initColumns();
+ }
+
+ private void initColumns() {
Set<ColumnImpl> cols = new TreeSet<ColumnImpl>();
for(IndexImpl idx : _table.getIndexes()) {
IndexImpl.ForeignKeyReference ref = idx.getReference();
@@ -79,6 +83,22 @@ final class FKEnforcer
}
/**
+ * Resets the internals of this FKEnforcer (for post-table modification)
+ */
+ void reset() {
+ // columns to enforce may have changed
+ initColumns();
+
+ // clear any existing joiners (will be re-created on next use)
+ _primaryJoinersChkUp = null;
+ _primaryJoinersChkDel = null;
+ _primaryJoinersDoUp = null;
+ _primaryJoinersDoDel = null;
+ _primaryJoinersDoNull = null;
+ _secondaryJoiners = null;
+ }
+
+ /**
* Does secondary initialization, if necessary.
*/
private void initialize() throws IOException {
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java b/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
index 10deea6..3961a9b 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
@@ -27,7 +27,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
-import com.healthmarketscience.jackcess.ColumnBuilder;
import com.healthmarketscience.jackcess.ConstraintViolationException;
import com.healthmarketscience.jackcess.Index;
import com.healthmarketscience.jackcess.IndexBuilder;
@@ -511,54 +510,8 @@ public class IndexData {
{
ByteBuffer rootPageBuffer = createRootPageBuffer(creator);
- for(TableCreator.IndexDataState idxDataState : creator.getIndexDataStates()) {
- buffer.putInt(MAGIC_INDEX_NUMBER); // seemingly constant magic value
-
- // write column information (always MAX_COLUMNS entries)
- IndexBuilder idx = idxDataState.getFirstIndex();
- List<IndexBuilder.Column> idxColumns = idx.getColumns();
- for(int i = 0; i < MAX_COLUMNS; ++i) {
-
- short columnNumber = COLUMN_UNUSED;
- byte flags = 0;
-
- if(i < idxColumns.size()) {
-
- // determine column info
- IndexBuilder.Column idxCol = idxColumns.get(i);
- flags = idxCol.getFlags();
-
- // find actual table column number
- for(ColumnBuilder col : creator.getColumns()) {
- if(col.getName().equalsIgnoreCase(idxCol.getName())) {
- columnNumber = col.getColumnNumber();
- break;
- }
- }
- if(columnNumber == COLUMN_UNUSED) {
- // should never happen as this is validated before
- throw new IllegalArgumentException(
- withErrorContext(
- "Column with name " + idxCol.getName() + " not found",
- creator.getDatabase(), creator.getName(), idx.getName()));
- }
- }
-
- buffer.putShort(columnNumber); // table column number
- buffer.put(flags); // column flags (e.g. ordering)
- }
-
- buffer.put(idxDataState.getUmapRowNumber()); // umap row
- ByteUtil.put3ByteInt(buffer, creator.getUmapPageNumber()); // umap page
-
- // write empty root index page
- creator.getPageChannel().writePage(rootPageBuffer,
- idxDataState.getRootPageNumber());
-
- buffer.putInt(idxDataState.getRootPageNumber());
- buffer.putInt(0); // unknown
- buffer.put(idx.getFlags()); // index flags (unique, etc.)
- ByteUtil.forward(buffer, 5); // unknown
+ for(DBMutator.IndexDataState idxDataState : creator.getIndexDataStates()) {
+ writeDefinition(creator, buffer, idxDataState, rootPageBuffer);
}
}
@@ -569,14 +522,13 @@ public class IndexData {
*/
protected static void writeDefinition(
DBMutator creator, ByteBuffer buffer,
- TableCreator.IndexDataState idxDataState, ByteBuffer rootPageBuffer)
+ DBMutator.IndexDataState idxDataState, ByteBuffer rootPageBuffer)
throws IOException
{
if(rootPageBuffer == null) {
rootPageBuffer = createRootPageBuffer(creator);
}
- // FIXME
buffer.putInt(MAGIC_INDEX_NUMBER); // seemingly constant magic value
// write column information (always MAX_COLUMNS entries)
@@ -609,18 +561,17 @@ public class IndexData {
buffer.put(flags); // column flags (e.g. ordering)
}
- // FIXME
- // buffer.put(idxDataState.getUmapRowNumber()); // umap row
- // ByteUtil.put3ByteInt(buffer, creator.getUmapPageNumber()); // umap page
+ buffer.put(idxDataState.getUmapRowNumber()); // umap row
+ ByteUtil.put3ByteInt(buffer, idxDataState.getUmapPageNumber()); // umap page
- // // write empty root index page
- // creator.getPageChannel().writePage(rootPageBuffer,
- // idxDataState.getRootPageNumber());
+ // write empty root index page
+ creator.getPageChannel().writePage(rootPageBuffer,
+ idxDataState.getRootPageNumber());
- // buffer.putInt(idxDataState.getRootPageNumber());
- // buffer.putInt(0); // unknown
- // buffer.put(idx.getFlags()); // index flags (unique, etc.)
- // ByteUtil.forward(buffer, 5); // unknown
+ buffer.putInt(idxDataState.getRootPageNumber());
+ buffer.putInt(0); // unknown
+ buffer.put(idx.getFlags()); // index flags (unique, etc.)
+ ByteUtil.forward(buffer, 5); // unknown
}
private static ByteBuffer createRootPageBuffer(DBMutator creator)
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
index a927071..43b6c44 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
@@ -75,7 +75,6 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
JetFormat format)
throws IOException
{
-
ByteUtil.forward(tableBuffer, format.SKIP_BEFORE_INDEX_SLOT); //Forward past Unknown
_indexNumber = tableBuffer.getInt();
int indexDataNumber = tableBuffer.getInt();
@@ -342,17 +341,7 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
{
// write logical index information
for(IndexBuilder idx : creator.getIndexes()) {
- TableCreator.IndexDataState idxDataState = creator.getIndexDataState(idx);
- buffer.putInt(TableImpl.MAGIC_TABLE_NUMBER); // seemingly constant magic value which matches the table def
- buffer.putInt(idx.getIndexNumber()); // index num
- buffer.putInt(idxDataState.getIndexDataNumber()); // index data num
- buffer.put((byte)0); // related table type
- buffer.putInt(INVALID_INDEX_NUMBER); // related index num
- buffer.putInt(0); // related table definition page number
- buffer.put((byte)0); // cascade updates flag
- buffer.put((byte)0); // cascade deletes flag
- buffer.put(idx.getType()); // index type flags
- buffer.putInt(0); // unknown
+ writeDefinition(creator, idx, buffer);
}
// write index names
@@ -361,6 +350,25 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
}
}
+ protected static void writeDefinition(
+ DBMutator mutator, IndexBuilder idx, ByteBuffer buffer)
+ throws IOException
+ {
+ DBMutator.IndexDataState idxDataState = mutator.getIndexDataState(idx);
+
+ // write logical index information
+ buffer.putInt(TableImpl.MAGIC_TABLE_NUMBER); // seemingly constant magic value which matches the table def
+ buffer.putInt(idx.getIndexNumber()); // index num
+ buffer.putInt(idxDataState.getIndexDataNumber()); // index data num
+ buffer.put((byte)0); // related table type
+ buffer.putInt(INVALID_INDEX_NUMBER); // related index num
+ buffer.putInt(0); // related table definition page number
+ buffer.put((byte)0); // cascade updates flag
+ buffer.put((byte)0); // cascade deletes flag
+ buffer.put(idx.getType()); // index type flags
+ buffer.putInt(0); // unknown
+ }
+
private String withErrorContext(String msg) {
return withErrorContext(msg, getTable().getDatabase(), getName());
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
index 2039d63..9234700 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
@@ -93,6 +93,7 @@ class TableCreator extends DBMutator
return _logicalIndexCount;
}
+ @Override
public IndexDataState getIndexDataState(IndexBuilder idx) {
for(IndexDataState idxDataState : _indexDataStates) {
for(IndexBuilder curIdx : idxDataState.getIndexes()) {
@@ -108,6 +109,7 @@ class TableCreator extends DBMutator
return _indexDataStates;
}
+ @Override
public ColumnState getColumnState(ColumnBuilder col) {
return _columnStates.get(col);
}
@@ -297,99 +299,4 @@ class TableCreator extends DBMutator
(col1.getFlags() == col2.getFlags()));
}
- /**
- * Maintains additional state used during column creation.
- * @usage _advanced_class_
- */
- static final class ColumnState
- {
- private byte _umapOwnedRowNumber;
- private byte _umapFreeRowNumber;
- // we always put both usage maps on the same page
- private int _umapPageNumber;
-
- public byte getUmapOwnedRowNumber() {
- return _umapOwnedRowNumber;
- }
-
- public void setUmapOwnedRowNumber(byte newUmapOwnedRowNumber) {
- _umapOwnedRowNumber = newUmapOwnedRowNumber;
- }
-
- public byte getUmapFreeRowNumber() {
- return _umapFreeRowNumber;
- }
-
- public void setUmapFreeRowNumber(byte newUmapFreeRowNumber) {
- _umapFreeRowNumber = newUmapFreeRowNumber;
- }
-
- public int getUmapPageNumber() {
- return _umapPageNumber;
- }
-
- public void setUmapPageNumber(int newUmapPageNumber) {
- _umapPageNumber = newUmapPageNumber;
- }
- }
-
- /**
- * Maintains additional state used during index data creation.
- * @usage _advanced_class_
- */
- static final class IndexDataState
- {
- private final List<IndexBuilder> _indexes = new ArrayList<IndexBuilder>();
- private int _indexDataNumber;
- private byte _umapRowNumber;
- private int _umapPageNumber;
- private int _rootPageNumber;
-
- public IndexBuilder getFirstIndex() {
- // all indexes which have the same backing IndexDataState will have
- // equivalent columns and flags.
- return _indexes.get(0);
- }
-
- public List<IndexBuilder> getIndexes() {
- return _indexes;
- }
-
- public void addIndex(IndexBuilder idx) {
- _indexes.add(idx);
- }
-
- public int getIndexDataNumber() {
- return _indexDataNumber;
- }
-
- public void setIndexDataNumber(int newIndexDataNumber) {
- _indexDataNumber = newIndexDataNumber;
- }
-
- public byte getUmapRowNumber() {
- return _umapRowNumber;
- }
-
- public void setUmapRowNumber(byte newUmapRowNumber) {
- _umapRowNumber = newUmapRowNumber;
- }
-
- public int getUmapPageNumber() {
- return _umapPageNumber;
- }
-
- public void setUmapPageNumber(int newUmapPageNumber) {
- _umapPageNumber = newUmapPageNumber;
- }
-
- public int getRootPageNumber() {
- return _rootPageNumber;
- }
-
- public void setRootPageNumber(int newRootPageNumber) {
- _rootPageNumber = newRootPageNumber;
- }
- }
-
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
index 5c704b6..97e073c 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
@@ -113,9 +113,9 @@ public class TableImpl implements Table
/** Type of the table (either TYPE_SYSTEM or TYPE_USER) */
private final byte _tableType;
/** Number of actual indexes on the table */
- private final int _indexCount;
+ private int _indexCount;
/** Number of logical indexes for the table */
- private final int _logicalIndexCount;
+ private int _logicalIndexCount;
/** page number of the definition of this table */
private final int _tableDefPageNumber;
/** max Number of columns in the table (includes previous deletions) */
@@ -998,19 +998,8 @@ public class TableImpl implements Table
IndexImpl.writeDefinitions(creator, buffer);
}
- // write long value column usage map references
- for(ColumnBuilder lvalCol : creator.getLongValueColumns()) {
- buffer.putShort(lvalCol.getColumnNumber());
- TableCreator.ColumnState colState =
- creator.getColumnState(lvalCol);
-
- // owned pages umap (both are on same page)
- buffer.put(colState.getUmapOwnedRowNumber());
- ByteUtil.put3ByteInt(buffer, colState.getUmapPageNumber());
- // free space pages umap
- buffer.put(colState.getUmapFreeRowNumber());
- ByteUtil.put3ByteInt(buffer, colState.getUmapPageNumber());
- }
+ // column usage map references
+ ColumnImpl.writeColUsageMapDefinitions(creator, buffer);
//End of tabledef
buffer.put((byte) 0xff);
@@ -1116,6 +1105,7 @@ public class TableImpl implements Table
boolean isVarCol = column.isVariableLength();
boolean isLongVal = column.getType().isLongValue();
+ ////
// calculate how much more space we need in the table def
if(isLongVal) {
mutator.addTdefLen(10);
@@ -1126,10 +1116,12 @@ public class TableImpl implements Table
int nameByteLen = DBMutator.calculateNameLength(column.getName());
mutator.addTdefLen(nameByteLen);
+ ////
// load current table definition and add space for new info
ByteBuffer tableBuffer = loadCompleteTableDefinitionBufferForUpdate(
mutator);
+ ////
// update various bits of the table def
ByteUtil.forward(tableBuffer, 29);
tableBuffer.putShort((short)(_maxColumnCount + 1));
@@ -1171,9 +1163,7 @@ public class TableImpl implements Table
ColumnImpl.writeDefinition(mutator, column, tableBuffer);
// skip existing column names and write new name
- for(int i = 0; i < _columns.size(); ++i) {
- ByteUtil.forward(tableBuffer, tableBuffer.getShort());
- }
+ skipNames(tableBuffer, _columns.size());
ByteUtil.insertEmptyData(tableBuffer, nameByteLen);
System.out.println("FOO pre name " + tableBuffer.position());
writeName(tableBuffer, column.getName(), mutator.getCharset());
@@ -1185,9 +1175,11 @@ public class TableImpl implements Table
// allocate usage maps for the long value col
Map.Entry<Integer,Integer> umapInfo = addUsageMaps(2);
System.out.println("FOO created umap " + umapInfo);
- int umapPageNum = umapInfo.getKey();
- int umapRow1 = umapInfo.getValue();
- int umapRow2 = umapRow1 + 1;
+ 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());
@@ -1197,11 +1189,7 @@ public class TableImpl implements Table
ByteUtil.forward(tableBuffer,
(_logicalIndexCount * format.SIZE_INDEX_INFO_BLOCK));
System.out.println("FOO moved to " + tableBuffer.position());
- for(int i = 0; i < _logicalIndexCount; ++i) {
- short len = tableBuffer.getShort();
- System.out.println("FOO skipping " + len);
- ByteUtil.forward(tableBuffer, len);
- }
+ skipNames(tableBuffer, _logicalIndexCount);
// skip existing usage maps
while(tableBuffer.remaining() >= 2) {
@@ -1220,32 +1208,24 @@ public class TableImpl implements Table
System.out.println("FOO about to write " + tableBuffer.position());
umapPos = tableBuffer.position();
ByteUtil.insertEmptyData(tableBuffer, 10);
- tableBuffer.putShort(column.getColumnNumber());
-
- // owned pages umap (both are on same page)
- tableBuffer.put((byte)umapRow1);
- ByteUtil.put3ByteInt(tableBuffer, umapPageNum);
- // free space pages umap
- tableBuffer.put((byte)umapRow2);
- ByteUtil.put3ByteInt(tableBuffer, umapPageNum);
+ ColumnImpl.writeColUsageMapDefinition(
+ mutator, column, tableBuffer);
}
// sanity check the updates
- if(!mutator.validateUpdatedTdef(tableBuffer)) {
- throw new IllegalStateException(
- withErrorContext("Failed update table definition (unexpected length)"));
- }
+ validateTableDefUpdate(mutator, tableBuffer);
// 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());
-
+ ////
// now, update current TableImpl
_columns.add(newCol);
@@ -1288,89 +1268,184 @@ public class TableImpl implements Table
* Writes a index defined by the given TableMutator to this table.
* @usage _advanced_method_
*/
- protected IndexImpl mutateAddIndex(TableMutator mutator) throws IOException
+ protected IndexData mutateAddIndexData(TableMutator mutator) throws IOException
{
IndexBuilder index = mutator.getIndex();
JetFormat format = mutator.getFormat();
+ ////
// calculate how much more space we need in the table def
- mutator.addTdefLen(format.SIZE_INDEX_INFO_BLOCK);
+ mutator.addTdefLen(format.SIZE_INDEX_DEFINITION +
+ format.SIZE_INDEX_COLUMN_BLOCK);
+
+ ////
+ // load current table definition and add space for new info
+ 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);
- // FIXME
- int indexDataNumber = 0;
- boolean addingIndexData = (indexDataNumber >= _indexCount);
- if(addingIndexData) {
+ // skip columns and column names
+ ByteUtil.forward(tableBuffer,
+ (_columns.size() * format.SIZE_COLUMN_DEF_BLOCK));
+ skipNames(tableBuffer, _columns.size());
- // we are adding an index data as well
- mutator.addTdefLen(format.SIZE_INDEX_DEFINITION +
- format.SIZE_INDEX_COLUMN_BLOCK);
+ // move to end of current index datas
+ ByteUtil.forward(tableBuffer, (_indexCount *
+ format.SIZE_INDEX_COLUMN_BLOCK));
+
+ // write index data def
+ DBMutator.IndexDataState idxDataState = mutator.getIndexDataState(index);
+ 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);
+
+ ////
+ // write updated table def back to the database
+ writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator,
+ mutator.getNextPages());
+
+ ////
+ // now, update current TableImpl
+
+ for(IndexData.ColumnDescriptor iCol : newIdxData.getColumns()) {
+ _indexColumns.add(iCol.getColumn());
}
+
+ ++_indexCount;
+ _indexDatas.add(newIdxData);
+
+ completeTableMutation(tableBuffer);
+
+ return newIdxData;
+ }
+
+ /**
+ * Writes a index defined by the given TableMutator to this table.
+ * @usage _advanced_method_
+ */
+ protected IndexImpl mutateAddIndex(TableMutator mutator) throws IOException
+ {
+ IndexBuilder index = mutator.getIndex();
+ JetFormat format = mutator.getFormat();
+
+ ////
+ // calculate how much more space we need in the table def
+ mutator.addTdefLen(format.SIZE_INDEX_INFO_BLOCK);
int nameByteLen = DBMutator.calculateNameLength(index.getName());
mutator.addTdefLen(nameByteLen);
+ ////
// load current table definition and add space for new info
ByteBuffer tableBuffer = loadCompleteTableDefinitionBufferForUpdate(
mutator);
+ ////
// update various bits of the table def
ByteUtil.forward(tableBuffer, 35);
tableBuffer.putInt(_logicalIndexCount + 1);
- int numIdxData = _indexCount + (addingIndexData ? 1 : 0);
- tableBuffer.putInt(numIdxData);
// move to end of index data def blocks
tableBuffer.position(format.SIZE_TDEF_HEADER +
(_indexCount * format.SIZE_INDEX_DEFINITION));
- if(addingIndexData) {
- // 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));
- for(int i = 0; i < _columns.size(); ++i) {
- ByteUtil.forward(tableBuffer, tableBuffer.getShort());
- }
+ 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));
- if(addingIndexData) {
- // write index data def
- ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_COLUMN_BLOCK);
-
- // FIXME
- }
+ int idxDefPos = tableBuffer.position();
+ IndexImpl.writeDefinition(mutator, index, tableBuffer);
- // FIXME
+ // skip existing index names and write new name
+ skipNames(tableBuffer, _logicalIndexCount);
+ ByteUtil.insertEmptyData(tableBuffer, nameByteLen);
+ writeName(tableBuffer, index.getName(), mutator.getCharset());
- IndexImpl newIdx = null;
+ // sanity check the updates
+ validateTableDefUpdate(mutator, tableBuffer);
- // FIXME
+ // before writing the new table def, create the index
+ tableBuffer.position(idxDefPos);
+ IndexImpl newIdx = new IndexImpl(tableBuffer, _indexDatas, format);
+ newIdx.setName(index.getName());
+
+ ////
+ // write updated table def back to the database
+ writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator,
+ mutator.getNextPages());
+ ////
+ // now, update current TableImpl
- // FIXME, need to reset fkenforcer?
+ ++_logicalIndexCount;
+ _indexes.add(newIdx);
completeTableMutation(tableBuffer);
return newIdx;
}
+ private void validateTableDefUpdate(TableMutator mutator, ByteBuffer tableBuffer)
+ throws IOException
+ {
+ if(!mutator.validateUpdatedTdef(tableBuffer)) {
+ throw new IllegalStateException(
+ withErrorContext("Failed updating table definition (unexpected length)"));
+ }
+ }
+
private void completeTableMutation(ByteBuffer tableBuffer) throws IOException
{
// lastly, may need to clear table def buffer
_tableDefBufferH.possiblyInvalidate(_tableDefPageNumber, tableBuffer);
+ // update any foreign key enforcing
+ _fkEnforcer.reset();
+
// update modification count so any active RowStates can keep themselves
// up-to-date
++_modCount;
}
+ /**
+ * Skips the given number of names in the table buffer.
+ */
+ private static void skipNames(ByteBuffer tableBuffer, int count) {
+ for(int i = 0; i < count; ++i) {
+ ByteUtil.forward(tableBuffer, tableBuffer.getShort());
+ }
+ }
+
private ByteBuffer loadCompleteTableDefinitionBufferForUpdate(
TableMutator mutator)
throws IOException
@@ -1591,7 +1666,7 @@ public class TableImpl implements Table
// index umap
int indexIdx = i - 2;
- TableCreator.IndexDataState idxDataState =
+ DBMutator.IndexDataState idxDataState =
creator.getIndexDataStates().get(indexIdx);
// allocate root page for the index
@@ -1615,7 +1690,7 @@ public class TableImpl implements Table
lvalColIdx /= 2;
ColumnBuilder lvalCol = lvalCols.get(lvalColIdx);
- TableCreator.ColumnState colState =
+ DBMutator.ColumnState colState =
creator.getColumnState(lvalCol);
umapBuf.put(rowStart, UsageMap.MAP_TYPE_INLINE);
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java
index 72a1481..b9e508f 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java
@@ -43,6 +43,8 @@ public class TableMutator extends DBMutator
private int _origTdefLen;
private int _addedTdefLen;
private List<Integer> _nextPages = new ArrayList<Integer>(1);
+ private ColumnState _colState;
+ private IndexDataState _idxDataState;
public TableMutator(TableImpl table) {
super(table.getDatabase());
@@ -72,6 +74,16 @@ public class TableMutator extends DBMutator
return IndexData.COLUMN_UNUSED;
}
+ @Override
+ public ColumnState getColumnState(ColumnBuilder col) {
+ return ((col == _column) ? _colState : null);
+ }
+
+ @Override
+ public IndexDataState getIndexDataState(IndexBuilder idx) {
+ return ((idx == _index) ? _idxDataState : null);
+ }
+
int getAddedTdefLen() {
return _addedTdefLen;
}
@@ -97,6 +109,9 @@ public class TableMutator extends DBMutator
// assign column number and do some assorted column bookkeeping
short columnNumber = (short)_table.getMaxColumnCount();
_column.setColumnNumber(columnNumber);
+ if(_column.getType().isLongValue()) {
+ _colState = new ColumnState();
+ }
getPageChannel().startExclusiveWrite();
try {
@@ -115,7 +130,7 @@ public class TableMutator extends DBMutator
validateAddIndex();
// assign index number and do some assorted index bookkeeping
- int indexNumber = _table.getIndexes().size();
+ int indexNumber = _table.getLogicalIndexCount();
_index.setIndexNumber(indexNumber);
// find backing index state
@@ -126,6 +141,9 @@ public class TableMutator extends DBMutator
getPageChannel().startExclusiveWrite();
try {
+ // FIXME, maybe add index data
+ // _table.mutateAddIndexData(this);
+
return _table.mutateAddIndex(this);
} finally {
@@ -169,7 +187,7 @@ public class TableMutator extends DBMutator
if(_index == null) {
throw new IllegalArgumentException("Cannot add index with no index");
}
- if((_table.getIndexes().size() + 1) > getFormat().MAX_INDEXES_PER_TABLE) {
+ if((_table.getLogicalIndexCount() + 1) > getFormat().MAX_INDEXES_PER_TABLE) {
throw new IllegalArgumentException(
"Cannot add index to table with " +
getFormat().MAX_INDEXES_PER_TABLE + " indexes");