blob: d22eb00b2c30d9f0236f84ba032de602293e0fd9 [file] [log] [blame]
/*
* 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 = new UnionExtensionWriter((ExtensionTypeVector) 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) {
getWriter(MinorType.EXTENSIONTYPE).writeExtension(value);
}
@Override
public void addExtensionTypeWriterFactory(ExtensionTypeWriterFactory factory) {
getWriter(MinorType.EXTENSIONTYPE).addExtensionTypeWriterFactory(factory);
}
public void addExtensionTypeWriterFactory(ExtensionTypeWriterFactory factory, ArrowType arrowType) {
getWriter(MinorType.EXTENSIONTYPE, arrowType).addExtensionTypeWriterFactory(factory);
}
@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;
}
}