All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.kuseman.payloadbuilder.api.execution.vector.ChainedTupleVector Maven / Gradle / Ivy

The newest version!
package se.kuseman.payloadbuilder.api.execution.vector;

import java.util.Arrays;
import java.util.List;

import se.kuseman.payloadbuilder.api.catalog.ResolvedType;
import se.kuseman.payloadbuilder.api.catalog.Schema;
import se.kuseman.payloadbuilder.api.execution.Decimal;
import se.kuseman.payloadbuilder.api.execution.EpochDateTime;
import se.kuseman.payloadbuilder.api.execution.EpochDateTimeOffset;
import se.kuseman.payloadbuilder.api.execution.ObjectVector;
import se.kuseman.payloadbuilder.api.execution.TupleVector;
import se.kuseman.payloadbuilder.api.execution.UTF8String;
import se.kuseman.payloadbuilder.api.execution.ValueVector;

/** A tuple vector that chains a list of other tuple vectros, exposing those as a single vector */
public class ChainedTupleVector implements TupleVector
{
    private final Schema schema;
    private final List vectors;
    private final int rowCount;
    /** Ordinals for where row counts starts in each nested tuple vector */
    private final int[] ordinals;
    private final ChainedValueVector[] columns;

    private ChainedTupleVector(Schema schema, List vectors, int rowCount, int[] ordinals)
    {
        this.schema = schema;
        this.vectors = vectors;
        this.rowCount = rowCount;
        this.ordinals = ordinals;
        this.columns = new ChainedValueVector[schema.getSize()];
    }

    @Override
    public int getRowCount()
    {
        return rowCount;
    }

    @Override
    public ValueVector getColumn(int column)
    {
        ChainedValueVector col = columns[column];
        if (col == null)
        {
            col = new ChainedValueVector(schema.getColumns()
                    .get(column)
                    .getType(), column);
            columns[column] = col;
        }
        return col;
    }

    @Override
    public Schema getSchema()
    {
        return schema;
    }

    class ChainedValueVector implements ValueVector
    {
        private final ResolvedType type;
        private final int column;

        // Cached values optimized for sequential access of rows
        private ValueVector currentVector;
        private int currentVectorUpperBound = -1;
        private int currentVectorLowerBound = -1;

        ChainedValueVector(ResolvedType type, int column)
        {
            this.type = type;
            this.column = column;
        }

        @Override
        public ResolvedType type()
        {
            return type;
        }

        @Override
        public int size()
        {
            return rowCount;
        }

        @Override
        public boolean isNull(int row)
        {
            setCurrentVector(row);
            return currentVector.isNull(row - currentVectorLowerBound);
        }

        @Override
        public boolean getBoolean(int row)
        {
            setCurrentVector(row);
            return currentVector.getBoolean(row - currentVectorLowerBound);
        }

        @Override
        public int getInt(int row)
        {
            setCurrentVector(row);
            return currentVector.getInt(row - currentVectorLowerBound);
        }

        @Override
        public long getLong(int row)
        {
            setCurrentVector(row);
            return currentVector.getLong(row - currentVectorLowerBound);
        }

        @Override
        public float getFloat(int row)
        {
            setCurrentVector(row);
            return currentVector.getFloat(row - currentVectorLowerBound);
        }

        @Override
        public double getDouble(int row)
        {
            setCurrentVector(row);
            return currentVector.getDouble(row - currentVectorLowerBound);
        }

        @Override
        public Decimal getDecimal(int row)
        {
            setCurrentVector(row);
            return currentVector.getDecimal(row - currentVectorLowerBound);
        }

        @Override
        public UTF8String getString(int row)
        {
            setCurrentVector(row);
            return currentVector.getString(row - currentVectorLowerBound);
        }

        @Override
        public EpochDateTime getDateTime(int row)
        {
            setCurrentVector(row);
            return currentVector.getDateTime(row - currentVectorLowerBound);
        }

        @Override
        public EpochDateTimeOffset getDateTimeOffset(int row)
        {
            setCurrentVector(row);
            return currentVector.getDateTimeOffset(row - currentVectorLowerBound);
        }

        @Override
        public ObjectVector getObject(int row)
        {
            setCurrentVector(row);
            return currentVector.getObject(row - currentVectorLowerBound);
        }

        @Override
        public ValueVector getArray(int row)
        {
            setCurrentVector(row);
            return currentVector.getArray(row - currentVectorLowerBound);
        }

        @Override
        public TupleVector getTable(int row)
        {
            setCurrentVector(row);
            return currentVector.getTable(row - currentVectorLowerBound);
        }

        @Override
        public Object getAny(int row)
        {
            setCurrentVector(row);
            return currentVector.getAny(row - currentVectorLowerBound);
        }

        private void setCurrentVector(int row)
        {
            // Vector already set
            if (row >= currentVectorLowerBound
                    && row <= currentVectorUpperBound)
            {
                return;
            }

            int index = getIndex(row);
            currentVectorLowerBound = index == 0 ? 0
                    : ordinals[index - 1];
            currentVectorUpperBound = ordinals[index] - 1;

            TupleVector tupleVector = vectors.get(index);

            // Current vector's schema doesn't have this column, return null
            if (column >= tupleVector.getSchema()
                    .getSize())
            {
                currentVector = ValueVector.literalNull(type, rowCount);
            }
            else
            {
                currentVector = tupleVector.getColumn(column);
            }
        }

        private int getIndex(int row)
        {
            /*
             * @formatter:off
             * 
             * 3 vectors with their row indices
             * [0-4] (0-4)
             * [0-4] (5-9)
             * [0-4] (10-14)
             * 
             * Ordinals array: [5,10,15]
             * 
             * Total index:            0,  1,  2,  3,  4   5,  6,  7,  8,  9   10, 11, 12, 13, 14
             * Index in vector:      [[0,  1,  2,  3,  4],[0,  1,  2,  3,  4],[ 0,  1,  2,  3,  4]]
             * Binary search result:  -1, -1, -1, -1, -1   0, -2, -2, -2, -2    1, -3, -3, -3, -3
             * @formatt:on
             */
            
            // Ordinals are row count + 1 in the source vectors
            int index = Arrays.binarySearch(ordinals, row);
            // Result is either the index or (-(insertion point) - 1)
            index++;
            if (index < 0)
            {
                index = -index;
            }
            return index;
        }
    }

    /**
     * Created a chained tuple vector. This returns a single tuple vector that wraps a list of source vectors. This requires that the provided vectors shares a common subset of their schema.
     */
    public static TupleVector chain(List vectors)
    {
        int size = vectors.size();
        
        if (size == 0)
        {
            return TupleVector.EMPTY;
        }
        else if (size == 1)
        {
            return vectors.get(0);
        }
        
        // Validate schema. All schemas must share the same columns or have less/more columns
        // ie.
        // Schema1
        // col1 int
        // col2 boolean
        //
        // Schema2
        // col1 int
        //
        // Schema3
        // col1 int
        // col2 boolean
        // col3 string
        //
        // The vector with the largest schema will be the resulting schema
        
        Schema schema = vectors.get(0).getSchema();
        int[] ordinals = new int[size];
        int rowCount = vectors.get(0).getRowCount();
        ordinals[0] = rowCount;
        
        for (int i=1;i schema.getSize())
            {
                schema = current;
            }
        }
        return new ChainedTupleVector(schema, vectors, rowCount, ordinals);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy