Murtadha Hubail has submitted this change and it was merged. Change subject: [NO ISSUE][FUN] Implement object-add(), object-put() ......................................................................
[NO ISSUE][FUN] Implement object-add(), object-put() - user model changes: no - storage format changes: no - interface changes: no Details: - Implement object-add function that adds a new field to a given object. - Implement object-put function that adds, removes, or updates an existing field in a given object. - Add new functions to docs. - Add test cases. Change-Id: I0b0b33f4ea82752ced0b5fc8f54d4474711192fc Reviewed-on: https://asterix-gerrit.ics.uci.edu/2713 Sonar-Qube: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Contrib: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Murtadha Hubail <mhub...@apache.org> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Dmitry Lychagin <dmitry.lycha...@couchbase.com> --- 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_add/object_add.1.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.2.update.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.3.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.4.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.1.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.2.update.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.3.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.4.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_add/object_add.3.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_put/object_put.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 A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordAddPutEvaluator.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddDescriptor.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddEvaluator.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutDescriptor.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutEvaluator.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java 19 files changed, 817 insertions(+), 2 deletions(-) Approvals: Anon. E. Moose #1000171: Jenkins: Verified; No violations found; ; Verified Murtadha Hubail: Looks good to me, but someone else must approve Dmitry Lychagin: Looks good to me, approved 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 184500e..42eeedd 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 @@ -140,6 +140,16 @@ <source-location>false</source-location> </compilation-unit> </test-case> + <test-case FilePath="objects">> + <compilation-unit name="object_add"> + <output-dir compare="Text">object_add</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="objects"> + <compilation-unit name="object_put"> + <output-dir compare="Text">object_put</output-dir> + </compilation-unit> + </test-case> <test-case FilePath="objects"> <compilation-unit name="object_pairs"> <output-dir compare="Text">object_pairs</output-dir> diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.1.ddl.sqlpp new file mode 100644 index 0000000..0573cc7 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.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_add 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/object_add/object_add.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.2.update.sqlpp new file mode 100644 index 0000000..2e1e348 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.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_add 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/object_add/object_add.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.3.query.sqlpp new file mode 100644 index 0000000..b3c90a2 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.3.query.sqlpp @@ -0,0 +1,58 @@ +/* + * 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_add under different queries. + * Expected Res : Success + */ + +use TinySocial; + +{ + "t1": [ + object_add(missing, missing, "value") is missing, + object_add(null, missing, "value") is missing, + object_add(missing, null, missing) is missing, + object_add(null, null, null) is null, + object_add("a", null, null) is null, + object_add("non-object", "field", "value") is null, + object_add({"a":1}, 1, "value") is null + ], + "t2": object_add({"a":1}, "field", "value"), + "t3": object_add({"a":1}, "field", null), + "t4": object_add({"a":1}, "field", {"x":["y", "z"]}), + "t5": object_add({"a":1}, "a", 5), + "t6": object_add({"a":1}, "field", missing), + + /* open type */ + "t7": ( + select value object_add(u, "field", "value") + from TwitterUsers as u + order by u.screen-name + limit 1 + ), + + /* closed type */ + "t8": ( + select value object_add(m, "field", {"a":1}) + from TweetMessages as m + order by m.tweetid + limit 1 + ) +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.4.ddl.sqlpp new file mode 100644 index 0000000..58af156 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_add/object_add.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 object_add 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/queries_sqlpp/objects/object_put/object_put.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.1.ddl.sqlpp new file mode 100644 index 0000000..6a7bed4 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.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_put 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/object_put/object_put.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.2.update.sqlpp new file mode 100644 index 0000000..c40cedd --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.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_put 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/object_put/object_put.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.3.query.sqlpp new file mode 100644 index 0000000..3706fd1 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.3.query.sqlpp @@ -0,0 +1,58 @@ +/* + * 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_put under different queries. + * Expected Res : Success + */ + +use TinySocial; + +{ + "t1": [ + object_put(missing, missing, "value") is missing, + object_put(null, missing, "value") is missing, + object_put(missing, null, missing) is missing, + object_put(null, null, null) is null, + object_put("a", null, null) is null, + object_put("non-object", "field", "value") is null, + object_add({"a":1}, 1, "value") is null + ], + "t2": object_put({"a":1}, "field", "value"), + "t3": object_put({"a":1}, "field", null), + "t4": object_put({"a":1}, "field", {"x":["y", "z"]}), + "t5": object_put({"a":1}, "a", "replaced"), + "t6": object_put({"a":1, "removed":2}, "removed", missing), + + /* open type */ + "t7": ( + select value object_put(u, "field", "value") + from TwitterUsers as u + order by u.screen-name + limit 1 + ), + + /* closed type */ + "t8": ( + select value object_put(m, "field", {"a":1}) + from TweetMessages as m + order by m.tweetid + limit 1 + ) +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.4.ddl.sqlpp new file mode 100644 index 0000000..050057f --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_put/object_put.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 object_put 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_add/object_add.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_add/object_add.3.adm new file mode 100644 index 0000000..676edeb --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_add/object_add.3.adm @@ -0,0 +1 @@ +{ "t1": [ true, true, true, true, true, true, true ], "t2": { "a": 1, "field": "value" }, "t3": { "a": 1, "field": null }, "t4": { "a": 1, "field": { "x": [ "y", "z" ] } }, "t5": { "a": 1 }, "t6": { "a": 1 }, "t7": [ { "screen-name": "ChangEwing_573", "lang": "en", "friends_count": 182, "statuses_count": 394, "name": "Chang Ewing", "followers_count": 32136, "field": "value" } ], "t8": [ { "tweetid": "1", "user": { "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" }}, "message-text": " love t-mobile its customization is good:)", "field": { "a": 1 } } ] } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_put/object_put.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_put/object_put.3.adm new file mode 100644 index 0000000..fc9a55a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_put/object_put.3.adm @@ -0,0 +1 @@ +{ "t1": [ true, true, true, true, true, true, true ], "t2": { "a": 1, "field": "value" }, "t3": { "a": 1, "field": null }, "t4": { "a": 1, "field": { "x": [ "y", "z" ] } }, "t5": { "a": "replaced" }, "t6": { "a": 1 }, "t7": [ { "screen-name": "ChangEwing_573", "lang": "en", "friends_count": 182, "statuses_count": 394, "name": "Chang Ewing", "followers_count": 32136, "field": "value" } ], "t8": [ { "tweetid": "1", "user": { "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" }}, "message-text": " love t-mobile its customization is good:)", "field": { "a": 1 } } ] } \ No newline at end of file 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 df04b33..be2e008 100644 --- a/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md +++ b/asterixdb/asterix-doc/src/main/markdown/builtins/8_record.md @@ -423,3 +423,78 @@ "location": {"city": "Irvine", "state": "CA"} } +### object_add ### + * Syntax: + + object_add(input_object, field_name, field_value) + + * Returns a new object that has the same fields as `input_object` as well as the new field `field_name`. + * Arguments: + * `input_object` : an object value. + * `field_name` : a string representing a field name to be added. + * `field_value` : a value to be assigned to the new field `field_name`. + * Return Value: + * A new object that has the same fields as `input_object` as well as the new field `field_name`, + * `missing` if `input_object` or `field_name` is `missing`, + * `null` if `input_object` or `field_name` is `null`, or `input_object` is not an object, or `field_name` is not + a string, + * `input_object` if `field_name`already exists in `input_object` or `field_value` is missing. + + * Example: + + object_add( + { + "id": 1, + "project": "AsterixDB", + "address": {"city": "Irvine", "state": "CA"} + } + , "company" + , "Apache" + ); + + * The expected result is: + + { + "id": 1, + "project": "AsterixDB", + "location": {"city": "Irvine", "state": "CA"}, + "company": "Apache" + } + +### object_put ### + * Syntax: + + object_put(input_object, field_name, field_value) + + * Adds, modifies, or removes a field of an object. + * Arguments: + * `input_object` : an object value. + * `field_name` : a string representing a field name to be added. + * `field_value` : a value to be assigned to the new field `field_name`. + * Return Value: + * a new object that has the same fields as `input_object` as well as the new field `field_name`, or with updated + `field_name` value to `field_value` if `field_name` already exists in `input_object`, or with `field_name`removed + if `field_name` already exists in `input_object` and `field_value` is `missing`, + * `missing` if `input_object` or `field_name` is `missing`, + * `null` if `input_object` or `field_name` is `null`, or `input_object` is not an object, or `field_name` is not + not a string. + + * Example: + + object_put( + { + "id": 1, + "project": "AsterixDB", + "address": {"city": "Irvine", "state": "CA"} + } + , "project" + , "Apache AsterixDB" + ); + + * The expected result is: + + { + "id": 1, + "project": "Apache AsterixDB", + "location": {"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 f17bc47..c73680c 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 @@ -228,6 +228,10 @@ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-unwrap", 1); public static final FunctionIdentifier RECORD_REPLACE = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-replace", 3); + public static final FunctionIdentifier RECORD_ADD = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-add", 3); + public static final FunctionIdentifier RECORD_PUT = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-put", 3); // numeric public static final FunctionIdentifier NUMERIC_UNARY_MINUS = @@ -1477,6 +1481,8 @@ addFunction(RECORD_RENAME, OpenARecordTypeComputer.INSTANCE, true); addFunction(RECORD_UNWRAP, AnyTypeComputer.INSTANCE, true); addFunction(RECORD_REPLACE, OpenARecordTypeComputer.INSTANCE, true); + addFunction(RECORD_ADD, OpenARecordTypeComputer.INSTANCE, true); + addFunction(RECORD_PUT, OpenARecordTypeComputer.INSTANCE, true); // temporal type accessors addFunction(ACCESSOR_TEMPORAL_YEAR, AInt64TypeComputer.INSTANCE, true); diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordAddPutEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordAddPutEvaluator.java new file mode 100644 index 0000000..0fba990 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/AbstractRecordAddPutEvaluator.java @@ -0,0 +1,114 @@ +/* + * 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.RecordBuilder; +import org.apache.asterix.om.pointables.ARecordVisitablePointable; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +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.dataflow.value.IBinaryComparator; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.primitive.UTF8StringPointable; +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 AbstractRecordAddPutEvaluator implements IScalarEvaluator { + + private final CastTypeEvaluator inputRecordCaster; + private final CastTypeEvaluator argRecordCaster; + private final IScalarEvaluator eval0; + private final IScalarEvaluator eval1; + private final IScalarEvaluator eval2; + final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage(); + final DataOutput resultOutput = resultStorage.getDataOutput(); + final IPointable inputRecordPointable = new VoidPointable(); + final UTF8StringPointable newFieldNamePointable = new UTF8StringPointable(); + final IPointable newFieldValuePointable = new VoidPointable(); + final IBinaryComparator stringBinaryComparator = PointableHelper.createStringBinaryComparator(); + final RecordBuilder outRecordBuilder = new RecordBuilder(); + final ARecordVisitablePointable inputOpenRecordPointable; + boolean newFieldValueIsMissing = false; + + AbstractRecordAddPutEvaluator(IScalarEvaluator eval0, IScalarEvaluator eval1, IScalarEvaluator eval2, + IAType[] argTypes) { + this.eval0 = eval0; + this.eval1 = eval1; + this.eval2 = eval2; + inputOpenRecordPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + inputRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, argTypes[0], eval0); + argRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, argTypes[2], eval2); + } + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + resultStorage.reset(); + eval0.evaluate(tuple, inputRecordPointable); + eval1.evaluate(tuple, newFieldNamePointable); + eval2.evaluate(tuple, newFieldValuePointable); + if (containsMissing(inputRecordPointable, newFieldNamePointable)) { + writeTypeTag(ATypeTag.SERIALIZED_MISSING_TYPE_TAG); + result.set(resultStorage); + return; + } + final ATypeTag inputObjectType = PointableHelper.getTypeTag(inputRecordPointable); + final ATypeTag newFieldNameValueType = PointableHelper.getTypeTag(newFieldNamePointable); + if (inputObjectType != ATypeTag.OBJECT || newFieldNameValueType != ATypeTag.STRING) { + PointableHelper.setNull(result); + return; + } + inputRecordCaster.evaluate(tuple, inputRecordPointable); + final ATypeTag newFieldValueTag = PointableHelper.getTypeTag(newFieldValuePointable); + if (newFieldValueTag.isDerivedType()) { + argRecordCaster.evaluate(tuple, newFieldValuePointable); + } + newFieldValueIsMissing = newFieldValueTag == ATypeTag.MISSING; + buildOutputRecord(); + result.set(resultStorage); + } + + protected abstract void buildOutputRecord() throws HyracksDataException; + + private boolean containsMissing(IPointable... pointables) { + for (int i = 0; i < pointables.length; i++) { + if (PointableHelper.getTypeTag(pointables[i]) == ATypeTag.MISSING) { + return true; + } + } + return false; + } + + private void writeTypeTag(byte typeTag) throws HyracksDataException { + try { + resultOutput.writeByte(typeTag); + } catch (IOException e) { + throw HyracksDataException.create(e); + } + } +} \ No newline at end of file diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddDescriptor.java new file mode 100644 index 0000000..7788bc1 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddDescriptor.java @@ -0,0 +1,79 @@ +/* + * 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 RecordAddDescriptor extends AbstractScalarFunctionDynamicDescriptor { + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new RecordAddDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + @Override + public void setImmutableStates(Object... states) { + argTypes = new IAType[states.length]; + for (int i = 0; i < states.length; i++) { + argTypes[i] = (IAType) states[i]; + } + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(IHyracksTaskContext ctx) throws HyracksDataException { + final IScalarEvaluator[] argEvals = new IScalarEvaluator[args.length]; + for (int i = 0; i < args.length; i++) { + argEvals[i] = args[i].createScalarEvaluator(ctx); + } + return new RecordAddEvaluator(argEvals[0], argEvals[1], argEvals[2], argTypes); + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.RECORD_ADD; + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddEvaluator.java new file mode 100644 index 0000000..bdadfb6 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordAddEvaluator.java @@ -0,0 +1,58 @@ +/* + * 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.util.List; + +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.pointables.base.IVisitablePointable; +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; + +class RecordAddEvaluator extends AbstractRecordAddPutEvaluator { + + RecordAddEvaluator(IScalarEvaluator eval0, IScalarEvaluator eval1, IScalarEvaluator eval2, IAType[] argTypes) { + super(eval0, eval1, eval2, argTypes); + } + + @Override + protected void buildOutputRecord() throws HyracksDataException { + resultStorage.reset(); + outRecordBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + outRecordBuilder.init(); + inputOpenRecordPointable.set(inputRecordPointable); + final List<IVisitablePointable> fieldNames = inputOpenRecordPointable.getFieldNames(); + final List<IVisitablePointable> fieldValues = inputOpenRecordPointable.getFieldValues(); + boolean newFieldFound = false; + for (int i = 0, fieldCount = fieldNames.size(); i < fieldCount; i++) { + final IVisitablePointable fieldName = fieldNames.get(i); + if (PointableHelper.isEqual(fieldName, newFieldNamePointable, stringBinaryComparator)) { + newFieldFound = true; + } + outRecordBuilder.addField(fieldName, fieldValues.get(i)); + } + if (!newFieldValueIsMissing && !newFieldFound) { + outRecordBuilder.addField(newFieldNamePointable, newFieldValuePointable); + } + outRecordBuilder.write(resultOutput, true); + } +} \ No newline at end of file diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutDescriptor.java new file mode 100644 index 0000000..a312795 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutDescriptor.java @@ -0,0 +1,79 @@ +/* + * 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 RecordPutDescriptor extends AbstractScalarFunctionDynamicDescriptor { + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new RecordPutDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + @Override + public void setImmutableStates(Object... states) { + argTypes = new IAType[states.length]; + for (int i = 0; i < states.length; i++) { + argTypes[i] = (IAType) states[i]; + } + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(IHyracksTaskContext ctx) throws HyracksDataException { + final IScalarEvaluator[] argEvals = new IScalarEvaluator[args.length]; + for (int i = 0; i < args.length; i++) { + argEvals[i] = args[i].createScalarEvaluator(ctx); + } + return new RecordPutEvaluator(argEvals[0], argEvals[1], argEvals[2], argTypes); + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.RECORD_PUT; + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutEvaluator.java new file mode 100644 index 0000000..83ee0c4 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordPutEvaluator.java @@ -0,0 +1,66 @@ +/* + * 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.util.List; + +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.pointables.base.IVisitablePointable; +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; + +class RecordPutEvaluator extends AbstractRecordAddPutEvaluator { + + RecordPutEvaluator(IScalarEvaluator eval0, IScalarEvaluator eval1, IScalarEvaluator eval2, IAType[] argTypes) { + super(eval0, eval1, eval2, argTypes); + } + + @Override + protected void buildOutputRecord() throws HyracksDataException { + resultStorage.reset(); + outRecordBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + outRecordBuilder.init(); + inputOpenRecordPointable.set(inputRecordPointable); + final List<IVisitablePointable> fieldNames = inputOpenRecordPointable.getFieldNames(); + final List<IVisitablePointable> fieldValues = inputOpenRecordPointable.getFieldValues(); + boolean newFieldFound = false; + for (int i = 0, fieldCount = fieldNames.size(); i < fieldCount; i++) { + final IVisitablePointable fieldName = fieldNames.get(i); + if (!PointableHelper.isEqual(fieldName, newFieldNamePointable, stringBinaryComparator)) { + outRecordBuilder.addField(fieldName, fieldValues.get(i)); + } else { + newFieldFound = true; + if (!newFieldValueIsMissing) { + putNewField(); + } + } + } + if (!newFieldFound) { + putNewField(); + } + outRecordBuilder.write(resultOutput, true); + } + + private void putNewField() throws HyracksDataException { + outRecordBuilder.addField(newFieldNamePointable, newFieldValuePointable); + } +} \ No newline at end of file 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 7663f19..f69ee7c 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 @@ -186,11 +186,10 @@ import org.apache.asterix.runtime.evaluators.functions.NumericATanDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericAbsDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericAddDescriptor; -import org.apache.asterix.runtime.evaluators.functions.NumericDivDescriptor; -import org.apache.asterix.runtime.evaluators.functions.NumericPowerDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericCeilingDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericCosDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericDegreesDescriptor; +import org.apache.asterix.runtime.evaluators.functions.NumericDivDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericDivideDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericExpDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericFloorDescriptor; @@ -198,6 +197,7 @@ import org.apache.asterix.runtime.evaluators.functions.NumericLogDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericModuloDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericMultiplyDescriptor; +import org.apache.asterix.runtime.evaluators.functions.NumericPowerDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericRadiansDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericRoundDescriptor; import org.apache.asterix.runtime.evaluators.functions.NumericRoundHalfToEven2Descriptor; @@ -275,6 +275,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.RecordAddDescriptor; 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; @@ -282,6 +283,7 @@ 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.RecordPutDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordRemoveDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordRemoveFieldsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordRenameDescriptor; @@ -656,6 +658,8 @@ fc.addGenerated(RecordRenameDescriptor.FACTORY); fc.addGenerated(RecordUnwrapDescriptor.FACTORY); fc.add(RecordReplaceDescriptor.FACTORY); + fc.add(RecordAddDescriptor.FACTORY); + fc.add(RecordPutDescriptor.FACTORY); // Spatial and temporal type accessors fc.addGenerated(TemporalYearAccessor.FACTORY); -- To view, visit https://asterix-gerrit.ics.uci.edu/2713 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: merged Gerrit-Change-Id: I0b0b33f4ea82752ced0b5fc8f54d4474711192fc Gerrit-PatchSet: 9 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Murtadha Hubail <mhub...@apache.org> 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>