Added built-in functions: ifmissing(), ifnull(), ifmissingornull()
Change-Id: Id114f6654b9814c5aeca07fffeea04daeb8dca19
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1745
Reviewed-by: Yingyi Bu <buyingyi@gmail.com>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
BAD: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
index 6f24fc5..7431218 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
@@ -158,6 +158,9 @@
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.IfMissingDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.IfMissingOrNullDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.IfNullDescriptor;
import org.apache.asterix.runtime.evaluators.functions.InjectFailureDescriptor;
import org.apache.asterix.runtime.evaluators.functions.IsArrayDescriptor;
import org.apache.asterix.runtime.evaluators.functions.IsBooleanDescriptor;
@@ -428,6 +431,9 @@
temp.add(IsUnknownDescriptor.FACTORY);
temp.add(IsSystemNullDescriptor.FACTORY);
temp.add(CheckUnknownDescriptor.FACTORY);
+ temp.add(IfMissingDescriptor.FACTORY);
+ temp.add(IfNullDescriptor.FACTORY);
+ temp.add(IfMissingOrNullDescriptor.FACTORY);
// uuid generators (zero independent functions)
temp.add(CreateUUIDDescriptor.FACTORY);
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/types/ifmissing/ifmissing.1.query.sqlpp
new file mode 100644
index 0000000..2f0d837
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifmissing/ifmissing.1.query.sqlpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+{
+ "a": isnull(ifmissing()),
+ "b": isnull(ifmissing(missing)),
+ "c": isnull(ifmissing(missing, missing)),
+ "d": ifmissing(missing, missing, true, 1),
+ "e": ifmissing(true, false, 1),
+ "f": isstring(ifmissing("true", true, 1)),
+ "g": if_missing(missing, true, 1),
+ "i": ifmissing(
+ missing,
+ case when get_year(current_datetime()) > 0 then missing else false end,
+ case when get_year(current_datetime()) > 0 then true else null end
+ )
+};
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/types/ifmissingornull/ifmissingornull.1.query.sqlpp
new file mode 100644
index 0000000..32f040f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifmissingornull/ifmissingornull.1.query.sqlpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+{
+ "a": isnull(ifmissingornull()),
+ "b": isnull(ifmissingornull(missing)),
+ "c": isnull(ifmissingornull(null)),
+ "d": isnull(ifmissingornull(null, missing)),
+ "e": ifmissingornull(null, true, 1),
+ "f": ifmissingornull(missing, true, 1),
+ "g": ifmissingornull(null, missing, true, 1),
+ "h": if_missing_or_null(null, missing, true, 1),
+ "i": ifmissingornull(
+ missing,
+ null,
+ case when get_year(current_datetime()) > 0 then missing else false end,
+ case when get_year(current_datetime()) > 0 then null else false end,
+ case when get_year(current_datetime()) > 0 then true else missing end
+ )
+};
\ No newline at end of file
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/types/ifnull/ifnull.1.query.sqlpp
new file mode 100644
index 0000000..c0683bd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/ifnull/ifnull.1.query.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+{
+ "a": isnull(null),
+ "b": isnull(ifnull()),
+ "c": isnull(ifnull(null)),
+ "d": ismissing(ifnull(missing)),
+ "e": ifnull(null, true, 1),
+ "f": ifnull(null, null, true, 1),
+ "g": ismissing(ifnull(missing, false, 1)),
+ "h": if_null(null, true),
+ "i": ifnull(
+ null,
+ case when get_year(current_datetime()) > 0 then null else false end,
+ case when get_year(current_datetime()) > 0 then true else missing end
+ )
+};
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/types/ifmissing/ifmissing.1.adm
new file mode 100644
index 0000000..0a2275f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifmissing/ifmissing.1.adm
@@ -0,0 +1 @@
+{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "i": true }
\ No newline at end of file
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/types/ifmissingornull/ifmissingornull.1.adm
new file mode 100644
index 0000000..633c503
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifmissingornull/ifmissingornull.1.adm
@@ -0,0 +1 @@
+{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "h": true, "i": true }
\ No newline at end of file
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/types/ifnull/ifnull.1.adm
new file mode 100644
index 0000000..633c503
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/ifnull/ifnull.1.adm
@@ -0,0 +1 @@
+{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "h": true, "i": true }
\ 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 d5716d1..29917d4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -8410,6 +8410,21 @@
<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-group>
<test-group name="materialization">
<test-case FilePath="materialization">
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index e59c379..8897dbf 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -98,6 +98,7 @@
public static final int INCOMPATIBLE_SEARCH_MODIFIER = 1035;
public static final int UNKNOWN_SEARCH_MODIFIER = 1036;
public static final int COMPILATION_BAD_QUERY_PARAMETER_VALUE = 1037;
+ public static final int COMPILATION_ILLEGAL_STATE = 1038;
// Feed errors
public static final int DATAFLOW_ILLEGAL_STATE = 3001;
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index 487758c..1c93efe 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -84,6 +84,7 @@
1035 = Incompatible search modifier %1$s for index type %2$s
1036 = Unknown search modifier type %1$s
1037 = Invalid query parameter %1$s -- value has to be greater than or equal to %2$s bytes
+1038 = Illegal state. %1$s
# Feed Errors
3001 = Illegal state.
diff --git a/asterixdb/asterix-doc/pom.xml b/asterixdb/asterix-doc/pom.xml
index fed37b8..9b980e1 100644
--- a/asterixdb/asterix-doc/pom.xml
+++ b/asterixdb/asterix-doc/pom.xml
@@ -56,10 +56,10 @@
<filelist dir="${project.basedir}/src/main/markdown/sqlpp" files="0_toc.md,1_intro.md,2_expr_title.md,2_expr.md,3_query_title.md,3_query.md,4_error_title.md,4_error.md,5_ddl.md,appendix_1_title.md,appendix_1_keywords.md,appendix_2_title.md,appendix_2_parameters.md" />
</concat>
<concat destfile="${project.build.directory}/generated-site/markdown/sqlpp/builtins.md">
- <filelist dir="${project.basedir}/src/main/markdown/builtins" files="0_toc.md,1_numeric.md,2_string.md,3_binary.md,4_spatial.md,5_similarity.md,6_tokenizing.md,7_temporal.md,7_allens.md,8_record.md,9_aggregate_sql.md,10_comparison.md,11_type.md,12_misc.md" />
+ <filelist dir="${project.basedir}/src/main/markdown/builtins" files="0_toc.md,1_numeric.md,2_string.md,3_binary.md,4_spatial.md,5_similarity.md,6_tokenizing.md,7_temporal.md,7_allens.md,8_record.md,9_aggregate_sql.md,10_comparison.md,11_type.md,13_conditional.md,12_misc.md" />
</concat>
<concat destfile="${project.build.directory}/generated-site/markdown/aql/builtins.md">
- <filelist dir="${project.basedir}/src/main/markdown/builtins" files="0_toc.md,1_numeric.md,2_string.md,3_binary.md,4_spatial.md,5_similarity.md,6_tokenizing.md,7_temporal.md,7_allens.md,8_record.md,9_aggregate_aql.md,10_comparison.md,11_type.md,12_misc.md" />
+ <filelist dir="${project.basedir}/src/main/markdown/builtins" files="0_toc.md,1_numeric.md,2_string.md,3_binary.md,4_spatial.md,5_similarity.md,6_tokenizing.md,7_temporal.md,7_allens.md,8_record.md,9_aggregate_aql.md,10_comparison.md,11_type.md,13_conditional.md,12_misc.md" />
</concat>
<concat destfile="${project.build.directory}/generated-site/markdown/ansible.md">
<filelist dir="${project.basedir}/src/main/installation/" files="ansible_title.md,ansible.md" />
diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/0_toc.md b/asterixdb/asterix-doc/src/main/markdown/builtins/0_toc.md
index 911ee63..e0d23d4 100644
--- a/asterixdb/asterix-doc/src/main/markdown/builtins/0_toc.md
+++ b/asterixdb/asterix-doc/src/main/markdown/builtins/0_toc.md
@@ -32,6 +32,7 @@
* [Aggregate Functions (Array Functions)](#AggregateFunctions)
* [Comparison Functions](#ComparisonFunctions)
* [Type Functions](#TypeFunctions)
+* [Conditional Functions](#ConditionalFunctions)
* [Miscellaneous Functions](#MiscFunctions)
The system provides various classes of functions to support operations on numeric, string, spatial, and temporal data.
diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md b/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md
new file mode 100644
index 0000000..04fa943
--- /dev/null
+++ b/asterixdb/asterix-doc/src/main/markdown/builtins/13_conditional.md
@@ -0,0 +1,103 @@
+<!--
+ ! 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.
+ !-->
+
+## <a id="ConditionalFunctions">Conditional Functions</a> <font size="4"><a href="#toc">[Back to TOC]</a></font> ##
+
+### if_null (ifnull) ###
+
+ * Syntax:
+
+ if_null(expression1, expression2, ... expressionN)
+
+ * Finds first argument which value is not `null` and returns that value
+ * Arguments:
+ * `expressionI` : an expression (any type is allowed).
+ * Return Value:
+ * a `null` if all arguments evaluate to `null` or no arguments specified
+ * a value of the first non-`null` argument otherwise
+
+ * Example:
+
+ {
+ "a": if_null(),
+ "b": if_null(null),
+ "c": if_null(null, "asterixdb"),
+ "d": is_missing(if_null(missing))
+ };
+
+ * The expected result is:
+
+ { "a": null, "b": null, "c": "asterixdb", "d": true }
+
+ The function has an alias `ifnull`.
+
+### if_missing (ifmissing) ###
+
+ * Syntax:
+
+ if_missing(expression1, expression2, ... expressionN)
+
+ * Finds first argument which value is not `missing` and returns that value
+ * Arguments:
+ * `expressionI` : an expression (any type is allowed).
+ * Return Value:
+ * a `null` if all arguments evaluate to `missing` or no arguments specified
+ * a value of the first non-`missing` argument otherwise
+
+ * Example:
+
+ {
+ "a": if_missing(),
+ "b": if_missing(missing),
+ "c": if_missing(missing, "asterixdb"),
+ "d": if_missing(null, "asterixdb")
+ };
+
+ * The expected result is:
+
+ { "a": null, "b": null, "c": "asterixdb", "d": null }
+
+ The function has an alias `ifmissing`.
+
+### if_missing_or_null (ifmissingornull) ###
+
+ * Syntax:
+
+ if_missing_or_null(expression1, expression2, ... expressionN)
+
+ * Finds first argument which value is not `null` or `missing` and returns that value
+ * Arguments:
+ * `expressionI` : an expression (any type is allowed).
+ * Return Value:
+ * a `null` if all arguments evaluate to either `null` or `missing`, or no arguments specified
+ * a value of the first non-`null`, non-`missing` argument otherwise
+
+* Example:
+
+ {
+ "a": if_missing_or_null(),
+ "b": if_missing_or_null(null, missing),
+ "c": if_missing_or_null(null, missing, "asterixdb")
+ };
+
+ * The expected result is:
+
+ { "a": null, "b": null, "c": "asterixdb" }
+
+ The function has an alias `ifmissingornull`.
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 33e0c52..6a0c05e 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
@@ -62,6 +62,9 @@
FUNCTION_NAME_MAP.put("isarray", "is-array"); // isarray, internal: is-array
FUNCTION_NAME_MAP.put("isobject", "is-object"); // isobject, internal: is-object
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
// Object functions
FUNCTION_NAME_MAP.put("record-merge", "object-merge"); // record-merge, internal: object-merge
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java
index 415c1ae..561df5e 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java
@@ -58,6 +58,21 @@
}
/**
+ * Returns a minimally generalized type that conforms to all input types.
+ *
+ * @param inputTypes,
+ * a list of input types
+ * @return a generalized type that conforms to all input types.
+ */
+ public static IAType resolve(IAType... inputTypes) {
+ IAType currentType = null;
+ for (IAType type : inputTypes) {
+ currentType = currentType == null ? type : generalizeTypes(currentType, type);
+ }
+ return currentType;
+ }
+
+ /**
* Decides whether a type cast is needed to covert data instances from the input type to the required type.
*
* @param reqType,
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 0769596..6fc3ed9 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,9 @@
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.IfMissingOrNullTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.IfMissingTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.IfNullTypeComputer;
import org.apache.asterix.om.typecomputer.impl.InjectFailureTypeComputer;
import org.apache.asterix.om.typecomputer.impl.LocalAvgTypeComputer;
import org.apache.asterix.om.typecomputer.impl.MinMaxAggTypeComputer;
@@ -792,7 +795,14 @@
public static final FunctionIdentifier CHECK_UNKNOWN = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
"check-unknown", 1);
public static final FunctionIdentifier COLLECTION_TO_SEQUENCE = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
- "" + "collection-to-sequence", 1);
+ "collection-to-sequence", 1);
+
+ public static final FunctionIdentifier IF_MISSING = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
+ "if-missing", FunctionIdentifier.VARARGS);
+ public static final FunctionIdentifier IF_NULL = 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 EXTERNAL_LOOKUP = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
"external-lookup", FunctionIdentifier.VARARGS);
@@ -880,6 +890,9 @@
addPrivateFunction(GRAM_TOKENS, OrderedListOfAStringTypeComputer.INSTANCE, true);
addPrivateFunction(HASHED_GRAM_TOKENS, OrderedListOfAInt32TypeComputer.INSTANCE, true);
addPrivateFunction(HASHED_WORD_TOKENS, OrderedListOfAInt32TypeComputer.INSTANCE, true);
+ addFunction(IF_MISSING_OR_NULL, IfMissingOrNullTypeComputer.INSTANCE, true);
+ addFunction(IF_MISSING, IfMissingTypeComputer.INSTANCE, true);
+ addFunction(IF_NULL, IfNullTypeComputer.INSTANCE, true);
addPrivateFunction(INDEX_SEARCH, AnyTypeComputer.INSTANCE, true);
addFunction(INT8_CONSTRUCTOR, AInt8TypeComputer.INSTANCE, true);
addFunction(INT16_CONSTRUCTOR, AInt16TypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractIfMissingOrNullTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractIfMissingOrNullTypeComputer.java
new file mode 100644
index 0000000..2626c6b
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractIfMissingOrNullTypeComputer.java
@@ -0,0 +1,112 @@
+/*
+ * 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.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.dataflow.data.common.TypeResolverUtil;
+import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
+
+abstract class AbstractIfMissingOrNullTypeComputer implements IResultTypeComputer {
+ @Override
+ public IAType computeType(ILogicalExpression expression, IVariableTypeEnvironment env,
+ IMetadataProvider<?, ?> metadataProvider) throws AlgebricksException {
+ AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expression;
+ IAType outPrimeType = null;
+ ATypeTag outQuantifier = null; // could be 'missing' or 'null'
+
+ for (Mutable<ILogicalExpression> argRef : fce.getArguments()) {
+ ILogicalExpression arg = argRef.getValue();
+ IAType argType = (IAType) env.getType(arg);
+ ATypeTag argTypeTag = argType.getTypeTag();
+
+ if (equalsIfType(argTypeTag)) {
+ continue;
+ }
+
+ if (argTypeTag == ATypeTag.UNION) {
+ AUnionType unionType = (AUnionType) argType;
+ if (intersectsIfType(unionType)) {
+ IAType primeType = getOutputPrimeType(unionType);
+ outPrimeType = outPrimeType == null ? primeType : TypeResolverUtil.resolve(outPrimeType, primeType);
+ if (outQuantifier == null) {
+ outQuantifier = getOutputQuantifier(unionType);
+ }
+ } else {
+ // no intersection
+ if (outPrimeType == null) {
+ return argType;
+ } else {
+ IAType primeType = getOutputPrimeType(unionType);
+ ATypeTag quantifier = outQuantifier != null ? outQuantifier : getOutputQuantifier(unionType);
+ return createOutputType(TypeResolverUtil.resolve(outPrimeType, primeType), quantifier);
+ }
+ }
+ } else {
+ // ANY or no intersection
+ return outPrimeType == null ? argType
+ : createOutputType(TypeResolverUtil.resolve(outPrimeType, argType), outQuantifier);
+ }
+ }
+
+ if (outPrimeType == null) {
+ return BuiltinType.ANULL;
+ }
+ IAType outType = createOutputType(outPrimeType, ATypeTag.NULL);
+ if (outQuantifier == ATypeTag.MISSING) {
+ outType = createOutputType(outType, ATypeTag.MISSING);
+ }
+ return outType;
+ }
+
+ protected abstract boolean equalsIfType(ATypeTag typeTag);
+
+ protected abstract boolean intersectsIfType(AUnionType type);
+
+ protected abstract ATypeTag getOutputQuantifier(AUnionType type);
+
+ private IAType getOutputPrimeType(AUnionType type) {
+ return type.getActualType();
+ }
+
+ private IAType createOutputType(IAType primeType, ATypeTag quantifier) throws AlgebricksException {
+ if (quantifier == null || primeType.getTypeTag() == ATypeTag.ANY) {
+ return primeType;
+ }
+ switch (quantifier) {
+ case MISSING:
+ return AUnionType.createMissableType(primeType);
+ case NULL:
+ return AUnionType.createNullableType(primeType, null);
+ default:
+ throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, String.valueOf(quantifier));
+ }
+ }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfMissingOrNullTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfMissingOrNullTypeComputer.java
new file mode 100644
index 0000000..fd35c79
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfMissingOrNullTypeComputer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.IResultTypeComputer;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+
+public class IfMissingOrNullTypeComputer extends AbstractIfMissingOrNullTypeComputer {
+
+ public static final IResultTypeComputer INSTANCE = new IfMissingOrNullTypeComputer();
+
+ @Override
+ protected boolean equalsIfType(ATypeTag typeTag) {
+ return typeTag == ATypeTag.MISSING || typeTag == ATypeTag.NULL;
+ }
+
+ @Override
+ protected boolean intersectsIfType(AUnionType type) {
+ return type.isUnknownableType();
+ }
+
+ @Override
+ protected ATypeTag getOutputQuantifier(AUnionType type) {
+ // 'missing' and 'null' cannot be in the output
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfMissingTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfMissingTypeComputer.java
new file mode 100644
index 0000000..1742921
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfMissingTypeComputer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.IResultTypeComputer;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+
+public class IfMissingTypeComputer extends AbstractIfMissingOrNullTypeComputer {
+
+ public static final IResultTypeComputer INSTANCE = new IfMissingTypeComputer();
+
+ @Override
+ protected boolean equalsIfType(ATypeTag typeTag) {
+ return typeTag == ATypeTag.MISSING;
+ }
+
+ @Override
+ protected boolean intersectsIfType(AUnionType type) {
+ return type.isMissableType();
+ }
+
+ @Override
+ protected ATypeTag getOutputQuantifier(AUnionType type) {
+ // 'null' may be in the output
+ return type.isNullableType() ? ATypeTag.NULL : null;
+ }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNullTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNullTypeComputer.java
new file mode 100644
index 0000000..149b35d
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/IfNullTypeComputer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.IResultTypeComputer;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+
+public class IfNullTypeComputer extends IfMissingOrNullTypeComputer {
+
+ public static final IResultTypeComputer INSTANCE = new IfNullTypeComputer();
+
+ @Override
+ protected boolean equalsIfType(ATypeTag typeTag) {
+ return typeTag == ATypeTag.NULL;
+ }
+
+ @Override
+ protected boolean intersectsIfType(AUnionType type) {
+ return type.isNullableType();
+ }
+
+ @Override
+ protected ATypeTag getOutputQuantifier(AUnionType type) {
+ // 'missing' may be in the output
+ return type.isMissableType() ? ATypeTag.MISSING : null;
+ }
+}
diff --git a/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java b/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java
index e1d4088..fc4646f 100644
--- a/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java
+++ b/asterixdb/asterix-om/src/test/java/org/apache/asterix/om/typecomputer/ExceptionTest.java
@@ -59,8 +59,8 @@
testTypeComputer(c);
++numTypeComputers;
}
- // Currently, there are 78 type computers.
- Assert.assertTrue(numTypeComputers >= 78);
+ // Currently, there are 83 type computers.
+ Assert.assertTrue(numTypeComputers >= 83);
}
private void testTypeComputer(Class<? extends IResultTypeComputer> c) throws Exception {
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
new file mode 100644
index 0000000..984b692
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingDescriptor.java
@@ -0,0 +1,57 @@
+/*
+ * 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.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;
+
+public class IfMissingDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+ public static final IFunctionDescriptorFactory FACTORY = IfMissingDescriptor::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 IfMissingOrNullDescriptor.AbstractIfEvaluator(ctx, args) {
+ @Override
+ protected boolean skip(byte argTypeTag) {
+ return argTypeTag == ATypeTag.SERIALIZED_MISSING_TYPE_TAG;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return BuiltinFunctions.IF_MISSING;
+ }
+}
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
new file mode 100644
index 0000000..28db4d6
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfMissingOrNullDescriptor.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.runtime.evaluators.functions;
+
+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.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public final class IfMissingOrNullDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+ private static final long serialVersionUID = 1L;
+ public static final IFunctionDescriptorFactory FACTORY = IfMissingOrNullDescriptor::new;
+
+ @Override
+ public IScalarEvaluatorFactory createEvaluatorFactory(IScalarEvaluatorFactory[] args) throws AlgebricksException {
+ return new IScalarEvaluatorFactory() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException {
+ return new AbstractIfEvaluator(ctx, args) {
+ @Override
+ protected boolean skip(byte argTypeTag) {
+ return argTypeTag == ATypeTag.SERIALIZED_MISSING_TYPE_TAG
+ || argTypeTag == ATypeTag.SERIALIZED_NULL_TYPE_TAG;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ 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 };
+
+ private final IScalarEvaluator[] argEvals;
+
+ private final IPointable argPtr;
+
+ AbstractIfEvaluator(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 (IScalarEvaluator argEval : argEvals) {
+ argEval.evaluate(tuple, argPtr);
+ byte[] bytes = argPtr.getByteArray();
+ int offset = argPtr.getStartOffset();
+ if (!skip(bytes[offset])) {
+ result.set(argPtr);
+ return;
+ }
+ }
+ result.set(nullBytes, 0, nullBytes.length);
+ }
+
+ protected abstract boolean skip(byte argTypeTag);
+ }
+}
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
new file mode 100644
index 0000000..11e464a
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/IfNullDescriptor.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.runtime.evaluators.functions;
+
+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.common.exceptions.AlgebricksException;
+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 final class IfNullDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+ public static final IFunctionDescriptorFactory FACTORY = IfNullDescriptor::new;
+
+ @Override
+ public IScalarEvaluatorFactory createEvaluatorFactory(IScalarEvaluatorFactory[] args) throws AlgebricksException {
+ return new IScalarEvaluatorFactory() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException {
+ return new IfMissingOrNullDescriptor.AbstractIfEvaluator(ctx, args) {
+ @Override
+ protected boolean skip(byte argTypeTag) {
+ return argTypeTag == ATypeTag.SERIALIZED_NULL_TYPE_TAG;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return BuiltinFunctions.IF_NULL;
+ }
+}