This is an automated email from the ASF dual-hosted git repository.

alsuliman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 4a2bd9a746 [ASTERIXDB-3444][COMP] Add put-autogenerated-key() function
4a2bd9a746 is described below

commit 4a2bd9a746d514c570b8057e73f10e3f9aade764
Author: Ali Alsuliman <ali.al.solai...@gmail.com>
AuthorDate: Sat Jun 22 01:19:43 2024 +0300

    [ASTERIXDB-3444][COMP] Add put-autogenerated-key() function
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Details:
    - Add a new internal function 'put-autogenerated-key()' to be
      used when updating collections using autogenerated keys.
    - Use the function in place of 'object-merge-ignore-duplicates()'
    
    Change-Id: I54cc2fe65d7a5d2534a2c5b9a2fb6de5448ddc98
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18385
    Reviewed-by: Ali Alsuliman <ali.al.solai...@gmail.com>
    Reviewed-by: Wail Alkowaileet <wael....@gmail.com>
    Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
    Tested-by: Ali Alsuliman <ali.al.solai...@gmail.com>
---
 .../asterix/optimizer/base/RuleCollections.java    |   1 +
 .../rules/IntroduceAutogenerateIDRule.java         |  61 ++----
 .../auto_key/nested-type/nested-type.1.ddl.sqlpp   |  25 +++
 .../auto_key/nested-type/nested-type.2.ddl.sqlpp   |  26 +++
 .../auto_key/nested-type/nested-type.3.query.sqlpp |  21 ++
 .../auto_key/nested-type/nested-type.4.query.sqlpp |  21 ++
 .../auto_key/nested-type/nested-type.5.query.sqlpp |  21 ++
 .../auto_key/nested-type/nested-type.9.ddl.sqlpp   |  20 ++
 .../auto_key/simple-type/simple-type.1.ddl.sqlpp   |  27 +++
 .../auto_key/simple-type/simple-type.2.ddl.sqlpp   |  22 +++
 .../auto_key/simple-type/simple-type.3.ddl.sqlpp   |  21 ++
 .../auto_key/simple-type/simple-type.4.ddl.sqlpp   | 124 ++++++++++++
 .../auto_key/simple-type/simple-type.5.query.sqlpp |  21 ++
 .../auto_key/simple-type/simple-type.6.query.sqlpp |  21 ++
 .../auto_key/simple-type/simple-type.9.ddl.sqlpp   |  20 ++
 .../results/auto_key/nested-type/nested-type.3.adm |   1 +
 .../results/auto_key/nested-type/nested-type.4.adm |   1 +
 .../results/auto_key/nested-type/nested-type.5.adm |   1 +
 .../results/auto_key/simple-type/simple-type.5.adm |   1 +
 .../results/auto_key/simple-type/simple-type.6.adm |   1 +
 .../src/test/resources/runtimets/sqlpp_queries.xml |  18 ++
 .../asterix/om/functions/BuiltinFunctions.java     |   7 +
 .../impl/PutAutogeneratedKeyTypeComputer.java      | 158 +++++++++++++++
 .../records/PutAutogeneratedKeyDescriptor.java     |  80 ++++++++
 .../records/PutAutogeneratedKeyEvaluator.java      | 215 +++++++++++++++++++++
 .../runtime/functions/FunctionCollection.java      |   2 +
 .../runtime/functions/FunctionTypeInferers.java    |  11 ++
 27 files changed, 904 insertions(+), 44 deletions(-)

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
index 67dab65c9d..5209b3eb5e 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
@@ -465,6 +465,7 @@ public final class RuleCollections {
         prepareForJobGenRewrites.add(new FixReplicateOperatorOutputsRule());
         prepareForJobGenRewrites.add(new PopulateResultMetadataRule());
         prepareForJobGenRewrites.add(new 
AnnotateOperatorCostCardinalityRule());
+        prepareForJobGenRewrites.add(new EnsureColumnarSupportedTypesRule());
         return prepareForJobGenRewrites;
     }
 }
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 1fb035fdfc..f51e307970 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
@@ -159,15 +159,14 @@ public class IntroduceAutogenerateIDRule implements 
IAlgebraicRewriteRule {
                 ((InternalDatasetDetails) 
dds.getDataset().getDatasetDetails()).getPrimaryKey().get(0);
         VariableReferenceExpression rec0 = new 
VariableReferenceExpression(inputRecord);
         rec0.setSourceLocation(inputRecordSourceLoc);
-        ILogicalExpression rec1 = 
createPrimaryKeyRecordExpression(pkFieldName, insertOpSourceLoc);
-        ILogicalExpression mergedRec = createRecordMergeFunction(rec0, rec1, 
insertOpSourceLoc);
+        ILogicalExpression mergedRec = createPutAutogeneratedKeyFunction(rec0, 
pkFieldName, insertOpSourceLoc);
         ILogicalExpression nonNullMergedRec = createNotNullFunction(mergedRec);
 
         LogicalVariable v = context.newVar();
-        AssignOperator newAssign = new AssignOperator(v, new 
MutableObject<ILogicalExpression>(nonNullMergedRec));
+        AssignOperator newAssign = new AssignOperator(v, new 
MutableObject<>(nonNullMergedRec));
         newAssign.setSourceLocation(insertOpSourceLoc);
-        newAssign.getInputs().add(new 
MutableObject<ILogicalOperator>(newAssignParentOp));
-        newAssignChildOp.getInputs().set(0, new 
MutableObject<ILogicalOperator>(newAssign));
+        newAssign.getInputs().add(new MutableObject<>(newAssignParentOp));
+        newAssignChildOp.getInputs().set(0, new MutableObject<>(newAssign));
         if (hasFilter) {
             VariableUtilities.substituteVariables(newAssignChildOp, 
inputRecord, v, context);
         }
@@ -189,52 +188,26 @@ public class IntroduceAutogenerateIDRule implements 
IAlgebraicRewriteRule {
 
     private ILogicalExpression createNotNullFunction(ILogicalExpression 
mergedRec) {
         List<Mutable<ILogicalExpression>> args = new ArrayList<>();
-        args.add(new MutableObject<ILogicalExpression>(mergedRec));
+        args.add(new MutableObject<>(mergedRec));
         AbstractFunctionCallExpression notNullFn =
                 new 
ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CHECK_UNKNOWN),
 args);
         notNullFn.setSourceLocation(mergedRec.getSourceLocation());
         return notNullFn;
     }
 
