blob: 45509f688ba889b1db26f186238c707036111cca [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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.arrow.vector.complex.impl;
import java.lang.reflect.Constructor;
import org.apache.arrow.vector.ValueVector;
import org.apache.arrow.vector.VectorDescriptor;
import org.apache.arrow.vector.ZeroVector;
import org.apache.arrow.vector.complex.AbstractMapVector;
import org.apache.arrow.vector.complex.ListVector;
import org.apache.arrow.vector.complex.UnionVector;
import org.apache.arrow.vector.complex.writer.FieldWriter;
import org.apache.arrow.vector.types.MaterializedField;
import org.apache.arrow.vector.types.Types.DataMode;
import org.apache.arrow.vector.types.Types.MajorType;
import org.apache.arrow.vector.types.Types.MinorType;
import org.apache.arrow.vector.util.BasicTypeHelper;
import org.apache.arrow.vector.util.TransferPair;
/**
* 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 AbstractMapVector or a ListVector.
*/
public class PromotableWriter extends AbstractPromotableFieldWriter {
private final AbstractMapVector parentContainer;
private final ListVector listVector;
private int position;
private enum State {
UNTYPED, SINGLE, UNION
}
private MinorType type;
private ValueVector vector;
private UnionVector unionVector;
private State state;
private FieldWriter writer;
public PromotableWriter(ValueVector v, AbstractMapVector parentContainer) {
super(null);
this.parentContainer = parentContainer;
this.listVector = null;
init(v);
}
public PromotableWriter(ValueVector v, ListVector listVector) {
super(null);
this.listVector = listVector;
this.parentContainer = null;
init(v);
}
private void init(ValueVector v) {
if (v instanceof UnionVector) {
state = State.UNION;
unionVector = (UnionVector) v;
writer = new UnionWriter(unionVector);
} else if (v instanceof ZeroVector) {
state = State.UNTYPED;
} else {
setWriter(v);
}
}
private void setWriter(ValueVector v) {
state = State.SINGLE;
vector = v;
type = v.getField().getType().getMinorType();
Class<?> writerClass = BasicTypeHelper
.getWriterImpl(v.getField().getType().getMinorType(), v.getField().getDataMode());
if (writerClass.equals(SingleListWriter.class)) {
writerClass = UnionListWriter.class;
}
Class<?> vectorClass = BasicTypeHelper.getValueVectorClass(v.getField().getType().getMinorType(), v.getField()
.getDataMode());
try {
Constructor<?> constructor = null;
for (Constructor<?> c : writerClass.getConstructors()) {
if (c.getParameterTypes().length == 3) {
constructor = c;
}
}
if (constructor == null) {
constructor = writerClass.getConstructor(vectorClass, AbstractFieldWriter.class);
writer = (FieldWriter) constructor.newInstance(vector, null);
} else {
writer = (FieldWriter) constructor.newInstance(vector, null, true);
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
@Override
public void setPosition(int index) {
super.setPosition(index);
FieldWriter w = getWriter();
if (w == null) {
position = index;
} else {
w.setPosition(index);
}
}
protected FieldWriter getWriter(MinorType type) {
if (state == State.UNION) {
return writer;
}
if (state == State.UNTYPED) {
if (type == null) {
return null;
}
ValueVector v = listVector.addOrGetVector(new VectorDescriptor(new MajorType(type, DataMode.OPTIONAL))).getVector();
v.allocateNew();
setWriter(v);
writer.setPosition(position);
}
if (type != this.type) {
return promoteToUnion();
}
return writer;
}
@Override
public boolean isEmptyMap() {
return writer.isEmptyMap();
}
protected FieldWriter getWriter() {
return getWriter(type);
}
private FieldWriter promoteToUnion() {
String name = vector.getField().getLastName();
TransferPair tp = vector.getTransferPair(vector.getField().getType().getMinorType().name().toLowerCase(), vector.getAllocator());
tp.transfer();
if (parentContainer != null) {
unionVector = parentContainer.addOrGet(name, new MajorType(MinorType.UNION, DataMode.OPTIONAL), UnionVector.class);
} else if (listVector != null) {
unionVector = listVector.promoteToUnion();
}
unionVector.addVector(tp.getTo());
writer = new UnionWriter(unionVector);
writer.setPosition(idx());
for (int i = 0; i < idx(); i++) {
unionVector.getMutator().setType(i, vector.getField().getType().getMinorType());
}
vector = null;
state = State.UNION;
return writer;
}
@Override
public void allocate() {
getWriter().allocate();
}
@Override
public void clear() {
getWriter().clear();
}
@Override
public MaterializedField getField() {
return getWriter().getField();
}
@Override
public int getValueCapacity() {
return getWriter().getValueCapacity();
}
@Override
public void close() throws Exception {
getWriter().close();
}
}