blob: adb90e2d649c2f351dc82ad249ba4b7d66ecd705 [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.
*/
package org.apache.arrow.vector.complex;
import static org.apache.arrow.util.Preconditions.checkNotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.util.ByteFunctionHelpers;
import org.apache.arrow.util.Preconditions;
import org.apache.arrow.vector.DensityAwareVector;
import org.apache.arrow.vector.FieldVector;
import org.apache.arrow.vector.ValueVector;
import org.apache.arrow.vector.compare.VectorVisitor;
import org.apache.arrow.vector.complex.impl.SingleStructReaderImpl;
import org.apache.arrow.vector.complex.reader.FieldReader;
import org.apache.arrow.vector.holders.ComplexHolder;
import org.apache.arrow.vector.types.Types.MinorType;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.FieldType;
import org.apache.arrow.vector.util.CallBack;
import org.apache.arrow.vector.util.JsonStringHashMap;
import org.apache.arrow.vector.util.TransferPair;
import io.netty.buffer.ArrowBuf;
/**
* A struct vector that has no null values (and no validity buffer).
* Child Vectors are handled in {@link AbstractStructVector}.
*/
public class NonNullableStructVector extends AbstractStructVector {
public static NonNullableStructVector empty(String name, BufferAllocator allocator) {
FieldType fieldType = new FieldType(false, ArrowType.Struct.INSTANCE, null, null);
return new NonNullableStructVector(name, allocator, fieldType, null);
}
private final SingleStructReaderImpl reader = new SingleStructReaderImpl(this);
protected final FieldType fieldType;
public int valueCount;
/**
* @deprecated Use FieldType or static constructor instead.
*/
@Deprecated
public NonNullableStructVector(String name, BufferAllocator allocator, CallBack callBack) {
this(name, allocator, new FieldType(false, ArrowType.Struct.INSTANCE, null, null), callBack);
}
/**
* Constructs a new instance.
*
* @param name The name of the instance.
* @param allocator The allocator to use to allocating/reallocating buffers.
* @param fieldType The type of this list.
* @param callBack A schema change callback.
*/
public NonNullableStructVector(String name, BufferAllocator allocator, FieldType fieldType, CallBack callBack) {
super(name, allocator, callBack);
this.fieldType = checkNotNull(fieldType);
this.valueCount = 0;
}
@Override
public FieldReader getReader() {
return reader;
}
private transient StructTransferPair ephPair;
/**
* Copies the element at fromIndex in the provided vector to thisIndex. Reallocates buffers
* if thisIndex is larger then current capacity.
*/
@Override
public void copyFrom(int fromIndex, int thisIndex, ValueVector from) {
Preconditions.checkArgument(this.getMinorType() == from.getMinorType());
if (ephPair == null || ephPair.from != from) {
ephPair = (StructTransferPair) from.makeTransferPair(this);
}
ephPair.copyValueSafe(fromIndex, thisIndex);
}
@Override
public void copyFromSafe(int fromIndex, int thisIndex, ValueVector from) {
copyFrom(fromIndex, thisIndex, from);
}
@Override
protected boolean supportsDirectRead() {
return true;
}
public Iterator<String> fieldNameIterator() {
return getChildFieldNames().iterator();
}
@Override
public void setInitialCapacity(int numRecords) {
for (final ValueVector v : (Iterable<ValueVector>) this) {
v.setInitialCapacity(numRecords);
}
}
@Override
public void setInitialCapacity(int valueCount, double density) {
for (final ValueVector vector : (Iterable<ValueVector>) this) {
if (vector instanceof DensityAwareVector) {
((DensityAwareVector)vector).setInitialCapacity(valueCount, density);
} else {
vector.setInitialCapacity(valueCount);
}
}
}
@Override
public int getBufferSize() {
if (valueCount == 0 || size() == 0) {
return 0;
}
long buffer = 0;
for (final ValueVector v : (Iterable<ValueVector>) this) {
buffer += v.getBufferSize();
}
return (int) buffer;
}
@Override
public int getBufferSizeFor(final int valueCount) {
if (valueCount == 0) {
return 0;
}
long bufferSize = 0;
for (final ValueVector v : (Iterable<ValueVector>) this) {
bufferSize += v.getBufferSizeFor(valueCount);
}
return (int) bufferSize;
}
@Override
public ArrowBuf getValidityBuffer() {
throw new UnsupportedOperationException();
}
@Override
public ArrowBuf getDataBuffer() {
throw new UnsupportedOperationException();
}
@Override
public ArrowBuf getOffsetBuffer() {
throw new UnsupportedOperationException();
}
@Override
public TransferPair getTransferPair(BufferAllocator allocator) {
return getTransferPair(name, allocator, null);
}
@Override
public TransferPair getTransferPair(String ref, BufferAllocator allocator, CallBack callBack) {
return new StructTransferPair(this, new NonNullableStructVector(name, allocator, fieldType, callBack), false);
}
@Override
public TransferPair makeTransferPair(ValueVector to) {
return new StructTransferPair(this, (NonNullableStructVector) to);
}
@Override
public TransferPair getTransferPair(String ref, BufferAllocator allocator) {
return new StructTransferPair(this, new NonNullableStructVector(ref, allocator, fieldType, callBack), false);
}
/**
* {@link TransferPair} for this this class.
*/
protected static class StructTransferPair implements TransferPair {
private final TransferPair[] pairs;
private final NonNullableStructVector from;
private final NonNullableStructVector to;
public StructTransferPair(NonNullableStructVector from, NonNullableStructVector to) {
this(from, to, true);
}
protected StructTransferPair(NonNullableStructVector from, NonNullableStructVector to, boolean allocate) {
this.from = from;
this.to = to;
this.pairs = new TransferPair[from.size()];
this.to.ephPair = null;
int i = 0;
FieldVector vector;
for (String child : from.getChildFieldNames()) {
int preSize = to.size();
vector = from.getChild(child);
if (vector == null) {
continue;
}
//DRILL-1872: we add the child fields for the vector, looking up the field by name. For a map vector,
// the child fields may be nested fields of the top level child. For example if the structure
// of a child field is oa.oab.oabc then we add oa, then add oab to oa then oabc to oab.
// But the children member of a Materialized field is a HashSet. If the fields are added in the
// children HashSet, and the hashCode of the Materialized field includes the hash code of the
// children, the hashCode value of oa changes *after* the field has been added to the HashSet.
// (This is similar to what happens in ScanBatch where the children cannot be added till they are
// read). To take care of this, we ensure that the hashCode of the MaterializedField does not
// include the hashCode of the children but is based only on MaterializedField$key.
final FieldVector newVector = to.addOrGet(child, vector.getField().getFieldType(), vector.getClass());
if (allocate && to.size() != preSize) {
newVector.allocateNew();
}
pairs[i++] = vector.makeTransferPair(newVector);
}
}
@Override
public void transfer() {
for (final TransferPair p : pairs) {
p.transfer();
}
to.valueCount = from.valueCount;
from.clear();
}
@Override
public ValueVector getTo() {
return to;
}
@Override
public void copyValueSafe(int from, int to) {
for (TransferPair p : pairs) {
p.copyValueSafe(from, to);
}
}
@Override
public void splitAndTransfer(int startIndex, int length) {
for (TransferPair p : pairs) {
p.splitAndTransfer(startIndex, length);
}
to.setValueCount(length);
}
}
@Override
public int getValueCapacity() {
if (size() == 0) {
return 0;
}
return getChildren().stream()
.mapToInt(child -> child.getValueCapacity())
.min()
.getAsInt();
}
@Override
public Object getObject(int index) {
Map<String, Object> vv = new JsonStringHashMap<>();
for (String child : getChildFieldNames()) {
ValueVector v = getChild(child);
if (v != null && index < v.getValueCount()) {
Object value = v.getObject(index);
if (value != null) {
vv.put(child, value);
}
}
}
return vv;
}
@Override
public int hashCode(int index) {
int hash = 0;
for (String child : getChildFieldNames()) {
ValueVector v = getChild(child);
if (v != null && index < v.getValueCount()) {
hash = ByteFunctionHelpers.combineHash(hash, v.hashCode(index));
}
}
return hash;
}
@Override
public <OUT, IN> OUT accept(VectorVisitor<OUT, IN> visitor, IN value) {
return visitor.visit(this, value);
}
@Override
public boolean isNull(int index) {
return false;
}
@Override
public int getNullCount() {
return 0;
}
public void get(int index, ComplexHolder holder) {
reader.setPosition(index);
holder.reader = reader;
}
@Override
public int getValueCount() {
return valueCount;
}
public ValueVector getVectorById(int id) {
return getChildByOrdinal(id);
}
@Override
public void setValueCount(int valueCount) {
for (final ValueVector v : getChildren()) {
v.setValueCount(valueCount);
}
NonNullableStructVector.this.valueCount = valueCount;
}
@Override
public void clear() {
for (final ValueVector v : getChildren()) {
v.clear();
}
valueCount = 0;
}
@Override
public void reset() {
for (final ValueVector v : getChildren()) {
v.reset();
}
valueCount = 0;
}
@Override
public Field getField() {
List<Field> children = new ArrayList<>();
for (ValueVector child : getChildren()) {
children.add(child.getField());
}
return new Field(name, fieldType, children);
}
@Override
public MinorType getMinorType() {
return MinorType.STRUCT;
}
@Override
public void close() {
final Collection<FieldVector> vectors = getChildren();
for (final FieldVector v : vectors) {
v.close();
}
vectors.clear();
valueCount = 0;
super.close();
}
/** Initializes the struct's members from the given Fields. */
public void initializeChildrenFromFields(List<Field> children) {
for (Field field : children) {
FieldVector vector = (FieldVector) this.add(field.getName(), field.getFieldType());
vector.initializeChildrenFromFields(field.getChildren());
}
}
public List<FieldVector> getChildrenFromFields() {
return getChildren();
}
}