[ASTERIXDB-2340][FUN] Implement object_length(), object_names() - user model changes: yes - storage format changes: no - interface changes: no
Details: - Implement object_length(), object_names() functions - Consolidate type inferers for some object accessor functions Change-Id: I1108466ffe4f6b002fa7dd25f76dd5e8d537b0be Reviewed-on: https://asterix-gerrit.ics.uci.edu/2522 Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Contrib: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Till Westmann <ti...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/f7c7059c Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/f7c7059c Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/f7c7059c Branch: refs/heads/release-0.9.4-pre-rc Commit: f7c7059c7e3145129d32de474f7401c25df76d32 Parents: 8d28443 Author: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Authored: Mon Mar 26 15:57:48 2018 -0700 Committer: Michael Blow <mb...@apache.org> Committed: Mon Mar 26 20:53:58 2018 -0700 ---------------------------------------------------------------------- .../queries_sqlpp/objects/ObjectsQueries.xml | 10 ++ .../object_length/object_length.1.ddl.sqlpp | 49 +++++++ .../object_length/object_length.2.update.sqlpp | 29 ++++ .../object_length/object_length.3.query.sqlpp | 56 ++++++++ .../object_names/object_names.1.ddl.sqlpp | 49 +++++++ .../object_names/object_names.2.update.sqlpp | 29 ++++ .../object_names/object_names.3.query.sqlpp | 59 ++++++++ .../objects/object_length/object_length.3.adm | 1 + .../objects/object_names/object_names.3.adm | 1 + .../src/main/markdown/builtins/8_record.md | 54 ++++++++ .../asterix/om/functions/BuiltinFunctions.java | 6 + .../typecomputer/impl/AInt64TypeComputer.java | 14 +- .../impl/OrderedListOfAStringTypeComputer.java | 13 +- .../records/GetRecordFieldValueDescriptor.java | 2 +- .../records/GetRecordFieldsDescriptor.java | 2 +- .../records/RecordLengthDescriptor.java | 122 +++++++++++++++++ .../records/RecordNamesDescriptor.java | 134 +++++++++++++++++++ .../records/RecordPairsDescriptor.java | 2 +- .../runtime/functions/FunctionCollection.java | 4 + .../runtime/functions/FunctionTypeInferers.java | 66 ++++----- 20 files changed, 653 insertions(+), 49 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/ObjectsQueries.xml ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/ObjectsQueries.xml b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/ObjectsQueries.xml index c5ff15b..507e276 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/ObjectsQueries.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/ObjectsQueries.xml @@ -108,6 +108,16 @@ </compilation-unit> </test-case> <test-case FilePath="objects"> + <compilation-unit name="object_length"> + <output-dir compare="Text">object_length</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="objects"> + <compilation-unit name="object_names"> + <output-dir compare="Text">object_names</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="objects"> <compilation-unit name="object_pairs"> <output-dir compare="Text">object_pairs</output-dir> </compilation-unit> http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.1.ddl.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.1.ddl.sqlpp new file mode 100644 index 0000000..a50bf21 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.1.ddl.sqlpp @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Description : Testing object_length under different queries. + * Expected Res : Success + */ + +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 +}; + +create type TinySocial.TweetMessageType as closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create dataset TwitterUsers(TwitterUserType) primary key `screen-name`; + +create dataset TweetMessages(TweetMessageType) primary key tweetid; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.2.update.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.2.update.sqlpp new file mode 100644 index 0000000..1bd2260 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.2.update.sqlpp @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/* + * Description : Testing object_length under different queries. + * Expected Res : Success + */ + +use TinySocial; + +load dataset TwitterUsers using localfs ((`path`=`asterix_nc1://data/tinysocial/twu.adm`),(`format`=`adm`)); + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.3.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.3.query.sqlpp new file mode 100644 index 0000000..67d88d9 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_length/object_length.3.query.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. + */ + +/* + * Description : Testing object_length under different queries. + * Expected Res : Success + */ + +use TinySocial; + +{ + "t1": [ + object_length(missing) is missing, + object_length(null) is null, + object_length("{}") is null, + object_length(0) is null, + is_number(object_length({})) + ], + + "t2": [ object_length({}), object_length({"a":1}), object_length({"a":1, "b": 2}) ], + + "t3": ( + select value object_length(o) + from ( + select x, current_datetime() y from range(1, 3) x + ) o + ), + + /* open type */ + "t4": ( + select distinct value object_length(t) + from TwitterUsers as t + ), + + /* closed type */ + "t5": ( + select distinct value object_length(user) + from TweetMessages as t + ) +}; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.1.ddl.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.1.ddl.sqlpp new file mode 100644 index 0000000..4f507b1 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.1.ddl.sqlpp @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Description : Testing object_names under different queries. + * Expected Res : Success + */ + +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 +}; + +create type TinySocial.TweetMessageType as closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create dataset TwitterUsers(TwitterUserType) primary key `screen-name`; + +create dataset TweetMessages(TweetMessageType) primary key tweetid; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.2.update.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.2.update.sqlpp new file mode 100644 index 0000000..cf03bed --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.2.update.sqlpp @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/* + * Description : Testing object_names under different queries. + * Expected Res : Success + */ + +use TinySocial; + +load dataset TwitterUsers using localfs ((`path`=`asterix_nc1://data/tinysocial/twu.adm`),(`format`=`adm`)); + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.3.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.3.query.sqlpp new file mode 100644 index 0000000..ae20bb0 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_names/object_names.3.query.sqlpp @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/* + * Description : Testing object_names under different queries. + * Expected Res : Success + */ + +use TinySocial; + +{ + "t1": [ + object_names(missing) is missing, + object_names(null) is null, + object_names("{}") is null, + object_names(0) is null, + is_array(object_names({})) + ], + + "t2": [ object_names({}), object_names({"a":1}), object_names({"a":1, "b": 2}), + object_names({"a":1, "b": 2, "c": 3}) ], + + "t3": ( + select value object_names(o) + from ( + select x, current_datetime() y from range(1, 3) x + ) o + ), + + /* open type */ + "t4": ( + select distinct string_join((select value f from g order by f), ",") res + from TwitterUsers as t, object_names(t) f + group by t.`screen-name` group as g + ), + + /* closed type */ + "t5": ( + select distinct string_join((select value f from g order by f), ",") res + from TweetMessages as t, object_names(t) f + group by t.tweetid group as g + ) +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_length/object_length.3.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_length/object_length.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_length/object_length.3.adm new file mode 100644 index 0000000..f03b7d5 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_length/object_length.3.adm @@ -0,0 +1 @@ +{ "t1": [ true, true, true, true, true ], "t2": [ 0, 1, 2 ], "t3": [ 2, 2, 2 ], "t4": [ 6 ], "t5": [ 6 ] } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_names/object_names.3.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_names/object_names.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_names/object_names.3.adm new file mode 100644 index 0000000..04441f8 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_names/object_names.3.adm @@ -0,0 +1 @@ +{ "t1": [ true, true, true, true, true ], "t2": [ [ ], [ "a" ], [ "a", "b" ], [ "a", "b", "c" ] ], "t3": [ [ "x", "y" ], [ "x", "y" ], [ "x", "y" ] ], "t4": [ { "res": "followers_count,friends_count,lang,name,screen-name,statuses_count" } ], "t5": [ { "res": "message-text,referred-topics,send-time,sender-location,tweetid,user" } ] } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md b/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md index d7ec35b..fefdb7b 100644 --- a/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md +++ b/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md @@ -233,3 +233,57 @@ "id": 1 } +### object_length ### + * Syntax: + + object_length(input_object) + + * Returns number of top-level fields in the given object + * Arguments: + * `input_object` : an object value. + * Return Value: + * an integer that represents the number of top-level fields in the given object, + * `missing` if the argument is a `missing` value, + * `null` if the argument is a `null` value or any other non-object value + + * Example: + + object_length( + { + "id": 1, + "project": "AsterixDB", + "address": {"city": "Irvine", "state": "CA"}, + } + ); + + * The expected result is: + + 3 + +### object_names ### + * Syntax: + + object_names(input_object) + + * Returns names of top-level fields in the given object + * Arguments: + * `input_object` : an object value. + * Return Value: + * an array with top-level field names of the given object, + * `missing` if the argument is a `missing` value, + * `null` if the argument is a `null` value or any other non-object value + + * Example: + + object_names( + { + "id": 1, + "project": "AsterixDB", + "address": {"city": "Irvine", "state": "CA"}, + } + ); + + * The expected result is: + + [ "id", "project", "address" ] + http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java ---------------------------------------------------------------------- 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 92617ee..6b86a26 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 @@ -205,6 +205,10 @@ public class BuiltinFunctions { new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "get-object-fields", 1); public static final FunctionIdentifier GET_RECORD_FIELD_VALUE = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "get-object-field-value", 2); + public static final FunctionIdentifier RECORD_LENGTH = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-length", 1); + public static final FunctionIdentifier RECORD_NAMES = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-names", 1); public static final FunctionIdentifier RECORD_PAIRS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-pairs", FunctionIdentifier.VARARGS); @@ -1214,6 +1218,8 @@ public class BuiltinFunctions { addFunction(FIELD_ACCESS_BY_NAME, FieldAccessByNameResultType.INSTANCE, true); addFunction(GET_RECORD_FIELDS, OrderedListOfAnyTypeComputer.INSTANCE, true); addFunction(GET_RECORD_FIELD_VALUE, FieldAccessNestedResultType.INSTANCE, true); + addFunction(RECORD_LENGTH, AInt64TypeComputer.INSTANCE_NULLABLE, true); + addFunction(RECORD_NAMES, OrderedListOfAStringTypeComputer.INSTANCE_NULLABLE, true); addFunction(RECORD_PAIRS, RecordPairsTypeComputer.INSTANCE, true); // temporal type accessors http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AInt64TypeComputer.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AInt64TypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AInt64TypeComputer.java index 9909c3d..d495acf 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AInt64TypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AInt64TypeComputer.java @@ -19,6 +19,7 @@ package org.apache.asterix.om.typecomputer.impl; import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; +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; @@ -26,14 +27,19 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; public class AInt64TypeComputer extends AbstractResultTypeComputer { - public static final AInt64TypeComputer INSTANCE = new AInt64TypeComputer(); + public static final AInt64TypeComputer INSTANCE = new AInt64TypeComputer(false); - private AInt64TypeComputer() { + public static final AInt64TypeComputer INSTANCE_NULLABLE = new AInt64TypeComputer(true); + + private final IAType type; + + private AInt64TypeComputer(boolean nullable) { + IAType t = BuiltinType.AINT64; + type = nullable ? AUnionType.createNullableType(t) : t; } @Override protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - return BuiltinType.AINT64; + return type; } - } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAStringTypeComputer.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAStringTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAStringTypeComputer.java index bd35872..1d315e2 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAStringTypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAStringTypeComputer.java @@ -20,6 +20,7 @@ package org.apache.asterix.om.typecomputer.impl; import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; import org.apache.asterix.om.types.AOrderedListType; +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; @@ -27,13 +28,19 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; public class OrderedListOfAStringTypeComputer extends AbstractResultTypeComputer { - public static final OrderedListOfAStringTypeComputer INSTANCE = new OrderedListOfAStringTypeComputer(); + public static final OrderedListOfAStringTypeComputer INSTANCE = new OrderedListOfAStringTypeComputer(false); - private OrderedListOfAStringTypeComputer() { + public static final OrderedListOfAStringTypeComputer INSTANCE_NULLABLE = new OrderedListOfAStringTypeComputer(true); + + private final IAType type; + + private OrderedListOfAStringTypeComputer(boolean nullable) { + IAType t = new AOrderedListType(BuiltinType.ASTRING, null); + type = nullable ? AUnionType.createNullableType(t) : t; } @Override protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - return new AOrderedListType(BuiltinType.ASTRING, null); + return type; } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueDescriptor.java index 631dd70..4c07e2d 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueDescriptor.java @@ -38,7 +38,7 @@ public class GetRecordFieldValueDescriptor extends AbstractScalarFunctionDynamic @Override public IFunctionTypeInferer createFunctionTypeInferer() { - return new FunctionTypeInferers.GetRecordFieldValueTypeInferer(); + return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_STRICT; } }; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldsDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldsDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldsDescriptor.java index 273e3ca..57e98d0 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldsDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldsDescriptor.java @@ -38,7 +38,7 @@ public class GetRecordFieldsDescriptor extends AbstractScalarFunctionDynamicDesc @Override public IFunctionTypeInferer createFunctionTypeInferer() { - return new FunctionTypeInferers.GetRecordFieldsTypeInferer(); + return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_STRICT; } }; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordLengthDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordLengthDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordLengthDescriptor.java new file mode 100644 index 0000000..cda069d --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordLengthDescriptor.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import java.io.DataOutput; + +import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider; +import org.apache.asterix.om.base.AInt64; +import org.apache.asterix.om.base.AMutableInt64; +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.nonvisitor.ARecordPointable; +import org.apache.asterix.om.types.ARecordType; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.evaluators.functions.PointableHelper; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +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.ISerializerDeserializer; +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 RecordLengthDescriptor extends AbstractScalarFunctionDynamicDescriptor { + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new RecordLengthDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_LAX; + } + }; + + private static final long serialVersionUID = 1L; + private ARecordType recType; + + @Override + public void setImmutableStates(Object... states) { + this.recType = (ARecordType) states[0]; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new IScalarEvaluator() { + + private IScalarEvaluator eval0 = args[0].createScalarEvaluator(ctx); + + private final IPointable argPtr = new VoidPointable(); + private final ARecordPointable recordPointable = + (ARecordPointable) ARecordPointable.FACTORY.createPointable(); + private final AMutableInt64 aInt64 = new AMutableInt64(0); + @SuppressWarnings("unchecked") + private final ISerializerDeserializer<AInt64> int64Serde = + SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT64); + private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage(); + private final DataOutput out = resultStorage.getDataOutput(); + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable resultPointable) + throws HyracksDataException { + resultStorage.reset(); + eval0.evaluate(tuple, argPtr); + + byte[] data = argPtr.getByteArray(); + int offset = argPtr.getStartOffset(); + + if (data[offset] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) { + PointableHelper.setNull(resultPointable); + return; + } + + recordPointable.set(data, offset, argPtr.getLength()); + int n = recordPointable.getSchemeFieldCount(recType) + + recordPointable.getOpenFieldCount(recType); + + aInt64.setValue(n); + int64Serde.serialize(aInt64, out); + resultPointable.set(resultStorage); + } + }; + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.RECORD_LENGTH; + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordNamesDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordNamesDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordNamesDescriptor.java new file mode 100644 index 0000000..bb8e3e7 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordNamesDescriptor.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import java.io.DataOutput; +import java.io.IOException; + +import org.apache.asterix.builders.OrderedListBuilder; +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.nonvisitor.ARecordPointable; +import org.apache.asterix.om.types.AOrderedListType; +import org.apache.asterix.om.types.ARecordType; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.evaluators.functions.PointableHelper; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +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.VoidPointable; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class RecordNamesDescriptor extends AbstractScalarFunctionDynamicDescriptor { + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new RecordNamesDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_LAX; + } + }; + + private static final long serialVersionUID = 1L; + private ARecordType recType; + + @Override + public void setImmutableStates(Object... states) { + this.recType = (ARecordType) states[0]; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new IScalarEvaluator() { + + private IScalarEvaluator eval0 = args[0].createScalarEvaluator(ctx); + private final IPointable argPtr = new VoidPointable(); + private final ARecordPointable recordPointable = + (ARecordPointable) ARecordPointable.FACTORY.createPointable(); + private final OrderedListBuilder listBuilder = new OrderedListBuilder(); + private final ArrayBackedValueStorage itemStorage = new ArrayBackedValueStorage(); + private final DataOutput itemOut = itemStorage.getDataOutput(); + private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage(); + private final DataOutput resultOut = resultStorage.getDataOutput(); + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable resultPointable) + throws HyracksDataException { + resultStorage.reset(); + eval0.evaluate(tuple, argPtr); + + byte[] data = argPtr.getByteArray(); + int offset = argPtr.getStartOffset(); + + if (data[offset] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) { + PointableHelper.setNull(resultPointable); + return; + } + + recordPointable.set(data, offset, argPtr.getLength()); + + listBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE); + + try { + for (int i = 0, n = recordPointable.getSchemeFieldCount(recType); i < n; i++) { + itemStorage.reset(); + recordPointable.getClosedFieldName(recType, i, itemOut); + listBuilder.addItem(itemStorage); + } + for (int i = 0, n = recordPointable.getOpenFieldCount(recType); i < n; i++) { + itemStorage.reset(); + recordPointable.getOpenFieldName(recType, i, itemOut); + listBuilder.addItem(itemStorage); + } + } catch (IOException e) { + throw HyracksDataException.create(e); + } + + listBuilder.write(resultOut, true); + + resultPointable.set(resultStorage); + } + }; + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.RECORD_NAMES; + } + +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsDescriptor.java index 2bf2530..96592e9 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsDescriptor.java @@ -59,7 +59,7 @@ public class RecordPairsDescriptor extends AbstractScalarFunctionDynamicDescript @Override public IFunctionTypeInferer createFunctionTypeInferer() { - return new FunctionTypeInferers.RecordPairsTypeInferer(); + return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_STRICT; } }; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java ---------------------------------------------------------------------- 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 487877b..6648ff2 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 @@ -263,7 +263,9 @@ import org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldsDe import org.apache.asterix.runtime.evaluators.functions.records.RecordAddFieldsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordConcatDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordConcatStrictDescriptor; +import org.apache.asterix.runtime.evaluators.functions.records.RecordLengthDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordMergeDescriptor; +import org.apache.asterix.runtime.evaluators.functions.records.RecordNamesDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordPairsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordRemoveFieldsDescriptor; import org.apache.asterix.runtime.evaluators.functions.temporal.AdjustDateTimeForTimeZoneDescriptor; @@ -614,6 +616,8 @@ public final class FunctionCollection implements IFunctionCollection { fc.addGenerated(RecordMergeDescriptor.FACTORY); fc.addGenerated(RecordAddFieldsDescriptor.FACTORY); fc.addGenerated(RecordRemoveFieldsDescriptor.FACTORY); + fc.addGenerated(RecordLengthDescriptor.FACTORY); + fc.addGenerated(RecordNamesDescriptor.FACTORY); // Spatial and temporal type accessors fc.addGenerated(TemporalYearAccessor.FACTORY); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f7c7059c/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java index 6261fb3..be041e5 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java @@ -149,36 +149,41 @@ public final class FunctionTypeInferers { } } - public static final class GetRecordFieldsTypeInferer implements IFunctionTypeInferer { - @Override - public void infer(ILogicalExpression expr, IFunctionDescriptor fd, IVariableTypeEnvironment context, - CompilerProperties compilerProps) throws AlgebricksException { - AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expr; - IAType t = (IAType) context.getType(fce.getArguments().get(0).getValue()); - ATypeTag typeTag = t.getTypeTag(); - if (typeTag.equals(ATypeTag.OBJECT)) { - fd.setImmutableStates(t); - } else if (typeTag.equals(ATypeTag.ANY)) { - fd.setImmutableStates(RecordUtil.FULLY_OPEN_RECORD_TYPE); - } else { - throw new NotImplementedException("get-record-fields for data of type " + t); - } + public static final class RecordAccessorTypeInferer implements IFunctionTypeInferer { + + public static final IFunctionTypeInferer INSTANCE_STRICT = new RecordAccessorTypeInferer(true); + + public static final IFunctionTypeInferer INSTANCE_LAX = new RecordAccessorTypeInferer(false); + + private final boolean strict; + + private RecordAccessorTypeInferer(boolean strict) { + this.strict = strict; } - } - public static final class GetRecordFieldValueTypeInferer implements IFunctionTypeInferer { @Override public void infer(ILogicalExpression expr, IFunctionDescriptor fd, IVariableTypeEnvironment context, CompilerProperties compilerProps) throws AlgebricksException { AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expr; IAType t = (IAType) context.getType(fce.getArguments().get(0).getValue()); ATypeTag typeTag = t.getTypeTag(); - if (typeTag.equals(ATypeTag.OBJECT)) { - fd.setImmutableStates(t); - } else if (typeTag.equals(ATypeTag.ANY)) { - fd.setImmutableStates(RecordUtil.FULLY_OPEN_RECORD_TYPE); - } else { - throw new NotImplementedException("get-record-field-value for data of type " + t); + switch (typeTag) { + case OBJECT: { + fd.setImmutableStates(t); + break; + } + case ANY: { + fd.setImmutableStates(RecordUtil.FULLY_OPEN_RECORD_TYPE); + break; + } + default: { + if (strict) { + throw new NotImplementedException(fd.getIdentifier().getName() + " for data of type " + t); + } else { + fd.setImmutableStates(new Object[] { null }); + } + break; + } } } } @@ -243,23 +248,6 @@ public final class FunctionTypeInferers { } } - public static final class RecordPairsTypeInferer implements IFunctionTypeInferer { - @Override - public void infer(ILogicalExpression expr, IFunctionDescriptor fd, IVariableTypeEnvironment context, - CompilerProperties compilerProps) throws AlgebricksException { - AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expr; - IAType t = (IAType) context.getType(fce.getArguments().get(0).getValue()); - ATypeTag typeTag = t.getTypeTag(); - if (typeTag.equals(ATypeTag.OBJECT)) { - fd.setImmutableStates(t); - } else if (typeTag.equals(ATypeTag.ANY)) { - fd.setImmutableStates(RecordUtil.FULLY_OPEN_RECORD_TYPE); - } else { - throw new NotImplementedException("record-fields with data of type " + t); - } - } - } - public static final class RecordRemoveFieldsTypeInferer implements IFunctionTypeInferer { @Override public void infer(ILogicalExpression expr, IFunctionDescriptor fd, IVariableTypeEnvironment context,