From 0d7974f27d6d922e597a3cfce52dd6f856ea2ac6 Mon Sep 17 00:00:00 2001 From: Ali Alsuliman Date: Thu, 12 Jul 2018 10:42:48 -0700 Subject: [PATCH] [NO ISSUE][FUN] Implement array functions p1 - user model changes: no - storage format changes: no - interface changes: no details: This is part of implementing array functions. This patch includes array_insert(), array_append(), array_prepend() array_put() and array_remove(). It includes re-organization of those functions. Change-Id: I7d9cb80325138daf99fb039793446d109481c94b Reviewed-on: https://asterix-gerrit.ics.uci.edu/2751 Sonar-Qube: Jenkins Integration-Tests: Jenkins Reviewed-by: abdullah alamoudi Tested-by: Jenkins Contrib: Jenkins --- .../apache/asterix/runtime/ExceptionIT.java | 9 +- .../asterix/runtime/NullMissingTest.java | 8 +- .../array_append/array_append.3.query.sqlpp | 13 +- .../array_insert/array_insert.1.ddl.sqlpp | 46 ++++ .../array_insert/array_insert.2.update.sqlpp | 22 ++ .../array_insert/array_insert.3.query.sqlpp | 43 ++++ .../array_insert/array_insert.4.ddl.sqlpp | 20 ++ .../array_prepend/array_prepend.1.ddl.sqlpp | 56 +++++ .../array_prepend.2.update.sqlpp | 27 +++ .../array_prepend/array_prepend.3.query.sqlpp | 32 +++ .../array_prepend/array_prepend.4.ddl.sqlpp | 20 ++ .../array_fun/array_put/array_put.1.ddl.sqlpp | 56 +++++ .../array_put/array_put.2.update.sqlpp | 27 +++ .../array_put/array_put.3.query.sqlpp | 33 +++ .../array_put/array_put.4.query.sqlpp | 22 ++ .../array_put/array_put.5.query.sqlpp | 22 ++ .../array_fun/array_put/array_put.6.ddl.sqlpp | 20 ++ .../array_remove/array_remove.1.ddl.sqlpp | 56 +++++ .../array_remove/array_remove.2.update.sqlpp | 27 +++ .../array_remove/array_remove.3.query.sqlpp | 32 +++ .../array_remove/array_remove.4.query.sqlpp | 22 ++ .../array_remove/array_remove.5.query.sqlpp | 22 ++ .../array_remove/array_remove.6.ddl.sqlpp | 20 ++ .../array_fun/array_append/array_append.3.adm | 2 +- .../array_fun/array_insert/array_insert.3.adm | 1 + .../array_prepend/array_prepend.3.adm | 1 + .../array_fun/array_put/array_put.3.adm | 1 + .../array_fun/array_remove/array_remove.3.adm | 1 + .../resources/runtimets/testsuite_sqlpp.xml | 24 ++ .../om/functions/BuiltinFunctions.java | 18 +- ...puter.java => AListFirstTypeComputer.java} | 36 ++- .../typecomputer/impl/AListTypeComputer.java | 59 ++++- .../om/typecomputer/ExceptionTest.java | 11 +- .../om/typecomputer/TypeComputerTest.java | 26 ++- .../functions/AbstractArrayAddRemoveEval.java | 209 ++++++++++++++++++ .../functions/ArrayAppendDescriptor.java | 105 ++------- .../functions/ArrayInsertDescriptor.java | 129 +++++++++++ .../functions/ArrayPrependDescriptor.java | 90 ++++++++ .../functions/ArrayPutDescriptor.java | 136 ++++++++++++ .../functions/ArrayRemoveDescriptor.java | 123 +++++++++++ .../functions/CastTypeEvaluator.java | 15 +- .../evaluators/functions/PointableHelper.java | 6 +- .../runtime/functions/FunctionCollection.java | 10 +- 43 files changed, 1495 insertions(+), 163 deletions(-) create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.1.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.2.update.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.3.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.4.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.1.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.2.update.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.3.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.4.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.5.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.6.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.1.ddl.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.2.update.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.3.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.4.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.5.query.sqlpp create mode 100755 asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.6.ddl.sqlpp create mode 100644 asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm create mode 100644 asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_prepend/array_prepend.3.adm create mode 100644 asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_put/array_put.3.adm create mode 100644 asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.3.adm rename asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/{ArrayAppendTypeComputer.java => AListFirstTypeComputer.java} (52%) mode change 100755 => 100644 mode change 100644 => 100755 asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListTypeComputer.java create mode 100755 asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java create mode 100755 asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java create mode 100755 asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPrependDescriptor.java create mode 100755 asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPutDescriptor.java create mode 100755 asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayRemoveDescriptor.java diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ExceptionIT.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ExceptionIT.java index e764c32159f..2e7445f99a2 100644 --- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ExceptionIT.java +++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ExceptionIT.java @@ -50,9 +50,8 @@ public void test() throws Exception { String className = func.getClass().getName(); // We test all generated functions except // record and cast functions, which requires type settings. - String[] splits = className.split("\\."); - if (className.contains("Gen") && !className.contains("record") && !className.contains("Cast") - && !splits[splits.length - 1].startsWith("Array")) { + if (className.contains("Gen") && !className.contains("record") && !className.contains("Cast")) { + System.out.println("Testing " + className); testFunction(func); ++testedFunctions; } @@ -83,6 +82,10 @@ private void testFunction(IFunctionDescriptorFactory funcFactory) throws Excepti int errorCode = Integer.parseInt(msg.substring(3, 7)); Assert.assertTrue(errorCode >= 0 && errorCode < 1000); continue; + } else if (msg.startsWith("HYR")) { + // Verifies the error code. + int errorCode = Integer.parseInt(msg.substring(3, 7)); + Assert.assertTrue(errorCode >= 0 && errorCode < 1000); } else { // Any root-level data exceptions thrown from runtime functions should have an error code. Assert.assertTrue(!(e instanceof HyracksDataException) || (e.getCause() != null)); diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/NullMissingTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/NullMissingTest.java index f6f617e73c4..f302cef0748 100644 --- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/NullMissingTest.java +++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/NullMissingTest.java @@ -41,21 +41,17 @@ public class NullMissingTest { - private static final String arrayAppend = "ArrayAppendDescriptor"; - @Test public void test() throws Exception { List functions = FunctionCollection.createDefaultFunctionCollection().getFunctionDescriptorFactories(); int testedFunctions = 0; - String[] splits; for (IFunctionDescriptorFactory func : functions) { String className = func.getClass().getName(); // We test all generated functions except // record and cast functions, which requires type settings (we test them in runtime tests). - splits = className.split("\\."); - if (className.contains("Gen") && !className.contains("record") && !className.contains("Cast") - && !splits[splits.length - 1].startsWith(arrayAppend)) { + if (className.contains("Gen") && !className.contains("record") && !className.contains("Cast")) { + System.out.println("Testing " + className); testFunction(func); ++testedFunctions; } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp index 8488e22b500..20ea6fc54da 100755 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp @@ -22,10 +22,11 @@ use TinySocial; { "t1": (select array_append(t.`referred-topics`, "sth", 5) from TweetMessages t order by t.tweetid), "t2": (select array_append([3, "John"], (select value v.compType from d1 v))), - "t3": (select array_append([3], 7, null, missing)), - "t4": (select array_append("non_array", 5)), - "t5": (select array_append("non_array", 5, missing)), - "t6": (select array_append([], 5, 10, 12.0, "sth")), - "t7": (select array_append(missing, 3, 9)), - "t8": (select array_append(null, 3, 9)) + "t3": (array_append([3], 7, null, missing)), // missing + "t4": (array_append("non_array", 5)), // null + "t5": (array_append(null, 3, 9)), // null + "t6": (array_append("non_array", 5, missing)), // missing + "t7": (array_append([], 5, 10, 12.0, "sth")), // OK + "t8": (array_append(missing, 3, 9)), // missing + "t9": (array_append([3], 3, [9], null, "sth")) // OK to add nulls }; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp new file mode 100755 index 00000000000..257c4ddf4c7 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp @@ -0,0 +1,46 @@ +/* + * 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 TinySocial if exists; +create dataverse TinySocial; + +use TinySocial; + + +create type TinySocial.TwitterUserType as +{ + `screen-name` : string, + lang : string, + friends_count : bigint, + statuses_count : bigint, + name : string, + followers_count : bigint +}; + +create type TinySocial.TweetMessageType as + closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp new file mode 100755 index 00000000000..4a0e7edf7a4 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.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 TinySocial; + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp new file mode 100755 index 00000000000..137c9fa1d8a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp @@ -0,0 +1,43 @@ +/* + * 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 TinySocial; + +{ + "t1": (array_insert([1,2,3], 0, "a", "b")), // OK + "t2": (array_insert([1,2,3], 3, "a", "b")), // OK + "t3": (array_insert([1,1,2,4], 3, "a", "b")), // OK + "t4": (array_insert([1,1,2,4], 3, 7, "a", 7, "one more")), // OK + "t5": (array_insert([1,2,3], 4, "a")), // null, out of bound + "t6": (array_insert([1,2,3], -1, "a", "b")), // OK + "t7": (array_insert([1,2,3], -4, "a", "b")), // null, out of bound + "t8": (array_insert("non_array", 5, "val")), // null + "t9": (array_insert("non_array", 5, missing)), // missing + "t10": (array_insert([], 5, 10, 12.0, "sth")), // null, out of bound + "t11": (array_insert([], 0, 10, 12.0, "sth")), // OK + "t12": (array_insert([6], "a", 9)), // null, position non-numeric + "t13": (array_insert([6], 1.0, 9)), // OK + "t14": (array_insert([6], 1.5, 9)), // OK + "t15": (array_insert(null, 3, 9)), // null + "t16": (array_insert(missing, 3, 9)), // missing + "t17": (array_insert([6], 1, null, 9, null)), // OK to insert nulls + "t18": (array_insert([6], null, 5, 9, null)), // null + "t19": (array_insert([6], 3, null, missing, 9, null)), // missing + "t20": (select array_insert(t.`referred-topics`, 0, 5) from TweetMessages t order by t.tweetid) +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp new file mode 100755 index 00000000000..3f8c8ec49ab --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.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 TinySocial; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.1.ddl.sqlpp new file mode 100755 index 00000000000..1c55a9a5d02 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.1.ddl.sqlpp @@ -0,0 +1,56 @@ +/* + * 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 TinySocial if exists; +create dataverse TinySocial; + +use TinySocial; + + +create type TinySocial.TwitterUserType as +{ + `screen-name` : string, + lang : string, + friends_count : bigint, + statuses_count : bigint, + name : string, + followers_count : bigint +}; + +create type TinySocial.TweetMessageType as + closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create type t1 AS { + +}; + +create type t2 AS { +id: int, +compType: t1 +}; + +create dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`); +create dataset d1(t2) primary key id; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.2.update.sqlpp new file mode 100755 index 00000000000..27672103d5a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.2.update.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. + */ + +use TinySocial; + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); + +insert into d1([ +{"id":1, "compType":{"sth":33}}, +{"id":2, "compType":{"sth":44}} +]); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.3.query.sqlpp new file mode 100755 index 00000000000..e912a75612a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.3.query.sqlpp @@ -0,0 +1,32 @@ +/* + * 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 TinySocial; + +{ + "t1": (select array_prepend("sth", 5, t.`referred-topics`) from TweetMessages t order by t.tweetid), + "t2": (select array_prepend((select value v.compType from d1 v), [3, "John"])), + "t3": (array_prepend(7, null, missing, [3])), // missing + "t4": (array_prepend(5, "non_array")), // null + "t5": (array_prepend(3, 9, null)), // null + "t6": (array_prepend(5, missing, "non_array")), // missing + "t7": (array_prepend(5, 10, 12.0, "sth",[77, "val"])), // OK + "t8": (array_prepend(5, 10, null, "sth",[77, "val"])), // OK to insert nulls + "t9": (array_prepend(3, 9, missing)) // missing +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.4.ddl.sqlpp new file mode 100755 index 00000000000..3f8c8ec49ab --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_prepend/array_prepend.4.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 TinySocial; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.1.ddl.sqlpp new file mode 100755 index 00000000000..1c55a9a5d02 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.1.ddl.sqlpp @@ -0,0 +1,56 @@ +/* + * 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 TinySocial if exists; +create dataverse TinySocial; + +use TinySocial; + + +create type TinySocial.TwitterUserType as +{ + `screen-name` : string, + lang : string, + friends_count : bigint, + statuses_count : bigint, + name : string, + followers_count : bigint +}; + +create type TinySocial.TweetMessageType as + closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create type t1 AS { + +}; + +create type t2 AS { +id: int, +compType: t1 +}; + +create dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`); +create dataset d1(t2) primary key id; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.2.update.sqlpp new file mode 100755 index 00000000000..27672103d5a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.2.update.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. + */ + +use TinySocial; + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); + +insert into d1([ +{"id":1, "compType":{"sth":33}}, +{"id":2, "compType":{"sth":44}} +]); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.3.query.sqlpp new file mode 100755 index 00000000000..2e37af2b984 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.3.query.sqlpp @@ -0,0 +1,33 @@ +/* + * 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 TinySocial; + +{ + "t1": (select array_put(t.`referred-topics`, "t-mobile", 5) from TweetMessages t order by t.tweetid), + "t2": (array_put([3], 7, null, missing)), // missing + "t3": (array_put("non_array", 5)), // null + "t4": (array_put("non_array", 5, missing)), // missing + "t5": (array_put([], 5, 10, 12.0, "sth")), // OK + "t6": (array_put(missing, 3, 9)), // missing + "t7": (array_put(null, 3, 9)), // null + "t8": (array_put([3,2,"sth"], 3, 9, 9, 3, "sth")), // OK + "t9": (array_put([3,2,"sth"], 1, 5)), // OK + "t10": (array_put([3,2,"sth"], null, 5)) // null +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.4.query.sqlpp new file mode 100755 index 00000000000..a4626000700 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.4.query.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 TinySocial; + +select array_put([3, "John"], (select value v.compType from d1 v)); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.5.query.sqlpp new file mode 100755 index 00000000000..0d2711770bd --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.5.query.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 TinySocial; + +select array_put([3], 3, [9], 4, "sth"); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.6.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.6.ddl.sqlpp new file mode 100755 index 00000000000..3f8c8ec49ab --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_put/array_put.6.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 TinySocial; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.1.ddl.sqlpp new file mode 100755 index 00000000000..1c55a9a5d02 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.1.ddl.sqlpp @@ -0,0 +1,56 @@ +/* + * 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 TinySocial if exists; +create dataverse TinySocial; + +use TinySocial; + + +create type TinySocial.TwitterUserType as +{ + `screen-name` : string, + lang : string, + friends_count : bigint, + statuses_count : bigint, + name : string, + followers_count : bigint +}; + +create type TinySocial.TweetMessageType as + closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create type t1 AS { + +}; + +create type t2 AS { +id: int, +compType: t1 +}; + +create dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`); +create dataset d1(t2) primary key id; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.2.update.sqlpp new file mode 100755 index 00000000000..27672103d5a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.2.update.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. + */ + +use TinySocial; + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); + +insert into d1([ +{"id":1, "compType":{"sth":33}}, +{"id":2, "compType":{"sth":44}} +]); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.3.query.sqlpp new file mode 100755 index 00000000000..f726e7c3bb8 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.3.query.sqlpp @@ -0,0 +1,32 @@ +/* + * 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 TinySocial; + +{ + "t1": (select array_remove(t.`referred-topics`, "t-mobile") from TweetMessages t order by t.tweetid), + "t2": (array_remove([3], 7, null, missing)), // missing + "t3": (array_remove("non_array", 5)), // null + "t4": (array_remove("non_array", 5, missing)), // missing + "t5": (array_remove([], 5, 10, 12.0, "sth")), // OK + "t6": (array_remove(missing, 3, 9)), // missing + "t7": (array_remove(null, 3, 9)), // null + "t8": (array_remove([3,2,"sth"], 3, 9, 9, 3, "sth")), // OK + "t9": (array_remove([3,2,"sth"], 1, null)) // null +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.4.query.sqlpp new file mode 100755 index 00000000000..2dfa5142b60 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.4.query.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 TinySocial; + +select array_remove([3, "John"], (select value v.compType from d1 v)); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.5.query.sqlpp new file mode 100755 index 00000000000..bfa878f7517 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.5.query.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 TinySocial; + +select array_remove([3], 3, [9], 4, "sth"); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.6.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.6.ddl.sqlpp new file mode 100755 index 00000000000..3f8c8ec49ab --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_remove/array_remove.6.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 TinySocial; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm index c435e4e654b..52c454670ca 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm @@ -1 +1 @@ -{ "t1": [ { "$1": {{ "t-mobile", "customization", "sth", 5 }} }, { "$1": {{ "verizon", "voice-clarity", "sth", 5 }} }, { "$1": {{ "iphone", "platform", "sth", 5 }} }, { "$1": {{ "samsung", "voice-command", "sth", 5 }} }, { "$1": {{ "verizon", "shortcut-menu", "sth", 5 }} }, { "$1": {{ "motorola", "speed", "sth", 5 }} }, { "$1": {{ "sprint", "voice-command", "sth", 5 }} }, { "$1": {{ "motorola", "speed", "sth", 5 }} }, { "$1": {{ "iphone", "voice-clarity", "sth", 5 }} }, { "$1": {{ "samsung", "platform", "sth", 5 }} }, { "$1": {{ "t-mobile", "shortcut-menu", "sth", 5 }} }, { "$1": {{ "verizon", "voicemail-service", "sth", 5 }} } ], "t2": [ { "$2": [ 3, "John", [ { "sth": 33 }, { "sth": 44 } ] ] } ], "t3": [ { } ], "t4": [ { "$4": null } ], "t5": [ { } ], "t6": [ { "$6": [ 5, 10, 12.0, "sth" ] } ], "t7": [ { } ], "t8": [ { "$8": null } ] } +{ "t1": [ { "$1": {{ "t-mobile", "customization", "sth", 5 }} }, { "$1": {{ "verizon", "voice-clarity", "sth", 5 }} }, { "$1": {{ "iphone", "platform", "sth", 5 }} }, { "$1": {{ "samsung", "voice-command", "sth", 5 }} }, { "$1": {{ "verizon", "shortcut-menu", "sth", 5 }} }, { "$1": {{ "motorola", "speed", "sth", 5 }} }, { "$1": {{ "sprint", "voice-command", "sth", 5 }} }, { "$1": {{ "motorola", "speed", "sth", 5 }} }, { "$1": {{ "iphone", "voice-clarity", "sth", 5 }} }, { "$1": {{ "samsung", "platform", "sth", 5 }} }, { "$1": {{ "t-mobile", "shortcut-menu", "sth", 5 }} }, { "$1": {{ "verizon", "voicemail-service", "sth", 5 }} } ], "t2": [ { "$2": [ 3, "John", [ { "sth": 33 }, { "sth": 44 } ] ] } ], "t4": null, "t5": null, "t9": [ 3, 3, [ 9 ], null, "sth" ], "t7": [ 5, 10, 12.0, "sth" ] } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm new file mode 100644 index 00000000000..86bc1140a66 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm @@ -0,0 +1 @@ +{ "t1": [ "a", "b", 1, 2, 3 ], "t2": [ 1, 2, 3, "a", "b" ], "t3": [ 1, 1, 2, "a", "b", 4 ], "t4": [ 1, 1, 2, 7, "a", 7, "one more", 4 ], "t5": null, "t6": [ 1, 2, "a", "b", 3 ], "t7": null, "t8": null, "t10": null, "t11": [ 10, 12.0, "sth" ], "t12": null, "t13": [ 6, 9 ], "t14": [ 6, 9 ], "t15": null, "t17": [ 6, null, 9, null ], "t18": null, "t20": [ { "$1": {{ 5, "t-mobile", "customization" }} }, { "$1": {{ 5, "verizon", "voice-clarity" }} }, { "$1": {{ 5, "iphone", "platform" }} }, { "$1": {{ 5, "samsung", "voice-command" }} }, { "$1": {{ 5, "verizon", "shortcut-menu" }} }, { "$1": {{ 5, "motorola", "speed" }} }, { "$1": {{ 5, "sprint", "voice-command" }} }, { "$1": {{ 5, "motorola", "speed" }} }, { "$1": {{ 5, "iphone", "voice-clarity" }} }, { "$1": {{ 5, "samsung", "platform" }} }, { "$1": {{ 5, "t-mobile", "shortcut-menu" }} }, { "$1": {{ 5, "verizon", "voicemail-service" }} } ] } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_prepend/array_prepend.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_prepend/array_prepend.3.adm new file mode 100644 index 00000000000..0e3a1af9ae4 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_prepend/array_prepend.3.adm @@ -0,0 +1 @@ +{ "t1": [ { "$1": {{ "sth", 5, "t-mobile", "customization" }} }, { "$1": {{ "sth", 5, "verizon", "voice-clarity" }} }, { "$1": {{ "sth", 5, "iphone", "platform" }} }, { "$1": {{ "sth", 5, "samsung", "voice-command" }} }, { "$1": {{ "sth", 5, "verizon", "shortcut-menu" }} }, { "$1": {{ "sth", 5, "motorola", "speed" }} }, { "$1": {{ "sth", 5, "sprint", "voice-command" }} }, { "$1": {{ "sth", 5, "motorola", "speed" }} }, { "$1": {{ "sth", 5, "iphone", "voice-clarity" }} }, { "$1": {{ "sth", 5, "samsung", "platform" }} }, { "$1": {{ "sth", 5, "t-mobile", "shortcut-menu" }} }, { "$1": {{ "sth", 5, "verizon", "voicemail-service" }} } ], "t2": [ { "$2": [ [ { "sth": 33 }, { "sth": 44 } ], 3, "John" ] } ], "t4": null, "t5": null, "t7": [ 5, 10, 12.0, "sth", 77, "val" ], "t8": [ 5, 10, null, "sth", 77, "val" ] } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_put/array_put.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_put/array_put.3.adm new file mode 100644 index 00000000000..e76b132477f --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_put/array_put.3.adm @@ -0,0 +1 @@ +{ "t1": [ { "$1": {{ "t-mobile", "customization", 5 }} }, { "$1": {{ "verizon", "voice-clarity", "t-mobile", 5 }} }, { "$1": {{ "iphone", "platform", "t-mobile", 5 }} }, { "$1": {{ "samsung", "voice-command", "t-mobile", 5 }} }, { "$1": {{ "verizon", "shortcut-menu", "t-mobile", 5 }} }, { "$1": {{ "motorola", "speed", "t-mobile", 5 }} }, { "$1": {{ "sprint", "voice-command", "t-mobile", 5 }} }, { "$1": {{ "motorola", "speed", "t-mobile", 5 }} }, { "$1": {{ "iphone", "voice-clarity", "t-mobile", 5 }} }, { "$1": {{ "samsung", "platform", "t-mobile", 5 }} }, { "$1": {{ "t-mobile", "shortcut-menu", 5 }} }, { "$1": {{ "verizon", "voicemail-service", "t-mobile", 5 }} } ], "t3": null, "t5": [ 5, 10, 12.0, "sth" ], "t7": null, "t8": [ 3, 2, "sth", 9, 9 ], "t9": [ 3, 2, "sth", 1, 5 ], "t10": null } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.3.adm new file mode 100644 index 00000000000..f579aa3113b --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.3.adm @@ -0,0 +1 @@ +{ "t1": [ { "$1": {{ "customization" }} }, { "$1": {{ "verizon", "voice-clarity" }} }, { "$1": {{ "iphone", "platform" }} }, { "$1": {{ "samsung", "voice-command" }} }, { "$1": {{ "verizon", "shortcut-menu" }} }, { "$1": {{ "motorola", "speed" }} }, { "$1": {{ "sprint", "voice-command" }} }, { "$1": {{ "motorola", "speed" }} }, { "$1": {{ "iphone", "voice-clarity" }} }, { "$1": {{ "samsung", "platform" }} }, { "$1": {{ "shortcut-menu" }} }, { "$1": {{ "verizon", "voicemail-service" }} } ], "t3": null, "t5": [ ], "t7": null, "t8": [ 2 ], "t9": null } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index 62659ca33e2..632185e6963 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -983,6 +983,11 @@ + + + array_prepend + + array_append @@ -1012,6 +1017,25 @@ HYR0115: Cannot compare non-primitive values (in line 22, at column 8) + + + array_insert + + + + + array_put + HYR0115: Cannot compare non-primitive values (in line 22, at column 8) + HYR0115: Cannot compare non-primitive values (in line 22, at column 8) + + + + + array_remove + HYR0115: Cannot compare non-primitive values (in line 22, at column 8) + HYR0115: Cannot compare non-primitive values (in line 22, at column 8) + + 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 da45e29991c..8a968df8d20 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 @@ -43,6 +43,7 @@ import org.apache.asterix.om.typecomputer.impl.AInt8TypeComputer; import org.apache.asterix.om.typecomputer.impl.AIntervalTypeComputer; import org.apache.asterix.om.typecomputer.impl.ALineTypeComputer; +import org.apache.asterix.om.typecomputer.impl.AListFirstTypeComputer; import org.apache.asterix.om.typecomputer.impl.AListTypeComputer; import org.apache.asterix.om.typecomputer.impl.APoint3DTypeComputer; import org.apache.asterix.om.typecomputer.impl.APointTypeComputer; @@ -54,7 +55,6 @@ import org.apache.asterix.om.typecomputer.impl.AUUIDTypeComputer; import org.apache.asterix.om.typecomputer.impl.AYearMonthDurationTypeComputer; import org.apache.asterix.om.typecomputer.impl.AnyTypeComputer; -import org.apache.asterix.om.typecomputer.impl.ArrayAppendTypeComputer; import org.apache.asterix.om.typecomputer.impl.ArrayRepeatTypeComputer; import org.apache.asterix.om.typecomputer.impl.BooleanFunctionTypeComputer; import org.apache.asterix.om.typecomputer.impl.BooleanOnlyTypeComputer; @@ -184,6 +184,12 @@ public enum SpatialFilterKind { new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "deep-equal", 2); // array functions + public static final FunctionIdentifier ARRAY_REMOVE = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-remove", FunctionIdentifier.VARARGS); + public static final FunctionIdentifier ARRAY_PUT = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-put", FunctionIdentifier.VARARGS); + public static final FunctionIdentifier ARRAY_PREPEND = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-prepend", FunctionIdentifier.VARARGS); public static final FunctionIdentifier ARRAY_APPEND = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-append", FunctionIdentifier.VARARGS); public static final FunctionIdentifier ARRAY_POSITION = @@ -194,6 +200,8 @@ public enum SpatialFilterKind { new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-reverse", 1); public static final FunctionIdentifier ARRAY_CONTAINS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-contains", 2); + public static final FunctionIdentifier ARRAY_INSERT = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-insert", FunctionIdentifier.VARARGS); // objects public static final FunctionIdentifier RECORD_MERGE = @@ -1470,10 +1478,14 @@ public static FunctionInfo lookupFunction(FunctionIdentifier fid) { addFunction(WORD_TOKENS, OrderedListOfAStringTypeComputer.INSTANCE, true); // array functions - addFunction(ARRAY_APPEND, ArrayAppendTypeComputer.INSTANCE, true); + addFunction(ARRAY_REMOVE, AListTypeComputer.INSTANCE_REMOVE, true); + addFunction(ARRAY_PUT, AListTypeComputer.INSTANCE_PUT, true); + addFunction(ARRAY_PREPEND, AListTypeComputer.INSTANCE_PREPEND, true); + addFunction(ARRAY_APPEND, AListTypeComputer.INSTANCE_APPEND, true); + addFunction(ARRAY_INSERT, AListTypeComputer.INSTANCE_INSERT, true); addFunction(ARRAY_POSITION, AInt32TypeComputer.INSTANCE, true); addFunction(ARRAY_REPEAT, ArrayRepeatTypeComputer.INSTANCE, true); - addFunction(ARRAY_REVERSE, AListTypeComputer.INSTANCE, true); + addFunction(ARRAY_REVERSE, AListFirstTypeComputer.INSTANCE, true); addFunction(ARRAY_CONTAINS, ABooleanTypeComputer.INSTANCE, true); // objects diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListFirstTypeComputer.java old mode 100755 new mode 100644 similarity index 52% rename from asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java rename to asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListFirstTypeComputer.java index f2fed42114d..5ba7ba47769 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListFirstTypeComputer.java @@ -19,36 +19,32 @@ package org.apache.asterix.om.typecomputer.impl; -import org.apache.asterix.common.exceptions.CompilationException; -import org.apache.asterix.common.exceptions.ErrorCode; -import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; -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.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; -import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; -public class ArrayAppendTypeComputer extends AbstractResultTypeComputer { +/** + * A type computer that returns the same list type as the presumably input list at argument 0. If the argument is not a + * list, it returns "ANY". + */ +public class AListFirstTypeComputer extends AbstractResultTypeComputer { + public static final AListFirstTypeComputer INSTANCE = new AListFirstTypeComputer(); - public static final ArrayAppendTypeComputer INSTANCE = new ArrayAppendTypeComputer(); + private AListFirstTypeComputer() { + } @Override protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - if (strippedInputTypes.length < 2) { - String functionName = ((AbstractFunctionCallExpression) expr).getFunctionIdentifier().getName(); - throw new CompilationException(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, expr.getSourceLocation(), 2, - functionName); - } - // type tag at [0] should be array or multiset. - ATypeTag typeTag = strippedInputTypes[0].getTypeTag(); - if (typeTag == ATypeTag.ARRAY) { - return DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE; - } else if (typeTag == ATypeTag.MULTISET) { - return DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE; - } else { - return BuiltinType.ANY; + IAType argType = strippedInputTypes[0]; + switch (argType.getTypeTag()) { + case ARRAY: + case MULTISET: + return AUnionType.createNullableType(argType); + default: + return BuiltinType.ANY; } } } diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListTypeComputer.java old mode 100644 new mode 100755 index 92730f51160..5b2513c11bb --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListTypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AListTypeComputer.java @@ -19,31 +19,68 @@ package org.apache.asterix.om.typecomputer.impl; +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; +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.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; +import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; /** - * A type computer that returns the same list type as the presumably input list at argument 0. If the argument is not a - * list, it returns "ANY". + * Returns a list that is missable/nullable. */ public class AListTypeComputer extends AbstractResultTypeComputer { - public static final AListTypeComputer INSTANCE = new AListTypeComputer(); + public static final AListTypeComputer INSTANCE_REMOVE = new AListTypeComputer(2, false, false, true); + public static final AListTypeComputer INSTANCE_PUT = new AListTypeComputer(2, false, true, true); + public static final AListTypeComputer INSTANCE_PREPEND = new AListTypeComputer(2, false, true, false); + public static final AListTypeComputer INSTANCE_APPEND = new AListTypeComputer(2, true, true, false); + public static final AListTypeComputer INSTANCE_INSERT = new AListTypeComputer(3, false, true, false); - private AListTypeComputer() { + private final int minNumArgs; + private final boolean listIsLast; + private final boolean makeOpen; + private final boolean nullInNullOut; + + private AListTypeComputer(int minNumArgs, boolean listIsLast, boolean makeOpen, boolean nullInNullOut) { + this.minNumArgs = minNumArgs; + this.listIsLast = listIsLast; + this.makeOpen = makeOpen; + this.nullInNullOut = nullInNullOut; } @Override protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - IAType argType = strippedInputTypes[0]; - switch (argType.getTypeTag()) { - case ARRAY: - case MULTISET: - return argType; - default: - return BuiltinType.ANY; + if (strippedInputTypes.length < minNumArgs) { + String functionName = ((AbstractFunctionCallExpression) expr).getFunctionIdentifier().getName(); + throw new CompilationException(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, expr.getSourceLocation(), + minNumArgs, functionName); + } + // output type should be the same as as the type tag at [list index]. The output type is nullable/missable + // since the output could be null due to other invalid arguments or the tag at [list index] itself is not list + int listIndex = 0; + if (listIsLast) { + listIndex = strippedInputTypes.length - 1; + } + + IAType listType = strippedInputTypes[listIndex]; + if (listType.getTypeTag() == ATypeTag.ARRAY) { + return makeOpen ? AUnionType.createUnknownableType(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE) + : AUnionType.createUnknownableType(listType); + } else if (listType.getTypeTag() == ATypeTag.MULTISET) { + return makeOpen ? AUnionType.createUnknownableType(DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE) + : AUnionType.createUnknownableType(listType); + } else { + return BuiltinType.ANY; } } + + @Override + protected boolean propagateNullAndMissing() { + return nullInNullOut; + } } diff --git a/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java b/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java index fc4646f4cda..29cb9a70087 100644 --- a/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java +++ b/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; @@ -105,8 +106,14 @@ private void testTypeComputer(Class c) throws Exc when(mockExpr.getOpaqueParameters()).thenReturn(opaqueParameters); // Invokes a type computer. - IResultTypeComputer instance = (IResultTypeComputer) c.getField("INSTANCE").get(null); - instance.computeType(mockExpr, mockTypeEnv, mockMetadataProvider); + IResultTypeComputer instance; + Field[] fields = c.getFields(); + for (Field field : fields) { + if (field.getName().startsWith("INSTANCE")) { + instance = (IResultTypeComputer) field.get(null); + instance.computeType(mockExpr, mockTypeEnv, mockMetadataProvider); + } + } } catch (AlgebricksException ae) { String msg = ae.getMessage(); if (msg.startsWith("ASX")) { diff --git a/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/TypeComputerTest.java b/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/TypeComputerTest.java index 1ff62b91522..c4646e5ed70 100644 --- a/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/TypeComputerTest.java +++ b/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/TypeComputerTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashSet; @@ -106,16 +107,21 @@ private boolean testTypeComputer(Class c) throws when(mockExpr.getOpaqueParameters()).thenReturn(opaqueParameters); // Tests the return type. It should be either ANY or NULLABLE/MISSABLE. - IResultTypeComputer instance = (IResultTypeComputer) c.getField("INSTANCE").get(null); - IAType resultType = instance.computeType(mockExpr, mockTypeEnv, mockMetadataProvider); - ATypeTag typeTag = resultType.getTypeTag(); - if (typeTag == ATypeTag.ANY) { - return true; - } - if (typeTag == ATypeTag.UNION) { - AUnionType unionType = (AUnionType) resultType; - return unionType.isMissableType() && unionType.isNullableType(); + IResultTypeComputer instance; + IAType resultType; + Field[] fields = c.getFields(); + for (Field field : fields) { + if (field.getName().startsWith("INSTANCE")) { + System.out.println("Test type computer INSTANCE: " + field.getName()); + instance = (IResultTypeComputer) field.get(null); + resultType = instance.computeType(mockExpr, mockTypeEnv, mockMetadataProvider); + ATypeTag typeTag = resultType.getTypeTag(); + if (typeTag != ATypeTag.ANY && !(typeTag == ATypeTag.UNION && ((AUnionType) resultType).isNullableType() + && ((AUnionType) resultType).isMissableType())) { + return false; + } + } } - return false; + return true; } } diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java new file mode 100755 index 00000000000..3701ff50488 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java @@ -0,0 +1,209 @@ +/* + * 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; + +import static org.apache.asterix.om.types.EnumDeserializer.ATYPETAGDESERIALIZER; + +import java.io.IOException; + +import org.apache.asterix.builders.IAsterixListBuilder; +import org.apache.asterix.builders.OrderedListBuilder; +import org.apache.asterix.builders.UnorderedListBuilder; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.types.AbstractCollectionType; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.runtime.evaluators.common.ListAccessor; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.ErrorCode; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.api.exceptions.SourceLocation; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.primitive.VoidPointable; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public abstract class AbstractArrayAddRemoveEval implements IScalarEvaluator { + protected static final int RETURN_MISSING = -1; + protected static final int RETURN_NULL = -2; + + private final IAType[] argTypes; + private final ArrayBackedValueStorage storage; + private final IPointable listArg; + private final IPointable[] valuesArgs; + private final IScalarEvaluator listArgEval; + private final IScalarEvaluator[] valuesEval; + private final SourceLocation sourceLocation; + private final CastTypeEvaluator caster; + private final ListAccessor listAccessor; + private final int listOffset; + private final int valuesOffset; + private final boolean comparesValues; + private final boolean makeOpen; + private final boolean acceptNullValues; + private IAsterixListBuilder orderedListBuilder; + private IAsterixListBuilder unorderedListBuilder; + + public AbstractArrayAddRemoveEval(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx, int listOffset, + int valuesOffset, int numValues, IAType[] argTypes, boolean comparesValues, SourceLocation sourceLocation, + boolean makeOpen, boolean acceptNullValues) throws HyracksDataException { + this.listOffset = listOffset; + this.valuesOffset = valuesOffset; + this.argTypes = argTypes; + this.comparesValues = comparesValues; + this.sourceLocation = sourceLocation; + this.makeOpen = makeOpen; + this.acceptNullValues = acceptNullValues; + orderedListBuilder = null; + unorderedListBuilder = null; + listAccessor = new ListAccessor(); + caster = new CastTypeEvaluator(); + storage = new ArrayBackedValueStorage(); + listArg = new VoidPointable(); + listArgEval = args[listOffset].createScalarEvaluator(ctx); + valuesArgs = new IPointable[numValues]; + valuesEval = new IScalarEvaluator[numValues]; + for (int i = 0; i < numValues; i++) { + valuesArgs[i] = new VoidPointable(); + valuesEval[i] = args[i + valuesOffset].createScalarEvaluator(ctx); + } + } + + /** + * @param listType the type of the list, ordered or unordered. + * @param listArg the list into which to insert the items at the calculated returned position + * @param tuple the tuple that contains the arguments including position argument + * @return -1 if position value is missing, -2 if null, otherwise should return the adjusted position value, >= 0 + */ + protected abstract int getPosition(IFrameTupleReference tuple, IPointable listArg, ATypeTag listType) + throws HyracksDataException; + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + // get the list argument, 1st or last argument, make sure it's a list + listArgEval.evaluate(tuple, listArg); + ATypeTag listArgTag = ATYPETAGDESERIALIZER.deserialize(listArg.getByteArray()[listArg.getStartOffset()]); + + // evaluate the position argument if provided by some functions + int adjustedPosition = getPosition(tuple, listArg, listArgTag); + + if (listArgTag == ATypeTag.MISSING || adjustedPosition == RETURN_MISSING) { + PointableHelper.setMissing(result); + return; + } + + boolean returnNull = false; + if (!listArgTag.isListType() || adjustedPosition == RETURN_NULL) { + returnNull = true; + } + + // evaluate values to be added/removed + ATypeTag valueTag; + IAType defaultOpenType; + boolean encounteredNonPrimitive = false; + for (int i = 0; i < valuesEval.length; i++) { + // cast val to open if needed. don't cast if function will return null anyway, e.g. list arg was not list + defaultOpenType = DefaultOpenFieldType.getDefaultOpenFieldType(argTypes[i + valuesOffset].getTypeTag()); + if (defaultOpenType != null && !returnNull) { + caster.reset(defaultOpenType, argTypes[i + valuesOffset], valuesEval[i]); + caster.evaluate(tuple, valuesArgs[i]); + } else { + valuesEval[i].evaluate(tuple, valuesArgs[i]); + } + valueTag = ATYPETAGDESERIALIZER.deserialize(valuesArgs[i].getByteArray()[valuesArgs[i].getStartOffset()]); + // for now, we don't support deep equality of object/lists. Throw an error if the value is of these types + if (comparesValues && valueTag.isDerivedType()) { + encounteredNonPrimitive = true; + } + if (valueTag == ATypeTag.MISSING) { + PointableHelper.setMissing(result); + return; + } + if (!acceptNullValues && valueTag == ATypeTag.NULL) { + returnNull = true; + } + } + + if (returnNull) { + PointableHelper.setNull(result); + return; + } + + if (encounteredNonPrimitive) { + throw HyracksDataException.create(ErrorCode.CANNOT_COMPARE_COMPLEX, sourceLocation); + } + // all arguments are valid + AbstractCollectionType listType = (AbstractCollectionType) argTypes[listOffset]; + IAsterixListBuilder listBuilder; + // create the new list to be returned. cast the input list and make it open if required + if (listArgTag == ATypeTag.ARRAY) { + if (orderedListBuilder == null) { + orderedListBuilder = new OrderedListBuilder(); + } + listBuilder = orderedListBuilder; + if (makeOpen) { + listType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE; + caster.reset(listType, argTypes[listOffset], listArgEval); + caster.evaluate(tuple, listArg); + } + } else { + if (unorderedListBuilder == null) { + unorderedListBuilder = new UnorderedListBuilder(); + } + listBuilder = unorderedListBuilder; + if (makeOpen) { + listType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE; + caster.reset(listType, argTypes[listOffset], listArgEval); + caster.evaluate(tuple, listArg); + } + } + + listBuilder.reset(listType); + listAccessor.reset(listArg.getByteArray(), listArg.getStartOffset()); + try { + processList(listAccessor, listBuilder, valuesArgs, adjustedPosition); + storage.reset(); + listBuilder.write(storage.getDataOutput(), true); + result.set(storage); + } catch (IOException e) { + throw HyracksDataException.create(e); + } + } + + protected void processList(ListAccessor listAccessor, IAsterixListBuilder listBuilder, IPointable[] values, + int position) throws IOException { + int i; + for (i = 0; i < position; i++) { + storage.reset(); + listAccessor.writeItem(i, storage.getDataOutput()); + listBuilder.addItem(storage); + } + // insert the values arguments + for (int j = 0; j < values.length; j++) { + listBuilder.addItem(values[j]); + } + for (; i < listAccessor.size(); i++) { + storage.reset(); + listAccessor.writeItem(i, storage.getDataOutput()); + listBuilder.addItem(storage); + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java index 3792b8e88d0..aae4d02286a 100755 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java @@ -18,24 +18,15 @@ */ package org.apache.asterix.runtime.evaluators.functions; -import static org.apache.asterix.om.types.EnumDeserializer.ATYPETAGDESERIALIZER; - -import java.io.IOException; -import java.util.Arrays; - -import org.apache.asterix.builders.IAsterixListBuilder; -import org.apache.asterix.builders.OrderedListBuilder; -import org.apache.asterix.builders.UnorderedListBuilder; +import org.apache.asterix.dataflow.data.nontagged.serde.AOrderedListSerializerDeserializer; +import org.apache.asterix.dataflow.data.nontagged.serde.AUnorderedListSerializerDeserializer; 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.pointables.base.DefaultOpenFieldType; import org.apache.asterix.om.types.ATypeTag; -import org.apache.asterix.om.types.AbstractCollectionType; import org.apache.asterix.om.types.IAType; import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; -import org.apache.asterix.runtime.evaluators.common.ListAccessor; import org.apache.asterix.runtime.functions.FunctionTypeInferers; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; @@ -44,8 +35,6 @@ import org.apache.hyracks.api.context.IHyracksTaskContext; import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.data.std.api.IPointable; -import org.apache.hyracks.data.std.primitive.VoidPointable; -import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; public class ArrayAppendDescriptor extends AbstractScalarFunctionDynamicDescriptor { @@ -84,92 +73,26 @@ public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) thr @Override public void setImmutableStates(Object... states) { - argTypes = Arrays.copyOf(states, states.length, IAType[].class); + argTypes = (IAType[]) states; } - public class ArrayAppendFunction implements IScalarEvaluator { - private final ArrayBackedValueStorage storage; - private final IPointable listArg; - private final IPointable[] appendedValues; - private final IScalarEvaluator listArgEval; - private final IScalarEvaluator[] appendedValuesEval; + public class ArrayAppendFunction extends AbstractArrayAddRemoveEval { public ArrayAppendFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx) throws HyracksDataException { - storage = new ArrayBackedValueStorage(); - listArg = new VoidPointable(); - listArgEval = args[0].createScalarEvaluator(ctx); - appendedValues = new IPointable[args.length - 1]; - appendedValuesEval = new IScalarEvaluator[args.length - 1]; - for (int i = 1; i < args.length; i++) { - appendedValues[i - 1] = new VoidPointable(); - appendedValuesEval[i - 1] = args[i].createScalarEvaluator(ctx); - } + super(args, ctx, 0, 1, args.length - 1, argTypes, false, sourceLoc, true, true); } @Override - public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { - // get the list argument, 1st argument, make sure it's a list - listArgEval.evaluate(tuple, listArg); - byte listArgType = listArg.getByteArray()[listArg.getStartOffset()]; - - CastTypeEvaluator caster = null; - AbstractCollectionType listType = null; - IAsterixListBuilder listBuilder = null; - // create the new list to be returned. The item type is always "ANY" - // cast the input list and make it open - if (listArgType == ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG) { - listBuilder = new OrderedListBuilder(); - listType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE; - caster = new CastTypeEvaluator(listType, argTypes[0], listArgEval); - caster.evaluate(tuple, listArg); - } else if (listArgType == ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG) { - listBuilder = new UnorderedListBuilder(); - listType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE; - caster = new CastTypeEvaluator(listType, argTypes[0], listArgEval); - caster.evaluate(tuple, listArg); - } - // else, don't return null right away. evaluate rest of args as some may be missing, return missing instead - IAType defaultOpenType; - for (int i = 0; i < appendedValuesEval.length; i++) { - // cast to open if necessary - defaultOpenType = DefaultOpenFieldType.getDefaultOpenFieldType(argTypes[i + 1].getTypeTag()); - if (defaultOpenType != null && caster != null) { - caster.reset(defaultOpenType, argTypes[i + 1], appendedValuesEval[i]); - caster.evaluate(tuple, appendedValues[i]); - } else { - // either no casting is needed (e.g. int and the like) or evaluate normally for the below case: - // when caster == null, it means the first arg was not a list and a null would be returned but - // evaluate values to be appended normally in case missing exists and return missing instead of null - appendedValuesEval[i].evaluate(tuple, appendedValues[i]); - } - } - - if (!ATYPETAGDESERIALIZER.deserialize(listArgType).isListType()) { - PointableHelper.setNull(result); - return; - } - - // arguments are good: no nulls/missings and 1st arg is a list - listBuilder.reset(listType); - ListAccessor listAccessor = new ListAccessor(); - listAccessor.reset(listArg.getByteArray(), listArg.getStartOffset()); - try { - // get the list items one by one and append to the new list - for (int i = 0; i < listAccessor.size(); i++) { - storage.reset(); - listAccessor.writeItem(i, storage.getDataOutput()); - listBuilder.addItem(storage); - } - // append the values arguments - for (IPointable appendedValue : appendedValues) { - listBuilder.addItem(appendedValue); - } - storage.reset(); - listBuilder.write(storage.getDataOutput(), true); - result.set(storage); - } catch (IOException e) { - throw HyracksDataException.create(e); + protected int getPosition(IFrameTupleReference tuple, IPointable l, ATypeTag listTag) + throws HyracksDataException { + // l = list + if (listTag == ATypeTag.ARRAY) { + return AOrderedListSerializerDeserializer.getNumberOfItems(l.getByteArray(), l.getStartOffset()); + } else if (listTag == ATypeTag.MULTISET) { + return AUnorderedListSerializerDeserializer.getNumberOfItems(l.getByteArray(), l.getStartOffset()); + } else { + return RETURN_NULL; } } } diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java new file mode 100755 index 00000000000..3d3c54c81e9 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java @@ -0,0 +1,129 @@ +/* + * 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; + +import static org.apache.asterix.om.types.EnumDeserializer.ATYPETAGDESERIALIZER; + +import org.apache.asterix.dataflow.data.nontagged.serde.AOrderedListSerializerDeserializer; +import org.apache.asterix.dataflow.data.nontagged.serde.AUnorderedListSerializerDeserializer; +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.types.ATypeTag; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.om.types.hierachy.ATypeHierarchy; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.primitive.TaggedValuePointable; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class ArrayInsertDescriptor extends AbstractScalarFunctionDynamicDescriptor { + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new ArrayInsertDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.ARRAY_INSERT; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) + throws AlgebricksException { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new ArrayInsertFunction(args, ctx); + } + }; + } + + @Override + public void setImmutableStates(Object... states) { + argTypes = (IAType[]) states; + } + + public class ArrayInsertFunction extends AbstractArrayAddRemoveEval { + private final TaggedValuePointable positionArg; + private final IScalarEvaluator positionArgEval; + + public ArrayInsertFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx) + throws HyracksDataException { + super(args, ctx, 0, 2, args.length - 2, argTypes, false, sourceLoc, true, true); + positionArg = new TaggedValuePointable(); + positionArgEval = args[1].createScalarEvaluator(ctx); + } + + @Override + protected int getPosition(IFrameTupleReference tuple, IPointable l, ATypeTag listTag) + throws HyracksDataException { + positionArgEval.evaluate(tuple, positionArg); + if (positionArg.getTag() == ATypeTag.SERIALIZED_MISSING_TYPE_TAG) { + return RETURN_MISSING; + } + + int position; + if (!ATypeHierarchy.isCompatible(ATypeTag.INTEGER, ATYPETAGDESERIALIZER.deserialize(positionArg.getTag())) + || !listTag.isListType()) { + return RETURN_NULL; + } else { + String name = getIdentifier().getName(); + position = ATypeHierarchy.getIntegerValue(name, 1, positionArg.getByteArray(), + positionArg.getStartOffset()); + // list size + int size; + if (listTag == ATypeTag.ARRAY) { + size = AOrderedListSerializerDeserializer.getNumberOfItems(l.getByteArray(), l.getStartOffset()); + } else { + size = AUnorderedListSerializerDeserializer.getNumberOfItems(l.getByteArray(), l.getStartOffset()); + } + // adjust position for negative positions + if (position < 0) { + position = size + position; + } + // position should always be positive now and should be within [0-list_size] + if (position < 0 || position > size) { + return RETURN_NULL; + } + return position; + } + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPrependDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPrependDescriptor.java new file mode 100755 index 00000000000..7e52df5a58b --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPrependDescriptor.java @@ -0,0 +1,90 @@ +/* + * 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; + +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.types.ATypeTag; +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.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class ArrayPrependDescriptor extends AbstractScalarFunctionDynamicDescriptor { + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new ArrayPrependDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.ARRAY_PREPEND; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) + throws AlgebricksException { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new ArrayPrependFunction(args, ctx); + } + }; + } + + @Override + public void setImmutableStates(Object... states) { + argTypes = (IAType[]) states; + } + + public class ArrayPrependFunction extends AbstractArrayAddRemoveEval { + + public ArrayPrependFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx) + throws HyracksDataException { + super(args, ctx, args.length - 1, 0, args.length - 1, argTypes, false, sourceLoc, true, true); + } + + @Override + protected int getPosition(IFrameTupleReference tuple, IPointable listArg, ATypeTag listTag) + throws HyracksDataException { + return 0; + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPutDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPutDescriptor.java new file mode 100755 index 00000000000..64353696cae --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayPutDescriptor.java @@ -0,0 +1,136 @@ +/* + * 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; + +import java.io.IOException; + +import org.apache.asterix.builders.IAsterixListBuilder; +import org.apache.asterix.dataflow.data.nontagged.comparators.AObjectAscBinaryComparatorFactory; +import org.apache.asterix.dataflow.data.nontagged.serde.AOrderedListSerializerDeserializer; +import org.apache.asterix.dataflow.data.nontagged.serde.AUnorderedListSerializerDeserializer; +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.types.ATypeTag; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.evaluators.common.ListAccessor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.dataflow.value.IBinaryComparator; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class ArrayPutDescriptor extends AbstractScalarFunctionDynamicDescriptor { + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new ArrayPutDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.ARRAY_PUT; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) + throws AlgebricksException { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new ArrayPutFunction(args, ctx); + } + }; + } + + @Override + public void setImmutableStates(Object... states) { + argTypes = (IAType[]) states; + } + + public class ArrayPutFunction extends AbstractArrayAddRemoveEval { + private final ArrayBackedValueStorage storage; + private final IBinaryComparator comp; + + public ArrayPutFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx) throws HyracksDataException { + super(args, ctx, 0, 1, args.length - 1, argTypes, true, sourceLoc, true, false); + comp = AObjectAscBinaryComparatorFactory.INSTANCE.createBinaryComparator(); + storage = new ArrayBackedValueStorage(); + } + + @Override + protected int getPosition(IFrameTupleReference tuple, IPointable l, ATypeTag listTag) + throws HyracksDataException { + // l = list + if (listTag == ATypeTag.ARRAY) { + return AOrderedListSerializerDeserializer.getNumberOfItems(l.getByteArray(), l.getStartOffset()); + } else if (listTag == ATypeTag.MULTISET) { + return AUnorderedListSerializerDeserializer.getNumberOfItems(l.getByteArray(), l.getStartOffset()); + } else { + return RETURN_NULL; + } + } + + @Override + protected void processList(ListAccessor listAccessor, IAsterixListBuilder listBuilder, IPointable[] values, + int position) throws IOException { + boolean[] dontAdd = new boolean[values.length]; + // get the list items one by one and append to the new list + for (int i = 0; i < listAccessor.size(); i++) { + storage.reset(); + listAccessor.writeItem(i, storage.getDataOutput()); + listBuilder.addItem(storage); + // mark the equal values to skip adding them + for (int j = 0; j < values.length; j++) { + if (!dontAdd[j] + && comp.compare(storage.getByteArray(), storage.getStartOffset(), storage.getLength(), + values[j].getByteArray(), values[j].getStartOffset(), values[j].getLength()) == 0) { + dontAdd[j] = true; + } + // skip comparison if the value is already marked + } + } + // append the values arguments only if they are not already present in the list, i.e. not marked + for (int i = 0; i < values.length; i++) { + if (!dontAdd[i]) { + listBuilder.addItem(values[i]); + } + } + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayRemoveDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayRemoveDescriptor.java new file mode 100755 index 00000000000..ff7ace188f1 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayRemoveDescriptor.java @@ -0,0 +1,123 @@ +/* + * 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; + +import java.io.IOException; + +import org.apache.asterix.builders.IAsterixListBuilder; +import org.apache.asterix.dataflow.data.nontagged.comparators.AObjectAscBinaryComparatorFactory; +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.types.ATypeTag; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.evaluators.common.ListAccessor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.dataflow.value.IBinaryComparator; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class ArrayRemoveDescriptor extends AbstractScalarFunctionDynamicDescriptor { + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new ArrayRemoveDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.ARRAY_REMOVE; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) + throws AlgebricksException { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new ArrayRemoveFunction(args, ctx); + } + }; + } + + @Override + public void setImmutableStates(Object... states) { + argTypes = (IAType[]) states; + } + + public class ArrayRemoveFunction extends AbstractArrayAddRemoveEval { + private final ArrayBackedValueStorage storage; + private final IBinaryComparator comp; + + public ArrayRemoveFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx) + throws HyracksDataException { + super(args, ctx, 0, 1, args.length - 1, argTypes, true, sourceLoc, false, false); + storage = new ArrayBackedValueStorage(); + comp = AObjectAscBinaryComparatorFactory.INSTANCE.createBinaryComparator(); + } + + @Override + protected int getPosition(IFrameTupleReference tuple, IPointable listArg, ATypeTag listTag) + throws HyracksDataException { + return 0; + } + + @Override + protected void processList(ListAccessor listAccessor, IAsterixListBuilder listBuilder, IPointable[] removed, + int position) throws IOException { + // get the list items one by one and append to the new list only if the list item is not in removed list + boolean addItem; + for (int i = 0; i < listAccessor.size(); i++) { + storage.reset(); + listAccessor.writeItem(i, storage.getDataOutput()); + addItem = true; + for (int j = 0; j < removed.length; j++) { + if (comp.compare(storage.getByteArray(), storage.getStartOffset(), storage.getLength(), + removed[j].getByteArray(), removed[j].getStartOffset(), removed[j].getLength()) == 0) { + addItem = false; + break; + } + } + if (addItem) { + listBuilder.addItem(storage); + } + } + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java index 7e3195104d1..d1879b24a0e 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java @@ -37,20 +37,18 @@ public class CastTypeEvaluator implements IScalarEvaluator { private IScalarEvaluator argEvaluator; private final IPointable argPointable = new VoidPointable(); - private final PointableAllocator allocator = new PointableAllocator(); private IVisitablePointable inputPointable; private IVisitablePointable resultPointable; + private final ACastVisitor castVisitor = createCastVisitor(); + private final Triple arg = new Triple<>(null, null, null); - private final ACastVisitor castVisitor; - private final Triple arg; + public CastTypeEvaluator() { + // reset() should be called after using this constructor before calling any method + } public CastTypeEvaluator(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) { - this.argEvaluator = argEvaluator; - this.inputPointable = allocatePointable(inputType, reqType); - this.resultPointable = allocatePointable(reqType, inputType); - this.arg = new Triple<>(resultPointable, reqType, Boolean.FALSE); - this.castVisitor = createCastVisitor(); + reset(reqType, inputType, argEvaluator); } public void reset(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) { @@ -59,6 +57,7 @@ public void reset(IAType reqType, IAType inputType, IScalarEvaluator argEvaluato this.resultPointable = allocatePointable(reqType, inputType); this.arg.first = resultPointable; this.arg.second = reqType; + this.arg.third = Boolean.FALSE; } protected ACastVisitor createCastVisitor() { diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java index 004e50a34f4..48b1785dd47 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java @@ -43,7 +43,7 @@ public class PointableHelper { private static final byte[] NULL_BYTES = new byte[] { ATypeTag.SERIALIZED_NULL_TYPE_TAG }; - + private static final byte[] MISSING_BYTES = new byte[] { ATypeTag.SERIALIZED_MISSING_TYPE_TAG }; private final UTF8StringWriter utf8Writer; public PointableHelper() { @@ -135,4 +135,8 @@ public void serializeString(String str, IMutableValueStorage vs, boolean writeTa public static void setNull(IPointable pointable) { pointable.set(NULL_BYTES, 0, NULL_BYTES.length); } + + public static void setMissing(IPointable pointable) { + pointable.set(MISSING_BYTES, 0, MISSING_BYTES.length); + } } 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 199cc406394..519cb8697ec 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 @@ -145,7 +145,11 @@ import org.apache.asterix.runtime.evaluators.functions.AnyCollectionMemberDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayAppendDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayContainsDescriptor; +import org.apache.asterix.runtime.evaluators.functions.ArrayInsertDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayPositionDescriptor; +import org.apache.asterix.runtime.evaluators.functions.ArrayPrependDescriptor; +import org.apache.asterix.runtime.evaluators.functions.ArrayPutDescriptor; +import org.apache.asterix.runtime.evaluators.functions.ArrayRemoveDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayRepeatDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayReverseDescriptor; import org.apache.asterix.runtime.evaluators.functions.CastTypeDescriptor; @@ -376,7 +380,11 @@ public static FunctionCollection createDefaultFunctionCollection() { FunctionCollection fc = new FunctionCollection(); // array functions - fc.addGenerated(ArrayAppendDescriptor.FACTORY); + fc.add(ArrayRemoveDescriptor.FACTORY); + fc.add(ArrayPutDescriptor.FACTORY); + fc.add(ArrayPrependDescriptor.FACTORY); + fc.add(ArrayAppendDescriptor.FACTORY); + fc.add(ArrayInsertDescriptor.FACTORY); fc.addGenerated(ArrayPositionDescriptor.FACTORY); fc.addGenerated(ArrayRepeatDescriptor.FACTORY); fc.addGenerated(ArrayReverseDescriptor.FACTORY);