From 022c5e9ed08c6393166e66ac5e862168bc6c5e77 Mon Sep 17 00:00:00 2001 From: Paul Rogers Date: Wed, 26 Jul 2017 22:03:50 -0700 Subject: [PATCH 01/10] DRILL-5688: Add repeated map support to column accessors Includes the core JSON-like reader and writer interfaces and implementations. --- .../codegen/templates/ColumnAccessors.java | 373 ++++++++++-------- .../vector/accessor/AccessorUtilities.java | 125 ------ .../exec/vector/accessor/ArrayReader.java | 108 +++-- .../exec/vector/accessor/ArrayWriter.java | 62 ++- .../vector/accessor/ColumnReaderIndex.java | 23 ++ .../exec/vector/accessor/ColumnWriter.java | 45 --- .../vector/accessor/ColumnWriterIndex.java | 23 ++ .../exec/vector/accessor/ObjectReader.java | 60 +++ .../exec/vector/accessor/ObjectType.java | 22 ++ .../exec/vector/accessor/ObjectWriter.java | 55 +++ .../vector/accessor/ScalarElementReader.java | 65 +++ .../{ColumnReader.java => ScalarReader.java} | 17 +- .../exec/vector/accessor/ScalarWriter.java | 47 ++- .../exec/vector/accessor/TupleAccessor.java | 59 --- .../exec/vector/accessor/TupleReader.java | 31 +- .../exec/vector/accessor/TupleWriter.java | 83 +++- .../{ColumnAccessor.java => ValueType.java} | 25 +- .../accessor/impl/AbstractArrayReader.java | 128 ------ .../accessor/impl/AbstractArrayWriter.java | 127 ------ .../accessor/impl/AbstractColumnReader.java | 126 ------ .../accessor/impl/AbstractColumnWriter.java | 87 ---- .../accessor/impl/AccessorUtilities.java | 88 +++++ .../accessor/impl/ColumnAccessorFactory.java | 174 ++++---- .../vector/accessor/impl/TupleReaderImpl.java | 151 ------- .../vector/accessor/impl/TupleWriterImpl.java | 162 -------- .../exec/vector/accessor/package-info.java | 35 +- .../accessor/reader/AbstractArrayReader.java | 186 +++++++++ .../accessor/reader/AbstractObjectReader.java | 52 +++ .../accessor/reader/AbstractTupleReader.java | 189 +++++++++ .../accessor/reader/BaseElementReader.java | 187 +++++++++ .../accessor/reader/BaseScalarReader.java | 186 +++++++++ .../accessor/reader/ElementReaderIndex.java | 24 ++ .../reader/FixedWidthElementReaderIndex.java | 38 ++ .../vector/accessor/reader/MapReader.java | 35 ++ .../accessor/reader/ObjectArrayReader.java | 159 ++++++++ .../accessor/reader/ScalarArrayReader.java | 102 +++++ .../VectorAccessor.java} | 27 +- .../vector/accessor/reader/package-info.java | 26 ++ .../accessor/writer/AbstractArrayWriter.java | 184 +++++++++ .../accessor/writer/AbstractObjectWriter.java | 49 +++ .../accessor/writer/AbstractScalarWriter.java | 198 ++++++++++ .../accessor/writer/AbstractTupleWriter.java | 223 +++++++++++ .../accessor/writer/BaseElementWriter.java | 41 ++ .../accessor/writer/BaseScalarWriter.java | 47 +++ .../ElementWriterIndex.java} | 22 +- .../writer/FixedWidthElementWriterIndex.java | 57 +++ .../vector/accessor/writer/MapWriter.java | 35 ++ .../accessor/writer/ObjectArrayWriter.java | 58 +++ .../accessor/writer/ScalarArrayWriter.java | 204 ++++++++++ .../vector/accessor/writer/WriterEvents.java | 25 ++ .../vector/accessor/writer/package-info.java | 25 ++ 51 files changed, 3313 insertions(+), 1367 deletions(-) delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/AccessorUtilities.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReaderIndex.java delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriterIndex.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectType.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarElementReader.java rename exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/{ColumnReader.java => ScalarReader.java} (85%) delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleAccessor.java rename exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/{ColumnAccessor.java => ValueType.java} (58%) delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayReader.java delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayWriter.java delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnReader.java delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AccessorUtilities.java delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleReaderImpl.java delete mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleWriterImpl.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractArrayReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractObjectReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractTupleReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseElementReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseScalarReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ElementReaderIndex.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/FixedWidthElementReaderIndex.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/MapReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ObjectArrayReader.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ScalarArrayReader.java rename exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/{impl/AbstractColumnAccessor.java => reader/VectorAccessor.java} (59%) create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/package-info.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractArrayWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractObjectWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractScalarWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractTupleWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/BaseElementWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/BaseScalarWriter.java rename exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/{impl/AbstractTupleAccessor.java => writer/ElementWriterIndex.java} (65%) create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/FixedWidthElementWriterIndex.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/MapWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/ObjectArrayWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/ScalarArrayWriter.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/WriterEvents.java create mode 100644 exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/package-info.java diff --git a/exec/vector/src/main/codegen/templates/ColumnAccessors.java b/exec/vector/src/main/codegen/templates/ColumnAccessors.java index f1fbf2f057c..045eca40270 100644 --- a/exec/vector/src/main/codegen/templates/ColumnAccessors.java +++ b/exec/vector/src/main/codegen/templates/ColumnAccessors.java @@ -19,143 +19,230 @@ <@pp.dropOutputFile /> <@pp.changeOutputFile name="/org/apache/drill/exec/vector/accessor/ColumnAccessors.java" /> <#include "/@includes/license.ftl" /> -<#macro getType label> +<#macro getType drillType label> @Override public ValueType valueType() { <#if label == "Int"> return ValueType.INTEGER; + <#elseif drillType == "VarChar" || drillType == "Var16Char"> + return ValueType.STRING; <#else> return ValueType.${label?upper_case}; } -<#macro bindReader prefix drillType> +<#macro bindReader vectorPrefix drillType isArray > <#if drillType = "Decimal9" || drillType == "Decimal18"> - private MaterializedField field; + private MajorType type; - private ${prefix}${drillType}Vector.Accessor accessor; + private ${vectorPrefix}${drillType}Vector.Accessor accessor; @Override - public void bind(RowIndex vectorIndex, ValueVector vector) { - bind(vectorIndex); + public void bindVector(ValueVector vector) { <#if drillType = "Decimal9" || drillType == "Decimal18"> - field = vector.getField(); + type = vector.getField().getType(); - accessor = ((${prefix}${drillType}Vector) vector).getAccessor(); + accessor = ((${vectorPrefix}${drillType}Vector) vector).getAccessor(); } <#if drillType = "Decimal9" || drillType == "Decimal18"> @Override - public void bind(RowIndex vectorIndex, MaterializedField field, VectorAccessor va) { - bind(vectorIndex, field, va); - this.field = field; + public void bindVector(MajorType type, VectorAccessor va) { + super.bindVector(type, va); + this.type = type; } - private ${prefix}${drillType}Vector.Accessor accessor() { + private ${vectorPrefix}${drillType}Vector.Accessor accessor() { if (vectorAccessor == null) { return accessor; } else { - return ((${prefix}${drillType}Vector) vectorAccessor.vector()).getAccessor(); + return ((${vectorPrefix}${drillType}Vector) vectorAccessor.vector()).getAccessor(); } } <#macro get drillType accessorType label isArray> @Override public ${accessorType} get${label}(<#if isArray>int index) { + <#assign getObject ="getObject"/> <#if isArray> - <#assign index=", index"/> - <#assign getObject="getSingleObject"> + <#assign indexVar = "index"/> <#else> - <#assign index=""/> - <#assign getObject="getObject"> + <#assign indexVar = ""/> - <#if drillType == "VarChar"> - return new String(accessor().get(vectorIndex.index()${index}), Charsets.UTF_8); - <#elseif drillType == "Var16Char"> - return new String(accessor().get(vectorIndex.index()${index}), Charsets.UTF_16); - <#elseif drillType == "VarBinary"> - return accessor().get(vectorIndex.index()${index}); + <#if drillType == "VarChar" || drillType == "Var16Char" || drillType == "VarBinary"> + return accessor().get(vectorIndex.vectorIndex(${indexVar})); <#elseif drillType == "Decimal9" || drillType == "Decimal18"> return DecimalUtility.getBigDecimalFromPrimitiveTypes( - accessor().get(vectorIndex.index()${index}), - field.getScale(), - field.getPrecision()); + accessor().get(vectorIndex.vectorIndex(${indexVar})), + type.getScale(), + type.getPrecision()); <#elseif accessorType == "BigDecimal" || accessorType == "Period"> - return accessor().${getObject}(vectorIndex.index()${index}); + return accessor().${getObject}(vectorIndex.vectorIndex(${indexVar})); <#else> - return accessor().get(vectorIndex.index()${index}); + return accessor().get(vectorIndex.vectorIndex(${indexVar})); } + <#if drillType == "VarChar"> + + @Override + public String getString(<#if isArray>int index) { + return new String(getBytes(${indexVar}), Charsets.UTF_8); + } + <#elseif drillType == "Var16Char"> + + @Override + public String getString(<#if isArray>int index) { + return new String(getBytes(${indexVar}), Charsets.UTF_16); + } + -<#macro bindWriter prefix drillType> +<#macro bindWriter vectorPrefix mode drillType> <#if drillType = "Decimal9" || drillType == "Decimal18"> - private MaterializedField field; + private MajorType type; - private ${prefix}${drillType}Vector.Mutator mutator; + private ${vectorPrefix}${drillType}Vector.Mutator mutator; @Override - public void bind(RowIndex vectorIndex, ValueVector vector) { - bind(vectorIndex); + public void bindVector(ValueVector vector) { <#if drillType = "Decimal9" || drillType == "Decimal18"> - field = vector.getField(); + type = vector.getField().getType(); - this.mutator = ((${prefix}${drillType}Vector) vector).getMutator(); + this.mutator = ((${vectorPrefix}${drillType}Vector) vector).getMutator(); } -<#macro set drillType accessorType label nullable verb> +<#-- DRILL-5529 describes how required and repeated vectors don't implement + fillEmpties() to recover from skiped writes. Since the mutator does + not do the work, we must insert code here to do it. + DRILL-5530 describes why required vectors may not be initialized + to zeros. --> +<#macro fillEmpties drillType mode> + <#if mode == "" && drillType != "Bit"> + // Work-around for DRILL-5529: lack of fillEmpties for some vectors. + // See DRILL-5530 for why this is needed for required vectors. + if (lastWriteIndex + 1 < writeIndex) { + mutator.fillEmptiesBounded(lastWriteIndex, writeIndex); + } + + +<#macro advance mode> + <#if mode == "Repeated"> + vectorIndex.next(); + + +<#macro set drillType accessorType label vectorPrefix mode setFn> + <#if accessorType == "byte[]"> + <#assign args = ", int len"> + <#else> + <#assign args = ""> + @Override - public void set${label}(${accessorType} value) { - <#if drillType == "VarChar"> - byte bytes[] = value.getBytes(Charsets.UTF_8); - mutator.${verb}Safe(vectorIndex.index(), bytes, 0, bytes.length); - <#elseif drillType == "Var16Char"> - byte bytes[] = value.getBytes(Charsets.UTF_16); - mutator.${verb}Safe(vectorIndex.index(), bytes, 0, bytes.length); - <#elseif drillType == "VarBinary"> - mutator.${verb}Safe(vectorIndex.index(), value, 0, value.length); + public void set${label}(${accessorType} value${args}) throws VectorOverflowException { + try { + final int writeIndex = vectorIndex.vectorIndex(); + <@fillEmpties drillType mode /> + <#if drillType == "VarChar" || drillType == "Var16Char" || drillType == "VarBinary"> + mutator.${setFn}(writeIndex, value, 0, len); <#elseif drillType == "Decimal9"> - mutator.${verb}Safe(vectorIndex.index(), - DecimalUtility.getDecimal9FromBigDecimal(value, - field.getScale(), field.getPrecision())); + mutator.${setFn}(writeIndex, + DecimalUtility.getDecimal9FromBigDecimal(value, + type.getScale(), type.getPrecision())); <#elseif drillType == "Decimal18"> - mutator.${verb}Safe(vectorIndex.index(), - DecimalUtility.getDecimal18FromBigDecimal(value, - field.getScale(), field.getPrecision())); + mutator.${setFn}(writeIndex, + DecimalUtility.getDecimal18FromBigDecimal(value, + type.getScale(), type.getPrecision())); <#elseif drillType == "IntervalYear"> - mutator.${verb}Safe(vectorIndex.index(), value.getYears() * 12 + value.getMonths()); + mutator.${setFn}(writeIndex, value.getYears() * 12 + value.getMonths()); <#elseif drillType == "IntervalDay"> - mutator.${verb}Safe(vectorIndex.index(),<#if nullable> 1, + mutator.${setFn}(writeIndex,<#if mode == "Nullable"> 1, value.getDays(), - ((value.getHours() * 60 + value.getMinutes()) * 60 + - value.getSeconds()) * 1000 + value.getMillis()); + periodToMillis(value)); <#elseif drillType == "Interval"> - mutator.${verb}Safe(vectorIndex.index(),<#if nullable> 1, + mutator.${setFn}(writeIndex,<#if mode == "Nullable"> 1, value.getYears() * 12 + value.getMonths(), - value.getDays(), - ((value.getHours() * 60 + value.getMinutes()) * 60 + - value.getSeconds()) * 1000 + value.getMillis()); + value.getDays(), periodToMillis(value)); <#else> - mutator.${verb}Safe(vectorIndex.index(), <#if cast=="set">(${javaType}) value); + mutator.${setFn}(writeIndex, <#if cast=="set">(${javaType}) value); + + <#if mode != "Repeated"> + lastWriteIndex = writeIndex; + + } catch (VectorOverflowException e) { + vectorIndex.overflowed(); + throw e; + } + <@advance mode /> + } + <#if drillType == "VarChar"> + + @Override + public void setString(String value) throws VectorOverflowException { + final byte bytes[] = value.getBytes(Charsets.UTF_8); + setBytes(bytes, bytes.length); + } + <#elseif drillType == "Var16Char"> + + @Override + public void setString(String value) throws VectorOverflowException { + final byte bytes[] = value.getBytes(Charsets.UTF_8); + setBytes(bytes, bytes.length); + } + +<#macro finishBatch drillType mode> + @Override + protected void finish() throws VectorOverflowException { + final int rowCount = vectorIndex.vectorIndex(); + <#-- See note above for the fillEmpties macro. --> + <#if mode == "" && drillType != "Bit"> + // Work-around for DRILL-5529: lack of fillEmpties for some vectors. + // See DRILL-5530 for why this is needed for required vectors. + mutator.fillEmptiesBounded(lastWriteIndex, rowCount - 1); + + mutator.setValueCount(rowCount); } +<#macro build types vectorType accessorType> + <#if vectorType == "Repeated"> + <#assign fnPrefix = "Array" /> + <#assign classType = "Element" /> + <#else> + <#assign fnPrefix = vectorType /> + <#assign classType = "Scalar" /> + + <#if vectorType == "Required"> + <#assign vectorPrefix = "" /> + <#else> + <#assign vectorPrefix = vectorType /> + + public static void define${fnPrefix}${accessorType}s( + Class ${accessorType?lower_case}s[]) { + <#list types as type> + <#list type.minor as minor> + <#assign drillType=minor.class> + <#assign notyet=minor.accessorDisabled!type.accessorDisabled!false> + <#if ! notyet> + <#assign typeEnum=drillType?upper_case> + ${accessorType?lower_case}s[MinorType.${typeEnum}.ordinal()] = ${vectorPrefix}${drillType}Column${accessorType}.class; + + + + } + package org.apache.drill.exec.vector.accessor; import java.math.BigDecimal; -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.vector.*; -import org.apache.drill.exec.record.MaterializedField; import org.apache.drill.exec.util.DecimalUtility; -import org.apache.drill.exec.vector.accessor.impl.AbstractColumnReader; -import org.apache.drill.exec.vector.accessor.impl.AbstractColumnWriter; -import org.apache.drill.exec.vector.complex.BaseRepeatedValueVector; -import org.apache.drill.exec.vector.accessor.impl.AbstractArrayReader; -import org.apache.drill.exec.vector.accessor.impl.AbstractArrayWriter; -import org.apache.drill.exec.vector.accessor.impl.AbstractColumnReader.VectorAccessor; +import org.apache.drill.exec.vector.accessor.reader.BaseScalarReader; +import org.apache.drill.exec.vector.accessor.reader.BaseElementReader; +import org.apache.drill.exec.vector.accessor.reader.VectorAccessor; +import org.apache.drill.exec.vector.accessor.writer.BaseScalarWriter; +import org.apache.drill.exec.vector.accessor.writer.BaseElementWriter; import com.google.common.base.Charsets; import org.joda.time.Period; @@ -191,141 +278,115 @@ public class ColumnAccessors { <#if accessorType=="BigDecimal"> <#assign label="Decimal"> + <#if drillType == "VarChar" || drillType == "Var16Char"> + <#assign accessorType = "byte[]"> + <#assign label = "Bytes"> + <#if ! notyet> //------------------------------------------------------------------------ // ${drillType} readers and writers - public static class ${drillType}ColumnReader extends AbstractColumnReader { + public static class ${drillType}ColumnReader extends BaseScalarReader { - <@bindReader "" drillType /> + <@bindReader "" drillType false /> - <@getType label /> + <@getType drillType label /> <@get drillType accessorType label false/> } - public static class Nullable${drillType}ColumnReader extends AbstractColumnReader { + public static class Nullable${drillType}ColumnReader extends BaseScalarReader { - <@bindReader "Nullable" drillType /> + <@bindReader "Nullable" drillType false /> - <@getType label /> + <@getType drillType label /> @Override public boolean isNull() { - return accessor().isNull(vectorIndex.index()); + return accessor().isNull(vectorIndex.vectorIndex()); } - <@get drillType accessorType label false/> + <@get drillType accessorType label false /> } - public static class Repeated${drillType}ColumnReader extends AbstractArrayReader { + public static class Repeated${drillType}ColumnReader extends BaseElementReader { - <@bindReader "Repeated" drillType /> + <@bindReader "" drillType true /> - <@getType label /> + <@getType drillType label /> - @Override - public int size() { - return accessor().getInnerValueCountAt(vectorIndex.index()); - } - - <@get drillType accessorType label true/> + <@get drillType accessorType label true /> } - public static class ${drillType}ColumnWriter extends AbstractColumnWriter { + public static class ${drillType}ColumnWriter extends BaseScalarWriter { + + <@bindWriter "" "Required" drillType /> - <@bindWriter "" drillType /> + <@getType drillType label /> - <@getType label /> + <@set drillType accessorType label "" "Required" "setScalar" /> - <@set drillType accessorType label false "set" /> + <@finishBatch drillType "" /> } - public static class Nullable${drillType}ColumnWriter extends AbstractColumnWriter { + public static class Nullable${drillType}ColumnWriter extends BaseScalarWriter { - <@bindWriter "Nullable" drillType /> + <@bindWriter "Nullable" "Nullable" drillType /> - <@getType label /> + <@getType drillType label /> + <#-- Generated for each type because, unfortunately, there is + no common base class for nullable vectors even though the + null vector is generic and should be common. Instead, the + null vector is generated as part of each kind of nullable + vector. + TODO: Factor out the null vector and move this code to + the base class. + --> @Override - public void setNull() { - mutator.setNull(vectorIndex.index()); + public void setNull() throws VectorOverflowException { + try { + final int writeIndex = vectorIndex.vectorIndex(); + mutator.setNullBounded(writeIndex); + lastWriteIndex = vectorIndex.vectorIndex(); + } catch (VectorOverflowException e) { + vectorIndex.overflowed(); + throw e; + } } - <@set drillType accessorType label true "set" /> + <@set drillType accessorType label "Nullable" "Nullable" "setScalar" /> + + <@finishBatch drillType "Nullable" /> } - public static class Repeated${drillType}ColumnWriter extends AbstractArrayWriter { + public static class Repeated${drillType}ColumnWriter extends BaseElementWriter { - <@bindWriter "Repeated" drillType /> + <@bindWriter "" "Repeated" drillType /> - <@getType label /> + <@getType drillType label /> - protected BaseRepeatedValueVector.BaseRepeatedMutator mutator() { - return mutator; - } - - <@set drillType accessorType label false "add" /> + <@set drillType accessorType label "" "Repeated" "setScalar" /> } - public static void defineReaders( - Class readers[][]) { -<#list vv.types as type> - <#list type.minor as minor> - <#assign drillType=minor.class> - <#assign notyet=minor.accessorDisabled!type.accessorDisabled!false> - <#if ! notyet> - <#assign typeEnum=drillType?upper_case> - readers[MinorType.${typeEnum}.ordinal()][DataMode.REQUIRED.ordinal()] = ${drillType}ColumnReader.class; - readers[MinorType.${typeEnum}.ordinal()][DataMode.OPTIONAL.ordinal()] = Nullable${drillType}ColumnReader.class; - - - + public static int periodToMillis(Period value) { + return ((value.getHours() * 60 + + value.getMinutes()) * 60 + + value.getSeconds()) * 1000 + + value.getMillis(); } +<@build vv.types "Required" "Reader" /> - public static void defineWriters( - Class writers[][]) { -<#list vv.types as type> - <#list type.minor as minor> - <#assign drillType=minor.class> - <#assign notyet=minor.accessorDisabled!type.accessorDisabled!false> - <#if ! notyet> - <#assign typeEnum=drillType?upper_case> - writers[MinorType.${typeEnum}.ordinal()][DataMode.REQUIRED.ordinal()] = ${drillType}ColumnWriter.class; - writers[MinorType.${typeEnum}.ordinal()][DataMode.OPTIONAL.ordinal()] = Nullable${drillType}ColumnWriter.class; - - - - } +<@build vv.types "Nullable" "Reader" /> - public static void defineArrayReaders( - Class readers[]) { -<#list vv.types as type> - <#list type.minor as minor> - <#assign drillType=minor.class> - <#assign notyet=minor.accessorDisabled!type.accessorDisabled!false> - <#if ! notyet> - <#assign typeEnum=drillType?upper_case> - readers[MinorType.${typeEnum}.ordinal()] = Repeated${drillType}ColumnReader.class; - - - - } +<@build vv.types "Repeated" "Reader" /> - public static void defineArrayWriters( - Class writers[]) { -<#list vv.types as type> - <#list type.minor as minor> - <#assign drillType=minor.class> - <#assign notyet=minor.accessorDisabled!type.accessorDisabled!false> - <#if ! notyet> - <#assign typeEnum=drillType?upper_case> - writers[MinorType.${typeEnum}.ordinal()] = Repeated${drillType}ColumnWriter.class; - - - - } +<@build vv.types "Required" "Writer" /> + +<@build vv.types "Nullable" "Writer" /> + +<@build vv.types "Repeated" "Writer" /> } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/AccessorUtilities.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/AccessorUtilities.java deleted file mode 100644 index 708d0db08bf..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/AccessorUtilities.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.exec.vector.accessor; - -import java.math.BigDecimal; - -import org.joda.time.Duration; -import org.joda.time.Period; - -public class AccessorUtilities { - - private AccessorUtilities() { } - - public static void setFromInt(ColumnWriter writer, int value) { - switch (writer.valueType()) { - case BYTES: - writer.setBytes(Integer.toHexString(value).getBytes()); - break; - case DOUBLE: - writer.setDouble(value); - break; - case INTEGER: - writer.setInt(value); - break; - case LONG: - writer.setLong(value); - break; - case STRING: - writer.setString(Integer.toString(value)); - break; - case DECIMAL: - writer.setDecimal(BigDecimal.valueOf(value)); - break; - case PERIOD: - writer.setPeriod(Duration.millis(value).toPeriod()); - break; - default: - throw new IllegalStateException("Unknown writer type: " + writer.valueType()); - } - } - - public static int sv4Batch(int sv4Index) { - return sv4Index >>> 16; - } - - public static int sv4Index(int sv4Index) { - return sv4Index & 0xFFFF; - } - - public static void setBooleanArray(ArrayWriter arrayWriter, boolean[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setInt(value[i] ? 1 : 0); - } - } - - public static void setByteArray(ArrayWriter arrayWriter, byte[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setInt(value[i]); - } - } - - public static void setShortArray(ArrayWriter arrayWriter, short[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setInt(value[i]); - } - } - - public static void setIntArray(ArrayWriter arrayWriter, int[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setInt(value[i]); - } - } - - public static void setLongArray(ArrayWriter arrayWriter, long[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setLong(value[i]); - } - } - - public static void setFloatArray(ArrayWriter arrayWriter, float[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setDouble(value[i]); - } - } - - public static void setDoubleArray(ArrayWriter arrayWriter, double[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setDouble(value[i]); - } - } - - public static void setStringArray(ArrayWriter arrayWriter, String[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setString(value[i]); - } - } - - public static void setPeriodArray(ArrayWriter arrayWriter, Period[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setPeriod(value[i]); - } - } - - public static void setBigDecimalArray(ArrayWriter arrayWriter, - BigDecimal[] value) { - for (int i = 0; i < value.length; i++) { - arrayWriter.setDecimal(value[i]); - } - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayReader.java index 040dcda120b..8f33f0ecf5b 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayReader.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayReader.java @@ -17,36 +17,90 @@ */ package org.apache.drill.exec.vector.accessor; -import java.math.BigDecimal; - -import org.joda.time.Period; - /** - * Interface to access the values of an array column. In general, each - * vector implements just one of the get methods. Check the vector type - * to know which method to use. Though, generally, when writing test - * code, the type is known to the test writer. - *

