/* * 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.metadata.ColumnMetadata; import org.apache.drill.exec.vector.UInt4Vector; import org.apache.drill.exec.vector.accessor.ArrayWriter; import org.apache.drill.exec.vector.accessor.ColumnWriter; 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.TupleWriter; import org.apache.drill.exec.vector.accessor.VariantWriter; 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. *

* 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. *

* 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 * endValue(). 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: * * * * * * * * * * * * * * * * * * * * * * * * * *
Public APIArray EventOffset EventElement Event
startBatch()startWrite()startWrite()startWrite()
start() (new row)startRow()startRow()startRow()
start() (without save)restartRow()restartRow()restartRow()
save() (array)saveValue()saveValue()saveValue()
save() (row)See subclasses.
harvest()endWrite()endWrite()endWrite()
* * Some items to note: *

*/ public abstract class AbstractArrayWriter implements ArrayWriter, WriterEvents { /** * Object representation of an array writer. */ public static class ArrayObjectWriter extends AbstractObjectWriter { private final AbstractArrayWriter arrayWriter; public ArrayObjectWriter(AbstractArrayWriter arrayWriter) { this.arrayWriter = arrayWriter; } @Override public ArrayWriter array() { return arrayWriter; } @Override public ColumnWriter writer() { return arrayWriter; } @Override public WriterEvents events() { return arrayWriter; } @Override public void dump(HierarchicalFormatter format) { format .startObject(this) .attribute("arrayWriter"); arrayWriter.dump(format); format.endObject(); } } /** * 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 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(); } } public static abstract class BaseArrayWriter extends AbstractArrayWriter { public BaseArrayWriter(ColumnMetadata schema, UInt4Vector offsetVector, AbstractObjectWriter elementObjWriter) { super(schema, elementObjWriter, new OffsetVectorWriterImpl(offsetVector)); } @Override public void bindIndex(ColumnWriterIndex index) { assert elementIndex != null; outerIndex = index; offsetsWriter.bindIndex(index); elementObjWriter.events().bindIndex(elementIndex); } @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 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 void endWrite() { offsetsWriter.endWrite(); elementObjWriter.events().endWrite(); } @Override public int lastWriteIndex() { return outerIndex.vectorIndex(); } @Override public void dump(HierarchicalFormatter format) { format.extend(); super.dump(format); format .attribute("elementIndex", elementIndex.vectorIndex()) .attribute("offsetsWriter"); offsetsWriter.dump(format); } } protected final ColumnMetadata schema; protected AbstractObjectWriter elementObjWriter; protected final OffsetVectorWriter offsetsWriter; protected ColumnWriterIndex outerIndex; protected ArrayElementWriterIndex elementIndex; public AbstractArrayWriter(ColumnMetadata schema, AbstractObjectWriter elementObjWriter, OffsetVectorWriter offsetVectorWriter) { this.schema = schema; this.elementObjWriter = elementObjWriter; this.offsetsWriter = offsetVectorWriter; } @Override public void bindListener(ColumnWriterListener listener) { elementObjWriter.events().bindListener(listener); offsetsWriter.bindListener(listener); } @Override public ObjectType type() { return ObjectType.ARRAY; } @Override public ObjectType entryType() { return elementObjWriter.type(); } @Override public ColumnMetadata schema() { return schema; } @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(); } @Override public VariantWriter variant() { return elementObjWriter.variant(); } @Override public int size() { return elementIndex.arraySize(); } @Override public boolean nullable() { return false; } @Override public void setNull() { throw new IllegalStateException("Not nullable"); } @Override public int rowStartIndex() { return outerIndex.rowStartIndex(); } @Override public int lastWriteIndex() { return offsetsWriter.lastWriteIndex(); } @Override public int writeIndex() { return outerIndex.vectorIndex(); } @Override public void setNull(boolean isNull) { if (isNull == true) { throw new UnsupportedOperationException(); } } /** * 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 */ public OffsetVectorWriter offsetWriter() { return offsetsWriter; } @Override public void dump(HierarchicalFormatter format) { format .startObject(this) .attribute("elementObjWriter"); elementObjWriter.dump(format); format.endObject(); } }