You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by mm...@apache.org on 2018/08/17 13:09:07 UTC

[2/3] hive git commit: HIVE-20321: Vectorization: Cut down memory size of 1 col VectorHashKeyWrapper to <1 CacheLine (Matt McCline, reviewed by Gopal Vijayaraghavan)

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBase.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBase.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBase.java
new file mode 100644
index 0000000..8bf2ccb
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBase.java
@@ -0,0 +1,223 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hive.common.util.Murmur3;
+
+import java.sql.Timestamp;
+
+import org.apache.hadoop.hive.common.type.HiveIntervalDayTime;
+import org.apache.hadoop.hive.ql.exec.KeyWrapper;
+import org.apache.hadoop.hive.ql.exec.vector.IntervalDayTimeColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.TimestampColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.VectorColumnSetInfo;
+import org.apache.hadoop.hive.ql.metadata.HiveException;
+import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+
+/**
+ * A hash map key wrapper for vectorized processing.
+ * It stores the key values as primitives in arrays for each supported primitive type.
+ * This works in conjunction with
+ * {@link org.apache.hadoop.hive.ql.exec.VectorHashKeyWrapperBatch VectorHashKeyWrapperBatch}
+ * to hash vectorized processing units (batches).
+ */
+public abstract class VectorHashKeyWrapperBase extends KeyWrapper {
+
+  public static final class HashContext {
+    private final Murmur3.IncrementalHash32 bytesHash = new Murmur3.IncrementalHash32();
+
+    public static Murmur3.IncrementalHash32 getBytesHash(HashContext ctx) {
+      if (ctx == null) {
+        return new Murmur3.IncrementalHash32();
+      }
+      return ctx.bytesHash;
+    }
+  }
+
+  protected int hashcode;
+
+  protected VectorHashKeyWrapperBase() {
+    hashcode = 0;
+  }
+
+  @Override
+  public void getNewKey(Object row, ObjectInspector rowInspector) throws HiveException {
+    throw new HiveException("Should not be called");
+  }
+
+  @Override
+  public void setHashKey() {
+    throw new RuntimeException("Not implemented");
+  }
+
+  @Override
+  public int hashCode() {
+    return hashcode;
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  @Override
+  protected Object clone() {
+    throw new RuntimeException("Not implemented");
+  }
+
+  @Override
+  public KeyWrapper copyKey() {
+    return (KeyWrapper) clone();
+  }
+
+  @Override
+  public void copyKey(KeyWrapper oldWrapper) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Object[] getKeyArray() {
+    throw new UnsupportedOperationException();
+  }
+
+  public void assignLong(int keyIndex, int index, long v) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  // FIXME: isNull is not updated; which might cause problems
+  @Deprecated
+  public void assignLong(int index, long v) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignNullLong(int keyIndex, int index) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignDouble(int index, double d) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignNullDouble(int keyIndex, int index) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignString(int index, byte[] bytes, int start, int length) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignNullString(int keyIndex, int index) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignDecimal(int index, HiveDecimalWritable value) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignNullDecimal(int keyIndex, int index) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignTimestamp(int index, Timestamp value) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignTimestamp(int index, TimestampColumnVector colVector, int elementNum) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignNullTimestamp(int keyIndex, int index) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignIntervalDayTime(int index, HiveIntervalDayTime value) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignIntervalDayTime(int index, IntervalDayTimeColumnVector colVector, int elementNum) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void assignNullIntervalDayTime(int keyIndex, int index) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  /*
+   * This method is mainly intended for debug display purposes.
+   */
+  public String stringifyKeys(VectorColumnSetInfo columnSetInfo)
+  {
+    throw new RuntimeException("Not implemented");
+  }
+
+  @Override
+  public String toString()
+  {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public long getLongValue(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public double getDoubleValue(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public byte[] getBytes(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public int getByteStart(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public int getByteLength(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public HiveDecimalWritable getDecimal(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public Timestamp getTimestamp(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public HiveIntervalDayTime getIntervalDayTime(int i) {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public int getVariableSize() {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void clearIsNull() {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public void setNull() {
+    throw new RuntimeException("Not implemented");
+  }
+
+  public boolean isNull(int keyIndex) {
+    throw new RuntimeException("Not implemented");
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBatch.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBatch.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBatch.java
new file mode 100644
index 0000000..dd31991
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperBatch.java
@@ -0,0 +1,1076 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hadoop.hive.ql.exec.vector.expressions.VectorExpression;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.VectorExpressionWriter;
+import org.apache.hadoop.hive.ql.metadata.HiveException;
+import org.apache.hadoop.hive.ql.util.JavaDataModel;
+import org.apache.hadoop.hive.ql.exec.vector.BytesColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.ColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.ColumnVector.Type;
+import org.apache.hadoop.hive.ql.exec.vector.DecimalColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.DoubleColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.IntervalDayTimeColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.LongColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.TimestampColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.VectorColumnSetInfo;
+import org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
+
+/**
+ * Class for handling vectorized hash map key wrappers. It evaluates the key columns in a
+ * row batch in a vectorized fashion.
+ * This class stores additional information about keys needed to evaluate and output the key values.
+ *
+ */
+public class VectorHashKeyWrapperBatch extends VectorColumnSetInfo {
+
+  public VectorHashKeyWrapperBatch(int keyCount) {
+    super(keyCount);
+  }
+
+  /**
+   * Number of object references in 'this' (for size computation)
+   */
+  private static final int MODEL_REFERENCES_COUNT = 7;
+
+  /**
+   * The key expressions that require evaluation and output the primitive values for each key.
+   */
+  private VectorExpression[] keyExpressions;
+
+  /**
+   * Pre-allocated batch size vector of keys wrappers.
+   * N.B. these keys are **mutable** and should never be used in a HashMap.
+   * Always clone the key wrapper to obtain an immutable keywrapper suitable
+   * to use a key in a HashMap.
+   */
+  private VectorHashKeyWrapperBase[] vectorHashKeyWrappers;
+
+  /**
+   * The fixed size of the key wrappers.
+   */
+  private int keysFixedSize;
+
+  /**
+   * Shared hashcontext for all keys in this batch
+   */
+  private final VectorHashKeyWrapperBase.HashContext hashCtx = new VectorHashKeyWrapperBase.HashContext();
+
+   /**
+   * Returns the compiled fixed size for the key wrappers.
+   * @return
+   */
+  public int getKeysFixedSize() {
+    return keysFixedSize;
+  }
+
+  /**
+   * Accessor for the batch-sized array of key wrappers.
+   */
+  public VectorHashKeyWrapperBase[] getVectorHashKeyWrappers() {
+    return vectorHashKeyWrappers;
+  }
+
+  /**
+   * Processes a batch:
+   * <ul>
+   * <li>Evaluates each key vector expression.</li>
+   * <li>Copies out each key's primitive values into the key wrappers</li>
+   * <li>computes the hashcode of the key wrappers</li>
+   * </ul>
+   * @param batch
+   * @throws HiveException
+   */
+  public void evaluateBatch(VectorizedRowBatch batch) throws HiveException {
+
+    if (keyCount == 0) {
+      // all keywrappers must be EmptyVectorHashKeyWrapper
+      return;
+    }
+
+    for(int i=0;i<batch.size;++i) {
+      vectorHashKeyWrappers[i].clearIsNull();
+    }
+
+    int keyIndex;
+    int columnIndex;
+    for(int i = 0; i< longIndices.length; ++i) {
+      keyIndex = longIndices[i];
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      LongColumnVector columnVector = (LongColumnVector) batch.cols[columnIndex];
+
+      evaluateLongColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<doubleIndices.length; ++i) {
+      keyIndex = doubleIndices[i];
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      DoubleColumnVector columnVector = (DoubleColumnVector) batch.cols[columnIndex];
+
+      evaluateDoubleColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<stringIndices.length; ++i) {
+      keyIndex = stringIndices[i];
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      BytesColumnVector columnVector = (BytesColumnVector) batch.cols[columnIndex];
+
+      evaluateStringColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<decimalIndices.length; ++i) {
+      keyIndex = decimalIndices[i];
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      DecimalColumnVector columnVector = (DecimalColumnVector) batch.cols[columnIndex];
+
+      evaluateDecimalColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<timestampIndices.length; ++i) {
+      keyIndex = timestampIndices[i];
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      TimestampColumnVector columnVector = (TimestampColumnVector) batch.cols[columnIndex];
+
+      evaluateTimestampColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<intervalDayTimeIndices.length; ++i) {
+      keyIndex = intervalDayTimeIndices[i];
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      IntervalDayTimeColumnVector columnVector = (IntervalDayTimeColumnVector) batch.cols[columnIndex];
+
+      evaluateIntervalDayTimeColumnVector(batch, columnVector, keyIndex, i);
+    }
+    for(int i=0;i<batch.size;++i) {
+      vectorHashKeyWrappers[i].setHashKey();
+    }
+  }
+
+  public void evaluateBatchGroupingSets(VectorizedRowBatch batch,
+      boolean[] groupingSetsOverrideIsNulls) throws HiveException {
+
+    for(int i=0;i<batch.size;++i) {
+      vectorHashKeyWrappers[i].clearIsNull();
+    }
+    int keyIndex;
+    int columnIndex;
+    for(int i = 0; i< longIndices.length; ++i) {
+      keyIndex = longIndices[i];
+      if (groupingSetsOverrideIsNulls[keyIndex]) {
+        final int batchSize = batch.size;
+        for(int r = 0; r < batchSize; ++r) {
+          vectorHashKeyWrappers[r].assignNullLong(keyIndex, i);
+        }
+        continue;
+      }
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      LongColumnVector columnVector = (LongColumnVector) batch.cols[columnIndex];
+
+      evaluateLongColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<doubleIndices.length; ++i) {
+      keyIndex = doubleIndices[i];
+      if (groupingSetsOverrideIsNulls[keyIndex]) {
+        final int batchSize = batch.size;
+        for(int r = 0; r < batchSize; ++r) {
+          vectorHashKeyWrappers[r].assignNullDouble(keyIndex, i);
+        }
+        continue;
+      }
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      DoubleColumnVector columnVector = (DoubleColumnVector) batch.cols[columnIndex];
+
+      evaluateDoubleColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<stringIndices.length; ++i) {
+      keyIndex = stringIndices[i];
+      if (groupingSetsOverrideIsNulls[keyIndex]) {
+        final int batchSize = batch.size;
+        for(int r = 0; r < batchSize; ++r) {
+          vectorHashKeyWrappers[r].assignNullString(keyIndex, i);
+        }
+        continue;
+      }
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      BytesColumnVector columnVector = (BytesColumnVector) batch.cols[columnIndex];
+
+      evaluateStringColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<decimalIndices.length; ++i) {
+      keyIndex = decimalIndices[i];
+      if (groupingSetsOverrideIsNulls[keyIndex]) {
+        final int batchSize = batch.size;
+        for(int r = 0; r < batchSize; ++r) {
+          vectorHashKeyWrappers[r].assignNullDecimal(keyIndex, i);
+        }
+        continue;
+      }
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      DecimalColumnVector columnVector = (DecimalColumnVector) batch.cols[columnIndex];
+
+      evaluateDecimalColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<timestampIndices.length; ++i) {
+      keyIndex = timestampIndices[i];
+      if (groupingSetsOverrideIsNulls[keyIndex]) {
+        final int batchSize = batch.size;
+        for(int r = 0; r < batchSize; ++r) {
+          vectorHashKeyWrappers[r].assignNullTimestamp(keyIndex, i);
+        }
+        continue;
+      }
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      TimestampColumnVector columnVector = (TimestampColumnVector) batch.cols[columnIndex];
+
+      evaluateTimestampColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<intervalDayTimeIndices.length; ++i) {
+      keyIndex = intervalDayTimeIndices[i];
+      if (groupingSetsOverrideIsNulls[keyIndex]) {
+        final int batchSize = batch.size;
+        for(int r = 0; r < batchSize; ++r) {
+          vectorHashKeyWrappers[r].assignNullIntervalDayTime(keyIndex, i);
+        }
+        continue;
+      }
+      columnIndex = keyExpressions[keyIndex].getOutputColumnNum();
+      IntervalDayTimeColumnVector columnVector = (IntervalDayTimeColumnVector) batch.cols[columnIndex];
+
+      evaluateIntervalDayTimeColumnVector(batch, columnVector, keyIndex, i);
+    }
+
+    for(int i=0;i<batch.size;++i) {
+      vectorHashKeyWrappers[i].setHashKey();
+    }
+  }
+
+  private void evaluateLongColumnVector(VectorizedRowBatch batch, LongColumnVector columnVector,
+      int keyIndex, int index) {
+    if (columnVector.isRepeating) {
+      if (columnVector.noNulls || !columnVector.isNull[0]) {
+        assignLongNoNullsRepeating(index, batch.size, columnVector);
+      } else {
+        assignLongNullsRepeating(keyIndex, index, batch.size, columnVector);
+      }
+    } else if (columnVector.noNulls) {
+      if (batch.selectedInUse) {
+        assignLongNoNullsNoRepeatingSelection(index, batch.size, columnVector, batch.selected);
+      } else {
+        assignLongNoNullsNoRepeatingNoSelection(index, batch.size, columnVector);
+      }
+    } else {
+      if (batch.selectedInUse) {
+        assignLongNullsNoRepeatingSelection (keyIndex, index, batch.size, columnVector, batch.selected);
+      } else {
+        assignLongNullsNoRepeatingNoSelection(keyIndex, index, batch.size, columnVector);
+      }
+    }
+  }
+
+  private void evaluateDoubleColumnVector(VectorizedRowBatch batch, DoubleColumnVector columnVector,
+      int keyIndex, int index) {
+    if (columnVector.isRepeating) {
+      if (columnVector.noNulls || !columnVector.isNull[0]) {
+        assignDoubleNoNullsRepeating(index, batch.size, columnVector);
+      } else {
+        assignDoubleNullsRepeating(keyIndex, index, batch.size, columnVector);
+      }
+    } else if (columnVector.noNulls) {
+      if (batch.selectedInUse) {
+        assignDoubleNoNullsNoRepeatingSelection(index, batch.size, columnVector, batch.selected);
+      } else {
+        assignDoubleNoNullsNoRepeatingNoSelection(index, batch.size, columnVector);
+      }
+    } else {
+      if (batch.selectedInUse) {
+        assignDoubleNullsNoRepeatingSelection (keyIndex, index, batch.size, columnVector, batch.selected);
+      } else {
+        assignDoubleNullsNoRepeatingNoSelection(keyIndex, index, batch.size, columnVector);
+      }
+    }
+  }
+
+  private void evaluateStringColumnVector(VectorizedRowBatch batch, BytesColumnVector columnVector,
+      int keyIndex, int index) {
+    if (columnVector.isRepeating) {
+      if (columnVector.noNulls || !columnVector.isNull[0]) {
+        assignStringNoNullsRepeating(index, batch.size, columnVector);
+      } else {
+        assignStringNullsRepeating(keyIndex, index, batch.size, columnVector);
+      }
+    } else if (columnVector.noNulls) {
+      if (batch.selectedInUse) {
+        assignStringNoNullsNoRepeatingSelection(index, batch.size, columnVector, batch.selected);
+      } else {
+        assignStringNoNullsNoRepeatingNoSelection(index, batch.size, columnVector);
+      }
+    } else {
+      if (batch.selectedInUse) {
+        assignStringNullsNoRepeatingSelection (keyIndex, index, batch.size, columnVector, batch.selected);
+      } else {
+        assignStringNullsNoRepeatingNoSelection(keyIndex, index, batch.size, columnVector);
+      }
+    }
+  }
+
+  private void evaluateDecimalColumnVector(VectorizedRowBatch batch, DecimalColumnVector columnVector,
+      int keyIndex, int index) {
+    if (columnVector.isRepeating) {
+      if (columnVector.noNulls || !columnVector.isNull[0]) {
+        assignDecimalNoNullsRepeating(index, batch.size, columnVector);
+      } else {
+        assignDecimalNullsRepeating(keyIndex, index, batch.size, columnVector);
+      }
+    } else if (columnVector.noNulls) {
+      if (batch.selectedInUse) {
+        assignDecimalNoNullsNoRepeatingSelection(index, batch.size, columnVector, batch.selected);
+      } else {
+        assignDecimalNoNullsNoRepeatingNoSelection(index, batch.size, columnVector);
+      }
+    } else {
+      if (batch.selectedInUse) {
+        assignDecimalNullsNoRepeatingSelection (keyIndex, index, batch.size, columnVector, batch.selected);
+      } else {
+        assignDecimalNullsNoRepeatingNoSelection(keyIndex, index, batch.size, columnVector);
+      }
+    }
+  }
+
+  private void evaluateTimestampColumnVector(VectorizedRowBatch batch, TimestampColumnVector columnVector,
+      int keyIndex, int index) {
+    if (columnVector.isRepeating) {
+      if (columnVector.noNulls || !columnVector.isNull[0]) {
+        assignTimestampNoNullsRepeating(index, batch.size, columnVector);
+      } else {
+        assignTimestampNullsRepeating(keyIndex, index, batch.size, columnVector);
+      }
+    } else if (columnVector.noNulls) {
+      if (batch.selectedInUse) {
+        assignTimestampNoNullsNoRepeatingSelection(index, batch.size, columnVector, batch.selected);
+      } else {
+        assignTimestampNoNullsNoRepeatingNoSelection(index, batch.size, columnVector);
+      }
+    } else {
+      if (batch.selectedInUse) {
+        assignTimestampNullsNoRepeatingSelection (keyIndex, index, batch.size, columnVector, batch.selected);
+      } else {
+        assignTimestampNullsNoRepeatingNoSelection(keyIndex, index, batch.size, columnVector);
+      }
+    }
+  }
+
+  private void evaluateIntervalDayTimeColumnVector(VectorizedRowBatch batch, IntervalDayTimeColumnVector columnVector,
+      int keyIndex, int index) {
+    if (columnVector.isRepeating) {
+      if (columnVector.noNulls || !columnVector.isNull[0]) {
+        assignIntervalDayTimeNoNullsRepeating(index, batch.size, columnVector);
+      } else {
+        assignIntervalDayTimeNullsRepeating(keyIndex, index, batch.size, columnVector);
+      }
+    } else if (columnVector.noNulls) {
+      if (batch.selectedInUse) {
+        assignIntervalDayTimeNoNullsNoRepeatingSelection(index, batch.size, columnVector, batch.selected);
+      } else {
+        assignIntervalDayTimeNoNullsNoRepeatingNoSelection(index, batch.size, columnVector);
+      }
+    } else {
+      if (batch.selectedInUse) {
+        assignIntervalDayTimeNullsNoRepeatingSelection (keyIndex, index, batch.size, columnVector, batch.selected);
+      } else {
+        assignIntervalDayTimeNullsNoRepeatingNoSelection(keyIndex, index, batch.size, columnVector);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for string type, possible nulls, no repeat values, batch selection vector.
+   */
+  private void assignStringNullsNoRepeatingSelection(int keyIndex, int index, int size,
+      BytesColumnVector columnVector, int[] selected) {
+    for(int i=0; i<size; ++i) {
+      int row = selected[i];
+      if (columnVector.isNull[row]) {
+        vectorHashKeyWrappers[i].assignNullString(keyIndex, index);
+      } else {
+        vectorHashKeyWrappers[i].assignString(
+            index,
+            columnVector.vector[row],
+            columnVector.start[row],
+            columnVector.length[row]);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, possible nulls, repeat values.
+   */
+  private void assignStringNullsRepeating(int keyIndex, int index, int size, BytesColumnVector columnVector) {
+    if (columnVector.isNull[0]) {
+      for(int i = 0; i < size; ++i) {
+        vectorHashKeyWrappers[i].assignNullString(keyIndex, index);
+      }
+    } else {
+      for(int i = 0; i < size; ++i) {
+        vectorHashKeyWrappers[i].assignString(
+            index,
+            columnVector.vector[0],
+            columnVector.start[0],
+            columnVector.length[0]);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for string type, possible nulls, no repeat values, no selection vector.
+   */
+  private void assignStringNullsNoRepeatingNoSelection(int keyIndex, int index, int size,
+      BytesColumnVector columnVector) {
+    for(int i=0; i<size; ++i) {
+      if (columnVector.isNull[i]) {
+        vectorHashKeyWrappers[i].assignNullString(keyIndex, index);
+      } else {
+        vectorHashKeyWrappers[i].assignString(
+            index,
+            columnVector.vector[i],
+            columnVector.start[i],
+            columnVector.length[i]);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, repeat values, no selection vector.
+   */
+  private void assignStringNoNullsRepeating(int index, int size,
+      BytesColumnVector columnVector) {
+    for(int i = 0; i < size; ++i) {
+      vectorHashKeyWrappers[i].assignString(
+          index,
+          columnVector.vector[0],
+          columnVector.start[0],
+          columnVector.length[0]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, no repeat values, batch selection vector.
+   */
+  private void assignStringNoNullsNoRepeatingSelection(int index, int size,
+      BytesColumnVector columnVector, int[] selected) {
+    for(int i=0; i<size; ++i) {
+      int row = selected[i];
+      vectorHashKeyWrappers[i].assignString(
+          index,
+          columnVector.vector[row],
+          columnVector.start[row],
+          columnVector.length[row]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, no repeat values, no selection vector.
+   */
+  private void assignStringNoNullsNoRepeatingNoSelection(int index, int size,
+      BytesColumnVector columnVector) {
+    for(int i=0; i<size; ++i) {
+      vectorHashKeyWrappers[i].assignString(
+          index,
+          columnVector.vector[i],
+          columnVector.start[i],
+          columnVector.length[i]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, possible nulls, no repeat values, batch selection vector.
+   */
+  private void assignDoubleNullsNoRepeatingSelection(int keyIndex, int index, int size,
+      DoubleColumnVector columnVector, int[] selected) {
+    for(int i = 0; i < size; ++i) {
+      int row = selected[i];
+      if (!columnVector.isNull[row]) {
+        vectorHashKeyWrappers[i].assignDouble(index, columnVector.vector[row]);
+      } else {
+        vectorHashKeyWrappers[i].assignNullDouble(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Double type, repeat null values.
+   */
+  private void assignDoubleNullsRepeating(int keyIndex, int index, int size,
+      DoubleColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignNullDouble(keyIndex, index);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Double type, possible nulls, repeat values.
+   */
+  private void assignDoubleNullsNoRepeatingNoSelection(int keyIndex, int index, int size,
+      DoubleColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      if (!columnVector.isNull[r]) {
+        vectorHashKeyWrappers[r].assignDouble(index, columnVector.vector[r]);
+      } else {
+        vectorHashKeyWrappers[r].assignNullDouble(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, repeat values, no selection vector.
+   */
+  private void assignDoubleNoNullsRepeating(int index, int size, DoubleColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignDouble(index, columnVector.vector[0]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, no repeat values, batch selection vector.
+   */
+  private void assignDoubleNoNullsNoRepeatingSelection(int index, int size,
+      DoubleColumnVector columnVector, int[] selected) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignDouble(index, columnVector.vector[selected[r]]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, no repeat values, no selection vector.
+   */
+  private void assignDoubleNoNullsNoRepeatingNoSelection(int index, int size,
+      DoubleColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignDouble(index, columnVector.vector[r]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, possible nulls, no repeat values, batch selection vector.
+   */
+  private void assignLongNullsNoRepeatingSelection(int keyIndex, int index, int size,
+      LongColumnVector columnVector, int[] selected) {
+    for(int i = 0; i < size; ++i) {
+      int row = selected[i];
+      if (!columnVector.isNull[row]) {
+        vectorHashKeyWrappers[i].assignLong(index, columnVector.vector[row]);
+      } else {
+        vectorHashKeyWrappers[i].assignNullLong(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, repeating nulls.
+   */
+  private void assignLongNullsRepeating(int keyIndex, int index, int size,
+      LongColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignNullLong(keyIndex, index);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, possible nulls, no repeat values, no selection vector.
+   */
+  private void assignLongNullsNoRepeatingNoSelection(int keyIndex, int index, int size,
+      LongColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      if (!columnVector.isNull[r]) {
+        vectorHashKeyWrappers[r].assignLong(index, columnVector.vector[r]);
+      } else {
+        vectorHashKeyWrappers[r].assignNullLong(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, repeat values, no selection vector.
+   */
+  private void assignLongNoNullsRepeating(int index, int size, LongColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignLong(index, columnVector.vector[0]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, no repeat values, batch selection vector.
+   */
+  private void assignLongNoNullsNoRepeatingSelection(int index, int size,
+      LongColumnVector columnVector, int[] selected) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignLong(index, columnVector.vector[selected[r]]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for double type, no nulls, no repeat values, no selection vector.
+   */
+  private void assignLongNoNullsNoRepeatingNoSelection(int index, int size,
+      LongColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignLong(index, columnVector.vector[r]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Decimal type, possible nulls, no repeat values, batch selection vector.
+   */
+  private void assignDecimalNullsNoRepeatingSelection(int keyIndex, int index, int size,
+      DecimalColumnVector columnVector, int[] selected) {
+    for(int i = 0; i < size; ++i) {
+      int row = selected[i];
+      if (!columnVector.isNull[row]) {
+        vectorHashKeyWrappers[i].assignDecimal(index, columnVector.vector[row]);
+      } else {
+        vectorHashKeyWrappers[i].assignNullDecimal(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Decimal type, repeat null values.
+   */
+  private void assignDecimalNullsRepeating(int keyIndex, int index, int size,
+      DecimalColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignNullDecimal(keyIndex, index);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Decimal type, possible nulls, repeat values.
+   */
+  private void assignDecimalNullsNoRepeatingNoSelection(int keyIndex, int index, int size,
+      DecimalColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      if (!columnVector.isNull[r]) {
+        vectorHashKeyWrappers[r].assignDecimal(index, columnVector.vector[r]);
+      } else {
+        vectorHashKeyWrappers[r].assignNullDecimal(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Decimal type, no nulls, repeat values, no selection vector.
+   */
+  private void assignDecimalNoNullsRepeating(int index, int size, DecimalColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignDecimal(index, columnVector.vector[0]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Decimal type, no nulls, no repeat values, batch selection vector.
+   */
+  private void assignDecimalNoNullsNoRepeatingSelection(int index, int size,
+      DecimalColumnVector columnVector, int[] selected) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignDecimal(index, columnVector.vector[selected[r]]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Decimal type, no nulls, no repeat values, no selection vector.
+   */
+  private void assignDecimalNoNullsNoRepeatingNoSelection(int index, int size,
+      DecimalColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignDecimal(index, columnVector.vector[r]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Timestamp type, possible nulls, no repeat values, batch selection vector.
+   */
+  private void assignTimestampNullsNoRepeatingSelection(int keyIndex, int index, int size,
+      TimestampColumnVector columnVector, int[] selected) {
+    for(int i = 0; i < size; ++i) {
+      int row = selected[i];
+      if (!columnVector.isNull[row]) {
+        vectorHashKeyWrappers[i].assignTimestamp(index, columnVector, row);
+      } else {
+        vectorHashKeyWrappers[i].assignNullTimestamp(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Timestamp type, repeat null values.
+   */
+  private void assignTimestampNullsRepeating(int keyIndex, int index, int size,
+      TimestampColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignNullTimestamp(keyIndex, index);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Timestamp type, possible nulls, repeat values.
+   */
+  private void assignTimestampNullsNoRepeatingNoSelection(int keyIndex, int index, int size,
+      TimestampColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      if (!columnVector.isNull[r]) {
+        vectorHashKeyWrappers[r].assignTimestamp(index, columnVector, r);
+      } else {
+        vectorHashKeyWrappers[r].assignNullTimestamp(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Timestamp type, no nulls, repeat values, no selection vector.
+   */
+  private void assignTimestampNoNullsRepeating(int index, int size, TimestampColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignTimestamp(index, columnVector, 0);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Timestamp type, no nulls, no repeat values, batch selection vector.
+   */
+  private void assignTimestampNoNullsNoRepeatingSelection(int index, int size,
+      TimestampColumnVector columnVector, int[] selected) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignTimestamp(index, columnVector, selected[r]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for Timestamp type, no nulls, no repeat values, no selection vector.
+   */
+  private void assignTimestampNoNullsNoRepeatingNoSelection(int index, int size,
+      TimestampColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignTimestamp(index, columnVector, r);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for IntervalDayTime type, possible nulls, no repeat values, batch selection vector.
+   */
+  private void assignIntervalDayTimeNullsNoRepeatingSelection(int keyIndex, int index, int size,
+      IntervalDayTimeColumnVector columnVector, int[] selected) {
+    for(int i = 0; i < size; ++i) {
+      int row = selected[i];
+      if (!columnVector.isNull[row]) {
+        vectorHashKeyWrappers[i].assignIntervalDayTime(index, columnVector, row);
+      } else {
+        vectorHashKeyWrappers[i].assignNullIntervalDayTime(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for IntervalDayTime type, repeat null values.
+   */
+  private void assignIntervalDayTimeNullsRepeating(int keyIndex, int index, int size,
+      IntervalDayTimeColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignNullIntervalDayTime(keyIndex, index);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for IntervalDayTime type, possible nulls, repeat values.
+   */
+  private void assignIntervalDayTimeNullsNoRepeatingNoSelection(int keyIndex, int index, int size,
+      IntervalDayTimeColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      if (!columnVector.isNull[r]) {
+        vectorHashKeyWrappers[r].assignIntervalDayTime(index, columnVector, r);
+      } else {
+        vectorHashKeyWrappers[r].assignNullIntervalDayTime(keyIndex, index);
+      }
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for IntervalDayTime type, no nulls, repeat values, no selection vector.
+   */
+  private void assignIntervalDayTimeNoNullsRepeating(int index, int size, IntervalDayTimeColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignIntervalDayTime(index, columnVector, 0);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for IntervalDayTime type, no nulls, no repeat values, batch selection vector.
+   */
+  private void assignIntervalDayTimeNoNullsNoRepeatingSelection(int index, int size,
+      IntervalDayTimeColumnVector columnVector, int[] selected) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignIntervalDayTime(index, columnVector, selected[r]);
+    }
+  }
+
+  /**
+   * Helper method to assign values from a vector column into the key wrapper.
+   * Optimized for IntervalDayTime type, no nulls, no repeat values, no selection vector.
+   */
+  private void assignIntervalDayTimeNoNullsNoRepeatingNoSelection(int index, int size,
+      IntervalDayTimeColumnVector columnVector) {
+    for(int r = 0; r < size; ++r) {
+      vectorHashKeyWrappers[r].assignIntervalDayTime(index, columnVector, r);
+    }
+  }
+
+  public static VectorHashKeyWrapperBatch compileKeyWrapperBatch(VectorExpression[] keyExpressions)
+      throws HiveException
+  {
+
+    final int size = keyExpressions.length;
+    TypeInfo[] typeInfos = new TypeInfo[size];
+    for (int i = 0; i < size; i++) {
+      typeInfos[i] = keyExpressions[i].getOutputTypeInfo();
+    }
+    return compileKeyWrapperBatch(keyExpressions, typeInfos);
+  }
+
+  /**
+   * Prepares a VectorHashKeyWrapperBatch to work for a specific set of keys.
+   * Computes the fast access lookup indices, preallocates all needed internal arrays.
+   * This step is done only once per query, not once per batch. The information computed now
+   * will be used to generate proper individual VectorKeyHashWrapper objects.
+   */
+  public static VectorHashKeyWrapperBatch compileKeyWrapperBatch(VectorExpression[] keyExpressions,
+      TypeInfo[] typeInfos)
+    throws HiveException {
+    VectorHashKeyWrapperBatch compiledKeyWrapperBatch = new VectorHashKeyWrapperBatch(keyExpressions.length);
+    compiledKeyWrapperBatch.keyExpressions = keyExpressions;
+
+    compiledKeyWrapperBatch.keysFixedSize = 0;
+
+    // Inspect the output type of each key expression.
+    for(int i=0; i < typeInfos.length; ++i) {
+      compiledKeyWrapperBatch.addKey(typeInfos[i]);
+    }
+    compiledKeyWrapperBatch.finishAdding();
+
+    compiledKeyWrapperBatch.vectorHashKeyWrappers =
+        new VectorHashKeyWrapperBase[VectorizedRowBatch.DEFAULT_SIZE];
+    for(int i=0;i<VectorizedRowBatch.DEFAULT_SIZE; ++i) {
+      compiledKeyWrapperBatch.vectorHashKeyWrappers[i] =
+          compiledKeyWrapperBatch.allocateKeyWrapper();
+    }
+
+    JavaDataModel model = JavaDataModel.get();
+
+    // Compute the fixed size overhead for the keys
+    // start with the keywrapper itself
+    compiledKeyWrapperBatch.keysFixedSize += JavaDataModel.alignUp(
+        model.object() +
+        model.ref() * MODEL_REFERENCES_COUNT +
+        model.primitive1(),
+        model.memoryAlign());
+
+    // Now add the key wrapper arrays
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForLongArrayOfSize(compiledKeyWrapperBatch.longIndices.length);
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForDoubleArrayOfSize(compiledKeyWrapperBatch.doubleIndices.length);
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForObjectArrayOfSize(compiledKeyWrapperBatch.stringIndices.length);
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForObjectArrayOfSize(compiledKeyWrapperBatch.decimalIndices.length);
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForObjectArrayOfSize(compiledKeyWrapperBatch.timestampIndices.length);
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForObjectArrayOfSize(compiledKeyWrapperBatch.intervalDayTimeIndices.length);
+    compiledKeyWrapperBatch.keysFixedSize += model.lengthForIntArrayOfSize(compiledKeyWrapperBatch.longIndices.length) * 2;
+    compiledKeyWrapperBatch.keysFixedSize +=
+        model.lengthForBooleanArrayOfSize(keyExpressions.length);
+
+    return compiledKeyWrapperBatch;
+  }
+
+  public VectorHashKeyWrapperBase allocateKeyWrapper() {
+    return VectorHashKeyWrapperFactory.allocate(hashCtx,
+        longIndices.length,
+        doubleIndices.length,
+        stringIndices.length,
+        decimalIndices.length,
+        timestampIndices.length,
+        intervalDayTimeIndices.length,
+        keyCount);
+  }
+
+  /**
+   * Get the row-mode writable object value of a key from a key wrapper
+   * @param keyOutputWriter
+   */
+  public Object getWritableKeyValue(VectorHashKeyWrapperBase kw, int keyIndex,
+      VectorExpressionWriter keyOutputWriter)
+    throws HiveException {
+
+    if (kw.isNull(keyIndex)) {
+      return null;
+    }
+
+    ColumnVector.Type columnVectorType = columnVectorTypes[keyIndex];
+    int columnTypeSpecificIndex = columnTypeSpecificIndices[keyIndex];
+
+    switch (columnVectorType) {
+    case LONG:
+      return keyOutputWriter.writeValue(
+          kw.getLongValue(columnTypeSpecificIndex));
+    case DOUBLE:
+      return keyOutputWriter.writeValue(
+          kw.getDoubleValue(columnTypeSpecificIndex));
+    case BYTES:
+      return keyOutputWriter.writeValue(
+          kw.getBytes(columnTypeSpecificIndex),
+          kw.getByteStart(columnTypeSpecificIndex),
+          kw.getByteLength(columnTypeSpecificIndex));
+    case DECIMAL:
+      return keyOutputWriter.writeValue(
+          kw.getDecimal(columnTypeSpecificIndex));
+    case DECIMAL_64:
+      throw new RuntimeException("Getting writable for DECIMAL_64 not supported");
+    case TIMESTAMP:
+      return keyOutputWriter.writeValue(
+          kw.getTimestamp(columnTypeSpecificIndex));
+    case INTERVAL_DAY_TIME:
+      return keyOutputWriter.writeValue(
+          kw.getIntervalDayTime(columnTypeSpecificIndex));
+    default:
+      throw new HiveException("Unexpected column vector type " + columnVectorType);
+    }
+  }
+
+  public void setLongValue(VectorHashKeyWrapperBase kw, int keyIndex, Long value)
+    throws HiveException {
+
+    if (columnVectorTypes[keyIndex] != Type.LONG) {
+      throw new HiveException("Consistency error: expected LONG type; found: " + columnVectorTypes[keyIndex]);
+    }
+    int columnTypeSpecificIndex = columnTypeSpecificIndices[keyIndex];
+
+    if (value == null) {
+      kw.assignNullLong(keyIndex, columnTypeSpecificIndex);
+      return;
+    }
+    kw.assignLong(keyIndex, columnTypeSpecificIndex, value);
+  }
+
+  public void assignRowColumn(VectorizedRowBatch batch, int batchIndex, int keyIndex,
+      VectorHashKeyWrapperBase kw)
+    throws HiveException {
+
+    ColumnVector colVector = batch.cols[keyIndex];
+
+    if (kw.isNull(keyIndex)) {
+      colVector.noNulls = false;
+      colVector.isNull[batchIndex] = true;
+      return;
+    }
+    colVector.isNull[batchIndex] = false;
+
+    ColumnVector.Type columnVectorType = columnVectorTypes[keyIndex];
+    int columnTypeSpecificIndex = columnTypeSpecificIndices[keyIndex];
+
+    switch (columnVectorType) {
+    case LONG:
+    case DECIMAL_64:
+      ((LongColumnVector) colVector).vector[batchIndex] =
+          kw.getLongValue(columnTypeSpecificIndex);
+      break;
+    case DOUBLE:
+      ((DoubleColumnVector) colVector).vector[batchIndex] =
+          kw.getDoubleValue(columnTypeSpecificIndex);
+      break;
+    case BYTES:
+      ((BytesColumnVector) colVector).setVal(
+          batchIndex,
+          kw.getBytes(columnTypeSpecificIndex),
+          kw.getByteStart(columnTypeSpecificIndex),
+          kw.getByteLength(columnTypeSpecificIndex));
+      break;
+    case DECIMAL:
+      ((DecimalColumnVector) colVector).set(batchIndex,
+          kw.getDecimal(columnTypeSpecificIndex));
+      break;
+    case TIMESTAMP:
+      ((TimestampColumnVector) colVector).set(
+          batchIndex, kw.getTimestamp(columnTypeSpecificIndex));
+      break;
+    case INTERVAL_DAY_TIME:
+      ((IntervalDayTimeColumnVector) colVector).set(
+          batchIndex, kw.getIntervalDayTime(columnTypeSpecificIndex));
+      break;
+    default:
+      throw new HiveException("Unexpected column vector type " + columnVectorType);
+    }
+  }
+
+  public int getVariableSize(int batchSize) {
+    int variableSize = 0;
+    if ( 0 < stringIndices.length) {
+      for (int k=0; k<batchSize; ++k) {
+        VectorHashKeyWrapperBase hkw = vectorHashKeyWrappers[k];
+        variableSize += hkw.getVariableSize();
+      }
+    }
+    return variableSize;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperEmpty.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperEmpty.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperEmpty.java
new file mode 100644
index 0000000..63fc0da
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperEmpty.java
@@ -0,0 +1,81 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hadoop.hive.ql.exec.vector.VectorColumnSetInfo;
+import org.apache.hive.common.util.HashCodeUtil;
+
+// No need to override assigns - all assign ops will fail due to 0 key size.
+public final class VectorHashKeyWrapperEmpty extends VectorHashKeyWrapperBase {
+
+  public final static VectorHashKeyWrapperBase EMPTY_KEY_WRAPPER = new VectorHashKeyWrapperEmpty();
+
+  private static final int emptyHashcode =
+      HashCodeUtil.calculateLongHashCode(88L);
+
+  private VectorHashKeyWrapperEmpty() {
+    super();
+  }
+
+  @Override
+  public void setHashKey() {
+    hashcode = emptyHashcode;
+  }
+
+  @Override
+  protected Object clone() {
+    // immutable
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if (that == this) {
+      // should only be one object
+      return true;
+    }
+    return super.equals(that);
+  }
+
+  public String stringifyKeys(VectorColumnSetInfo columnSetInfo)
+  {
+    return "";
+  }
+
+  @Override
+  public String toString()
+  {
+    return "nulls []";
+  }
+
+  @Override
+  public int getVariableSize() {
+    return 0;
+  }
+
+  @Override
+  public void clearIsNull() {
+    // Nothing to do.
+  }
+
+  @Override
+  public void setNull() {
+    // Nothing to do.
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperFactory.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperFactory.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperFactory.java
new file mode 100644
index 0000000..5645c47
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hadoop.hive.ql.exec.vector.wrapper.VectorHashKeyWrapperBase.HashContext;
+
+public class VectorHashKeyWrapperFactory {
+
+  public static VectorHashKeyWrapperBase allocate(HashContext ctx, int longValuesCount,
+      int doubleValuesCount, int byteValuesCount, int decimalValuesCount, int timestampValuesCount,
+      int intervalDayTimeValuesCount, int keyCount) {
+
+    final int nonLongBytesCount =
+        doubleValuesCount + decimalValuesCount +
+        timestampValuesCount + intervalDayTimeValuesCount;
+
+    /*
+     * Add more special cases as desired.
+     * FUTURE: Consider writing a init time "classifier" that returns an enum so we don't have to
+     * FUTURE: analyze these counts over and over...
+     */
+    if (nonLongBytesCount == 0) {
+      if (byteValuesCount == 0) {
+        if (longValuesCount == 1) {
+          return new VectorHashKeyWrapperSingleLong();
+        } else if (longValuesCount == 2) {
+          return new VectorHashKeyWrapperTwoLong();
+        } else if (longValuesCount == 0) {
+          return VectorHashKeyWrapperEmpty.EMPTY_KEY_WRAPPER;
+        }
+      }
+    }
+
+    // Fall through to use the general wrapper.
+    return new VectorHashKeyWrapperGeneral(ctx, longValuesCount, doubleValuesCount, byteValuesCount,
+        decimalValuesCount, timestampValuesCount, intervalDayTimeValuesCount,
+        keyCount);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperGeneral.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperGeneral.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperGeneral.java
new file mode 100644
index 0000000..8fe53e7
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperGeneral.java
@@ -0,0 +1,649 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hadoop.hive.serde2.io.DateWritableV2;
+import org.apache.hive.common.util.Murmur3;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.util.Arrays;
+
+import org.apache.hadoop.hive.common.type.HiveDecimal;
+import org.apache.hadoop.hive.common.type.HiveIntervalDayTime;
+import org.apache.hadoop.hive.ql.exec.KeyWrapper;
+import org.apache.hadoop.hive.ql.exec.vector.IntervalDayTimeColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.TimestampColumnVector;
+import org.apache.hadoop.hive.ql.exec.vector.VectorColumnSetInfo;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.StringExpr;
+import org.apache.hadoop.hive.ql.metadata.HiveException;
+import org.apache.hadoop.hive.ql.util.JavaDataModel;
+import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+import org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A hash map key wrapper for vectorized processing.
+ * It stores the key values as primitives in arrays for each supported primitive type.
+ * This works in conjunction with
+ * {@link org.apache.hadoop.hive.ql.exec.VectorHashKeyWrapperBatch VectorHashKeyWrapperBatch}
+ * to hash vectorized processing units (batches).
+ */
+public class VectorHashKeyWrapperGeneral extends VectorHashKeyWrapperBase {
+
+  private static final int[] EMPTY_INT_ARRAY = new int[0];
+  private static final long[] EMPTY_LONG_ARRAY = new long[0];
+  private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+  private static final byte[][] EMPTY_BYTES_ARRAY = new byte[0][];
+  private static final HiveDecimalWritable[] EMPTY_DECIMAL_ARRAY = new HiveDecimalWritable[0];
+  private static final Timestamp[] EMPTY_TIMESTAMP_ARRAY = new Timestamp[0];
+  private static final HiveIntervalDayTime[] EMPTY_INTERVAL_DAY_TIME_ARRAY = new HiveIntervalDayTime[0];
+
+  private long[] longValues;
+  private double[] doubleValues;
+
+  private byte[][] byteValues;
+  private int[] byteStarts;
+  private int[] byteLengths;
+
+  private HiveDecimalWritable[] decimalValues;
+
+  private Timestamp[] timestampValues;
+  private static Timestamp ZERO_TIMESTAMP = new Timestamp(0);
+
+  private HiveIntervalDayTime[] intervalDayTimeValues;
+  private static HiveIntervalDayTime ZERO_INTERVALDAYTIME= new HiveIntervalDayTime(0, 0);
+
+  private HashContext hashCtx;
+
+  private int keyCount;
+
+  // NOTE: The null array is indexed by keyIndex, which is not available internally.  The mapping
+  //       from a long, double, etc index to key index is kept once in the separate
+  //       VectorColumnSetInfo object.
+  protected boolean[] isNull;
+
+  public VectorHashKeyWrapperGeneral(HashContext ctx, int longValuesCount, int doubleValuesCount,
+          int byteValuesCount, int decimalValuesCount, int timestampValuesCount,
+          int intervalDayTimeValuesCount,
+          int keyCount) {
+    super();
+    hashCtx = ctx;
+    this.keyCount = keyCount;
+    longValues = longValuesCount > 0 ? new long[longValuesCount] : EMPTY_LONG_ARRAY;
+    doubleValues = doubleValuesCount > 0 ? new double[doubleValuesCount] : EMPTY_DOUBLE_ARRAY;
+    decimalValues = decimalValuesCount > 0 ? new HiveDecimalWritable[decimalValuesCount] : EMPTY_DECIMAL_ARRAY;
+    timestampValues = timestampValuesCount > 0 ? new Timestamp[timestampValuesCount] : EMPTY_TIMESTAMP_ARRAY;
+    intervalDayTimeValues = intervalDayTimeValuesCount > 0 ? new HiveIntervalDayTime[intervalDayTimeValuesCount] : EMPTY_INTERVAL_DAY_TIME_ARRAY;
+    for(int i = 0; i < decimalValuesCount; ++i) {
+      decimalValues[i] = new HiveDecimalWritable(HiveDecimal.ZERO);
+    }
+    if (byteValuesCount > 0) {
+      byteValues = new byte[byteValuesCount][];
+      byteStarts = new int[byteValuesCount];
+      byteLengths = new int[byteValuesCount];
+    } else {
+      byteValues = EMPTY_BYTES_ARRAY;
+      byteStarts = EMPTY_INT_ARRAY;
+      byteLengths = EMPTY_INT_ARRAY;
+    }
+    for(int i = 0; i < timestampValuesCount; ++i) {
+      timestampValues[i] = new Timestamp(0);
+    }
+    for(int i = 0; i < intervalDayTimeValuesCount; ++i) {
+      intervalDayTimeValues[i] = new HiveIntervalDayTime();
+    }
+    isNull = new boolean[keyCount];
+  }
+
+  private VectorHashKeyWrapperGeneral() {
+    super();
+  }
+
+  @Override
+  public void setHashKey() {
+    // compute locally and assign
+    int hash = Arrays.hashCode(longValues) ^
+        Arrays.hashCode(doubleValues) ^
+        Arrays.hashCode(isNull);
+
+    for (int i = 0; i < decimalValues.length; i++) {
+      // Use the new faster hash code since we are hashing memory objects.
+      hash ^= decimalValues[i].newFasterHashCode();
+    }
+
+    for (int i = 0; i < timestampValues.length; i++) {
+      hash ^= timestampValues[i].hashCode();
+    }
+
+    for (int i = 0; i < intervalDayTimeValues.length; i++) {
+      hash ^= intervalDayTimeValues[i].hashCode();
+    }
+
+    // This code, with branches and all, is not executed if there are no string keys
+    Murmur3.IncrementalHash32 bytesHash = null;
+    for (int i = 0; i < byteValues.length; ++i) {
+      /*
+       *  Hashing the string is potentially expensive so is better to branch.
+       *  Additionally not looking at values for nulls allows us not reset the values.
+       */
+      if (byteLengths[i] == -1) {
+        continue;
+      }
+      if (bytesHash == null) {
+        bytesHash = HashContext.getBytesHash(hashCtx);
+        bytesHash.start(hash);
+      }
+      bytesHash.add(byteValues[i], byteStarts[i], byteLengths[i]);
+    }
+    if (bytesHash != null) {
+      hash = bytesHash.end();
+    }
+    this.hashcode = hash;
+  }
+
+  @Override
+  public int hashCode() {
+    return hashcode;
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if (that instanceof VectorHashKeyWrapperGeneral) {
+      VectorHashKeyWrapperGeneral keyThat = (VectorHashKeyWrapperGeneral)that;
+      // not comparing hashCtx - irrelevant
+      return hashcode == keyThat.hashcode &&
+          Arrays.equals(longValues, keyThat.longValues) &&
+          Arrays.equals(doubleValues, keyThat.doubleValues) &&
+          Arrays.equals(decimalValues,  keyThat.decimalValues) &&
+          Arrays.equals(timestampValues,  keyThat.timestampValues) &&
+          Arrays.equals(intervalDayTimeValues,  keyThat.intervalDayTimeValues) &&
+          Arrays.equals(isNull, keyThat.isNull) &&
+          byteValues.length == keyThat.byteValues.length &&
+          (0 == byteValues.length || bytesEquals(keyThat));
+    }
+    return false;
+  }
+
+  private boolean bytesEquals(VectorHashKeyWrapperGeneral keyThat) {
+    //By the time we enter here the byteValues.lentgh and isNull must have already been compared
+    for (int i = 0; i < byteValues.length; ++i) {
+      // the byte comparison is potentially expensive so is better to branch on null
+      if (byteLengths[i] != -1) {
+        if (!StringExpr.equal(
+            byteValues[i],
+            byteStarts[i],
+            byteLengths[i],
+            keyThat.byteValues[i],
+            keyThat.byteStarts[i],
+            keyThat.byteLengths[i])) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  @Override
+  protected Object clone() {
+    VectorHashKeyWrapperGeneral clone = new VectorHashKeyWrapperGeneral();
+    duplicateTo(clone);
+    return clone;
+  }
+
+  private void duplicateTo(VectorHashKeyWrapperGeneral clone) {
+    clone.hashCtx = hashCtx;
+    clone.keyCount = keyCount;
+    clone.longValues = (longValues.length > 0) ? longValues.clone() : EMPTY_LONG_ARRAY;
+    clone.doubleValues = (doubleValues.length > 0) ? doubleValues.clone() : EMPTY_DOUBLE_ARRAY;
+    clone.isNull = isNull.clone();
+
+    if (decimalValues.length > 0) {
+      // Decimal columns use HiveDecimalWritable.
+      clone.decimalValues = new HiveDecimalWritable[decimalValues.length];
+      for(int i = 0; i < decimalValues.length; ++i) {
+        clone.decimalValues[i] = new HiveDecimalWritable(decimalValues[i]);
+      }
+    } else {
+      clone.decimalValues = EMPTY_DECIMAL_ARRAY;
+    }
+
+    if (byteLengths.length > 0) {
+      clone.byteValues = new byte[byteValues.length][];
+      clone.byteStarts = new int[byteValues.length];
+      clone.byteLengths = byteLengths.clone();
+      for (int i = 0; i < byteValues.length; ++i) {
+        // avoid allocation/copy of nulls, because it potentially expensive.
+        // branch instead.
+        if (byteLengths[i] != -1) {
+          clone.byteValues[i] = Arrays.copyOfRange(byteValues[i],
+              byteStarts[i], byteStarts[i] + byteLengths[i]);
+        }
+      }
+    } else {
+      clone.byteValues = EMPTY_BYTES_ARRAY;
+      clone.byteStarts = EMPTY_INT_ARRAY;
+      clone.byteLengths = EMPTY_INT_ARRAY;
+    }
+    if (timestampValues.length > 0) {
+      clone.timestampValues = new Timestamp[timestampValues.length];
+      for(int i = 0; i < timestampValues.length; ++i) {
+        clone.timestampValues[i] = (Timestamp) timestampValues[i].clone();
+      }
+    } else {
+      clone.timestampValues = EMPTY_TIMESTAMP_ARRAY;
+    }
+    if (intervalDayTimeValues.length > 0) {
+      clone.intervalDayTimeValues = new HiveIntervalDayTime[intervalDayTimeValues.length];
+      for(int i = 0; i < intervalDayTimeValues.length; ++i) {
+        clone.intervalDayTimeValues[i] = (HiveIntervalDayTime) intervalDayTimeValues[i].clone();
+      }
+    } else {
+      clone.intervalDayTimeValues = EMPTY_INTERVAL_DAY_TIME_ARRAY;
+    }
+
+    clone.hashcode = hashcode;
+    assert clone.equals(this);
+  }
+
+  @Override
+  public void assignLong(int keyIndex, int index, long v) {
+    isNull[keyIndex] = false;
+    longValues[index] = v;
+  }
+
+  // FIXME: isNull is not updated; which might cause problems
+  @Deprecated
+  @Override
+  public void assignLong(int index, long v) {
+    longValues[index] = v;
+  }
+
+  @Override
+  public void assignNullLong(int keyIndex, int index) {
+    isNull[keyIndex] = true;
+    longValues[index] = 0; // assign 0 to simplify hashcode
+  }
+
+  @Override
+  public void assignDouble(int index, double d) {
+    doubleValues[index] = d;
+  }
+
+  @Override
+  public void assignNullDouble(int keyIndex, int index) {
+    isNull[keyIndex] = true;
+    doubleValues[index] = 0; // assign 0 to simplify hashcode
+  }
+
+  @Override
+  public void assignString(int index, byte[] bytes, int start, int length) {
+    Preconditions.checkState(bytes != null);
+    byteValues[index] = bytes;
+    byteStarts[index] = start;
+    byteLengths[index] = length;
+  }
+
+  @Override
+  public void assignNullString(int keyIndex, int index) {
+    isNull[keyIndex] = true;
+    byteValues[index] = null;
+    byteStarts[index] = 0;
+    // We need some value that indicates NULL.
+    byteLengths[index] = -1;
+  }
+
+  @Override
+  public void assignDecimal(int index, HiveDecimalWritable value) {
+    decimalValues[index].set(value);
+  }
+
+  @Override
+  public void assignNullDecimal(int keyIndex, int index) {
+    isNull[keyIndex] = true;
+    decimalValues[index].set(HiveDecimal.ZERO); // assign 0 to simplify hashcode
+  }
+
+  @Override
+  public void assignTimestamp(int index, Timestamp value) {
+    // Do not assign the input value object to the timestampValues array element.
+    // Always copy value using set* methods.
+    timestampValues[index].setTime(value.getTime());
+    timestampValues[index].setNanos(value.getNanos());
+  }
+
+  @Override
+  public void assignTimestamp(int index, TimestampColumnVector colVector, int elementNum) {
+    colVector.timestampUpdate(timestampValues[index], elementNum);
+  }
+
+  @Override
+  public void assignNullTimestamp(int keyIndex, int index) {
+    isNull[keyIndex] = true;
+    // assign 0 to simplify hashcode
+    timestampValues[index].setTime(ZERO_TIMESTAMP.getTime());
+    timestampValues[index].setNanos(ZERO_TIMESTAMP.getNanos());
+  }
+
+  @Override
+  public void assignIntervalDayTime(int index, HiveIntervalDayTime value) {
+    intervalDayTimeValues[index].set(value);
+  }
+
+  @Override
+  public void assignIntervalDayTime(int index, IntervalDayTimeColumnVector colVector, int elementNum) {
+    intervalDayTimeValues[index].set(colVector.asScratchIntervalDayTime(elementNum));
+  }
+
+  @Override
+  public void assignNullIntervalDayTime(int keyIndex, int index) {
+    isNull[keyIndex] = true;
+    intervalDayTimeValues[index].set(ZERO_INTERVALDAYTIME); // assign 0 to simplify hashcode
+  }
+
+  /*
+   * This method is mainly intended for debug display purposes.
+   */
+  @Override
+  public String stringifyKeys(VectorColumnSetInfo columnSetInfo)
+  {
+    StringBuilder sb = new StringBuilder();
+    boolean isFirstKey = true;
+
+    if (longValues.length > 0) {
+      isFirstKey = false;
+      sb.append("longs ");
+      boolean isFirstValue = true;
+      for (int i = 0; i < columnSetInfo.longIndices.length; i++) {
+        if (isFirstValue) {
+          isFirstValue = false;
+        } else {
+          sb.append(", ");
+        }
+        int keyIndex = columnSetInfo.longIndices[i];
+        if (isNull[keyIndex]) {
+          sb.append("null");
+        } else {
+          sb.append(longValues[i]);
+          PrimitiveTypeInfo primitiveTypeInfo = (PrimitiveTypeInfo) columnSetInfo.typeInfos[keyIndex];
+          // FUTURE: Add INTERVAL_YEAR_MONTH, etc, as desired.
+          switch (primitiveTypeInfo.getPrimitiveCategory()) {
+          case DATE:
+            {
+              Date dt = new Date(0);
+              dt.setTime(DateWritableV2.daysToMillis((int) longValues[i]));
+              sb.append(" date ");
+              sb.append(dt.toString());
+            }
+            break;
+          default:
+            // Add nothing more.
+            break;
+          }
+        }
+      }
+    }
+    if (doubleValues.length > 0) {
+      if (isFirstKey) {
+        isFirstKey = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("doubles ");
+      boolean isFirstValue = true;
+      for (int i = 0; i < columnSetInfo.doubleIndices.length; i++) {
+        if (isFirstValue) {
+          isFirstValue = false;
+        } else {
+          sb.append(", ");
+        }
+        int keyIndex = columnSetInfo.doubleIndices[i];
+        if (isNull[keyIndex]) {
+          sb.append("null");
+        } else {
+          sb.append(doubleValues[i]);
+        }
+      }
+    }
+    if (byteValues.length > 0) {
+      if (isFirstKey) {
+        isFirstKey = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("byte lengths ");
+      boolean isFirstValue = true;
+      for (int i = 0; i < columnSetInfo.stringIndices.length; i++) {
+        if (isFirstValue) {
+          isFirstValue = false;
+        } else {
+          sb.append(", ");
+        }
+        int keyIndex = columnSetInfo.stringIndices[i];
+        if (isNull[keyIndex]) {
+          sb.append("null");
+        } else {
+          sb.append(byteLengths[i]);
+        }
+      }
+    }
+    if (decimalValues.length > 0) {
+      if (isFirstKey) {
+        isFirstKey = true;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("decimals ");
+      boolean isFirstValue = true;
+      for (int i = 0; i < columnSetInfo.decimalIndices.length; i++) {
+        if (isFirstValue) {
+          isFirstValue = false;
+        } else {
+          sb.append(", ");
+        }
+        int keyIndex = columnSetInfo.decimalIndices[i];
+        if (isNull[keyIndex]) {
+          sb.append("null");
+        } else {
+          sb.append(decimalValues[i]);
+        }
+      }
+    }
+    if (timestampValues.length > 0) {
+      if (isFirstKey) {
+        isFirstKey = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("timestamps ");
+      boolean isFirstValue = true;
+      for (int i = 0; i < columnSetInfo.timestampIndices.length; i++) {
+        if (isFirstValue) {
+          isFirstValue = false;
+        } else {
+          sb.append(", ");
+        }
+        int keyIndex = columnSetInfo.timestampIndices[i];
+        if (isNull[keyIndex]) {
+          sb.append("null");
+        } else {
+          sb.append(timestampValues[i]);
+        }
+      }
+    }
+    if (intervalDayTimeValues.length > 0) {
+      if (isFirstKey) {
+        isFirstKey = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("interval day times ");
+      boolean isFirstValue = true;
+      for (int i = 0; i < columnSetInfo.intervalDayTimeIndices.length; i++) {
+        if (isFirstValue) {
+          isFirstValue = false;
+        } else {
+          sb.append(", ");
+        }
+        int keyIndex = columnSetInfo.intervalDayTimeIndices[i];
+        if (isNull[keyIndex]) {
+          sb.append("null");
+        } else {
+          sb.append(intervalDayTimeValues[i]);
+        }
+      }
+    }
+
+    return sb.toString();
+  }
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder();
+    boolean isFirst = true;
+    if (longValues.length > 0) {
+      isFirst = false;
+      sb.append("longs ");
+      sb.append(Arrays.toString(longValues));
+    }
+    if (doubleValues.length > 0) {
+      if (isFirst) {
+        isFirst = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("doubles ");
+      sb.append(Arrays.toString(doubleValues));
+    }
+    if (byteValues.length > 0) {
+      if (isFirst) {
+        isFirst = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("byte lengths ");
+      sb.append(Arrays.toString(byteLengths));
+    }
+    if (decimalValues.length > 0) {
+      if (isFirst) {
+        isFirst = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("decimals ");
+      sb.append(Arrays.toString(decimalValues));
+    }
+    if (timestampValues.length > 0) {
+      if (isFirst) {
+        isFirst = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("timestamps ");
+      sb.append(Arrays.toString(timestampValues));
+    }
+    if (intervalDayTimeValues.length > 0) {
+      if (isFirst) {
+        isFirst = false;
+      } else {
+        sb.append(", ");
+      }
+      sb.append("interval day times ");
+      sb.append(Arrays.toString(intervalDayTimeValues));
+    }
+
+    if (isFirst) {
+      isFirst = false;
+    } else {
+      sb.append(", ");
+    }
+    sb.append("nulls ");
+    sb.append(Arrays.toString(isNull));
+
+    return sb.toString();
+  }
+
+  @Override
+  public long getLongValue(int i) {
+    return longValues[i];
+  }
+
+  @Override
+  public double getDoubleValue(int i) {
+    return doubleValues[i];
+  }
+
+  @Override
+  public byte[] getBytes(int i) {
+    return byteValues[i];
+  }
+
+  @Override
+  public int getByteStart(int i) {
+    return byteStarts[i];
+  }
+
+  @Override
+  public int getByteLength(int i) {
+    return byteLengths[i];
+  }
+
+  @Override
+  public HiveDecimalWritable getDecimal(int i) {
+    return decimalValues[i];
+  }
+
+  @Override
+  public Timestamp getTimestamp(int i) {
+    return timestampValues[i];
+  }
+
+  @Override
+  public HiveIntervalDayTime getIntervalDayTime(int i) {
+    return intervalDayTimeValues[i];
+  }
+
+  @Override
+  public int getVariableSize() {
+    int variableSize = 0;
+    for (int i=0; i<byteLengths.length; ++i) {
+      JavaDataModel model = JavaDataModel.get();
+      variableSize += model.lengthForByteArrayOfSize(byteLengths[i]);
+    }
+    return variableSize;
+  }
+
+  @Override
+  public void clearIsNull() {
+    Arrays.fill(isNull, false);
+  }
+
+  @Override
+  public void setNull() {
+    Arrays.fill(isNull, true);
+  }
+
+  @Override
+  public boolean isNull(int keyIndex) {
+    return isNull[keyIndex];
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleBase.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleBase.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleBase.java
new file mode 100644
index 0000000..b34ac6b
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleBase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hive.common.util.HashCodeUtil;
+
+public abstract class VectorHashKeyWrapperSingleBase extends VectorHashKeyWrapperBase {
+
+  protected boolean isNull0;
+
+  protected static final int nullHashcode =
+      HashCodeUtil.calculateLongHashCode(238322L);
+
+  protected VectorHashKeyWrapperSingleBase() {
+    super();
+    isNull0 = false;
+  }
+
+  @Override
+  public void clearIsNull() {
+    isNull0 = false;
+  }
+
+  @Override
+  public void setNull() {
+    isNull0 = true;
+  }
+
+  @Override
+  public boolean isNull(int keyIndex) {
+    if (keyIndex == 0) {
+      return isNull0;
+    } else {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleLong.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleLong.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleLong.java
new file mode 100644
index 0000000..7229836
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperSingleLong.java
@@ -0,0 +1,131 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hadoop.hive.ql.exec.vector.VectorColumnSetInfo;
+import org.apache.hive.common.util.HashCodeUtil;
+
+public class VectorHashKeyWrapperSingleLong extends VectorHashKeyWrapperSingleBase {
+
+  private long longValue0;
+
+  protected VectorHashKeyWrapperSingleLong() {
+    super();
+    longValue0 = 0;
+  }
+
+  @Override
+  public void setHashKey() {
+    hashcode =
+        isNull0 ?
+            nullHashcode :
+            HashCodeUtil.calculateLongHashCode(longValue0);
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if (that instanceof VectorHashKeyWrapperSingleLong) {
+      VectorHashKeyWrapperSingleLong keyThat = (VectorHashKeyWrapperSingleLong) that;
+      return
+          isNull0 == keyThat.isNull0 &&
+          longValue0 == keyThat.longValue0;
+    }
+    return false;
+  }
+
+  @Override
+  protected Object clone() {
+    VectorHashKeyWrapperSingleLong clone = new VectorHashKeyWrapperSingleLong();
+    clone.isNull0 = isNull0;
+    clone.longValue0 = longValue0;
+    clone.hashcode = hashcode;
+    return clone;
+  }
+
+  public void assignLong(int keyIndex, int index, long v) {
+    if (keyIndex == 0 && index == 0) {
+      isNull0 = false;
+      longValue0 = v;
+    } else {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+  }
+
+  // FIXME: isNull is not updated; which might cause problems
+  @Deprecated
+  public void assignLong(int index, long v) {
+    if (index == 0) {
+      longValue0 = v;
+    } else {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+  }
+
+  public void assignNullLong(int keyIndex, int index) {
+    if (keyIndex == 0 && index == 0) {
+      isNull0 = true;
+      longValue0 = 0;
+    } else {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+  }
+
+  /*
+   * This method is mainly intended for debug display purposes.
+   */
+  @Override
+  public String stringifyKeys(VectorColumnSetInfo columnSetInfo)
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append("longs [");
+    if (!isNull0) {
+      sb.append(longValue0);
+    } else {
+      sb.append("null");
+    }
+    sb.append("]");
+    return sb.toString();
+  }
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append("longs [");
+    sb.append(longValue0);
+    sb.append("], nulls [");
+    sb.append(isNull0);
+    sb.append("]");
+    return sb.toString();
+  }
+
+  @Override
+  public long getLongValue(int i) {
+    if (i == 0) {
+      return longValue0;
+    } else {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+  }
+
+  @Override
+  public int getVariableSize() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/ccdcc5e2/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperTwoBase.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperTwoBase.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperTwoBase.java
new file mode 100644
index 0000000..292b9a8
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/wrapper/VectorHashKeyWrapperTwoBase.java
@@ -0,0 +1,63 @@
+/*
+ * 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.hadoop.hive.ql.exec.vector.wrapper;
+
+import org.apache.hive.common.util.HashCodeUtil;
+
+public abstract class VectorHashKeyWrapperTwoBase extends VectorHashKeyWrapperBase {
+
+  protected boolean isNull0;
+  protected boolean isNull1;
+
+  protected static final int null0Hashcode =
+      HashCodeUtil.calculateLongHashCode(8893L);
+  protected static final int null1Hashcode =
+      HashCodeUtil.calculateLongHashCode(255533L);
+  protected static final int twoNullHashcode =
+      HashCodeUtil.calculateLongHashCode(7566L);
+
+  protected VectorHashKeyWrapperTwoBase() {
+    super();
+    isNull0 = false;
+    isNull1 = false;
+  }
+
+  @Override
+  public void clearIsNull() {
+    isNull0 = false;
+    isNull1 = false;
+  }
+
+  @Override
+  public void setNull() {
+    isNull0 = true;
+    isNull1 = true;
+  }
+
+  @Override
+  public boolean isNull(int keyIndex) {
+    if (keyIndex == 0) {
+      return isNull0;
+    } else if (keyIndex == 1) {
+      return isNull1;
+    } else {
+      throw new ArrayIndexOutOfBoundsException();
+    }
+  }
+}