-    private AbstractFunctionCallExpression 
createPrimaryKeyRecordExpression(List<String> pkFieldName,
-            SourceLocation sourceLoc) {
-        //Create lowest level of nested uuid
-        AbstractFunctionCallExpression uuidFn =
-                new 
ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CREATE_UUID));
-        uuidFn.setSourceLocation(sourceLoc);
-        List<Mutable<ILogicalExpression>> openRecordConsArgs = new 
ArrayList<>();
-        ConstantExpression pkFieldNameExpression =
-                new ConstantExpression(new AsterixConstantValue(new 
AString(pkFieldName.get(pkFieldName.size() - 1))));
-        pkFieldNameExpression.setSourceLocation(sourceLoc);
-        openRecordConsArgs.add(new MutableObject<>(pkFieldNameExpression));
-        openRecordConsArgs.add(new MutableObject<>(uuidFn));
-        AbstractFunctionCallExpression openRecFn = new 
ScalarFunctionCallExpression(
-                
FunctionUtil.getFunctionInfo(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR), 
openRecordConsArgs);
-        openRecFn.setSourceLocation(sourceLoc);
-
-        //Create higher levels
-        for (int i = pkFieldName.size() - 2; i > -1; i--) {
-            AString fieldName = new AString(pkFieldName.get(i));
-            openRecordConsArgs = new ArrayList<>();
-            openRecordConsArgs.add(
-                    new MutableObject<ILogicalExpression>(new 
ConstantExpression(new AsterixConstantValue(fieldName))));
-            openRecordConsArgs.add(new 
MutableObject<ILogicalExpression>(openRecFn));
-            openRecFn = new ScalarFunctionCallExpression(
-                    
FunctionUtil.getFunctionInfo(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR), 
openRecordConsArgs);
-            openRecFn.setSourceLocation(sourceLoc);
+    private AbstractFunctionCallExpression 
createPutAutogeneratedKeyFunction(ILogicalExpression rec0,
+            List<String> keyName, SourceLocation sourceLoc) {
+        List<Mutable<ILogicalExpression>> putAutogeneratedKeyFnArgs = new 
ArrayList<>();
+        putAutogeneratedKeyFnArgs.add(new MutableObject<>(rec0));
+        for (String s : keyName) {
+            ConstantExpression pkFieldNameExpression = new 
ConstantExpression(new AsterixConstantValue(new AString(s)));
+            pkFieldNameExpression.setSourceLocation(sourceLoc);
+            putAutogeneratedKeyFnArgs.add(new 
MutableObject<>(pkFieldNameExpression));
         }
 
-        return openRecFn;
-    }
-
-    private AbstractFunctionCallExpression 
createRecordMergeFunction(ILogicalExpression rec0, ILogicalExpression rec1,
-            SourceLocation sourceLoc) {
-        List<Mutable<ILogicalExpression>> recordMergeFnArgs = new 
ArrayList<>();
-        recordMergeFnArgs.add(new MutableObject<>(rec0));
-        recordMergeFnArgs.add(new MutableObject<>(rec1));
-        AbstractFunctionCallExpression recordMergeFn = new 
ScalarFunctionCallExpression(
-                
FunctionUtil.getFunctionInfo(BuiltinFunctions.RECORD_MERGE_IGNORE_DUPLICATES), 
recordMergeFnArgs);
-        recordMergeFn.setSourceLocation(sourceLoc);
-        return recordMergeFn;
+        AbstractFunctionCallExpression putAutogeneratedKeyFn = new 
ScalarFunctionCallExpression(
+                
FunctionUtil.getFunctionInfo(BuiltinFunctions.PUT_AUTOGENERATED_KEY), 
putAutogeneratedKeyFnArgs);
+        putAutogeneratedKeyFn.setSourceLocation(sourceLoc);
+        return putAutogeneratedKeyFn;
     }
 }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.1.ddl.sqlpp
