>From Ali Alsuliman <[email protected]>:

Ali Alsuliman has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18385 )


Change subject: WIP: auto generated key
......................................................................

WIP: auto generated key

Change-Id: I54cc2fe65d7a5d2534a2c5b9a2fb6de5448ddc98
---
M 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
A 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyEvaluator.java
M asterixdb/asterix-app/src/test/resources/runtimets/only_sqlpp.xml
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
M 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
A 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AddAutoKeyTypeComputer.java
M 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
A 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyDescriptor.java
8 files changed, 483 insertions(+), 1 deletion(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/85/18385/1

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
index 1fb035f..e2b0b94 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceAutogenerateIDRule.java
@@ -160,7 +160,8 @@
         VariableReferenceExpression rec0 = new 
VariableReferenceExpression(inputRecord);
         rec0.setSourceLocation(inputRecordSourceLoc);
         ILogicalExpression rec1 = 
createPrimaryKeyRecordExpression(pkFieldName, insertOpSourceLoc);
-        ILogicalExpression mergedRec = createRecordMergeFunction(rec0, rec1, 
insertOpSourceLoc);
+        //        ILogicalExpression mergedRec = 
createRecordMergeFunction(rec0, pkFieldNameExpression, insertOpSourceLoc);
+        ILogicalExpression mergedRec = createAddAutoKeyFunction(rec0, 
pkFieldName, insertOpSourceLoc);
         ILogicalExpression nonNullMergedRec = createNotNullFunction(mergedRec);

         LogicalVariable v = context.newVar();
@@ -237,4 +238,20 @@
         recordMergeFn.setSourceLocation(sourceLoc);
         return recordMergeFn;
     }
+
+    private AbstractFunctionCallExpression 
createAddAutoKeyFunction(ILogicalExpression rec0, List<String> keyName,
+            SourceLocation sourceLoc) {
+        List<Mutable<ILogicalExpression>> addAutoKeyFnArgs = new ArrayList<>();
+        addAutoKeyFnArgs.add(new MutableObject<>(rec0));
+        for (String s : keyName) {
+            ConstantExpression pkFieldNameExpression = new 
ConstantExpression(new AsterixConstantValue(new AString(s)));
+            pkFieldNameExpression.setSourceLocation(sourceLoc);
+            addAutoKeyFnArgs.add(new MutableObject<>(pkFieldNameExpression));
+        }
+
+        AbstractFunctionCallExpression addAutoKeyFn = new 
ScalarFunctionCallExpression(
+                FunctionUtil.getFunctionInfo(BuiltinFunctions.ADD_AUTO_KEY), 
addAutoKeyFnArgs);
+        addAutoKeyFn.setSourceLocation(sourceLoc);
+        return addAutoKeyFn;
+    }
 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/only_sqlpp.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/only_sqlpp.xml
index 334dd52..08f98f3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/only_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/only_sqlpp.xml
@@ -19,5 +19,10 @@
  !-->
 <test-suite xmlns="urn:xml.testframework.asterix.apache.org" 
ResultOffsetPath="results" QueryOffsetPath="queries_sqlpp" 
QueryFileExtension=".sqlpp">
   <test-group name="failed">
+    <test-case FilePath="nested-index-dml">
+      <compilation-unit name="nested-uuid-insert">
+        <output-dir compare="Text">nested-uuid-insert</output-dir>
+      </compilation-unit>
+    </test-case>
   </test-group>
 </test-suite>
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index c65cf38..a8d3b3ba 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -65,6 +65,7 @@
 import org.apache.asterix.om.typecomputer.impl.ATimeTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.AUUIDTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.AYearMonthDurationTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.AddAutoKeyTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.AnyTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.ArrayExceptTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.ArrayIfNullTypeComputer;
@@ -245,6 +246,8 @@
     public static final FunctionIdentifier RECORD_MERGE = 
FunctionConstants.newAsterix("object-merge", 2);
     public static final FunctionIdentifier RECORD_MERGE_IGNORE_DUPLICATES =
             FunctionConstants.newAsterix("object-merge-ignore-duplicates", 2);
+    public static final FunctionIdentifier ADD_AUTO_KEY =
+            FunctionConstants.newAsterix("add-autogenerated-key", 
FunctionIdentifier.VARARGS);
     public static final FunctionIdentifier RECORD_CONCAT =
             FunctionConstants.newAsterix("object-concat", 
FunctionIdentifier.VARARGS);
     public static final FunctionIdentifier RECORD_CONCAT_STRICT =
