>From Shahrzad Shirazi <[email protected]>: Shahrzad Shirazi has uploaded this change for review. ( https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/21205?usp=email )
Change subject: WIP: replace an entire object or field with "UPDATE" ...................................................................... WIP: replace an entire object or field with "UPDATE" Change-Id: I07a2fc3c76afe1f26d95225e4010b57f662f5ef0 --- A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.12.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.13.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.14.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.15.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.13.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.15.adm M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/ChangeExpression.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppChangeExprToSelectExprVisitor.java 9 files changed, 299 insertions(+), 4 deletions(-) git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/05/21205/1 diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.12.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.12.ddl.sqlpp new file mode 100644 index 0000000..d92587e --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.12.ddl.sqlpp @@ -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. + */ +DROP DATAVERSE test IF EXISTS; +CREATE DATAVERSE test; +USE test; + +CREATE TYPE UserType2 AS { + userId: int +}; + +CREATE DATASET UserTypes2(UserType2) PRIMARY KEY userId; + + +INSERT INTO UserTypes2([ + { + "userId": 3, + "email": "[email protected]", + "username": "carol", + "isActive": true, + "roles": [ + { "roleId": "role1", "roleName": "moderator" } + ], + "c_purchase_history": { + "c_recent_orders": [ + { "orderId": "101"} , + { "orderId": "102" } , + { "orderId": "103"} + ] + } + }, + { + "userId": 4, + "email": "[email protected]", + "username": "carol", + "isActive": true, + "roles": [ + { "roleId": "role1", "roleName": "moderator" } + ], + "c_purchase_history": { + "c_recent_orders": [ + { "orderId": "101"} , + { "orderId": "102" } , + { "orderId": "103"} + ] + } + },{ + "userId": 5, + "email": "[email protected]", + "username": "carol", + "isActive": true, + "roles": [ + { "roleId": "role1", "roleName": "moderator" } + ], + "c_purchase_history": { + "c_recent_orders": [ + { "orderId": "101"} , + { "orderId": "102" } , + { "orderId": "103"} + ] + } + } +]); + diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.13.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.13.query.sqlpp new file mode 100644 index 0000000..f5e8586 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.13.query.sqlpp @@ -0,0 +1,40 @@ + +/* + * 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; + +UPDATE UserTypes2 AS u +set u. c_purchase_history={"a1":33} +set u. c_purchase_history2={"a2":33} +WHERE u.userId= 3; + +UPDATE UserTypes2 AS u +set u. c_purchase_history.c_recent_orders=["a","5"] +set u.a="p" +set u.isActive=Missing +WHERE u.userId= 4; + + +UPDATE UserTypes2 AS u +set u={"userId":5} +WHERE u.userId= 5; + + +select * from UserTypes2 +order by userId; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.14.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.14.ddl.sqlpp new file mode 100644 index 0000000..1e7bf85 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.14.ddl.sqlpp @@ -0,0 +1,82 @@ +/* + * 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 TYPE UserType2 AS { + userId: int +}; + +CREATE DATASET UserTypes2(UserType2) PRIMARY KEY userId; + + +INSERT INTO UserTypes2([ + { + "userId": 3, + "email": "[email protected]", + "username": "carol", + "isActive": true, + "roles": [ + { "roleId": "role1", "roleName": "moderator" }, + { "roleId": "role2", "roleName": "moderator" } + + + ], + "c_purchase_history": { + "c_recent_orders": [ + { "orderId": "101"} , + { "orderId": "102" } , + { "orderId": "103"} + ] + } + }, + { + "userId": 4, + "email": "[email protected]", + "username": "carol", + "isActive": true, + "roles": [ + { "roleId": "role1", "roleName": "moderator" } + ], + "c_purchase_history": { + "c_recent_orders": [ + { "orderId": "101"} , + { "orderId": "102" } , + { "orderId": "103"} + ] + } + },{ + "userId": 5, + "email": "[email protected]", + "username": "carol", + "isActive": true, + "roles": [ + { "roleId": "role1", "roleName": "moderator" } + ], + "c_purchase_history": { + "c_recent_orders": [ + { "orderId": "101"} , + { "orderId": "102" } , + { "orderId": "103"} + ] + } + } +]); + diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.15.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.15.query.sqlpp new file mode 100644 index 0000000..7947916 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/complex-case/complex-case.15.query.sqlpp @@ -0,0 +1,49 @@ + +/* + * 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; + +UPDATE UserTypes2 AS u +(UPDATE roles AS r at o +SET r.roleName = {"a":"manager"} +where o=0) +set u.c_purchase_history.c_recent_orders={"a":33} +WHERE u.userId= 3; + + +UPDATE UserTypes2 AS u +(UPDATE roles AS r +SET r.roleName = {"a":"manager"}) +set u.c_purchase_history.c_recent_orders={"a":33} +set u.isActive=missing +set u.username=null +WHERE u.userId= 4; + + + +UPDATE UserTypes2 AS u +set u.c_purchase_history.c_recent_orders={"a":null} +set u.isActive=missing +set u.username=null +WHERE u.userId= 5; + + + +select * from UserTypes2 +order by userId; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.13.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.13.adm new file mode 100644 index 0000000..3f72b2d --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.13.adm @@ -0,0 +1,3 @@ +{ "UserTypes2": { "userId": 3, "c_purchase_history2": { "a2": 33 }, "c_purchase_history": { "a1": 33 }, "email": "[email protected]", "username": "carol", "isActive": true, "roles": [ { "roleId": "role1", "roleName": "moderator" } ] } } +{ "UserTypes2": { "userId": 4, "a": "p", "c_purchase_history": { "c_recent_orders": [ "a", "5" ] }, "email": "[email protected]", "username": "carol", "roles": [ { "roleId": "role1", "roleName": "moderator" } ] } } +{ "UserTypes2": { "userId": 5 } } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.15.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.15.adm new file mode 100644 index 0000000..8356589 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/complex-case/complex-case.15.adm @@ -0,0 +1,3 @@ +{ "UserTypes2": { "userId": 3, "c_purchase_history": { "c_recent_orders": { "a": 33 } }, "roles": [ { "roleId": "role1", "roleName": "moderator" }, { "roleId": "role2", "roleName": "moderator" } ], "email": "[email protected]", "username": "carol", "isActive": true } } +{ "UserTypes2": { "userId": 4, "username": null, "c_purchase_history": { "c_recent_orders": { "a": 33 } }, "roles": [ { "roleName": { "a": "manager" }, "roleId": "role1" } ], "email": "[email protected]" } } +{ "UserTypes2": { "userId": 5, "username": null, "c_purchase_history": { "c_recent_orders": { "a": null } }, "email": "[email protected]", "roles": [ { "roleId": "role1", "roleName": "moderator" } ] } } diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/ChangeExpression.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/ChangeExpression.java index 39b6a44..cfc6984 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/ChangeExpression.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/ChangeExpression.java @@ -244,6 +244,10 @@ dataRemovalRecord = result.second; } + public boolean assignWholeRecord() { + return exprTree.isWholeRowAssignment(); + } + @Override public int hashCode() { return Objects.hash(pathExprs, valueExprs, dataTransformRecord, dataRemovalRecord, exprTree, priorExpr, diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java index fe2031f..e1e670a 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java @@ -1,3 +1,4 @@ + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -50,7 +51,11 @@ * by walking the tree: * <ul> * <li><b>Transformation record:</b> contains all fields with normal values (for updates/adds)</li> - * <li><b>Deletion record:</b> contains fields set to {@code MISSING} (for removal)</li> + * <li><b>Deletion record:</b> contains fields set to {@code MISSING} (for removal), plus when a path is + * assigned a <em>record constructor</em> {@code { ... }} directly (e.g. {@code SET u.s = {"rating": 675}}), + * a {@code null} marker on that path so {@code object-remove-recursive} clears the previous value before + * {@code object-transform}. That replaces the whole field object; assigning a scalar or a longer path + * (e.g. {@code SET u.s.rating = 675}) uses merge only and keeps sibling fields under {@code u.s}.</li> * </ul> * </li> * </ul> @@ -102,6 +107,14 @@ return createRecordConstructorInner(root); } + /** + * {@code SET alias = expr} alone (no {@code SET alias.field = ...}): the result row is exactly {@code expr}, + * not a merge of {@code expr} into the previous row. + */ + public boolean isWholeRowAssignment() { + return root.hasExpression() && !root.hasChildren(); + } + private Node accessOrCreatePath(FieldAccessor path, Node node) throws CompilationException { Expression leadingExpr = path.getExpr(); @@ -118,6 +131,12 @@ if (node.hasExpression()) { Expression expr = node.getExpression(); if (expr.getKind() != Expression.Kind.LITERAL_EXPRESSION) { + //if we are assigning a record to a field, we need a deletionRecord + // for that field and also a setRecord to make sure that the new + // value for the field only includes the new sub.fields. + if (useRemovalBeforeAssignRecordValue(node, expr)) { + return new Pair<>(expr, new LiteralExpr(NullLiteral.INSTANCE)); + } return new Pair<>(expr, null); } LiteralExpr literalExpr = (LiteralExpr) expr; @@ -146,6 +165,19 @@ return new Pair<>(setRecord, deletionRecord); } + /** + * if the Node name is init that means we are at the root of the tree and we are replacing the whole record + * Note that this is only possible if the primary key is not changes in the new record + */ + private static boolean isSyntheticTreeRoot(Node node) { + return "init".equals(node.name); + } + + private static boolean useRemovalBeforeAssignRecordValue(Node node, Expression expr) { + return !node.hasChildren() && !isSyntheticTreeRoot(node) + && expr.getKind() == Expression.Kind.RECORD_CONSTRUCTOR_EXPRESSION; + } + private static class Node { private final String name; private Expression expr; @@ -180,10 +212,10 @@ } } // If not found and createIfEmpty is true, create and add the child node - Node newChild = new Node(childName, null); // New child node with no expression + Node newChild = new Node(childName, null);// New child node with no expression children.add(newChild); return newChild; } } -} +} \ No newline at end of file diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppChangeExprToSelectExprVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppChangeExprToSelectExprVisitor.java index 0d1527c..dac8e5e 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppChangeExprToSelectExprVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppChangeExprToSelectExprVisitor.java @@ -198,7 +198,9 @@ dataTransformRecord = substituteVariableInExpression(dataTransformRecord, originalVarName, currentContextVariable, changeExpr); changeExpr.setPriorExpr(projectExpr); - if (dataTransformRecord.getKind() == Expression.Kind.RECORD_CONSTRUCTOR_EXPRESSION) { + if (changeExpr.assignWholeRecord()) { + projectExpr = dataTransformRecord; + } else if (dataTransformRecord.getKind() == Expression.Kind.RECORD_CONSTRUCTOR_EXPRESSION) { projectExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.RECORD_TRANSFORM), new ArrayList<>(Arrays.asList(dataTransformRecord, projectExpr))); ((CallExpr) projectExpr).setSourceLocation(rewrittenFirstExpr.getSourceLocation()); -- To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/21205?usp=email To unsubscribe, or for help writing mail filters, visit https://asterix-gerrit.ics.uci.edu/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: asterixdb Gerrit-Branch: lumina Gerrit-Change-Id: I07a2fc3c76afe1f26d95225e4010b57f662f5ef0 Gerrit-Change-Number: 21205 Gerrit-PatchSet: 1 Gerrit-Owner: Shahrzad Shirazi <[email protected]>
