Dmitry Lychagin has submitted this change and it was merged. Change subject: [ASTERIXDB-2406][FUN] Implement pairs() function ......................................................................
[ASTERIXDB-2406][FUN] Implement pairs() function - user model changes: yes - storage format changes: no - interface changes: no Details: - Implement pairs() function - Fix object_pairs() function to return null for non-object input instead of raising type error - Add documentation for pairs() and object_pairs() Change-Id: I1d4917a496a2f49679d64109e5f5bf4b05609f01 Reviewed-on: https://asterix-gerrit.ics.uci.edu/2734 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> --- M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java M asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/ObjectsQueries.xml A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_pairs/object_pairs.2.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.1.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.2.update.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.3.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.4.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_pairs/object_pairs.2.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/objects/pairs/pairs.3.adm M asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AFlatValuePointable.java M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AListVisitablePointable.java M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/ARecordVisitablePointable.java M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/PointableAllocator.java M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAnyTypeComputer.java D asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/RecordPairsTypeComputer.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsDescriptor.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsEvaluator.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsDescriptor.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsEvaluator.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java 23 files changed, 676 insertions(+), 167 deletions(-) Approvals: Anon. E. Moose #1000171: Till Westmann: Looks good to me, approved Jenkins: Verified; ; Verified Objections: Jenkins: Violations found diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java index 7110dbb..06f7cc2 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java @@ -96,7 +96,8 @@ BuiltinFunctions.FIELD_ACCESS_NESTED, BuiltinFunctions.GET_ITEM, BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR, BuiltinFunctions.FIELD_ACCESS_BY_INDEX, BuiltinFunctions.CAST_TYPE, BuiltinFunctions.META, BuiltinFunctions.META_KEY, BuiltinFunctions.RECORD_CONCAT, BuiltinFunctions.RECORD_CONCAT_STRICT, - BuiltinFunctions.TO_ATOMIC, BuiltinFunctions.TO_ARRAY); + BuiltinFunctions.RECORD_PAIRS, BuiltinFunctions.PAIRS, BuiltinFunctions.TO_ATOMIC, + BuiltinFunctions.TO_ARRAY); private static final Map<FunctionIdentifier, IAObject> FUNC_ID_TO_CONSTANT = ImmutableMap .of(BuiltinFunctions.NUMERIC_E, new ADouble(Math.E), BuiltinFunctions.NUMERIC_PI, new ADouble(Math.PI)); 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 9eca213..a537e2b 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 @@ -196,4 +196,9 @@ <source-location>false</source-location> </compilation-unit> </test-case> + <test-case FilePath="objects"> + <compilation-unit name="pairs"> + <output-dir compare="Text">pairs</output-dir> + </compilation-unit> + </test-case> </test-group> diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_pairs/object_pairs.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_pairs/object_pairs.2.query.sqlpp new file mode 100644 index 0000000..27a088f --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_pairs/object_pairs.2.query.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. + */ + +{ + "t1": object_pairs(missing) is missing, + "t2": object_pairs(null) is null, + "t3": object_pairs(1) is null, + "t4": object_pairs("a") is null, + "t5": object_pairs(true) is null, + "t6": object_pairs([]) is null, + "t7": object_pairs([{"a":1}]) is null, + "t8": object_pairs({"a":{"b":{"c":{"d":1}}}}) +} diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.1.ddl.sqlpp new file mode 100644 index 0000000..b3d125a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.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 pairs() 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; diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.2.update.sqlpp new file mode 100644 index 0000000..9a25de1 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.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 pairs() 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`)); diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.3.query.sqlpp new file mode 100644 index 0000000..a1a63cb --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.3.query.sqlpp @@ -0,0 +1,60 @@ +/* + * 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 pairs() under different queries. + * Expected Res : Success + */ + +use TinySocial; + +{ + "t1": [ + pairs(missing) is missing, + pairs(null) is null, + pairs("non-object") is null + ], + + "t2": [ + pairs({}), + pairs([]), + pairs([{}]), + pairs([1,2]), + pairs([1,2,null,{"a":3}]) + ], + + "t3": pairs({"object":{"a":{"b":{"c":3}}}, "array":[1,2], "primitive": 4}), + + /* open type */ + "t4": ( + select value pairs(u) + from TwitterUsers as u + order by u.screen-name + limit 1 + ), + + /* closed type */ + "t5": ( + select value pairs(m) + from TweetMessages as m + order by m.tweetid + limit 1 + ) +}; + diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.4.ddl.sqlpp new file mode 100644 index 0000000..7e23af2 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/pairs/pairs.4.ddl.sqlpp @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Description : Testing pairs() under different queries. + * Expected Res : Success + */ + +drop dataverse TinySocial; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_pairs/object_pairs.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_pairs/object_pairs.2.adm new file mode 100644 index 0000000..713966d --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_pairs/object_pairs.2.adm @@ -0,0 +1 @@ +{ "t1": true, "t2": true, "t3": true, "t4": true, "t5": true, "t6": true, "t7": true, "t8": [ { "name": "a", "value": { "b": { "c": { "d": 1 } } } } ] } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/pairs/pairs.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/pairs/pairs.3.adm new file mode 100644 index 0000000..41715ad --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/pairs/pairs.3.adm @@ -0,0 +1 @@ +{ "t1": [ true, true, true ], "t2": [ [ ], [ ], [ ], [ ], [ [ "a", 3 ] ] ], "t3": [ [ "object", { "a": { "b": { "c": 3 } } } ], [ "a", { "b": { "c": 3 } } ], [ "b", { "c": 3 } ], [ "c", 3 ], [ "array", [ 1, 2 ] ], [ "array", 1 ], [ "array", 2 ], [ "primitive", 4 ] ], "t4": [ [ [ "screen-name", "ChangEwing_573" ], [ "lang", "en" ], [ "friends_count", 182 ], [ "statuses_count", 394 ], [ "name", "Chang Ewing" ], [ "followers_count", 32136 ] ] ], "t5": [ [ [ "tweetid", "1" ], [ "user", { "screen-name": "NathanGiesen@211", "lang": "en", "friends_count": 39339, "statuses_count": 473, "name": "Nathan Giesen", "followers_count": 49416 } ], [ "screen-name", "NathanGiesen@211" ], [ "lang", "en" ], [ "friends_count", 39339 ], [ "statuses_count", 473 ], [ "name", "Nathan Giesen" ], [ "followers_count", 49416 ], [ "sender-location", point("47.44,80.65") ], [ "send-time", datetime("2008-04-26T10:10:00.000Z") ], [ "referred-topics", {{ "t-mobile", "customization" }} ], [ "referred-topics", "t- mobile" ], [ "referred-topics", "customization" ], [ "message-text", " love t-mobile its customization is good:)" ] ] ] } 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 6596b99..187f04c 100644 --- a/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md +++ b/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md @@ -323,7 +323,7 @@ ### object_rename ### * Syntax: - object_name(input_object, old_field, new_field) + object_rename(input_object, old_field, new_field) * Returns a new object that has the same fields as `input_object` with field `old_field` replaced by `new_field` * Arguments: @@ -530,3 +530,76 @@ {"city": "Irvine", "state": "CA"} ] +### object_pairs ### + * Syntax: + + object_pairs(input_object) + + * Returns an array of objects describing fields of `input_object`. + For each field of the `input_object` the returned array contains an object with two fields `name` and `value` + which are set to the `input_object`'s field name and value. + + * Arguments: + * `input_object` : an object value. + * Return Value: + * An array of the `name`/`value` pairs of the fields in `input_object`, + * `missing` if `input_object` is `missing`, + * `null` if `input_object` is null or any non-object value. + + * Example: + + object_pairs( + { + "id": 1, + "project": "AsterixDB", + "address": {"city": "Irvine", "state": "CA"} + } + ); + + * The expected result is: + + [ + { "name": "id", "value": 1 }, + { "name": "project", "value": "AsterixDB" }, + { "name": "address", "value": {"city": "Irvine", "state": "CA"} } + ] + +### pairs ### + * Syntax: + + pairs(input_object) + + * Returns an array of arrays describing fields of `input_object`, including nested fields. + For each field of the `input_object` the returned array contains an array with two elements. + The first element is the name and the second one is the value of the `input_object`'s field. + The input object is introspected recursively, so all fields of its nested objects are returned. + Nested objects contained in arrays and multisets are also processed by this function. + + * Arguments: + * `input_object` : an object value (or an array or a multiset) + * Return Value: + * An array of arrays with name, value pairs of the fields in `input_object`, including nested fields. + Each inner array has exactly two items: name and value of the `input_object`'s field. + * `missing` if `input_object` is `missing`, + * `null` if `input_object` is null or a value of a primitive data type. + + * Example: + + pairs( + { + "id": 1, + "project": "AsterixDB", + "address": {"city": "Irvine", "state": "CA"} + } + ); + + * The expected result is: + + [ + [ "id", 1 ], + [ "project", "AsterixDB" ], + [ "address", { "city": "Irvine", "state": "CA" } ], + [ "city", "Irvine" ], + [ "state", "CA" ] + ] + 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 10e5a9a..da45e29 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 @@ -101,7 +101,6 @@ import org.apache.asterix.om.typecomputer.impl.PropagateTypeComputer; import org.apache.asterix.om.typecomputer.impl.RecordAddFieldsTypeComputer; import org.apache.asterix.om.typecomputer.impl.RecordMergeTypeComputer; -import org.apache.asterix.om.typecomputer.impl.RecordPairsTypeComputer; import org.apache.asterix.om.typecomputer.impl.RecordRemoveFieldsTypeComputer; import org.apache.asterix.om.typecomputer.impl.ScalarVersionOfAggregateResultType; import org.apache.asterix.om.typecomputer.impl.SleepTypeComputer; @@ -244,6 +243,7 @@ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-put", 3); public static final FunctionIdentifier RECORD_VALUES = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-values", 1); + public static final FunctionIdentifier PAIRS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "pairs", 1); // numeric public static final FunctionIdentifier NUMERIC_UNARY_MINUS = @@ -1491,7 +1491,8 @@ 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); + addFunction(RECORD_PAIRS, OrderedListOfAnyTypeComputer.INSTANCE_NULLABLE, true); + addFunction(PAIRS, OrderedListOfAnyTypeComputer.INSTANCE_NULLABLE, true); addFunction(GEOMETRY_CONSTRUCTOR, AGeometryTypeComputer.INSTANCE, true); addFunction(RECORD_REMOVE, OpenARecordTypeComputer.INSTANCE, true); addFunction(RECORD_RENAME, OpenARecordTypeComputer.INSTANCE, true); diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AFlatValuePointable.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AFlatValuePointable.java index 86a8a29..4108aca 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AFlatValuePointable.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AFlatValuePointable.java @@ -19,7 +19,6 @@ package org.apache.asterix.om.pointables; -import org.apache.asterix.om.pointables.base.IVisitablePointable; import org.apache.asterix.om.pointables.visitor.IVisitablePointableVisitor; import org.apache.asterix.om.types.IAType; import org.apache.asterix.om.util.container.IObjectFactory; @@ -37,11 +36,7 @@ * use object pool based allocator. The factory is not public so that it * cannot called in other places than PointableAllocator. */ - static IObjectFactory<IVisitablePointable, IAType> FACTORY = new IObjectFactory<IVisitablePointable, IAType>() { - public AFlatValuePointable create(IAType type) { - return new AFlatValuePointable(); - } - }; + static IObjectFactory<AFlatValuePointable, IAType> FACTORY = type -> new AFlatValuePointable(); /** * private constructor, to prevent arbitrary creation diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AListVisitablePointable.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AListVisitablePointable.java index 5b85d00..15766b3 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AListVisitablePointable.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/AListVisitablePointable.java @@ -47,11 +47,8 @@ * DO NOT allow to create AListPointable object arbitrarily, force to use * object pool based allocator, in order to have object reuse. */ - static IObjectFactory<IVisitablePointable, IAType> FACTORY = new IObjectFactory<IVisitablePointable, IAType>() { - public IVisitablePointable create(IAType type) { - return new AListVisitablePointable((AbstractCollectionType) type); - } - }; + static IObjectFactory<AListVisitablePointable, IAType> FACTORY = + type -> new AListVisitablePointable((AbstractCollectionType) type); private final List<IVisitablePointable> items = new ArrayList<IVisitablePointable>(); private final List<IVisitablePointable> itemTags = new ArrayList<IVisitablePointable>(); diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/ARecordVisitablePointable.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/ARecordVisitablePointable.java index b6ba848..7089fd6 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/ARecordVisitablePointable.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/ARecordVisitablePointable.java @@ -49,12 +49,8 @@ * DO NOT allow to create ARecordPointable object arbitrarily, force to use * object pool based allocator, in order to have object reuse */ - static IObjectFactory<IVisitablePointable, IAType> FACTORY = new IObjectFactory<IVisitablePointable, IAType>() { - @Override - public IVisitablePointable create(IAType type) { - return new ARecordVisitablePointable((ARecordType) type); - } - }; + static IObjectFactory<ARecordVisitablePointable, IAType> FACTORY = + type -> new ARecordVisitablePointable((ARecordType) type); // access results: field names, field types, and field values private final List<IVisitablePointable> fieldNames = new ArrayList<>(); diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/PointableAllocator.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/PointableAllocator.java index abd4841..91c47fd 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/PointableAllocator.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/PointableAllocator.java @@ -37,21 +37,21 @@ */ public class PointableAllocator { - private IObjectPool<IVisitablePointable, IAType> flatValueAllocator = - new ListObjectPool<IVisitablePointable, IAType>(AFlatValuePointable.FACTORY); - private IObjectPool<IVisitablePointable, IAType> recordValueAllocator = - new ListObjectPool<IVisitablePointable, IAType>(ARecordVisitablePointable.FACTORY); - private IObjectPool<IVisitablePointable, IAType> listValueAllocator = - new ListObjectPool<IVisitablePointable, IAType>(AListVisitablePointable.FACTORY); + private IObjectPool<AFlatValuePointable, IAType> flatValueAllocator = + new ListObjectPool<>(AFlatValuePointable.FACTORY); + private IObjectPool<ARecordVisitablePointable, IAType> recordValueAllocator = + new ListObjectPool<>(ARecordVisitablePointable.FACTORY); + private IObjectPool<AListVisitablePointable, IAType> listValueAllocator = + new ListObjectPool<>(AListVisitablePointable.FACTORY); private IObjectPool<AOrderedListType, IAType> orederedListTypeAllocator = - new ListObjectPool<AOrderedListType, IAType>(new IObjectFactory<AOrderedListType, IAType>() { + new ListObjectPool<>(new IObjectFactory<AOrderedListType, IAType>() { @Override public AOrderedListType create(IAType type) { return new AOrderedListType(type, type.getTypeName() + "OrderedList"); } }); private IObjectPool<AOrderedListType, IAType> unorederedListTypeAllocator = - new ListObjectPool<AOrderedListType, IAType>(new IObjectFactory<AOrderedListType, IAType>() { + new ListObjectPool<>(new IObjectFactory<AOrderedListType, IAType>() { @Override public AOrderedListType create(IAType type) { return new AOrderedListType(type, type.getTypeName() + "UnorderedList"); @@ -126,11 +126,11 @@ return flatValueAllocator.allocate(null); } - public IVisitablePointable allocateListValue(IAType type) { + public AListVisitablePointable allocateListValue(IAType type) { return listValueAllocator.allocate(type); } - public IVisitablePointable allocateRecordValue(IAType type) { + public ARecordVisitablePointable allocateRecordValue(IAType type) { return recordValueAllocator.allocate(type); } diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAnyTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAnyTypeComputer.java index 19f0e70..8c23f51 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAnyTypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OrderedListOfAnyTypeComputer.java @@ -20,20 +20,26 @@ import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; import org.apache.asterix.om.types.AOrderedListType; -import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.om.types.AUnionType; import org.apache.asterix.om.types.IAType; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; public class OrderedListOfAnyTypeComputer extends AbstractResultTypeComputer { - public static final OrderedListOfAnyTypeComputer INSTANCE = new OrderedListOfAnyTypeComputer(); + public static final OrderedListOfAnyTypeComputer INSTANCE = new OrderedListOfAnyTypeComputer(false); - private OrderedListOfAnyTypeComputer() { + public static final OrderedListOfAnyTypeComputer INSTANCE_NULLABLE = new OrderedListOfAnyTypeComputer(true); + + private final IAType type; + + private OrderedListOfAnyTypeComputer(boolean nullable) { + IAType t = AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE; + type = nullable ? AUnionType.createNullableType(t) : t; } @Override protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - return new AOrderedListType(BuiltinType.ANY, null); + return type; } } diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/RecordPairsTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/RecordPairsTypeComputer.java deleted file mode 100644 index ae51c61..0000000 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/RecordPairsTypeComputer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.asterix.om.typecomputer.impl; - -import org.apache.asterix.om.exceptions.TypeMismatchException; -import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; -import org.apache.asterix.om.types.AOrderedListType; -import org.apache.asterix.om.types.ATypeTag; -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.api.exceptions.SourceLocation; - -public class RecordPairsTypeComputer extends AbstractResultTypeComputer { - - public static final RecordPairsTypeComputer INSTANCE = new RecordPairsTypeComputer(); - - private RecordPairsTypeComputer() { - } - - @Override - protected void checkArgType(String funcName, int argIndex, IAType type, SourceLocation sourceLoc) - throws AlgebricksException { - ATypeTag typeTag = type.getTypeTag(); - if (typeTag != ATypeTag.OBJECT) { - throw new TypeMismatchException(sourceLoc, funcName, argIndex, typeTag, ATypeTag.OBJECT); - } - } - - @Override - public IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - return AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE; - } - -} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java new file mode 100644 index 0000000..82c45af --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordPairsEvaluator.java @@ -0,0 +1,67 @@ +/* + * 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.om.types.ATypeTag; +import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.runtime.evaluators.functions.CastTypeEvaluator; +import org.apache.asterix.runtime.evaluators.functions.PointableHelper; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +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; + +abstract class AbstractRecordPairsEvaluator implements IScalarEvaluator { + protected final IScalarEvaluator eval0; + protected final IPointable inputPointable = new VoidPointable(); + protected final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage(); + protected final DataOutput resultOutput = resultStorage.getDataOutput(); + private CastTypeEvaluator inputCaster; + + AbstractRecordPairsEvaluator(IScalarEvaluator eval0, IAType inputType) { + this.eval0 = eval0; + if (inputType != null) { + inputCaster = new CastTypeEvaluator(BuiltinType.ANY, inputType, eval0); + } + } + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + eval0.evaluate(tuple, inputPointable); + final ATypeTag inputTypeTag = PointableHelper.getTypeTag(inputPointable); + if (!validateInputType(inputTypeTag)) { + PointableHelper.setNull(result); + return; + } + inputCaster.evaluate(tuple, inputPointable); + resultStorage.reset(); + buildOutput(); + result.set(resultStorage); + } + + protected abstract boolean validateInputType(ATypeTag inputTypeTag); + + protected abstract void buildOutput() throws HyracksDataException; +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsDescriptor.java new file mode 100644 index 0000000..38295b0 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsDescriptor.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import org.apache.asterix.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.IAType; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.HyracksDataException; + +public class PairsDescriptor extends AbstractScalarFunctionDynamicDescriptor { + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new PairsDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENT_TYPE; + } + }; + + private static final long serialVersionUID = 1L; + private IAType inputType; + + @Override + public void setImmutableStates(Object... states) { + inputType = (IAType) states[0]; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(IHyracksTaskContext ctx) throws HyracksDataException { + return new PairsEvaluator(args[0].createScalarEvaluator(ctx), inputType); + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.PAIRS; + } +} \ No newline at end of file diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsEvaluator.java new file mode 100644 index 0000000..4cc54e1 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/PairsEvaluator.java @@ -0,0 +1,133 @@ +/* + * 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.util.ArrayDeque; +import java.util.List; + +import org.apache.asterix.builders.OrderedListBuilder; +import org.apache.asterix.om.pointables.AListVisitablePointable; +import org.apache.asterix.om.pointables.ARecordVisitablePointable; +import org.apache.asterix.om.pointables.PointableAllocator; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.pointables.base.IVisitablePointable; +import org.apache.asterix.om.types.AOrderedListType; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.runtime.evaluators.functions.PointableHelper; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +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; + +class PairsEvaluator extends AbstractRecordPairsEvaluator { + + // For writing output list + private final OrderedListBuilder outerListBuilder = new OrderedListBuilder(); + + // For writing each individual inner list. + private final ArrayBackedValueStorage innerListStorage = new ArrayBackedValueStorage(); + private final DataOutput innerListOutput = innerListStorage.getDataOutput(); + private final OrderedListBuilder innerListBuilder = new OrderedListBuilder(); + + private final PointableAllocator pAlloc = new PointableAllocator(); + private final ArrayDeque<IPointable> pNameQueue = new ArrayDeque<>(); + private final ArrayDeque<IPointable> pValueQueue = new ArrayDeque<>(); + + private final VoidPointable nullPointable = new VoidPointable(); + + PairsEvaluator(IScalarEvaluator eval0, IAType inputType) { + super(eval0, inputType); + PointableHelper.setNull(nullPointable); + } + + @Override + protected void buildOutput() throws HyracksDataException { + pAlloc.reset(); + pNameQueue.clear(); + pValueQueue.clear(); + + outerListBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE); + + addMembersToQueue(nullPointable, inputPointable); + IPointable namePointable, valuePointable; + while ((valuePointable = pValueQueue.poll()) != null) { + namePointable = pNameQueue.remove(); + + addMembersToQueue(namePointable, valuePointable); + + if (PointableHelper.getTypeTag(namePointable) != ATypeTag.NULL) { + innerListStorage.reset(); + innerListBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE); + innerListBuilder.addItem(namePointable); + innerListBuilder.addItem(valuePointable); + innerListBuilder.write(innerListOutput, true); + + outerListBuilder.addItem(innerListStorage); + } + } + + // Writes the result and sets the result pointable. + outerListBuilder.write(resultOutput, true); + } + + private void addMembersToQueue(IPointable namePointable, IPointable valuePointable) { + ATypeTag valueTypeTag = PointableHelper.getTypeTag(valuePointable); + switch (valueTypeTag) { + case OBJECT: + addRecordFieldsToQueue(valuePointable); + break; + case ARRAY: + case MULTISET: + addListItemsToQueue(valuePointable, DefaultOpenFieldType.getDefaultOpenFieldType(valueTypeTag), + namePointable); + break; + } + } + + private void addRecordFieldsToQueue(IPointable recordPointable) { + ARecordVisitablePointable visitablePointable = + pAlloc.allocateRecordValue(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + visitablePointable.set(recordPointable); + List<IVisitablePointable> fieldNames = visitablePointable.getFieldNames(); + List<IVisitablePointable> fieldValues = visitablePointable.getFieldValues(); + for (int i = fieldNames.size() - 1; i >= 0; i--) { + pNameQueue.push(fieldNames.get(i)); + pValueQueue.push(fieldValues.get(i)); + } + } + + private void addListItemsToQueue(IPointable listPointable, IAType listType, IPointable fieldNamePointable) { + AListVisitablePointable visitablePointable = pAlloc.allocateListValue(listType); + visitablePointable.set(listPointable); + List<IVisitablePointable> items = visitablePointable.getItems(); + for (int i = items.size() - 1; i >= 0; i--) { + pNameQueue.push(fieldNamePointable); + pValueQueue.push(items.get(i)); + } + } + + @Override + protected boolean validateInputType(ATypeTag inputTypeTag) { + return inputTypeTag == ATypeTag.OBJECT || inputTypeTag == ATypeTag.ARRAY || inputTypeTag == ATypeTag.MULTISET; + } +} 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 770f5bb..166ce96 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 @@ -18,25 +18,11 @@ */ package org.apache.asterix.runtime.evaluators.functions.records; -import java.io.DataOutput; -import java.io.IOException; -import java.util.List; - -import org.apache.asterix.builders.OrderedListBuilder; -import org.apache.asterix.builders.RecordBuilder; -import org.apache.asterix.dataflow.data.nontagged.serde.AObjectSerializerDeserializer; -import org.apache.asterix.om.base.AString; -import org.apache.asterix.om.functions.IFunctionTypeInferer; -import org.apache.asterix.runtime.exceptions.TypeMismatchException; 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.pointables.ARecordVisitablePointable; -import org.apache.asterix.om.pointables.base.IVisitablePointable; -import org.apache.asterix.om.types.AOrderedListType; +import org.apache.asterix.om.functions.IFunctionTypeInferer; import org.apache.asterix.om.types.ARecordType; -import org.apache.asterix.om.types.ATypeTag; -import org.apache.asterix.om.utils.RecordUtil; import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; import org.apache.asterix.runtime.functions.FunctionTypeInferers; import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; @@ -44,10 +30,6 @@ 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 RecordPairsDescriptor extends AbstractScalarFunctionDynamicDescriptor { @@ -59,7 +41,7 @@ @Override public IFunctionTypeInferer createFunctionTypeInferer() { - return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_STRICT; + return FunctionTypeInferers.RecordAccessorTypeInferer.INSTANCE_LAX; } }; @@ -83,67 +65,7 @@ @Override public IScalarEvaluator createScalarEvaluator(IHyracksTaskContext ctx) throws HyracksDataException { - // For writing each individual output record. - final ArrayBackedValueStorage itemStorage = new ArrayBackedValueStorage(); - final DataOutput itemOutput = itemStorage.getDataOutput(); - final RecordBuilder recBuilder = new RecordBuilder(); - recBuilder.reset(RecordUtil.FULLY_OPEN_RECORD_TYPE); - - // For writing the resulting list of records. - final OrderedListBuilder listBuilder = new OrderedListBuilder(); - final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage(); - final DataOutput resultOut = resultStorage.getDataOutput(); - - // Sets up the constant field names, "name" for the key field, "value" for the value field. - final ArrayBackedValueStorage nameStorage = new ArrayBackedValueStorage(); - final ArrayBackedValueStorage valueStorage = new ArrayBackedValueStorage(); - AObjectSerializerDeserializer serde = AObjectSerializerDeserializer.INSTANCE; - try { - serde.serialize(new AString("name"), nameStorage.getDataOutput()); - serde.serialize(new AString("value"), valueStorage.getDataOutput()); - } catch (IOException e) { - throw HyracksDataException.create(e); - } - - return new IScalarEvaluator() { - private final IScalarEvaluator argEvaluator = args[0].createScalarEvaluator(ctx); - private final IPointable argPtr = new VoidPointable(); - private final ARecordVisitablePointable recordVisitablePointable = - new ARecordVisitablePointable(recType); - - @Override - public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { - // Resets the result storage. - resultStorage.reset(); - - // Gets the input record. - argEvaluator.evaluate(tuple, argPtr); - byte inputTypeTag = argPtr.getByteArray()[argPtr.getStartOffset()]; - if (inputTypeTag != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) { - throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, inputTypeTag, - ATypeTag.SERIALIZED_RECORD_TYPE_TAG); - } - recordVisitablePointable.set(argPtr); - - listBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE); - List<IVisitablePointable> fieldNames = recordVisitablePointable.getFieldNames(); - List<IVisitablePointable> fieldValues = recordVisitablePointable.getFieldValues(); - // Adds each field of the input record as a key-value pair into the result. - int numFields = recordVisitablePointable.getFieldNames().size(); - for (int fieldIndex = 0; fieldIndex < numFields; ++fieldIndex) { - itemStorage.reset(); - recBuilder.init(); - recBuilder.addField(nameStorage, fieldNames.get(fieldIndex)); - recBuilder.addField(valueStorage, fieldValues.get(fieldIndex)); - recBuilder.write(itemOutput, true); - listBuilder.addItem(itemStorage); - } - - // Writes the result and sets the result pointable. - listBuilder.write(resultOut, true); - result.set(resultStorage); - } - }; + return new RecordPairsEvaluator(args[0].createScalarEvaluator(ctx), recType); } }; } diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsEvaluator.java new file mode 100644 index 0000000..03273d9 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPairsEvaluator.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import java.io.DataOutput; +import java.io.IOException; +import java.util.List; + +import org.apache.asterix.builders.OrderedListBuilder; +import org.apache.asterix.builders.RecordBuilder; +import org.apache.asterix.dataflow.data.nontagged.serde.AObjectSerializerDeserializer; +import org.apache.asterix.om.base.AString; +import org.apache.asterix.om.pointables.ARecordVisitablePointable; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.pointables.base.IVisitablePointable; +import org.apache.asterix.om.types.AOrderedListType; +import org.apache.asterix.om.types.ARecordType; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; + +class RecordPairsEvaluator extends AbstractRecordPairsEvaluator { + + // For writing output list + private final OrderedListBuilder listBuilder = new OrderedListBuilder(); + + // For writing each individual output record. + private final ArrayBackedValueStorage itemStorage = new ArrayBackedValueStorage(); + private final DataOutput itemOutput = itemStorage.getDataOutput(); + private final RecordBuilder recBuilder = new RecordBuilder(); + + // Sets up the constant field names, "name" for the key field, "value" for the value field. + private final ArrayBackedValueStorage nameStorage = new ArrayBackedValueStorage(); + private final ArrayBackedValueStorage valueStorage = new ArrayBackedValueStorage(); + + private ARecordVisitablePointable recordVisitablePointable; + + RecordPairsEvaluator(IScalarEvaluator eval0, ARecordType recordType) throws HyracksDataException { + super(eval0, recordType); + recBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + recordVisitablePointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + + try { + AObjectSerializerDeserializer serde = AObjectSerializerDeserializer.INSTANCE; + serde.serialize(new AString("name"), nameStorage.getDataOutput()); + serde.serialize(new AString("value"), valueStorage.getDataOutput()); + } catch (IOException e) { + throw HyracksDataException.create(e); + } + } + + @Override + protected void buildOutput() throws HyracksDataException { + listBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE); + + recordVisitablePointable.set(inputPointable); + List<IVisitablePointable> fieldNames = recordVisitablePointable.getFieldNames(); + List<IVisitablePointable> fieldValues = recordVisitablePointable.getFieldValues(); + // Adds each field of the input record as a key-value pair into the result. + int numFields = recordVisitablePointable.getFieldNames().size(); + for (int fieldIndex = 0; fieldIndex < numFields; ++fieldIndex) { + itemStorage.reset(); + recBuilder.init(); + recBuilder.addField(nameStorage, fieldNames.get(fieldIndex)); + recBuilder.addField(valueStorage, fieldValues.get(fieldIndex)); + recBuilder.write(itemOutput, true); + listBuilder.addItem(itemStorage); + } + + // Writes the result and sets the result pointable. + listBuilder.write(resultOutput, true); + } + + @Override + protected boolean validateInputType(ATypeTag inputTypeTag) { + return inputTypeTag == ATypeTag.OBJECT; + } +} 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 61a158e..199cc40 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 @@ -279,6 +279,7 @@ import org.apache.asterix.runtime.evaluators.functions.records.FieldAccessNestedDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldValueDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldsDescriptor; +import org.apache.asterix.runtime.evaluators.functions.records.PairsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordAddDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordAddFieldsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordConcatDescriptor; @@ -670,6 +671,7 @@ fc.add(RecordAddDescriptor.FACTORY); fc.add(RecordPutDescriptor.FACTORY); fc.addGenerated(RecordValuesDescriptor.FACTORY); + fc.addGenerated(PairsDescriptor.FACTORY); // Spatial and temporal type accessors fc.addGenerated(TemporalYearAccessor.FACTORY); -- To view, visit https://asterix-gerrit.ics.uci.edu/2734 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: merged Gerrit-Change-Id: I1d4917a496a2f49679d64109e5f5bf4b05609f01 Gerrit-PatchSet: 4 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Gerrit-Reviewer: Anon. E. Moose #1000171 Gerrit-Reviewer: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Gerrit-Reviewer: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Gerrit-Reviewer: Murtadha Hubail <mhub...@apache.org> Gerrit-Reviewer: Till Westmann <ti...@apache.org>