@@ -2002,6 +2005,7 @@
         // objects
         addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true);
         addPrivateFunction(RECORD_MERGE_IGNORE_DUPLICATES, 
RecordMergeTypeComputer.INSTANCE_IGNORE_DUPLICATES, true);
+        addPrivateFunction(ADD_AUTO_KEY, AddAutoKeyTypeComputer.INSTANCE, 
true);
         addFunction(RECORD_CONCAT, OpenARecordTypeComputer.INSTANCE, true);
         addPrivateFunction(RECORD_CONCAT_STRICT, 
OpenARecordTypeComputer.INSTANCE, true);
         addFunction(ADD_FIELDS, RecordAddFieldsTypeComputer.INSTANCE, true);
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AddAutoKeyTypeComputer.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AddAutoKeyTypeComputer.java
new file mode 100644
index 0000000..57a482b
--- /dev/null
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AddAutoKeyTypeComputer.java
@@ -0,0 +1,132 @@
+/*
+ * 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.asterix.om.typecomputer.impl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.exceptions.TypeMismatchException;
+import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.TypeHelper;
+import org.apache.asterix.om.utils.ConstantExpressionUtil;
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+public class AddAutoKeyTypeComputer implements IResultTypeComputer {
+
+    public static final AddAutoKeyTypeComputer INSTANCE = new 
AddAutoKeyTypeComputer();
+
+    private AddAutoKeyTypeComputer() {
+    }
+
+    @Override
+    public IAType computeType(ILogicalExpression expression, 
IVariableTypeEnvironment env,
+            IMetadataProvider<?, ?> metadataProvider) throws 
AlgebricksException {
+        AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) 
expression;
+        FunctionIdentifier funcId = f.getFunctionIdentifier();
+        List<Mutable<ILogicalExpression>> funArgs = f.getArguments();
+        IAType arg0Type = (IAType) env.getType(funArgs.get(0).getValue());
+        boolean unknownable = TypeHelper.canBeUnknown(arg0Type);
+        ARecordType inRecType = TypeComputeUtils.extractRecordType(arg0Type);
+        if (inRecType == null) {
+            throw new TypeMismatchException(f.getSourceLocation(), funcId, 0, 
arg0Type.getTypeTag(), ATypeTag.OBJECT);
+        }
+
+        String[] keyName = validateGetKeyName(funArgs);
+        return computeType(inRecType, keyName, unknownable, 
f.getSourceLocation());
+    }
+
+    private static String[] 
validateGetKeyName(List<Mutable<ILogicalExpression>> funArgs) {
+        String[] keyName = new String[funArgs.size() - 1];
+        for (int i = 1, k = 0; i < funArgs.size(); i++, k++) {
+            keyName[k] = 
ConstantExpressionUtil.getStringConstant(funArgs.get(i).getValue());
+        }
+        return keyName;
+    }
+
+    private static IAType computeType(ARecordType inRecType, String[] keyName, 
boolean unknownable,
+            SourceLocation sourceLocation) throws AlgebricksException {
+
+        String[] inFieldNames = inRecType.getFieldNames();
+        String[] resultFieldNames = Arrays.copyOf(inFieldNames, 
inFieldNames.length);
+
+        IAType[] resultFieldTypes = new IAType[resultFieldNames.length];
+        for (int i = 0; i < resultFieldNames.length; i++) {
+            IAType fieldType = inRecType.getFieldType(resultFieldNames[i]);
+            if (fieldType.getTypeTag() == ATypeTag.OBJECT) {
+                ARecordType nestedType = (ARecordType) fieldType;
+                // deep copy prevents altering of input types
+                resultFieldTypes[i] = nestedType.deepCopy(nestedType);
+            } else {
+                resultFieldTypes[i] = fieldType;
+            }
+        }
+
+        ARecordType recType = inRecType;
+        IAType fieldType = recType.getFieldType(keyName[0]);
+        int i = 1;
+        for (; i < keyName.length; i++) {
+            ARecordType subRec = null;
+            if (fieldType == null || (subRec = getSubRec(fieldType)) == null) {
+                break;
+            }
+            recType = subRec;
+            fieldType = subRec.getFieldType(keyName[i]);
+        }
+        boolean pkFieldMissing;
+        if (fieldType == null || i != keyName.length) {
+            // make sure the recType is "open" to allow adding the pk field
+            pkFieldMissing = true;
+            // if the recType is not open, then indicate that the record 
should be cast to open
+        } else {
+            // make sure the fieldType is UUID?
+            pkFieldMissing = false;
+        }
+
+        boolean isOpen = inRecType.isOpen() || pkFieldMissing;
+        IAType resultType = new ARecordType("", resultFieldNames, 
resultFieldTypes, isOpen);
+
+        if (unknownable) {
+            resultType = AUnionType.createUnknownableType(resultType);
+        }
+        return resultType;
+    }
+
+    private static ARecordType getSubRec(IAType fieldType) {
+        IAType t = fieldType;
+        if (fieldType.getTypeTag() == ATypeTag.UNION) {
+            t = ((AUnionType) fieldType).getActualType();
+        }
+        if (t.getTypeTag() == ATypeTag.OBJECT) {
+            return (ARecordType) t;
+        }
+        return null;
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyDescriptor.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyDescriptor.java
new file mode 100644
index 0000000..f97d1df
--- /dev/null
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyDescriptor.java
@@ -0,0 +1,76 @@
+/*
+ * 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.asterix.runtime.evaluators.functions.records;
+
+import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptor;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.functions.IFunctionTypeInferer;
+import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils;
+import org.apache.asterix.om.types.IAType;
+import 
org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.functions.FunctionTypeInferers;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+@MissingNullInOutFunction
+public class AddAutoKeyDescriptor extends 
AbstractScalarFunctionDynamicDescriptor {
+
+    public static final IFunctionDescriptorFactory FACTORY = new 
IFunctionDescriptorFactory() {
+        @Override
+        public IFunctionDescriptor createFunctionDescriptor() {
+            return new AddAutoKeyDescriptor();
+        }
+
+        @Override
+        public IFunctionTypeInferer createFunctionTypeInferer() {
+            return new FunctionTypeInferers.AddAutoKeyTypeInferer();
+        }
+    };
+
+    private static final long serialVersionUID = 1L;
+    private final IAType[] argTypes = new IAType[2];
+
+    @Override
+    public void setImmutableStates(Object... states) {
+        argTypes[0] = TypeComputeUtils.extractRecordType((IAType) states[0]);
+        argTypes[1] = TypeComputeUtils.extractRecordType((IAType) states[1]);
+    }
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(final 
IScalarEvaluatorFactory[] args) {
+        return new IScalarEvaluatorFactory() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public IScalarEvaluator createScalarEvaluator(final 
IEvaluatorContext ctx) throws HyracksDataException {
+                return new AddAutoKeyEvaluator(ctx, args, argTypes, sourceLoc, 
getIdentifier());
+            }
+        };
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ADD_AUTO_KEY;
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyEvaluator.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyEvaluator.java
new file mode 100644
index 0000000..24b465d
--- /dev/null
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AddAutoKeyEvaluator.java
@@ -0,0 +1,225 @@
+/*
+ * 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.asterix.runtime.evaluators.functions.records;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.builders.RecordBuilder;
+import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
+import org.apache.asterix.om.base.AGeneratedUUID;
+import org.apache.asterix.om.base.AUUID;
+import org.apache.asterix.om.pointables.ARecordVisitablePointable;
+import org.apache.asterix.om.pointables.PointableAllocator;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.pointables.base.IVisitablePointable;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.runtime.RuntimeRecordTypeInfo;
+import org.apache.asterix.runtime.evaluators.comparisons.DeepEqualAssessor;
+import org.apache.asterix.runtime.evaluators.functions.AbstractScalarEval;
+import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.dataflow.value.IBinaryComparator;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+import org.apache.hyracks.data.std.accessors.UTF8StringBinaryComparatorFactory;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class AddAutoKeyEvaluator extends AbstractScalarEval {
+
+    private final ARecordType outRecType;
+
+    private final IVisitablePointable vp0;
+
+    private final IPointable argPtr0 = new VoidPointable();
+    private final IPointable argPtr1 = new VoidPointable();
+    private final IPointable str = new VoidPointable();
+
+    private final IScalarEvaluator eval0;
+    private final IScalarEvaluator evals[];
+
+    private final List<RecordBuilder> rbStack = new ArrayList<>();
+
+    private final ArrayBackedValueStorage tabvs = new 
ArrayBackedValueStorage();
+    private final IBinaryComparator stringBinaryComparator =
+            
UTF8StringBinaryComparatorFactory.INSTANCE.createBinaryComparator();
+
+    private final RuntimeRecordTypeInfo runtimeRecordTypeInfo = new 
RuntimeRecordTypeInfo();
+    private final DeepEqualAssessor deepEqualAssessor = new 
DeepEqualAssessor();
+    private final ArrayBackedValueStorage resultStorage = new 
ArrayBackedValueStorage();
+    private final DataOutput out = resultStorage.getDataOutput();
+
+    private final ArrayBackedValueStorage uuidStorage = new 
ArrayBackedValueStorage();
+    private final DataOutput uuidOut = uuidStorage.getDataOutput();
+    private final AGeneratedUUID uuid = new AGeneratedUUID();
+    private final ISerializerDeserializer<AUUID> uuidSerDe =
+            
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AUUID);
+    private final ARecordType inRecType0;
+    private final PointableAllocator pa;
+    private final ARecordVisitablePointable dummy;
+
+    AddAutoKeyEvaluator(IEvaluatorContext ctx, IScalarEvaluatorFactory[] args, 
IAType[] argTypes,
+            SourceLocation sourceLocation, FunctionIdentifier identifier) 
throws HyracksDataException {
+        super(sourceLocation, identifier);
+        eval0 = args[0].createScalarEvaluator(ctx);
+        evals = new IScalarEvaluator[args.length - 1];
+        for (int i = 1, e = 0; i < args.length; i++, e++) {
+            evals[e] = args[i].createScalarEvaluator(ctx);
+        }
+
+        outRecType = (ARecordType) argTypes[0];
+        inRecType0 = (ARecordType) argTypes[1];
+        pa = new PointableAllocator();
+        vp0 = pa.allocateRecordValue(inRecType0);
+        dummy = 
pa.allocateRecordValue(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws 
HyracksDataException {
+        resultStorage.reset();
+        eval0.evaluate(tuple, argPtr0);
+
+        if (PointableHelper.checkAndSetMissingOrNull(result, argPtr0)) {
+            return;
+        }
+
+        vp0.set(argPtr0);
+
+        ARecordVisitablePointable rp0 = (ARecordVisitablePointable) vp0;
+
+        try {
+            mergeFields(outRecType, rp0, null, 0, tuple);
+            rbStack.get(0).write(out, true);
+        } catch (IOException e) {
+            throw HyracksDataException.create(e);
+        }
+        result.set(resultStorage);
+    }
+
+    private void mergeFields(ARecordType combinedType, 
ARecordVisitablePointable leftRecord,
+            ARecordVisitablePointable rightRecord, int nestedLevel, 
IFrameTupleReference tuple) throws IOException {
+        if (rbStack.size() < (nestedLevel + 1)) {
+            rbStack.add(new RecordBuilder());
+        }
+
+        rbStack.get(nestedLevel).reset(combinedType);
+        rbStack.get(nestedLevel).init();
+
+        evals[nestedLevel].evaluate(tuple, str);
+        // Add all fields from left record
+        boolean foundMatch = false;
+        for (int i = 0; i < leftRecord.getFieldNames().size(); i++) {
+            IVisitablePointable leftName = leftRecord.getFieldNames().get(i);
+            IVisitablePointable leftValue = leftRecord.getFieldValues().get(i);
+            IVisitablePointable leftType = 
leftRecord.getFieldTypeTags().get(i);
+
+            if (PointableHelper.isEqual(leftName, str, 
stringBinaryComparator)) {
+                foundMatch = true;
+                if (nestedLevel == evals.length - 1) {
+                    if (PointableHelper.sameType(ATypeTag.OBJECT, leftType)) {
+                        // throw
+                        throw new IOException("last field is not supposed to 
be a record");
+                    }
+                    if (!PointableHelper.sameType(ATypeTag.UUID, leftType)) {
+                        // throw
+                        throw new IOException("last field is not UUID");
+                    }
+                    addFieldToSubRecord(combinedType, leftName, leftValue, 
null, nestedLevel, tuple);
+                } else {
+                    if (!PointableHelper.sameType(ATypeTag.OBJECT, leftType)) {
+                        // throw
+                        throw new IOException("intermediate field is not a 
record");
+                    }
+                    // we are merging two sub records
+                    addFieldToSubRecord(combinedType, leftName, leftValue, 
dummy, nestedLevel, tuple);
+                }
+            } else {
+                addFieldToSubRecord(combinedType, leftName, leftValue, null, 
nestedLevel, tuple);
+            }
+        }
+        if (!foundMatch) {
+            IVisitablePointable strVisitable = 
pa.allocateFieldValue(BuiltinType.ASTRING);
+            strVisitable.set(str);
+            if (nestedLevel == evals.length - 1) {
+                IVisitablePointable uuidVis = 
pa.allocateFieldValue(BuiltinType.AUUID);
+                uuidStorage.reset();
+                uuid.nextUUID();
+                uuidSerDe.serialize(uuid, uuidOut);
+                uuidVis.set(uuidStorage);
+                addFieldToSubRecord(combinedType, strVisitable, uuidVis, null, 
nestedLevel, tuple);
+            } else {
+                addFieldToSubRecord(combinedType, strVisitable,
+                        
pa.allocateRecordValue(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE), dummy, 
nestedLevel,
+                        tuple);
+            }
+        }
+    }
+
+    /*
+     * Takes in a record type, field name, and the field values (which are 
record) from two records
+     * Merges them into one record of combinedType
+     * And adds that record as a field to the Record in subrb
+     * the second value can be null, indicated that you just add the value of 
left as a field to subrb
+     *
+     */
+    private void addFieldToSubRecord(ARecordType combinedType, 
IVisitablePointable fieldNamePointable,
+            IVisitablePointable leftValue, IVisitablePointable rightValue, int 
nestedLevel, IFrameTupleReference tuple)
+            throws IOException {
+
+        runtimeRecordTypeInfo.reset(combinedType);
+        int pos = 
runtimeRecordTypeInfo.getFieldIndex(fieldNamePointable.getByteArray(),
+                fieldNamePointable.getStartOffset() + 1, 
fieldNamePointable.getLength() - 1);
+
+        //Add the merged field
+        if (combinedType != null && pos >= 0) {
+            if (rightValue == null) {
+                rbStack.get(nestedLevel).addField(pos, leftValue);
+            } else {
+                mergeFields((ARecordType) combinedType.getFieldTypes()[pos], 
(ARecordVisitablePointable) leftValue,
+                        (ARecordVisitablePointable) rightValue, nestedLevel + 
1, tuple);
+
+                tabvs.reset();
+                rbStack.get(nestedLevel + 1).write(tabvs.getDataOutput(), 
true);
+                rbStack.get(nestedLevel).addField(pos, tabvs);
+            }
+        } else {
+            if (rightValue == null) {
+                rbStack.get(nestedLevel).addField(fieldNamePointable, 
leftValue);
+            } else {
+                mergeFields(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE, 
(ARecordVisitablePointable) leftValue,
+                        (ARecordVisitablePointable) rightValue, nestedLevel + 
1, tuple);
+                tabvs.reset();
+                rbStack.get(nestedLevel + 1).write(tabvs.getDataOutput(), 
true);
+                rbStack.get(nestedLevel).addField(fieldNamePointable, tabvs);
+            }
+        }
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
index 7001c25..9ea99a6 100644
--- 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
@@ -535,6 +535,7 @@
 import 
org.apache.asterix.runtime.evaluators.functions.bitwise.BitXorDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.bitwise.IsBitSetWithAllFlagDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.bitwise.IsBitSetWithoutAllFlagDescriptor;
+import 
org.apache.asterix.runtime.evaluators.functions.records.AddAutoKeyDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.FieldAccessByIndexDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.FieldAccessByNameDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.FieldAccessNestedDescriptor;
@@ -1200,6 +1201,7 @@
         fc.add(DeepEqualityDescriptor.FACTORY);
         fc.add(RecordMergeDescriptor.FACTORY);
         fc.add(RecordMergeIgnoreDuplicatesDescriptor.FACTORY);
+        fc.add(AddAutoKeyDescriptor.FACTORY);
         fc.add(RecordAddFieldsDescriptor.FACTORY);
         fc.add(RecordRemoveFieldsDescriptor.FACTORY);
         fc.add(RecordLengthDescriptor.FACTORY);
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
index 9c25f6e..067ef1a 100644
--- 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
@@ -302,6 +302,18 @@
         }
     }

+    public static final class AddAutoKeyTypeInferer implements 
IFunctionTypeInferer {
+        @Override
+        public void infer(ILogicalExpression expr, IFunctionDescriptor fd, 
IVariableTypeEnvironment context,
+                CompilerProperties compilerProps) throws AlgebricksException {
+            AbstractFunctionCallExpression f = 
(AbstractFunctionCallExpression) expr;
+            IAType outType = (IAType) context.getType(expr);
+            IAType type0 = (IAType) 
context.getType(f.getArguments().get(0).getValue());
+            // check the key name
+            fd.setImmutableStates(outType, type0);
+        }
+    }
+
     public static final class RecordRemoveFieldsTypeInferer implements 
IFunctionTypeInferer {
         @Override
         public void infer(ILogicalExpression expr, IFunctionDescriptor fd, 
IVariableTypeEnvironment context,

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18385
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: I54cc2fe65d7a5d2534a2c5b9a2fb6de5448ddc98
Gerrit-Change-Number: 18385
Gerrit-PatchSet: 1
Gerrit-Owner: Ali Alsuliman <[email protected]>
Gerrit-MessageType: newchange

Reply via email to