- * Arrays allow random access to the values within the array. The index - * passed to each method is the index into the array for the current - * row and column. (This means that arrays are three dimensional: - * the usual (row, column) dimensions plus an array index dimension: - * (row, column, array index). - *

- * Note that the isNull() method is provided for completeness, - * but no Drill array allows null values at present. + * Generic array reader. An array is one of the following: + *

+ * {@see ArrayWriter} */ -public interface ArrayReader extends ColumnAccessor { +public interface ArrayReader { + + /** + * Number of elements in the array. + * @return the number of elements + */ + int size(); - boolean isNull(int index); - int getInt(int index); - long getLong(int index); - double getDouble(int index); - String getString(int index); - byte[] getBytes(int index); - BigDecimal getDecimal(int index); - Period getPeriod(int index); - TupleReader map(int index); + + /** + * The object type of the list entry. All entries have the same + * type. + * @return the object type of each entry + */ + + ObjectType entryType(); + + /** + * Return a reader for the elements of a scalar array. + * @return reader for scalar elements + */ + + ScalarElementReader elements(); + + /** + * Return a generic object reader for the array entry. Not available + * for scalar elements. Positions the reader to read the selected + * element. + * + * @param index array index + * @return generic object reader + */ + + ObjectReader entry(int index); + TupleReader tuple(int index); ArrayReader array(int index); + + /** + * Return the generic object reader for the array element. This + * version does not position the reader, the client must + * call {@link setPosn()} to set the position. This form allows + * up-front setup of the readers when convenient for the caller. + */ + + ObjectReader entry(); + TupleReader tuple(); + ArrayReader array(); + + /** + * Set the array reader to read a given array entry. Not used for + * scalars, only for maps and arrays when using the non-indexed + * methods {@link #entry()}, {@link #tuple()} and {@link #array()}. + */ + + void setPosn(int index); + + /** + * Return the entire array as an List of objects. + * Note, even if the array is scalar, the elements are still returned + * as a list. This method is primarily for testing. + * @return array as a List of objects + */ + + Object getObject(); + + /** + * Return the entire array as a string. Primarily for debugging. + * @return string representation of the array + */ + + String getAsString(); } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayWriter.java index 16ff89ed1be..48e2192f9c5 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayWriter.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ArrayWriter.java @@ -17,26 +17,68 @@ */ package org.apache.drill.exec.vector.accessor; +import org.apache.drill.exec.vector.VectorOverflowException; + /** - * Writer for values into an array. Array writes are write-once, - * sequential: each call to a setFoo() method writes a - * value and advances the array index. + * Writer for values into an array. Array writes are write-once, sequential: + * each call to a setFoo() method writes a value and advances the array + * index. *

* {@see ArrayReader} */ -public interface ArrayWriter extends ColumnAccessor, ScalarWriter { +public interface ArrayWriter { + + /** + * Number of elements written thus far to the array. + * @return the number of elements + */ int size(); /** - * Determine if the next position is valid for writing. Will be invalid - * if the writer hits a size or other limit. + * The object type of the list entry. All entries have the same + * type. + * @return the object type of each entry + */ + + ObjectWriter entry(); + + /** + * Return a generic object writer for the array entry. + * + * @return generic object reader + */ + + ObjectType entryType(); + ScalarWriter scalar(); + TupleWriter tuple(); + ArrayWriter array(); + + /** + * When the array contains a tuple or an array, call save() + * after each array value. Not necessary when writing scalars; each + * set operation calls save automatically. + */ + + void save(); + + /** + * Write the values of an array from a list of arguments. + * @param values values for each array element + * @throws VectorOverflowException + */ + void set(Object ...values) throws VectorOverflowException; + + /** + * Write the array given an array of values. The type of array must match + * the type of element in the array. That is, if the value is an int, + * provide an int[] array. * - * @return true if another item is available and the reader is positioned - * at that item, false if no more items are available and the reader - * is no longer valid + * @param array array of values to write + * @throws VectorOverflowException */ - boolean valid(); + void setArray(Object array) throws VectorOverflowException; +// void setList(List list); } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReaderIndex.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReaderIndex.java new file mode 100644 index 00000000000..1bbfe613159 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReaderIndex.java @@ -0,0 +1,23 @@ +/* + * 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.exec.vector.accessor; + +public interface ColumnReaderIndex { + int batchIndex(); + int vectorIndex(); +} \ No newline at end of file diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriter.java deleted file mode 100644 index 0cc691cefe5..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.exec.vector.accessor; - -/** - * Defines a writer to set values for value vectors using - * a simple, uniform interface. Vector values are mapped to - * their "natural" representations: the representation closest - * to the actual vector value. For date and time values, this - * generally means a numeric value. Applications can then map - * this value to Java objects as desired. Decimal types all - * map to BigDecimal as that is the only way in Java to - * represent large decimal values. - *

- * In general, a column maps to just one value. However, derived - * classes may choose to provide type conversions if convenient. - * An exception is thrown if a call is made to a method that - * is not supported by the column type. - *

- * Values of scalars are set directly, using the get method - * for the target type. Maps and arrays are structured types and - * require another level of writer abstraction to access each value - * in the structure. - */ - -public interface ColumnWriter extends ColumnAccessor, ScalarWriter { - void setNull(); - TupleWriter map(); - ArrayWriter array(); -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriterIndex.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriterIndex.java new file mode 100644 index 00000000000..4f64b506661 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnWriterIndex.java @@ -0,0 +1,23 @@ +/* + * 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.exec.vector.accessor; + +public interface ColumnWriterIndex { + int vectorIndex(); + void overflowed(); +} \ No newline at end of file diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectReader.java new file mode 100644 index 00000000000..039d1d29dee --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectReader.java @@ -0,0 +1,60 @@ +/* + * 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.exec.vector.accessor; + +/** + * Defines a reader to get values for value vectors using + * a simple, uniform interface modeled after a JSON object. + * Every column value is an object of one of three types: + * scalar, array or tuple. Methods exist to "cast" this object + * to the proper type. This model allows a very simple representation: + * tuples (rows, maps) consist of objects. Arrays are lists of + * objects. + *

+ * {@see ObjectWriter> + */ + +public interface ObjectReader { + + /** + * The type of this reader. + * + * @return type of reader + */ + + ObjectType type(); + ScalarReader scalar(); + ScalarElementReader elements(); + TupleReader tuple(); + ArrayReader array(); + + /** + * Return the value of the underlying data as a Java object. + * Primarily for testing + * @return Java object that represents the underlying value + */ + + Object getObject(); + + /** + * Return the entire object as a string. Primarily for debugging. + * @return string representation of the object + */ + + String getAsString(); +} \ No newline at end of file diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectType.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectType.java new file mode 100644 index 00000000000..26f1ca8c3c8 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectType.java @@ -0,0 +1,22 @@ +/* + * 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.exec.vector.accessor; + +public enum ObjectType { + SCALAR, TUPLE, ARRAY +} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectWriter.java new file mode 100644 index 00000000000..6e287303963 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ObjectWriter.java @@ -0,0 +1,55 @@ +/* + * 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.exec.vector.accessor; + +import org.apache.drill.exec.vector.VectorOverflowException; + +/** + * Defines a writer to set values for value vectors using + * a simple, uniform interface modeled after a JSON object. + * Every column value is an object of one of three types: + * scalar, array or tuple. Methods exist to "cast" this object + * to the proper type. This model allows a very simple representation: + * tuples (rows, maps) consist of objects. Arrays are lists of + * objects. + *

+ * {@see ObjectReader} + */ + +public interface ObjectWriter { + + /** + * Return the object (structure) type of this writer. + * @return type indicating if this is a scalar, tuple or array + */ + + ObjectType type(); + ScalarWriter scalar(); + TupleWriter tuple(); + ArrayWriter array(); + + /** + * For debugging, set the object to the proper form of Java object + * as defined by the underlying writer type. + * + * @param value Java object value to write + * @throws VectorOverflowException + */ + + void set(Object value) throws VectorOverflowException; +} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarElementReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarElementReader.java new file mode 100644 index 00000000000..d1f31a82f24 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarElementReader.java @@ -0,0 +1,65 @@ +/* + * 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.exec.vector.accessor; + +import java.math.BigDecimal; + +import org.joda.time.Period; + +/** + * Interface to access the values of an array column. In general, each + * vector implements just one of the get methods. Check the vector type + * to know which method to use. Though, generally, when writing test + * code, the type is known to the test writer. + *

+ * Arrays allow random access to the values within the array. The index + * passed to each method is the index into the array for the current + * row and column. (This means that arrays are three dimensional: + * the usual (row, column) dimensions plus an array index dimension: + * (row, column, array index). + *

+ * Note that the isNull() method is provided for completeness, + * but no Drill array allows null values at present. + *

+ * {@see ScalarWriter} + */ + +public interface ScalarElementReader { + /** + * Describe the type of the value. This is a compression of the + * value vector type: it describes which method will return the + * vector value. + * @return the value type which indicates which get method + * is valid for the column + */ + + ValueType valueType(); + int size(); + + boolean isNull(int index); + int getInt(int index); + long getLong(int index); + double getDouble(int index); + String getString(int index); + byte[] getBytes(int index); + BigDecimal getDecimal(int index); + Period getPeriod(int index); + + Object getObject(int index); + String getAsString(int index); +} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarReader.java similarity index 85% rename from exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReader.java rename to exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarReader.java index 4932567f262..e1c26bf29e9 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnReader.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarReader.java @@ -40,9 +40,20 @@ * for the target type. Maps and arrays are structured types and * require another level of reader abstraction to access each value * in the structure. + *

+ * {@see ScalarWriter} */ -public interface ColumnReader extends ColumnAccessor { +public interface ScalarReader { + /** + * Describe the type of the value. This is a compression of the + * value vector type: it describes which method will return the + * vector value. + * @return the value type which indicates which get method + * is valid for the column + */ + + ValueType valueType(); /** * Report if the column is null. Non-nullable columns always @@ -58,7 +69,7 @@ public interface ColumnReader extends ColumnAccessor { byte[] getBytes(); BigDecimal getDecimal(); Period getPeriod(); + Object getObject(); - TupleReader map(); - ArrayReader array(); + String getAsString(); } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarWriter.java index 5cbe80a379a..39ec323fa60 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarWriter.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ScalarWriter.java @@ -19,19 +19,48 @@ import java.math.BigDecimal; +import org.apache.drill.exec.vector.VectorOverflowException; import org.joda.time.Period; /** - * Methods common to the {@link ColumnWriter} and - * {@link ArrayWriter} interfaces. + * Represents a scalar value: a required column, a nullable column, + * or one element within an array of scalars. + *

+ * Vector values are mapped to + * their "natural" representations: the representation closest + * to the actual vector value. For date and time values, this + * generally means a numeric value. Applications can then map + * this value to Java objects as desired. Decimal types all + * map to BigDecimal as that is the only way in Java to + * represent large decimal values. + *

+ * In general, a column maps to just one value. However, derived + * classes may choose to provide type conversions if convenient. + * An exception is thrown if a call is made to a method that + * is not supported by the column type. + *

+ * {@see ScalarReader} + * {@see ScalarElementReader} */ public interface ScalarWriter { - void setInt(int value); - void setLong(long value); - void setDouble(double value); - void setString(String value); - void setBytes(byte[] value); - void setDecimal(BigDecimal value); - void setPeriod(Period value); + /** + * Describe the type of the value. This is a compression of the + * value vector type: it describes which method will return the + * vector value. + * @return the value type which indicates which get method + * is valid for the column + */ + + ValueType valueType(); + void setNull() throws VectorOverflowException; + void setInt(int value) throws VectorOverflowException; + void setLong(long value) throws VectorOverflowException; + void setDouble(double value) throws VectorOverflowException; + void setString(String value) throws VectorOverflowException; + void setBytes(byte[] value, int len) throws VectorOverflowException; + void setDecimal(BigDecimal value) throws VectorOverflowException; + void setPeriod(Period value) throws VectorOverflowException; + + void setObject(Object value) throws VectorOverflowException; } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleAccessor.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleAccessor.java deleted file mode 100644 index 2ebb32ce652..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleAccessor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.exec.vector.accessor; - -import org.apache.drill.exec.record.MaterializedField; - -/** - * Provides access to a "tuple". In Drill, both rows and maps are - * tuples: both are an ordered collection of values, defined by a - * schema. Each tuple has a schema that defines the column ordering - * for indexed access. Each tuple also provides methods to get column - * accessors by name or index. - */ - -public interface TupleAccessor { - - /** - * Flattened view of the schema as needed for row-based access of scalar - * members. The scalar view presents scalar fields: those that can be set - * or retrieved. A separate map view presents map vectors. The scalar - * view is the one used by row set readers and writers. Column indexes - * are into the flattened view, with maps removed and map members flattened - * into the top-level name space with compound names. - */ - - public interface TupleSchema { - /** - * Return a column schema given an indexed into the flattened row structure. - * - * @param index index of the row in the flattened structure - * @return schema of the column - */ - - MaterializedField column(int index); - - MaterializedField column(String name); - - int columnIndex(String name); - - int count(); - } - - TupleSchema schema(); -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleReader.java index 57425afd4a3..908d6a07805 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleReader.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleReader.java @@ -17,17 +17,38 @@ */ package org.apache.drill.exec.vector.accessor; +import org.apache.drill.exec.record.TupleMetadata; + /** * Interface for reading from tuples (rows or maps). Provides * a column reader for each column that can be obtained either * by name or column index (as defined in the tuple schema.) * Also provides two generic methods to get the value as a * Java object or as a string. + *

+ * {@see TupleWriter} */ -public interface TupleReader extends TupleAccessor { - ColumnReader column(int colIndex); - ColumnReader column(String colName); - Object get(int colIndex); - String getAsString(int colIndex); +public interface TupleReader { + TupleMetadata schema(); + int columnCount(); + + ObjectReader column(int colIndex); + ObjectReader column(String colName); + + // Convenience methods + + ObjectType type(int colIndex); + ObjectType type(String colName); + ScalarReader scalar(int colIndex); + ScalarReader scalar(String colName); + TupleReader tuple(int colIndex); + TupleReader tuple(String colName); + ArrayReader array(int colIndex); + ArrayReader array(String colName); + ScalarElementReader elements(int colIndex); + ScalarElementReader elements(String colName); + + Object getObject(); + String getAsString(); } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleWriter.java index 59eca794ec4..581c31191ea 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleWriter.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/TupleWriter.java @@ -17,18 +17,79 @@ */ package org.apache.drill.exec.vector.accessor; +import org.apache.drill.exec.record.TupleMetadata; +import org.apache.drill.exec.vector.VectorOverflowException; + /** - * Interface for writing to rows via a column writer. - * Column writers can be obtained by name or index. Column - * indexes are defined by the tuple schema. Also provides - * a convenience method to set the column value from a Java - * object. The caller is responsible for providing the - * correct object type for each column. (The object type - * must match the column accessor type.) + * Interface for writing to rows via a column writer. Column writers can be + * obtained by name or index. Column indexes are defined by the tuple schema. + * Also provides a convenience method to set the column value from a Java + * object. The caller is responsible for providing the correct object type for + * each column. (The object type must match the column accessor type.) + *

+ * A tuple is composed of columns with a fixed order and unique names: either + * can be used to reference columns. Columns are scalar (simple values), tuples + * (i.e. maps), or arrays (of scalars, tuples or arrays.) + *

+ * Convenience methods allow getting a column as a scalar, tuple or array. These + * methods throw an exception if the column is not of the requested type. */ -public interface TupleWriter extends TupleAccessor { - ColumnWriter column(int colIndex); - ColumnWriter column(String colName); - void set(int colIndex, Object value); +public interface TupleWriter { + TupleMetadata schema(); + int size(); + + // Return the column as a generic object + + ObjectWriter column(int colIndex); + ObjectWriter column(String colName); + + // Convenience methods + + ScalarWriter scalar(int colIndex); + ScalarWriter scalar(String colName); + TupleWriter tuple(int colIndex); + TupleWriter tuple(String colName); + ArrayWriter array(int colIndex); + ArrayWriter array(String colName); + ObjectType type(int colIndex); + ObjectType type(String colName); + + /** + * Set one column given a generic object value. Most helpful for testing, + * not performant for production code due to object creation and dynamic + * type checking. + * + * @param colIndex the index of the column to set + * @param value the value to set. The type of the object must be compatible + * with the type of the target column + * @throws VectorOverflowException if the vector overflows + */ + + void set(int colIndex, Object value) throws VectorOverflowException; + + /** + * Write a row or map of values, given by Java objects. Object type must + * match expected column type. + *

+ * Note that a single-column tuple is ambiguous if that column is an + * array. To avoid ambiguity, use set(0, value) in this case. + * + * @param values variable-length argument list of column values + * @return true if the row was written, false if any column + * caused vector overflow. + * @throws VectorOverflowException if the vector overflows + */ + + void setTuple(Object ...values) throws VectorOverflowException; + + /** + * Set the tuple from an array of objects. Primarily for use in + * test tools. + * + * @param value + * @throws VectorOverflowException + */ + + void setObject(Object value) throws VectorOverflowException; } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnAccessor.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ValueType.java similarity index 58% rename from exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnAccessor.java rename to exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ValueType.java index 44cd48aed19..e6687dcd311 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ColumnAccessor.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/ValueType.java @@ -18,23 +18,14 @@ package org.apache.drill.exec.vector.accessor; /** - * Common base interface for columns readers and writers. Provides - * the access type for the column. Note that multiple Drill types and - * data modes map to the same access type. + * Represents the primitive types supported to read and write data + * from value vectors. Vectors support many data widths. For simplicity + * (and because of no difference in performance), the get/set methods + * use a reduced set of types. In general, each reader and writer + * supports just one type. Though some may provide more than one + * (such as access to bytes for a STRING value.) */ -public interface ColumnAccessor { - public enum ValueType { - INTEGER, LONG, DOUBLE, STRING, BYTES, DECIMAL, PERIOD, ARRAY, MAP - } - - /** - * Describe the type of the value. This is a compression of the - * value vector type: it describes which method will return the - * vector value. - * @return the value type which indicates which get method - * is valid for the column - */ - - ColumnAccessor.ValueType valueType(); +public enum ValueType { + INTEGER, LONG, DOUBLE, STRING, BYTES, DECIMAL, PERIOD } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayReader.java deleted file mode 100644 index deea7f8865e..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayReader.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.exec.vector.accessor.impl; - -import java.math.BigDecimal; - -import org.apache.drill.exec.record.MaterializedField; -import org.apache.drill.exec.vector.ValueVector; -import org.apache.drill.exec.vector.accessor.ArrayReader; -import org.apache.drill.exec.vector.accessor.TupleReader; -import org.apache.drill.exec.vector.accessor.impl.AbstractColumnReader.VectorAccessor; -import org.joda.time.Period; - -/** - * Reader for an array-valued column. This reader provides access to specific - * array members via an array index. This is an abstract base class; - * subclasses are generated for each repeated value vector type. - */ - -public abstract class AbstractArrayReader extends AbstractColumnAccessor implements ArrayReader { - - /** - * Column reader that provides access to an array column by returning a - * separate reader specifically for that array. That is, reading a column - * is a two-part process:


-   * tupleReader.column("arrayCol").array().getInt(2);
- * This pattern is used to avoid overloading the column reader with - * both scalar and array access. Also, this pattern mimics the way - * that nested tuples (Drill maps) are handled. - */ - - public static class ArrayColumnReader extends AbstractColumnReader { - - private final AbstractArrayReader arrayReader; - - public ArrayColumnReader(AbstractArrayReader arrayReader) { - this.arrayReader = arrayReader; - } - - @Override - public ValueType valueType() { - return ValueType.ARRAY; - } - - @Override - public void bind(RowIndex rowIndex, ValueVector vector) { - arrayReader.bind(rowIndex, vector); - vectorIndex = rowIndex; - } - - @Override - public ArrayReader array() { - return arrayReader; - } - } - - protected VectorAccessor vectorAccessor; - - public void bind(RowIndex rowIndex, MaterializedField field, VectorAccessor va) { - bind(rowIndex); - vectorAccessor = va; - } - - @Override - public boolean isNull(int index) { - return false; - } - - @Override - public int getInt(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public long getLong(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public double getDouble(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public String getString(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public byte[] getBytes(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public BigDecimal getDecimal(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public Period getPeriod(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public TupleReader map(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public ArrayReader array(int index) { - throw new UnsupportedOperationException(); - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayWriter.java deleted file mode 100644 index d1d126333db..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractArrayWriter.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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.exec.vector.accessor.impl; - -import java.math.BigDecimal; - -import org.apache.drill.exec.vector.ValueVector; -import org.apache.drill.exec.vector.accessor.ArrayWriter; -import org.apache.drill.exec.vector.complex.BaseRepeatedValueVector; -import org.joda.time.Period; - -/** - * Writer for an array-valued column. This writer appends values: once a value - * is written, it cannot be changed. As a result, writer methods have no item index; - * each set advances the array to the next position. This is an abstract base class; - * subclasses are generated for each repeated value vector type. - */ - -public abstract class AbstractArrayWriter extends AbstractColumnAccessor implements ArrayWriter { - - /** - * Column writer that provides access to an array column by returning a - * separate writer specifically for that array. That is, writing an array - * is a two-part process:

-   * tupleWriter.column("arrayCol").array().setInt(2);
- * This pattern is used to avoid overloading the column reader with - * both scalar and array access. Also, this pattern mimics the way - * that nested tuples (Drill maps) are handled. - */ - - public static class ArrayColumnWriter extends AbstractColumnWriter { - - private final AbstractArrayWriter arrayWriter; - - public ArrayColumnWriter(AbstractArrayWriter arrayWriter) { - this.arrayWriter = arrayWriter; - } - - @Override - public ValueType valueType() { - return ValueType.ARRAY; - } - - @Override - public void bind(RowIndex rowIndex, ValueVector vector) { - arrayWriter.bind(rowIndex, vector); - vectorIndex = rowIndex; - } - - @Override - public ArrayWriter array() { - return arrayWriter; - } - - /** - * Arrays require a start step for each row, regardless of - * whether any values are written for that row. - */ - - public void start() { - arrayWriter.mutator().startNewValue(vectorIndex.index()); - } - } - - protected abstract BaseRepeatedValueVector.BaseRepeatedMutator mutator(); - - @Override - public int size() { - return mutator().getInnerValueCountAt(vectorIndex.index()); - } - - @Override - public boolean valid() { - // Not implemented yet - return true; - } - - @Override - public void setInt(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setLong(long value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setDouble(double value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setString(String value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setBytes(byte[] value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setDecimal(BigDecimal value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setPeriod(Period value) { - throw new UnsupportedOperationException(); - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnReader.java deleted file mode 100644 index b88b08bc8cf..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnReader.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.exec.vector.accessor.impl; - -import java.math.BigDecimal; - -import org.apache.drill.exec.record.MaterializedField; -import org.apache.drill.exec.vector.ValueVector; -import org.apache.drill.exec.vector.accessor.ArrayReader; -import org.apache.drill.exec.vector.accessor.ColumnReader; -import org.apache.drill.exec.vector.accessor.TupleReader; -import org.joda.time.Period; - -/** - * Column reader implementation that acts as the basis for the - * generated, vector-specific implementations. All set methods - * throw an exception; subclasses simply override the supported - * method(s). - */ - -public abstract class AbstractColumnReader extends AbstractColumnAccessor implements ColumnReader { - - public interface VectorAccessor { - ValueVector vector(); - } - - protected VectorAccessor vectorAccessor; - - public void bind(RowIndex rowIndex, MaterializedField field, VectorAccessor va) { - bind(rowIndex); - vectorAccessor = va; - } - - @Override - public Object getObject() { - switch (valueType()) { - case ARRAY: - // TODO: build an array. Just a bit tedious... - throw new UnsupportedOperationException(); - case BYTES: - return getBytes(); - case DECIMAL: - return getDecimal(); - case DOUBLE: - return getDouble(); - case INTEGER: - return getInt(); - case LONG: - return getLong(); - case MAP: - // TODO: build an array. Just a bit tedious... - throw new UnsupportedOperationException(); - case PERIOD: - return getPeriod(); - case STRING: - return getString(); - default: - throw new IllegalStateException("Unexpected type: " + valueType()); - } - } - - @Override - public boolean isNull() { - return false; - } - - @Override - public int getInt() { - throw new UnsupportedOperationException(); - } - - @Override - public long getLong() { - throw new UnsupportedOperationException(); - } - - @Override - public double getDouble() { - throw new UnsupportedOperationException(); - } - - @Override - public String getString() { - throw new UnsupportedOperationException(); - } - - @Override - public byte[] getBytes() { - throw new UnsupportedOperationException(); - } - - @Override - public BigDecimal getDecimal() { - throw new UnsupportedOperationException(); - } - - @Override - public Period getPeriod() { - throw new UnsupportedOperationException(); - } - - @Override - public TupleReader map() { - throw new UnsupportedOperationException(); - } - - @Override - public ArrayReader array() { - throw new UnsupportedOperationException(); - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnWriter.java deleted file mode 100644 index 5071e033a3d..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AbstractColumnWriter.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.exec.vector.accessor.impl; - -import java.math.BigDecimal; - -import org.apache.drill.exec.vector.accessor.ArrayWriter; -import org.apache.drill.exec.vector.accessor.ColumnWriter; -import org.apache.drill.exec.vector.accessor.TupleWriter; -import org.joda.time.Period; - -/** - * Column writer implementation that acts as the basis for the - * generated, vector-specific implementations. All set methods - * throw an exception; subclasses simply override the supported - * method(s). - */ - -public abstract class AbstractColumnWriter extends AbstractColumnAccessor implements ColumnWriter { - - public void start() { } - - @Override - public void setNull() { - throw new UnsupportedOperationException(); - } - - @Override - public void setInt(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setLong(long value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setDouble(double value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setString(String value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setBytes(byte[] value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setDecimal(BigDecimal value) { - throw new UnsupportedOperationException(); - } - - @Override - public void setPeriod(Period value) { - throw new UnsupportedOperationException(); - } - - @Override - public TupleWriter map() { - throw new UnsupportedOperationException(); - } - - @Override - public ArrayWriter array() { - throw new UnsupportedOperationException(); - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AccessorUtilities.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AccessorUtilities.java new file mode 100644 index 00000000000..a4a26766410 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/AccessorUtilities.java @@ -0,0 +1,88 @@ +/* + * 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.exec.vector.accessor.impl; + +import java.math.BigDecimal; + +import org.apache.drill.exec.vector.VectorOverflowException; +import org.apache.drill.exec.vector.accessor.ScalarWriter; +import org.joda.time.Duration; + +public class AccessorUtilities { + + private AccessorUtilities() { } + + public static void setFromInt(ScalarWriter writer, int value) throws VectorOverflowException { + switch (writer.valueType()) { + case BYTES: + byte bytes[] = Integer.toHexString(value).getBytes(); + writer.setBytes(bytes, bytes.length); + break; + case DOUBLE: + writer.setDouble(value); + break; + case INTEGER: + writer.setInt(value); + break; + case LONG: + writer.setLong(value); + break; + case STRING: + writer.setString(Integer.toString(value)); + break; + case DECIMAL: + writer.setDecimal(BigDecimal.valueOf(value)); + break; + case PERIOD: + writer.setPeriod(Duration.millis(value).toPeriod()); + break; + default: + throw new IllegalStateException("Unknown writer type: " + writer.valueType()); + } + } + + public static int sv4Batch(int sv4Index) { + return sv4Index >>> 16; + } + + public static int sv4Index(int sv4Index) { + return sv4Index & 0xFFFF; + } + + public static String bytesToString(byte[] value) { + StringBuilder buf = new StringBuilder() + .append("["); + int len = Math.min(value.length, 20); + for (int i = 0; i < len; i++) { + if (i > 0) { + buf.append(", "); + } + String str = Integer.toHexString(value[i] & 0xFF); + if (str.length() < 2) { + buf.append("0"); + } + buf.append(str); + } + if (value.length > len) { + buf.append("..."); + } + buf.append("]"); + return buf.toString(); + } + +} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/ColumnAccessorFactory.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/ColumnAccessorFactory.java index 019d3bed129..877707cfdec 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/ColumnAccessorFactory.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/ColumnAccessorFactory.java @@ -20,101 +20,129 @@ 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.vector.ValueVector; import org.apache.drill.exec.vector.accessor.ColumnAccessors; -import org.apache.drill.exec.vector.accessor.impl.AbstractArrayReader.ArrayColumnReader; -import org.apache.drill.exec.vector.accessor.impl.AbstractArrayWriter.ArrayColumnWriter; +import org.apache.drill.exec.vector.accessor.reader.AbstractObjectReader; +import org.apache.drill.exec.vector.accessor.reader.BaseElementReader; +import org.apache.drill.exec.vector.accessor.reader.BaseScalarReader; +import org.apache.drill.exec.vector.accessor.reader.ScalarArrayReader; +import org.apache.drill.exec.vector.accessor.reader.VectorAccessor; +import org.apache.drill.exec.vector.accessor.writer.AbstractObjectWriter; +import org.apache.drill.exec.vector.accessor.writer.BaseElementWriter; +import org.apache.drill.exec.vector.accessor.writer.BaseScalarWriter; +import org.apache.drill.exec.vector.accessor.writer.ScalarArrayWriter; +import org.apache.drill.exec.vector.complex.RepeatedValueVector; /** - * Gather generated accessor classes into a set of class - * tables to allow rapid run-time creation of accessors. - * The caller is responsible for binding the accessor to - * a vector and a row index. + * Gather generated accessor classes into a set of class tables to allow rapid + * run-time creation of accessors. Builds the accessor and its object reader/writer + * wrapper which binds the vector to the accessor. */ +@SuppressWarnings("unchecked") public class ColumnAccessorFactory { - private static Class columnWriters[][] = buildColumnWriters(); - private static Class columnReaders[][] = buildColumnReaders(); - private static Class arrayWriters[] = buildArrayWriters(); - private static Class arrayReaders[] = buildArrayReaders(); + private static final int typeCount = MinorType.values().length; + private static final Class requiredReaders[] = new Class[typeCount]; + private static final Class nullableReaders[] = new Class[typeCount]; + private static final Class elementReaders[] = new Class[typeCount]; + private static final Class requiredWriters[] = new Class[typeCount]; + private static final Class nullableWriters[] = new Class[typeCount]; + private static final Class elementWriters[] = new Class[typeCount]; - @SuppressWarnings("unchecked") - private static Class[][] buildColumnWriters() { - int typeCount = MinorType.values().length; - int modeCount = DataMode.values().length; - Class writers[][] = new Class[typeCount][]; - for (int i = 0; i < typeCount; i++) { - writers[i] = new Class[modeCount]; - } - - ColumnAccessors.defineWriters(writers); - return writers; + static { + ColumnAccessors.defineRequiredReaders(requiredReaders); + ColumnAccessors.defineNullableReaders(nullableReaders); + ColumnAccessors.defineArrayReaders(elementReaders); + ColumnAccessors.defineRequiredWriters(requiredWriters); + ColumnAccessors.defineNullableWriters(nullableWriters); + ColumnAccessors.defineArrayWriters(elementWriters); } - @SuppressWarnings("unchecked") - private static Class[][] buildColumnReaders() { - int typeCount = MinorType.values().length; - int modeCount = DataMode.values().length; - Class readers[][] = new Class[typeCount][]; - for (int i = 0; i < typeCount; i++) { - readers[i] = new Class[modeCount]; - } + public static AbstractObjectWriter buildColumnWriter(ValueVector vector) { + MajorType major = vector.getField().getType(); + MinorType type = major.getMinorType(); + DataMode mode = major.getMode(); - ColumnAccessors.defineReaders(readers); - return readers; + switch (type) { + case GENERIC_OBJECT: + case LATE: + case NULL: + case LIST: + case MAP: + throw new UnsupportedOperationException(type.toString()); + default: + switch (mode) { + case OPTIONAL: + return BaseScalarWriter.build(vector, newAccessor(type, nullableWriters)); + case REQUIRED: + return BaseScalarWriter.build(vector, newAccessor(type, requiredWriters)); + case REPEATED: + return ScalarArrayWriter.build((RepeatedValueVector) vector, newAccessor(type, elementWriters)); + default: + throw new UnsupportedOperationException(mode.toString()); + } + } } - @SuppressWarnings("unchecked") - private static Class[] buildArrayWriters() { - int typeCount = MinorType.values().length; - Class writers[] = new Class[typeCount]; - ColumnAccessors.defineArrayWriters(writers); - return writers; - } + public static AbstractObjectReader buildColumnReader(ValueVector vector) { + MajorType major = vector.getField().getType(); + MinorType type = major.getMinorType(); + DataMode mode = major.getMode(); - @SuppressWarnings("unchecked") - private static Class[] buildArrayReaders() { - int typeCount = MinorType.values().length; - Class readers[] = new Class[typeCount]; - ColumnAccessors.defineArrayReaders(readers); - return readers; + switch (type) { + case GENERIC_OBJECT: + case LATE: + case NULL: + case LIST: + case MAP: + throw new UnsupportedOperationException(type.toString()); + default: + switch (mode) { + case OPTIONAL: + return BaseScalarReader.build(vector, newAccessor(type, nullableReaders)); + case REQUIRED: + return BaseScalarReader.build(vector, newAccessor(type, requiredReaders)); + case REPEATED: + return ScalarArrayReader.build((RepeatedValueVector) vector, newAccessor(type, elementReaders)); + default: + throw new UnsupportedOperationException(mode.toString()); + } + } } - public static AbstractColumnWriter newWriter(MajorType type) { - try { - if (type.getMode() == DataMode.REPEATED) { - Class writerClass = arrayWriters[type.getMinorType().ordinal()]; - if (writerClass == null) { - throw new UnsupportedOperationException(); - } - return new ArrayColumnWriter(writerClass.newInstance()); - } else { - Class writerClass = columnWriters[type.getMinorType().ordinal()][type.getMode().ordinal()]; - if (writerClass == null) { - throw new UnsupportedOperationException(); - } - return writerClass.newInstance(); + public static AbstractObjectReader buildColumnReader(MajorType majorType, VectorAccessor va) { + MinorType type = majorType.getMinorType(); + DataMode mode = majorType.getMode(); + + switch (type) { + case GENERIC_OBJECT: + case LATE: + case NULL: + case LIST: + case MAP: + throw new UnsupportedOperationException(type.toString()); + default: + switch (mode) { + case OPTIONAL: + return BaseScalarReader.build(majorType, va, newAccessor(type, nullableReaders)); + case REQUIRED: + return BaseScalarReader.build(majorType, va, newAccessor(type, requiredReaders)); + case REPEATED: + return ScalarArrayReader.build(majorType, va, newAccessor(type, elementReaders)); + default: + throw new UnsupportedOperationException(mode.toString()); } - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalStateException(e); } } - public static AbstractColumnReader newReader(MajorType type) { + public static T newAccessor(MinorType type, Class accessors[]) { try { - if (type.getMode() == DataMode.REPEATED) { - Class readerClass = arrayReaders[type.getMinorType().ordinal()]; - if (readerClass == null) { - throw new UnsupportedOperationException(); - } - return new ArrayColumnReader(readerClass.newInstance()); - } else { - Class readerClass = columnReaders[type.getMinorType().ordinal()][type.getMode().ordinal()]; - if (readerClass == null) { - throw new UnsupportedOperationException(); - } - return readerClass.newInstance(); + Class accessorClass = accessors[type.ordinal()]; + if (accessorClass == null) { + throw new UnsupportedOperationException(type.toString()); } + return accessorClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new IllegalStateException(e); } diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleReaderImpl.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleReaderImpl.java deleted file mode 100644 index 97a6e3c3013..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleReaderImpl.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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.exec.vector.accessor.impl; - -import org.apache.drill.exec.vector.accessor.ArrayReader; -import org.apache.drill.exec.vector.accessor.ColumnReader; -import org.apache.drill.exec.vector.accessor.TupleReader; - -/** - * Reader for a tuple (a row or a map.) Provides access to each - * column using either a name or a numeric index. - */ - -public class TupleReaderImpl extends AbstractTupleAccessor implements TupleReader { - - private final AbstractColumnReader readers[]; - - public TupleReaderImpl(TupleSchema schema, AbstractColumnReader readers[]) { - super(schema); - this.readers = readers; - } - - @Override - public ColumnReader column(int colIndex) { - return readers[colIndex]; - } - - @Override - public ColumnReader column(String colName) { - int index = schema.columnIndex(colName); - if (index == -1) { - return null; } - return readers[index]; - } - - @Override - public Object get(int colIndex) { - ColumnReader colReader = column(colIndex); - if (colReader.isNull()) { - return null; } - switch (colReader.valueType()) { - case BYTES: - return colReader.getBytes(); - case DOUBLE: - return colReader.getDouble(); - case INTEGER: - return colReader.getInt(); - case LONG: - return colReader.getLong(); - case STRING: - return colReader.getString(); - default: - throw new IllegalArgumentException("Unsupported type " + colReader.valueType()); - } - } - - @Override - public String getAsString(int colIndex) { - ColumnReader colReader = column(colIndex); - if (colReader.isNull()) { - return "null"; - } - switch (colReader.valueType()) { - case BYTES: - return bytesToString(colReader.getBytes()); - case DOUBLE: - return Double.toString(colReader.getDouble()); - case INTEGER: - return Integer.toString(colReader.getInt()); - case LONG: - return Long.toString(colReader.getLong()); - case STRING: - return "\"" + colReader.getString() + "\""; - case DECIMAL: - return colReader.getDecimal().toPlainString(); - case ARRAY: - return getArrayAsString(colReader.array()); - default: - throw new IllegalArgumentException("Unsupported type " + colReader.valueType()); - } - } - - private String bytesToString(byte[] value) { - StringBuilder buf = new StringBuilder() - .append("["); - int len = Math.min(value.length, 20); - for (int i = 0; i < len; i++) { - if (i > 0) { - buf.append(", "); - } - buf.append((int) value[i]); - } - if (value.length > len) { - buf.append("..."); - } - buf.append("]"); - return buf.toString(); - } - - private String getArrayAsString(ArrayReader array) { - StringBuilder buf = new StringBuilder(); - buf.append("["); - for (int i = 0; i < array.size(); i++) { - if (i > 0) { - buf.append( ", " ); - } - switch (array.valueType()) { - case BYTES: - buf.append(bytesToString(array.getBytes(i))); - break; - case DOUBLE: - buf.append(Double.toString(array.getDouble(i))); - break; - case INTEGER: - buf.append(Integer.toString(array.getInt(i))); - break; - case LONG: - buf.append(Long.toString(array.getLong(i))); - break; - case STRING: - buf.append("\"" + array.getString(i) + "\""); - break; - case DECIMAL: - buf.append(array.getDecimal(i).toPlainString()); - break; - case MAP: - case ARRAY: - throw new UnsupportedOperationException("Unsupported type " + array.valueType()); - default: - throw new IllegalArgumentException("Unexpected type " + array.valueType()); - } - } - buf.append("]"); - return buf.toString(); - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleWriterImpl.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleWriterImpl.java deleted file mode 100644 index 015b099668c..00000000000 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/impl/TupleWriterImpl.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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.exec.vector.accessor.impl; - -import java.math.BigDecimal; - -import org.apache.drill.exec.vector.accessor.AccessorUtilities; -import org.apache.drill.exec.vector.accessor.ArrayWriter; -import org.apache.drill.exec.vector.accessor.ColumnAccessor.ValueType; -import org.apache.drill.exec.vector.accessor.ColumnWriter; -import org.apache.drill.exec.vector.accessor.TupleWriter; -import org.joda.time.Period; - -/** - * Implementation for a writer for a tuple (a row or a map.) Provides access to each - * column using either a name or a numeric index. - */ - -public class TupleWriterImpl extends AbstractTupleAccessor implements TupleWriter { - - private final AbstractColumnWriter writers[]; - - public TupleWriterImpl(TupleSchema schema, AbstractColumnWriter writers[]) { - super(schema); - this.writers = writers; - } - - public void start() { - for (int i = 0; i < writers.length; i++) { - writers[i].start(); - } - } - - @Override - public ColumnWriter column(int colIndex) { - return writers[colIndex]; - } - - @Override - public ColumnWriter column(String colName) { - int index = schema.columnIndex(colName); - if (index == -1) { - return null; } - return writers[index]; - } - - @Override - public void set(int colIndex, Object value) { - ColumnWriter colWriter = column(colIndex); - if (value == null) { - // Arrays have no null concept, just an empty array. - if (colWriter.valueType() != ValueType.ARRAY) { - colWriter.setNull(); - } - } else if (value instanceof Integer) { - colWriter.setInt((Integer) value); - } else if (value instanceof Long) { - colWriter.setLong((Long) value); - } else if (value instanceof String) { - colWriter.setString((String) value); - } else if (value instanceof BigDecimal) { - colWriter.setDecimal((BigDecimal) value); - } else if (value instanceof Period) { - colWriter.setPeriod((Period) value); - } else if (value instanceof byte[]) { - colWriter.setBytes((byte[]) value); - } else if (value instanceof Byte) { - colWriter.setInt((Byte) value); - } else if (value instanceof Short) { - colWriter.setInt((Short) value); - } else if (value instanceof Double) { - colWriter.setDouble((Double) value); - } else if (value instanceof Float) { - colWriter.setDouble((Float) value); - } else if (value.getClass().getName().startsWith("[")) { - setArray(colIndex, value); - } else { - throw new IllegalArgumentException("Unsupported type " + - value.getClass().getSimpleName() + " for column " + colIndex); - } - } - - public void setArray(int colIndex, Object value) { - if (value == null) { - // Assume null means a 0-element array since Drill does - // not support null for the whole array. - - return; - } - String objClass = value.getClass().getName(); - if (!objClass.startsWith("[")) { - throw new IllegalArgumentException("Argument is not an array"); - } - - ColumnWriter colWriter = column(colIndex); - if (colWriter.valueType() != ValueType.ARRAY) { - throw new IllegalArgumentException("Column is not an array"); - } - - ArrayWriter arrayWriter = colWriter.array(); - - // Figure out type - - char second = objClass.charAt( 1 ); - switch ( second ) { - case 'B': - AccessorUtilities.setByteArray(arrayWriter, (byte[]) value ); - break; - case 'S': - AccessorUtilities.setShortArray(arrayWriter, (short[]) value ); - break; - case 'I': - AccessorUtilities.setIntArray(arrayWriter, (int[]) value ); - break; - case 'J': - AccessorUtilities.setLongArray(arrayWriter, (long[]) value ); - break; - case 'F': - AccessorUtilities.setFloatArray(arrayWriter, (float[]) value ); - break; - case 'D': - AccessorUtilities.setDoubleArray(arrayWriter, (double[]) value ); - break; - case 'Z': - AccessorUtilities.setBooleanArray(arrayWriter, (boolean[]) value ); - break; - case 'L': - int posn = objClass.indexOf(';'); - - // If the array is of type Object, then we have no type info. - - String memberClassName = objClass.substring( 2, posn ); - if (memberClassName.equals(String.class.getName())) { - AccessorUtilities.setStringArray(arrayWriter, (String[]) value ); - } else if (memberClassName.equals(Period.class.getName())) { - AccessorUtilities.setPeriodArray(arrayWriter, (Period[]) value ); - } else if (memberClassName.equals(BigDecimal.class.getName())) { - AccessorUtilities.setBigDecimalArray(arrayWriter, (BigDecimal[]) value ); - } else { - throw new IllegalArgumentException( "Unknown Java array type: " + memberClassName ); - } - break; - default: - throw new IllegalArgumentException( "Unknown Java array type: " + second ); - } - } -} diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/package-info.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/package-info.java index f51c1a998c3..02f4dc951cc 100644 --- a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/package-info.java +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/package-info.java @@ -25,6 +25,23 @@ * unit tests, but the accessor framework could easily be used for other * purposes as well. *

+ * The object reader and writer provide a generic, JSON-like interface + * to allow any valid combination of readers or writers (generically + * accessors):


+ * row : tuple
+ * tuple : (name column) *
+ * column : scalar obj | array obj | tuple obj
+ * scalar obj : scalar accessor
+ * array obj : array accessor
+ * array accessor : element accessor
+ * tuple obj : tuple
+ *

+ * As seen above, the accessor tree starts with a tuple (a row in the form of + * a class provided by the consumer.) Each column in the tuple is represented + * by an object accesor. That object accessor contains a scalar, tuple or array + * accessor. This models Drill's JSON structure: a row can have a list of lists + * of tuples that contains lists of ints, say. + *

* Drill provides a set of column readers and writers. Compared to those, this * set: *