http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/package-info.java ---------------------------------------------------------------------- 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 f51c1a9..c90a734 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 @@ -24,8 +24,40 @@ * framework for the java-exec project. That one implementation is specific to * unit tests, but the accessor framework could easily be used for other * purposes as well. + * + * <h4>Vector Overflow Handling</h4> + * + * The writers provide integrated support for detecting and handling vector + * overflow. Overflow occurs when a value exceeds some maximum, such as the + * 16MB block size in Netty. Overflow handling consists of replacing the + * "full" vector with a new, empty vector as part of a new batch. Overflow + * handing code must copy partially written values from the "overflow" row + * to the new vectors. The classes here do not provide overflow handling, + * rather they provide the framework on top of which overflow handling can be + * built by a higher level of abstraction. + * + * <h4>JSON-Like Model</h4> + * + * The object reader and writer provide a generic, JSON-like interface + * to allow any valid combination of readers or writers (generically + * accessors):<pre><code> + * 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</code></pre> * <p> - * Drill provides a set of column readers and writers. Compared to those, this + * 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. + * + * <h4>Comparison with Previous Vector Readers and Writers</h4> + * + * Drill provides a set of vector readers and writers. Compared to those, this * set: * <ul> * <li>Works with all Drill data types. The other set works only with repeated @@ -36,23 +68,24 @@ * other set has accessors specific to each of the ~30 data types which Drill * supports.</li> * </ul> - * The key difference is that this set is designed for developer ease-of-use, a - * primary requirement for unit tests. The other set is designed to be used in + * The key difference is that this set is designed for both developer ease-of-use + * and performance. Developer eas-of-use is a + * primary requirement for unit tests. Performance is critical for production + * code. The other set is designed to be used in * machine-generated or write-once code and so can be much more complex. - * <p> - * That is, the accessors here are optimized for test code: they trade - * convenience for a slight decrease in speed (the performance hit comes from - * the extra level of indirection which hides the complex, type-specific code - * otherwise required.) - * <p> - * {@link ColumnReader} and {@link ColumnWriter} are the core abstractions: they + * + * <h4>Overview of the Code Structure</h4> + * + * {@link ScalarReader} and {@link ColumnWriter} are the core abstractions: they * provide simplified access to the myriad of Drill column types via a * simplified, uniform API. {@link TupleReader} and {@link TupleWriter} provide * a simplified API to rows or maps (both of which are tuples in Drill.) * {@link AccessorUtilities} provides a number of data conversion tools. - * <p> - * Overview of the code structure: * <dl> + * <dt>ObjectWriter, ObjectReader</dt> + * <dd>Drill follows a JSON data model. A row is a tuple (AKA structure). Each + * column is a scalar, a map (AKA tuple, structure) or an array (AKA a repeated + * value.)</dd> * <dt>TupleWriter, TupleReader</dt> * <dd>In relational terms, a tuple is an ordered collection of values, where * the meaning of the order is provided by a schema (usually a name/type pair.) @@ -62,12 +95,8 @@ * But, doing so is slower than access by position (index). To provide efficient * code, the tuple classes assume that the implementation imposes a column * ordering which can be exposed via the indexes.</dd> - * <dt>ColumnAccessor</dt> - * <dd>A generic base class for column readers and writers that provides the - * column data type.</dd> - * <dt>ColumnWriter, ColumnReader</dt> - * <dd>A uniform interface implemented for each column type ("major type" in - * Drill terminology). The scalar types: Nullable (Drill optional) and + * <dt>ScalarWriter, ScalarReader</dt> + * <dd>A uniform interface for the scalar types: Nullable (Drill optional) and * non-nullable (Drill required) fields use the same interface. Arrays (Drill * repeated) are special. To handle the array aspect, even array fields use the * same interface, but the <tt>getArray</tt> method returns another layer of @@ -98,11 +127,11 @@ * <dd>The generated accessors: one for each combination of write/read, data * (minor) type and cardinality (data model). * <dd> - * <dt>RowIndex</dt> + * <dt>ColumnReaderIndex, ColumnWriterIndex</dt> * <dd>This nested class binds the accessor to the current row position for the * entire record batch. That is, you don't ask for the value of column a for row * 5, then the value of column b for row 5, etc. as with the "raw" vectors. - * Instead, the implementation sets the row position (with, say an interator.) + * Instead, the implementation sets the row position (with, say an iterator.) * Then, all columns implicitly return values for the current row. * <p> * Different implementations of the row index handle the case of no selection @@ -122,6 +151,16 @@ * The column index picks out the x coordinate (horizontal position along the * columns.)</dt> * </dl> + * <h4>Column Writer Optimizations</h4> + * The writer classes here started as a simple abstraction on top of the existing + * vector mutators. The classes were then recruited for use in a new writer + * abstraction for Drill's record readers. At that point, performance became + * critical. The key to performance is to bypass the vector and the mutator and + * instead work with the Netty direct memory functions. This seems a risky + * approach until we realize that the writers form a very clear interface: + * the same interface supported the original mutator-based implementation and + * the revised Netty-based implementation. The benefit, however, is stark; + * the direct-to-Netty version is up to 4x faster (for repeated types). */ package org.apache.drill.exec.vector.accessor;
http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractArrayReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractArrayReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractArrayReader.java new file mode 100644 index 0000000..7fb0c9d --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractArrayReader.java @@ -0,0 +1,188 @@ +/* + * 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.reader; + +import org.apache.drill.exec.vector.UInt4Vector.Accessor; +import org.apache.drill.exec.vector.accessor.ArrayReader; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectReader; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.accessor.TupleReader; +import org.apache.drill.exec.vector.complex.RepeatedValueVector; + +/** + * 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 implements ArrayReader { + + /** + * Object representation of an array reader. + */ + + public static class ArrayObjectReader extends AbstractObjectReader { + + private AbstractArrayReader arrayReader; + + public ArrayObjectReader(AbstractArrayReader arrayReader) { + this.arrayReader = arrayReader; + } + + @Override + public void bindIndex(ColumnReaderIndex index) { + arrayReader.bindIndex(index); + } + + @Override + public ObjectType type() { + return ObjectType.ARRAY; + } + + @Override + public ArrayReader array() { + return arrayReader; + } + + @Override + public ScalarElementReader elements() { + return arrayReader.elements(); + } + + @Override + public Object getObject() { + return arrayReader.getObject(); + } + + @Override + public String getAsString() { + return arrayReader.getAsString(); + } + + @Override + public void reposition() { + arrayReader.reposition(); + } + } + + public static class BaseElementIndex { + private final ColumnReaderIndex base; + protected int startOffset; + protected int length; + + public BaseElementIndex(ColumnReaderIndex base) { + this.base = base; + } + + public int batchIndex() { + return base.batchIndex(); + } + + public void reset(int startOffset, int length) { + assert length >= 0; + assert startOffset >= 0; + this.startOffset = startOffset; + this.length = length; + } + + public int size() { return length; } + + public int elementIndex(int index) { + if (index < 0 || length <= index) { + throw new IndexOutOfBoundsException("Index = " + index + ", length = " + length); + } + return startOffset + index; + } + } + + private final Accessor accessor; + private final VectorAccessor vectorAccessor; + protected ColumnReaderIndex baseIndex; + protected BaseElementIndex elementIndex; + + public AbstractArrayReader(RepeatedValueVector vector) { + accessor = vector.getOffsetVector().getAccessor(); + vectorAccessor = null; + } + + public AbstractArrayReader(VectorAccessor vectorAccessor) { + accessor = null; + this.vectorAccessor = vectorAccessor; + } + + public void bindIndex(ColumnReaderIndex index) { + baseIndex = index; + if (vectorAccessor != null) { + vectorAccessor.bind(index); + } + } + + private Accessor accessor() { + if (accessor != null) { + return accessor; + } + return ((RepeatedValueVector) (vectorAccessor.vector())).getOffsetVector().getAccessor(); + } + + public void reposition() { + final int index = baseIndex.vectorIndex(); + final Accessor curAccesssor = accessor(); + final int startPosn = curAccesssor.get(index); + elementIndex.reset(startPosn, curAccesssor.get(index + 1) - startPosn); + } + + @Override + public int size() { return elementIndex.size(); } + + @Override + public ScalarElementReader elements() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectReader entry(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public TupleReader tuple(int index) { + return entry(index).tuple(); + } + + @Override + public ArrayReader array(int index) { + return entry(index).array(); + } + + @Override + public ObjectReader entry() { + throw new UnsupportedOperationException(); + } + + @Override + public TupleReader tuple() { + return entry().tuple(); + } + + @Override + public ArrayReader array() { + return entry().array(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractObjectReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractObjectReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractObjectReader.java new file mode 100644 index 0000000..59a066e --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractObjectReader.java @@ -0,0 +1,52 @@ +/* + * 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.reader; + +import org.apache.drill.exec.vector.accessor.ArrayReader; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectReader; +import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.accessor.ScalarReader; +import org.apache.drill.exec.vector.accessor.TupleReader; + +public abstract class AbstractObjectReader implements ObjectReader { + + public abstract void bindIndex(ColumnReaderIndex index); + + public void reposition() { } + + @Override + public ScalarReader scalar() { + throw new UnsupportedOperationException(); + } + + @Override + public TupleReader tuple() { + throw new UnsupportedOperationException(); + } + + @Override + public ArrayReader array() { + throw new UnsupportedOperationException(); + } + + @Override + public ScalarElementReader elements() { + throw new UnsupportedOperationException(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractTupleReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractTupleReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractTupleReader.java new file mode 100644 index 0000000..afa0cb7 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/AbstractTupleReader.java @@ -0,0 +1,189 @@ +/* + * 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.reader; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.drill.exec.record.TupleMetadata; +import org.apache.drill.exec.vector.accessor.ArrayReader; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectReader; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.accessor.ScalarReader; +import org.apache.drill.exec.vector.accessor.TupleReader; + +/** + * Reader for a tuple (a row or a map.) Provides access to each + * column using either a name or a numeric index. + */ + +public abstract class AbstractTupleReader implements TupleReader { + + public static class TupleObjectReader extends AbstractObjectReader { + + private AbstractTupleReader tupleReader; + + public TupleObjectReader(AbstractTupleReader tupleReader) { + this.tupleReader = tupleReader; + } + + @Override + public void bindIndex(ColumnReaderIndex index) { + tupleReader.bindIndex(index); + } + + @Override + public ObjectType type() { + return ObjectType.TUPLE; + } + + @Override + public TupleReader tuple() { + return tupleReader; + } + + @Override + public Object getObject() { + return tupleReader.getObject(); + } + + @Override + public String getAsString() { + return tupleReader.getAsString(); + } + + @Override + public void reposition() { + tupleReader.reposition(); + } + } + + protected final TupleMetadata schema; + private final AbstractObjectReader readers[]; + + protected AbstractTupleReader(TupleMetadata schema, AbstractObjectReader readers[]) { + this.schema = schema; + this.readers = readers; + } + + public void bindIndex(ColumnReaderIndex index) { + for (int i = 0; i < readers.length; i++) { + readers[i].bindIndex(index); + } + } + + @Override + public TupleMetadata schema() { return schema; } + + @Override + public int columnCount() { return schema().size(); } + + @Override + public ObjectReader column(int colIndex) { + return readers[colIndex]; + } + + @Override + public ObjectReader column(String colName) { + int index = schema.index(colName); + if (index == -1) { + return null; } + return readers[index]; + } + + @Override + public ScalarReader scalar(int colIndex) { + return column(colIndex).scalar(); + } + + @Override + public ScalarReader scalar(String colName) { + return column(colName).scalar(); + } + + @Override + public TupleReader tuple(int colIndex) { + return column(colIndex).tuple(); + } + + @Override + public TupleReader tuple(String colName) { + return column(colName).tuple(); + } + + @Override + public ArrayReader array(int colIndex) { + return column(colIndex).array(); + } + + @Override + public ArrayReader array(String colName) { + return column(colName).array(); + } + + @Override + public ObjectType type(int colIndex) { + return column(colIndex).type(); + } + + @Override + public ObjectType type(String colName) { + return column(colName).type(); + } + + @Override + public ScalarElementReader elements(int colIndex) { + return column(colIndex).elements(); + } + + @Override + public ScalarElementReader elements(String colName) { + return column(colName).elements(); + } + + public void reposition() { + for (int i = 0; i < columnCount(); i++) { + readers[i].reposition(); + } + } + + @Override + public Object getObject() { + List<Object> elements = new ArrayList<>(); + for (int i = 0; i < columnCount(); i++) { + elements.add(readers[i].getObject()); + } + return elements; + } + + @Override + public String getAsString() { + StringBuilder buf = new StringBuilder(); + buf.append("("); + for (int i = 0; i < columnCount(); i++) { + if (i > 0) { + buf.append( ", " ); + } + buf.append(readers[i].getAsString()); + } + buf.append(")"); + return buf.toString(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseElementReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseElementReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseElementReader.java new file mode 100644 index 0000000..f32c101 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseElementReader.java @@ -0,0 +1,187 @@ +/* + * 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.reader; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import org.apache.drill.common.types.TypeProtos.MajorType; +import org.apache.drill.exec.vector.ValueVector; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.accessor.impl.AccessorUtilities; +import org.joda.time.Period; + +public abstract class BaseElementReader implements ScalarElementReader { + + public static class ScalarElementObjectReader extends AbstractObjectReader { + + private BaseElementReader elementReader; + + public ScalarElementObjectReader(BaseElementReader elementReader) { + this.elementReader = elementReader; + } + + @Override + public void bindIndex(ColumnReaderIndex index) { + elementReader.bindIndex((ElementReaderIndex) index); + } + + @Override + public ObjectType type() { + return ObjectType.SCALAR; + } + + @Override + public ScalarElementReader elements() { + return elementReader; + } + + @Override + public Object getObject() { + // Simple: return elements as an object list. + // If really needed, could return as a typed array, but that + // is a bit of a hassle. + + List<Object> elements = new ArrayList<>(); + for (int i = 0; i < elementReader.size(); i++) { + elements.add(elementReader.getObject(i)); + } + return elements; + } + + @Override + public String getAsString() { + StringBuilder buf = new StringBuilder(); + buf.append("["); + for (int i = 0; i < elementReader.size(); i++) { + if (i > 0) { + buf.append( ", " ); + } + buf.append(elementReader.getAsString(i)); + } + buf.append("]"); + return buf.toString(); + } + } + + protected ElementReaderIndex vectorIndex; + protected VectorAccessor vectorAccessor; + + public abstract void bindVector(ValueVector vector); + + public void bindVector(MajorType majorType, VectorAccessor va) { + vectorAccessor = va; + } + + protected void bindIndex(ElementReaderIndex rowIndex) { + this.vectorIndex = rowIndex; + } + + @Override + public int size() { return vectorIndex.size(); } + + @Override + public Object getObject(int index) { + if (isNull(index)) { + return "null"; + } + switch (valueType()) { + case BYTES: + return getBytes(index); + case DECIMAL: + return getDecimal(index); + case DOUBLE: + return getDouble(index); + case INTEGER: + return getInt(index); + case LONG: + return getLong(index); + case PERIOD: + return getPeriod(index); + case STRING: + return getString(index); + default: + throw new IllegalStateException("Unexpected type: " + valueType()); + } + } + + @Override + public String getAsString(int index) { + switch (valueType()) { + case BYTES: + return AccessorUtilities.bytesToString(getBytes(index)); + case DOUBLE: + return Double.toString(getDouble(index)); + case INTEGER: + return Integer.toString(getInt(index)); + case LONG: + return Long.toString(getLong(index)); + case STRING: + return "\"" + getString(index) + "\""; + case DECIMAL: + return getDecimal(index).toPlainString(); + case PERIOD: + return getPeriod(index).normalizedStandard().toString(); + default: + throw new IllegalArgumentException("Unsupported type " + valueType()); + } + } + + @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(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseScalarReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseScalarReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseScalarReader.java new file mode 100644 index 0000000..fb9a711 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/BaseScalarReader.java @@ -0,0 +1,189 @@ +/* + * 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.reader; + +import java.math.BigDecimal; + +import org.apache.drill.common.types.TypeProtos.MajorType; +import org.apache.drill.exec.vector.ValueVector; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ScalarReader; +import org.apache.drill.exec.vector.accessor.impl.AccessorUtilities; +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 BaseScalarReader implements ScalarReader { + + public static class ScalarObjectReader extends AbstractObjectReader { + + private BaseScalarReader scalarReader; + + public ScalarObjectReader(BaseScalarReader scalarReader) { + this.scalarReader = scalarReader; + } + + @Override + public void bindIndex(ColumnReaderIndex index) { + scalarReader.bindIndex(index); + } + + @Override + public ObjectType type() { + return ObjectType.SCALAR; + } + + @Override + public ScalarReader scalar() { + return scalarReader; + } + + @Override + public Object getObject() { + return scalarReader.getObject(); + } + + @Override + public String getAsString() { + return scalarReader.getAsString(); + } + } + + protected ColumnReaderIndex vectorIndex; + protected VectorAccessor vectorAccessor; + + public static ScalarObjectReader build(ValueVector vector, BaseScalarReader reader) { + reader.bindVector(vector); + return new ScalarObjectReader(reader); + } + + public static AbstractObjectReader build(MajorType majorType, VectorAccessor va, + BaseScalarReader reader) { + reader.bindVector(majorType, va); + return new ScalarObjectReader(reader); + } + + public abstract void bindVector(ValueVector vector); + + protected void bindIndex(ColumnReaderIndex rowIndex) { + this.vectorIndex = rowIndex; + if (vectorAccessor != null) { + vectorAccessor.bind(rowIndex); + } + } + + public void bindVector(MajorType majorType, VectorAccessor va) { + vectorAccessor = va; + } + + @Override + public Object getObject() { + if (isNull()) { + return null; + } + switch (valueType()) { + case BYTES: + return getBytes(); + case DECIMAL: + return getDecimal(); + case DOUBLE: + return getDouble(); + case INTEGER: + return getInt(); + case LONG: + return getLong(); + case PERIOD: + return getPeriod(); + case STRING: + return getString(); + default: + throw new IllegalStateException("Unexpected type: " + valueType()); + } + } + + @Override + public String getAsString() { + if (isNull()) { + return "null"; + } + switch (valueType()) { + case BYTES: + return AccessorUtilities.bytesToString(getBytes()); + case DOUBLE: + return Double.toString(getDouble()); + case INTEGER: + return Integer.toString(getInt()); + case LONG: + return Long.toString(getLong()); + case STRING: + return "\"" + getString() + "\""; + case DECIMAL: + return getDecimal().toPlainString(); + case PERIOD: + return getPeriod().normalizedStandard().toString(); + default: + throw new IllegalArgumentException("Unsupported 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(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ColumnReaderFactory.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ColumnReaderFactory.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ColumnReaderFactory.java new file mode 100644 index 0000000..0bcb6e2 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ColumnReaderFactory.java @@ -0,0 +1,109 @@ +/* + * 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.reader; + +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.complex.RepeatedValueVector; + +/** + * Gather generated reader classes into a set of class tables to allow rapid + * run-time creation of readers. Builds the reader and its object reader + * wrapper which binds the vector to the reader. + */ + +@SuppressWarnings("unchecked") +public class ColumnReaderFactory { + + private static final int typeCount = MinorType.values().length; + private static final Class<? extends BaseScalarReader> requiredReaders[] = new Class[typeCount]; + private static final Class<? extends BaseScalarReader> nullableReaders[] = new Class[typeCount]; + private static final Class<? extends BaseElementReader> elementReaders[] = new Class[typeCount]; + + static { + ColumnAccessors.defineRequiredReaders(requiredReaders); + ColumnAccessors.defineNullableReaders(nullableReaders); + ColumnAccessors.defineArrayReaders(elementReaders); + } + + public static AbstractObjectReader buildColumnReader(ValueVector vector) { + MajorType major = vector.getField().getType(); + MinorType type = major.getMinorType(); + DataMode mode = major.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(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 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()); + } + } + } + + public static <T> T newAccessor(MinorType type, Class<? extends T> accessors[]) { + try { + Class<? extends T> accessorClass = accessors[type.ordinal()]; + if (accessorClass == null) { + throw new UnsupportedOperationException(type.toString()); + } + return accessorClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ElementReaderIndex.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ElementReaderIndex.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ElementReaderIndex.java new file mode 100644 index 0000000..9985edc --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ElementReaderIndex.java @@ -0,0 +1,24 @@ +/* + * 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.reader; + +public interface ElementReaderIndex { + int batchIndex(); + int size(); + int vectorIndex(int posn); +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/FixedWidthElementReaderIndex.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/FixedWidthElementReaderIndex.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/FixedWidthElementReaderIndex.java new file mode 100644 index 0000000..4f3aeeb --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/FixedWidthElementReaderIndex.java @@ -0,0 +1,38 @@ +/* + * 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.reader; + +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.reader.AbstractArrayReader.BaseElementIndex; + +/** + * Index into the vector of elements for a repeated vector. + * Keeps track of the current offset in terms of value positions. + */ + +public class FixedWidthElementReaderIndex extends BaseElementIndex implements ElementReaderIndex { + + public FixedWidthElementReaderIndex(ColumnReaderIndex base) { + super(base); + } + + @Override + public int vectorIndex(int posn) { + return elementIndex(posn); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/MapReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/MapReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/MapReader.java new file mode 100644 index 0000000..66bc067 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/MapReader.java @@ -0,0 +1,43 @@ +/* + * 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.reader; + +import java.util.List; + +import org.apache.drill.exec.record.ColumnMetadata; + +/** + * Reader for a Drill Map type. Maps are actually tuples, just like rows. + */ + +public class MapReader extends AbstractTupleReader { + + protected MapReader(ColumnMetadata schema, AbstractObjectReader readers[]) { + super(schema.mapSchema(), readers); + } + + public static TupleObjectReader build(ColumnMetadata schema, AbstractObjectReader readers[]) { + return new TupleObjectReader(new MapReader(schema, readers)); + } + + public static AbstractObjectReader build(ColumnMetadata metadata, + List<AbstractObjectReader> readers) { + AbstractObjectReader readerArray[] = new AbstractObjectReader[readers.size()]; + return build(metadata, readers.toArray(readerArray)); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ObjectArrayReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ObjectArrayReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ObjectArrayReader.java new file mode 100644 index 0000000..9ed89f1 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ObjectArrayReader.java @@ -0,0 +1,159 @@ +/* + * 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.reader; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectReader; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.complex.RepeatedValueVector; + +/** + * Reader for an array of either tuples or other arrays. + */ + +public class ObjectArrayReader extends AbstractArrayReader { + + /** + * Index into the vector of elements for a repeated vector. + * Keeps track of the current offset in terms of value positions. + * This is a derived index. The base index points to an entry + * in the offset vector for the array. This inner index picks + * off elements within the range of offsets for that one entry. + * For example:<pre><code> + * [ ... 100 105 ...] + * </code></pre>In the above the value 100 might be at outer + * offset 5. The inner array will pick off the five values + * 100...104. + * <p> + * Because arrays allow random access on read, the inner offset + * is reset on each access to the array. + */ + + public static class ObjectElementReaderIndex extends BaseElementIndex implements ColumnReaderIndex { + + private int posn; + + public ObjectElementReaderIndex(ColumnReaderIndex base) { + super(base); + } + + @Override + public int vectorIndex() { + return startOffset + posn; + } + + public void set(int index) { + if (index < 0 || length <= index) { + throw new IndexOutOfBoundsException("Index = " + index + ", length = " + length); + } + posn = index; + } + + public int posn() { return posn; } + } + + /** + * Reader for each element. + */ + + private final AbstractObjectReader elementReader; + + /** + * Index used to access elements. + */ + + private ObjectElementReaderIndex objElementIndex; + + private ObjectArrayReader(RepeatedValueVector vector, AbstractObjectReader elementReader) { + super(vector); + this.elementReader = elementReader; + } + + private ObjectArrayReader(VectorAccessor vectorAccessor, AbstractObjectReader elementReader) { + super(vectorAccessor); + this.elementReader = elementReader; + } + + public static ArrayObjectReader build(RepeatedValueVector vector, + AbstractObjectReader elementReader) { + return new ArrayObjectReader( + new ObjectArrayReader(vector, elementReader)); + } + + public static AbstractObjectReader build(VectorAccessor vectorAccessor, + AbstractObjectReader elementReader) { + return new ArrayObjectReader( + new ObjectArrayReader(vectorAccessor, elementReader)); + } + + @Override + public void bindIndex(ColumnReaderIndex index) { + super.bindIndex(index); + objElementIndex = new ObjectElementReaderIndex(baseIndex); + elementIndex = objElementIndex; + elementReader.bindIndex(objElementIndex); + } + + @Override + public ObjectType entryType() { + return elementReader.type(); + } + + @Override + public void setPosn(int index) { + objElementIndex.set(index); + elementReader.reposition(); + } + + @Override + public ObjectReader entry() { + return elementReader; + } + + @Override + public ObjectReader entry(int index) { + setPosn(index); + return entry(); + } + + @Override + public Object getObject() { + List<Object> array = new ArrayList<>(); + for (int i = 0; i < objElementIndex.size(); i++) { + array.add(entry(i).getObject()); + } + return array; + } + + @Override + public String getAsString() { + StringBuilder buf = new StringBuilder(); + buf.append("["); + for (int i = 0; i < size(); i++) { + if (i > 0) { + buf.append( ", " ); + } + buf.append(entry(i).getAsString()); + } + buf.append("]"); + return buf.toString(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ScalarArrayReader.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ScalarArrayReader.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ScalarArrayReader.java new file mode 100644 index 0000000..d93e4a5 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/ScalarArrayReader.java @@ -0,0 +1,102 @@ +/* + * 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.reader; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.drill.common.types.TypeProtos.MajorType; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ScalarElementReader; +import org.apache.drill.exec.vector.complex.RepeatedValueVector; + +public class ScalarArrayReader extends AbstractArrayReader { + + private final BaseElementReader elementReader; + + private ScalarArrayReader(RepeatedValueVector vector, + BaseElementReader elementReader) { + super(vector); + this.elementReader = elementReader; + } + + private ScalarArrayReader(VectorAccessor va, + BaseElementReader elementReader) { + super(va); + this.elementReader = elementReader; + } + + public static ArrayObjectReader build(RepeatedValueVector vector, + BaseElementReader elementReader) { + elementReader.bindVector(vector.getDataVector()); + return new ArrayObjectReader(new ScalarArrayReader(vector, elementReader)); + } + + public static ArrayObjectReader build(MajorType majorType, VectorAccessor va, + BaseElementReader elementReader) { + elementReader.bindVector(majorType, va); + return new ArrayObjectReader(new ScalarArrayReader(va, elementReader)); + } + + @Override + public void bindIndex(ColumnReaderIndex index) { + super.bindIndex(index); + FixedWidthElementReaderIndex fwElementIndex = new FixedWidthElementReaderIndex(baseIndex); + elementIndex = fwElementIndex; + elementReader.bindIndex(fwElementIndex); + } + + @Override + public ObjectType entryType() { + return ObjectType.SCALAR; + } + + @Override + public ScalarElementReader elements() { + return elementReader; + } + + @Override + public void setPosn(int index) { + throw new IllegalStateException("setPosn() not supported for scalar arrays"); + } + + @Override + public Object getObject() { + List<Object> elements = new ArrayList<>(); + for (int i = 0; i < size(); i++) { + elements.add(elementReader.getObject(i)); + } + return elements; + } + + @Override + public String getAsString() { + StringBuilder buf = new StringBuilder(); + buf.append("["); + for (int i = 0; i < size(); i++) { + if (i > 0) { + buf.append( ", " ); + } + buf.append(elementReader.getAsString(i)); + } + buf.append("]"); + return buf.toString(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/VectorAccessor.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/VectorAccessor.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/VectorAccessor.java new file mode 100644 index 0000000..1cf2a19 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/VectorAccessor.java @@ -0,0 +1,26 @@ +/* + * 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.reader; + +import org.apache.drill.exec.vector.ValueVector; +import org.apache.drill.exec.vector.accessor.ColumnReaderIndex; + +public interface VectorAccessor { + void bind(ColumnReaderIndex index); + ValueVector vector(); +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/package-info.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/package-info.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/package-info.java new file mode 100644 index 0000000..a94d2e8 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/reader/package-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ +/** + * Provides the reader hierarchy as explained in the API package. + * The only caveat is that a simplification is provided for arrays of + * scalar values: rather than a scalar reader for each value, the + * {#link ScalarElementReader} class provides access to the entire array + * via indexed get methods. + */ + +package org.apache.drill.exec.vector.accessor.reader; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractArrayWriter.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractArrayWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractArrayWriter.java new file mode 100644 index 0000000..e6e29b4 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractArrayWriter.java @@ -0,0 +1,348 @@ +/* + * 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.writer; + +import org.apache.drill.exec.record.ColumnMetadata; +import org.apache.drill.exec.vector.UInt4Vector; +import org.apache.drill.exec.vector.accessor.ArrayWriter; +import org.apache.drill.exec.vector.accessor.ColumnWriterIndex; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ObjectWriter; +import org.apache.drill.exec.vector.accessor.ScalarWriter; +import org.apache.drill.exec.vector.accessor.ScalarWriter.ColumnWriterListener; +import org.apache.drill.exec.vector.accessor.TupleWriter; +import org.apache.drill.exec.vector.accessor.TupleWriter.TupleWriterListener; +import org.apache.drill.exec.vector.accessor.impl.HierarchicalFormatter; + +/** + * 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. + * <p> + * This class represents the array as a whole. In practice that means building + * the offset vector. The array is associated with an element object that + * manages writing to the scalar, array or tuple that is the array element. Note + * that this representation makes little use of the methods in the "Repeated" + * vector class: instead it works directly with the offset and element vectors. + * <p> + * An array has a one-to-many relationship with its children. Starting an array + * prepares for writing the first element. Each element must be saved by calling + * <tt>endValue()</tt>. This is done automatically for scalars (since there is + * exactly one value per element), but must be done via the client code for + * arrays of arrays or tuples. Valid state transitions: + * + * <table border=1> + * <tr><th>Public API</th><th>Array Event</th><th>Offset Event</th><th>Element Event</th></tr> + * <tr><td>startBatch()</td> + * <td>startWrite()</td> + * <td>startWrite()</td> + * <td>startWrite()</td></tr> + * <tr><td>start() (new row)</td> + * <td>startRow()</td> + * <td>startRow()</td> + * <td>startRow()</td></tr> + * <tr><td>start() (without save)</td> + * <td>restartRow()</td> + * <td>restartRow()</td> + * <td>restartRow()</td></tr> + * <tr><td>save() (array)</td> + * <td>saveValue()</td> + * <td>saveValue()</td> + * <td>saveValue()</td></tr> + * <tr><td>save() (row)</td> + * <td colspan=3>See subclasses.</td></tr> + * <tr><td>harvest()</td> + * <td>endWrite()</td> + * <td>endWrite()</td> + * <td>endWrite()</td></tr> + * </table> + * + * Some items to note: + * <ul> + * <li>Batch and row events are passed to the element.</li> + * <li>Each element is saved via a call to {@link #save()} on the array. + * Without this call, the element value is discarded. This is necessary + * because the array always has an active element: no "startElement" + * method is necessary. This also means that any unsaved element values + * can be discarded simply by omitting a call to <tt>save()</tt>.</li> + * <li>Since elements must be saved individually, the call to + * {@link #saveRow()} <i>does not</i> call <tt>saveValue()</tt>. This + * is an important distinction between an array and a tuple.</li> + * <li>The offset and element writers are treated equally: the same events + * are passed to both.</li> + * </ul> + */ + +public abstract class AbstractArrayWriter implements ArrayWriter, WriterEvents { + + /** + * Object representation of an array writer. + */ + + public static class ArrayObjectWriter extends AbstractObjectWriter { + + private AbstractArrayWriter arrayWriter; + + public ArrayObjectWriter(ColumnMetadata schema, AbstractArrayWriter arrayWriter) { + super(schema); + this.arrayWriter = arrayWriter; + } + + @Override + public ObjectType type() { return ObjectType.ARRAY; } + + @Override + public void set(Object value) { + arrayWriter.setObject(value); + } + + @Override + public ArrayWriter array() { return arrayWriter; } + + @Override + public WriterEvents events() { return arrayWriter; } + + @Override + public void bindListener(ColumnWriterListener listener) { + arrayWriter.bindListener(listener); + } + + @Override + public void bindListener(TupleWriterListener listener) { + arrayWriter.bindListener(listener); + } + + @Override + public void dump(HierarchicalFormatter format) { + format + .startObject(this) + .attribute("arrayWriter"); + arrayWriter.dump(format); + format.endObject(); + } + } + + public static abstract class BaseArrayWriter extends AbstractArrayWriter { + + /** + * Index into the vector of elements for a repeated vector. + * Keeps track of the current offset in terms of value positions. + * Forwards overflow events to the base index. + */ + + public class ArrayElementWriterIndex implements ColumnWriterIndex { + + private int elementIndex; + + public void reset() { elementIndex = 0; } + + @Override + public int vectorIndex() { return elementIndex + offsetsWriter.nextOffset(); } + + @Override + public int rowStartIndex() { return offsetsWriter.rowStartOffset(); } + + public int arraySize() { return elementIndex; } + + @Override + public void nextElement() { } + + public final void next() { elementIndex++; } + + public int valueStartOffset() { return offsetsWriter.nextOffset(); } + + @Override + public void rollover() { } + + @Override + public ColumnWriterIndex outerIndex() { + return outerIndex; + } + + @Override + public String toString() { + return new StringBuilder() + .append("[") + .append(getClass().getSimpleName()) + .append(" elementIndex = ") + .append(elementIndex) + .append("]") + .toString(); + } + } + + private final OffsetVectorWriter offsetsWriter; + private ColumnWriterIndex outerIndex; + protected ArrayElementWriterIndex elementIndex; + + public BaseArrayWriter(UInt4Vector offsetVector, AbstractObjectWriter elementObjWriter) { + super(elementObjWriter); + offsetsWriter = new OffsetVectorWriter(offsetVector); + } + + @Override + public void bindIndex(ColumnWriterIndex index) { + assert elementIndex != null; + outerIndex = index; + offsetsWriter.bindIndex(index); + elementObjWriter.events().bindIndex(elementIndex); + } + + @Override + public ColumnWriterIndex writerIndex() { return outerIndex; } + + @Override + public int size() { return elementIndex.arraySize(); } + + @Override + public void startWrite() { + elementIndex.reset(); + offsetsWriter.startWrite(); + elementObjWriter.events().startWrite(); + } + + @Override + public void startRow() { + + // Starting an outer value automatically starts the first + // element value. If no elements are written, then this + // inner start will just be ignored. + + offsetsWriter.startRow(); + elementIndex.reset(); + elementObjWriter.events().startRow(); + } + + @Override + public void endArrayValue() { + offsetsWriter.setNextOffset(elementIndex.vectorIndex()); + elementIndex.reset(); + } + + @Override + public void restartRow() { + offsetsWriter.restartRow(); + elementIndex.reset(); + elementObjWriter.events().restartRow(); + } + + @Override + public void saveRow() { + offsetsWriter.saveRow(); + elementObjWriter.events().saveRow(); + } + + @Override + public void endWrite() { + offsetsWriter.endWrite(); + elementObjWriter.events().endWrite(); + } + + @Override + public void preRollover() { + elementObjWriter.events().preRollover(); + offsetsWriter.preRollover(); + } + + @Override + public void postRollover() { + elementObjWriter.events().postRollover(); + + // Reset the index after the vectors: the vectors + // need the old row start index from the index. + + offsetsWriter.postRollover(); + elementIndex.rollover(); + } + + @Override + public int lastWriteIndex() { return outerIndex.vectorIndex(); } + + /** + * Return the writer for the offset vector for this array. Primarily used + * to handle overflow; other clients should not attempt to muck about with + * the offset vector directly. + * + * @return the writer for the offset vector associated with this array + */ + + @Override + public OffsetVectorWriter offsetWriter() { return offsetsWriter; } + + @Override + public void bindListener(ColumnWriterListener listener) { + elementObjWriter.bindListener(listener); + } + + @Override + public void bindListener(TupleWriterListener listener) { + elementObjWriter.bindListener(listener); + } + + @Override + public void dump(HierarchicalFormatter format) { + format.extend(); + super.dump(format); + format + .attribute("elementIndex", elementIndex.vectorIndex()) + .attribute("offsetsWriter"); + offsetsWriter.dump(format); + } + } + + protected final AbstractObjectWriter elementObjWriter; + + public AbstractArrayWriter(AbstractObjectWriter elementObjWriter) { + this.elementObjWriter = elementObjWriter; + } + + @Override + public ObjectType entryType() { + return elementObjWriter.type(); + } + + @Override + public ObjectWriter entry() { return elementObjWriter; } + + @Override + public ScalarWriter scalar() { + return elementObjWriter.scalar(); + } + + @Override + public TupleWriter tuple() { + return elementObjWriter.tuple(); + } + + @Override + public ArrayWriter array() { + return elementObjWriter.array(); + } + + public abstract void bindListener(ColumnWriterListener listener); + public abstract void bindListener(TupleWriterListener listener); + public abstract OffsetVectorWriter offsetWriter(); + + public void dump(HierarchicalFormatter format) { + format + .startObject(this) + .attribute("elementObjWriter"); + elementObjWriter.dump(format); + format.endObject(); + } +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractFixedWidthWriter.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractFixedWidthWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractFixedWidthWriter.java new file mode 100644 index 0000000..e49f92c --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractFixedWidthWriter.java @@ -0,0 +1,258 @@ +/* + * 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.writer; + +import org.apache.drill.exec.memory.BaseAllocator; +import org.apache.drill.exec.vector.ValueVector; +import org.apache.drill.exec.vector.accessor.impl.HierarchicalFormatter; + +/** + * Base class for writers for fixed-width vectors. Handles common + * tasks, leaving the generated code to handle only type-specific + * operations. + */ + +public abstract class AbstractFixedWidthWriter extends BaseScalarWriter { + + public static abstract class BaseFixedWidthWriter extends AbstractFixedWidthWriter { + + /** + * Buffer of zeros used to back-fill vector buffers with + * zeros. + */ + + private static final byte ZERO_BUF[] = new byte[256]; + + /** + * Determine the write index, growing, overflowing and back-filling + * the vector as needed. + * <p> + * This is a bit tricky. This method has side effects, by design. + * The current vector buffer, and buffer address, will change in + * this method when a vector grows or overflows. So, don't use this + * method in inline calls of the form<br><code> + * vector.getBuffer().doSomething(writeIndex());</code></br> + * The buffer obtained by <tt>getBuffer()</tt> can be different than + * the current buffer after <tt>writeIndex()</tt>. + * + * @return the index at which to write the current value + */ + + protected final int writeIndex() { + + // "Fast path" for the normal case of no fills, no overflow. + // This is the only bounds check we want to do for the entire + // set operation. + + // This is performance critical code; every operation counts. + // Please be thoughtful when changing the code. + + int writeIndex = vectorIndex.vectorIndex(); + if (lastWriteIndex + 1 < writeIndex || writeIndex >= capacity) { + writeIndex = prepareWrite(writeIndex); + } + + // Track the last write location for zero-fill use next time around. + + lastWriteIndex = writeIndex; + return writeIndex; + } + + protected final int prepareWrite(int writeIndex) { + + // Either empties must be filed or the vector is full. + + writeIndex = resize(writeIndex); + + // Fill empties to the write position. + + fillEmpties(writeIndex); + return writeIndex; + } + + /** + * Fill empties. This is required because the allocated memory is not + * zero-filled. + */ + + @Override + protected final void fillEmpties(final int writeIndex) { + final int width = width(); + final int stride = ZERO_BUF.length / width; + int dest = lastWriteIndex + 1; + while (dest < writeIndex) { + int length = writeIndex - dest; + length = Math.min(length, stride); + drillBuf.unsafeCopyMemory(ZERO_BUF, 0, dest * width, length * width); + dest += length; + } + } + } + + /** + * The largest position to which the writer has written data. Used to allow + * "fill-empties" (AKA "back-fill") of missing values one each value write + * and at the end of a batch. Note that this is the position of the last + * write, not the next write position. Starts at -1 (no last write). + */ + + protected int lastWriteIndex; + + @Override + public void startWrite() { + setBuffer(); + lastWriteIndex = -1; + } + + public abstract int width(); + + @Override + protected final void setBuffer() { + drillBuf = vector().getBuffer(); + capacity = drillBuf.capacity() / width(); + } + + protected final void mandatoryResize(final int writeIndex) { + if (writeIndex < capacity) { + return; + } + + // Since some vectors start off as 0 length, set a + // minimum size to avoid silly thrashing on early rows. + + final int size = BaseAllocator.nextPowerOfTwo( + Math.max((writeIndex + 1) * width(), MIN_BUFFER_SIZE)); + realloc(size); + } + + protected final int resize(final int writeIndex) { + if (writeIndex < capacity) { + return writeIndex; + } + final int width = width(); + + // Since some vectors start off as 0 length, set a + // minimum size to avoid silly thrashing on early rows. + + final int size = BaseAllocator.nextPowerOfTwo( + Math.max((writeIndex + 1) * width, MIN_BUFFER_SIZE)); + + // Two cases: grow this vector or allocate a new one. + + // Grow the vector -- or overflow if the growth would make the batch + // consume too much memory. The idea is that we grow vectors as they + // fit the available memory budget, then we fill those vectors until + // one of them needs more space. At that point we trigger overflow to + // a new set of vectors. Internal fragmentation will result, but this + // approach (along with proper initial vector sizing), minimizes that + // fragmentation. + + if (size <= ValueVector.MAX_BUFFER_SIZE && + canExpand(size - capacity * width)) { + + // Optimized form of reAlloc() which does not zero memory, does not do + // bounds checks (since they were already done above). The write index + // and offset remain unchanged. + + realloc(size); + } else { + + // Allocate a new vector, or throw an exception if overflow is not + // supported. If overflow is supported, the callback will call + // endWrite(), which will fill empties, so no need to do that here. + // The call to endWrite() will also set the final writer index for the + // current vector. Then, bindVector() will be called to provide the new + // vector. The write index changes with the new vector. + + overflowed(); + } + + // Call to resize may cause rollover, so reset write index + // afterwards. + + return vectorIndex.vectorIndex(); + } + + @Override + public int lastWriteIndex() { return lastWriteIndex; } + + @Override + public void skipNulls() { + + // Pretend we've written up to the previous value. + // This will leave null values (as specified by the + // caller) uninitialized. + + lastWriteIndex = vectorIndex.vectorIndex() - 1; + } + + @Override + public void restartRow() { + lastWriteIndex = Math.min(lastWriteIndex, vectorIndex.vectorIndex() - 1); + } + + @Override + public void preRollover() { + setValueCount(vectorIndex.rowStartIndex()); + } + + @Override + public void postRollover() { + int newIndex = Math.max(lastWriteIndex - vectorIndex.rowStartIndex(), -1); + startWrite(); + lastWriteIndex = newIndex; + } + + @Override + public void endWrite() { + setValueCount(vectorIndex.vectorIndex()); + } + + protected abstract void fillEmpties(int writeIndex); + + public void setValueCount(int valueCount) { + + // Done this way to avoid another drill buf access in value set path. + // Though this calls writeOffset(), which handles vector overflow, + // such overflow should never occur because here we are simply + // finalizing a position already set. However, the vector size may + // grow and the "missing" values may be zero-filled. Note that, in + // odd cases, the call to writeOffset() might cause the vector to + // resize (as part of filling empties), so grab the buffer AFTER + // the call to writeOffset(). + + mandatoryResize(valueCount - 1); + fillEmpties(valueCount); + vector().getBuffer().writerIndex(valueCount * width()); + + // Last write index is either the last value we just filled, + // or it is the last actual write, if this is an overflow + // situation. + + lastWriteIndex = Math.max(lastWriteIndex, valueCount - 1); + } + + @Override + public void dump(HierarchicalFormatter format) { + format.extend(); + super.dump(format); + format + .attribute("lastWriteIndex", lastWriteIndex) + .endObject(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractObjectWriter.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractObjectWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractObjectWriter.java new file mode 100644 index 0000000..a8f1c64 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractObjectWriter.java @@ -0,0 +1,72 @@ +/* + * 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.writer; + +import org.apache.drill.exec.record.ColumnMetadata; +import org.apache.drill.exec.vector.accessor.ArrayWriter; +import org.apache.drill.exec.vector.accessor.ObjectWriter; +import org.apache.drill.exec.vector.accessor.ScalarWriter; +import org.apache.drill.exec.vector.accessor.ScalarWriter.ColumnWriterListener; +import org.apache.drill.exec.vector.accessor.TupleWriter; +import org.apache.drill.exec.vector.accessor.TupleWriter.TupleWriterListener; +import org.apache.drill.exec.vector.accessor.impl.HierarchicalFormatter; + +/** + * Abstract base class for the object layer in writers. This class acts + * as the glue between a column and the data type of that column, per the + * JSON model which Drill uses. This base class provides stubs for most + * methods so that type-specific subclasses can simply fill in the bits + * needed for that particular class. + */ + +public abstract class AbstractObjectWriter implements ObjectWriter { + + private ColumnMetadata schema; + + public AbstractObjectWriter(ColumnMetadata schema) { + this.schema = schema; + } + + @Override + public ColumnMetadata schema() { return schema; } + + @Override + public ScalarWriter scalar() { + throw new UnsupportedOperationException(); + } + + @Override + public TupleWriter tuple() { + throw new UnsupportedOperationException(); + } + + @Override + public ArrayWriter array() { + throw new UnsupportedOperationException(); + } + + public abstract WriterEvents events(); + + @Override + public void bindListener(ColumnWriterListener listener) { } + + @Override + public void bindListener(TupleWriterListener listener) { } + + public abstract void dump(HierarchicalFormatter format); +} http://git-wip-us.apache.org/repos/asf/drill/blob/40de8ca4/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractScalarWriter.java ---------------------------------------------------------------------- diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractScalarWriter.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractScalarWriter.java new file mode 100644 index 0000000..c02e2d9 --- /dev/null +++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/accessor/writer/AbstractScalarWriter.java @@ -0,0 +1,126 @@ +/* + * 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.writer; + +import java.math.BigDecimal; + +import org.apache.drill.exec.record.ColumnMetadata; +import org.apache.drill.exec.vector.BaseDataValueVector; +import org.apache.drill.exec.vector.accessor.ObjectType; +import org.apache.drill.exec.vector.accessor.ScalarWriter; +import org.apache.drill.exec.vector.accessor.impl.HierarchicalFormatter; +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 AbstractScalarWriter implements ScalarWriter, WriterEvents { + + public static class ScalarObjectWriter extends AbstractObjectWriter { + + private AbstractScalarWriter scalarWriter; + + public ScalarObjectWriter(ColumnMetadata schema, AbstractScalarWriter scalarWriter) { + super(schema); + this.scalarWriter = scalarWriter; + } + + @Override + public ObjectType type() { return ObjectType.SCALAR; } + + @Override + public void set(Object value) { scalarWriter.setObject(value); } + + @Override + public ScalarWriter scalar() { return scalarWriter; } + + @Override + public WriterEvents events() { return scalarWriter; } + + @Override + public void bindListener(ColumnWriterListener listener) { + scalarWriter.bindListener(listener); + } + + @Override + public void dump(HierarchicalFormatter format) { + format + .startObject(this) + .attribute("scalarWriter"); + scalarWriter.dump(format); + format.endObject(); + } + } + + public abstract BaseDataValueVector vector(); + + @Override + public void startWrite() { } + + @Override + public void startRow() { } + + @Override + public void endArrayValue() { } + + @Override + public void saveRow() { } + + @Override + public void setObject(Object value) { + if (value == null) { + setNull(); + } else if (value instanceof Integer) { + setInt((Integer) value); + } else if (value instanceof Long) { + setLong((Long) value); + } else if (value instanceof String) { + setString((String) value); + } else if (value instanceof BigDecimal) { + setDecimal((BigDecimal) value); + } else if (value instanceof Period) { + setPeriod((Period) value); + } else if (value instanceof byte[]) { + byte[] bytes = (byte[]) value; + setBytes(bytes, bytes.length); + } else if (value instanceof Byte) { + setInt((Byte) value); + } else if (value instanceof Short) { + setInt((Short) value); + } else if (value instanceof Double) { + setDouble((Double) value); + } else if (value instanceof Float) { + setDouble((Float) value); + } else { + throw new IllegalArgumentException("Unsupported type " + + value.getClass().getSimpleName()); + } + } + + public void dump(HierarchicalFormatter format) { + format + .startObject(this) + .attributeIdentity("vector", vector()) + .attribute("schema", vector().getField()) + .endObject(); + } +}