You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by am...@apache.org on 2018/01/24 18:35:22 UTC

[08/11] drill git commit: DRILL-6049: Misc. hygiene and code cleanup changes

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/FixedValueVectors.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/FixedValueVectors.java b/exec/vector/src/main/codegen/templates/FixedValueVectors.java
index 1f6a008..79beb52 100644
--- a/exec/vector/src/main/codegen/templates/FixedValueVectors.java
+++ b/exec/vector/src/main/codegen/templates/FixedValueVectors.java
@@ -106,7 +106,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
   }
 
   @Override
-  public int getValueCapacity(){
+  public int getValueCapacity() {
     return data.capacity() / VALUE_WIDTH;
   }
 
@@ -129,7 +129,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
 
   @Override
   public void allocateNew() {
-    if (!allocateNewSafe()){
+    if (!allocateNewSafe()) {
       throw new OutOfMemoryException("Failure while allocating buffer.");
     }
   }
@@ -264,12 +264,12 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
   }
 
   @Override
-  public TransferPair getTransferPair(BufferAllocator allocator){
+  public TransferPair getTransferPair(BufferAllocator allocator) {
     return new TransferImpl(getField(), allocator);
   }
 
   @Override
-  public TransferPair getTransferPair(String ref, BufferAllocator allocator){
+  public TransferPair getTransferPair(String ref, BufferAllocator allocator) {
     return new TransferImpl(getField().withPath(ref), allocator);
   }
 
@@ -278,7 +278,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     return new TransferImpl((${minor.class}Vector) to);
   }
 
-  public void transferTo(${minor.class}Vector target){
+  public void transferTo(${minor.class}Vector target) {
     target.clear();
     target.data = data.transferOwnership(target.allocator).buffer;
     target.data.writerIndex(data.writerIndex());
@@ -298,10 +298,10 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     return valueCount * ${type.width};
   }
 
-  private class TransferImpl implements TransferPair{
+  private class TransferImpl implements TransferPair {
     private ${minor.class}Vector to;
 
-    public TransferImpl(MaterializedField field, BufferAllocator allocator){
+    public TransferImpl(MaterializedField field, BufferAllocator allocator) {
       to = new ${minor.class}Vector(field, allocator);
     }
 
@@ -310,12 +310,12 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     }
 
     @Override
-    public ${minor.class}Vector getTo(){
+    public ${minor.class}Vector getTo() {
       return to;
     }
 
     @Override
-    public void transfer(){
+    public void transfer() {
       transferTo(to);
     }
 
@@ -330,7 +330,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     }
   }
 
-  public void copyFrom(int fromIndex, int thisIndex, ${minor.class}Vector from){
+  public void copyFrom(int fromIndex, int thisIndex, ${minor.class}Vector from) {
     <#if (type.width > 8)>
     from.data.getBytes(fromIndex * VALUE_WIDTH, data, thisIndex * VALUE_WIDTH, VALUE_WIDTH);
     <#else> <#-- type.width <= 8 -->
@@ -340,7 +340,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     </#if> <#-- type.width -->
   }
 
-  public void copyFromSafe(int fromIndex, int thisIndex, ${minor.class}Vector from){
+  public void copyFromSafe(int fromIndex, int thisIndex, ${minor.class}Vector from) {
     while(thisIndex >= getValueCapacity()) {
         reAlloc();
     }
@@ -376,24 +376,24 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     }
 
     @Override
-    public boolean isNull(int index){
+    public boolean isNull(int index) {
       return false;
     }
-
     <#if (type.width > 8)>
+    
     public ${minor.javaType!type.javaType} get(int index) {
       return data.slice(index * VALUE_WIDTH, VALUE_WIDTH);
     }
-
     <#if (minor.class == "Interval")>
-    public void get(int index, ${minor.class}Holder holder){
+    
+    public void get(int index, ${minor.class}Holder holder) {
       final int offsetIndex = index * VALUE_WIDTH;
       holder.months = data.getInt(offsetIndex);
       holder.days = data.getInt(offsetIndex + ${minor.daysOffset});
       holder.milliseconds = data.getInt(offsetIndex + ${minor.millisecondsOffset});
     }
 
-    public void get(int index, Nullable${minor.class}Holder holder){
+    public void get(int index, Nullable${minor.class}Holder holder) {
       final int offsetIndex = index * VALUE_WIDTH;
       holder.isSet = 1;
       holder.months = data.getInt(offsetIndex);
@@ -407,52 +407,25 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       final int months  = data.getInt(offsetIndex);
       final int days    = data.getInt(offsetIndex + ${minor.daysOffset});
       final int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
-      final Period p = new Period();
-      return p.plusMonths(months).plusDays(days).plusMillis(millis);
+      return DateUtilities.fromInterval(months, days, millis);
     }
 
     public StringBuilder getAsStringBuilder(int index) {
-
       final int offsetIndex = index * VALUE_WIDTH;
-
-      int months  = data.getInt(offsetIndex);
-      final int days    = data.getInt(offsetIndex + ${minor.daysOffset});
-      int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
-
-      final int years  = (months / org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
-      months = (months % org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
-
-      final int hours  = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
-      millis     = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
-
-      final int minutes = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
-      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
-
-      final long seconds = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
-      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
-
-      final String yearString = (Math.abs(years) == 1) ? " year " : " years ";
-      final String monthString = (Math.abs(months) == 1) ? " month " : " months ";
-      final String dayString = (Math.abs(days) == 1) ? " day " : " days ";
-
-      return(new StringBuilder().
-             append(years).append(yearString).
-             append(months).append(monthString).
-             append(days).append(dayString).
-             append(hours).append(":").
-             append(minutes).append(":").
-             append(seconds).append(".").
-             append(millis));
+      final int months = data.getInt(offsetIndex);
+      final int days   = data.getInt(offsetIndex + ${minor.daysOffset});
+      final int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});      
+      return DateUtilities.intervalStringBuilder(months, days, millis);
     }
-
     <#elseif (minor.class == "IntervalDay")>
-    public void get(int index, ${minor.class}Holder holder){
+    
+    public void get(int index, ${minor.class}Holder holder) {
       final int offsetIndex = index * VALUE_WIDTH;
       holder.days = data.getInt(offsetIndex);
       holder.milliseconds = data.getInt(offsetIndex + ${minor.millisecondsOffset});
     }
 
-    public void get(int index, Nullable${minor.class}Holder holder){
+    public void get(int index, Nullable${minor.class}Holder holder) {
       final int offsetIndex = index * VALUE_WIDTH;
       holder.isSet = 1;
       holder.days = data.getInt(offsetIndex);
@@ -462,38 +435,19 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     @Override
     public ${friendlyType} getObject(int index) {
       final int offsetIndex = index * VALUE_WIDTH;
+      final int days   = data.getInt(offsetIndex);
       final int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
-      final int  days   = data.getInt(offsetIndex);
-      final Period p = new Period();
-      return p.plusDays(days).plusMillis(millis);
+      return DateUtilities.fromIntervalDay(days, millis);
     }
 
     public StringBuilder getAsStringBuilder(int index) {
       final int offsetIndex = index * VALUE_WIDTH;
-
-      int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
-      final int  days   = data.getInt(offsetIndex);
-
-      final int hours  = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
-      millis     = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
-
-      final int minutes = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
-      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
-
-      final int seconds = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
-      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
-
-      final String dayString = (Math.abs(days) == 1) ? " day " : " days ";
-
-      return(new StringBuilder().
-              append(days).append(dayString).
-              append(hours).append(":").
-              append(minutes).append(":").
-              append(seconds).append(".").
-              append(millis));
+      final int days   = data.getInt(offsetIndex);
+      final int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});     
+      return DateUtilities.intervalDayStringBuilder(days, millis);
     }
-
     <#elseif minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse" || minor.class == "Decimal28Dense" || minor.class == "Decimal38Dense">
+
     public void get(int index, ${minor.class}Holder holder) {
       holder.start = index * VALUE_WIDTH;
       holder.buffer = data;
@@ -515,17 +469,19 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       // Get the BigDecimal object
       return DecimalUtility.getBigDecimalFromSparse(data, index * VALUE_WIDTH, ${minor.nDecimalDigits}, getField().getScale());
       <#else>
-      return DecimalUtility.getBigDecimalFromDense(data, index * VALUE_WIDTH, ${minor.nDecimalDigits}, getField().getScale(), ${minor.maxPrecisionDigits}, VALUE_WIDTH);
+      return DecimalUtility.getBigDecimalFromDense(data, index * VALUE_WIDTH,
+          ${minor.nDecimalDigits}, getField().getScale(),
+          ${minor.maxPrecisionDigits}, VALUE_WIDTH);
       </#if>
     }
-
     <#else>
-    public void get(int index, ${minor.class}Holder holder){
+
+    public void get(int index, ${minor.class}Holder holder) {
       holder.buffer = data;
       holder.start = index * VALUE_WIDTH;
     }
 
-    public void get(int index, Nullable${minor.class}Holder holder){
+    public void get(int index, Nullable${minor.class}Holder holder) {
       holder.isSet = 1;
       holder.buffer = data;
       holder.start = index * VALUE_WIDTH;
@@ -535,76 +491,61 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     public ${friendlyType} getObject(int index) {
       return data.slice(index * VALUE_WIDTH, VALUE_WIDTH)
     }
-
     </#if>
     <#else> <#-- type.width <= 8 -->
+    
     public ${minor.javaType!type.javaType} get(int index) {
       return data.get${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH);
     }
-
     <#if type.width == 4>
+    
     public long getTwoAsLong(int index) {
       return data.getLong(index * VALUE_WIDTH);
     }
-
     </#if>
     <#if minor.class == "Date">
+
     @Override
     public ${friendlyType} getObject(int index) {
       org.joda.time.DateTime date = new org.joda.time.DateTime(get(index), org.joda.time.DateTimeZone.UTC);
       date = date.withZoneRetainFields(org.joda.time.DateTimeZone.getDefault());
       return date;
     }
-
     <#elseif minor.class == "TimeStamp">
+
     @Override
     public ${friendlyType} getObject(int index) {
       org.joda.time.DateTime date = new org.joda.time.DateTime(get(index), org.joda.time.DateTimeZone.UTC);
       date = date.withZoneRetainFields(org.joda.time.DateTimeZone.getDefault());
       return date;
     }
-
     <#elseif minor.class == "IntervalYear">
+
     @Override
     public ${friendlyType} getObject(int index) {
-      final int value = get(index);
-      final int years  = (value / org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
-      final int months = (value % org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
-      final Period p = new Period();
-      return p.plusYears(years).plusMonths(months);
+      return DateUtilities.fromIntervalYear(get(index));
     }
 
     public StringBuilder getAsStringBuilder(int index) {
-
-      int months  = data.getInt(index);
-
-      final int years  = (months / org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
-      months = (months % org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
-
-      final String yearString = (Math.abs(years) == 1) ? " year " : " years ";
-      final String monthString = (Math.abs(months) == 1) ? " month " : " months ";
-
-      return(new StringBuilder().
-             append(years).append(yearString).
-             append(months).append(monthString));
+      return DateUtilities.intervalYearStringBuilder(data.getInt(index));
     }
-
     <#elseif minor.class == "Time">
+
     @Override
     public DateTime getObject(int index) {
       org.joda.time.DateTime time = new org.joda.time.DateTime(get(index), org.joda.time.DateTimeZone.UTC);
       time = time.withZoneRetainFields(org.joda.time.DateTimeZone.getDefault());
       return time;
     }
-
     <#elseif minor.class == "Decimal9" || minor.class == "Decimal18">
+
     @Override
     public ${friendlyType} getObject(int index) {
       final BigInteger value = BigInteger.valueOf(((${type.boxedType})get(index)).${type.javaType}Value());
       return new BigDecimal(value, getField().getScale());
     }
-
     <#else>
+
     @Override
     public ${friendlyType} getObject(int index) {
       return get(index);
@@ -613,9 +554,9 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     public ${minor.javaType!type.javaType} getPrimitiveObject(int index) {
       return get(index);
     }
-
     </#if>
-    public void get(int index, ${minor.class}Holder holder){
+
+    public void get(int index, ${minor.class}Holder holder) {
       <#if minor.class.startsWith("Decimal")>
       holder.scale = getField().getScale();
       holder.precision = getField().getPrecision();
@@ -624,7 +565,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       holder.value = data.get${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH);
     }
 
-    public void get(int index, Nullable${minor.class}Holder holder){
+    public void get(int index, Nullable${minor.class}Holder holder) {
       holder.isSet = 1;
       holder.value = data.get${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH);
     }
@@ -658,8 +599,8 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
      * @param value
      *          value to set
      */
-
   <#if (type.width > 8)>
+  
     public void set(int index, <#if (type.width > 4)>${minor.javaType!type.javaType}<#else>int</#if> value) {
       data.setBytes(index * VALUE_WIDTH, value, 0, VALUE_WIDTH);
     }
@@ -670,8 +611,8 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       }
       data.setBytes(index * VALUE_WIDTH, value, 0, VALUE_WIDTH);
     }
-
     <#if minor.class == "Interval">
+    
     public void set(int index, int months, int days, int milliseconds) {
       final int offsetIndex = index * VALUE_WIDTH;
       data.setInt(offsetIndex, months);
@@ -701,8 +642,8 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     public void setSafe(int index, Nullable${minor.class}Holder holder) {
       setSafe(index, holder.months, holder.days, holder.milliseconds);
     }
-
     <#elseif minor.class == "IntervalDay">
+    
     public void set(int index, int days, int milliseconds) {
       final int offsetIndex = index * VALUE_WIDTH;
       data.setInt(offsetIndex, days);
@@ -728,11 +669,11 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       set(index, holder.days, holder.milliseconds);
     }
 
-    public void setSafe(int index, Nullable${minor.class}Holder holder){
+    public void setSafe(int index, Nullable${minor.class}Holder holder) {
       setSafe(index, holder.days, holder.milliseconds);
     }
-
     <#elseif minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse" || minor.class == "Decimal28Dense" || minor.class == "Decimal38Dense">
+    
     public void setSafe(int index, int start, DrillBuf buffer) {
       while(index >= getValueCapacity()) {
         reAlloc();
@@ -755,8 +696,8 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
     public void setSafe(int index, Nullable${minor.class}Holder holder) {
       setSafe(index, holder.start, holder.buffer);
     }
-
       <#if minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse">
+      
     public void set(int index, BigDecimal value) {
       DecimalUtility.getSparseFromBigDecimal(value, data, index * VALUE_WIDTH,
            field.getScale(), field.getPrecision(), ${minor.nDecimalDigits});
@@ -768,13 +709,13 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       }
       set(index, value);
     }
-
       </#if>
-    public void set(int index, int start, DrillBuf buffer){
+      
+    public void set(int index, int start, DrillBuf buffer) {
       data.setBytes(index * VALUE_WIDTH, buffer, start, VALUE_WIDTH);
     }
-
     </#if>
+    
     @Override
     public void generateTestData(int count) {
       setValueCount(count);
@@ -782,13 +723,13 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
       final int valueCount = getAccessor().getValueCount();
       for(int i = 0; i < valueCount; i++, even = !even) {
         final byte b = even ? Byte.MIN_VALUE : Byte.MAX_VALUE;
-        for(int w = 0; w < VALUE_WIDTH; w++){
+        for(int w = 0; w < VALUE_WIDTH; w++) {
           data.setByte(i + w, b);
         }
       }
     }
-
   <#else> <#-- type.width <= 8 -->
+  
     public void set(int index, <#if (type.width >= 4)>${minor.javaType!type.javaType}<#else>int</#if> value) {
       data.set${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH, value);
     }
@@ -855,8 +796,8 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
         }
       }
     }
-
   </#if> <#-- type.width -->
+  
     @Override
     public void setValueCount(int valueCount) {
       final int currentValueCapacity = getValueCapacity();

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/ListWriters.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/ListWriters.java b/exec/vector/src/main/codegen/templates/ListWriters.java
index 16d41ec..f10cfc4 100644
--- a/exec/vector/src/main/codegen/templates/ListWriters.java
+++ b/exec/vector/src/main/codegen/templates/ListWriters.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -43,7 +43,10 @@ package org.apache.drill.exec.vector.complex.impl;
 public class ${mode}ListWriter extends AbstractFieldWriter {
   private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${mode}ListWriter.class);
 
-  static enum Mode { INIT, IN_MAP, IN_LIST <#list vv.types as type><#list type.minor as minor>, IN_${minor.class?upper_case}</#list></#list> }
+  enum Mode {
+    INIT, IN_MAP, IN_LIST
+    <#list vv.types as type><#list type.minor as minor>,
+    IN_${minor.class?upper_case}</#list></#list> }
 
   private final String name;
   protected final ${containerClass} container;
@@ -69,7 +72,6 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
     if(writer != null) {
       writer.allocate();
     }
-
     <#if mode == "Repeated">
     container.allocateNew();
     </#if>
@@ -97,12 +99,14 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
   }
 
   public void setValueCount(int count){
-    if(innerVector != null) innerVector.getMutator().setValueCount(count);
+    if (innerVector != null) {
+      innerVector.getMutator().setValueCount(count);
+    }
   }
 
   @Override
   public MapWriter map() {
-    switch(mode) {
+    switch (mode) {
     case INIT:
       int vectorCount = container.size();
       final RepeatedMapVector vector = container.addOrGet(name, RepeatedMapVector.TYPE, RepeatedMapVector.class);
@@ -116,21 +120,23 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
       return writer;
     case IN_MAP:
       return writer;
+    default:
+      throw UserException
+        .unsupportedError()
+        .message(getUnsupportedErrorMsg("MAP", mode.name()))
+        .build(logger);
     }
-
-  throw UserException.unsupportedError().message(getUnsupportedErrorMsg("MAP", mode.name())).build(logger);
-
   }
 
   @Override
   public ListWriter list() {
-    switch(mode) {
+    switch (mode) {
     case INIT:
       final int vectorCount = container.size();
       final RepeatedListVector vector = container.addOrGet(name, RepeatedListVector.TYPE, RepeatedListVector.class);
       innerVector = vector;
       writer = new RepeatedListWriter(null, vector, this);
-      if(vectorCount != container.size()) {
+      if (vectorCount != container.size()) {
         writer.allocate();
       }
       writer.setPosition(${index});
@@ -138,10 +144,12 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
       return writer;
     case IN_LIST:
       return writer;
+    default:
+      throw UserException
+        .unsupportedError()
+        .message(getUnsupportedErrorMsg("LIST", mode.name()))
+        .build(logger);
     }
-
-  throw UserException.unsupportedError().message(getUnsupportedErrorMsg("LIST", mode.name())).build(logger);
-
   }
 
   <#list vv.types as type><#list type.minor as minor>
@@ -149,12 +157,11 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
   <#assign upperName = minor.class?upper_case />
   <#assign capName = minor.class?cap_first />
   <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
-
   private static final MajorType ${upperName}_TYPE = Types.repeated(MinorType.${upperName});
 
   @Override
   public ${capName}Writer ${lowerName}() {
-    switch(mode) {
+    switch (mode) {
     case INIT:
       final int vectorCount = container.size();
       final Repeated${capName}Vector vector = container.addOrGet(name, ${upperName}_TYPE, Repeated${capName}Vector.class);
@@ -168,19 +175,22 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
       return writer;
     case IN_${upperName}:
       return writer;
+    default:
+      throw UserException
+         .unsupportedError()
+         .message(getUnsupportedErrorMsg("${upperName}", mode.name()))
+         .build(logger);
     }
-
-  throw UserException.unsupportedError().message(getUnsupportedErrorMsg("${upperName}", mode.name())).build(logger);
-
   }
+  
   </#list></#list>
-
+  @Override
   public MaterializedField getField() {
     return container.getField();
   }
-
   <#if mode == "Repeated">
-
+  
+  @Override
   public void startList() {
     final RepeatedListVector list = (RepeatedListVector) container;
     final RepeatedListVector.RepeatedMutator mutator = list.getMutator();
@@ -202,11 +212,13 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
     }
   }
 
+  @Override
   public void endList() {
     // noop, we initialize state at start rather than end.
   }
   <#else>
 
+  @Override
   public void setPosition(int index) {
     super.setPosition(index);
     if(writer != null) {
@@ -214,10 +226,12 @@ public class ${mode}ListWriter extends AbstractFieldWriter {
     }
   }
 
+  @Override
   public void startList() {
     // noop
   }
 
+  @Override
   public void endList() {
     // noop
   }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/NullableValueVectors.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/NullableValueVectors.java b/exec/vector/src/main/codegen/templates/NullableValueVectors.java
index fdb0200..93f8e7b 100644
--- a/exec/vector/src/main/codegen/templates/NullableValueVectors.java
+++ b/exec/vector/src/main/codegen/templates/NullableValueVectors.java
@@ -15,7 +15,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import org.apache.drill.common.types.TypeProtos.DataMode;
 import org.apache.drill.exec.memory.AllocationManager.BufferLedger;
+import org.apache.drill.exec.record.MaterializedField;
 import org.apache.drill.exec.util.DecimalUtility;
 import org.apache.drill.exec.vector.BaseDataValueVector;
 import org.apache.drill.exec.vector.NullableVectorDefinitionSetter;
@@ -49,12 +51,9 @@ package org.apache.drill.exec.vector;
  */
 
 public final class ${className} extends BaseDataValueVector implements <#if type.major == "VarLen">VariableWidth<#else>FixedWidth</#if>Vector, NullableVector {
-  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${className}.class);
 
   private final FieldReader reader = new Nullable${minor.class}ReaderImpl(Nullable${minor.class}Vector.this);
 
-  private final MaterializedField bitsField = MaterializedField.create("$bits$", Types.required(MinorType.UINT1));
-
   /**
    * Set value flag. Meaning:
    * <ul>
@@ -67,13 +66,26 @@ public final class ${className} extends BaseDataValueVector implements <#if type
    */
 
   private final UInt1Vector bits = new UInt1Vector(bitsField, allocator);
-  private final ${valuesName} values = new ${minor.class}Vector(field, allocator);
+
+  private final ${valuesName} values;
 
   private final Mutator mutator = new Mutator();
-  private final Accessor accessor = new Accessor();
+  private final Accessor accessor;
 
   public ${className}(MaterializedField field, BufferAllocator allocator) {
     super(field, allocator);
+    
+    // The values vector has its own name, and has the same type and attributes
+    // as the nullable vector. This ensures that
+    // things like scale and precision are preserved in the values vector.
+    
+    values = new ${minor.class}Vector(
+        MaterializedField.create(VALUES_VECTOR_NAME, field.getType()),
+        allocator);
+    
+    field.addChild(bits.getField());
+    field.addChild(values.getField());
+    accessor = new Accessor();
   }
 
   @Override
@@ -128,6 +140,11 @@ public final class ${className} extends BaseDataValueVector implements <#if type
   }
 
   @Override
+  public int getAllocatedSize(){
+    return bits.getAllocatedSize() + values.getAllocatedSize();
+  }
+
+  @Override
   public DrillBuf getBuffer() {
     return values.getBuffer();
   }
@@ -138,6 +155,13 @@ public final class ${className} extends BaseDataValueVector implements <#if type
   @Override
   public UInt1Vector getBitsVector() { return bits; }
 
+  <#if type.major == "VarLen">
+  @Override
+  public UInt4Vector getOffsetVector() {
+    return ((VariableWidthVector) values).getOffsetVector();
+  }
+
+  </#if>
   @Override
   public void setInitialCapacity(int numRecords) {
     bits.setInitialCapacity(numRecords);

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/UnionListWriter.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/UnionListWriter.java b/exec/vector/src/main/codegen/templates/UnionListWriter.java
index c676769..81d5f9c 100644
--- a/exec/vector/src/main/codegen/templates/UnionListWriter.java
+++ b/exec/vector/src/main/codegen/templates/UnionListWriter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -32,15 +32,12 @@ package org.apache.drill.exec.vector.complex.impl;
  * This class is generated using freemarker and the ${.template_name} template.
  */
 
-@SuppressWarnings("unused")
 public class UnionListWriter extends AbstractFieldWriter {
 
   private ListVector vector;
   private UInt4Vector offsets;
   private PromotableWriter writer;
   private boolean inMap = false;
-  private String mapName;
-  private int lastIndex = 0;
 
   public UnionListWriter(ListVector vector) {
     super(null);
@@ -74,14 +71,10 @@ public class UnionListWriter extends AbstractFieldWriter {
   }
 
   @Override
-  public void close() throws Exception {
-
-  }
-
+  public void close() throws Exception { }
   <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
   <#assign fields = minor.fields!type.fields />
   <#assign uncappedName = name?uncap_first/>
-
   <#if !minor.class?starts_with("Decimal")>
 
   @Override
@@ -92,16 +85,13 @@ public class UnionListWriter extends AbstractFieldWriter {
   @Override
   public ${name}Writer <#if uncappedName == "int">integer<#else>${uncappedName}</#if>(String name) {
     assert inMap;
-    mapName = name;
     final int nextOffset = offsets.getAccessor().get(idx() + 1);
     vector.getMutator().setNotNull(idx());
     writer.setPosition(nextOffset);
     ${name}Writer ${uncappedName}Writer = writer.<#if uncappedName == "int">integer<#else>${uncappedName}</#if>(name);
     return ${uncappedName}Writer;
   }
-
   </#if>
-
   </#list></#list>
 
   @Override
@@ -140,9 +130,7 @@ public class UnionListWriter extends AbstractFieldWriter {
   }
 
   @Override
-  public void endList() {
-
-  }
+  public void endList() { }
 
   @Override
   public void start() {
@@ -161,11 +149,9 @@ public class UnionListWriter extends AbstractFieldWriter {
       offsets.getMutator().setSafe(idx() + 1, nextOffset + 1);
     }
   }
-
   <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
   <#assign fields = minor.fields!type.fields />
   <#assign uncappedName = name?uncap_first/>
-
   <#if !minor.class?starts_with("Decimal")>
 
   @Override
@@ -177,9 +163,6 @@ public class UnionListWriter extends AbstractFieldWriter {
     writer.write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
     offsets.getMutator().setSafe(idx() + 1, nextOffset + 1);
   }
-
   </#if>
-
   </#list></#list>
-
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/UnionVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/UnionVector.java b/exec/vector/src/main/codegen/templates/UnionVector.java
index a46779d..248b010 100644
--- a/exec/vector/src/main/codegen/templates/UnionVector.java
+++ b/exec/vector/src/main/codegen/templates/UnionVector.java
@@ -32,9 +32,15 @@ import java.util.Iterator;
 import java.util.Set;
 
 import org.apache.drill.exec.vector.complex.impl.ComplexCopier;
+
+import com.google.common.base.Preconditions;
+
 import org.apache.drill.exec.util.CallBack;
 import org.apache.drill.exec.expr.BasicTypeHelper;
 import org.apache.drill.exec.memory.AllocationManager.BufferLedger;
+import org.apache.drill.exec.record.MaterializedField;
+
+import com.google.common.annotations.VisibleForTesting;
 
 /*
  * This class is generated using freemarker and the ${.template_name} template.
@@ -43,43 +49,91 @@ import org.apache.drill.exec.memory.AllocationManager.BufferLedger;
 
 
 /**
- * A vector which can hold values of different types. It does so by using a MapVector which contains a vector for each
- * primitive type that is stored. MapVector is used in order to take advantage of its serialization/deserialization methods,
- * as well as the addOrGet method.
+ * A vector which can hold values of different types. It does so by using a
+ * MapVector which contains a vector for each primitive type that is stored.
+ * MapVector is used in order to take advantage of its
+ * serialization/deserialization methods, as well as the addOrGet method.
  *
- * For performance reasons, UnionVector stores a cached reference to each subtype vector, to avoid having to do the map lookup
- * each time the vector is accessed.
+ * For performance reasons, UnionVector stores a cached reference to each
+ * subtype vector, to avoid having to do the map lookup each time the vector is
+ * accessed.
  */
 public class UnionVector implements ValueVector {
 
+  public static final int NULL_MARKER = 0;
+  public static final String TYPE_VECTOR_NAME = "types";
+  public static final String INTERNAL_MAP_NAME = "internal";
+  
+  private static final MajorType MAJOR_TYPES[] = new MajorType[MinorType.values().length];
+  
+  static {
+    MAJOR_TYPES[MinorType.MAP.ordinal()] = Types.optional(MinorType.MAP);
+    MAJOR_TYPES[MinorType.LIST.ordinal()] = Types.optional(MinorType.LIST);
+    <#list vv.types as type>
+      <#list type.minor as minor>
+        <#assign name = minor.class?cap_first />
+        <#assign fields = minor.fields!type.fields />
+        <#assign uncappedName = name?uncap_first/>
+        <#if !minor.class?starts_with("Decimal")>
+    MAJOR_TYPES[MinorType.${name?upper_case}.ordinal()] = Types.optional(MinorType.${name?upper_case});
+        </#if>
+      </#list>
+    </#list>
+  }
+
   private MaterializedField field;
   private BufferAllocator allocator;
   private Accessor accessor = new Accessor();
   private Mutator mutator = new Mutator();
   private int valueCount;
 
+  /**
+   * Map which holds one vector for each subtype, along with a vector that indicates
+   * types and the null state. There appears to be no reason other than convenience
+   * for using a map. Future implementations may wish to store vectors directly in
+   * the union vector, but must then implement the required vector serialization/
+   * deserialization and other functionality.
+   */
+  
   private MapVector internalMap;
+  
+  /**
+   * Cached type vector. The vector's permament location is in the
+   * internal map, it is cached for performance. Call
+   * {@link #getTypeVector()} to get the cached copy, or to refresh
+   * the cache from the internal map if not set.
+   */
+  
   private UInt1Vector typeVector;
 
-  private MapVector mapVector;
-  private ListVector listVector;
+  /**
+   * Set of cached vectors that duplicate vectors store in the
+   * internal map. Used to avoid a name lookup on every access.
+   * The cache is populated as vectors are added. But, after the
+   * union is sent over the wire, the map is populated, but the
+   * array is not. It will be repopulated upon first access to
+   * the deserialized vectors.
+   */
+  
+  private ValueVector cachedSubtypes[] = new ValueVector[MinorType.values().length];
 
   private FieldReader reader;
-  private NullableBitVector bit;
-
-  private int singleType = 0;
-  private ValueVector singleVector;
-  private MajorType majorType;
 
   private final CallBack callBack;
 
   public UnionVector(MaterializedField field, BufferAllocator allocator, CallBack callBack) {
+    
+    // The metadata may start off listing subtypes for which vectors
+    // do not actually exist. It appears that the semantics are to list
+    // the subtypes that *could* appear. For example, in a sort we may
+    // have two types: one batch has type A, the other type B, but the
+    // batches must list both A and B as subtypes.
+    
     this.field = field.clone();
     this.allocator = allocator;
-    this.internalMap = new MapVector("internal", allocator, callBack);
-    this.typeVector = internalMap.addOrGet("types", Types.required(MinorType.UINT1), UInt1Vector.class);
+    this.internalMap = new MapVector(INTERNAL_MAP_NAME, allocator, callBack);
+    this.typeVector = internalMap.addOrGet(TYPE_VECTOR_NAME, Types.required(MinorType.UINT1), UInt1Vector.class);
     this.field.addChild(internalMap.getField().clone());
-    this.majorType = field.getType();
     this.callBack = callBack;
   }
 
@@ -87,94 +141,180 @@ public class UnionVector implements ValueVector {
   public BufferAllocator getAllocator() {
     return allocator;
   }
-
+  
   public List<MinorType> getSubTypes() {
-    return majorType.getSubTypeList();
-  }
-
+    return field.getType().getSubTypeList();
+  }
+  
+  @SuppressWarnings("unchecked")
+  public <T extends ValueVector> T subtype(MinorType type) {
+    return (T) cachedSubtypes[type.ordinal()];
+  }
+
+  
+  /**
+   * Add an externally-created subtype vector. The vector must represent a type that
+   * does not yet exist in the union, and must be of OPTIONAL mode. Does not call
+   * the callback since the client (presumably) knows that it is adding the type.
+   * The caller must also allocate the buffer for the vector.
+   * 
+   * @param vector subtype vector to add
+   */
+  
+  public void addType(ValueVector vector) {
+    MinorType type = vector.getField().getType().getMinorType();
+    assert subtype(type) == null;
+    assert vector.getField().getType().getMode() == DataMode.OPTIONAL;
+    assert vector.getField().getName().equals(type.name().toLowerCase());
+    cachedSubtypes[type.ordinal()] = vector;
+    internalMap.putChild(type.name(), vector);
+    addSubType(type);
+  }
+  
   public void addSubType(MinorType type) {
-    if (majorType.getSubTypeList().contains(type)) {
+    if (field.getType().getSubTypeList().contains(type)) {
       return;
     }
-    majorType =  MajorType.newBuilder(this.majorType).addSubType(type).build();
-    field = MaterializedField.create(field.getName(), majorType);
+    field.replaceType(
+        MajorType.newBuilder(field.getType()).addSubType(type).build());
     if (callBack != null) {
       callBack.doWork();
     }
   }
 
-  private static final MajorType MAP_TYPE = Types.optional(MinorType.MAP);
+  /**
+   * "Classic" way to add a subtype when working directly with a union vector.
+   * Creates the vector, adds it to the internal structures and creates a
+   * new buffer of the default size.
+   * 
+   * @param type the type to add
+   * @param vectorClass class of the vector to create
+   * @return typed form of the new value vector
+   */
+  
+  private <T extends ValueVector> T classicAddType(MinorType type, Class<? extends ValueVector> vectorClass) {
+    int vectorCount = internalMap.size();
+    @SuppressWarnings("unchecked")
+    T vector = (T) internalMap.addOrGet(type.name().toLowerCase(), MAJOR_TYPES[type.ordinal()], vectorClass);
+    cachedSubtypes[type.ordinal()] = vector;
+    if (internalMap.size() > vectorCount) {
+      vector.allocateNew();
+      addSubType(type);
+      if (callBack != null) {
+        callBack.doWork();
+      }
+    }
+    return vector;
+  }
 
   public MapVector getMap() {
+    MapVector mapVector = subtype(MinorType.MAP);
     if (mapVector == null) {
-      int vectorCount = internalMap.size();
-      mapVector = internalMap.addOrGet("map", MAP_TYPE, MapVector.class);
-      addSubType(MinorType.MAP);
-      if (internalMap.size() > vectorCount) {
-        mapVector.allocateNew();
-      }
+      mapVector = classicAddType(MinorType.MAP, MapVector.class);
     }
     return mapVector;
   }
-  <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
-  <#assign fields = minor.fields!type.fields />
-  <#assign uncappedName = name?uncap_first/>
-  <#if !minor.class?starts_with("Decimal")>
 
-  private Nullable${name}Vector ${uncappedName}Vector;
-  private static final MajorType ${name?upper_case}_TYPE = Types.optional(MinorType.${name?upper_case});
+  public ListVector getList() {
+    ListVector listVector = subtype(MinorType.LIST);
+    if (listVector == null) {
+      listVector = classicAddType(MinorType.LIST, ListVector.class);
+    }
+    return listVector;
+  }
+  <#-- Generating a method per type is probably overkill. However, existing code
+       depends on these methods, so didn't want to remove them. Over time, a
+       generic, parameterized addOrGet(MinorType type) would be more compact.
+       Would need a function to map from minor type to vector class, which
+       can be generated here or in TypeHelper. -->
+  <#list vv.types as type>
+    <#list type.minor as minor>
+      <#assign name = minor.class?cap_first />
+      <#assign fields = minor.fields!type.fields />
+      <#assign uncappedName = name?uncap_first/>
+      <#if !minor.class?starts_with("Decimal")>
 
   public Nullable${name}Vector get${name}Vector() {
-    if (${uncappedName}Vector == null) {
-      int vectorCount = internalMap.size();
-      ${uncappedName}Vector = internalMap.addOrGet("${uncappedName}", ${name?upper_case}_TYPE, Nullable${name}Vector.class);
-      addSubType(MinorType.${name?upper_case});
-      if (internalMap.size() > vectorCount) {
-        ${uncappedName}Vector.allocateNew();
-      }
+    Nullable${name}Vector vector = subtype(MinorType.${name?upper_case});
+    if (vector == null) {
+      vector = classicAddType(MinorType.${name?upper_case}, Nullable${name}Vector.class);
     }
-    return ${uncappedName}Vector;
+    return vector;
   }
-  </#if>
-  </#list></#list>
-
-  private static final MajorType LIST_TYPE = Types.optional(MinorType.LIST);
-
-  public ListVector getList() {
-    if (listVector == null) {
-      int vectorCount = internalMap.size();
-      listVector = internalMap.addOrGet("list", LIST_TYPE, ListVector.class);
-      addSubType(MinorType.LIST);
-      if (internalMap.size() > vectorCount) {
-        listVector.allocateNew();
-      }
+      </#if>
+    </#list>
+  </#list>
+  
+  /**
+   * Add or get a type member given the type.
+   * 
+   * @param type the type of the vector to retrieve
+   * @return the (potentially newly created) vector that backs the given type
+   */
+  
+  public ValueVector getMember(MinorType type) {
+    switch (type) {
+    case MAP:
+      return getMap();
+    case LIST:
+      return getList();
+  <#-- This awkard switch statement and call to type-specific method logic
+       can be generalized as described above. -->
+  <#list vv.types as type>
+    <#list type.minor as minor>
+      <#assign name = minor.class?cap_first />
+      <#assign fields = minor.fields!type.fields />
+      <#assign uncappedName = name?uncap_first/>
+      <#if !minor.class?starts_with("Decimal")>
+    case ${name?upper_case}:
+      return get${name}Vector();
+      </#if>
+    </#list>
+  </#list>
+    default:
+      throw new UnsupportedOperationException(type.toString());
     }
-    return listVector;
+  }
+  
+  @SuppressWarnings("unchecked")
+  public <T extends ValueVector> T member(MinorType type) {
+    return (T) getMember(type);
   }
 
   public int getTypeValue(int index) {
-    return typeVector.getAccessor().get(index);
+    return getTypeVector().getAccessor().get(index);
   }
 
   public UInt1Vector getTypeVector() {
+    if (typeVector == null) {
+      typeVector = (UInt1Vector) internalMap.getChild(TYPE_VECTOR_NAME);
+    }
     return typeVector;
   }
+  
+  @VisibleForTesting
+  public MapVector getTypeMap() {
+    return internalMap;
+  }
 
   @Override
   public void allocateNew() throws OutOfMemoryException {
     internalMap.allocateNew();
-    if (typeVector != null) {
-      typeVector.zeroVector();
-    }
+    getTypeVector().zeroVector();
+  }
+
+  public void allocateNew(int rowCount) throws OutOfMemoryException {
+    // The map vector does not have a form that takes a row count,
+    // but it should.
+    internalMap.allocateNew();
+    getTypeVector().zeroVector();
   }
 
   @Override
   public boolean allocateNewSafe() {
     boolean safe = internalMap.allocateNewSafe();
     if (safe) {
-      if (typeVector != null) {
-        typeVector.zeroVector();
-      }
+      getTypeVector().zeroVector();
     }
     return safe;
   }
@@ -184,7 +324,7 @@ public class UnionVector implements ValueVector {
 
   @Override
   public int getValueCapacity() {
-    return Math.min(typeVector.getValueCapacity(), internalMap.getValueCapacity());
+    return Math.min(getTypeVector().getValueCapacity(), internalMap.getValueCapacity());
   }
 
   @Override
@@ -200,12 +340,7 @@ public class UnionVector implements ValueVector {
 
   @Override
   public void collectLedgers(Set<BufferLedger> ledgers) {
-    // Most vectors are held inside the internal map.
-
     internalMap.collectLedgers(ledgers);
-    if (bit != null) {
-      bit.collectLedgers(ledgers);
-    }
   }
 
   @Override
@@ -231,7 +366,6 @@ public class UnionVector implements ValueVector {
   public void transferTo(UnionVector target) {
     internalMap.makeTransferPair(target.internalMap).transfer();
     target.valueCount = valueCount;
-    target.majorType = majorType;
   }
 
   public void copyFrom(int inIndex, int outIndex, UnionVector from) {
@@ -249,16 +383,48 @@ public class UnionVector implements ValueVector {
     copyFromSafe(fromIndex, toIndex, (UnionVector) from);
   }
 
+  /**
+   * Add a vector that matches the argument. Transfer the buffer from the argument
+   * to the new vector.
+   * 
+   * @param v the vector to clone and add
+   * @return the cloned vector that now holds the data from the argument
+   */
+  
   public ValueVector addVector(ValueVector v) {
     String name = v.getField().getType().getMinorType().name().toLowerCase();
     MajorType type = v.getField().getType();
+    MinorType minorType = type.getMinorType();
     Preconditions.checkState(internalMap.getChild(name) == null, String.format("%s vector already exists", name));
-    final ValueVector newVector = internalMap.addOrGet(name, type, BasicTypeHelper.getValueVectorClass(type.getMinorType(), type.getMode()));
+    final ValueVector newVector = internalMap.addOrGet(name, type, BasicTypeHelper.getValueVectorClass(minorType, type.getMode()));
     v.makeTransferPair(newVector).transfer();
     internalMap.putChild(name, newVector);
-    addSubType(v.getField().getType().getMinorType());
+    cachedSubtypes[minorType.ordinal()] = newVector;
+    addSubType(minorType);
     return newVector;
   }
+  
+  // Called from SchemaUtil
+  
+  public ValueVector setFirstType(ValueVector v, int newValueCount) {
+    
+    // We can't check that this really is the first subtype since
+    // the subtypes can be declared before vectors are added.
+    
+    Preconditions.checkState(accessor.getValueCount() == 0);
+    final ValueVector vv = addVector(v);
+    MinorType type = v.getField().getType().getMinorType();
+    ValueVector.Accessor vAccessor = vv.getAccessor();
+    for (int i = 0; i < newValueCount; i++) {
+      if (! vAccessor.isNull(i)) {
+        mutator.setType(i, type);
+      } else {
+        mutator.setNull(i);
+      }
+    }
+    mutator.setValueCount(newValueCount);
+    return vv;
+  }
 
   @Override
   public void toNullable(ValueVector nullableVector) {
@@ -267,7 +433,7 @@ public class UnionVector implements ValueVector {
 
   private class TransferImpl implements TransferPair {
 
-    UnionVector to;
+    private final UnionVector to;
 
     public TransferImpl(MaterializedField field, BufferAllocator allocator) {
       to = new UnionVector(field, allocator, null);
@@ -319,13 +485,12 @@ public class UnionVector implements ValueVector {
 
   @Override
   public UserBitShared.SerializedField getMetadata() {
-    SerializedField.Builder b = getField() //
-            .getAsBuilder() //
-            .setBufferLength(getBufferSize()) //
-            .setValueCount(valueCount);
-
-    b.addChild(internalMap.getMetadata());
-    return b.build();
+    return getField()
+            .getAsBuilder()
+            .setBufferLength(getBufferSize())
+            .setValueCount(valueCount)
+            .addChild(internalMap.getMetadata())
+            .build();
   }
 
   @Override
@@ -366,18 +531,16 @@ public class UnionVector implements ValueVector {
 
   @Override
   public Iterator<ValueVector> iterator() {
-    List<ValueVector> vectors = Lists.newArrayList(internalMap.iterator());
-    vectors.add(typeVector);
-    return vectors.iterator();
+    return internalMap.iterator();
   }
 
   public class Accessor extends BaseValueVector.BaseAccessor {
 
     @Override
     public Object getObject(int index) {
-      int type = typeVector.getAccessor().get(index);
+      int type = getTypeVector().getAccessor().get(index);
       switch (type) {
-      case 0:
+      case NULL_MARKER:
         return null;
       <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
       <#assign fields = minor.fields!type.fields />
@@ -386,7 +549,6 @@ public class UnionVector implements ValueVector {
       case MinorType.${name?upper_case}_VALUE:
         return get${name}Vector().getAccessor().getObject(index);
       </#if>
-
       </#list></#list>
       case MinorType.MAP_VALUE:
         return getMap().getAccessor().getObject(index);
@@ -412,7 +574,12 @@ public class UnionVector implements ValueVector {
 
     @Override
     public boolean isNull(int index) {
-      return typeVector.getAccessor().get(index) == 0;
+      
+      // Note that type code == 0 is used to indicate a null.
+      // This corresponds to the LATE type, not the NULL type.
+      // This is presumably an artifact of an earlier implementation...
+      
+      return getTypeVector().getAccessor().get(index) == NULL_MARKER;
     }
 
     public int isSet(int index) {
@@ -449,14 +616,12 @@ public class UnionVector implements ValueVector {
         break;
       </#if>
       </#list></#list>
-      case MAP: {
+      case MAP:
         ComplexCopier.copy(reader, writer);
         break;
-      }
-      case LIST: {
+      case LIST:
         ComplexCopier.copy(reader, writer);
         break;
-      }
       default:
         throw new UnsupportedOperationException();
       }
@@ -475,7 +640,11 @@ public class UnionVector implements ValueVector {
     </#list></#list>
 
     public void setType(int index, MinorType type) {
-      typeVector.getMutator().setSafe(index, type.getNumber());
+      getTypeVector().getMutator().setSafe(index, type.getNumber());
+    }
+    
+    public void setNull(int index) {
+      getTypeVector().getMutator().setSafe(index, NULL_MARKER);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/UnionWriter.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/UnionWriter.java b/exec/vector/src/main/codegen/templates/UnionWriter.java
index 7a123b4..58cc455 100644
--- a/exec/vector/src/main/codegen/templates/UnionWriter.java
+++ b/exec/vector/src/main/codegen/templates/UnionWriter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -29,10 +29,11 @@ package org.apache.drill.exec.vector.complex.impl;
 /*
  * This class is generated using freemarker and the ${.template_name} template.
  */
-@SuppressWarnings("unused")
+
 public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
 
-  UnionVector data;
+  // Accessed by UnionReader
+  protected UnionVector data;
   private MapWriter mapWriter;
   private UnionListWriter listWriter;
   private List<BaseWriter> writers = Lists.newArrayList();
@@ -59,7 +60,6 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
     }
   }
 
-
   @Override
   public void start() {
     data.getMutator().setType(idx(), MinorType.MAP);
@@ -145,11 +145,9 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
     get${name}Writer().write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
   }
   </#if>
-
   </#list></#list>
 
-  public void writeNull() {
-  }
+  public void writeNull() { }
 
   @Override
   public MapWriter map() {

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/codegen/templates/VariableLengthVectors.java b/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
index a29194a..87dbe95 100644
--- a/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
+++ b/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
@@ -50,17 +50,14 @@ package org.apache.drill.exec.vector;
  * variable, this width is used as a guess for certain calculations.</li>
  * <li>The equivalent Java primitive is '${minor.javaType!type.javaType}'<li>
  * </ul>
- * NB: this class is automatically generated from ${.template_name} and ValueVectorTypes.tdd using FreeMarker.
+ * NB: this class is automatically generated from <tt>${.template_name}</tt>
+ * and <tt>ValueVectorTypes.tdd</tt> using FreeMarker.
  */
 
 public final class ${minor.class}Vector extends BaseDataValueVector implements VariableWidthVector {
 
-  private static final int DEFAULT_RECORD_BYTE_COUNT = 8;
   private static final int INITIAL_BYTE_COUNT = Math.min(INITIAL_VALUE_ALLOCATION * DEFAULT_RECORD_BYTE_COUNT, MAX_BUFFER_SIZE);
-  private static final int MIN_BYTE_COUNT = 4096;
-  public final static String OFFSETS_VECTOR_NAME = "$offsets$";
-
-  private final MaterializedField offsetsField = MaterializedField.create(OFFSETS_VECTOR_NAME, Types.required(MinorType.UINT4));
+  
   private final UInt${type.width}Vector offsetVector = new UInt${type.width}Vector(offsetsField, allocator);
   private final FieldReader reader = new ${minor.class}ReaderImpl(${minor.class}Vector.this);
 
@@ -175,6 +172,7 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements V
     return offsetVector.getBuffer().memoryAddress();
   }
 
+  @Override
   public UInt${type.width}Vector getOffsetVector() {
     return offsetVector;
   }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java b/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
index 992ae03..67594fe 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -18,7 +18,6 @@
 
 package org.apache.drill.exec.expr.fn.impl;
 
-import org.joda.time.Period;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 import org.joda.time.format.DateTimeFormatterBuilder;
@@ -26,18 +25,23 @@ import org.joda.time.format.DateTimeParser;
 
 import com.carrotsearch.hppc.ObjectIntHashMap;
 
-// Utility class for Date, DateTime, TimeStamp, Interval data types
-public class DateUtility {
+/**
+ * Utility class for Date, DateTime, TimeStamp, Interval data types.
+ * <p>
+ * WARNING: This class is excluded from the JDBC driver. If vectors refer
+ * to this code, they will fail when called from JDBC.
+ */
 
+public class DateUtility {
 
-    /* We have a hashmap that stores the timezone as the key and an index as the value
-     * While storing the timezone in value vectors, holders we only use this index. As we
-     * reconstruct the timestamp, we use this index to index through the array timezoneList
-     * and get the corresponding timezone and pass it to joda-time
-     */
+  /* We have a hashmap that stores the timezone as the key and an index as the value
+   * While storing the timezone in value vectors, holders we only use this index. As we
+   * reconstruct the timestamp, we use this index to index through the array timezoneList
+   * and get the corresponding timezone and pass it to joda-time
+   */
   public static ObjectIntHashMap<String> timezoneMap = new ObjectIntHashMap<String>();
 
-    public static String[] timezoneList =  {"Africa/Abidjan",
+  public static String[] timezoneList =  {  "Africa/Abidjan",
                                             "Africa/Accra",
                                             "Africa/Addis_Ababa",
                                             "Africa/Algiers",
@@ -612,71 +616,53 @@ public class DateUtility {
                                             "WET",
                                             "Zulu"};
 
-    static {
-      for (int i = 0; i < timezoneList.length; i++) {
-        timezoneMap.put(timezoneList[i], i);
-      }
+  static {
+    for (int i = 0; i < timezoneList.length; i++) {
+      timezoneMap.put(timezoneList[i], i);
     }
+  }
 
-    public static final DateTimeFormatter formatDate        = DateTimeFormat.forPattern("yyyy-MM-dd");
-    public static final DateTimeFormatter formatTimeStamp    = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
-    public static final DateTimeFormatter formatTimeStampTZ = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS ZZZ");
-    public static final DateTimeFormatter formatTime        = DateTimeFormat.forPattern("HH:mm:ss.SSS");
+  public static final DateTimeFormatter formatDate        = DateTimeFormat.forPattern("yyyy-MM-dd");
+  public static final DateTimeFormatter formatTimeStamp    = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
+  public static final DateTimeFormatter formatTimeStampTZ = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS ZZZ");
+  public static final DateTimeFormatter formatTime        = DateTimeFormat.forPattern("HH:mm:ss.SSS");
 
-    public static DateTimeFormatter dateTimeTZFormat = null;
-    public static DateTimeFormatter timeFormat = null;
+  public static DateTimeFormatter dateTimeTZFormat = null;
+  public static DateTimeFormatter timeFormat = null;
 
-    public static final int yearsToMonths = 12;
-    public static final int hoursToMillis = 60 * 60 * 1000;
-    public static final int minutesToMillis = 60 * 1000;
-    public static final int secondsToMillis = 1000;
-    public static final int monthToStandardDays = 30;
-    public static final long monthsToMillis = 2592000000L; // 30 * 24 * 60 * 60 * 1000
-    public static final int daysToStandardMillis = 24 * 60 * 60 * 1000;
 
 
   public static int getIndex(String timezone) {
-        return timezoneMap.get(timezone);
-    }
+    return timezoneMap.get(timezone);
+  }
 
-    public static String getTimeZone(int index) {
-        return timezoneList[index];
-    }
-
-    // Function returns the date time formatter used to parse date strings
-    public static DateTimeFormatter getDateTimeFormatter() {
+  public static String getTimeZone(int index) {
+    return timezoneList[index];
+  }
 
-        if (dateTimeTZFormat == null) {
-            DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd");
-            DateTimeParser optionalTime = DateTimeFormat.forPattern(" HH:mm:ss").getParser();
-            DateTimeParser optionalSec = DateTimeFormat.forPattern(".SSS").getParser();
-            DateTimeParser optionalZone = DateTimeFormat.forPattern(" ZZZ").getParser();
+  // Returns the date time formatter used to parse date strings
+  public static DateTimeFormatter getDateTimeFormatter() {
 
-            dateTimeTZFormat = new DateTimeFormatterBuilder().append(dateFormatter).appendOptional(optionalTime).appendOptional(optionalSec).appendOptional(optionalZone).toFormatter();
-        }
+    if (dateTimeTZFormat == null) {
+      DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd");
+      DateTimeParser optionalTime = DateTimeFormat.forPattern(" HH:mm:ss").getParser();
+      DateTimeParser optionalSec = DateTimeFormat.forPattern(".SSS").getParser();
+      DateTimeParser optionalZone = DateTimeFormat.forPattern(" ZZZ").getParser();
 
-        return dateTimeTZFormat;
+      dateTimeTZFormat = new DateTimeFormatterBuilder().append(dateFormatter).appendOptional(optionalTime).appendOptional(optionalSec).appendOptional(optionalZone).toFormatter();
     }
 
-    // Function returns time formatter used to parse time strings
-    public static DateTimeFormatter getTimeFormatter() {
-        if (timeFormat == null) {
-            DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm:ss");
-            DateTimeParser optionalSec = DateTimeFormat.forPattern(".SSS").getParser();
-            timeFormat = new DateTimeFormatterBuilder().append(timeFormatter).appendOptional(optionalSec).toFormatter();
-        }
-        return timeFormat;
-    }
-
-    public static int monthsFromPeriod(Period period){
-      return (period.getYears() * yearsToMonths) + period.getMonths();
-    }
+    return dateTimeTZFormat;
+  }
 
-    public static int millisFromPeriod(final Period period){
-      return (period.getHours() * hoursToMillis) +
-      (period.getMinutes() * minutesToMillis) +
-      (period.getSeconds() * secondsToMillis) +
-      (period.getMillis());
+  // Returns time formatter used to parse time strings
+  public static DateTimeFormatter getTimeFormatter() {
+    if (timeFormat == null) {
+      DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm:ss");
+      DateTimeParser optionalSec = DateTimeFormat.forPattern(".SSS").getParser();
+      timeFormat = new DateTimeFormatterBuilder().append(timeFormatter).appendOptional(optionalSec).toFormatter();
     }
+    return timeFormat;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/record/MaterializedField.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/record/MaterializedField.java b/exec/vector/src/main/java/org/apache/drill/exec/record/MaterializedField.java
index b4b23c7..fa4d276 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/record/MaterializedField.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/record/MaterializedField.java
@@ -26,6 +26,7 @@ import java.util.Objects;
 import org.apache.drill.common.types.TypeProtos.DataMode;
 import org.apache.drill.common.types.TypeProtos.MajorType;
 import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.types.Types;
 import org.apache.drill.exec.expr.BasicTypeHelper;
 import org.apache.drill.exec.proto.UserBitShared.NamePart;
 import org.apache.drill.exec.proto.UserBitShared.SerializedField;
@@ -38,7 +39,7 @@ import org.apache.drill.exec.proto.UserBitShared.SerializedField;
 
 public class MaterializedField {
   private final String name;
-  private final MajorType type;
+  private MajorType type;
   // use an ordered set as existing code relies on order (e,g. parquet writer)
   private final LinkedHashSet<MaterializedField> children;
 
@@ -87,13 +88,47 @@ public class MaterializedField {
     children.add(field);
   }
 
+  public void removeChild(MaterializedField field) {
+    children.remove(field);
+  }
+
+  /**
+   * Replace the type with a new one that has the same minor type
+   * and mode, but with perhaps different details.
+   * <p>
+   * The type is immutable. But, it contains subtypes, used or lists
+   * and unions. To add a subtype, we must create a whole new major type.
+   * <p>
+   * It appears that the <tt>MaterializedField</tt> class was also meant
+   * to be immutable. But, it holds the children for a map, and contains
+   * methods to add children. So, it is not immutable.
+   * <p>
+   * This method allows evolving a list or union without the need to create
+   * a new <tt>MaterializedField</tt>. Doing so is problematic for nested
+   * maps because the map (or list, or union) holds onto the
+   * <tt>MaterializedField</tt>'s of its children. There is no way for
+   * an inner map to reach out and change the child of its parent.
+   * <p>
+   * By allowing the non-critical metadata to change, we preserve the
+   * child relationships as a list or union evolves.
+   * @param type
+   */
+
+  public void replaceType(MajorType newType) {
+    assert type.getMinorType() == newType.getMinorType();
+    assert type.getMode() == newType.getMode();
+    type = newType;
+  }
+
   @Override
   public MaterializedField clone() {
     return withPathAndType(name, getType());
   }
 
   public MaterializedField cloneEmpty() {
-    return create(name, type);
+    return create(name, type.toBuilder()
+        .clearSubType()
+        .build());
   }
 
   public MaterializedField withType(MajorType type) {
@@ -213,16 +248,77 @@ public class MaterializedField {
     // But, unset fields are equivalent to 0. Can't use the protobuf-provided
     // isEquals(), that treats set and unset fields as different.
 
+    if (! Types.isEquivalent(type, other.type)) {
+      return false;
+    }
+
+    // Compare children -- but only for maps, not the internal children
+    // for Varchar, repeated or nullable types.
+
+    if (type.getMinorType() != MinorType.MAP) {
+      return true;
+    }
+
+    if (children == null || other.children == null) {
+      return children == other.children;
+    }
+    if (children.size() != other.children.size()) {
+      return false;
+    }
+
+    // Maps are name-based, not position. But, for our
+    // purposes, we insist on identical ordering.
+
+    Iterator<MaterializedField> thisIter = children.iterator();
+    Iterator<MaterializedField> otherIter = other.children.iterator();
+    while (thisIter.hasNext()) {
+      MaterializedField thisChild = thisIter.next();
+      MaterializedField otherChild = otherIter.next();
+      if (! thisChild.isEquivalent(otherChild)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Determine if the present column schema can be promoted to the
+   * given schema. Promotion is possible if the schemas are
+   * equivalent, or if required mode is promoted to nullable, or
+   * if scale or precision can be increased.
+   *
+   * @param other the field to which this one is to be promoted
+   * @return true if promotion is possible, false otherwise
+   */
+
+  public boolean isPromotableTo(MaterializedField other, boolean allowModeChange) {
+    if (! name.equalsIgnoreCase(other.name)) {
+      return false;
+    }
+
+    // Requires full type equality, including fields such as precision and scale.
+    // But, unset fields are equivalent to 0. Can't use the protobuf-provided
+    // isEquals(), that treats set and unset fields as different.
+
     if (type.getMinorType() != other.type.getMinorType()) {
       return false;
     }
     if (type.getMode() != other.type.getMode()) {
-      return false;
+
+      // Modes differ, but type can be promoted from required to
+      // nullable
+
+      if (! allowModeChange) {
+        return false;
+      }
+      if (! (type.getMode() == DataMode.REQUIRED && other.type.getMode() == DataMode.OPTIONAL)) {
+        return false;
+      }
     }
-    if (type.getScale() != other.type.getScale()) {
+    if (type.getScale() > other.type.getScale()) {
       return false;
     }
-    if (type.getPrecision() != other.type.getPrecision()) {
+    if (type.getPrecision() > other.type.getPrecision()) {
       return false;
     }
 
@@ -233,7 +329,7 @@ public class MaterializedField {
       return true;
     }
 
-    if (children == null || other.children == null) {
+    if (children == null  ||  other.children == null) {
       return children == other.children;
     }
     if (children.size() != other.children.size()) {
@@ -248,7 +344,7 @@ public class MaterializedField {
     while (thisIter.hasNext()) {
       MaterializedField thisChild = thisIter.next();
       MaterializedField otherChild = otherIter.next();
-      if (! thisChild.isEquivalent(otherChild)) {
+      if (! thisChild.isPromotableTo(otherChild, allowModeChange)) {
         return false;
       }
     }
@@ -269,30 +365,45 @@ public class MaterializedField {
   @Override
   public String toString() {
     final int maxLen = 10;
-    String childString = children != null && !children.isEmpty() ? toString(children, maxLen) : "";
     StringBuilder builder = new StringBuilder();
     builder
-        .append(name)
-        .append("(")
-        .append(type.getMinorType().name());
+      .append("[`")
+      .append(name)
+      .append("` (")
+      .append(type.getMinorType().name());
 
     if (type.hasPrecision()) {
       builder.append("(");
       builder.append(type.getPrecision());
       if (type.hasScale()) {
-        builder.append(",");
+        builder.append(", ");
         builder.append(type.getScale());
       }
       builder.append(")");
     }
 
     builder
-        .append(":")
-        .append(type.getMode().name())
-        .append(")")
-        .append(childString);
+      .append(":")
+      .append(type.getMode().name())
+      .append(")");
+
+    if (type.getSubTypeCount() > 0) {
+      builder
+        .append(", subtypes=(")
+        .append(type.getSubTypeList().toString())
+        .append(")");
+    }
 
-    return builder.toString();
+    if (children != null && ! children.isEmpty()) {
+      builder
+        .append(", children=(")
+        .append(toString(children, maxLen))
+        .append(")");
+    }
+
+    return builder
+        .append("]")
+        .toString();
   }
 
   /**
@@ -307,7 +418,6 @@ public class MaterializedField {
 
   private String toString(Collection<?> collection, int maxLen) {
     StringBuilder builder = new StringBuilder();
-    builder.append(" [");
     int i = 0;
     for (Iterator<?> iterator = collection.iterator(); iterator.hasNext() && i < maxLen; i++) {
       if (i > 0){
@@ -315,7 +425,6 @@ public class MaterializedField {
       }
       builder.append(iterator.next());
     }
-    builder.append("]");
     return builder.toString();
   }
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseDataValueVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseDataValueVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseDataValueVector.java
index 4391e8c..b27d7ba 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseDataValueVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseDataValueVector.java
@@ -107,6 +107,9 @@ public abstract class BaseDataValueVector extends BaseValueVector {
 
   @Override
   public void exchange(ValueVector other) {
+
+    // Exchange the data buffers
+
     BaseDataValueVector target = (BaseDataValueVector) other;
     DrillBuf temp = data;
     data = target.data;

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseValueVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseValueVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseValueVector.java
index 63f4528..864d8e4 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseValueVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/BaseValueVector.java
@@ -17,20 +17,20 @@
  */
 package org.apache.drill.exec.vector;
 
-import io.netty.buffer.DrillBuf;
-
 import java.util.Collections;
 import java.util.Iterator;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterators;
-
 import org.apache.drill.exec.memory.BufferAllocator;
 import org.apache.drill.exec.proto.UserBitShared.SerializedField;
 import org.apache.drill.exec.record.MaterializedField;
 import org.apache.drill.exec.record.TransferPair;
 
+import com.google.common.base.Preconditions;
+
+import io.netty.buffer.DrillBuf;
+
 public abstract class BaseValueVector implements ValueVector {
+
   /**
    * Physical maximum allocation. This is the value prior to Drill 1.11.
    * This size causes memory fragmentation. Please use

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/DateUtilities.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/DateUtilities.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/DateUtilities.java
new file mode 100644
index 0000000..4ea460b
--- /dev/null
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/DateUtilities.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.drill.exec.vector;
+
+import org.joda.time.Period;
+
+/**
+ * Utility class for Date, DateTime, TimeStamp, Interval data types.
+ * <p>
+ * WARNING: This class is included from the JDBC driver. There is another, similar
+ * class called <tt>org.apache.drill.exec.expr.fn.impl.DateUtility</tt>. If vectors refer
+ * to that class, they will fail when called from JDBC. So, place code here if
+ * it is needed by JDBC, in the other class if only needed by the Drill engine.
+ * (This is a very poor design, but it is what it is.)
+ */
+
+public class DateUtilities {
+
+  public static final int yearsToMonths = 12;
+  public static final int hoursToMillis = 60 * 60 * 1000;
+  public static final int minutesToMillis = 60 * 1000;
+  public static final int secondsToMillis = 1000;
+  public static final int monthToStandardDays = 30;
+  public static final long monthsToMillis = 2592000000L; // 30 * 24 * 60 * 60 * 1000
+  public static final int daysToStandardMillis = 24 * 60 * 60 * 1000;
+
+  public static int monthsFromPeriod(Period period){
+    return (period.getYears() * yearsToMonths) + period.getMonths();
+  }
+
+  public static int periodToMillis(final Period period){
+    return (period.getHours() * hoursToMillis) +
+           (period.getMinutes() * minutesToMillis) +
+           (period.getSeconds() * secondsToMillis) +
+           (period.getMillis());
+  }
+
+  public static int toMonths(int years, int months) {
+    return years * yearsToMonths + months;
+  }
+
+  public static int periodToMonths(Period value) {
+    return value.getYears() * yearsToMonths + value.getMonths();
+  }
+
+  public static Period fromIntervalYear(int value) {
+    final int years  = (value / yearsToMonths);
+    final int months = (value % yearsToMonths);
+    return new Period()
+        .plusYears(years)
+        .plusMonths(months);
+  }
+
+  public static StringBuilder intervalYearStringBuilder(int months) {
+    final int years = months / yearsToMonths;
+    months %= yearsToMonths;
+
+    return new StringBuilder()
+           .append(years)
+           .append(pluralify("year", years))
+           .append(" ")
+           .append(months)
+           .append(pluralify("month", months));
+  }
+
+  public static StringBuilder intervalYearStringBuilder(Period value) {
+    return intervalYearStringBuilder(
+        value.getYears() * 12 + value.getMonths());
+  }
+
+  public static String pluralify(String term, int value) {
+    term = (Math.abs(value) == 1) ? term : term + "s";
+    return " " + term;
+  }
+
+  public static Period fromIntervalDay(int days, int millis) {
+    return new Period()
+        .plusDays(days)
+        .plusMillis(millis);
+  }
+
+  public static StringBuilder intervalDayStringBuilder(int days, int millis) {
+
+    final int hours  = millis / (hoursToMillis);
+    millis %= (hoursToMillis);
+
+    final int minutes = millis / (minutesToMillis);
+    millis %= (minutesToMillis);
+
+    final int seconds = millis / (secondsToMillis);
+    millis %= (secondsToMillis);
+
+    StringBuilder buf = new StringBuilder()
+            .append(days)
+            .append(pluralify("day", days))
+            .append(" ")
+            .append(hours)
+            .append(":")
+            .append(asTwoDigits(minutes))
+            .append(":")
+            .append(asTwoDigits(seconds));
+    if (millis != 0) {
+      buf.append(".")
+         .append(millis);
+    }
+    return buf;
+  }
+
+  public static StringBuilder intervalDayStringBuilder(Period value) {
+    return intervalDayStringBuilder(
+        value.getDays(),
+        periodToMillis(value));
+  }
+
+  public static Period fromInterval(int months, int days, int millis) {
+    return new Period()
+        .plusMonths(months)
+        .plusDays(days)
+        .plusMillis(millis);
+  }
+
+  public static String asTwoDigits(int value) {
+    return String.format("%02d", value);
+  }
+
+  public static StringBuilder intervalStringBuilder(int months, int days, int millis) {
+
+    final int years = months / yearsToMonths;
+    months %= yearsToMonths;
+
+    final int hours  = millis / hoursToMillis;
+    millis %= hoursToMillis;
+
+    final int minutes = millis / minutesToMillis;
+    millis %= minutesToMillis;
+
+    final int seconds = millis / secondsToMillis;
+    millis %= secondsToMillis;
+
+    StringBuilder buf = new StringBuilder()
+           .append(years)
+           .append(pluralify("year", years))
+           .append(" ")
+           .append(months)
+           .append(pluralify("month", months))
+           .append(" ")
+           .append(days)
+           .append(pluralify("day", days))
+           .append(" ")
+           .append(hours)
+           .append(":")
+           .append(asTwoDigits(minutes))
+           .append(":")
+           .append(asTwoDigits(seconds));
+    if (millis != 0) {
+      buf.append(".")
+         .append(millis);
+    }
+    return buf;
+  }
+
+  public static StringBuilder intervalStringBuilder(Period value) {
+    return intervalStringBuilder(
+        value.getYears() * 12 + value.getMonths(),
+        value.getDays(),
+        periodToMillis(value));
+  }
+
+  public static int timeToMillis(int hours, int minutes, int seconds, int millis) {
+    return ((hours * 60 +
+             minutes) * 60 +
+            seconds) * 1000 +
+           millis;
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/NullableVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/NullableVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/NullableVector.java
index 51b5e0c..80b732a 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/NullableVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/NullableVector.java
@@ -17,7 +17,13 @@
  */
 package org.apache.drill.exec.vector;
 
-public interface NullableVector extends ValueVector{
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.types.Types;
+import org.apache.drill.exec.record.MaterializedField;
+
+public interface NullableVector extends ValueVector {
+
+  MaterializedField bitsField = MaterializedField.create(BITS_VECTOR_NAME, Types.required(MinorType.UINT1));
 
   ValueVector getBitsVector();
   ValueVector getValuesVector();

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/ValueVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/ValueVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/ValueVector.java
index bc06803..44a467e 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/ValueVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/ValueVector.java
@@ -20,7 +20,6 @@ package org.apache.drill.exec.vector;
 import java.io.Closeable;
 import java.util.Set;
 
-import com.google.common.annotations.VisibleForTesting;
 import io.netty.buffer.DrillBuf;
 
 import org.apache.drill.exec.exception.OutOfMemoryException;
@@ -86,6 +85,12 @@ public interface ValueVector extends Closeable, Iterable<ValueVector> {
 
   int MAX_ROW_COUNT = Character.MAX_VALUE + 1;
 
+  // Commonly-used internal vector names
+
+  String BITS_VECTOR_NAME = "$bits$";
+  String OFFSETS_VECTOR_NAME = "$offsets$";
+  String VALUES_VECTOR_NAME = "$values$";
+
   /**
    * Allocate new buffers. ValueVector implements logic to determine how much to allocate.
    * @throws OutOfMemoryException Thrown if no memory can be allocated.

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/VariableWidthVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/VariableWidthVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/VariableWidthVector.java
index f5373d0..1e77417 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/VariableWidthVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/VariableWidthVector.java
@@ -17,8 +17,24 @@
  */
 package org.apache.drill.exec.vector;
 
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.types.Types;
+import org.apache.drill.exec.record.MaterializedField;
+
 public interface VariableWidthVector extends ValueVector {
 
+  int DEFAULT_RECORD_BYTE_COUNT = 8;
+  int MIN_BYTE_COUNT = 4096;
+  MaterializedField offsetsField = MaterializedField.create(OFFSETS_VECTOR_NAME, Types.required(MinorType.UINT4));
+
+  interface VariableWidthAccessor extends Accessor {
+    int getValueLength(int index);
+  }
+
+  interface VariableWidthMutator extends Mutator {
+    void setValueLengthSafe(int index, int length);
+  }
+
   /**
    * Allocate a new memory space for this vector.  Must be called prior to using the ValueVector.
    *
@@ -39,13 +55,7 @@ public interface VariableWidthVector extends ValueVector {
   @Override
   VariableWidthAccessor getAccessor();
 
-  interface VariableWidthAccessor extends Accessor {
-    int getValueLength(int index);
-  }
-
   int getCurrentSizeInBytes();
 
-  interface VariableWidthMutator extends Mutator {
-    void setValueLengthSafe(int index, int length);
-  }
+  UInt4Vector getOffsetVector();
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/AbstractMapVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/AbstractMapVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/AbstractMapVector.java
index 5ac28c5..5515b7a 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/AbstractMapVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/AbstractMapVector.java
@@ -36,7 +36,7 @@ import org.apache.drill.exec.vector.ValueVector;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
-/*
+/**
  * Base class for MapVectors. Currently used by RepeatedMapVector and MapVector
  */
 public abstract class AbstractMapVector extends AbstractContainerVector {
@@ -47,14 +47,14 @@ public abstract class AbstractMapVector extends AbstractContainerVector {
 
   protected AbstractMapVector(MaterializedField field, BufferAllocator allocator, CallBack callBack) {
     super(field.clone(), allocator, callBack);
-    MaterializedField clonedField = field.clone();
     // create the hierarchy of the child vectors based on the materialized field
-    for (MaterializedField child : clonedField.getChildren()) {
-      if (!child.equals(BaseRepeatedValueVector.OFFSETS_FIELD)) {
-        final String fieldName = child.getName();
-        final ValueVector v = BasicTypeHelper.getNewVector(child, allocator, callBack);
-        putVector(fieldName, v);
+    for (MaterializedField child : field.getChildren()) {
+      if (child.getName().equals(BaseRepeatedValueVector.OFFSETS_FIELD.getName())) {
+        continue;
       }
+      final String fieldName = child.getName();
+      final ValueVector v = BasicTypeHelper.getNewVector(child, allocator, callBack);
+      putVector(fieldName, v);
     }
   }
 
@@ -77,13 +77,13 @@ public abstract class AbstractMapVector extends AbstractContainerVector {
     boolean success = false;
     try {
       for (final ValueVector v : vectors.values()) {
-        if (!v.allocateNewSafe()) {
+        if (! v.allocateNewSafe()) {
           return false;
         }
       }
       success = true;
     } finally {
-      if (!success) {
+      if (! success) {
         clear();
       }
     }
@@ -145,7 +145,7 @@ public abstract class AbstractMapVector extends AbstractContainerVector {
 
   private boolean nullFilled(ValueVector vector) {
     for (int r = 0; r < vector.getAccessor().getValueCount(); r++) {
-      if (!vector.getAccessor().isNull(r)) {
+      if (! vector.getAccessor().isNull(r)) {
         return false;
       }
     }
@@ -304,4 +304,17 @@ public abstract class AbstractMapVector extends AbstractContainerVector {
     }
     return count;
   }
+
+  @Override
+  public void exchange(ValueVector other) {
+    AbstractMapVector otherMap = (AbstractMapVector) other;
+    if (vectors.size() != otherMap.vectors.size()) {
+      throw new IllegalStateException("Maps have different column counts");
+    }
+    for (int i = 0; i < vectors.size(); i++) {
+      assert vectors.getByOrdinal(i).getField().isEquivalent(
+          otherMap.vectors.getByOrdinal(i).getField());
+      vectors.getByOrdinal(i).exchange(otherMap.vectors.getByOrdinal(i));
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/e791ed62/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/BaseRepeatedValueVector.java
----------------------------------------------------------------------
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/BaseRepeatedValueVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/BaseRepeatedValueVector.java
index 8472f80..4b0c1b5 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/BaseRepeatedValueVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/complex/BaseRepeatedValueVector.java
@@ -85,7 +85,6 @@ public abstract class BaseRepeatedValueVector extends BaseValueVector implements
     return success;
   }
 
-
   @Override
   public UInt4Vector getOffsetVector() { return offsets; }