http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderProtocol.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderProtocol.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderProtocol.java index 352ab34..c402466 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderProtocol.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderProtocol.java @@ -433,7 +433,7 @@ public class TestResultSetLoaderProtocol extends SubOperatorTest { assertEquals(5, schema.size()); assertEquals(4, schema.index("e")); assertEquals(4, schema.index("E")); - rootWriter.array(4).set("e1", "e2", "e3"); + rootWriter.array(4).setObject(strArray("e1", "e2", "e3")); rootWriter.save(); // Verify. No reason to expect problems, but might as well check.
http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderTorture.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderTorture.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderTorture.java index cc2a83e..07100ed 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderTorture.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/rowSet/impl/TestResultSetLoaderTorture.java @@ -29,7 +29,6 @@ import org.apache.drill.exec.record.metadata.TupleMetadata; import org.apache.drill.exec.vector.ValueVector; import org.apache.drill.exec.vector.accessor.ArrayReader; import org.apache.drill.exec.vector.accessor.ArrayWriter; -import org.apache.drill.exec.vector.accessor.ScalarElementReader; import org.apache.drill.exec.vector.accessor.ScalarReader; import org.apache.drill.exec.vector.accessor.ScalarWriter; import org.apache.drill.exec.vector.accessor.TupleReader; @@ -256,7 +255,8 @@ public class TestResultSetLoaderTorture extends SubOperatorTest { ScalarReader n2Reader; ScalarReader s2Reader; ScalarReader n3Reader; - ScalarElementReader s3Reader; + ArrayReader s3Array; + ScalarReader s3Reader; ReadState readState; public BatchReader(TestSetup setup, RowSetReader reader, ReadState readState) { @@ -272,7 +272,8 @@ public class TestResultSetLoaderTorture extends SubOperatorTest { s2Reader = m2Reader.scalar("s2"); TupleReader m3Reader = m2Reader.tuple("m3"); n3Reader = m3Reader.scalar("n3"); - s3Reader = m3Reader.array("s3").elements(); + s3Array = m3Reader.array("s3"); + s3Reader = s3Array.scalar(); } public void verify() { @@ -312,7 +313,7 @@ public class TestResultSetLoaderTorture extends SubOperatorTest { private void verifyM2Array() { for (int i = 0; i < setup.m2Count; i++) { - a2Reader.setPosn(i); + assert(a2Reader.next()); // n2: usual int @@ -321,7 +322,7 @@ public class TestResultSetLoaderTorture extends SubOperatorTest { if (readState.innerCount % setup.s2Cycle == 0) { // Skipped values should be null assertTrue( - String.format("Row %d, entry %d", rootReader.rowIndex(), i), + String.format("Row %d, entry %d", rootReader.offset(), i), s2Reader.isNull()); } else if (readState.innerCount % setup.s2Cycle % setup.nullCycle == 0) { assertTrue(s2Reader.isNull()); @@ -338,10 +339,11 @@ public class TestResultSetLoaderTorture extends SubOperatorTest { // s3: a repeated VarChar if (readState.innerCount % setup.s3Cycle == 0) { - assertEquals(0, s3Reader.size()); + assertEquals(0, s3Array.size()); } else { for (int j = 0; j < setup.s3Count; j++) { - assertEquals(setup.s3Value + (readState.innerCount * setup.s3Count + j), s3Reader.getString(j)); + assertTrue(s3Array.next()); + assertEquals(setup.s3Value + (readState.innerCount * setup.s3Count + j), s3Reader.getString()); } } readState.innerCount++; http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/exec/record/TestVectorContainer.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/record/TestVectorContainer.java b/exec/java-exec/src/test/java/org/apache/drill/exec/record/TestVectorContainer.java index a511a0a..0882a1c 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/record/TestVectorContainer.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/record/TestVectorContainer.java @@ -28,6 +28,7 @@ import org.apache.drill.test.rowSet.RowSet; import org.apache.drill.test.rowSet.RowSet.SingleRowSet; import org.apache.drill.test.rowSet.schema.SchemaBuilder; import org.apache.drill.test.rowSet.RowSetComparison; +import org.apache.drill.test.rowSet.schema.SchemaBuilder; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -72,7 +73,7 @@ public class TestVectorContainer extends DrillTest { .addRow(30, "wilma") .build(); - // Simulated "implicit" coumns: row number and file name + // Simulated "implicit" columns: row number and file name BatchSchema rightSchema = new SchemaBuilder() .add("x", MinorType.SMALLINT) http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/DirectRowSet.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/DirectRowSet.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/DirectRowSet.java index 9262706..0e63c0e 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/DirectRowSet.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/DirectRowSet.java @@ -20,17 +20,17 @@ package org.apache.drill.test.rowSet; import com.google.common.collect.Sets; import org.apache.drill.exec.memory.BufferAllocator; import org.apache.drill.exec.physical.rowSet.model.MetadataProvider.MetadataRetrieval; -import org.apache.drill.exec.physical.rowSet.model.ReaderIndex; -import org.apache.drill.exec.physical.rowSet.model.SchemaInference; import org.apache.drill.exec.physical.rowSet.model.single.BaseWriterBuilder; import org.apache.drill.exec.physical.rowSet.model.single.BuildVectorsFromMetadata; +import org.apache.drill.exec.physical.rowSet.model.single.DirectRowIndex; +import org.apache.drill.exec.physical.rowSet.model.single.SingleSchemaInference; import org.apache.drill.exec.physical.rowSet.model.single.VectorAllocator; import org.apache.drill.exec.record.BatchSchema; import org.apache.drill.exec.record.BatchSchema.SelectionVectorMode; -import org.apache.drill.exec.record.VectorAccessible; -import org.apache.drill.exec.record.VectorContainer; import org.apache.drill.exec.record.metadata.MetadataUtils; import org.apache.drill.exec.record.metadata.TupleMetadata; +import org.apache.drill.exec.record.VectorAccessible; +import org.apache.drill.exec.record.VectorContainer; import org.apache.drill.exec.record.selection.SelectionVector2; import org.apache.drill.test.rowSet.RowSet.ExtendableRowSet; import org.apache.drill.test.rowSet.RowSetWriterImpl.WriterIndexImpl; @@ -44,26 +44,6 @@ import java.util.Set; public class DirectRowSet extends AbstractSingleRowSet implements ExtendableRowSet { - /** - * Reader index that points directly to each row in the row set. - * This index starts with pointing to the -1st row, so that the - * reader can require a <tt>next()</tt> for every row, including - * the first. (This is the JDBC RecordSet convention.) - */ - - private static class DirectRowIndex extends ReaderIndex { - - public DirectRowIndex(int rowCount) { - super(rowCount); - } - - @Override - public int vectorIndex() { return rowIndex; } - - @Override - public int batchIndex() { return 0; } - } - public static class RowSetWriterBuilder extends BaseWriterBuilder { public RowSetWriter buildWriter(DirectRowSet rowSet) { @@ -94,7 +74,7 @@ public class DirectRowSet extends AbstractSingleRowSet implements ExtendableRowS } public static DirectRowSet fromContainer(VectorContainer container) { - return new DirectRowSet(container, new SchemaInference().infer(container)); + return new DirectRowSet(container, new SingleSchemaInference().infer(container)); } public static DirectRowSet fromVectorAccessible(BufferAllocator allocator, VectorAccessible va) { @@ -151,7 +131,6 @@ public class DirectRowSet extends AbstractSingleRowSet implements ExtendableRowS return new IndirectRowSet(this, skipIndices); } - @Override public SelectionVector2 getSv2() { return null; } } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/HyperRowSetImpl.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/HyperRowSetImpl.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/HyperRowSetImpl.java index 70b8a20..542421e 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/HyperRowSetImpl.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/HyperRowSetImpl.java @@ -17,11 +17,16 @@ */ package org.apache.drill.test.rowSet; -import org.apache.drill.exec.physical.rowSet.model.MetadataProvider.MetadataRetrieval; -import org.apache.drill.exec.physical.rowSet.model.SchemaInference; +import java.util.ArrayList; +import java.util.List; + +import org.apache.drill.exec.exception.SchemaChangeException; +import org.apache.drill.exec.memory.BufferAllocator; import org.apache.drill.exec.physical.rowSet.model.hyper.BaseReaderBuilder; +import org.apache.drill.exec.physical.rowSet.model.hyper.HyperSchemaInference; import org.apache.drill.exec.record.BatchSchema.SelectionVectorMode; import org.apache.drill.exec.record.metadata.TupleMetadata; +import org.apache.drill.exec.record.ExpandableHyperContainer; import org.apache.drill.exec.record.VectorContainer; import org.apache.drill.exec.record.selection.SelectionVector4; import org.apache.drill.test.rowSet.RowSet.HyperRowSet; @@ -45,8 +50,67 @@ public class HyperRowSetImpl extends AbstractRowSet implements HyperRowSet { TupleMetadata schema = rowSet.schema(); HyperRowIndex rowIndex = new HyperRowIndex(sv4); return new RowSetReaderImpl(schema, rowIndex, - buildContainerChildren(rowSet.container(), - new MetadataRetrieval(schema))); + buildContainerChildren(rowSet.container(), schema)); + } + } + + public static class HyperRowSetBuilderImpl implements HyperRowSetBuilder { + + private final BufferAllocator allocator; + private final List<VectorContainer> batches = new ArrayList<>(); + private int totalRowCount; + + public HyperRowSetBuilderImpl(BufferAllocator allocator) { + this.allocator = allocator; + } + + @Override + public void addBatch(SingleRowSet rowSet) { + if (rowSet.rowCount() == 0) { + return; + } + if (rowSet.indirectionType() != SelectionVectorMode.NONE) { + throw new IllegalArgumentException("Batches must not have a selection vector."); + } + batches.add(rowSet.container()); + totalRowCount += rowSet.rowCount(); + } + + @Override + public void addBatch(VectorContainer container) { + if (container.getRecordCount() == 0) { + return; + } + if (container.getSchema().getSelectionVectorMode() != SelectionVectorMode.NONE) { + throw new IllegalArgumentException("Batches must not have a selection vector."); + } + batches.add(container); + totalRowCount += container.getRecordCount(); + } + + @SuppressWarnings("resource") + @Override + public HyperRowSet build() throws SchemaChangeException { + SelectionVector4 sv4 = new SelectionVector4(allocator, totalRowCount); + ExpandableHyperContainer hyperContainer = new ExpandableHyperContainer(); + for (VectorContainer container : batches) { + hyperContainer.addBatch(container); + } + + // TODO: This has a bug. If the hyperset has two batches with unions, + // and the first union contains only VARCHAR, while the second contains + // only INT, the combined schema should be (VARCHAR, INT). Same is true + // of lists. But, this code looks at only the first container. + // + // This is only a theoretical bug as Drill does not support unions + // completely, but must be fixed if we want complete union support. + // + // Actually, the problem is more fundamental. The extendable hyper + // container, which creates the metadata schema, does not handle the + // case either. + + TupleMetadata schema = new HyperSchemaInference().infer(hyperContainer); + return new HyperRowSetImpl(schema, hyperContainer, sv4); } } @@ -56,13 +120,37 @@ public class HyperRowSetImpl extends AbstractRowSet implements HyperRowSet { private final SelectionVector4 sv4; - public HyperRowSetImpl(VectorContainer container, SelectionVector4 sv4) { - super(container, new SchemaInference().infer(container)); + public HyperRowSetImpl(TupleMetadata schema, VectorContainer container, SelectionVector4 sv4) { + super(container, schema); this.sv4 = sv4; } + public HyperRowSetImpl(VectorContainer container, SelectionVector4 sv4) throws SchemaChangeException { + this(new HyperSchemaInference().infer(container), container, sv4); + } + + public static HyperRowSetBuilder builder(BufferAllocator allocator) { + return new HyperRowSetBuilderImpl(allocator); + } + public static HyperRowSet fromContainer(VectorContainer container, SelectionVector4 sv4) { - return new HyperRowSetImpl(container, sv4); + try { + return new HyperRowSetImpl(container, sv4); + } catch (SchemaChangeException e) { + throw new UnsupportedOperationException(e); + } + } + + public static HyperRowSet fromRowSets(BufferAllocator allocator, SingleRowSet...rowSets) { + HyperRowSetBuilder builder = builder(allocator); + for (SingleRowSet rowSet : rowSets) { + builder.addBatch(rowSet); + } + try { + return builder.build(); + } catch (SchemaChangeException e) { + throw new IllegalArgumentException("Incompatible schemas", e); + } } @Override http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/IndirectRowSet.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/IndirectRowSet.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/IndirectRowSet.java index 42d97db..a2bc5e8 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/IndirectRowSet.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/IndirectRowSet.java @@ -20,10 +20,10 @@ package org.apache.drill.test.rowSet; import com.google.common.collect.Sets; import org.apache.drill.exec.exception.OutOfMemoryException; import org.apache.drill.exec.memory.BufferAllocator; -import org.apache.drill.exec.record.RecordBatchSizer; import org.apache.drill.exec.physical.rowSet.model.ReaderIndex; -import org.apache.drill.exec.physical.rowSet.model.SchemaInference; +import org.apache.drill.exec.physical.rowSet.model.single.SingleSchemaInference; import org.apache.drill.exec.record.BatchSchema.SelectionVectorMode; +import org.apache.drill.exec.record.RecordBatchSizer; import org.apache.drill.exec.record.VectorContainer; import org.apache.drill.exec.record.selection.SelectionVector2; @@ -38,8 +38,8 @@ public class IndirectRowSet extends AbstractSingleRowSet { /** * Reader index that points to each row indirectly through the - * selection vector. The {@link #vectorIndex()} method points to the - * actual data row, while the {@link #position()} method gives + * selection vector. The {@link #physicalIndex()} method points to the + * actual data row, while the {@link #logicalIndex()} method gives * the position relative to the indirection vector. That is, * the position increases monotonically, but the index jumps * around as specified by the indirection vector. @@ -55,16 +55,16 @@ public class IndirectRowSet extends AbstractSingleRowSet { } @Override - public int vectorIndex() { return sv2.getIndex(rowIndex); } + public int offset() { return sv2.getIndex(position); } @Override - public int batchIndex() { return 0; } + public int hyperVectorIndex() { return 0; } } private final SelectionVector2 sv2; private IndirectRowSet(VectorContainer container, SelectionVector2 sv2) { - super(container, new SchemaInference().infer(container)); + super(container, new SingleSchemaInference().infer(container)); this.sv2 = sv2; } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSet.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSet.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSet.java index 53be75d..63a4959 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSet.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSet.java @@ -17,6 +17,7 @@ */ package org.apache.drill.test.rowSet; +import org.apache.drill.exec.exception.SchemaChangeException; import org.apache.drill.exec.memory.BufferAllocator; import org.apache.drill.exec.record.BatchSchema; import org.apache.drill.exec.record.BatchSchema.SelectionVectorMode; @@ -143,4 +144,10 @@ public interface RowSet { interface HyperRowSet extends RowSet { SelectionVector4 getSv4(); } + + interface HyperRowSetBuilder { + void addBatch(SingleRowSet rowSet); + void addBatch(VectorContainer container); + HyperRowSet build() throws SchemaChangeException; + } } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetComparison.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetComparison.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetComparison.java index 1cae64f..e098e33 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetComparison.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetComparison.java @@ -20,15 +20,14 @@ package org.apache.drill.test.rowSet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.util.Comparator; + import org.apache.drill.exec.vector.accessor.ArrayReader; import org.apache.drill.exec.vector.accessor.ObjectReader; -import org.apache.drill.exec.vector.accessor.ScalarElementReader; import org.apache.drill.exec.vector.accessor.ScalarReader; import org.apache.drill.exec.vector.accessor.TupleReader; import org.bouncycastle.util.Arrays; -import java.util.Comparator; - /** * For testing, compare the contents of two row sets (record batches) * to verify that they are identical. Supports masks to exclude certain @@ -149,6 +148,9 @@ public class RowSetComparison { */ public void verify(RowSet actual) { + assertTrue("Schemas don't match.\n" + + "Expected: " + expected.schema().toString() + + "\nActual: " + actual.schema(), expected.schema().isEquivalent(actual.schema())); int testLength = expected.rowCount() - offset; if (span > -1) { testLength = span; @@ -165,7 +167,7 @@ public class RowSetComparison { for (int i = 0; i < testLength; i++) { er.next(); ar.next(); - String label = Integer.toString(er.index() + 1); + String label = Integer.toString(er.logicalIndex() + 1); verifyRow(label, er, ar); } } @@ -276,63 +278,12 @@ public class RowSetComparison { private void verifyArray(String label, ArrayReader ea, ArrayReader aa) { - assertEquals(label, ea.entryType(), aa.entryType()); - assertEquals(label, ea.size(), aa.size()); - switch (ea.entryType()) { - case ARRAY: - throw new UnsupportedOperationException(); - case SCALAR: - verifyScalarArray(label, ea.elements(), aa.elements()); - break; - case TUPLE: - verifyTupleArray(label, ea, aa); - break; - default: - throw new IllegalStateException( "Unexpected type: " + ea.entryType()); - } - } - - private void verifyTupleArray(String label, ArrayReader ea, ArrayReader aa) { - for (int i = 0; i < ea.size(); i++) { - verifyTuple(label + "[" + i + "]", ea.tuple(i), aa.tuple(i)); - } - } - - private void verifyScalarArray(String colLabel, ScalarElementReader ea, - ScalarElementReader aa) { - assertEquals(colLabel, ea.valueType(), aa.valueType()); - assertEquals(colLabel, ea.size(), aa.size()); - for (int i = 0; i < ea.size(); i++) { - String label = colLabel + "[" + i + "]"; - switch (ea.valueType()) { - case BYTES: { - byte expected[] = ea.getBytes(i); - byte actual[] = aa.getBytes(i); - assertEquals(label + " - byte lengths differ", expected.length, actual.length); - assertTrue(label, Arrays.areEqual(expected, actual)); - break; - } - case DOUBLE: - assertEquals(label, ea.getDouble(i), aa.getDouble(i), delta); - break; - case INTEGER: - assertEquals(label, ea.getInt(i), aa.getInt(i)); - break; - case LONG: - assertEquals(label, ea.getLong(i), aa.getLong(i)); - break; - case STRING: - assertEquals(label, ea.getString(i), aa.getString(i)); - break; - case DECIMAL: - assertEquals(label, ea.getDecimal(i), aa.getDecimal(i)); - break; - case PERIOD: - assertEquals(label, ea.getPeriod(i), aa.getPeriod(i)); - break; - default: - throw new IllegalStateException( "Unexpected type: " + ea.valueType()); - } + assertEquals(label + " - array element type", ea.entryType(), aa.entryType()); + assertEquals(label + " - array length", ea.size(), aa.size()); + int i = 0; + while (ea.next()) { + assertTrue(aa.next()); + verifyColumn(label + "[" + i++ + "]", ea.entry(), aa.entry()); } } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetPrinter.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetPrinter.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetPrinter.java index fe50197..82d4bbd 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetPrinter.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetPrinter.java @@ -41,7 +41,7 @@ public class RowSetPrinter { public void print(PrintStream out) { SelectionVectorMode selectionMode = rowSet.indirectionType(); RowSetReader reader = rowSet.reader(); - int colCount = reader.schema().size(); + int colCount = reader.tupleSchema().size(); printSchema(out, selectionMode, reader); while (reader.next()) { printHeader(out, reader, selectionMode); @@ -68,12 +68,12 @@ public class RowSetPrinter { break; } out.print(": "); - TupleMetadata schema = reader.schema(); + TupleMetadata schema = reader.tupleSchema(); printTupleSchema(out, schema); out.println(); } - private void printTupleSchema(PrintStream out, TupleMetadata schema) { + public static void printTupleSchema(PrintStream out, TupleMetadata schema) { for (int i = 0; i < schema.size(); i++) { if (i > 0) { out.print(", "); @@ -81,26 +81,26 @@ public class RowSetPrinter { ColumnMetadata colSchema = schema.metadata(i); out.print(colSchema.name()); if (colSchema.isMap()) { - out.print("("); + out.print("{"); printTupleSchema(out, colSchema.mapSchema()); - out.print(")"); + out.print("}"); } } } private void printHeader(PrintStream out, RowSetReader reader, SelectionVectorMode selectionMode) { - out.print(reader.index()); + out.print(reader.logicalIndex()); switch (selectionMode) { case FOUR_BYTE: out.print(" ("); - out.print(reader.batchIndex()); + out.print(reader.hyperVectorIndex()); out.print(", "); - out.print(reader.rowIndex()); + out.print(reader.offset()); out.print(")"); break; case TWO_BYTE: out.print(" ("); - out.print(reader.rowIndex()); + out.print(reader.offset()); out.print(")"); break; default: http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReader.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReader.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReader.java index 3e27529..4a966cd 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReader.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReader.java @@ -32,23 +32,22 @@ public interface RowSetReader extends TupleReader { int rowCount(); boolean next(); - int index(); - void set(int index); + int logicalIndex(); + void setPosn(int index); /** * Batch index: 0 for a single batch, batch for the current * row is a hyper-batch. * @return index of the batch for the current row */ - int batchIndex(); + int hyperVectorIndex(); /** * The index of the underlying row which may be indexed by an - * Sv2 or Sv4. + * SV2 or SV4. * * @return */ - int rowIndex(); - boolean valid(); + int offset(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReaderImpl.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReaderImpl.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReaderImpl.java index 7217187..6344419 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReaderImpl.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/RowSetReaderImpl.java @@ -20,9 +20,11 @@ package org.apache.drill.test.rowSet; import java.util.List; import org.apache.drill.exec.physical.rowSet.model.ReaderIndex; +import org.apache.drill.exec.record.metadata.ColumnMetadata; import org.apache.drill.exec.record.metadata.TupleMetadata; import org.apache.drill.exec.vector.accessor.reader.AbstractObjectReader; import org.apache.drill.exec.vector.accessor.reader.AbstractTupleReader; +import org.apache.drill.exec.vector.accessor.reader.NullStateReaders; /** * Reader implementation for a row set. @@ -30,11 +32,14 @@ import org.apache.drill.exec.vector.accessor.reader.AbstractTupleReader; public class RowSetReaderImpl extends AbstractTupleReader implements RowSetReader { + private final TupleMetadata schema; protected final ReaderIndex readerIndex; public RowSetReaderImpl(TupleMetadata schema, ReaderIndex index, AbstractObjectReader[] readers) { - super(schema, readers); + super(readers); + this.schema = schema; this.readerIndex = index; + bindNullState(NullStateReaders.REQUIRED_STATE_READER); bindIndex(index); } @@ -54,23 +59,26 @@ public class RowSetReaderImpl extends AbstractTupleReader implements RowSetReade } @Override - public boolean valid() { return readerIndex.valid(); } - - @Override - public int index() { return readerIndex.position(); } + public int logicalIndex() { return readerIndex.logicalIndex(); } @Override public int rowCount() { return readerIndex.size(); } @Override - public int rowIndex() { return readerIndex.vectorIndex(); } + public int offset() { return readerIndex.offset(); } @Override - public int batchIndex() { return readerIndex.batchIndex(); } + public int hyperVectorIndex() { return readerIndex.hyperVectorIndex(); } @Override - public void set(int index) { + public void setPosn(int index) { this.readerIndex.set(index); reposition(); } + + @Override + public ColumnMetadata schema() { return null; } + + @Override + public TupleMetadata tupleSchema() { return schema; } } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/schema/UnionBuilder.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/schema/UnionBuilder.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/schema/UnionBuilder.java index e47e552..1aa636d 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/schema/UnionBuilder.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/schema/UnionBuilder.java @@ -17,9 +17,9 @@ */ package org.apache.drill.test.rowSet.schema; -import org.apache.drill.common.types.Types; import org.apache.drill.common.types.TypeProtos.DataMode; import org.apache.drill.common.types.TypeProtos.MinorType; +import org.apache.drill.common.types.Types; import org.apache.drill.exec.record.metadata.AbstractColumnMetadata; import org.apache.drill.exec.record.metadata.VariantColumnMetadata; import org.apache.drill.exec.record.metadata.VariantSchema; @@ -33,7 +33,6 @@ public class UnionBuilder implements SchemaContainer { private final SchemaContainer parent; private final String name; private final MinorType type; - private final DataMode mode; private final VariantSchema union; public UnionBuilder(SchemaContainer parent, String name, @@ -41,7 +40,6 @@ public class UnionBuilder implements SchemaContainer { this.parent = parent; this.name = name; this.type = type; - this.mode = mode; union = new VariantSchema(); } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/RowSetTest.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/RowSetTest.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/RowSetTest.java index 9ad4133..92b9266 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/RowSetTest.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/RowSetTest.java @@ -36,7 +36,6 @@ import org.apache.drill.exec.vector.VectorOverflowException; import org.apache.drill.exec.vector.accessor.ArrayReader; import org.apache.drill.exec.vector.accessor.ArrayWriter; import org.apache.drill.exec.vector.accessor.ObjectType; -import org.apache.drill.exec.vector.accessor.ScalarElementReader; import org.apache.drill.exec.vector.accessor.ScalarReader; import org.apache.drill.exec.vector.accessor.ScalarWriter; import org.apache.drill.exec.vector.accessor.TupleReader; @@ -45,6 +44,7 @@ import org.apache.drill.exec.vector.accessor.ValueType; import org.apache.drill.exec.vector.complex.MapVector; import org.apache.drill.exec.vector.complex.RepeatedMapVector; import org.apache.drill.test.SubOperatorTest; +import org.apache.drill.test.rowSet.DirectRowSet; import org.apache.drill.test.rowSet.RowSet.ExtendableRowSet; import org.apache.drill.test.rowSet.RowSet.SingleRowSet; import org.apache.drill.test.rowSet.RowSetComparison; @@ -60,12 +60,17 @@ import org.junit.Test; * Tests basic protocol of the writers: <pre><code> * row : tuple * tuple : column * - * column : scalar obj | array obj | tuple obj + * column : scalar obj | array obj | tuple obj | variant obj * scalar obj : scalar - * array obj : array writer - * array writer : element + * array obj : array + * array : index --> column * element : column - * tuple obj : tuple</code></pre> + * tuple obj : tuple + * tuple : name --> column (also index --> column) + * variant obj : variant + * variant : type --> column</code></pre> + * <p> + * A list is an array of variants. Variants are tested elsewhere. */ public class RowSetTest extends SubOperatorTest { @@ -137,16 +142,21 @@ public class RowSetTest extends SubOperatorTest { assertSame(reader.column("a").scalar(), reader.scalar("a")); assertSame(reader.column(0).scalar(), reader.scalar(0)); assertEquals(ValueType.INTEGER, reader.scalar(0).valueType()); + assertTrue(schema.metadata("a").isEquivalent(reader.column("a").schema())); // Test various accessors: full and simple assertTrue(reader.next()); + assertFalse(reader.column("a").scalar().isNull()); assertEquals(10, reader.column("a").scalar().getInt()); assertTrue(reader.next()); + assertFalse(reader.scalar("a").isNull()); assertEquals(20, reader.scalar("a").getInt()); assertTrue(reader.next()); + assertFalse(reader.column(0).scalar().isNull()); assertEquals(30, reader.column(0).scalar().getInt()); assertTrue(reader.next()); + assertFalse(reader.column(0).scalar().isNull()); assertEquals(40, reader.scalar(0).getInt()); assertFalse(reader.next()); @@ -238,27 +248,50 @@ public class RowSetTest extends SubOperatorTest { assertSame(reader.column(0).array(), reader.array(0)); assertEquals(ObjectType.SCALAR, reader.column("a").array().entryType()); - assertEquals(ValueType.INTEGER, reader.array(0).elements().valueType()); + assertEquals(ValueType.INTEGER, reader.array(0).scalar().valueType()); // Read and verify the rows - ScalarElementReader intReader = reader.array(0).elements(); + ArrayReader arrayReader = reader.array(0); + ScalarReader intReader = arrayReader.scalar(); assertTrue(reader.next()); - assertEquals(2, intReader.size()); - assertEquals(10, intReader.getInt(0)); - assertEquals(11, intReader.getInt(1)); + assertFalse(arrayReader.isNull()); + assertEquals(2, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(10, intReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(11, intReader.getInt()); + assertFalse(arrayReader.next()); + assertTrue(reader.next()); - assertEquals(3, intReader.size()); - assertEquals(20, intReader.getInt(0)); - assertEquals(21, intReader.getInt(1)); - assertEquals(22, intReader.getInt(2)); + assertFalse(arrayReader.isNull()); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(20, intReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(21, intReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(22, intReader.getInt()); + assertFalse(arrayReader.next()); + assertTrue(reader.next()); - assertEquals(1, intReader.size()); - assertEquals(30, intReader.getInt(0)); + assertFalse(arrayReader.isNull()); + assertEquals(1, arrayReader.size()); + assertTrue(arrayReader.next()); + assertEquals(30, intReader.getInt()); + assertFalse(arrayReader.next()); + assertTrue(reader.next()); - assertEquals(2, intReader.size()); - assertEquals(40, intReader.getInt(0)); - assertEquals(41, intReader.getInt(1)); + assertFalse(arrayReader.isNull()); + assertEquals(2, arrayReader.size()); + assertTrue(arrayReader.next()); + assertEquals(40, intReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(41, intReader.getInt()); + assertFalse(arrayReader.next()); + assertFalse(reader.next()); // Test the above again via the writer and reader @@ -352,22 +385,47 @@ public class RowSetTest extends SubOperatorTest { ScalarReader aReader = reader.column(0).scalar(); TupleReader mReader = reader.column(1).tuple(); - assertEquals(ObjectType.SCALAR, mReader.column("b").array().entryType()); - ScalarElementReader bReader = mReader.column(0).elements(); + ArrayReader bArray = mReader.column("b").array(); + assertEquals(ObjectType.SCALAR, bArray.entryType()); + ScalarReader bReader = bArray.scalar(); assertEquals(ValueType.INTEGER, bReader.valueType()); + // Row 1: (10, {[11, 12]}) + assertTrue(reader.next()); assertEquals(10, aReader.getInt()); - assertEquals(11, bReader.getInt(0)); - assertEquals(12, bReader.getInt(1)); + assertFalse(mReader.isNull()); + + assertTrue(bArray.next()); + assertFalse(bReader.isNull()); + assertEquals(11, bReader.getInt()); + assertTrue(bArray.next()); + assertFalse(bReader.isNull()); + assertEquals(12, bReader.getInt()); + assertFalse(bArray.next()); + + // Row 2: (20, {[21, 22]}) + assertTrue(reader.next()); assertEquals(20, aReader.getInt()); - assertEquals(21, bReader.getInt(0)); - assertEquals(22, bReader.getInt(1)); + assertFalse(mReader.isNull()); + + assertTrue(bArray.next()); + assertEquals(21, bReader.getInt()); + assertTrue(bArray.next()); + assertEquals(22, bReader.getInt()); + + // Row 3: (30, {[31, 32]}) + assertTrue(reader.next()); assertEquals(30, aReader.getInt()); - assertEquals(31, bReader.getInt(0)); - assertEquals(32, bReader.getInt(1)); + assertFalse(mReader.isNull()); + + assertTrue(bArray.next()); + assertEquals(31, bReader.getInt()); + assertTrue(bArray.next()); + assertEquals(32, bReader.getInt()); + assertFalse(reader.next()); // Verify that the map accessor's value count was set. @@ -472,18 +530,22 @@ public class RowSetTest extends SubOperatorTest { assertEquals(ValueType.INTEGER, bReader.valueType()); assertEquals(ValueType.INTEGER, cReader.valueType()); - // Row 1: use index accessors + // Row 1: Use iterator-like accessors assertTrue(reader.next()); assertEquals(10, aReader.getInt()); - TupleReader ixReader = maReader.tuple(0); - assertEquals(101, ixReader.scalar(0).getInt()); - assertEquals(102, ixReader.scalar(1).getInt()); - ixReader = maReader.tuple(1); - assertEquals(111, ixReader.scalar(0).getInt()); - assertEquals(112, ixReader.scalar(1).getInt()); - - // Row 2: use common accessor with explicit positioning, + assertFalse(maReader.isNull()); // Array itself is not null + + assertTrue(maReader.next()); + assertFalse(mapReader.isNull()); // Tuple 0 is not null + assertEquals(101, mapReader.scalar(0).getInt()); + assertEquals(102, mapReader.scalar(1).getInt()); + + assertTrue(maReader.next()); + assertEquals(111, mapReader.scalar(0).getInt()); + assertEquals(112, mapReader.scalar(1).getInt()); + + // Row 2: use explicit positioning, // but access scalars through the map reader. assertTrue(reader.next()); @@ -495,14 +557,16 @@ public class RowSetTest extends SubOperatorTest { assertEquals(211, mapReader.scalar(0).getInt()); assertEquals(212, mapReader.scalar(1).getInt()); - // Row 3: use common accessor for scalars + // Row 3: use scalar accessor assertTrue(reader.next()); assertEquals(30, aReader.getInt()); - maReader.setPosn(0); + + assertTrue(maReader.next()); assertEquals(301, bReader.getInt()); assertEquals(302, cReader.getInt()); - maReader.setPosn(1); + + assertTrue(maReader.next()); assertEquals(311, bReader.getInt()); assertEquals(312, cReader.getInt()); @@ -555,18 +619,28 @@ public class RowSetTest extends SubOperatorTest { SingleRowSet result = writer.done(); RowSetReader reader = result.reader(); + ArrayReader arrayReader = reader.array(1); + ScalarReader elementReader = arrayReader.scalar(); + assertTrue(reader.next()); assertEquals(10, reader.scalar(0).getInt()); - ScalarElementReader arrayReader = reader.array(1).elements(); assertEquals(2, arrayReader.size()); - assertEquals(100, arrayReader.getInt(0)); - assertEquals(110, arrayReader.getInt(1)); + + assertTrue(arrayReader.next()); + assertEquals(100, elementReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(110, elementReader.getInt()); + assertTrue(reader.next()); assertEquals(20, reader.scalar(0).getInt()); assertEquals(3, arrayReader.size()); - assertEquals(200, arrayReader.getInt(0)); - assertEquals(120, arrayReader.getInt(1)); - assertEquals(220, arrayReader.getInt(2)); + assertTrue(arrayReader.next()); + assertEquals(200, elementReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(120, elementReader.getInt()); + assertTrue(arrayReader.next()); + assertEquals(220, elementReader.getInt()); + assertTrue(reader.next()); assertEquals(30, reader.scalar(0).getInt()); assertEquals(0, arrayReader.size()); @@ -581,7 +655,6 @@ public class RowSetTest extends SubOperatorTest { new RowSetComparison(rs1) .verifyAndClearAll(rs2); } - /** * Test filling a row set up to the maximum number of rows. * Values are small enough to prevent filling to the @@ -666,4 +739,107 @@ public class RowSetTest extends SubOperatorTest { assertEquals(count, rs.rowCount()); rs.clear(); } + + /** + * The code below is not a test. Rather, it is a simple example of + * how to write a batch of data using writers, then read it using + * readers. + */ + + @Test + public void example() { + + // Step 1: Define a schema. In a real app, this + // will be provided by a reader, by an incoming batch, + // etc. + + BatchSchema schema = new SchemaBuilder() + .add("a", MinorType.VARCHAR) + .addArray("b", MinorType.INT) + .addMap("c") + .add("c1", MinorType.INT) + .add("c2", MinorType.VARCHAR) + .resumeSchema() + .build(); + + // Step 2: Create a batch. Done here because this is + // a batch-oriented test. Done automatically in the + // result set loader. + + DirectRowSet drs = DirectRowSet.fromSchema(fixture.allocator(), schema); + + // Step 3: Create the writer. + + RowSetWriter writer = drs.writer(); + + // Step 4: Populate data. Here we do it the way an app would: + // using the individual accessors. See tests above for the many + // ways this can be done depending on the need of the app. + // + // Write two rows: + // ("fred", [10, 11], {12, "wilma"}) + // ("barney", [20, 21], {22, "betty"}) + // + // This example uses Java strings for Varchar. Real code might + // use byte arrays. + + writer.scalar("a").setString("fred"); + ArrayWriter bWriter = writer.array("b"); + bWriter.scalar().setInt(10); + bWriter.scalar().setInt(11); + TupleWriter cWriter = writer.tuple("c"); + cWriter.scalar("c1").setInt(12); + cWriter.scalar("c2").setString("wilma"); + writer.save(); + + writer.scalar("a").setString("barney"); + bWriter.scalar().setInt(20); + bWriter.scalar().setInt(21); + cWriter.scalar("c1").setInt(22); + cWriter.scalar("c2").setString("betty"); + writer.save(); + + // Step 5: "Harvest" the batch. Done differently in the + // result set loader. + + SingleRowSet rowSet = writer.done(); + + // Step 5: Create a reader. + + RowSetReader reader = rowSet.reader(); + + // Step 6: Retrieve the data. Here we just print the + // values. + + while (reader.next()) { + print(reader.scalar("a").getString()); + ArrayReader bReader = reader.array("b"); + while (bReader.next()) { + print(bReader.scalar().getInt()); + } + TupleReader cReader = reader.tuple("c"); + print(cReader.scalar("c1").getInt()); + print(cReader.scalar("c2").getString()); + endRow(); + } + + // Step 7: Free memory. + + rowSet.clear(); + } + + public void print(Object obj) { + if (obj instanceof String) { + System.out.print("\""); + System.out.print(obj); + System.out.print("\""); + } else { + System.out.print(obj); + } + System.out.print(" "); + } + + public void endRow() { + System.out.println(); + } } http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestFillEmpties.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestFillEmpties.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestFillEmpties.java index 490a9fd..f4c00ca 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestFillEmpties.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestFillEmpties.java @@ -24,17 +24,17 @@ import org.apache.drill.common.types.TypeProtos.DataMode; import org.apache.drill.common.types.TypeProtos.MajorType; import org.apache.drill.common.types.TypeProtos.MinorType; import org.apache.drill.exec.record.metadata.TupleMetadata; -import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.accessor.ArrayReader; import org.apache.drill.exec.vector.accessor.ScalarReader; import org.apache.drill.exec.vector.accessor.ScalarWriter; import org.apache.drill.exec.vector.accessor.ValueType; import org.apache.drill.test.SubOperatorTest; import org.apache.drill.test.rowSet.RowSet.ExtendableRowSet; import org.apache.drill.test.rowSet.RowSet.SingleRowSet; -import org.apache.drill.test.rowSet.schema.SchemaBuilder; import org.apache.drill.test.rowSet.RowSetReader; import org.apache.drill.test.rowSet.RowSetUtilities; import org.apache.drill.test.rowSet.RowSetWriter; +import org.apache.drill.test.rowSet.schema.SchemaBuilder; import org.junit.Test; /** @@ -219,16 +219,18 @@ public class TestFillEmpties extends SubOperatorTest { } SingleRowSet result = writer.done(); RowSetReader reader = result.reader(); - ScalarElementReader colReader = reader.array(0).elements(); + ArrayReader aReader = reader.array(0); + ScalarReader colReader = aReader.scalar(); for (int i = 0; i < ROW_COUNT; i++) { assertTrue(reader.next()); if (i % 5 != 0) { // Empty arrays are defined to be the same as a zero-length array. - assertEquals(0, colReader.size()); + assertEquals(0, aReader.size()); } else { for (int j = 0; j < 2; j++) { - Object actual = colReader.getObject(j); + assertTrue(aReader.next()); + Object actual = colReader.getObject(); Object expected = RowSetUtilities.testDataFromInt(valueType, majorType, i + j); RowSetUtilities.assertEqualValues( majorType.toString().replace('\n', ' ') + "[" + i + "][" + j + "]", http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestHyperVectorReaders.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestHyperVectorReaders.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestHyperVectorReaders.java new file mode 100644 index 0000000..00e72d4 --- /dev/null +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestHyperVectorReaders.java @@ -0,0 +1,365 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.drill.test.rowSet.test; + +import static org.apache.drill.test.rowSet.RowSetUtilities.mapArray; +import static org.apache.drill.test.rowSet.RowSetUtilities.mapValue; +import static org.apache.drill.test.rowSet.RowSetUtilities.strArray; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.apache.drill.common.types.TypeProtos.MinorType; +import org.apache.drill.exec.record.metadata.TupleMetadata; +import org.apache.drill.exec.record.selection.SelectionVector4; +import org.apache.drill.test.SubOperatorTest; +import org.apache.drill.test.rowSet.HyperRowSetImpl; +import org.apache.drill.test.rowSet.RowSet.ExtendableRowSet; +import org.apache.drill.test.rowSet.RowSet.HyperRowSet; +import org.apache.drill.test.rowSet.RowSet.SingleRowSet; +import org.apache.drill.test.rowSet.RowSetBuilder; +import org.apache.drill.test.rowSet.RowSetReader; +import org.apache.drill.test.rowSet.RowSetUtilities; +import org.apache.drill.test.rowSet.RowSetWriter; +import org.apache.drill.test.rowSet.schema.SchemaBuilder; +import org.junit.Test; + +/** + * Test the reader mechanism that reads rows indexed via an SV4. + * SV4's introduce an additional level of indexing: each row may + * come from a different batch. The readers use the SV4 to find + * the root batch and vector, then must navigate downward from that + * vector for maps, repeated maps, lists, unions, repeated lists, + * nullable vectors and variable-length vectors. + * <p> + * This test does not cover repeated vectors; those tests should be added. + */ + +public class TestHyperVectorReaders extends SubOperatorTest { + + /** + * Test the simplest case: a top-level required vector. Has no contained vectors. + * This test focuses on the SV4 indirection mechanism itself. + */ + + @Test + public void testRequired() { + TupleMetadata schema = new SchemaBuilder() + .add("a", MinorType.INT) + .buildSchema(); + + SingleRowSet rowSet1; + { + ExtendableRowSet rowSet = fixture.rowSet(schema); + RowSetWriter writer = rowSet.writer(); + for (int i = 0; i < 10; i++) { + writer.scalar(0).setInt(i * 10); + writer.save(); + } + rowSet1 = writer.done(); + } + + SingleRowSet rowSet2; + { + ExtendableRowSet rowSet = fixture.rowSet(schema); + RowSetWriter writer = rowSet.writer(); + for (int i = 10; i < 20; i++) { + writer.scalar(0).setInt(i * 10); + writer.save(); + } + rowSet2 = writer.done(); + } + + // Build the hyper batch + // [0, 10, 20, ... 190] + + HyperRowSet hyperSet = HyperRowSetImpl.fromRowSets(fixture.allocator(), rowSet1, rowSet2); + assertEquals(20, hyperSet.rowCount()); + + // Populate the indirection vector: + // (1, 9), (0, 9), (1, 8), (0, 8), ... (0, 0) + + SelectionVector4 sv4 = hyperSet.getSv4(); + for (int i = 0; i < 20; i++) { + int batch = i % 2; + int offset = 9 - i / 2; + sv4.set(i, batch, offset); + } + + // Sanity check. + + for (int i = 0; i < 20; i++) { + int batch = i % 2; + int offset = 9 - i / 2; + int encoded = sv4.get(i); + assertEquals(batch, SelectionVector4.getBatchIndex(encoded)); + assertEquals(offset, SelectionVector4.getRecordIndex(encoded)); + } + + // Verify reader + // Expected: [190, 90, 180, 80, ... 0] + + RowSetReader reader = hyperSet.reader(); + for (int i = 0; i < 20; i++) { + assertTrue(reader.next()); + int batch = i % 2; + int offset = 9 - i / 2; + int expected = batch * 100 + offset * 10; + assertEquals(expected, reader.scalar(0).getInt()); + } + assertFalse(reader.next()); + + // Validate using an expected result set. + + RowSetBuilder rsBuilder = fixture.rowSetBuilder(schema); + for (int i = 0; i < 20; i++) { + int batch = i % 2; + int offset = 9 - i / 2; + int expected = batch * 100 + offset * 10; + rsBuilder.addRow(expected); + } + + RowSetUtilities.verify(rsBuilder.build(), hyperSet); + } + + @Test + public void testVarWidth() { + TupleMetadata schema = new SchemaBuilder() + .add("a", MinorType.VARCHAR) + .buildSchema(); + + SingleRowSet rowSet1 = fixture.rowSetBuilder(schema) + .addSingleCol("second") + .addSingleCol("fourth") + .build(); + + SingleRowSet rowSet2 = fixture.rowSetBuilder(schema) + .addSingleCol("first") + .addSingleCol("third") + .build(); + + // Build the hyper batch + + HyperRowSet hyperSet = HyperRowSetImpl.fromRowSets(fixture.allocator(), rowSet1, rowSet2); + assertEquals(4, hyperSet.rowCount()); + SelectionVector4 sv4 = hyperSet.getSv4(); + sv4.set(0, 1, 0); + sv4.set(1, 0, 0); + sv4.set(2, 1, 1); + sv4.set(3, 0, 1); + + SingleRowSet expected = fixture.rowSetBuilder(schema) + .addRow("first") + .addRow("second") + .addRow("third") + .addRow("fourth") + .build(); + + RowSetUtilities.verify(expected, hyperSet); + } + + /** + * Test a nullable varchar. Requires multiple indirections: + * <ul> + * <li>From the SV4 to the nullable vector.</li> + * <li>From the nullable vector to the bits vector.</li> + * <li>From the nullable vector to the data vector.</li> + * <li>From the data vector to the offset vector.</li> + * <li>From the data vector to the values vector.</li> + * </ul> + * All are coordinated by the vector index and vector accessors. + * This test verifies that each of the indirections does, in fact, + * work as expected. + */ + + @Test + public void testOptional() { + TupleMetadata schema = new SchemaBuilder() + .addNullable("a", MinorType.VARCHAR) + .buildSchema(); + + SingleRowSet rowSet1 = fixture.rowSetBuilder(schema) + .addSingleCol("sixth") + .addSingleCol(null) + .addSingleCol("fourth") + .build(); + + SingleRowSet rowSet2 = fixture.rowSetBuilder(schema) + .addSingleCol(null) + .addSingleCol("first") + .addSingleCol("third") + .build(); + + // Build the hyper batch + + HyperRowSet hyperSet = HyperRowSetImpl.fromRowSets(fixture.allocator(), rowSet1, rowSet2); + assertEquals(6, hyperSet.rowCount()); + SelectionVector4 sv4 = hyperSet.getSv4(); + sv4.set(0, 1, 1); + sv4.set(1, 0, 1); + sv4.set(2, 1, 2); + sv4.set(3, 0, 2); + sv4.set(4, 1, 0); + sv4.set(5, 0, 0); + + SingleRowSet expected = fixture.rowSetBuilder(schema) + .addSingleCol("first") + .addSingleCol(null) + .addSingleCol("third") + .addSingleCol("fourth") + .addSingleCol(null) + .addSingleCol("sixth") + .build(); + + RowSetUtilities.verify(expected, hyperSet); + } + + /** + * Test an array to test the indirection from the repeated vector + * to the array offsets vector and the array values vector. (Uses + * varchar to add another level of indirection to the data offset + * and data values vectors.) + */ + + @Test + public void testRepeated() { + TupleMetadata schema = new SchemaBuilder() + .addArray("a", MinorType.VARCHAR) + .buildSchema(); + + SingleRowSet rowSet1 = fixture.rowSetBuilder(schema) + .addSingleCol(strArray("sixth", "6.1", "6.2")) + .addSingleCol(strArray("second", "2.1", "2.2", "2.3")) + .addSingleCol(strArray("fourth", "4.1")) + .build(); + + SingleRowSet rowSet2 = fixture.rowSetBuilder(schema) + .addSingleCol(strArray("fifth", "51", "5.2")) + .addSingleCol(strArray("first", "1.1", "1.2", "1.3")) + .addSingleCol(strArray("third", "3.1")) + .build(); + + // Build the hyper batch + + HyperRowSet hyperSet = HyperRowSetImpl.fromRowSets(fixture.allocator(), rowSet1, rowSet2); + assertEquals(6, hyperSet.rowCount()); + SelectionVector4 sv4 = hyperSet.getSv4(); + sv4.set(0, 1, 1); + sv4.set(1, 0, 1); + sv4.set(2, 1, 2); + sv4.set(3, 0, 2); + sv4.set(4, 1, 0); + sv4.set(5, 0, 0); + + SingleRowSet expected = fixture.rowSetBuilder(schema) + .addSingleCol(strArray("first", "1.1", "1.2", "1.3")) + .addSingleCol(strArray("second", "2.1", "2.2", "2.3")) + .addSingleCol(strArray("third", "3.1")) + .addSingleCol(strArray("fourth", "4.1")) + .addSingleCol(strArray("fifth", "51", "5.2")) + .addSingleCol(strArray("sixth", "6.1", "6.2")) + .build(); + + RowSetUtilities.verify(expected, hyperSet); + } + + /** + * Maps are an interesting case. The hyper-vector wrapper holds a mirror-image of the + * map members. So, we can reach the map members either via the vector wrappers or + * the original map vector. + */ + + @Test + public void testMap() { + TupleMetadata schema = new SchemaBuilder() + .addMap("m") + .add("a", MinorType.INT) + .add("b", MinorType.VARCHAR) + .resumeSchema() + .buildSchema(); + + SingleRowSet rowSet1 = fixture.rowSetBuilder(schema) + .addSingleCol(mapValue(2, "second")) + .addSingleCol(mapValue(4, "fourth")) + .build(); + + SingleRowSet rowSet2 = fixture.rowSetBuilder(schema) + .addSingleCol(mapValue(2, "first")) + .addSingleCol(mapValue(4, "third")) + .build(); + + // Build the hyper batch + + HyperRowSet hyperSet = HyperRowSetImpl.fromRowSets(fixture.allocator(), rowSet1, rowSet2); + assertEquals(4, hyperSet.rowCount()); + SelectionVector4 sv4 = hyperSet.getSv4(); + sv4.set(0, 1, 0); + sv4.set(1, 0, 0); + sv4.set(2, 1, 1); + sv4.set(3, 0, 1); + + SingleRowSet expected = fixture.rowSetBuilder(schema) + .addSingleCol(mapValue(2, "first")) + .addSingleCol(mapValue(2, "second")) + .addSingleCol(mapValue(4, "third")) + .addSingleCol(mapValue(4, "fourth")) + .build(); + + RowSetUtilities.verify(expected, hyperSet); + } + + @Test + public void testRepeatedMap() { + TupleMetadata schema = new SchemaBuilder() + .add("a", MinorType.INT) + .addMapArray("ma") + .add("b", MinorType.INT) + .add("c", MinorType.VARCHAR) + .resumeSchema() + .buildSchema(); + + SingleRowSet rowSet1 = fixture.rowSetBuilder(schema) + .addRow(2, mapArray(mapValue(21, "second.1"), mapValue(22, "second.2"))) + .addRow(4, mapArray(mapValue(41, "fourth.1"))) + .build(); + + SingleRowSet rowSet2 = fixture.rowSetBuilder(schema) + .addRow(1, mapArray(mapValue(11, "first.1"), mapValue(12, "first.2"))) + .addRow(3, mapArray(mapValue(31, "third.1"), mapValue(32, "third.2"), mapValue(33, "third.3"))) + .build(); + + // Build the hyper batch + + HyperRowSet hyperSet = HyperRowSetImpl.fromRowSets(fixture.allocator(), rowSet1, rowSet2); + assertEquals(4, hyperSet.rowCount()); + SelectionVector4 sv4 = hyperSet.getSv4(); + sv4.set(0, 1, 0); + sv4.set(1, 0, 0); + sv4.set(2, 1, 1); + sv4.set(3, 0, 1); + + SingleRowSet expected = fixture.rowSetBuilder(schema) + .addRow(1, mapArray(mapValue(11, "first.1"), mapValue(12, "first.2"))) + .addRow(2, mapArray(mapValue(21, "second.1"), mapValue(22, "second.2"))) + .addRow(3, mapArray(mapValue(31, "third.1"), mapValue(32, "third.2"), mapValue(33, "third.3"))) + .addRow(4, mapArray(mapValue(41, "fourth.1"))) + .build(); + + RowSetUtilities.verify(expected, hyperSet); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/4f2182e4/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestScalarAccessors.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestScalarAccessors.java b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestScalarAccessors.java index 1daeef4..ecd1ebc 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestScalarAccessors.java +++ b/exec/java-exec/src/test/java/org/apache/drill/test/rowSet/test/TestScalarAccessors.java @@ -26,7 +26,8 @@ import org.apache.drill.common.types.TypeProtos.DataMode; import org.apache.drill.common.types.TypeProtos.MajorType; import org.apache.drill.common.types.TypeProtos.MinorType; import org.apache.drill.exec.record.BatchSchema; -import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.DateUtilities; +import org.apache.drill.exec.vector.accessor.ArrayReader; import org.apache.drill.exec.vector.accessor.ScalarReader; import org.apache.drill.exec.vector.accessor.ValueType; import org.apache.drill.test.SubOperatorTest; @@ -36,6 +37,8 @@ import org.apache.drill.test.rowSet.RowSet.SingleRowSet; import org.apache.drill.test.rowSet.schema.SchemaBuilder; import org.junit.Test; +import com.google.common.collect.Lists; + /** * Verify that simple scalar (non-repeated) column readers * and writers work as expected. The focus is on the generated @@ -51,6 +54,70 @@ import org.junit.Test; public class TestScalarAccessors extends SubOperatorTest { @Test + public void testUInt1RW() { + BatchSchema batchSchema = new SchemaBuilder() + .add("col", MinorType.UINT1) + .build(); + SingleRowSet rs = fixture.rowSetBuilder(batchSchema) + .addRow(0) + .addRow(0x7F) + .addRow(0xFF) + .build(); + assertEquals(3, rs.rowCount()); + + RowSetReader reader = rs.reader(); + ScalarReader colReader = reader.scalar(0); + assertEquals(ValueType.INTEGER, colReader.valueType()); + + assertTrue(reader.next()); + assertFalse(colReader.isNull()); + assertEquals(0, colReader.getInt()); + + assertTrue(reader.next()); + assertEquals(0x7F, colReader.getInt()); + assertEquals(0x7F, colReader.getObject()); + assertEquals(Integer.toString(0x7F), colReader.getAsString()); + + assertTrue(reader.next()); + assertEquals(0xFF, colReader.getInt()); + + assertFalse(reader.next()); + rs.clear(); + } + + @Test + public void testUInt2RW() { + BatchSchema batchSchema = new SchemaBuilder() + .add("col", MinorType.UINT2) + .build(); + SingleRowSet rs = fixture.rowSetBuilder(batchSchema) + .addRow(0) + .addRow(0x7FFF) + .addRow(0xFFFF) + .build(); + assertEquals(3, rs.rowCount()); + + RowSetReader reader = rs.reader(); + ScalarReader colReader = reader.scalar(0); + assertEquals(ValueType.INTEGER, colReader.valueType()); + + assertTrue(reader.next()); + assertFalse(colReader.isNull()); + assertEquals(0, colReader.getInt()); + + assertTrue(reader.next()); + assertEquals(0x7FFF, colReader.getInt()); + assertEquals(0x7FFF, colReader.getObject()); + assertEquals(Integer.toString(0x7FFF), colReader.getAsString()); + + assertTrue(reader.next()); + assertEquals(0xFFFF, colReader.getInt()); + + assertFalse(reader.next()); + rs.clear(); + } + + @Test public void testTinyIntRW() { BatchSchema batchSchema = new SchemaBuilder() .add("col", MinorType.TINYINT) @@ -129,23 +196,37 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.INTEGER, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(0, colReader.getInt(0)); - assertEquals(20, colReader.getInt(1)); - assertEquals(30, colReader.getInt(2)); - assertEquals(0, colReader.getObject(0)); - assertEquals(20, colReader.getObject(1)); - assertEquals(30, colReader.getObject(2)); - assertEquals("0", colReader.getAsString(0)); - assertEquals("20", colReader.getAsString(1)); - assertEquals("30", colReader.getAsString(2)); + assertEquals(3, arrayReader.size()); + assertTrue(arrayReader.next()); + assertFalse(colReader.isNull()); + assertEquals(0, colReader.getInt()); + assertEquals(0, colReader.getObject()); + assertEquals("0", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertFalse(colReader.isNull()); + assertEquals(20, colReader.getInt()); + assertEquals(20, colReader.getObject()); + assertEquals("20", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertFalse(colReader.isNull()); + assertEquals(30, colReader.getInt()); + assertEquals(30, colReader.getObject()); + assertEquals("30", colReader.getAsString()); + + assertFalse(arrayReader.next()); + + assertEquals("[0, 20, 30]", arrayReader.getAsString()); + assertEquals(Lists.newArrayList(0, 20, 30), arrayReader.getObject()); assertFalse(reader.next()); rs.clear(); @@ -323,23 +404,35 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.LONG, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(0, colReader.getLong(0)); - assertEquals(20, colReader.getLong(1)); - assertEquals(30, colReader.getLong(2)); - assertEquals(0L, colReader.getObject(0)); - assertEquals(20L, colReader.getObject(1)); - assertEquals(30L, colReader.getObject(2)); - assertEquals("0", colReader.getAsString(0)); - assertEquals("20", colReader.getAsString(1)); - assertEquals("30", colReader.getAsString(2)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(0, colReader.getLong()); + assertEquals(0L, colReader.getObject()); + assertEquals("0", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(20, colReader.getLong()); + assertEquals(20L, colReader.getObject()); + assertEquals("20", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(30, colReader.getLong()); + assertEquals(30L, colReader.getObject()); + assertEquals("30", colReader.getAsString()); + + assertFalse(arrayReader.next()); + + assertEquals("[0, 20, 30]", arrayReader.getAsString()); + assertEquals(Lists.newArrayList(0L, 20L, 30L), arrayReader.getObject()); assertFalse(reader.next()); rs.clear(); @@ -373,7 +466,7 @@ public class TestScalarAccessors extends SubOperatorTest { assertTrue(reader.next()); assertEquals(Float.MAX_VALUE, colReader.getDouble(), 0.000001); - assertEquals((double) Float.MAX_VALUE, (double) colReader.getObject(), 0.000001); + assertEquals(Float.MAX_VALUE, (double) colReader.getObject(), 0.000001); assertTrue(reader.next()); assertEquals(Float.MIN_VALUE, colReader.getDouble(), 0.000001); @@ -433,23 +526,34 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.DOUBLE, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(0, colReader.getDouble(0), 0.00001); - assertEquals(20.5, colReader.getDouble(1), 0.00001); - assertEquals(30.0, colReader.getDouble(2), 0.00001); - assertEquals(0, (double) colReader.getObject(0), 0.00001); - assertEquals(20.5, (double) colReader.getObject(1), 0.00001); - assertEquals(30.0, (double) colReader.getObject(2), 0.00001); - assertEquals("0.0", colReader.getAsString(0)); - assertEquals("20.5", colReader.getAsString(1)); - assertEquals("30.0", colReader.getAsString(2)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(0, colReader.getDouble(), 0.00001); + assertEquals(0, (double) colReader.getObject(), 0.00001); + assertEquals("0.0", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(20.5, colReader.getDouble(), 0.00001); + assertEquals(20.5, (double) colReader.getObject(), 0.00001); + assertEquals("20.5", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(30.0, colReader.getDouble(), 0.00001); + assertEquals(30.0, (double) colReader.getObject(), 0.00001); + assertEquals("30.0", colReader.getAsString()); + assertFalse(arrayReader.next()); + + assertEquals("[0.0, 20.5, 30.0]", arrayReader.getAsString()); + assertEquals(Lists.newArrayList(0.0D, 20.5D, 30D), arrayReader.getObject()); assertFalse(reader.next()); rs.clear(); @@ -507,15 +611,16 @@ public class TestScalarAccessors extends SubOperatorTest { } @Test - public void testStringRW() { + public void testVarcharRW() { BatchSchema batchSchema = new SchemaBuilder() .add("col", MinorType.VARCHAR) .build(); SingleRowSet rs = fixture.rowSetBuilder(batchSchema) .addRow("") - .addRow("abcd") + .addRow("fred") + .addRow("barney") .build(); - assertEquals(2, rs.rowCount()); + assertEquals(3, rs.rowCount()); RowSetReader reader = rs.reader(); ScalarReader colReader = reader.scalar(0); @@ -526,16 +631,21 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals("", colReader.getString()); assertTrue(reader.next()); - assertEquals("abcd", colReader.getString()); - assertEquals("abcd", colReader.getObject()); - assertEquals("\"abcd\"", colReader.getAsString()); + assertEquals("fred", colReader.getString()); + assertEquals("fred", colReader.getObject()); + assertEquals("\"fred\"", colReader.getAsString()); + + assertTrue(reader.next()); + assertEquals("barney", colReader.getString()); + assertEquals("barney", colReader.getObject()); + assertEquals("\"barney\"", colReader.getAsString()); assertFalse(reader.next()); rs.clear(); } @Test - public void testNullableString() { + public void testNullableVarchar() { BatchSchema batchSchema = new SchemaBuilder() .addNullable("col", MinorType.VARCHAR) .build(); @@ -568,7 +678,7 @@ public class TestScalarAccessors extends SubOperatorTest { } @Test - public void testStringArray() { + public void testVarcharArray() { BatchSchema batchSchema = new SchemaBuilder() .addArray("col", MinorType.VARCHAR) .build(); @@ -579,28 +689,71 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.STRING, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals("fred", colReader.getString(0)); - assertEquals("", colReader.getString(1)); - assertEquals("wilma", colReader.getString(2)); - assertEquals("fred", colReader.getObject(0)); - assertEquals("", colReader.getObject(1)); - assertEquals("wilma", colReader.getObject(2)); - assertEquals("\"fred\"", colReader.getAsString(0)); - assertEquals("\"\"", colReader.getAsString(1)); - assertEquals("\"wilma\"", colReader.getAsString(2)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals("fred", colReader.getString()); + assertEquals("fred", colReader.getObject()); + assertEquals("\"fred\"", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals("", colReader.getString()); + assertEquals("", colReader.getObject()); + assertEquals("\"\"", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals("wilma", colReader.getString()); + assertEquals("wilma", colReader.getObject()); + assertEquals("\"wilma\"", colReader.getAsString()); + + assertFalse(arrayReader.next()); + + assertEquals("[\"fred\", \"\", \"wilma\"]", arrayReader.getAsString()); + assertEquals(Lists.newArrayList("fred", "", "wilma"), arrayReader.getObject()); assertFalse(reader.next()); rs.clear(); } + /** + * Test the low-level interval-year utilities used by the column accessors. + */ + + @Test + public void testIntervalYearUtils() { + { + Period expected = Period.months(0); + Period actual = DateUtilities.fromIntervalYear(0); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalYearStringBuilder(expected).toString(); + assertEquals("0 years 0 months", fmt); + } + + { + Period expected = Period.years(1).plusMonths(2); + Period actual = DateUtilities.fromIntervalYear(DateUtilities.periodToMonths(expected)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalYearStringBuilder(expected).toString(); + assertEquals("1 year 2 months", fmt); + } + + { + Period expected = Period.years(6).plusMonths(1); + Period actual = DateUtilities.fromIntervalYear(DateUtilities.periodToMonths(expected)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalYearStringBuilder(expected).toString(); + assertEquals("6 years 1 month", fmt); + } + } + @Test public void testIntervalYearRW() { BatchSchema batchSchema = new SchemaBuilder() @@ -664,7 +817,6 @@ public class TestScalarAccessors extends SubOperatorTest { assertTrue(reader.next()); assertTrue(colReader.isNull()); - assertNull(colReader.getPeriod()); assertNull(colReader.getObject()); assertEquals("null", colReader.getAsString()); @@ -692,24 +844,64 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.PERIOD, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(p1, colReader.getPeriod(0)); - assertEquals(p2, colReader.getPeriod(1)); - assertEquals(p3, colReader.getPeriod(2)); - assertEquals(p2, colReader.getObject(1)); - assertEquals(p2.toString(), colReader.getAsString(1)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(p1, colReader.getPeriod()); + + assertTrue(arrayReader.next()); + assertEquals(p2, colReader.getPeriod()); + assertEquals(p2, colReader.getObject()); + assertEquals(p2.toString(), colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(p3, colReader.getPeriod()); + + assertFalse(arrayReader.next()); assertFalse(reader.next()); rs.clear(); } + /** + * Test the low-level interval-day utilities used by the column accessors. + */ + + @Test + public void testIntervalDayUtils() { + { + Period expected = Period.days(0); + Period actual = DateUtilities.fromIntervalDay(0, 0); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalDayStringBuilder(expected).toString(); + assertEquals("0 days 0:00:00", fmt); + } + + { + Period expected = Period.days(1).plusHours(5).plusMinutes(6).plusSeconds(7); + Period actual = DateUtilities.fromIntervalDay(1, DateUtilities.timeToMillis(5, 6, 7, 0)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalDayStringBuilder(expected).toString(); + assertEquals("1 day 5:06:07", fmt); + } + + { + Period expected = Period.days(2).plusHours(12).plusMinutes(23).plusSeconds(34).plusMillis(567); + Period actual = DateUtilities.fromIntervalDay(2, DateUtilities.timeToMillis(12, 23, 34, 567)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalDayStringBuilder(expected).toString(); + assertEquals("2 days 12:23:34.567", fmt); + } + } + @Test public void testIntervalDayRW() { BatchSchema batchSchema = new SchemaBuilder() @@ -774,7 +966,6 @@ public class TestScalarAccessors extends SubOperatorTest { assertTrue(reader.next()); assertTrue(colReader.isNull()); - assertNull(colReader.getPeriod()); assertNull(colReader.getObject()); assertEquals("null", colReader.getAsString()); @@ -802,24 +993,79 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.PERIOD, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(p1, colReader.getPeriod(0).normalizedStandard()); - assertEquals(p2, colReader.getPeriod(1).normalizedStandard()); - assertEquals(p3.normalizedStandard(), colReader.getPeriod(2).normalizedStandard()); - assertEquals(p2, ((Period) colReader.getObject(1)).normalizedStandard()); - assertEquals(p2.toString(), colReader.getAsString(1)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(p1, colReader.getPeriod().normalizedStandard()); + + assertTrue(arrayReader.next()); + assertEquals(p2, colReader.getPeriod().normalizedStandard()); + assertEquals(p2, ((Period) colReader.getObject()).normalizedStandard()); + assertEquals(p2.toString(), colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(p3.normalizedStandard(), colReader.getPeriod().normalizedStandard()); + + assertFalse(arrayReader.next()); assertFalse(reader.next()); rs.clear(); } + /** + * Test the low-level interval utilities used by the column accessors. + */ + + @Test + public void testIntervalUtils() { + { + Period expected = Period.months(0); + Period actual = DateUtilities.fromInterval(0, 0, 0); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalStringBuilder(expected).toString(); + assertEquals("0 years 0 months 0 days 0:00:00", fmt); + } + + { + Period expected = Period.years(1).plusMonths(2).plusDays(3) + .plusHours(5).plusMinutes(6).plusSeconds(7); + Period actual = DateUtilities.fromInterval(DateUtilities.periodToMonths(expected), 3, + DateUtilities.periodToMillis(expected)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalStringBuilder(expected).toString(); + assertEquals("1 year 2 months 3 days 5:06:07", fmt); + } + + { + Period expected = Period.years(2).plusMonths(1).plusDays(3) + .plusHours(12).plusMinutes(23).plusSeconds(34) + .plusMillis(456); + Period actual = DateUtilities.fromInterval(DateUtilities.periodToMonths(expected), 3, + DateUtilities.periodToMillis(expected)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalStringBuilder(expected).toString(); + assertEquals("2 years 1 month 3 days 12:23:34.456", fmt); + } + + { + Period expected = Period.years(2).plusMonths(3).plusDays(1) + .plusHours(12).plusMinutes(23).plusSeconds(34); + Period actual = DateUtilities.fromInterval(DateUtilities.periodToMonths(expected), 1, + DateUtilities.periodToMillis(expected)); + assertEquals(expected, actual.normalizedStandard()); + String fmt = DateUtilities.intervalStringBuilder(expected).toString(); + assertEquals("2 years 3 months 1 day 12:23:34", fmt); + } + } + @Test public void testIntervalRW() { BatchSchema batchSchema = new SchemaBuilder() @@ -890,7 +1136,6 @@ public class TestScalarAccessors extends SubOperatorTest { assertTrue(reader.next()); assertTrue(colReader.isNull()); - assertNull(colReader.getPeriod()); assertNull(colReader.getObject()); assertEquals("null", colReader.getAsString()); @@ -922,19 +1167,28 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.PERIOD, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(p1, colReader.getPeriod(0).normalizedStandard()); - assertEquals(p2, colReader.getPeriod(1).normalizedStandard()); - assertEquals(p3.normalizedStandard(), colReader.getPeriod(2).normalizedStandard()); - assertEquals(p2, ((Period) colReader.getObject(1)).normalizedStandard()); - assertEquals(p2.toString(), colReader.getAsString(1)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(p1, colReader.getPeriod().normalizedStandard()); + + assertTrue(arrayReader.next()); + assertEquals(p2, colReader.getPeriod().normalizedStandard()); + assertEquals(p2, ((Period) colReader.getObject()).normalizedStandard()); + assertEquals(p2.toString(), colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(p3.normalizedStandard(), colReader.getPeriod().normalizedStandard()); + + assertFalse(arrayReader.next()); assertFalse(reader.next()); rs.clear(); @@ -1051,19 +1305,28 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.DECIMAL, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertEquals(0, v1.compareTo(colReader.getDecimal(0))); - assertEquals(0, v2.compareTo(colReader.getDecimal(1))); - assertEquals(0, v3.compareTo(colReader.getDecimal(2))); - assertEquals(0, v2.compareTo((BigDecimal) colReader.getObject(1))); - assertEquals(v2.toString(), colReader.getAsString(1)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertEquals(0, v1.compareTo(colReader.getDecimal())); + + assertTrue(arrayReader.next()); + assertEquals(0, v2.compareTo(colReader.getDecimal())); + assertEquals(0, v2.compareTo((BigDecimal) colReader.getObject())); + assertEquals(v2.toString(), colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertEquals(0, v3.compareTo(colReader.getDecimal())); + + assertFalse(arrayReader.next()); assertFalse(reader.next()); rs.clear(); @@ -1246,19 +1509,28 @@ public class TestScalarAccessors extends SubOperatorTest { assertEquals(2, rs.rowCount()); RowSetReader reader = rs.reader(); - ScalarElementReader colReader = reader.elements(0); + ArrayReader arrayReader = reader.array(0); + ScalarReader colReader = arrayReader.scalar(); assertEquals(ValueType.BYTES, colReader.valueType()); assertTrue(reader.next()); - assertEquals(0, colReader.size()); + assertEquals(0, arrayReader.size()); assertTrue(reader.next()); - assertEquals(3, colReader.size()); - assertTrue(Arrays.equals(v1, colReader.getBytes(0))); - assertTrue(Arrays.equals(v2, colReader.getBytes(1))); - assertTrue(Arrays.equals(v3, colReader.getBytes(2))); - assertTrue(Arrays.equals(v2, (byte[]) colReader.getObject(1))); - assertEquals("[00, 7f, 80, ff]", colReader.getAsString(1)); + assertEquals(3, arrayReader.size()); + + assertTrue(arrayReader.next()); + assertTrue(Arrays.equals(v1, colReader.getBytes())); + + assertTrue(arrayReader.next()); + assertTrue(Arrays.equals(v2, colReader.getBytes())); + assertTrue(Arrays.equals(v2, (byte[]) colReader.getObject())); + assertEquals("[00, 7f, 80, ff]", colReader.getAsString()); + + assertTrue(arrayReader.next()); + assertTrue(Arrays.equals(v3, colReader.getBytes())); + + assertFalse(arrayReader.next()); assertFalse(reader.next()); rs.clear();