new file mode 100644
index 0000000000..3ae1d7e893
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.1.ddl.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE COLLECTION c PRIMARY KEY (a.id: uuid) AUTOGENERATED;
+UPSERT INTO c ([{"name":"j", "a":{"id": uuid()}}, {"a":{"id":uuid()}}]);
+UPSERT INTO c ([{"name":"j", "a":{"id": uuid()}}, {"a":{"id":"a"}}]);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.2.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.2.ddl.sqlpp
new file mode 100644
index 0000000000..124746b601
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.2.ddl.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+USE test;
+
+CREATE TYPE openType AS {id: int};
+CREATE TYPE openType2 AS {id: int, myKey: uuid};
+CREATE DATASET ds(openType) PRIMARY KEY id;
+CREATE DATASET ds2(openType2) PRIMARY KEY myKey AUTOGENERATED;
+UPSERT INTO ds ([{"id": 1, "myKey": "xxxx"}, {"id": 2, "myKey": "yyyy"}]);
+UPSERT INTO ds2 SELECT VALUE v FROM ds v;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.3.query.sqlpp
new file mode 100644
index 0000000000..f9e0334012
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.3.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+USE test;
+
+SELECT COUNT(*) AS cnt FROM c;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.4.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.4.query.sqlpp
new file mode 100644
index 0000000000..7a5b1e0ac9
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.4.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+USE test;
+
+SELECT COUNT(*) AS cnt FROM ds;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.5.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.5.query.sqlpp
new file mode 100644
index 0000000000..812f2c5a8b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.5.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+USE test;
+
+SELECT COUNT(*) AS cnt FROM ds2;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.9.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.9.ddl.sqlpp
new file mode 100644
index 0000000000..36b2bab543
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/nested-type/nested-type.9.ddl.sqlpp
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.1.ddl.sqlpp
new file mode 100644
index 0000000000..2e3cbcbd3c
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.1.ddl.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE COLLECTION pk_auto PRIMARY KEY (myKey: uuid) AUTOGENERATED;
+CREATE COLLECTION pk_auto2 PRIMARY KEY (myKey: uuid) AUTOGENERATED;
+UPSERT INTO pk_auto ([ {"x": "a"}] );
+UPSERT INTO pk_auto ([{"myKey" :uuid()} , {"x": 5}] );
+UPSERT INTO pk_auto ([{"myKey" :"x"} , {"x": "abc"}] );
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.2.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.2.ddl.sqlpp
new file mode 100644
index 0000000000..81ceb399e6
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.2.ddl.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+USE test;
+
+UPSERT INTO pk_auto ([{"x": "abc","myKey": uuid(),"emp":{"age":23,"myKey":345 
}},{"myKey":uuid()}]);
+UPSERT INTO pk_auto ([{"x": "abc","myKey": 566,"emp":{"age":23,"myKey":345 
}},{"myKey":uuid()}]);
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.3.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.3.ddl.sqlpp
new file mode 100644
index 0000000000..b710bb60a2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.3.ddl.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+USE test;
+
+UPSERT INTO pk_auto ([{"x": "abc","myKey": uuid(),"emp":{"age":23,"myKey":345 
}},{"myKey":"abc"}]);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.4.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.4.ddl.sqlpp
new file mode 100644
index 0000000000..308402511d
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.4.ddl.sqlpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+USE test;
+
+UPSERT INTO pk_auto2 (
+[
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b6355d",
+    "callsign": "AIRLINAIR",
+    "country": "France",
+    "iata": "A5",
+    "icao": "RLA",
+    "id": 1203,
+    "name": "Airlinair",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b63555",
+    "callsign": "TXW",
+    "country": "United States",
+    "iata": "TQ",
+    "icao": "TXW",
+    "id": 10123,
+    "name": "Texas Wings",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b63556",
+    "callsign": "atifly",
+    "country": "United States",
+    "iata": "A1",
+    "icao": "A1F",
+    "id": 10226,
+    "name": "Atifly",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b6355a",
+    "callsign": "ACE AIR",
+    "country": "United States",
+    "iata": "KO",
+    "icao": "AER",
+    "id": 109,
+    "name": "Alaska Central Express",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b63559",
+    "callsign": "SASQUATCH",
+    "country": "United States",
+    "iata": "K5",
+    "icao": "SQH",
+    "id": 10765,
+    "name": "SeaPort Airlines",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b6355b",
+    "callsign": "FLYSTAR",
+    "country": "United Kingdom",
+    "iata": "5W",
+    "icao": "AEU",
+    "id": 112,
+    "name": "Astraeus",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b63558",
+    "callsign": "LOCAIR",
+    "country": "United States",
+    "iata": "ZQ",
+    "icao": "LOC",
+    "id": 10748,
+    "name": "Locair",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b63554",
+    "callsign": "MILE-AIR",
+    "country": "United States",
+    "iata": "Q5",
+    "icao": "MLA",
+    "id": 10,
+    "name": "40-Mile Air",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b63557",
+    "callsign": null,
+    "country": "United Kingdom",
+    "iata": null,
+    "icao": "JRB",
+    "id": 10642,
+    "name": "Jc royal.britannica",
+    "type": "airline"
+  },
+  {
+    "myKey": "2be3fcf4-f86b-09d0-4bf2-eac9d1b6355c",
+    "callsign": "REUNION",
+    "country": "France",
+    "iata": "UU",
+    "icao": "REU",
+    "id": 1191,
+    "name": "Air Austral",
+    "type": "airline"
+  }
+]
+);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.5.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.5.query.sqlpp
new file mode 100644
index 0000000000..43e184b665
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.5.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+USE test;
+
+SELECT COUNT(*) AS cnt FROM pk_auto;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.6.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.6.query.sqlpp
new file mode 100644
index 0000000000..2dc2e9c322
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.6.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+USE test;
+
+SELECT COUNT(*) AS cnt FROM pk_auto2;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.9.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.9.ddl.sqlpp
new file mode 100644
index 0000000000..36b2bab543
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/auto_key/simple-type/simple-type.9.ddl.sqlpp
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.3.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.3.adm
new file mode 100644
index 0000000000..3591912129
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.3.adm
@@ -0,0 +1 @@
+{ "cnt": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.4.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.4.adm
new file mode 100644
index 0000000000..3591912129
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.4.adm
@@ -0,0 +1 @@
+{ "cnt": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.5.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.5.adm
new file mode 100644
index 0000000000..bacb60c0e2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/nested-type/nested-type.5.adm
@@ -0,0 +1 @@
+{ "cnt": 0 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/simple-type/simple-type.5.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/simple-type/simple-type.5.adm
new file mode 100644
index 0000000000..c3bf580eb6
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/simple-type/simple-type.5.adm
@@ -0,0 +1 @@
+{ "cnt": 5 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/simple-type/simple-type.6.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/simple-type/simple-type.6.adm
new file mode 100644
index 0000000000..bacb60c0e2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/auto_key/simple-type/simple-type.6.adm
@@ -0,0 +1 @@
+{ "cnt": 0 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
index d476c25cd6..040b3ca874 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
@@ -16622,4 +16622,22 @@
       </compilation-unit>
     </test-case>
   </test-group>
+  <test-group name="auto_key">
+    <test-case FilePath="auto_key">
+      <compilation-unit name="simple-type">
+        <output-dir compare="Clean-JSON">simple-type</output-dir>
+        <expected-error>ASX0001: Field type string cannot be promoted to type 
uuid</expected-error>
+        <expected-error>ASX0001: Field type bigint cannot be promoted to type 
uuid</expected-error>
+        <expected-error>ASX0001: Field type string cannot be promoted to type 
uuid</expected-error>
+        <expected-error>ASX0001: Field type string cannot be promoted to type 
uuid</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="auto_key">
+      <compilation-unit name="nested-type">
+        <output-dir compare="Clean-JSON">nested-type</output-dir>
+        <expected-error>ASX0001: Field type string cannot be promoted to type 
uuid</expected-error>
+        <expected-error>ASX0001: Field type string cannot be promoted to type 
uuid</expected-error>
+      </compilation-unit>
+    </test-case>
+  </test-group>
 </test-group>
\ No newline at end of file
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 c65cf38c98..d7e9210533 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
@@ -119,6 +119,7 @@ import 
org.apache.asterix.om.typecomputer.impl.OrderedListOfAPointTypeComputer;
 import 
org.apache.asterix.om.typecomputer.impl.OrderedListOfAStringTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.OrderedListOfAnyTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.PropagateTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.PutAutogeneratedKeyTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.RecordAddFieldsTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.RecordAddTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.RecordMergeTypeComputer;
@@ -1282,6 +1283,9 @@ public class BuiltinFunctions {
 
     public static final FunctionIdentifier SERIALIZED_SIZE = 
FunctionConstants.newAsterix("serialized-size", 1);
 
+    public static final FunctionIdentifier PUT_AUTOGENERATED_KEY =
+            FunctionConstants.newAsterix("put-autogenerated-key", 
FunctionIdentifier.VARARGS);
+
     static {
         // first, take care of Algebricks builtin functions
         addFunction(IS_MISSING, BooleanOnlyTypeComputer.INSTANCE, true);
@@ -2136,6 +2140,9 @@ public class BuiltinFunctions {
         // unnesting function
         addPrivateFunction(SCAN_COLLECTION, 
CollectionMemberResultType.INSTANCE, true);
 
+        // used by UPSERT/INSERT for collections with autogenerated uuid
+        addPrivateFunction(PUT_AUTOGENERATED_KEY, 
PutAutogeneratedKeyTypeComputer.INSTANCE, false);
+
     }
 
     static {
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/PutAutogeneratedKeyTypeComputer.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/PutAutogeneratedKeyTypeComputer.java
new file mode 100644
index 0000000000..7f3bbdc75c
--- /dev/null
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/PutAutogeneratedKeyTypeComputer.java
@@ -0,0 +1,158 @@
+/*
+ * 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.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
+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.BuiltinType;
+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 PutAutogeneratedKeyTypeComputer implements IResultTypeComputer {
+
+    public static final PutAutogeneratedKeyTypeComputer INSTANCE = new 
PutAutogeneratedKeyTypeComputer();
+
+    private PutAutogeneratedKeyTypeComputer() {
+    }
+
+    @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 inRecArg = (IAType) env.getType(funArgs.get(0).getValue());
+        boolean unknownable = TypeHelper.canBeUnknown(inRecArg);
+        ARecordType inRecType = TypeComputeUtils.extractRecordType(inRecArg);
+        if (inRecType == null) {
+            throw new TypeMismatchException(f.getSourceLocation(), funcId, 0, 
inRecArg.getTypeTag(), ATypeTag.OBJECT);
+        }
+        String[] keyNameParts = getKeyNameParts(funArgs);
+        return computeOutRecType(inRecType, keyNameParts, unknownable, 
f.getSourceLocation());
+    }
+
+    private static IAType computeOutRecType(ARecordType inRecType, String[] 
keyNameParts, boolean unknownable,
+            SourceLocation sourceLocation) throws AlgebricksException {
+        String[] inFieldNames = inRecType.getFieldNames();
+        String[] resultFieldNames = Arrays.copyOf(inFieldNames, 
inFieldNames.length);
+        IAType[] resultFieldTypes = new IAType[resultFieldNames.length];
+        int k = 0;
+        return computeResultType(resultFieldNames, resultFieldTypes, 
inRecType, keyNameParts, k, unknownable,
+                sourceLocation);
+    }
+
+    private static IAType computeResultType(String[] resultFieldNames, 
IAType[] resultFieldTypes, ARecordType inRecType,
+            String[] keyNameParts, int k, boolean unknownable, SourceLocation 
sourceLocation)
+            throws CompilationException {
+        boolean keyFound = false;
+        for (int i = 0; i < resultFieldNames.length; i++) {
+            String fName = resultFieldNames[i];
+            IAType fType = inRecType.getFieldType(fName);
+            if (keyNameParts[k].equals(fName)) {
+                keyFound = true;
+                resultFieldTypes[i] = computeAutoType(fType, keyNameParts, k, 
sourceLocation);
+            } else {
+                if (fType.getTypeTag() == ATypeTag.OBJECT) {
+                    ARecordType nestedType = (ARecordType) fType;
+                    // deep copy prevents altering of input types
+                    resultFieldTypes[i] = nestedType.deepCopy(nestedType);
+                } else {
+                    resultFieldTypes[i] = fType;
+                }
+            }
+        }
+        boolean isOpen = inRecType.isOpen();
+        IAType resultType;
+        if (!keyFound) {
+            resultType = addAutoKeyType(resultFieldNames, resultFieldTypes, 
isOpen, keyNameParts, k);
+        } else {
+            resultType = new ARecordType("", resultFieldNames, 
resultFieldTypes, isOpen);
+        }
+        if (unknownable) {
+            resultType = AUnionType.createUnknownableType(resultType);
+        }
+        return resultType;
+    }
+
+    private static IAType addAutoKeyType(String[] resultFieldNames, IAType[] 
resultFieldTypes, boolean isOpen,
+            String[] keyNameParts, int k) {
+        IAType computedNestedType = BuiltinType.AUUID;
+        int lastPart = keyNameParts.length - 1;
+        for (int i = lastPart; i > k; i--) {
+            computedNestedType =
+                    new ARecordType("", new String[] { keyNameParts[i] }, new 
IAType[] { computedNestedType }, isOpen);
+        }
+        String[] finalResultFieldNames = Arrays.copyOf(resultFieldNames, 
resultFieldNames.length + 1);
+        IAType[] finalResultFieldTypes = Arrays.copyOf(resultFieldTypes, 
resultFieldTypes.length + 1);
+        finalResultFieldNames[finalResultFieldNames.length - 1] = 
keyNameParts[k];
+        finalResultFieldTypes[finalResultFieldTypes.length - 1] = 
computedNestedType;
+        return new ARecordType("", finalResultFieldNames, 
finalResultFieldTypes, isOpen);
+    }
+
+    private static IAType computeAutoType(IAType keyPartType, String[] 
keyNameParts, int k,
+            SourceLocation sourceLocation) throws CompilationException {
+        IAType fType = TypeComputeUtils.getActualType(keyPartType);
+        if (k == keyNameParts.length - 1) {
+            // reached the final key name part, check it's UUID
+            if (fType.getTypeTag() != ATypeTag.UUID) {
+                throw new CompilationException(ErrorCode.CASTING_FIELD, 
sourceLocation, fType.getTypeTag(),
+                        ATypeTag.UUID);
+            }
+            return fType;
+        }
+        // keyPartType should be a record because there is more nesting until 
reaching the final key part
+        if (fType.getTypeTag() != ATypeTag.OBJECT) {
+            throw new CompilationException(ErrorCode.CASTING_FIELD, 
sourceLocation, fType.getTypeTag(),
+                    ATypeTag.OBJECT);
+        }
+        boolean unknownable = TypeHelper.canBeUnknown(keyPartType);
+        ARecordType recType = (ARecordType) fType;
+        String[] inFieldNames = recType.getFieldNames();
+        String[] resultFieldNames = Arrays.copyOf(inFieldNames, 
inFieldNames.length);
+        IAType[] resultFieldTypes = new IAType[resultFieldNames.length];
+        return computeResultType(resultFieldNames, resultFieldTypes, recType, 
keyNameParts, k + 1, unknownable,
+                sourceLocation);
+    }
+
+    private static String[] getKeyNameParts(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;
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PutAutogeneratedKeyDescriptor.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PutAutogeneratedKeyDescriptor.java
new file mode 100644
index 0000000000..8293a2675f
--- /dev/null
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PutAutogeneratedKeyDescriptor.java
@@ -0,0 +1,80 @@
+/*
+ * 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.ARecordType;
+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 PutAutogeneratedKeyDescriptor extends 
AbstractScalarFunctionDynamicDescriptor {
+
+    private static final long serialVersionUID = 1L;
+
+    public static final IFunctionDescriptorFactory FACTORY = new 
IFunctionDescriptorFactory() {
+        @Override
+        public IFunctionDescriptor createFunctionDescriptor() {
+            return new PutAutogeneratedKeyDescriptor();
+        }
+
+        @Override
+        public IFunctionTypeInferer createFunctionTypeInferer() {
+            return new FunctionTypeInferers.PutAutogeneratedKeyTypeInferer();
+        }
+    };
+
+    private ARecordType outRecType;
+    private ARecordType inRecType;
+
+    @Override
+    public void setImmutableStates(Object... states) {
+        outRecType = TypeComputeUtils.extractRecordType((IAType) states[0]);
+        inRecType = 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 PutAutogeneratedKeyEvaluator(ctx, args, outRecType, 
inRecType, sourceLoc, getIdentifier());
+            }
+        };
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.PUT_AUTOGENERATED_KEY;
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PutAutogeneratedKeyEvaluator.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PutAutogeneratedKeyEvaluator.java
new file mode 100644
index 0000000000..6302c78b54
--- /dev/null
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PutAutogeneratedKeyEvaluator.java
@@ -0,0 +1,215 @@
+/*
+ * 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.common.exceptions.ErrorCode;
+import org.apache.asterix.common.exceptions.RuntimeDataException;
+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.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.runtime.RuntimeRecordTypeInfo;
+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.api.IValueReference;
+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 PutAutogeneratedKeyEvaluator extends AbstractScalarEval {
+
+    private final IPointable inRecPointable = new VoidPointable();
+    private final List<RecordBuilder> rbStack = new ArrayList<>();
+    private final ArrayBackedValueStorage tempStorage = new 
ArrayBackedValueStorage();
+    private final IBinaryComparator stringBinaryComparator =
+            
UTF8StringBinaryComparatorFactory.INSTANCE.createBinaryComparator();
+    private final RuntimeRecordTypeInfo runtimeRecordTypeInfo = new 
RuntimeRecordTypeInfo();
+    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();
+    @SuppressWarnings("unchecked")
+    private final ISerializerDeserializer<AUUID> uuidSerDe =
+            
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AUUID);
+
+    private final ARecordType outRecType;
+    private final IVisitablePointable inRecVisitable;
+    private final IPointable[] keyNameParts;
+    private final IScalarEvaluator inRecEval;
+    private final IScalarEvaluator[] keyNamePartsEvals;
+
+    PutAutogeneratedKeyEvaluator(IEvaluatorContext ctx, 
IScalarEvaluatorFactory[] args, ARecordType outRecType,
+            ARecordType inRecType, SourceLocation sourceLocation, 
FunctionIdentifier identifier)
+            throws HyracksDataException {
+        super(sourceLocation, identifier);
+        this.outRecType = outRecType;
+        inRecEval = args[0].createScalarEvaluator(ctx);
+        keyNamePartsEvals = new IScalarEvaluator[args.length - 1];
+        keyNameParts = new VoidPointable[args.length - 1];
+        for (int i = 1, e = 0; i < args.length; i++, e++) {
+            keyNamePartsEvals[e] = args[i].createScalarEvaluator(ctx);
+            keyNameParts[e] = new VoidPointable();
+        }
+        PointableAllocator pa = new PointableAllocator();
+        inRecVisitable = pa.allocateRecordValue(inRecType);
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws 
HyracksDataException {
+        inRecEval.evaluate(tuple, inRecPointable);
+        if (PointableHelper.checkAndSetMissingOrNull(result, inRecPointable)) {
+            // TODO: can probably fail instead of producing NULL/MISSING
+            return;
+        }
+        ATypeTag inputTypeTag = PointableHelper.getTypeTag(inRecPointable);
+        if (inputTypeTag != ATypeTag.OBJECT) {
+            throw new RuntimeDataException(ErrorCode.CASTING_FIELD, srcLoc, 
inputTypeTag, ATypeTag.OBJECT);
+        }
+        for (int i = 0; i < keyNamePartsEvals.length; i++) {
+            keyNamePartsEvals[i].evaluate(tuple, keyNameParts[i]);
+            if (PointableHelper.checkAndSetMissingOrNull(result, 
keyNameParts[i])) {
+                // TODO: can probably fail instead of producing NULL/MISSING
+                return;
+            }
+        }
+        resultStorage.reset();
+        processTuple(tuple);
+        result.set(resultStorage);
+    }
+
+    private void processTuple(IFrameTupleReference tuple) throws 
HyracksDataException {
+        inRecVisitable.set(inRecPointable);
+        try {
+            mergeAutoKeyToRecord(outRecType, (ARecordVisitablePointable) 
inRecVisitable, 0, tuple, keyNameParts[0]);
+            rbStack.get(0).write(out, true);
+        } catch (IOException e) {
+            throw HyracksDataException.create(e);
+        }
+    }
+
+    private void mergeAutoKeyToRecord(ARecordType outType, 
ARecordVisitablePointable record, int nestedLevel,
+            IFrameTupleReference tuple, IValueReference keyNamePart) throws 
IOException {
+        if (rbStack.size() < (nestedLevel + 1)) {
+            rbStack.add(new RecordBuilder());
+        }
+        rbStack.get(nestedLevel).reset(outType);
+        rbStack.get(nestedLevel).init();
+        boolean foundKeyNamePart = false;
+        if (record != null) {
+            for (int i = 0; i < record.getFieldNames().size(); i++) {
+                IVisitablePointable fieldName = record.getFieldNames().get(i);
+                IVisitablePointable fieldVal = record.getFieldValues().get(i);
+                if (PointableHelper.isEqual(fieldName, keyNamePart, 
stringBinaryComparator)) {
+                    foundKeyNamePart = true;
+                    addKeyPart(outType, nestedLevel, tuple, fieldName, 
fieldVal);
+                } else {
+                    addField(outType, fieldName, fieldVal, nestedLevel);
+                }
+            }
+        }
+        if (!foundKeyNamePart) {
+            // the input record does not have the key, generate a new key with 
all the field(s) nesting needed
+            if (lastKeyPartName(nestedLevel, keyNamePartsEvals.length)) {
+                addAutogeneratedKey(outType, keyNamePart, nestedLevel);
+            } else {
+                mergeAutoKeyToRecordField(outType, keyNamePart, null, 
nestedLevel, tuple);
+            }
+        }
+    }
+
+    private void addKeyPart(ARecordType outType, int nestedLevel, 
IFrameTupleReference tuple,
+            IVisitablePointable keyPartName, IVisitablePointable keyPartVal) 
throws IOException {
+        ATypeTag typeTag = PointableHelper.getTypeTag(keyPartVal);
+        if (lastKeyPartName(nestedLevel, keyNamePartsEvals.length)) {
+            switch (typeTag) {
+                case UUID:
+                    addField(outType, keyPartName, keyPartVal, nestedLevel);
+                    break;
+                case MISSING:
+                    addAutogeneratedKey(outType, keyPartName, nestedLevel);
+                    break;
+                default:
+                    throw new RuntimeDataException(ErrorCode.CASTING_FIELD, 
srcLoc, typeTag, ATypeTag.UUID);
+            }
+        } else {
+            if (typeTag != ATypeTag.OBJECT) {
+                throw new RuntimeDataException(ErrorCode.CASTING_FIELD, 
srcLoc, typeTag, ATypeTag.OBJECT);
+            }
+            mergeAutoKeyToRecordField(outType, keyPartName, 
(ARecordVisitablePointable) keyPartVal, nestedLevel, tuple);
+        }
+    }
+
+    private void mergeAutoKeyToRecordField(ARecordType combinedType, 
IValueReference recFieldName,
+            ARecordVisitablePointable recFieldVal, int nestedLevel, 
IFrameTupleReference tuple) throws IOException {
+        runtimeRecordTypeInfo.reset(combinedType);
+        int pos = 
runtimeRecordTypeInfo.getFieldIndex(recFieldName.getByteArray(), 
recFieldName.getStartOffset() + 1,
+                recFieldName.getLength() - 1);
+        mergeAutoKeyToRecord((ARecordType) combinedType.getFieldTypes()[pos], 
recFieldVal, nestedLevel + 1, tuple,
+                keyNameParts[nestedLevel + 1]);
+        tempStorage.reset();
+        rbStack.get(nestedLevel + 1).write(tempStorage.getDataOutput(), true);
+        rbStack.get(nestedLevel).addField(pos, tempStorage);
+    }
+
+    private void addAutogeneratedKey(ARecordType outType, IValueReference 
keyNamePart, int nestedLevel)
+            throws IOException {
+        uuidStorage.reset();
+        uuid.nextUUID();
+        uuidSerDe.serialize(uuid, uuidOut);
+        addField(outType, keyNamePart, uuidStorage, nestedLevel);
+    }
+
+    private void addField(ARecordType outType, IValueReference fieldName, 
IValueReference fieldValue, int nestedLevel)
+            throws IOException {
+        runtimeRecordTypeInfo.reset(outType);
+        int pos = 
runtimeRecordTypeInfo.getFieldIndex(fieldName.getByteArray(), 
fieldName.getStartOffset() + 1,
+                fieldName.getLength() - 1);
+        if (pos >= 0) {
+            rbStack.get(nestedLevel).addField(pos, fieldValue);
+        } else {
+            rbStack.get(nestedLevel).addField(fieldName, fieldValue);
+        }
+    }
+
+    private static boolean lastKeyPartName(int nestedLevel, int keyNameParts) {
+        return nestedLevel == keyNameParts - 1;
+    }
+}
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 7001c25391..4149e1c448 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
@@ -541,6 +541,7 @@ import 
org.apache.asterix.runtime.evaluators.functions.records.FieldAccessNested
 import 
org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldValueDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldsDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.records.PairsDescriptor;
+import 
org.apache.asterix.runtime.evaluators.functions.records.PutAutogeneratedKeyDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.RecordAddDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.RecordAddFieldsDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.records.RecordConcatDescriptor;
@@ -1337,6 +1338,7 @@ public final class FunctionCollection implements 
IFunctionCollection {
         fc.add(DecodeDataverseNameDescriptor.FACTORY);
         fc.add(RandomWithSeedDescriptor.FACTORY);
         fc.add(SerializedSizeDescriptor.FACTORY);
+        fc.add(PutAutogeneratedKeyDescriptor.FACTORY);
 
         
ServiceLoader.load(IFunctionRegistrant.class).iterator().forEachRemaining(c -> 
c.register(fc));
         return fc;
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 9c25f6ebfd..731a880c5a 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
@@ -372,6 +372,17 @@ public final class FunctionTypeInferers {
         }
     }
 
+    public static final class PutAutogeneratedKeyTypeInferer 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 incRecType = (IAType) 
context.getType(f.getArguments().get(0).getValue());
+            fd.setImmutableStates(outType, incRecType);
+        }
+    }
+
     private static IAType[] getArgumentsTypes(AbstractFunctionCallExpression 
funExp, IVariableTypeEnvironment ctx)
             throws AlgebricksException {
         IAType[] argsTypes = new IAType[funExp.getArguments().size()];

Reply via email to