import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
-import org.apache.commons.collections.bidimap.DualHashBidiMap;
+
import org.apache.commons.collections.BidiMap;
+import org.apache.commons.collections.bidimap.DualHashBidiMap;
import org.apache.commons.lang.builder.CompareToBuilder;
/**
private int _indexNumber;
/** Index name */
private String _name;
+ /** is this index a primary key */
+ private boolean _primaryKey;
public Index(int parentPageNumber, PageChannel channel, JetFormat format) {
_parentPageNumber = parentPageNumber;
public void setName(String name) {
_name = name;
}
+
+ public boolean isPrimaryKey() {
+ return _primaryKey;
+ }
+
+ public void setPrimaryKey(boolean newPrimaryKey) {
+ _primaryKey = newPrimaryKey;
+ }
+
+ /**
+ * Returns the Columns for this index (unmodifiable)
+ */
+ public Collection<Column> getColumns() {
+ return Collections.unmodifiableCollection(_columns.keySet());
+ }
public void update() throws IOException {
_pageChannel.writePage(write(), _pageNumber);
}
-
+
/**
* Write this index out to a buffer
*/
rtn.append("\tName: " + _name);
rtn.append("\n\tNumber: " + _indexNumber);
rtn.append("\n\tPage number: " + _pageNumber);
+ rtn.append("\n\tIs Primary Key: " + _primaryKey);
rtn.append("\n\tColumns: " + _columns);
rtn.append("\n\tEntries: " + _entries);
rtn.append("\n\n");
public final int OFFSET_NEXT_TABLE_DEF_PAGE;
public final int OFFSET_NUM_ROWS;
public final int OFFSET_TABLE_TYPE;
+ public final int OFFSET_MAX_COLS;
+ public final int OFFSET_NUM_VAR_COLS;
public final int OFFSET_NUM_COLS;
public final int OFFSET_NUM_INDEXES;
public final int OFFSET_OWNED_PAGES;
public final int OFFSET_FREE_SPACE_PAGES;
public final int OFFSET_INDEX_DEF_BLOCK;
+ public final int OFFSET_INDEX_NUMBER_BLOCK;
+
public final int OFFSET_COLUMN_TYPE;
public final int OFFSET_COLUMN_NUMBER;
public final int OFFSET_COLUMN_PRECISION;
OFFSET_NEXT_TABLE_DEF_PAGE = defineOffsetNextTableDefPage();
OFFSET_NUM_ROWS = defineOffsetNumRows();
OFFSET_TABLE_TYPE = defineOffsetTableType();
+ OFFSET_MAX_COLS = defineOffsetMaxCols();
+ OFFSET_NUM_VAR_COLS = defineOffsetNumVarCols();
OFFSET_NUM_COLS = defineOffsetNumCols();
OFFSET_NUM_INDEXES = defineOffsetNumIndexes();
OFFSET_OWNED_PAGES = defineOffsetOwnedPages();
OFFSET_FREE_SPACE_PAGES = defineOffsetFreeSpacePages();
OFFSET_INDEX_DEF_BLOCK = defineOffsetIndexDefBlock();
+ OFFSET_INDEX_NUMBER_BLOCK = defineOffsetIndexNumberBlock();
+
OFFSET_COLUMN_TYPE = defineOffsetColumnType();
OFFSET_COLUMN_NUMBER = defineOffsetColumnNumber();
OFFSET_COLUMN_PRECISION = defineOffsetColumnPrecision();
protected abstract int defineOffsetNextTableDefPage();
protected abstract int defineOffsetNumRows();
protected abstract int defineOffsetTableType();
+ protected abstract int defineOffsetMaxCols();
+ protected abstract int defineOffsetNumVarCols();
protected abstract int defineOffsetNumCols();
protected abstract int defineOffsetNumIndexes();
protected abstract int defineOffsetOwnedPages();
protected abstract int defineOffsetFreeSpacePages();
protected abstract int defineOffsetIndexDefBlock();
+ protected abstract int defineOffsetIndexNumberBlock();
+
protected abstract int defineOffsetColumnType();
protected abstract int defineOffsetColumnNumber();
protected abstract int defineOffsetColumnPrecision();
protected int defineOffsetNextTableDefPage() { return 4; }
protected int defineOffsetNumRows() { return 16; }
protected int defineOffsetTableType() { return 40; }
+ protected int defineOffsetMaxCols() { return 41; }
+ protected int defineOffsetNumVarCols() { return 43; }
protected int defineOffsetNumCols() { return 45; }
protected int defineOffsetNumIndexes() { return 51; }
protected int defineOffsetOwnedPages() { return 55; }
protected int defineOffsetFreeSpacePages() { return 59; }
protected int defineOffsetIndexDefBlock() { return 63; }
+
+ protected int defineOffsetIndexNumberBlock() { return 52; }
protected int defineOffsetColumnType() { return 0; }
protected int defineOffsetColumnNumber() { return 5; }
private short _rowsLeftOnPage = 0;
/** Offset index in the buffer of the start of the current row */
private short _rowStart;
+ /** max Number of columns in the table (includes previous deletions) */
+ private short _maxColumnCount;
+ /** max Number of variable columns in the table */
+ private short _varColumnCount;
+ /** Number of fixed columns in the table */
+ private short _fixedColumnCount;
/** Number of columns in the table */
private short _columnCount;
/** Format of the database that contains this table */
":\n" + ByteUtil.toHexString(_buffer, _buffer.position(),
_buffer.limit() - _buffer.position()));
}
- short columnCount = _buffer.getShort(); //Number of columns in this table
+ 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);
- _buffer.position(_buffer.limit() - nullMask.byteSize() - 2);
- short varColumnCount = _buffer.getShort(); //Number of variable length columns
- byte[][] varColumnData = new byte[varColumnCount][]; //Holds variable length column data
-
- //Read in the offsets of each of the variable length columns
- short[] varColumnOffsets = new short[varColumnCount];
- _buffer.position(_buffer.position() - 2 - (varColumnCount * 2) - 2);
- short lastVarColumnStart = _buffer.getShort();
- for (short i = 0; i < varColumnCount; i++) {
- varColumnOffsets[i] = _buffer.getShort();
+
+ short varColumnCount = 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) {
+ _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
+
+ //Read in the offsets of each of the variable length columns
+ varColumnOffsets = new short[varColumnCount];
+ _buffer.position(_buffer.position() - 2 - (varColumnCount * 2) - 2);
+ lastVarColumnStart = _buffer.getShort();
+ for (short i = 0; i < varColumnCount; i++) {
+ varColumnOffsets[i] = _buffer.getShort();
+ }
}
+
//Read in the actual data for each of the variable length columns
for (short i = 0; i < varColumnCount; i++) {
}
_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);
_columnCount = _buffer.getShort(_format.OFFSET_NUM_COLS);
_indexCount = _buffer.getInt(_format.OFFSET_NUM_INDEXES);
for (int i = 0; i < _columnCount; i++) {
column = new Column(_buffer,
offset + i * _format.SIZE_COLUMN_HEADER, _pageChannel, _format);
+ if(!column.isVariableLength()) {
+ _fixedColumnCount++;
+ }
_columns.add(column);
}
offset += _columnCount * _format.SIZE_COLUMN_HEADER;
offset += nameLength;
}
Collections.sort(_columns);
-
- for (int i = 0; i < _indexCount; i++) {
- _buffer.getInt(); //Forward past Unknown
- ((Index) _indexes.get(i)).read(_buffer, _columns);
- }
+
+ int idxOffset = _buffer.position();
+ _buffer.position(idxOffset +
+ (_format.OFFSET_INDEX_NUMBER_BLOCK * _indexCount));
for (int i = 0; i < _indexCount; i++) {
+ Index index = _indexes.get(i);
_buffer.getInt(); //Forward past Unknown
- ((Index) _indexes.get(i)).setIndexNumber(_buffer.getInt());
- _buffer.position(_buffer.position() + 20);
+ index.setIndexNumber(_buffer.getInt());
+ _buffer.position(_buffer.position() + 15);
+ index.setPrimaryKey(_buffer.get() == 1);
+ _buffer.position(_buffer.position() + 4);
}
- Collections.sort(_indexes);
for (int i = 0; i < _indexCount; i++) {
byte[] nameBytes = new byte[_buffer.getShort()];
_buffer.get(nameBytes);
((Index) _indexes.get(i)).setName(_format.CHARSET.decode(ByteBuffer.wrap(
nameBytes)).toString());
}
+ int idxEndOffset = _buffer.position();
+ Collections.sort(_indexes);
+
+ // go back to index column info after sorting
+ _buffer.position(idxOffset);
+ for (int i = 0; i < _indexCount; i++) {
+ _buffer.getInt(); //Forward past Unknown
+ ((Index) _indexes.get(i)).read(_buffer, _columns);
+ }
+
+ // reset to end of index info
+ _buffer.position(idxEndOffset);
}
/**
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
}
assertTrue(!bogusFile.exists());
}
+
+ public void testPrimaryKey() throws Exception {
+ Table table = open().getTable("Table1");
+ Map<String, Boolean> foundPKs = new HashMap<String, Boolean>();
+ for(Index index : table.getIndexes()) {
+ System.out.println(index);
+ foundPKs.put(index.getColumns().iterator().next().getName(),
+ index.isPrimaryKey());
+ }
+ Map<String, Boolean> expectedPKs = new HashMap<String, Boolean>();
+ expectedPKs.put("A", Boolean.TRUE);
+ expectedPKs.put("B", Boolean.FALSE);
+ assertEquals(expectedPKs, foundPKs);
+ }
private int countRows(Table table) throws Exception {
table.reset();