BooleanField
provides a wrapper for boolean data which is read or
* written to a Record.
*/
-public final class BooleanField extends Field {
+public final class BooleanField extends PrimitiveField {
/**
* Minimum boolean field value (FALSE)
@@ -56,14 +56,9 @@ public final class BooleanField extends Field {
this(b, false);
}
- @Override
- boolean isNull() {
- return value == 0;
- }
-
@Override
void setNull() {
- checkImmutable();
+ super.setNull();
value = 0;
}
@@ -84,7 +79,7 @@ public final class BooleanField extends Field {
@Override
public void setBooleanValue(boolean b) {
- checkImmutable();
+ updatingPrimitiveValue();
this.value = b ? (byte) 1 : (byte) 0;
}
@@ -100,7 +95,7 @@ public final class BooleanField extends Field {
@Override
int read(Buffer buf, int offset) throws IOException {
- checkImmutable();
+ updatingPrimitiveValue();
value = buf.getByte(offset);
return offset + 1;
}
@@ -115,11 +110,6 @@ public final class BooleanField extends Field {
return BOOLEAN_TYPE;
}
- @Override
- public String toString() {
- return "BooleanField: " + Boolean.toString(getBooleanValue());
- }
-
@Override
public String getValueAsString() {
return Boolean.toString(getBooleanValue());
@@ -127,11 +117,10 @@ public final class BooleanField extends Field {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof BooleanField)) {
+ if (!(obj instanceof BooleanField)) {
return false;
}
- BooleanField otherField = (BooleanField) obj;
- return otherField.value == value;
+ return ((BooleanField) obj).value == value;
}
@Override
@@ -180,10 +169,10 @@ public final class BooleanField extends Field {
@Override
public void setBinaryData(byte[] bytes) {
- checkImmutable();
if (bytes.length != 1) {
throw new IllegalFieldAccessException();
}
+ updatingPrimitiveValue();
value = bytes[0];
}
diff --git a/Ghidra/Framework/DB/src/main/java/db/ByteField.java b/Ghidra/Framework/DB/src/main/java/db/ByteField.java
index f208e19aef..19d9d3f8e6 100644
--- a/Ghidra/Framework/DB/src/main/java/db/ByteField.java
+++ b/Ghidra/Framework/DB/src/main/java/db/ByteField.java
@@ -23,7 +23,7 @@ import db.buffers.DataBuffer;
* ByteField
provides a wrapper for single signed byte data
* which is read or written to a Record.
*/
-public final class ByteField extends Field {
+public final class ByteField extends PrimitiveField {
/**
* Minimum byte field value
@@ -71,14 +71,9 @@ public final class ByteField extends Field {
value = b;
}
- @Override
- boolean isNull() {
- return value == 0;
- }
-
@Override
void setNull() {
- checkImmutable();
+ super.setNull();
value = 0;
}
@@ -89,7 +84,7 @@ public final class ByteField extends Field {
@Override
public void setByteValue(byte value) {
- checkImmutable();
+ updatingPrimitiveValue();
this.value = value;
}
@@ -105,7 +100,7 @@ public final class ByteField extends Field {
@Override
int read(Buffer buf, int offset) throws IOException {
- checkImmutable();
+ updatingPrimitiveValue();
value = buf.getByte(offset);
return offset + 1;
}
@@ -120,11 +115,6 @@ public final class ByteField extends Field {
return BYTE_TYPE;
}
- @Override
- public String toString() {
- return "Byte: " + Byte.toString(value);
- }
-
@Override
public String getValueAsString() {
return "0x" + Integer.toHexString(value & 0xff);
@@ -132,7 +122,7 @@ public final class ByteField extends Field {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof ByteField)) {
+ if (!(obj instanceof ByteField)) {
return false;
}
return ((ByteField) obj).value == value;
@@ -189,10 +179,10 @@ public final class ByteField extends Field {
@Override
public void setBinaryData(byte[] bytes) {
- checkImmutable();
if (bytes.length != 1) {
throw new IllegalFieldAccessException();
}
+ updatingPrimitiveValue();
value = bytes[0];
}
diff --git a/Ghidra/Framework/DB/src/main/java/db/DBRecord.java b/Ghidra/Framework/DB/src/main/java/db/DBRecord.java
index a3945dd6d4..3168948040 100644
--- a/Ghidra/Framework/DB/src/main/java/db/DBRecord.java
+++ b/Ghidra/Framework/DB/src/main/java/db/DBRecord.java
@@ -52,6 +52,10 @@ public class DBRecord implements ComparableField
is an abstract data wrapper for use with Records.
+ * Field
is an abstract data wrapper for use with Records.
* Note that when comparing two Field instances both must be of the same
- * class.
+ * class.
Fields may take on a null state. In the case of {@link FixedField} + * and {@link PrimitiveField} this state is distinct from value and only + * applies when used for a sparse column within a {@link SparseRecord}. + * In this sparse column situation the {@link SparseRecord#setField(int, Field)} + * method may be passed a null Field argument. Sparse columns with a + * null value/state will not be indexed within a {@link Table}. * *
Stored Schema Field Type Encoding:
* @@ -376,6 +383,13 @@ public abstract class Field implements ComparableFixedField
provides an abstract implementation of a fixed-length
- * binary field.
+ * FixedField
provides an abstract implementation of an unsigned fixed-length
+ * field whose value is specified with a byte-array. This field behaves similar to a
+ * {@link PrimitiveField} in that a null "state" (see {@link #isNull()}) is supported for
+ * sparse record column use with a zero (0) value. Unlike a variable-length
+ * {@link BinaryField} a null "value" (i.e., data byte array) is not permitted.
+ * IntField
provides a wrapper for 4-byte signed integer data
* which is read or written to a Record.
*/
-public final class IntField extends Field {
+public final class IntField extends PrimitiveField {
/**
* Minimum integer field value
@@ -71,14 +71,9 @@ public final class IntField extends Field {
value = i;
}
- @Override
- boolean isNull() {
- return value == 0;
- }
-
@Override
void setNull() {
- checkImmutable();
+ super.setNull();
value = 0;
}
@@ -89,7 +84,7 @@ public final class IntField extends Field {
@Override
public void setIntValue(int value) {
- checkImmutable();
+ updatingPrimitiveValue();
this.value = value;
}
@@ -105,7 +100,7 @@ public final class IntField extends Field {
@Override
int read(Buffer buf, int offset) throws IOException {
- checkImmutable();
+ updatingPrimitiveValue();
value = buf.getInt(offset);
return offset + 4;
}
@@ -120,11 +115,6 @@ public final class IntField extends Field {
return INT_TYPE;
}
- @Override
- public String toString() {
- return "IntField: " + Integer.toString(value);
- }
-
@Override
public String getValueAsString() {
return "0x" + Integer.toHexString(value);
@@ -132,7 +122,7 @@ public final class IntField extends Field {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof IntField)) {
+ if (!(obj instanceof IntField)) {
return false;
}
return ((IntField) obj).value == value;
@@ -190,10 +180,10 @@ public final class IntField extends Field {
@Override
public void setBinaryData(byte[] bytes) {
- checkImmutable();
if (bytes.length != 4) {
throw new IllegalFieldAccessException();
}
+ updatingPrimitiveValue();
value = ((bytes[0] & 0xff) << 24) | ((bytes[1] & 0xff) << 16) | ((bytes[2] & 0xff) << 8) |
(bytes[3] & 0xff);
}
diff --git a/Ghidra/Framework/DB/src/main/java/db/LongField.java b/Ghidra/Framework/DB/src/main/java/db/LongField.java
index 94bb7f2ef2..318d38bc24 100644
--- a/Ghidra/Framework/DB/src/main/java/db/LongField.java
+++ b/Ghidra/Framework/DB/src/main/java/db/LongField.java
@@ -23,7 +23,7 @@ import db.buffers.DataBuffer;
* LongField
provides a wrapper for 8-byte signed long data
* which is read or written to a Record.
*/
-public final class LongField extends Field {
+public final class LongField extends PrimitiveField {
/**
* Minimum long field value
@@ -71,14 +71,9 @@ public final class LongField extends Field {
value = l;
}
- @Override
- boolean isNull() {
- return value == 0;
- }
-
@Override
void setNull() {
- checkImmutable();
+ super.setNull();
value = 0;
}
@@ -89,7 +84,7 @@ public final class LongField extends Field {
@Override
public void setLongValue(long value) {
- checkImmutable();
+ updatingPrimitiveValue();
this.value = value;
}
@@ -105,7 +100,7 @@ public final class LongField extends Field {
@Override
int read(Buffer buf, int offset) throws IOException {
- checkImmutable();
+ updatingPrimitiveValue();
value = buf.getLong(offset);
return offset + 8;
}
@@ -120,11 +115,6 @@ public final class LongField extends Field {
return LONG_TYPE;
}
- @Override
- public String toString() {
- return "LongField: " + Long.toString(value);
- }
-
@Override
public String getValueAsString() {
return "0x" + Long.toHexString(value);
@@ -132,7 +122,7 @@ public final class LongField extends Field {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof LongField)) {
+ if (!(obj instanceof LongField)) {
return false;
}
return ((LongField) obj).value == value;
@@ -184,10 +174,10 @@ public final class LongField extends Field {
@Override
public void setBinaryData(byte[] bytes) {
- checkImmutable();
if (bytes.length != 8) {
throw new IllegalFieldAccessException();
}
+ updatingPrimitiveValue();
value = (((long) bytes[0] & 0xff) << 56) | (((long) bytes[1] & 0xff) << 48) |
(((long) bytes[2] & 0xff) << 40) | (((long) bytes[3] & 0xff) << 32) |
(((long) bytes[4] & 0xff) << 24) | (((long) bytes[5] & 0xff) << 16) |
diff --git a/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java b/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java
new file mode 100644
index 0000000000..384edc5980
--- /dev/null
+++ b/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java
@@ -0,0 +1,74 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package db;
+
+/**
+ * PrimitiveField
provides a base implementation for
+ * all primitive value {@link Field}s.
+ * ShortField
provides a wrapper for 2-byte signed short data
* which is read or written to a Record.
*/
-public final class ShortField extends Field {
+public final class ShortField extends PrimitiveField {
/**
* Minimum short field value
@@ -71,14 +71,9 @@ public final class ShortField extends Field {
value = s;
}
- @Override
- boolean isNull() {
- return value == 0;
- }
-
@Override
void setNull() {
- checkImmutable();
+ super.setNull();
value = 0;
}
@@ -89,7 +84,7 @@ public final class ShortField extends Field {
@Override
public void setShortValue(short value) {
- checkImmutable();
+ updatingPrimitiveValue();
this.value = value;
}
@@ -105,7 +100,7 @@ public final class ShortField extends Field {
@Override
int read(Buffer buf, int offset) throws IOException {
- checkImmutable();
+ updatingPrimitiveValue();
value = buf.getShort(offset);
return offset + 2;
}
@@ -120,11 +115,6 @@ public final class ShortField extends Field {
return SHORT_TYPE;
}
- @Override
- public String toString() {
- return "ShortField: " + Short.toString(value);
- }
-
@Override
public String getValueAsString() {
return "0x" + Integer.toHexString(value & 0xffff);
@@ -132,7 +122,7 @@ public final class ShortField extends Field {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof ShortField)) {
+ if (!(obj instanceof ShortField)) {
return false;
}
return ((ShortField) obj).value == value;
@@ -189,10 +179,10 @@ public final class ShortField extends Field {
@Override
public void setBinaryData(byte[] bytes) {
- checkImmutable();
if (bytes.length != 2) {
throw new IllegalFieldAccessException();
}
+ updatingPrimitiveValue();
value = (short) (((bytes[0] & 0xff) << 8) | (bytes[1] & 0xff));
}
diff --git a/Ghidra/Framework/DB/src/main/java/db/SparseRecord.java b/Ghidra/Framework/DB/src/main/java/db/SparseRecord.java
index b9011e2e96..bcf1cabad9 100644
--- a/Ghidra/Framework/DB/src/main/java/db/SparseRecord.java
+++ b/Ghidra/Framework/DB/src/main/java/db/SparseRecord.java
@@ -102,6 +102,18 @@ public class SparseRecord extends DBRecord {
return oldSparse != newSparse;
}
+ @Override
+ public void setField(int colIndex, Field value) {
+ if (value == null) {
+ if (!schema.isSparseColumn(colIndex)) {
+ throw new IllegalArgumentException("null value supported for sparse column only");
+ }
+ value = getField(colIndex).newField();
+ value.setNull();
+ }
+ super.setField(colIndex, value);
+ }
+
@Override
public void setLongValue(int colIndex, long value) {
if (changeInSparseStorage(colIndex, value)) {
diff --git a/Ghidra/Framework/DB/src/main/java/db/StringField.java b/Ghidra/Framework/DB/src/main/java/db/StringField.java
index d064e7ad06..e7cb1c0cd2 100644
--- a/Ghidra/Framework/DB/src/main/java/db/StringField.java
+++ b/Ghidra/Framework/DB/src/main/java/db/StringField.java
@@ -161,7 +161,7 @@ public final class StringField extends Field {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof StringField)) {
+ if (!(obj instanceof StringField)) {
return false;
}
StringField f = (StringField) obj;
diff --git a/Ghidra/Framework/DB/src/test/java/db/DBFixedKeySparseIndexedTableTest.java b/Ghidra/Framework/DB/src/test/java/db/DBFixedKeySparseIndexedTableTest.java
index bed54e6508..e09dba8f47 100644
--- a/Ghidra/Framework/DB/src/test/java/db/DBFixedKeySparseIndexedTableTest.java
+++ b/Ghidra/Framework/DB/src/test/java/db/DBFixedKeySparseIndexedTableTest.java
@@ -32,10 +32,17 @@ public class DBFixedKeySparseIndexedTableTest extends AbstractGenericTest {
private static final int BUFFER_SIZE = 2048;// keep small for chained buffer testing
private static final int CACHE_SIZE = 4 * 1024 * 1024;
- private static final int ITER_REC_CNT = 1000;
-
private static final String table1Name = "TABLE1";
+ private static final int BOOLEAN_COL = 0; // not indexed
+ private static final int BYTE_COL = 1; // not indexed
+ private static final int INT_COL = 2;
+ private static final int SHORT_COL = 3;
+ private static final int LONG_COL = 4;
+ private static final int STR_COL = 5;
+ private static final int BIN_COL = 6;
+ private static final int FIXED10_COL = 7;
+
private File testDir;
private static final String dbName = "test";
@@ -125,9 +132,7 @@ public class DBFixedKeySparseIndexedTableTest extends AbstractGenericTest {
assertTrue(!iter.hasNext());
}
- @Test
- public void testFixedKeyIterator() throws IOException {
-
+ private void populateFixedKeySparseRecords() throws IOException {
long txId = dbh.startTransaction();
Table table =
DBTestUtils.createFixedKeyTable(dbh, table1Name, DBTestUtils.ALL_TYPES, true, true);
@@ -136,65 +141,239 @@ public class DBFixedKeySparseIndexedTableTest extends AbstractGenericTest {
assertTrue(schema.isSparseColumn(i));
}
+// DBRecord r1 = schema.createRecord(FixedField10.ZERO_VALUE);
+// System.out.println("Sparse record test columns:");
+// for (Field f : r1.getFields()) {
+// System.out.println(" " + f.toString());
+// }
+
int cnt = schema.getFieldCount();
- for (int i = 0; i < cnt; i++) {
+
+// System.out.println("Write sparse records:");
+ for (int i = 0; i < cnt + 1; i++) {
Field key = new FixedField10(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, (byte) i });
DBRecord r = schema.createRecord(key);
- Field f = schema.getField(i);
- if (f.isVariableLength()) {
- f.setBinaryData(new byte[] { 'X' });
+ for (Field f : r.getFields()) {
+ // all fields correspond to a sparse columns and
+ // should have a null state initially
+ assertTrue(f.isNull());
}
- else {
- f = f.getMaxValue();
- }
- r.setField(i, f);
- int nextCol = i + 1;
- if (nextCol < cnt) {
- f = schema.getField(nextCol);
+ if (i < cnt) {
+ Field f = schema.getField(i);
+ if (f.isVariableLength()) {
+ f.setBinaryData(new byte[] { 'X' });
+ }
+ else {
+ f = f.getMaxValue();
+ }
+ r.setField(i, f);
+ }
+
+ // set min value all fields before i
+ for (int m = 0; m < i; m++) {
+ Field f = schema.getField(m);
if (f.isVariableLength()) {
f.setBinaryData(new byte[] { 'x' });
}
else {
f = f.getMinValue();
}
- r.setField(nextCol, f);
+ r.setField(m, f);
}
+// // NOTE: sparse columns default to a null state if not explicitly set
+
+// System.out.println("-> " + r.getField(2) + ", " + r.getField(6).toString() + ", " +
+// r.getField(7).toString());
+
table.putRecord(r);
}
+ assertEquals(cnt + 1, table.getRecordCount());
+
dbh.endTransaction(txId, true);
saveAsAndReopen(dbName);
+ }
- table = dbh.getTable(table1Name);
- assertEquals(cnt, table.getRecordCount());
+ @Test
+ public void testFixedKeyIterator() throws IOException {
+
+ populateFixedKeySparseRecords();
+
+ Table table = dbh.getTable(table1Name);
+ int cnt = table.getSchema().getFieldCount();
+ assertEquals(8, cnt); // testing 8 field types as sparse columns in 9 data records
+ assertEquals(cnt + 1, table.getRecordCount());
// see DBTestUtils for schema column types
- // Index does not track null/zero values
- assertEquals(0, table.findRecords(IntField.ZERO_VALUE, 2).length);
- assertEquals(0, table.findRecords(ShortField.ZERO_VALUE, 3).length);
- assertEquals(0, table.findRecords(LongField.ZERO_VALUE, 4).length);
- assertEquals(0, table.findRecords(StringField.NULL_VALUE, 5).length);
- assertEquals(0, table.findRecords(new BinaryField(), 6).length);
- assertEquals(0, table.findRecords(FixedField10.ZERO_VALUE, 7).length);
+// System.out.println("Read sparse records:");
+ int recordIndex = 0;
+ RecordIterator iterator = table.iterator();
+ while (iterator.hasNext()) {
+ DBRecord r = iterator.next();
- assertEquals(1, table.findRecords(IntField.MAX_VALUE, 2).length);
- assertEquals(1, table.findRecords(ShortField.MAX_VALUE, 3).length);
- assertEquals(1, table.findRecords(LongField.MAX_VALUE, 4).length);
- assertEquals(1, table.findRecords(new StringField("X"), 5).length);
- assertEquals(1, table.findRecords(new BinaryField(new byte[] { 'X' }), 6).length);
- assertEquals(1, table.findRecords(FixedField10.MAX_VALUE, 7).length);
+ Field key =
+ new FixedField10(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, (byte) recordIndex });
+ assertEquals(key, r.getKeyField());
- assertEquals(1, table.findRecords(IntField.MIN_VALUE, 2).length);
- assertEquals(1, table.findRecords(ShortField.MIN_VALUE, 3).length);
- assertEquals(1, table.findRecords(LongField.MIN_VALUE, 4).length);
- assertEquals(1, table.findRecords(new StringField("x"), 5).length);
- assertEquals(1, table.findRecords(new BinaryField(new byte[] { 'x' }), 6).length);
- assertEquals(0, table.findRecords(FixedField10.MIN_VALUE, 7).length); // same as zero/null
+// System.out.println("<- " + r.getField(2) + ", " + r.getField(6).toString() + ", " +
+// r.getField(7).toString());
+
+ // recordIndex used as walking columnIndex
+ int columnIndex = recordIndex;
+
+ if (columnIndex < cnt) {
+ Field f = r.getField(columnIndex);
+ if (f.isVariableLength()) {
+ Field f2 = f.newField();
+ f2.setBinaryData(new byte[] { 'X' });
+ assertEquals(f2, f);
+ }
+ else {
+ assertEquals(f.getMaxValue(), f);
+ }
+ }
+
+ // set min value all fields before i
+ for (int m = 0; m < columnIndex; m++) {
+ Field f = r.getField(m);
+ if (f.isVariableLength()) {
+ Field f2 = f.newField();
+ f2.setBinaryData(new byte[] { 'x' });
+ assertEquals(f2, f);
+ }
+ else {
+ assertEquals(f.getMinValue(), f);
+ }
+ }
+
+ for (int n = columnIndex + 1; n < cnt; n++) {
+ Field f = r.getField(n);
+ assertTrue(f.isNull());
+ }
+
+ ++recordIndex;
+ }
+
+ }
+
+ @Test
+ public void testFixedKeySparseIndex() throws IOException {
+
+ populateFixedKeySparseRecords();
+
+ Table table = dbh.getTable(table1Name);
+ int cnt = table.getSchema().getFieldCount();
+ assertEquals(8, cnt); // testing 8 field types as sparse columns in 9 data records
+ assertEquals(cnt + 1, table.getRecordCount());
+
+ // see DBTestUtils for schema column types
+
+ // null state/value not indexed (corresponds to a 0 primitive value)
+ assertEquals(0, table.findRecords(IntField.ZERO_VALUE, INT_COL).length);
+ assertEquals(0, table.findRecords(ShortField.ZERO_VALUE, SHORT_COL).length);
+ assertEquals(0, table.findRecords(LongField.ZERO_VALUE, LONG_COL).length);
+ assertEquals(0, table.findRecords(StringField.NULL_VALUE, STR_COL).length);
+ assertEquals(0, table.findRecords(new BinaryField(), BIN_COL).length);
+ assertEquals(1, table.findRecords(FixedField10.ZERO_VALUE, FIXED10_COL).length); // last record has a FixedField10.ZERO_VALUE
+
+ assertEquals(1, table.findRecords(IntField.MAX_VALUE, INT_COL).length);
+ assertEquals(1, table.findRecords(ShortField.MAX_VALUE, SHORT_COL).length);
+ assertEquals(1, table.findRecords(LongField.MAX_VALUE, LONG_COL).length);
+ assertEquals(1, table.findRecords(new StringField("X"), STR_COL).length);
+ assertEquals(1, table.findRecords(new BinaryField(new byte[] { 'X' }), BIN_COL).length);
+ assertEquals(1, table.findRecords(FixedField10.MAX_VALUE, FIXED10_COL).length);
+
+ assertEquals(6, table.findRecords(IntField.MIN_VALUE, INT_COL).length);
+ assertEquals(5, table.findRecords(ShortField.MIN_VALUE, SHORT_COL).length);
+ assertEquals(4, table.findRecords(LongField.MIN_VALUE, LONG_COL).length);
+ assertEquals(3, table.findRecords(new StringField("x"), STR_COL).length);
+ assertEquals(2, table.findRecords(new BinaryField(new byte[] { 'x' }), BIN_COL).length);
+ assertEquals(1, table.findRecords(FixedField10.MIN_VALUE, FIXED10_COL).length); // same as ZERO_VALUE
+
+ assertEquals(6, table.getMatchingRecordCount(IntField.MIN_VALUE, INT_COL));
+ assertEquals(5, table.getMatchingRecordCount(ShortField.MIN_VALUE, SHORT_COL));
+ assertEquals(4, table.getMatchingRecordCount(LongField.MIN_VALUE, LONG_COL));
+ assertEquals(3, table.getMatchingRecordCount(new StringField("x"), STR_COL));
+ assertEquals(2, table.getMatchingRecordCount(new BinaryField(new byte[] { 'x' }), BIN_COL));
+ assertEquals(1, table.getMatchingRecordCount(FixedField10.MIN_VALUE, FIXED10_COL)); // same as ZERO_VALUE
+ }
+
+ private int count(DBFieldIterator iter) throws IOException {
+ int count = 0;
+ while (iter.hasNext()) {
+ iter.next();
+ ++count;
+ }
+ return count;
+ }
+
+ private int count(RecordIterator iter) throws IOException {
+ int count = 0;
+ while (iter.hasNext()) {
+ iter.next();
+ ++count;
+ }
+ return count;
+ }
+
+ @Test
+ public void testFixedKeySparseIndexIterator() throws IOException {
+
+ populateFixedKeySparseRecords();
+
+ Table table = dbh.getTable(table1Name);
+ int cnt = table.getSchema().getFieldCount();
+ assertEquals(8, cnt); // testing 8 field types as sparse columns in 9 data records
+ assertEquals(cnt + 1, table.getRecordCount());
+
+ // see DBTestUtils for schema column types
+
+ // null state/value not indexed
+
+ assertEquals(7, count(table.indexIterator(INT_COL)));
+ assertEquals(6, count(table.indexIterator(SHORT_COL)));
+ assertEquals(5, count(table.indexIterator(LONG_COL)));
+ assertEquals(4, count(table.indexIterator(STR_COL)));
+ assertEquals(3, count(table.indexIterator(BIN_COL)));
+ assertEquals(2, count(table.indexIterator(FIXED10_COL)));
+ }
+
+ @Test
+ public void testFixedKeySparseIndexFieldIterator() throws IOException {
+
+ populateFixedKeySparseRecords();
+
+ Table table = dbh.getTable(table1Name);
+ int cnt = table.getSchema().getFieldCount();
+ assertEquals(8, cnt); // testing 8 field types as sparse columns in 9 data records
+ assertEquals(cnt + 1, table.getRecordCount());
+
+ // see DBTestUtils for schema column types
+
+ // null state/value not indexed - only 2 unique values were used
+
+ assertEquals(2, count(table.indexFieldIterator(INT_COL)));
+ assertEquals(2, count(table.indexFieldIterator(SHORT_COL)));
+ assertEquals(2, count(table.indexFieldIterator(LONG_COL)));
+ try {
+ assertEquals(2, count(table.indexFieldIterator(STR_COL)));
+ }
+ catch (UnsupportedOperationException e) {
+ // expected
+ }
+ try {
+ assertEquals(2, count(table.indexFieldIterator(BIN_COL)));
+ }
+ catch (UnsupportedOperationException e) {
+ // expected
+ }
+ assertEquals(2, count(table.indexFieldIterator(FIXED10_COL)));
}
}
+
diff --git a/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java b/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java
index 5eb3ac557f..eedec3b7db 100644
--- a/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java
+++ b/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java
@@ -134,7 +134,7 @@ public class DBTestUtils {
int indexCnt = 0;
int[] indexedColumns = null;
- Schema[] schemas = longKeySchemas;
+ Schema[] schemas = longKeySchemas.clone();
if (useSparseColumns) {
for (int i = 0; i < schemas.length; i++) {
schemas[i] = createSparseSchema(schemas[i]);
@@ -199,7 +199,7 @@ public class DBTestUtils {
int indexCnt = 0;
int[] indexedColumns = null;
- Schema[] schemas = fixedKeySchemas;
+ Schema[] schemas = fixedKeySchemas.clone();
if (useSparseColumns) {
for (int i = 0; i < schemas.length; i++) {
schemas[i] = createSparseSchema(schemas[i]);