| /* | |
| * 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. | |
| */ | |
| <@pp.dropOutputFile /> | |
| <@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/PromotableWriter.java" /> | |
| <#include "/@includes/license.ftl" /> | |
| package org.apache.arrow.vector.complex.impl; | |
| import java.util.Locale; | |
| <#include "/@includes/vv_imports.ftl" /> | |
| /** | |
| * This FieldWriter implementation delegates all FieldWriter API calls to an inner FieldWriter. This | |
| * inner field writer can start as a specific type, and this class will promote the writer to a | |
| * UnionWriter if a call is made that the specifically typed writer cannot handle. A new UnionVector | |
| * is created, wrapping the original vector, and replaces the original vector in the parent vector, | |
| * which can be either an AbstractStructVector or a ListVector. | |
| * | |
| * <p>The writer used can either be for single elements (struct) or lists. | |
| */ | |
| public class PromotableWriter extends AbstractPromotableFieldWriter { | |
| protected final AbstractStructVector parentContainer; | |
| protected final ListVector listVector; | |
| protected final ListViewVector listViewVector; | |
| protected final FixedSizeListVector fixedListVector; | |
| protected final LargeListVector largeListVector; | |
| protected final LargeListViewVector largeListViewVector; | |
| protected final NullableStructWriterFactory nullableStructWriterFactory; | |
| protected int position; | |
| protected static final int MAX_DECIMAL_PRECISION = 38; | |
| protected static final int MAX_DECIMAL256_PRECISION = 76; | |
| protected enum State { | |
| UNTYPED, | |
| SINGLE, | |
| UNION | |
| } | |
| protected MinorType type; | |
| protected ValueVector vector; | |
| protected UnionVector unionVector; | |
| protected State state; | |
| protected FieldWriter writer; | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to write. | |
| * @param parentContainer The parent container for the vector. | |
| */ | |
| public PromotableWriter(ValueVector v, AbstractStructVector parentContainer) { | |
| this(v, parentContainer, NullableStructWriterFactory.getNullableStructWriterFactoryInstance()); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param parentContainer The parent container for the vector. | |
| * @param nullableStructWriterFactory The factory to create the delegate writer. | |
| */ | |
| public PromotableWriter( | |
| ValueVector v, | |
| AbstractStructVector parentContainer, | |
| NullableStructWriterFactory nullableStructWriterFactory) { | |
| this.parentContainer = parentContainer; | |
| this.listVector = null; | |
| this.listViewVector = null; | |
| this.fixedListVector = null; | |
| this.largeListVector = null; | |
| this.largeListViewVector = null; | |
| this.nullableStructWriterFactory = nullableStructWriterFactory; | |
| init(v); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param listVector The vector that serves as a parent of v. | |
| */ | |
| public PromotableWriter(ValueVector v, ListVector listVector) { | |
| this(v, listVector, NullableStructWriterFactory.getNullableStructWriterFactoryInstance()); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param fixedListVector The vector that serves as a parent of v. | |
| */ | |
| public PromotableWriter(ValueVector v, FixedSizeListVector fixedListVector) { | |
| this(v, fixedListVector, NullableStructWriterFactory.getNullableStructWriterFactoryInstance()); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param largeListVector The vector that serves as a parent of v. | |
| */ | |
| public PromotableWriter(ValueVector v, LargeListVector largeListVector) { | |
| this(v, largeListVector, NullableStructWriterFactory.getNullableStructWriterFactoryInstance()); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param listViewVector The vector that serves as a parent of v. | |
| */ | |
| public PromotableWriter(ValueVector v, ListViewVector listViewVector) { | |
| this(v, listViewVector, NullableStructWriterFactory.getNullableStructWriterFactoryInstance()); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param largeListViewVector The vector that serves as a parent of v. | |
| */ | |
| public PromotableWriter(ValueVector v, LargeListViewVector largeListViewVector) { | |
| this(v, largeListViewVector, NullableStructWriterFactory.getNullableStructWriterFactoryInstance()); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param listVector The vector that serves as a parent of v. | |
| * @param nullableStructWriterFactory The factory to create the delegate writer. | |
| */ | |
| public PromotableWriter( | |
| ValueVector v, | |
| ListVector listVector, | |
| NullableStructWriterFactory nullableStructWriterFactory) { | |
| this.listVector = listVector; | |
| this.listViewVector = null; | |
| this.parentContainer = null; | |
| this.fixedListVector = null; | |
| this.largeListVector = null; | |
| this.largeListViewVector = null; | |
| this.nullableStructWriterFactory = nullableStructWriterFactory; | |
| init(v); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param listViewVector The vector that serves as a parent of v. | |
| * @param nullableStructWriterFactory The factory to create the delegate writer. | |
| */ | |
| public PromotableWriter( | |
| ValueVector v, | |
| ListViewVector listViewVector, | |
| NullableStructWriterFactory nullableStructWriterFactory) { | |
| this.listViewVector = listViewVector; | |
| this.listVector = null; | |
| this.parentContainer = null; | |
| this.fixedListVector = null; | |
| this.largeListVector = null; | |
| this.largeListViewVector = null; | |
| this.nullableStructWriterFactory = nullableStructWriterFactory; | |
| init(v); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param fixedListVector The vector that serves as a parent of v. | |
| * @param nullableStructWriterFactory The factory to create the delegate writer. | |
| */ | |
| public PromotableWriter( | |
| ValueVector v, | |
| FixedSizeListVector fixedListVector, | |
| NullableStructWriterFactory nullableStructWriterFactory) { | |
| this.fixedListVector = fixedListVector; | |
| this.parentContainer = null; | |
| this.listVector = null; | |
| this.listViewVector = null; | |
| this.largeListVector = null; | |
| this.largeListViewVector = null; | |
| this.nullableStructWriterFactory = nullableStructWriterFactory; | |
| init(v); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param largeListVector The vector that serves as a parent of v. | |
| * @param nullableStructWriterFactory The factory to create the delegate writer. | |
| */ | |
| public PromotableWriter( | |
| ValueVector v, | |
| LargeListVector largeListVector, | |
| NullableStructWriterFactory nullableStructWriterFactory) { | |
| this.largeListVector = largeListVector; | |
| this.fixedListVector = null; | |
| this.parentContainer = null; | |
| this.listVector = null; | |
| this.listViewVector = null; | |
| this.largeListViewVector = null; | |
| this.nullableStructWriterFactory = nullableStructWriterFactory; | |
| init(v); | |
| } | |
| /** | |
| * Constructs a new instance. | |
| * | |
| * @param v The vector to initialize the writer with. | |
| * @param largeListViewVector The vector that serves as a parent of v. | |
| * @param nullableStructWriterFactory The factory to create the delegate writer. | |
| */ | |
| public PromotableWriter( | |
| ValueVector v, | |
| LargeListViewVector largeListViewVector, | |
| NullableStructWriterFactory nullableStructWriterFactory) { | |
| this.largeListViewVector = largeListViewVector; | |
| this.fixedListVector = null; | |
| this.parentContainer = null; | |
| this.listVector = null; | |
| this.listViewVector = null; | |
| this.largeListVector = null; | |
| this.nullableStructWriterFactory = nullableStructWriterFactory; | |
| init(v); | |
| } | |
| private void init(ValueVector v) { | |
| if (v instanceof UnionVector) { | |
| state = State.UNION; | |
| unionVector = (UnionVector) v; | |
| writer = new UnionWriter(unionVector, nullableStructWriterFactory); | |
| } else if (v instanceof NullVector) { | |
| state = State.UNTYPED; | |
| } else { | |
| setWriter(v); | |
| } | |
| } | |
| @Override | |
| public void setAddVectorAsNullable(boolean nullable) { | |
| super.setAddVectorAsNullable(nullable); | |
| if (writer instanceof AbstractFieldWriter) { | |
| ((AbstractFieldWriter) writer).setAddVectorAsNullable(nullable); | |
| } | |
| } | |
| protected void setWriter(ValueVector v) { | |
| state = State.SINGLE; | |
| vector = v; | |
| type = v.getMinorType(); | |
| switch (type) { | |
| case STRUCT: | |
| writer = nullableStructWriterFactory.build((StructVector) vector); | |
| break; | |
| case LIST: | |
| writer = new UnionListWriter((ListVector) vector, nullableStructWriterFactory); | |
| break; | |
| case LISTVIEW: | |
| writer = new UnionListViewWriter((ListViewVector) vector, nullableStructWriterFactory); | |
| break; | |
| case MAP: | |
| writer = new UnionMapWriter((MapVector) vector); | |
| break; | |
| case UNION: | |
| writer = new UnionWriter((UnionVector) vector, nullableStructWriterFactory); | |
| break; | |
| case EXTENSIONTYPE: | |
| writer = ((ExtensionType) vector.getField().getType()).getNewFieldWriter(vector); | |
| break; | |
| default: | |
| writer = type.getNewFieldWriter(vector); | |
| break; | |
| } | |
| } | |
| @Override | |
| public void writeNull() { | |
| FieldWriter w = getWriter(); | |
| if (w != null) { | |
| w.writeNull(); | |
| } | |
| setPosition(idx() + 1); | |
| } | |
| @Override | |
| public void setPosition(int index) { | |
| super.setPosition(index); | |
| FieldWriter w = getWriter(); | |
| if (w == null) { | |
| position = index; | |
| } else { | |
| w.setPosition(index); | |
| } | |
| } | |
| protected boolean requiresArrowType(MinorType type) { | |
| return type == MinorType.DECIMAL | |
| || type == MinorType.MAP | |
| || type == MinorType.DURATION | |
| || type == MinorType.FIXEDSIZEBINARY | |
| || type == MinorType.EXTENSIONTYPE | |
| || (type.name().startsWith("TIMESTAMP") && type.name().endsWith("TZ")); | |
| } | |
| @Override | |
| protected FieldWriter getWriter(MinorType type, ArrowType arrowType) { | |
| if (state == State.UNION) { | |
| if (requiresArrowType(type)) { | |
| ((UnionWriter) writer).getWriter(type, arrowType); | |
| } else { | |
| ((UnionWriter) writer).getWriter(type); | |
| } | |
| } else if (state == State.UNTYPED) { | |
| if (type == null) { | |
| // ??? | |
| return null; | |
| } | |
| if (arrowType == null) { | |
| arrowType = type.getType(); | |
| } | |
| FieldType fieldType = new FieldType(addVectorAsNullable, arrowType, null, null); | |
| ValueVector v; | |
| if (listVector != null) { | |
| v = listVector.addOrGetVector(fieldType).getVector(); | |
| } else if (fixedListVector != null) { | |
| v = fixedListVector.addOrGetVector(fieldType).getVector(); | |
| } else if (listViewVector != null) { | |
| v = listViewVector.addOrGetVector(fieldType).getVector(); | |
| } else { | |
| v = largeListVector.addOrGetVector(fieldType).getVector(); | |
| } | |
| v.allocateNew(); | |
| setWriter(v); | |
| writer.setPosition(position); | |
| } else if (type != this.type) { | |
| promoteToUnion(); | |
| if (requiresArrowType(type)) { | |
| ((UnionWriter) writer).getWriter(type, arrowType); | |
| } else { | |
| ((UnionWriter) writer).getWriter(type); | |
| } | |
| } | |
| return writer; | |
| } | |
| @Override | |
| public boolean isEmptyStruct() { | |
| return writer.isEmptyStruct(); | |
| } | |
| @Override | |
| protected FieldWriter getWriter() { | |
| return writer; | |
| } | |
| protected FieldWriter promoteToUnion() { | |
| String name = vector.getField().getName(); | |
| TransferPair tp = | |
| vector.getTransferPair( | |
| vector.getMinorType().name().toLowerCase(Locale.ROOT), vector.getAllocator()); | |
| tp.transfer(); | |
| if (parentContainer != null) { | |
| // TODO allow dictionaries in complex types | |
| unionVector = parentContainer.addOrGetUnion(name); | |
| unionVector.allocateNew(); | |
| } else if (listVector != null) { | |
| unionVector = listVector.promoteToUnion(); | |
| } else if (fixedListVector != null) { | |
| unionVector = fixedListVector.promoteToUnion(); | |
| } else if (largeListVector != null) { | |
| unionVector = largeListVector.promoteToUnion(); | |
| } else if (listViewVector != null) { | |
| unionVector = listViewVector.promoteToUnion(); | |
| } | |
| unionVector.addVector((FieldVector) tp.getTo()); | |
| writer = new UnionWriter(unionVector, nullableStructWriterFactory); | |
| writer.setPosition(idx()); | |
| for (int i = 0; i <= idx(); i++) { | |
| unionVector.setType(i, vector.getMinorType()); | |
| } | |
| vector = null; | |
| state = State.UNION; | |
| return writer; | |
| } | |
| @Override | |
| public void write(DecimalHolder holder) { | |
| getWriter( | |
| MinorType.DECIMAL, | |
| new ArrowType.Decimal(MAX_DECIMAL_PRECISION, holder.scale, /*bitWidth=*/ 128)) | |
| .write(holder); | |
| } | |
| @Override | |
| public void writeDecimal(long start, ArrowBuf buffer, ArrowType arrowType) { | |
| getWriter( | |
| MinorType.DECIMAL, | |
| new ArrowType.Decimal( | |
| MAX_DECIMAL_PRECISION, | |
| ((ArrowType.Decimal) arrowType).getScale(), | |
| /*bitWidth=*/ 128)) | |
| .writeDecimal(start, buffer, arrowType); | |
| } | |
| @Override | |
| public void writeDecimal(BigDecimal value) { | |
| getWriter( | |
| MinorType.DECIMAL, | |
| new ArrowType.Decimal(MAX_DECIMAL_PRECISION, value.scale(), /*bitWidth=*/ 128)) | |
| .writeDecimal(value); | |
| } | |
| @Override | |
| public void writeBigEndianBytesToDecimal(byte[] value, ArrowType arrowType) { | |
| getWriter( | |
| MinorType.DECIMAL, | |
| new ArrowType.Decimal( | |
| MAX_DECIMAL_PRECISION, | |
| ((ArrowType.Decimal) arrowType).getScale(), | |
| /*bitWidth=*/ 128)) | |
| .writeBigEndianBytesToDecimal(value, arrowType); | |
| } | |
| @Override | |
| public void write(Decimal256Holder holder) { | |
| getWriter( | |
| MinorType.DECIMAL256, | |
| new ArrowType.Decimal(MAX_DECIMAL256_PRECISION, holder.scale, /*bitWidth=*/ 256)) | |
| .write(holder); | |
| } | |
| @Override | |
| public void writeDecimal256(long start, ArrowBuf buffer, ArrowType arrowType) { | |
| getWriter( | |
| MinorType.DECIMAL256, | |
| new ArrowType.Decimal( | |
| MAX_DECIMAL256_PRECISION, | |
| ((ArrowType.Decimal) arrowType).getScale(), | |
| /*bitWidth=*/ 256)) | |
| .writeDecimal256(start, buffer, arrowType); | |
| } | |
| @Override | |
| public void writeDecimal256(BigDecimal value) { | |
| getWriter( | |
| MinorType.DECIMAL256, | |
| new ArrowType.Decimal(MAX_DECIMAL256_PRECISION, value.scale(), /*bitWidth=*/ 256)) | |
| .writeDecimal256(value); | |
| } | |
| @Override | |
| public void writeBigEndianBytesToDecimal256(byte[] value, ArrowType arrowType) { | |
| getWriter( | |
| MinorType.DECIMAL256, | |
| new ArrowType.Decimal( | |
| MAX_DECIMAL256_PRECISION, | |
| ((ArrowType.Decimal) arrowType).getScale(), | |
| /*bitWidth=*/ 256)) | |
| .writeBigEndianBytesToDecimal256(value, arrowType); | |
| } | |
| @Override | |
| public void writeVarBinary(byte[] value) { | |
| getWriter(MinorType.VARBINARY).writeVarBinary(value); | |
| } | |
| @Override | |
| public void writeVarBinary(byte[] value, int offset, int length) { | |
| getWriter(MinorType.VARBINARY).writeVarBinary(value, offset, length); | |
| } | |
| @Override | |
| public void writeVarBinary(ByteBuffer value) { | |
| getWriter(MinorType.VARBINARY).writeVarBinary(value); | |
| } | |
| @Override | |
| public void writeVarBinary(ByteBuffer value, int offset, int length) { | |
| getWriter(MinorType.VARBINARY).writeVarBinary(value, offset, length); | |
| } | |
| @Override | |
| public void writeLargeVarBinary(byte[] value) { | |
| getWriter(MinorType.LARGEVARBINARY).writeLargeVarBinary(value); | |
| } | |
| @Override | |
| public void writeLargeVarBinary(byte[] value, int offset, int length) { | |
| getWriter(MinorType.LARGEVARBINARY).writeLargeVarBinary(value, offset, length); | |
| } | |
| @Override | |
| public void writeLargeVarBinary(ByteBuffer value) { | |
| getWriter(MinorType.LARGEVARBINARY).writeLargeVarBinary(value); | |
| } | |
| @Override | |
| public void writeLargeVarBinary(ByteBuffer value, int offset, int length) { | |
| getWriter(MinorType.LARGEVARBINARY).writeLargeVarBinary(value, offset, length); | |
| } | |
| @Override | |
| public void writeVarChar(Text value) { | |
| getWriter(MinorType.VARCHAR).writeVarChar(value); | |
| } | |
| @Override | |
| public void writeVarChar(String value) { | |
| getWriter(MinorType.VARCHAR).writeVarChar(value); | |
| } | |
| @Override | |
| public void writeLargeVarChar(Text value) { | |
| getWriter(MinorType.LARGEVARCHAR).writeLargeVarChar(value); | |
| } | |
| @Override | |
| public void writeLargeVarChar(String value) { | |
| getWriter(MinorType.LARGEVARCHAR).writeLargeVarChar(value); | |
| } | |
| @Override | |
| public void writeExtension(Object value, ArrowType arrowType) { | |
| getWriter(MinorType.EXTENSIONTYPE, arrowType).writeExtension(value, arrowType); | |
| } | |
| @Override | |
| public void write(ExtensionHolder holder) { | |
| getWriter(MinorType.EXTENSIONTYPE, holder.type()).write(holder); | |
| } | |
| @Override | |
| public void allocate() { | |
| getWriter().allocate(); | |
| } | |
| @Override | |
| public void clear() { | |
| getWriter().clear(); | |
| } | |
| @Override | |
| public Field getField() { | |
| return getWriter().getField(); | |
| } | |
| @Override | |
| public int getValueCapacity() { | |
| return getWriter().getValueCapacity(); | |
| } | |
| @Override | |
| public void close() throws Exception { | |
| getWriter().close(); | |
| } | |
| /** | |
| * Convert the writer to a PromotableViewWriter. | |
| * | |
| * @return The writer as a PromotableViewWriter. | |
| */ | |
| public PromotableViewWriter toViewWriter() { | |
| PromotableViewWriter promotableViewWriter = new PromotableViewWriter(unionVector, parentContainer, nullableStructWriterFactory); | |
| promotableViewWriter.position = position; | |
| promotableViewWriter.writer = writer; | |
| promotableViewWriter.state = state; | |
| promotableViewWriter.unionVector = unionVector; | |
| promotableViewWriter.type = MinorType.LISTVIEW; | |
| return promotableViewWriter; | |
| } | |
| } |