add not-null function to the output of autoidgeneration; allow record merge to handle null/union types
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
index c06c5a9..2f90e92 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
@@ -85,9 +85,10 @@
         ILogicalExpression rec0 = new VariableReferenceExpression(inputRecord);
         ILogicalExpression rec1 = createPrimaryKeyRecordExpression(pkFieldName);
         ILogicalExpression mergedRec = createRecordMergeFunction(rec0, rec1);
+        ILogicalExpression nonNullMergedRec = createNotNullFunction(mergedRec);
 
         LogicalVariable v = context.newVar();
-        AssignOperator newAssign = new AssignOperator(v, new MutableObject<ILogicalExpression>(mergedRec));
+        AssignOperator newAssign = new AssignOperator(v, new MutableObject<ILogicalExpression>(nonNullMergedRec));
         newAssign.getInputs().add(new MutableObject<ILogicalOperator>(projectOp));
         assignOp.getInputs().set(0, new MutableObject<ILogicalOperator>(newAssign));
         VariableUtilities.substituteVariables(assignOp, inputRecord, v, context);
@@ -102,6 +103,14 @@
         return true;
     }
 
+    private ILogicalExpression createNotNullFunction(ILogicalExpression mergedRec) {
+        List<Mutable<ILogicalExpression>> args = new ArrayList<>();
+        args.add(new MutableObject<ILogicalExpression>(mergedRec));
+        AbstractFunctionCallExpression notNullFn = new ScalarFunctionCallExpression(
+                FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.NOT_NULL), args);
+        return notNullFn;
+    }
+
     private AbstractFunctionCallExpression createPrimaryKeyRecordExpression(String pkFieldName) {
         AbstractFunctionCallExpression uuidFn = new ScalarFunctionCallExpression(
                 FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.CREATE_UUID));
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/RecordMergeTypeComputer.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/RecordMergeTypeComputer.java
index d9aa939..f663d50 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/RecordMergeTypeComputer.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/RecordMergeTypeComputer.java
@@ -26,7 +26,7 @@
     private RecordMergeTypeComputer() {
     }
 
-    private ARecordType extractRecordType(IAType t) {
+    public static ARecordType extractRecordType(IAType t) {
         if (t.getTypeTag() == ATypeTag.RECORD) {
             return (ARecordType) t;
         }
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/RecordMergeDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/RecordMergeDescriptor.java
index 7b2f211..f3cbf1d 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/RecordMergeDescriptor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/RecordMergeDescriptor.java
@@ -4,18 +4,26 @@
 
 import edu.uci.ics.asterix.builders.RecordBuilder;
 import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.ANull;
 import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
 import edu.uci.ics.asterix.om.functions.IFunctionDescriptor;
 import edu.uci.ics.asterix.om.functions.IFunctionDescriptorFactory;
 import edu.uci.ics.asterix.om.pointables.ARecordPointable;
 import edu.uci.ics.asterix.om.pointables.PointableAllocator;
 import edu.uci.ics.asterix.om.pointables.base.IVisitablePointable;
+import edu.uci.ics.asterix.om.typecomputer.impl.RecordMergeTypeComputer;
 import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
 import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluator;
 import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
 import edu.uci.ics.hyracks.data.std.api.IDataOutputProvider;
 import edu.uci.ics.hyracks.data.std.primitive.UTF8StringPointable;
 import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
@@ -26,6 +34,8 @@
 
     private static final long serialVersionUID = 1L;
 
+    private static final byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+
     public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
         public IFunctionDescriptor createFunctionDescriptor() {
             return new RecordMergeDescriptor();
@@ -36,10 +46,10 @@
     private ARecordType inRecType0;
     private ARecordType inRecType1;
 
-    public void reset(ARecordType outRecType, ARecordType inRecType0, ARecordType inRecType1) {
-        this.outRecType = outRecType;
-        this.inRecType0 = inRecType0;
-        this.inRecType1 = inRecType1;
+    public void reset(IAType outType, IAType inType0, IAType inType1) {
+        this.outRecType = RecordMergeTypeComputer.extractRecordType(outType);
+        this.inRecType0 = RecordMergeTypeComputer.extractRecordType(inType0);
+        this.inRecType1 = RecordMergeTypeComputer.extractRecordType(inType1);
     }
 
     @Override
@@ -50,6 +60,10 @@
 
             private final ARecordType recType = RecordMergeDescriptor.this.outRecType;
 
+            @SuppressWarnings("unchecked")
+            private final ISerializerDeserializer<ANull> nullSerDe = AqlSerializerDeserializerProvider.INSTANCE
+                    .getSerializerDeserializer(BuiltinType.ANULL);
+
             @Override
             public ICopyEvaluator createEvaluator(final IDataOutputProvider output) throws AlgebricksException {
                 final PointableAllocator pa = new PointableAllocator();
@@ -74,6 +88,17 @@
 
                         eval0.evaluate(tuple);
                         eval1.evaluate(tuple);
+
+                        if (abvs0.getByteArray()[0] == SER_NULL_TYPE_TAG
+                                || abvs1.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+                            try {
+                                nullSerDe.serialize(ANull.NULL, output.getDataOutput());
+                            } catch (HyracksDataException e) {
+                                throw new AlgebricksException(e);
+                            }
+                            return;
+                        }
+
                         vp0.set(abvs0);
                         vp1.set(abvs1);
 
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
index 9cecaaa..ea75c77 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
@@ -731,10 +731,10 @@
         }
         if (fd.getIdentifier().equals(AsterixBuiltinFunctions.RECORD_MERGE)) {
             AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) expr;
-            ARecordType outRecType = (ARecordType) context.getType(expr);
-            ARecordType recType0 = (ARecordType) context.getType(f.getArguments().get(0).getValue());
-            ARecordType recType1 = (ARecordType) context.getType(f.getArguments().get(1).getValue());
-            ((RecordMergeDescriptor) fd).reset(outRecType, recType0, recType1);
+            IAType outType = (IAType) context.getType(expr);
+            IAType type0 = (IAType) context.getType(f.getArguments().get(0).getValue());
+            IAType type1 = (IAType) context.getType(f.getArguments().get(1).getValue());
+            ((RecordMergeDescriptor) fd).reset(outType, type0, type1);
         }
         if (fd.getIdentifier().equals(AsterixBuiltinFunctions.CAST_RECORD)) {
             AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;