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;