>From Shahrzad Shirazi <[email protected]>: Shahrzad Shirazi has submitted this change. ( https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/21205?usp=email )
Change subject: [ASTERIXDB-3770][COMP] Fix incorrect Result When Updating a Full Object ...................................................................... [ASTERIXDB-3770][COMP] Fix incorrect Result When Updating a Full Object - user model changes: yes - storage format changes: no - interface changes: no Ext-ref: MB-70961 Change-Id: I07a2fc3c76afe1f26d95225e4010b57f662f5ef0 Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/21205 Integration-Tests: Jenkins <[email protected]> Tested-by: Ali Alsuliman <[email protected]> Reviewed-by: Ali Alsuliman <[email protected]> --- 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 M asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/simple-case/simple-case.22.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-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.19.adm M asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.20.adm M asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.21.adm M asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.23.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 14 files changed, 345 insertions(+), 20 deletions(-) Approvals: Ali Alsuliman: Looks good to me, approved; Verified Jenkins: Verified Objections: Anon. E. Moose #1000171: Violations found 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..b4a4b09 --- /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..113713d --- /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/queries_sqlpp/update-statements/simple-case/simple-case.22.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/simple-case/simple-case.22.query.sqlpp index b91d248..6e6eebe 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/simple-case/simple-case.22.query.sqlpp +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/update-statements/simple-case/simple-case.22.query.sqlpp @@ -19,6 +19,16 @@ Use test; +upsert into UserTypes([{ "userId": 3, "email": "[email protected]", "username": "michaelb", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "five", "occupation": 4 }, +{ "userId": 4, "email": "[email protected]", "username": "emilyd", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": 23.1 } , + { "userId": 5, "email": "[email protected]", "username": "chrisj", "isActive": false, "u1": { "u2": null, "u3": 1 }, "age": "old" } +,{ "userId": 6, "email": "[email protected]", "username": "patriciag", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "45" }, +{ "userId": 7, "email": "[email protected]", "username": "lindam", "isActive": false, "u1": { "u2": null, "u3": 1 } }, +{ "userId": 8, "email": "[email protected]", "username": "robertl", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": 31 }, + { "userId": 9, "email": "[email protected]", "username": "jamesw", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "65" }, + { "userId": 10, "email": "[email protected]", "username": "marym", "isActive": false, "u1": { "u2": null, "u3": 1 }, "timeZone": "PT", "age": 32, "addresses": [ { "city": "Riverside", "zipcode": 92510 } ] } , +{ "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "age": 31, "addresses": [{ "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 }, { "city": "iii, United States", "street": "Second st", "zipcode": 9000 } ], "job": "pilot2", "u1": { "u2": null, "u3": 1, "u1": 1 }, "age2": null, "job3": null } +]); UPDATE UserTypes as u SET u.age=30 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..e782e99 --- /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": [ { "roleName": { "a": "manager" }, "roleId": "role1" }, { "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" } ] } } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.19.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.19.adm index bce9ccb..232b330 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.19.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.19.adm @@ -1 +1 @@ -{ "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "u1": { "u2": "3", "u1": 1 }, "age2": null, "job3": null, "age": null, "addresses": [ { "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 } ] } +{ "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "age2": null, "job3": null, "age": null, "addresses": [ { "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 } ] } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.20.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.20.adm index 9d7f002..a964f80 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.20.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.20.adm @@ -1,11 +1,11 @@ -{ "UserTypes": { "userId": 1, "email": "[email protected]", "username": "johndoe", "isActive": true, "u1": { "u2": null, "u3": 1 }, "totaltax": 0.25, "totalcost": 25, "occupation": "teacher", "age": 23 } } -{ "UserTypes": { "userId": 2, "email": "[email protected]", "username": "janesmith", "isActive": false, "u1": { "u2": null, "u3": 1 }, "occupation": "firefighter" } } -{ "UserTypes": { "userId": 3, "email": "[email protected]", "username": "michaelb", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "five", "occupation": 4 } } -{ "UserTypes": { "userId": 4, "email": "[email protected]", "username": "emilyd", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": 23.1 } } -{ "UserTypes": { "userId": 5, "email": "[email protected]", "username": "chrisj", "isActive": false, "u1": { "u2": null, "u3": 1 }, "age": "old" } } -{ "UserTypes": { "userId": 6, "email": "[email protected]", "username": "patriciag", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "45" } } -{ "UserTypes": { "userId": 7, "email": "[email protected]", "username": "lindam", "isActive": false, "u1": { "u2": null, "u3": 1 } } } -{ "UserTypes": { "userId": 8, "email": "[email protected]", "username": "robertl", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": 31 } } -{ "UserTypes": { "userId": 9, "email": "[email protected]", "username": "jamesw", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "65" } } -{ "UserTypes": { "userId": 10, "email": "[email protected]", "username": "marym", "isActive": false, "u1": { "u2": null, "u3": 1 }, "timeZone": "PT", "age": 32, "addresses": [ { "city": "Riverside", "zipcode": 92510 } ] } } -{ "UserTypes": { "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "u1": { "u2": null, "u3": 1, "u1": 1 }, "age2": null, "job3": null, "age": null, "addresses": [ { "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 } ] } } +{ "UserTypes": { "userId": 1, "email": "[email protected]", "username": "johndoe", "isActive": true, "totaltax": 0.25, "totalcost": 25, "occupation": "teacher", "age": 23 } } +{ "UserTypes": { "userId": 2, "email": "[email protected]", "username": "janesmith", "isActive": false, "occupation": "firefighter" } } +{ "UserTypes": { "userId": 3, "email": "[email protected]", "username": "michaelb", "isActive": true, "age": "five", "occupation": 4 } } +{ "UserTypes": { "userId": 4, "email": "[email protected]", "username": "emilyd", "isActive": true, "age": 23.1 } } +{ "UserTypes": { "userId": 5, "email": "[email protected]", "username": "chrisj", "isActive": false, "age": "old" } } +{ "UserTypes": { "userId": 6, "email": "[email protected]", "username": "patriciag", "isActive": true, "age": "45" } } +{ "UserTypes": { "userId": 7, "email": "[email protected]", "username": "lindam", "isActive": false } } +{ "UserTypes": { "userId": 8, "email": "[email protected]", "username": "robertl", "isActive": true, "age": 31 } } +{ "UserTypes": { "userId": 9, "email": "[email protected]", "username": "jamesw", "isActive": true, "age": "65" } } +{ "UserTypes": { "userId": 10, "email": "[email protected]", "username": "marym", "isActive": false, "timeZone": "PT", "age": 32, "addresses": [ { "city": "Riverside", "zipcode": 92510 } ] } } +{ "UserTypes": { "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "age2": null, "job3": null, "age": null, "addresses": [ { "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 } ] } } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.21.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.21.adm index a54c923..506ca2a 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.21.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.21.adm @@ -1 +1 @@ -{ "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "job": "pilot2", "age": 31, "addresses": [ { "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 }, { "city": "iii, United States", "street": "Second st", "zipcode": 9000 } ], "u1": { "u2": null, "u3": 1, "u1": 1 }, "age2": null, "job3": null } +{ "userId": 11, "email": "[email protected]", "username": "jk", "isActive": true, "job": "pilot2", "age": 31, "addresses": [ { "city": "Irvine, United States", "street": "Second st", "zipcode": 98128 }, { "city": "iii, United States", "street": "Second st", "zipcode": 9000 } ], "age2": null, "job3": null } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.23.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.23.adm index 53c9081..d929b58 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.23.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/update-statements/simple-case/simple-case.23.adm @@ -1,5 +1,5 @@ -{ "UserTypes": { "userId": 1, "email": "[email protected]", "username": "johndoe", "isActive": true, "u1": { "u2": null, "u3": 1 }, "totaltax": 0.25, "totalcost": 25, "occupation": "teacher", "age": 23 } } -{ "UserTypes": { "userId": 2, "email": "[email protected]", "username": "janesmith", "isActive": false, "u1": { "u2": null, "u3": 1 }, "occupation": "firefighter" } } +{ "UserTypes": { "userId": 1, "email": "[email protected]", "username": "johndoe", "isActive": true, "totaltax": 0.25, "totalcost": 25, "occupation": "teacher", "age": 23 } } +{ "UserTypes": { "userId": 2, "email": "[email protected]", "username": "janesmith", "isActive": false, "occupation": "firefighter" } } { "UserTypes": { "userId": 3, "email": "[email protected]", "username": "michaelb", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": "five", "occupation": 4 } } { "UserTypes": { "userId": 4, "email": "[email protected]", "username": "emilyd", "isActive": true, "u1": { "u2": null, "u3": 1 }, "age": 23.1 } } { "UserTypes": { "userId": 5, "email": "[email protected]", "username": "chrisj", "isActive": false, "u1": { "u2": null, "u3": 1 }, "age": "old" } } 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..ac38e8d 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 assignsWholeRecord() { + return exprTree.assignsWholeRecord(); + } + @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..69c076a 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 @@ -20,18 +20,24 @@ package org.apache.asterix.lang.sqlpp.parser; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.apache.asterix.common.exceptions.CompilationException; import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.functions.FunctionSignature; import org.apache.asterix.lang.common.base.Expression; import org.apache.asterix.lang.common.base.Literal; +import org.apache.asterix.lang.common.expression.CallExpr; import org.apache.asterix.lang.common.expression.FieldAccessor; import org.apache.asterix.lang.common.expression.FieldBinding; import org.apache.asterix.lang.common.expression.LiteralExpr; import org.apache.asterix.lang.common.expression.RecordConstructor; import org.apache.asterix.lang.common.literal.NullLiteral; import org.apache.asterix.lang.common.literal.StringLiteral; +import org.apache.asterix.lang.common.literal.TrueLiteral; +import org.apache.asterix.lang.sqlpp.expression.CaseExpression; +import org.apache.asterix.om.functions.BuiltinFunctions; import org.apache.hyracks.algebricks.common.utils.Pair; /** @@ -74,7 +80,7 @@ private final Node root; public SetExpressionTree() { - root = new Node("init", null); + root = new Node("init", null, true); } public void insertPath(Expression path, Expression valueExpr) throws CompilationException { @@ -102,6 +108,11 @@ return createRecordConstructorInner(root); } + /** Used by UPDATE rewrite: {@code SET u = expr} replaces the row with {@code expr}. */ + public boolean assignsWholeRecord() { + return root.hasExpression() && !root.hasChildren(); + } + private Node accessOrCreatePath(FieldAccessor path, Node node) throws CompilationException { Expression leadingExpr = path.getExpr(); @@ -111,13 +122,21 @@ if (node.hasExpression()) { throw new CompilationException(ErrorCode.UPDATE_ATTEMPT_ON_CONFLICTING_PATHS, path.getSourceLocation()); } - return node.retrieveChild(path.getIdent().getValue()); + Node child = node.retrieveChild(path.getIdent().getValue()); + // Save the path on first visit; the runtime is-object guard for deep-path SETs needs it. + child.pathExpr = path; + return child; } private Pair<Expression, Expression> createRecordConstructorInner(Node node) { if (node.hasExpression()) { Expression expr = node.getExpression(); if (expr.getKind() != Expression.Kind.LITERAL_EXPRESSION) { + // SET p.f = {...}: also emit a deletion entry so the old value is removed + // before the new record is written (full replace, not merge). + if (replaceWholeFieldWithObject(node, expr)) { + return new Pair<>(expr, new LiteralExpr(NullLiteral.INSTANCE)); + } return new Pair<>(expr, null); } LiteralExpr literalExpr = (LiteralExpr) expr; @@ -143,17 +162,50 @@ Expression setRecord = setRecordArgs.isEmpty() ? null : new RecordConstructor(setRecordArgs, true); Expression deletionRecord = deletionRecordArgs.isEmpty() ? null : new RecordConstructor(deletionRecordArgs, true); + // Deep-path SET only (e.g. SET p.a.b = X): wrap the overlay in + // CASE WHEN is-object(prefix) THEN overlay ELSE prefix + // so that when the prefix isn't a record at runtime, the merge sees the same value on + // both sides and leaves the field untouched. + if (setRecord != null && !node.isRoot && node.pathExpr != null) { + Expression prefix = node.pathExpr; + CallExpr isObject = + new CallExpr(new FunctionSignature(BuiltinFunctions.IS_OBJECT), Collections.singletonList(prefix)); + isObject.setSourceLocation(prefix.getSourceLocation()); + CaseExpression guarded = + new CaseExpression(isObject, Collections.singletonList(new LiteralExpr(TrueLiteral.INSTANCE)), + Collections.singletonList(setRecord), prefix); + guarded.setSourceLocation(prefix.getSourceLocation()); + setRecord = guarded; + } return new Pair<>(setRecord, deletionRecord); } + /** True only for "whole-field" record assignments: SET alias.f = {...}. */ + private static boolean replaceWholeFieldWithObject(Node node, Expression expr) { + if (node.isRoot || node.hasChildren()) { + return false; + } + if (expr.getKind() != Expression.Kind.RECORD_CONSTRUCTOR_EXPRESSION) { + return false; + } + if (node.pathExpr == null || node.pathExpr.getKind() != Expression.Kind.FIELD_ACCESSOR_EXPRESSION) { + return false; + } + Expression lead = ((FieldAccessor) node.pathExpr).getExpr(); + return lead.getKind() == Expression.Kind.VARIABLE_EXPRESSION; + } + private static class Node { private final String name; private Expression expr; + private Expression pathExpr; List<Node> children; + private final boolean isRoot; - private Node(String name, Expression expr) { + private Node(String name, Expression expr, boolean isRoot) { this.name = name; this.expr = expr; + this.isRoot = isRoot; children = new ArrayList<>(); } @@ -180,7 +232,7 @@ } } // 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, false); // New child node with no expression children.add(newChild); return newChild; } 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 80263b9..a2ab7ad 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 @@ -206,7 +206,9 @@ dataTransformRecord = substituteVariableInExpression(dataTransformRecord, originalVarName, currentContextVariable, changeExpr); changeExpr.setPriorExpr(projectExpr); - if (dataTransformRecord.getKind() == Expression.Kind.RECORD_CONSTRUCTOR_EXPRESSION) { + if (changeExpr.assignsWholeRecord()) { + 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: merged Gerrit-Project: asterixdb Gerrit-Branch: lumina Gerrit-Change-Id: I07a2fc3c76afe1f26d95225e4010b57f662f5ef0 Gerrit-Change-Number: 21205 Gerrit-PatchSet: 18 Gerrit-Owner: Shahrzad Shirazi <[email protected]> Gerrit-Reviewer: Ali Alsuliman <[email protected]> Gerrit-Reviewer: Anon. E. Moose #1000171 Gerrit-Reviewer: Jenkins <[email protected]> Gerrit-Reviewer: Shahrzad Shirazi <[email protected]>
