aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2016-06-01 01:51:55 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2016-06-01 01:51:55 +0000
commita45ac7fc22c133a110ae54a6261857f96491bff8 (patch)
treedcb8c42bfff20e03ba32a0c997ad4a730fed76af /src
parentaa9555c6679d41a7c6f9d05c7fa2178d2882dd6e (diff)
downloadjackcess-a45ac7fc22c133a110ae54a6261857f96491bff8.tar.gz
jackcess-a45ac7fc22c133a110ae54a6261857f96491bff8.zip
checkpointing some progress on add index
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@995 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java16
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/TableModBuilder.java18
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java58
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java90
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java6
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java108
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java124
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java127
8 files changed, 428 insertions, 119 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java b/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java
index 9c9f584..52a4550 100644
--- a/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java
+++ b/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java
@@ -47,6 +47,8 @@ public class IndexBuilder
private byte _flags = IndexData.UNKNOWN_INDEX_FLAG;
/** the names and orderings of the indexed columns */
private final List<Column> _columns = new ArrayList<Column>();
+ /** 0-based index number */
+ private int _indexNumber;
public IndexBuilder(String name) {
_name = name;
@@ -141,6 +143,20 @@ public class IndexBuilder
return this;
}
+ /**
+ * @usage _advanced_method_
+ */
+ public int getIndexNumber() {
+ return _indexNumber;
+ }
+
+ /**
+ * @usage _advanced_method_
+ */
+ public void setIndexNumber(int newIndexNumber) {
+ _indexNumber = newIndexNumber;
+ }
+
public void validate(Set<String> tableColNames, JetFormat format) {
DatabaseImpl.validateIdentifierName(
diff --git a/src/main/java/com/healthmarketscience/jackcess/TableModBuilder.java b/src/main/java/com/healthmarketscience/jackcess/TableModBuilder.java
index e7a654a..e776c3c 100644
--- a/src/main/java/com/healthmarketscience/jackcess/TableModBuilder.java
+++ b/src/main/java/com/healthmarketscience/jackcess/TableModBuilder.java
@@ -37,6 +37,10 @@ public class TableModBuilder
return new AddColumn(column);
}
+ public AddIndex addIndex(IndexBuilder index) {
+ return new AddIndex(index);
+ }
+
public class AddColumn
{
private ColumnBuilder _column;
@@ -50,4 +54,18 @@ public class TableModBuilder
return new TableMutator((TableImpl)_table).addColumn(_column);
}
}
+
+ public class AddIndex
+ {
+ private IndexBuilder _index;
+
+ private AddIndex(IndexBuilder index) {
+ _index = index;
+ }
+
+ public Index add() throws IOException
+ {
+ return new TableMutator((TableImpl)_table).addIndex(_index);
+ }
+ }
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java b/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java
index e3825d2..8abc390 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/DBMutator.java
@@ -22,6 +22,7 @@ import java.util.Set;
import com.healthmarketscience.jackcess.ColumnBuilder;
import com.healthmarketscience.jackcess.DataType;
+import com.healthmarketscience.jackcess.IndexBuilder;
/**
* Helper class used to maintain state during database mutation.
@@ -90,8 +91,25 @@ abstract class DBMutator
setColumnSortOrder(column);
}
- protected void validateAutoNumberColumn(Set<DataType> autoTypes,
- ColumnBuilder column)
+ protected void validateIndex(Set<String> colNames, Set<String> idxNames,
+ boolean[] foundPk, IndexBuilder index) {
+
+ index.validate(colNames, getFormat());
+ if(!idxNames.add(index.getName().toUpperCase())) {
+ throw new IllegalArgumentException("duplicate index name: " +
+ index.getName());
+ }
+ if(index.isPrimaryKey()) {
+ if(foundPk[0]) {
+ throw new IllegalArgumentException(
+ "found second primary key index: " + index.getName());
+ }
+ foundPk[0] = true;
+ }
+ }
+
+ protected static void validateAutoNumberColumn(Set<DataType> autoTypes,
+ ColumnBuilder column)
{
if(!column.getType().isMultipleAutoNumberAllowed() &&
!autoTypes.add(column.getType())) {
@@ -117,41 +135,9 @@ abstract class DBMutator
return null;
}
- /**
- * 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 abstract int getTdefPageNumber();
- public byte getUmapFreeRowNumber() {
- return _umapFreeRowNumber;
- }
-
- public void setUmapFreeRowNumber(byte newUmapFreeRowNumber) {
- _umapFreeRowNumber = newUmapFreeRowNumber;
- }
-
- public int getUmapPageNumber() {
- return _umapPageNumber;
- }
-
- public void setUmapPageNumber(int newUmapPageNumber) {
- _umapPageNumber = newUmapPageNumber;
- }
- }
+ abstract short getColumnNumber(String colName);
/**
* Maintains additional state used during column writing.
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java b/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
index 090baf0..10deea6 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
@@ -483,8 +483,20 @@ public class IndexData {
protected static void writeRowCountDefinitions(
TableCreator creator, ByteBuffer buffer)
{
+ writeRowCountDefinitions(creator, buffer, creator.getIndexCount());
+ }
+
+ /**
+ * Writes the index row count definitions into a table definition buffer.
+ * @param creator description of the indexes to write
+ * @param buffer Buffer to write to
+ * @param idxCount num indexes to write
+ */
+ protected static void writeRowCountDefinitions(
+ DBMutator creator, ByteBuffer buffer, int idxCount)
+ {
// index row counts (empty data)
- ByteUtil.forward(buffer, (creator.getIndexCount() *
+ ByteUtil.forward(buffer, (idxCount *
creator.getFormat().SIZE_INDEX_DEFINITION));
}
@@ -497,15 +509,13 @@ public class IndexData {
TableCreator creator, ByteBuffer buffer)
throws IOException
{
- ByteBuffer rootPageBuffer = creator.getPageChannel().createPageBuffer();
- writeDataPage(rootPageBuffer, NEW_ROOT_DATA_PAGE,
- creator.getTdefPageNumber(), creator.getFormat());
+ 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.getIndex();
+ IndexBuilder idx = idxDataState.getFirstIndex();
List<IndexBuilder.Column> idxColumns = idx.getColumns();
for(int i = 0; i < MAX_COLUMNS; ++i) {
@@ -553,6 +563,76 @@ public class IndexData {
}
/**
+ * Writes the index definitions into a table definition buffer.
+ * @param creator description of the indexes to write
+ * @param buffer Buffer to write to
+ */
+ protected static void writeDefinition(
+ DBMutator creator, ByteBuffer buffer,
+ TableCreator.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)
+ 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
+ columnNumber = creator.getColumnNumber(idxCol.getName());
+ if(columnNumber == COLUMN_UNUSED) {
+ // should never happen as this is validated before
+ // FIXME
+ // 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)
+ }
+
+ // FIXME
+ // 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
+ }
+
+ private static ByteBuffer createRootPageBuffer(DBMutator creator)
+ throws IOException
+ {
+ ByteBuffer rootPageBuffer = creator.getPageChannel().createPageBuffer();
+ writeDataPage(rootPageBuffer, NEW_ROOT_DATA_PAGE,
+ creator.getTdefPageNumber(), creator.getFormat());
+ return rootPageBuffer;
+ }
+
+ /**
* Prepares to add a row to this index. All constraints are checked before
* this method returns.
* <p>
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
index 41eb669..a927071 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
@@ -342,10 +342,10 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
{
// write logical index information
for(IndexBuilder idx : creator.getIndexes()) {
- TableCreator.IndexState idxState = creator.getIndexState(idx);
+ TableCreator.IndexDataState idxDataState = creator.getIndexDataState(idx);
buffer.putInt(TableImpl.MAGIC_TABLE_NUMBER); // seemingly constant magic value which matches the table def
- buffer.putInt(idxState.getIndexNumber()); // index num
- buffer.putInt(idxState.getIndexDataState().getIndexDataNumber()); // index data num
+ 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
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
index a58622f..2039d63 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java
@@ -41,8 +41,6 @@ class TableCreator extends DBMutator
private final String _name;
private final List<ColumnBuilder> _columns;
private final List<IndexBuilder> _indexes;
- private final Map<IndexBuilder,IndexState> _indexStates =
- new IdentityHashMap<IndexBuilder,IndexState>();
private final List<IndexDataState> _indexDataStates =
new ArrayList<IndexDataState>();
private final Map<ColumnBuilder,ColumnState> _columnStates =
@@ -66,6 +64,7 @@ class TableCreator extends DBMutator
return _name;
}
+ @Override
public int getTdefPageNumber() {
return _tdefPageNumber;
}
@@ -94,8 +93,15 @@ class TableCreator extends DBMutator
return _logicalIndexCount;
}
- public IndexState getIndexState(IndexBuilder idx) {
- return _indexStates.get(idx);
+ public IndexDataState getIndexDataState(IndexBuilder idx) {
+ for(IndexDataState idxDataState : _indexDataStates) {
+ for(IndexBuilder curIdx : idxDataState.getIndexes()) {
+ if(idx == curIdx) {
+ return idxDataState;
+ }
+ }
+ }
+ throw new IllegalStateException("could not find state for index");
}
public List<IndexDataState> getIndexDataStates() {
@@ -110,6 +116,16 @@ class TableCreator extends DBMutator
return _lvalCols;
}
+ @Override
+ short getColumnNumber(String colName) {
+ for(ColumnBuilder col : _columns) {
+ if(col.getName().equalsIgnoreCase(colName)) {
+ return col.getColumnNumber();
+ }
+ }
+ return IndexData.COLUMN_UNUSED;
+ }
+
/**
* @return The number of variable length columns which are not long values
* found in the list
@@ -146,13 +162,10 @@ class TableCreator extends DBMutator
}
if(hasIndexes()) {
- // sort out index numbers. for now, these values will always match
- // (until we support writing foreign key indexes)
+ // sort out index numbers (and backing index data).
for(IndexBuilder idx : _indexes) {
- IndexState idxState = new IndexState();
- idxState.setIndexNumber(_logicalIndexCount++);
- idxState.setIndexDataState(findIndexDataState(idx));
- _indexStates.put(idx, idxState);
+ idx.setIndexNumber(_logicalIndexCount++);
+ findIndexDataState(idx);
}
}
@@ -180,15 +193,16 @@ class TableCreator extends DBMutator
// search for an index which matches the given index (in terms of the
// backing data)
for(IndexDataState idxDataState : _indexDataStates) {
- if(sameIndexData(idxDataState.getIndex(), idx)) {
+ if(sameIndexData(idxDataState.getFirstIndex(), idx)) {
+ idxDataState.addIndex(idx);
return idxDataState;
}
}
// no matches found, need new index data state
IndexDataState idxDataState = new IndexDataState();
- idxDataState.setIndex(idx);
idxDataState.setIndexDataNumber(_indexCount++);
+ idxDataState.addIndex(idx);
_indexDataStates.add(idxDataState);
return idxDataState;
}
@@ -236,20 +250,9 @@ class TableCreator extends DBMutator
// now, validate the indexes
Set<String> idxNames = new HashSet<String>();
- boolean foundPk = false;
+ boolean foundPk[] = new boolean[1];
for(IndexBuilder index : _indexes) {
- index.validate(colNames, getFormat());
- if(!idxNames.add(index.getName().toUpperCase())) {
- throw new IllegalArgumentException("duplicate index name: " +
- index.getName());
- }
- if(index.isPrimaryKey()) {
- if(foundPk) {
- throw new IllegalArgumentException(
- "found second primary key index: " + index.getName());
- }
- foundPk = true;
- }
+ validateIndex(colNames, idxNames, foundPk, index);
}
}
}
@@ -295,52 +298,65 @@ class TableCreator extends DBMutator
}
/**
- * Maintains additional state used during index creation.
+ * Maintains additional state used during column creation.
* @usage _advanced_class_
*/
- static final class IndexState
+ static final class ColumnState
{
- private int _indexNumber;
- private IndexDataState _dataState;
+ private byte _umapOwnedRowNumber;
+ private byte _umapFreeRowNumber;
+ // we always put both usage maps on the same page
+ private int _umapPageNumber;
- public int getIndexNumber() {
- return _indexNumber;
+ public byte getUmapOwnedRowNumber() {
+ return _umapOwnedRowNumber;
}
- public void setIndexNumber(int newIndexNumber) {
- _indexNumber = newIndexNumber;
+ public void setUmapOwnedRowNumber(byte newUmapOwnedRowNumber) {
+ _umapOwnedRowNumber = newUmapOwnedRowNumber;
}
- public IndexDataState getIndexDataState() {
- return _dataState;
+ public byte getUmapFreeRowNumber() {
+ return _umapFreeRowNumber;
}
- public void setIndexDataState(IndexDataState dataState) {
- _dataState = dataState;
+ 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
{
- // all indexes which have the same backing IndexDataState will have
- // equivalent columns and flags. we keep a reference to the first index
- // which uses this backing index data.
- private IndexBuilder _idx;
+ private final List<IndexBuilder> _indexes = new ArrayList<IndexBuilder>();
private int _indexDataNumber;
private byte _umapRowNumber;
private int _umapPageNumber;
private int _rootPageNumber;
- public IndexBuilder getIndex() {
- return _idx;
+ 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 setIndex(IndexBuilder idx) {
- _idx = idx;
+ public void addIndex(IndexBuilder idx) {
+ _indexes.add(idx);
}
public int getIndexDataNumber() {
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
index 1a3d19f..5c704b6 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
@@ -1117,22 +1117,18 @@ public class TableImpl implements Table
boolean isLongVal = column.getType().isLongValue();
// calculate how much more space we need in the table def
- int addedLen = 0;
-
if(isLongVal) {
- addedLen += 10;
+ mutator.addTdefLen(10);
}
- addedLen += format.SIZE_COLUMN_DEF_BLOCK;
+ mutator.addTdefLen(format.SIZE_COLUMN_DEF_BLOCK);
int nameByteLen = DBMutator.calculateNameLength(column.getName());
- addedLen += nameByteLen;
+ mutator.addTdefLen(nameByteLen);
// load current table definition and add space for new info
- List<Integer> nextPages = new ArrayList<Integer>(1);
ByteBuffer tableBuffer = loadCompleteTableDefinitionBufferForUpdate(
- nextPages, addedLen);
- int origTdefLen = tableBuffer.limit();
+ mutator);
// update various bits of the table def
ByteUtil.forward(tableBuffer, 29);
@@ -1195,13 +1191,13 @@ public class TableImpl implements Table
// skip past index defs
System.out.println("FOO pre move " + tableBuffer.position());
- ByteUtil.forward(tableBuffer, (_indexDatas.size() *
+ ByteUtil.forward(tableBuffer, (_indexCount *
format.SIZE_INDEX_COLUMN_BLOCK));
System.out.println("FOO moved to " + tableBuffer.position());
ByteUtil.forward(tableBuffer,
- (_indexes.size() * format.SIZE_INDEX_INFO_BLOCK));
+ (_logicalIndexCount * format.SIZE_INDEX_INFO_BLOCK));
System.out.println("FOO moved to " + tableBuffer.position());
- for(int i = 0; i < _indexes.size(); ++i) {
+ for(int i = 0; i < _logicalIndexCount; ++i) {
short len = tableBuffer.getShort();
System.out.println("FOO skipping " + len);
ByteUtil.forward(tableBuffer, len);
@@ -1235,7 +1231,7 @@ public class TableImpl implements Table
}
// sanity check the updates
- if((origTdefLen + addedLen) != tableBuffer.limit()) {
+ if(!mutator.validateUpdatedTdef(tableBuffer)) {
throw new IllegalStateException(
withErrorContext("Failed update table definition (unexpected length)"));
}
@@ -1247,7 +1243,7 @@ public class TableImpl implements Table
// write updated table def back to the database
writeTableDefinitionBuffer(tableBuffer, _tableDefPageNumber, mutator,
- nextPages);
+ mutator.getNextPages());
// now, update current TableImpl
@@ -1276,27 +1272,119 @@ public class TableImpl implements Table
newCol.setColumnValidator(null);
}
+ // save any column properties
+ Map<String,PropertyMap.Property> colProps = column.getProperties();
+ if(colProps != null) {
+ newCol.getProperties().putAll(colProps.values());
+ getProperties().save();
+ }
+
+ completeTableMutation(tableBuffer);
+
+ return newCol;
+ }
+
+ /**
+ * 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);
+
+ // FIXME
+ int indexDataNumber = 0;
+ boolean addingIndexData = (indexDataNumber >= _indexCount);
+ if(addingIndexData) {
+
+ // we are adding an index data as well
+ mutator.addTdefLen(format.SIZE_INDEX_DEFINITION +
+ format.SIZE_INDEX_COLUMN_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());
+ }
+
+ // move to end of current index datas
+ ByteUtil.forward(tableBuffer, (_indexCount *
+ format.SIZE_INDEX_COLUMN_BLOCK));
+
+ if(addingIndexData) {
+ // write index data def
+ ByteUtil.insertEmptyData(tableBuffer, format.SIZE_INDEX_COLUMN_BLOCK);
+
+ // FIXME
+ }
+
+ // FIXME
+
+ IndexImpl newIdx = null;
+
+ // FIXME
+
+
+ // FIXME, need to reset fkenforcer?
+
+ completeTableMutation(tableBuffer);
+
+ return newIdx;
+ }
+
+ private void completeTableMutation(ByteBuffer tableBuffer) throws IOException
+ {
// lastly, may need to clear table def buffer
_tableDefBufferH.possiblyInvalidate(_tableDefPageNumber, tableBuffer);
// update modification count so any active RowStates can keep themselves
// up-to-date
++_modCount;
-
- return newCol;
}
private ByteBuffer loadCompleteTableDefinitionBufferForUpdate(
- List<Integer> nextPages, int addedLen)
+ TableMutator mutator)
throws IOException
{
// load complete table definition
ByteBuffer tableBuffer = _tableDefBufferH.setPage(getPageChannel(),
_tableDefPageNumber);
- tableBuffer = loadCompleteTableDefinitionBuffer(tableBuffer, nextPages);
+ tableBuffer = loadCompleteTableDefinitionBuffer(
+ tableBuffer, mutator.getNextPages());
// make sure the table buffer has enough room for the new info
+ int addedLen = mutator.getAddedTdefLen();
int origTdefLen = tableBuffer.getInt(8);
+ mutator.setOrigTdefLen(origTdefLen);
int newTdefLen = origTdefLen + addedLen;
System.out.println("FOO new " + newTdefLen + " add " + addedLen);
while(newTdefLen > tableBuffer.capacity()) {
@@ -1308,7 +1396,7 @@ public class TableImpl implements Table
// set new tdef length
tableBuffer.position(8);
- tableBuffer.putInt(newTdefLen);
+ tableBuffer.putInt(newTdefLen);
return tableBuffer;
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java
index 2dd2fa5..72a1481 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java
@@ -17,12 +17,16 @@ limitations under the License.
package com.healthmarketscience.jackcess.impl;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import com.healthmarketscience.jackcess.ColumnBuilder;
import com.healthmarketscience.jackcess.DataType;
+import com.healthmarketscience.jackcess.IndexBuilder;
/**
* Helper class used to maintain state during table mutation.
@@ -35,6 +39,10 @@ public class TableMutator extends DBMutator
private final TableImpl _table;
private ColumnBuilder _column;
+ private IndexBuilder _index;
+ private int _origTdefLen;
+ private int _addedTdefLen;
+ private List<Integer> _nextPages = new ArrayList<Integer>(1);
public TableMutator(TableImpl table) {
super(table.getDatabase());
@@ -45,13 +53,48 @@ public class TableMutator extends DBMutator
return _column;
}
- public ColumnImpl addColumn(ColumnBuilder column) throws IOException
- {
+ public IndexBuilder getIndex() {
+ return _index;
+ }
+
+ @Override
+ public int getTdefPageNumber() {
+ return _table.getTableDefPageNumber();
+ }
+
+ @Override
+ short getColumnNumber(String colName) {
+ for(ColumnImpl col : _table.getColumns()) {
+ if(col.getName().equalsIgnoreCase(colName)) {
+ return col.getColumnNumber();
+ }
+ }
+ return IndexData.COLUMN_UNUSED;
+ }
+
+ int getAddedTdefLen() {
+ return _addedTdefLen;
+ }
+
+ void addTdefLen(int add) {
+ _addedTdefLen += add;
+ }
+
+ void setOrigTdefLen(int len) {
+ _origTdefLen = len;
+ }
+
+ List<Integer> getNextPages() {
+ return _nextPages;
+ }
+
+ public ColumnImpl addColumn(ColumnBuilder column) throws IOException {
+
_column = column;
validateAddColumn();
- // assign column numbers and do some assorted column bookkeeping
+ // assign column number and do some assorted column bookkeeping
short columnNumber = (short)_table.getMaxColumnCount();
_column.setColumnNumber(columnNumber);
@@ -65,8 +108,38 @@ public class TableMutator extends DBMutator
}
}
- private void validateAddColumn()
- {
+ public IndexImpl addIndex(IndexBuilder index) throws IOException {
+
+ _index = index;
+
+ validateAddIndex();
+
+ // assign index number and do some assorted index bookkeeping
+ int indexNumber = _table.getIndexes().size();
+ _index.setIndexNumber(indexNumber);
+
+ // find backing index state
+
+ // FIXME, writeme!
+
+
+ getPageChannel().startExclusiveWrite();
+ try {
+
+ return _table.mutateAddIndex(this);
+
+ } finally {
+ getPageChannel().finishWrite();
+ }
+ }
+
+ boolean validateUpdatedTdef(ByteBuffer tableBuffer) {
+ // sanity check the updates
+ return((_origTdefLen + _addedTdefLen) == tableBuffer.limit());
+ }
+
+ private void validateAddColumn() {
+
if(_column == null) {
throw new IllegalArgumentException("Cannot add column with no column");
}
@@ -76,12 +149,8 @@ public class TableMutator extends DBMutator
getFormat().MAX_COLUMNS_PER_TABLE + " columns");
}
- Set<String> colNames = new HashSet<String>();
- // next, validate the column definitions
- for(ColumnImpl column : _table.getColumns()) {
- colNames.add(column.getName().toUpperCase());
- }
-
+ Set<String> colNames = getColumnNames();
+ // next, validate the column definition
validateColumn(colNames, _column);
if(_column.isAutoNumber()) {
@@ -94,4 +163,40 @@ public class TableMutator extends DBMutator
validateAutoNumberColumn(autoTypes, _column);
}
}
+
+ private void validateAddIndex() {
+
+ if(_index == null) {
+ throw new IllegalArgumentException("Cannot add index with no index");
+ }
+ if((_table.getIndexes().size() + 1) > getFormat().MAX_INDEXES_PER_TABLE) {
+ throw new IllegalArgumentException(
+ "Cannot add index to table with " +
+ getFormat().MAX_INDEXES_PER_TABLE + " indexes");
+ }
+
+ boolean foundPk[] = new boolean[1];
+ Set<String> idxNames = getIndexNames(foundPk);
+ // next, validate the index definition
+ validateIndex(getColumnNames(), idxNames, foundPk, _index);
+ }
+
+ private Set<String> getColumnNames() {
+ Set<String> colNames = new HashSet<String>();
+ for(ColumnImpl column : _table.getColumns()) {
+ colNames.add(column.getName().toUpperCase());
+ }
+ return colNames;
+ }
+
+ private Set<String> getIndexNames(boolean[] foundPk) {
+ Set<String> idxNames = new HashSet<String>();
+ for(IndexImpl index : _table.getIndexes()) {
+ idxNames.add(index.getName().toUpperCase());
+ if(index.isPrimaryKey()) {
+ foundPk[0] = true;
+ }
+ }
+ return idxNames;
+ }
}