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 <jenk...@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <ti...@apache.org>
---
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 <dmitry.lycha...@couchbase.com>
Gerrit-Reviewer: Anon. E. Moose #1000171
Gerrit-Reviewer: Dmitry Lychagin <dmitry.lycha...@couchbase.com>
Gerrit-Reviewer: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Gerrit-Reviewer: Till Westmann <ti...@apache.org>

Reply via email to