Dmitry Lychagin has submitted this change and it was merged. Change subject: [ASTERIXDB-2291][FUN] Implement if_inf,if_nan,if_nan_or_inf ......................................................................
[ASTERIXDB-2291][FUN] Implement if_inf,if_nan,if_nan_or_inf - user model changes: yes - storage format changes: no - interface changes: no Details: - Implement functions: if_inf(), if_nan(), if_nan_or_inf() - Add testcases and documentation - INF to string conversion should produce "INF" instead of "Infinity" - Move if_missing(), if_null() testcases to 'null-missing' folder Change-Id: I12dccd848a1d6b4ba102bea3b7602c2cbd8aaef5 Reviewed-on: https://asterix-gerrit.ics.uci.edu/2411 Tested-by: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Contrib: Jenkins <[email protected]> Reviewed-by: Till Westmann <[email protected]> --- M asterixdb/asterix-app/src/test/resources/runtimets/queries/types/to_string_01/to_string_01.1.query.aql R asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp R asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp R asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifinf/ifinf.1.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnan/ifnan.1.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnanorinf/ifnanorinf.1.query.sqlpp M asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_string_01/to_string_01.1.query.sqlpp R asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm R asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm R asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifinf/ifinf.1.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnan/ifnan.1.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnanorinf/ifnanorinf.1.adm M asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_string_01/to_string_01.1.adm M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml M asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md M asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/CommonFunctionMapUtil.java 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/typecomputer/base/AbstractResultTypeComputer.java A asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNanOrInfTypeComputer.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AFloatConstructorDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractDoubleConstructorEvaluator.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractStringConstructorEvaluator.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfInfDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingOrNullDescriptor.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanDescriptor.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanOrInfDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNullDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java 32 files changed, 757 insertions(+), 55 deletions(-) Approvals: Till Westmann: Looks good to me, approved Jenkins: Verified; ; Verified Objections: Anon. E. Moose #1000171: Violations found Jenkins: Violations found diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/types/to_string_01/to_string_01.1.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/types/to_string_01/to_string_01.1.query.aql index 2abf4c3..ee5ed6f 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/types/to_string_01/to_string_01.1.query.aql +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/types/to_string_01/to_string_01.1.query.aql @@ -30,5 +30,11 @@ "t11": is_null(to_string({{}})), "t12": is_null(to_string({})), "t13": is_null(to_string(null)), - "t14": is_missing(to_string(missing)) + "t14": is_missing(to_string(missing)), + "t15": to_string(double("NaN")), + "t16": to_string(float("NaN")), + "t17": to_string(double("INF")), + "t18": to_string(float("INF")), + "t19": to_string(double("-INF")), + "t20": to_string(float("-INF")) } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifmissing/ifmissing.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp similarity index 100% rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifmissing/ifmissing.1.query.sqlpp rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifmissingornull/ifmissingornull.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp similarity index 100% rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifmissingornull/ifmissingornull.1.query.sqlpp rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifnull/ifnull.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp similarity index 100% rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifnull/ifnull.1.query.sqlpp rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifinf/ifinf.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifinf/ifinf.1.query.sqlpp new file mode 100644 index 0000000..3b12ead --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifinf/ifinf.1.query.sqlpp @@ -0,0 +1,44 @@ +/* + * 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. + */ + +select value t +from [ + [ 0, isnull(ifinf()) ], + [ 1, isnull(ifinf(null)) ], + [ 2, ismissing(ifinf(missing)) ], + [ 3, isnull(ifinf(double("INF"))) ], + [ 4, isnull(ifinf(double("-INF"))) ], + [ 5, isnull(ifinf(float("INF"))) ], + [ 6, isnull(ifinf(float("-INF"))) ], + [ 7, ifinf(tinyint("1")) ], + [ 8, ifinf(smallint("2")) ], + [ 9, ifinf(integer("3")) ], + [ 10, ifinf(bigint("4")) ], + [ 11, ifinf(float("1.5")) ], + [ 12, ifinf(double("2.5")) ], + [ 13, ifinf(2, null, missing) ], + [ 14, isnull(ifinf(null, missing, 2)) ], + [ 15, ismissing(ifinf(missing, null, 2)) ], + [ 16, ifinf(double("INF"), float("-INF"), 2) ], + [ 17, ifinf(float("INF"), double("-INF"), 2) ], + [ 18, isnull(ifinf(double("INF"), double("-INF"), [], 2)) ], + [ 19, ismissing(if_inf(double("INF"), double("-INF"), missing, 2)) ], + [ 20, tostring(ifinf(float("INF"), float("NaN"), 2)) ] +] t +order by t[0] \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnan/ifnan.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnan/ifnan.1.query.sqlpp new file mode 100644 index 0000000..40a55d1 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnan/ifnan.1.query.sqlpp @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +select value t +from [ + [ 0, isnull(ifnan()) ], + [ 1, isnull(ifnan(null)) ], + [ 2, ismissing(ifnan(missing)) ], + [ 3, isnull(ifnan(double("NaN"))) ], + [ 5, isnull(ifnan(float("NaN"))) ], + [ 7, ifnan(tinyint("1")) ], + [ 8, ifnan(smallint("2")) ], + [ 9, ifnan(integer("3")) ], + [ 10, ifnan(bigint("4")) ], + [ 11, ifnan(float("1.5")) ], + [ 12, ifnan(double("2.5")) ], + [ 13, ifnan(2, null, missing) ], + [ 14, isnull(ifnan(null, missing, 2)) ], + [ 15, ismissing(ifnan(missing, null, 2)) ], + [ 16, ifnan(double("NaN"), 2) ], + [ 17, ifnan(float("NaN"), 2) ], + [ 18, isnull(ifnan(double("NaN"), [], 2)) ], + [ 19, ismissing(if_nan(double("NaN"), missing, 2)) ], + [ 20, tostring(ifnan(double("NaN"), double("INF"), 2)) ], + [ 21, tostring(ifnan(float("NaN"), float("-INF"), 2)) ] +] t +order by t[0] \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnanorinf/ifnanorinf.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnanorinf/ifnanorinf.1.query.sqlpp new file mode 100644 index 0000000..d4b1863 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/numeric/ifnanorinf/ifnanorinf.1.query.sqlpp @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +select value t +from [ + [ 0, isnull(ifnanorinf()) ], + [ 1, isnull(ifnanorinf(null)) ], + [ 2, ismissing(ifnanorinf(missing)) ], + [ 3, isnull(ifnanorinf(double("NaN"))) ], + [ 5, isnull(ifnanorinf(float("INF"))) ], + [ 7, ifnanorinf(tinyint("1")) ], + [ 8, ifnanorinf(smallint("2")) ], + [ 9, ifnanorinf(integer("3")) ], + [ 10, ifnanorinf(bigint("4")) ], + [ 11, ifnanorinf(float("1.5")) ], + [ 12, ifnanorinf(double("2.5")) ], + [ 13, ifnanorinf(2, null, missing) ], + [ 14, isnull(ifnanorinf(null, missing, 2)) ], + [ 15, ismissing(ifnanorinf(missing, null, 2)) ], + [ 16, ifnanorinf(double("-INF"), 2) ], + [ 17, ifnanorinf(float("NaN"), 2) ], + [ 18, isnull(ifnanorinf(double("NaN"), [], 2)) ], + [ 19, ismissing(if_nan_or_inf(double("NaN"), missing, 2)) ], + [ 20, ifnanorinf(double("NaN"), double("INF"), 2) ], + [ 21, ifnanorinf(float("NaN"), float("-INF"), 2) ] +] t +order by t[0] \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_string_01/to_string_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_string_01/to_string_01.1.query.sqlpp index 8582521..f759e16 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_string_01/to_string_01.1.query.sqlpp +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_string_01/to_string_01.1.query.sqlpp @@ -30,5 +30,11 @@ "t11": is_null(to_string({{}})), "t12": is_null(to_string({})), "t13": is_null(to_string(null)), - "t14": is_missing(to_string(missing)) + "t14": is_missing(to_string(missing)), + "t15": to_string(double("NaN")), + "t16": to_string(float("NaN")), + "t17": to_string(double("INF")), + "t18": to_string(float("INF")), + "t19": to_string(double("-INF")), + "t20": to_string(float("-INF")) } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifmissing/ifmissing.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm similarity index 100% rename from asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifmissing/ifmissing.1.adm rename to asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifmissingornull/ifmissingornull.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm similarity index 100% rename from asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifmissingornull/ifmissingornull.1.adm rename to asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifnull/ifnull.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm similarity index 100% rename from asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifnull/ifnull.1.adm rename to asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifinf/ifinf.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifinf/ifinf.1.adm new file mode 100644 index 0000000..c45efa6 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifinf/ifinf.1.adm @@ -0,0 +1,21 @@ +[ 0, true ] +[ 1, true ] +[ 2, true ] +[ 3, true ] +[ 4, true ] +[ 5, true ] +[ 6, true ] +[ 7, 1 ] +[ 8, 2 ] +[ 9, 3 ] +[ 10, 4 ] +[ 11, 1.5 ] +[ 12, 2.5 ] +[ 13, 2 ] +[ 14, true ] +[ 15, true ] +[ 16, 2 ] +[ 17, 2 ] +[ 18, true ] +[ 19, true ] +[ 20, "NaN" ] \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnan/ifnan.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnan/ifnan.1.adm new file mode 100644 index 0000000..ec02746 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnan/ifnan.1.adm @@ -0,0 +1,20 @@ +[ 0, true ] +[ 1, true ] +[ 2, true ] +[ 3, true ] +[ 5, true ] +[ 7, 1 ] +[ 8, 2 ] +[ 9, 3 ] +[ 10, 4 ] +[ 11, 1.5 ] +[ 12, 2.5 ] +[ 13, 2 ] +[ 14, true ] +[ 15, true ] +[ 16, 2 ] +[ 17, 2 ] +[ 18, true ] +[ 19, true ] +[ 20, "INF" ] +[ 21, "-INF" ] \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnanorinf/ifnanorinf.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnanorinf/ifnanorinf.1.adm new file mode 100644 index 0000000..34476cc --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/numeric/ifnanorinf/ifnanorinf.1.adm @@ -0,0 +1,20 @@ +[ 0, true ] +[ 1, true ] +[ 2, true ] +[ 3, true ] +[ 5, true ] +[ 7, 1 ] +[ 8, 2 ] +[ 9, 3 ] +[ 10, 4 ] +[ 11, 1.5 ] +[ 12, 2.5 ] +[ 13, 2 ] +[ 14, true ] +[ 15, true ] +[ 16, 2 ] +[ 17, 2 ] +[ 18, true ] +[ 19, true ] +[ 20, 2 ] +[ 21, 2 ] \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_string_01/to_string_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_string_01/to_string_01.1.adm index 83dee03..11a3abb 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_string_01/to_string_01.1.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_string_01/to_string_01.1.adm @@ -1 +1 @@ -{ "t1": "false", "t2": "true", "t3": "8", "t4": "16", "t5": "32", "t6": "64", "t7": "128.0", "t8": "256.0", "t9": "foo", "t10": true, "t11": true, "t12": true, "t13": true, "t14": true } \ No newline at end of file +{ "t1": "false", "t2": "true", "t3": "8", "t4": "16", "t5": "32", "t6": "64", "t7": "128.0", "t8": "256.0", "t9": "foo", "t10": true, "t11": true, "t12": true, "t13": true, "t14": true, "t15": "NaN", "t16": "NaN", "t17": "INF", "t18": "INF", "t19": "-INF", "t20": "-INF" } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index a869b22..bb0d473 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -4648,6 +4648,21 @@ </compilation-unit> </test-case> <test-case FilePath="null-missing"> + <compilation-unit name="ifmissing"> + <output-dir compare="Text">ifmissing</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="null-missing"> + <compilation-unit name="ifnull"> + <output-dir compare="Text">ifnull</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="null-missing"> + <compilation-unit name="ifmissingornull"> + <output-dir compare="Text">ifmissingornull</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="null-missing"> <compilation-unit name="query-ASTERIXDB-1689"> <output-dir compare="Text">query-ASTERIXDB-1689</output-dir> </compilation-unit> @@ -4802,6 +4817,21 @@ <test-case FilePath="numeric"> <compilation-unit name="floor4"> <output-dir compare="Text">floor4</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="numeric"> + <compilation-unit name="ifinf"> + <output-dir compare="Text">ifinf</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="numeric"> + <compilation-unit name="ifnan"> + <output-dir compare="Text">ifnan</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="numeric"> + <compilation-unit name="ifnanorinf"> + <output-dir compare="Text">ifnanorinf</output-dir> </compilation-unit> </test-case> <test-case FilePath="numeric"> @@ -9179,21 +9209,6 @@ <test-case FilePath="types"> <compilation-unit name="promotion_opentype_field_vs_opentype_field_02"> <output-dir compare="Text">promotion_opentype_field_vs_opentype_field_02</output-dir> - </compilation-unit> - </test-case> - <test-case FilePath="types"> - <compilation-unit name="ifmissing"> - <output-dir compare="Text">ifmissing</output-dir> - </compilation-unit> - </test-case> - <test-case FilePath="types"> - <compilation-unit name="ifnull"> - <output-dir compare="Text">ifnull</output-dir> - </compilation-unit> - </test-case> - <test-case FilePath="types"> - <compilation-unit name="ifmissingornull"> - <output-dir compare="Text">ifmissingornull</output-dir> </compilation-unit> </test-case> <test-case FilePath="types"> diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md b/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md index 202f7e4..ed9551e 100644 --- a/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md +++ b/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md @@ -101,3 +101,101 @@ { "a": null, "b": null, "c": "asterixdb" } The function has an alias `ifmissingornull`. + +### if_inf (ifinf) ### + + * Syntax: + + if_inf(expression1, expression2, ... expressionN) + + * Finds first argument which is a non-infinite (`INF` or`-INF`) number + * Arguments: + * `expressionI` : an expression (any type is allowed). + * Return Value: + * a `missing` if `missing` argument was encountered before the first non-infinite number argument + * a `null` if `null` argument or any other non-number argument was encountered before the first non-infinite number argument + * the first non-infinite number argument otherwise + + * Example: + + { + "a": is_null(if_inf(null)), + "b": is_missing(if_inf(missing)), + "c": is_null(if_inf(double("INF"))), + "d": if_inf(1, null, missing) ], + "e": is_null(if_inf(null, missing, 1)) ], + "f": is_missing(if_inf(missing, null, 1)) ], + "g": if_inf(float("INF"), 1) ], + "h": to_string(if_inf(float("INF"), double("NaN"), 1)) ] + }; + + * The expected result is: + + { "a": true, "b": true, "c": true, "d": 1, "e": true, "f": true, "g": 1, "h": "NaN" } + + The function has an alias `ifinf`. + +### if_nan (ifnan) ### + + * Syntax: + + if_nan(expression1, expression2, ... expressionN) + + * Finds first argument which is a non-`NaN` number + * Arguments: + * `expressionI` : an expression (any type is allowed). + * Return Value: + * a `missing` if `missing` argument was encountered before the first non-`NaN` number argument + * a `null` if `null` argument or any other non-number argument was encountered before the first non-`NaN` number argument + * the first non-`NaN` number argument otherwise + + * Example: + + { + "a": is_null(if_nan(null)), + "b": is_missing(if_nan(missing)), + "c": is_null(if_nan(double("NaN"))), + "d": if_nan(1, null, missing) ], + "e": is_null(if_nan(null, missing, 1)) ], + "f": is_missing(if_nan(missing, null, 1)) ], + "g": if_nan(float("NaN"), 1) ], + "h": to_string(if_nan(float("NaN"), double("INF"), 1)) ] + }; + + * The expected result is: + + { "a": true, "b": true, "c": true, "d": 1, "e": true, "f": true, "g": 1, "h": "INF" } + + The function has an alias `ifnan`. + +### if_nan_or_inf (ifnanorinf) ### + + * Syntax: + + if_nan_or_inf(expression1, expression2, ... expressionN) + + * Finds first argument which is a non-infinite (`INF` or`-INF`) and non-`NaN` number + * Arguments: + * `expressionI` : an expression (any type is allowed). + * Return Value: + * a `missing` if `missing` argument was encountered before the first non-infinite and non-`NaN` number argument + * a `null` if `null` argument or any other non-number argument was encountered before the first non-infinite and non-`NaN` number argument + * the first non-infinite and non-`NaN` number argument otherwise + + * Example: + + { + "a": is_null(if_nan_or_inf(null)), + "b": is_missing(if_nan_or_inf(missing)), + "c": is_null(if_nan_or_inf(double("NaN"), double("INF"))), + "d": if_nan_or_inf(1, null, missing) ], + "e": is_null(if_nan_or_inf(null, missing, 1)) ], + "f": is_missing(if_nan_or_inf(missing, null, 1)) ], + "g": if_nan_or_inf(float("NaN"), float("INF"), 1) ], + }; + + * The expected result is: + + { "a": true, "b": true, "c": true, "d": 1, "e": true, "f": true, "g": 1 } + + The function has an alias `ifnanorinf`. diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/CommonFunctionMapUtil.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/CommonFunctionMapUtil.java index b78ee9f..5556ea9 100644 --- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/CommonFunctionMapUtil.java +++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/CommonFunctionMapUtil.java @@ -66,7 +66,10 @@ FUNCTION_NAME_MAP.put("isobj", "is-object"); // isobj, internal: is-object FUNCTION_NAME_MAP.put("ifmissing", "if-missing"); // ifmissing, internal: if-missing FUNCTION_NAME_MAP.put("ifnull", "if-null"); // ifnull, internal: if-null - FUNCTION_NAME_MAP.put("ifmissingornull", "if-missing-or-null"); // ifmissingornull, internal: is-missing-or-null + FUNCTION_NAME_MAP.put("ifmissingornull", "if-missing-or-null"); // ifmissingornull, internal: if-missing-or-null + FUNCTION_NAME_MAP.put("ifinf", "if-inf"); // ifinf, internal: if-inf + FUNCTION_NAME_MAP.put("ifnan", "if-nan"); // ifnan, internal: if-nan + FUNCTION_NAME_MAP.put("ifnanorinf", "if-nan-or-inf"); // ifnanorinf, internal: if-nan-or-inf FUNCTION_NAME_MAP.put("toboolean", "to-boolean"); // toboolean, internal: to-boolean FUNCTION_NAME_MAP.put("tostring", "to-string"); // tostring, internal: to-string FUNCTION_NAME_MAP.put("todouble", "to-double"); // todouble, internal: to-double 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 153ea45..761ddba 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 @@ -66,6 +66,7 @@ import org.apache.asterix.om.typecomputer.impl.FieldAccessNestedResultType; import org.apache.asterix.om.typecomputer.impl.FullTextContainsResultTypeComputer; import org.apache.asterix.om.typecomputer.impl.GetOverlappingInvervalTypeComputer; +import org.apache.asterix.om.typecomputer.impl.IfNanOrInfTypeComputer; import org.apache.asterix.om.typecomputer.impl.IfMissingOrNullTypeComputer; import org.apache.asterix.om.typecomputer.impl.IfMissingTypeComputer; import org.apache.asterix.om.typecomputer.impl.IfNullTypeComputer; @@ -855,6 +856,12 @@ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "if-null", FunctionIdentifier.VARARGS); public static final FunctionIdentifier IF_MISSING_OR_NULL = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "if-missing-or-null", FunctionIdentifier.VARARGS); + public static final FunctionIdentifier IF_INF = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "if-inf", FunctionIdentifier.VARARGS); + public static final FunctionIdentifier IF_NAN = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "if-nan", FunctionIdentifier.VARARGS); + public static final FunctionIdentifier IF_NAN_OR_INF = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "if-nan-or-inf", FunctionIdentifier.VARARGS); public static final FunctionIdentifier TO_BOOLEAN = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "to-boolean", 1); @@ -992,6 +999,9 @@ addFunction(NUMERIC_ROUND_HALF_TO_EVEN, NumericUnaryFunctionTypeComputer.INSTANCE, true); addFunction(NUMERIC_ROUND_HALF_TO_EVEN2, NumericRound2TypeComputer.INSTANCE, true); addFunction(NUMERIC_TRUNC, NumericRound2TypeComputer.INSTANCE, true); + addFunction(IF_INF, IfNanOrInfTypeComputer.INSTANCE, true); + addFunction(IF_NAN, IfNanOrInfTypeComputer.INSTANCE, true); + addFunction(IF_NAN_OR_INF, IfNanOrInfTypeComputer.INSTANCE, true); addFunction(BINARY_LENGTH, UnaryBinaryInt64TypeComputer.INSTANCE, true); addFunction(PARSE_BINARY, ABinaryTypeComputer.INSTANCE, true); diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java index f33db4b..4d6b7e6 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java @@ -40,7 +40,7 @@ AbstractFunctionCallExpression functionCallExpression = (AbstractFunctionCallExpression) expression; String funcName = functionCallExpression.getFunctionIdentifier().getName(); return TypeComputeUtils.resolveResultType(expression, env, (index, type) -> checkArgType(funcName, index, type), - this::getResultType, true); + this::getResultType, propagateNullAndMissing()); } /** @@ -70,4 +70,12 @@ */ protected abstract IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException; + + /** + * Whether the expression follows MISSING-in-MISSING-out and NULL-in-NULL-out semantics + * @return said value + */ + protected boolean propagateNullAndMissing() { + return true; + } } diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNanOrInfTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNanOrInfTypeComputer.java new file mode 100644 index 0000000..bb9fa38 --- /dev/null +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNanOrInfTypeComputer.java @@ -0,0 +1,74 @@ +/* + * 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.typecomputer.base.AbstractResultTypeComputer; +import org.apache.asterix.om.types.AUnionType; +import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.om.types.IAType; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; + +public class IfNanOrInfTypeComputer extends AbstractResultTypeComputer { + + public static final IfNanOrInfTypeComputer INSTANCE = new IfNanOrInfTypeComputer(); + + @Override + protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { + if (strippedInputTypes.length == 0) { + return BuiltinType.ANULL; + } + + boolean any = false; + IAType currentType = null; + for (IAType type : strippedInputTypes) { + if (currentType != null && !type.equals(currentType)) { + any = true; + break; + } + currentType = type; + } + if (any || currentType == null) { + return BuiltinType.ANY; + } + + switch (currentType.getTypeTag()) { + case ANY: + case MISSING: + case BIGINT: + case INTEGER: + case SMALLINT: + case TINYINT: + return currentType; + + case DOUBLE: + case FLOAT: + return AUnionType.createNullableType(currentType, null); + + default: + return BuiltinType.ANULL; + } + } + + @Override + protected boolean propagateNullAndMissing() { + return false; + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AFloatConstructorDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AFloatConstructorDescriptor.java index ffc982a..8c69671 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AFloatConstructorDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AFloatConstructorDescriptor.java @@ -68,11 +68,6 @@ private DataOutput out = resultStorage.getDataOutput(); private IPointable inputArg = new VoidPointable(); private IScalarEvaluator eval = args[0].createScalarEvaluator(ctx); - private final byte[] POSITIVE_INF = UTF8StringUtil.writeStringToBytes("INF"); - private final byte[] NEGATIVE_INF = UTF8StringUtil.writeStringToBytes("-INF"); - private final byte[] NAN = UTF8StringUtil.writeStringToBytes("NaN"); - private IBinaryComparator utf8BinaryComparator = - BinaryComparatorFactoryProvider.UTF8STRING_POINTABLE_INSTANCE.createBinaryComparator(); private AMutableFloat aFloat = new AMutableFloat(0); @SuppressWarnings("unchecked") private ISerializerDeserializer<AFloat> floatSerde = @@ -92,17 +87,19 @@ result.set(inputArg); } else if (tt == ATypeTag.SERIALIZED_STRING_TYPE_TAG) { resultStorage.reset(); - if (utf8BinaryComparator.compare(serString, offset + 1, len - 1, POSITIVE_INF, 0, - 5) == 0) { + int utf8offset = offset + 1; + int utf8len = len - 1; + if (AbstractDoubleConstructorEvaluator.POSITIVE_INF.compareTo(serString, utf8offset, + utf8len) == 0) { aFloat.setValue(Float.POSITIVE_INFINITY); - } else if (utf8BinaryComparator.compare(serString, offset + 1, len - 1, NEGATIVE_INF, 0, - 6) == 0) { + } else if (AbstractDoubleConstructorEvaluator.NEGATIVE_INF.compareTo(serString, + utf8offset, utf8len) == 0) { aFloat.setValue(Float.NEGATIVE_INFINITY); - } else if (utf8BinaryComparator.compare(serString, offset + 1, len - 1, NAN, 0, - 5) == 0) { + } else if (AbstractDoubleConstructorEvaluator.NAN.compareTo(serString, utf8offset, + utf8len) == 0) { aFloat.setValue(Float.NaN); } else { - utf8Ptr.set(serString, offset + 1, len - 1); + utf8Ptr.set(serString, utf8offset, utf8len); aFloat.setValue(Float.parseFloat(utf8Ptr.toString())); } floatSerde.serialize(aFloat, out); diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractDoubleConstructorEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractDoubleConstructorEvaluator.java index 332bfc2..e10bf68 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractDoubleConstructorEvaluator.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractDoubleConstructorEvaluator.java @@ -22,7 +22,6 @@ import java.io.DataOutput; import java.io.IOException; -import org.apache.asterix.formats.nontagged.BinaryComparatorFactoryProvider; import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider; import org.apache.asterix.om.base.ADouble; import org.apache.asterix.om.base.AMutableDouble; @@ -32,7 +31,6 @@ import org.apache.asterix.runtime.exceptions.TypeMismatchException; import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; -import org.apache.hyracks.api.dataflow.value.IBinaryComparator; import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer; import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.data.std.api.IPointable; @@ -40,19 +38,15 @@ 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; -import org.apache.hyracks.util.string.UTF8StringUtil; public abstract class AbstractDoubleConstructorEvaluator implements IScalarEvaluator { @SuppressWarnings("unchecked") protected static final ISerializerDeserializer<ADouble> DOUBLE_SERDE = SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADOUBLE); - protected static final IBinaryComparator UTF8_BINARY_CMP = - BinaryComparatorFactoryProvider.UTF8STRING_POINTABLE_INSTANCE.createBinaryComparator(); - - protected static final byte[] POSITIVE_INF = UTF8StringUtil.writeStringToBytes("INF"); - protected static final byte[] NEGATIVE_INF = UTF8StringUtil.writeStringToBytes("-INF"); - protected static final byte[] NAN = UTF8StringUtil.writeStringToBytes("NaN"); + protected static final UTF8StringPointable POSITIVE_INF = UTF8StringPointable.generateUTF8Pointable("INF"); + protected static final UTF8StringPointable NEGATIVE_INF = UTF8StringPointable.generateUTF8Pointable("-INF"); + protected static final UTF8StringPointable NAN = UTF8StringPointable.generateUTF8Pointable("NaN"); protected final IScalarEvaluator inputEval; protected final ArrayBackedValueStorage resultStorage; @@ -89,14 +83,16 @@ result.set(inputArg); } else if (tt == ATypeTag.SERIALIZED_STRING_TYPE_TAG) { int len = inputArg.getLength(); - if (UTF8_BINARY_CMP.compare(bytes, offset + 1, len - 1, POSITIVE_INF, 0, 5) == 0) { + int utf8offset = offset + 1; + int utf8len = len - 1; + if (POSITIVE_INF.compareTo(bytes, utf8offset, utf8len) == 0) { setDouble(result, Double.POSITIVE_INFINITY); - } else if (UTF8_BINARY_CMP.compare(bytes, offset + 1, len - 1, NEGATIVE_INF, 0, 6) == 0) { + } else if (NEGATIVE_INF.compareTo(bytes, utf8offset, utf8len) == 0) { setDouble(result, Double.NEGATIVE_INFINITY); - } else if (UTF8_BINARY_CMP.compare(bytes, offset + 1, len - 1, NAN, 0, 5) == 0) { + } else if (NAN.compareTo(bytes, utf8offset, utf8len) == 0) { setDouble(result, Double.NaN); } else { - utf8Ptr.set(bytes, offset + 1, len - 1); + utf8Ptr.set(bytes, utf8offset, utf8len); try { setDouble(result, Double.parseDouble(utf8Ptr.toString())); } catch (NumberFormatException e) { diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractStringConstructorEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractStringConstructorEvaluator.java index 6918bb9..11576aa 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractStringConstructorEvaluator.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractStringConstructorEvaluator.java @@ -106,12 +106,28 @@ } case DOUBLE: { double d = ADoubleSerializerDeserializer.getDouble(serString, startOffset); - builder.appendString(String.valueOf(d)); + if (Double.isNaN(d)) { + builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NAN); + } else if (d == Double.POSITIVE_INFINITY) { // NOSONAR + builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.POSITIVE_INF); + } else if (d == Double.NEGATIVE_INFINITY) { // NOSONAR + builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NEGATIVE_INF); + } else { + builder.appendString(String.valueOf(d)); + } break; } case FLOAT: { float f = AFloatSerializerDeserializer.getFloat(serString, startOffset); - builder.appendString(String.valueOf(f)); + if (Float.isNaN(f)) { + builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NAN); + } else if (f == Float.POSITIVE_INFINITY) { // NOSONAR + builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.POSITIVE_INF); + } else if (f == Float.NEGATIVE_INFINITY) { // NOSONAR + builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NEGATIVE_INF); + } else { + builder.appendString(String.valueOf(f)); + } break; } case BOOLEAN: { diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfInfDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfInfDescriptor.java new file mode 100644 index 0000000..0ff08a4 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfInfDescriptor.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; + +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.functions.IFunctionDescriptorFactory; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +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 IfInfDescriptor extends AbstractScalarFunctionDynamicDescriptor { + + private static final long serialVersionUID = 1L; + public static final IFunctionDescriptorFactory FACTORY = IfInfDescriptor::new; + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new IfNanOrInfDescriptor.AbstractIfInfOrNanEval(ctx, args) { + @Override + protected boolean skipDouble(double d) { + return Double.isInfinite(d); + } + + @Override + protected boolean skipFloat(float f) { + return Float.isInfinite(f); + } + + @Override + protected FunctionIdentifier getIdentifier() { + return IfInfDescriptor.this.getIdentifier(); + } + }; + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.IF_INF; + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingDescriptor.java index 984b692..c3c017c 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingDescriptor.java @@ -40,7 +40,7 @@ @Override public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { - return new IfMissingOrNullDescriptor.AbstractIfEvaluator(ctx, args) { + return new IfMissingOrNullDescriptor.AbstractIfMissingOrNullEval(ctx, args) { @Override protected boolean skip(byte argTypeTag) { return argTypeTag == ATypeTag.SERIALIZED_MISSING_TYPE_TAG; diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingOrNullDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingOrNullDescriptor.java index 28db4d6..3166c40 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingOrNullDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingOrNullDescriptor.java @@ -45,7 +45,7 @@ @Override public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { - return new AbstractIfEvaluator(ctx, args) { + return new AbstractIfMissingOrNullEval(ctx, args) { @Override protected boolean skip(byte argTypeTag) { return argTypeTag == ATypeTag.SERIALIZED_MISSING_TYPE_TAG @@ -61,15 +61,14 @@ return BuiltinFunctions.IF_MISSING_OR_NULL; } - public static abstract class AbstractIfEvaluator implements IScalarEvaluator { - - private static final byte[] nullBytes = new byte[] { ATypeTag.SERIALIZED_NULL_TYPE_TAG }; + public static abstract class AbstractIfMissingOrNullEval implements IScalarEvaluator { private final IScalarEvaluator[] argEvals; private final IPointable argPtr; - AbstractIfEvaluator(IHyracksTaskContext ctx, IScalarEvaluatorFactory[] args) throws HyracksDataException { + AbstractIfMissingOrNullEval(IHyracksTaskContext ctx, IScalarEvaluatorFactory[] args) + throws HyracksDataException { argEvals = new IScalarEvaluator[args.length]; for (int i = 0; i < argEvals.length; i++) { argEvals[i] = args[i].createScalarEvaluator(ctx); @@ -88,7 +87,7 @@ return; } } - result.set(nullBytes, 0, nullBytes.length); + PointableHelper.setNull(result); } protected abstract boolean skip(byte argTypeTag); diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanDescriptor.java new file mode 100644 index 0000000..9c1f024 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanDescriptor.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; + +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.functions.IFunctionDescriptorFactory; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +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 IfNanDescriptor extends AbstractScalarFunctionDynamicDescriptor { + + private static final long serialVersionUID = 1L; + public static final IFunctionDescriptorFactory FACTORY = IfNanDescriptor::new; + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new IfNanOrInfDescriptor.AbstractIfInfOrNanEval(ctx, args) { + @Override + protected boolean skipDouble(double d) { + return Double.isNaN(d); + } + + @Override + protected boolean skipFloat(float f) { + return Float.isNaN(f); + } + + @Override + protected FunctionIdentifier getIdentifier() { + return IfNanDescriptor.this.getIdentifier(); + } + }; + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.IF_NAN; + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanOrInfDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanOrInfDescriptor.java new file mode 100644 index 0000000..bf61922 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNanOrInfDescriptor.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions; + +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.exceptions.RuntimeDataException; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.functions.IFunctionDescriptorFactory; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.primitive.DoublePointable; +import org.apache.hyracks.data.std.primitive.FloatPointable; +import org.apache.hyracks.data.std.primitive.VoidPointable; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class IfNanOrInfDescriptor extends AbstractScalarFunctionDynamicDescriptor { + + private static final long serialVersionUID = 1L; + public static final IFunctionDescriptorFactory FACTORY = IfNanOrInfDescriptor::new; + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new AbstractIfInfOrNanEval(ctx, args) { + @Override + protected boolean skipDouble(double d) { + return Double.isInfinite(d) || Double.isNaN(d); + } + + @Override + protected boolean skipFloat(float f) { + return Float.isInfinite(f) || Float.isNaN(f); + } + + @Override + protected FunctionIdentifier getIdentifier() { + return IfNanOrInfDescriptor.this.getIdentifier(); + } + }; + } + }; + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.IF_NAN_OR_INF; + } + + public static abstract class AbstractIfInfOrNanEval implements IScalarEvaluator { + + private final IScalarEvaluator[] argEvals; + + private final IPointable argPtr; + + AbstractIfInfOrNanEval(IHyracksTaskContext ctx, IScalarEvaluatorFactory[] args) throws HyracksDataException { + argEvals = new IScalarEvaluator[args.length]; + for (int i = 0; i < argEvals.length; i++) { + argEvals[i] = args[i].createScalarEvaluator(ctx); + } + argPtr = new VoidPointable(); + } + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + for (int i = 0; i < argEvals.length; i++) { + argEvals[i].evaluate(tuple, argPtr); + ATypeTag argTypeTag = PointableHelper.getTypeTag(argPtr); + if (argTypeTag == null) { + throw new RuntimeDataException(ErrorCode.INVALID_FORMAT, getIdentifier(), i); + } + switch (argTypeTag) { + case DOUBLE: + double d = DoublePointable.getDouble(argPtr.getByteArray(), argPtr.getStartOffset() + 1); + if (skipDouble(d)) { + continue; + } + result.set(argPtr); + return; + case FLOAT: + float f = FloatPointable.getFloat(argPtr.getByteArray(), argPtr.getStartOffset() + 1); + if (skipFloat(f)) { + continue; + } + result.set(argPtr); + return; + case BIGINT: + case INTEGER: + case SMALLINT: + case TINYINT: + case MISSING: + result.set(argPtr); + return; + default: + PointableHelper.setNull(result); + return; + } + } + + PointableHelper.setNull(result); + } + + protected abstract FunctionIdentifier getIdentifier(); + + protected abstract boolean skipDouble(double d); + + protected abstract boolean skipFloat(float f); + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNullDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNullDescriptor.java index 11e464a..e5316cb 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNullDescriptor.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNullDescriptor.java @@ -41,7 +41,7 @@ @Override public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { - return new IfMissingOrNullDescriptor.AbstractIfEvaluator(ctx, args) { + return new IfMissingOrNullDescriptor.AbstractIfMissingOrNullEval(ctx, args) { @Override protected boolean skip(byte argTypeTag) { return argTypeTag == ATypeTag.SERIALIZED_NULL_TYPE_TAG; diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java index df8fc75..1c69d4c 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableHelper.java @@ -28,6 +28,7 @@ import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.data.std.accessors.PointableBinaryComparatorFactory; import org.apache.hyracks.data.std.api.IMutableValueStorage; +import org.apache.hyracks.data.std.api.IPointable; import org.apache.hyracks.data.std.api.IValueReference; import org.apache.hyracks.data.std.primitive.UTF8StringPointable; import org.apache.hyracks.util.string.UTF8StringWriter; @@ -40,6 +41,9 @@ */ public class PointableHelper { + + private static final byte[] NULL_BYTES = new byte[] { ATypeTag.SERIALIZED_NULL_TYPE_TAG }; + private static final IBinaryComparator STRING_BINARY_COMPARATOR = PointableBinaryComparatorFactory.of(UTF8StringPointable.FACTORY).createBinaryComparator(); private final UTF8StringWriter utf8Writer; @@ -123,4 +127,8 @@ throw new HyracksDataException("Could not serialize " + str); } } + + public static void setNull(IPointable pointable) { + pointable.set(NULL_BYTES, 0, NULL_BYTES.length); + } } diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java index 2f1fdcb..c47a4de 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 @@ -162,8 +162,11 @@ import org.apache.asterix.runtime.evaluators.functions.GramTokensDescriptor; import org.apache.asterix.runtime.evaluators.functions.HashedGramTokensDescriptor; import org.apache.asterix.runtime.evaluators.functions.HashedWordTokensDescriptor; +import org.apache.asterix.runtime.evaluators.functions.IfInfDescriptor; +import org.apache.asterix.runtime.evaluators.functions.IfNanOrInfDescriptor; import org.apache.asterix.runtime.evaluators.functions.IfMissingDescriptor; import org.apache.asterix.runtime.evaluators.functions.IfMissingOrNullDescriptor; +import org.apache.asterix.runtime.evaluators.functions.IfNanDescriptor; import org.apache.asterix.runtime.evaluators.functions.IfNullDescriptor; import org.apache.asterix.runtime.evaluators.functions.InjectFailureDescriptor; import org.apache.asterix.runtime.evaluators.functions.IsArrayDescriptor; @@ -483,6 +486,9 @@ fc.addGenerated(GetItemDescriptor.FACTORY); // Numeric functions + fc.add(IfInfDescriptor.FACTORY); + fc.add(IfNanDescriptor.FACTORY); + fc.add(IfNanOrInfDescriptor.FACTORY); fc.addGenerated(NumericUnaryMinusDescriptor.FACTORY); fc.addGenerated(NumericAddDescriptor.FACTORY); fc.addGenerated(NumericDivideDescriptor.FACTORY); -- To view, visit https://asterix-gerrit.ics.uci.edu/2411 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: merged Gerrit-Change-Id: I12dccd848a1d6b4ba102bea3b7602c2cbd8aaef5 Gerrit-PatchSet: 5 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Dmitry Lychagin <[email protected]> Gerrit-Reviewer: Anon. E. Moose #1000171 Gerrit-Reviewer: Dmitry Lychagin <[email protected]> Gerrit-Reviewer: Jenkins <[email protected]> Gerrit-Reviewer: Till Westmann <[email protected]>
