blob: 3245323c33033c6df8acebcf5d443c98b03dec35 [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.drill.exec.vector.accessor.writer;
import java.util.ArrayList;
import java.util.List;
import org.apache.drill.exec.record.metadata.ColumnMetadata;
import org.apache.drill.exec.vector.accessor.ColumnReader;
import org.apache.drill.exec.vector.accessor.ColumnWriterIndex;
import org.apache.drill.exec.vector.accessor.writer.AbstractArrayWriter.ArrayObjectWriter;
import org.apache.drill.exec.vector.accessor.writer.dummy.DummyArrayWriter;
import org.apache.drill.exec.vector.complex.AbstractMapVector;
import org.apache.drill.exec.vector.complex.MapVector;
import org.apache.drill.exec.vector.complex.RepeatedMapVector;
/**
* Writer for a Drill Map type. Maps are actually tuples, just like rows.
*/
public abstract class MapWriter extends AbstractTupleWriter {
/**
* Writer for a single (non-array) map. Clients don't really "write" maps;
* rather, this writer is a holder for the columns within the map, and those
* columns are what is written.
*/
protected static class SingleMapWriter extends MapWriter {
private final MapVector mapVector;
protected SingleMapWriter(ColumnMetadata schema, MapVector vector, List<AbstractObjectWriter> writers) {
super(schema, writers);
mapVector = vector;
}
@Override
public void endWrite() {
super.endWrite();
// A non repeated map has a field that holds the value count.
// Update it. (A repeated map uses the offset vector's value count.)
// Special form of set value count: used only for
// this class to avoid setting the value count of children.
// Setting these counts was already done. Doing it again
// will corrupt nullable vectors because the writers don't
// set the "lastSet" field of nullable vector accessors,
// and the initial value of -1 will cause all values to
// be overwritten.
mapVector.setMapValueCount(vectorIndex.vectorIndex());
}
@Override
public void preRollover() {
super.preRollover();
mapVector.setMapValueCount(vectorIndex.rowStartIndex());
}
@Override
public boolean isProjected() { return true; }
}
/**
* Writer for a an array of maps. A single array index coordinates writes
* to the constituent member vectors so that, say, the values for (row 10,
* element 5) all occur to the same position in the columns within the map.
* Since the map is an array, it has an associated offset vector, which the
* parent array writer is responsible for maintaining.
*/
protected static class ArrayMapWriter extends MapWriter {
protected ArrayMapWriter(ColumnMetadata schema, List<AbstractObjectWriter> writers) {
super(schema, writers);
}
@Override
public void bindIndex(ColumnWriterIndex index) {
// This is a repeated map, so the provided index is an array element
// index. Convert this to an index that will not increment the element
// index on each write so that a map with three members, say, won't
// increment the index for each member. Rather, the index must be
// incremented at the array level.
bindIndex(index, new MemberWriterIndex(index));
}
@Override
public boolean isProjected() { return true; }
}
protected static class DummyMapWriter extends MapWriter {
protected DummyMapWriter(ColumnMetadata schema,
List<AbstractObjectWriter> writers) {
super(schema, writers);
}
@Override
public boolean isProjected() { return false; }
@Override
public void copy(ColumnReader from) { }
}
protected static class DummyArrayMapWriter extends MapWriter {
protected DummyArrayMapWriter(ColumnMetadata schema,
List<AbstractObjectWriter> writers) {
super(schema, writers);
}
@Override
public boolean isProjected() { return false; }
@Override
public void copy(ColumnReader from) { }
}
protected final ColumnMetadata mapColumnSchema;
protected MapWriter(ColumnMetadata schema, List<AbstractObjectWriter> writers) {
super(schema.tupleSchema(), writers);
mapColumnSchema = schema;
}
public static TupleObjectWriter buildMap(ColumnMetadata schema, MapVector vector,
List<AbstractObjectWriter> writers) {
MapWriter mapWriter;
if (vector != null) {
// Vector is not required for a map writer; the map's columns
// are written, but not the (non-array) map.
mapWriter = new SingleMapWriter(schema, vector, writers);
} else {
mapWriter = new DummyMapWriter(schema, writers);
}
return new TupleObjectWriter(mapWriter);
}
public static ArrayObjectWriter buildMapArray(ColumnMetadata schema,
RepeatedMapVector mapVector,
List<AbstractObjectWriter> writers) {
MapWriter mapWriter;
if (mapVector != null) {
mapWriter = new ArrayMapWriter(schema, writers);
} else {
mapWriter = new DummyArrayMapWriter(schema, writers);
}
TupleObjectWriter mapArray = new TupleObjectWriter(mapWriter);
AbstractArrayWriter arrayWriter;
if (mapVector != null) {
arrayWriter = new ObjectArrayWriter(schema,
mapVector.getOffsetVector(),
mapArray);
} else {
arrayWriter = new DummyArrayWriter(schema, mapArray);
}
return new ArrayObjectWriter(arrayWriter);
}
public static AbstractObjectWriter buildMapWriter(ColumnMetadata schema,
AbstractMapVector vector,
List<AbstractObjectWriter> writers) {
if (schema.isArray()) {
return MapWriter.buildMapArray(schema,
(RepeatedMapVector) vector, writers);
} else {
return MapWriter.buildMap(schema, (MapVector) vector, writers);
}
}
public static AbstractObjectWriter buildMapWriter(ColumnMetadata schema, AbstractMapVector vector) {
assert schema.tupleSchema().size() == 0;
return buildMapWriter(schema, vector, new ArrayList<AbstractObjectWriter>());
}
@Override
public ColumnMetadata schema() { return mapColumnSchema; }
}