[NO ISSUE][FUN] Add to_number() function
- user model changes: yes
- storage format changes: no
- interface changes: no
Details:
- add to_number() function
- add testcases and documentation
- fix type inference for to_bigint() and to_double()
to return optional type in cases when NULL can
be produced at runtime
Change-Id: Id370aadcf16447f7c775c30d2bffc33fc6a96927
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2449
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_number_01/to_number_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_number_01/to_number_01.1.query.sqlpp
new file mode 100644
index 0000000..739a6a9
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_number_01/to_number_01.1.query.sqlpp
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+ {
+ "t1": tonumber(false),
+ "t2": to_number(true),
+ "t3": tonum(int8("8")),
+ "t4": to_number(int16("16")),
+ "t5": to_number(int32("32")),
+ "t6": to_number(int64("64")),
+ "t7": to_number(float("1.5")),
+ "t8": to_number(double("2.25")),
+ "t9": to_number("512"),
+ "t10": is_null(to_number("foo")),
+ "t11": is_null(to_number([])),
+ "t12": is_null(to_number({{}})),
+ "t13": is_null(to_number({})),
+ "t14": is_null(to_number(null)),
+ "t15": is_missing(to_number(missing)),
+ "t16": to_string(to_number(float("INF"))),
+ "t17": to_string(to_number(float("-INF"))),
+ "t18": to_string(to_number(float("NaN"))),
+ "t19": to_string(to_number(double("INF"))),
+ "t20": to_string(to_number(double("-INF"))),
+ "t21": to_string(to_number(double("NaN")))
+ };
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_number_02/to_number_02.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_number_02/to_number_02.1.query.sqlpp
new file mode 100644
index 0000000..837750e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/types/to_number_02/to_number_02.1.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+{
+ "t": to_number(date("2017-06-30"))
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_number_01/to_number_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_number_01/to_number_01.1.adm
new file mode 100644
index 0000000..72416e4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/types/to_number_01/to_number_01.1.adm
@@ -0,0 +1 @@
+{ "t1": 0, "t2": 1, "t3": 8, "t4": 16, "t5": 32, "t6": 64, "t7": 1.5, "t8": 2.25, "t9": 512, "t10": true, "t11": true, "t12": true, "t13": true, "t14": true, "t15": true, "t16": "INF", "t17": "-INF", "t18": "NaN", "t19": "INF", "t20": "-INF", "t21": "NaN" }
\ 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 67980d0..6bb1886 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -9285,6 +9285,17 @@
<expected-error>ASX0002: Type mismatch</expected-error>
</compilation-unit>
</test-case>
+ <test-case FilePath="types">
+ <compilation-unit name="to_number_01">
+ <output-dir compare="Text">to_number_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="types">
+ <compilation-unit name="to_number_02">
+ <output-dir compare="Text">to_number_02</output-dir>
+ <expected-error>ASX0002: Type mismatch</expected-error>
+ </compilation-unit>
+ </test-case>
</test-group>
<test-group name="materialization">
<test-case FilePath="materialization">
diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/11_type.md b/asterixdb/asterix-doc/src/main/markdown/builtins/11_type.md
index fd6a262..f972735 100644
--- a/asterixdb/asterix-doc/src/main/markdown/builtins/11_type.md
+++ b/asterixdb/asterix-doc/src/main/markdown/builtins/11_type.md
@@ -399,6 +399,40 @@
The function has an alias `todouble`.
+### to_number ###
+ * Syntax:
+
+ to_number(expr)
+
+ * Converts input value to a numeric value
+ * Arguments:
+ * `expr` : an expression
+ * Return Value:
+ * if the argument is `missing` then `missing` is returned
+ * if the argument is `null` then `null` is returned
+ * if the argument is of numeric type then it is returned as is
+ * if the argument is of `boolean` type then `1` is returned if it is `true`, `0` if it is `false`
+ * if the argument is of `string` type and can be parsed as `bigint` then that `bigint` value is returned,
+ otherwise if it can be parsed as `double` then that `double` value is returned,
+ otherwise `null` is returned
+ * if the argument is of `array`/`multiset`/`object` type then `null` is returned
+ * type error is raised for all other input types
+
+ * Example:
+
+ {
+ "v1": to_number(false),
+ "v2": to_number(true),
+ "v3": to_number(10),
+ "v4": to_number(11.5),
+ "v5": to_number("12.5")
+ };
+
+ * The expected result is:
+
+ { "v1": 0, "v2": 1, "v3": 10, "v4": 11.5, "v5": 12.5 }
+
+ The function has an alias `tonumber`.
### to_string ###
* Syntax:
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 e5d1643..0646224 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
@@ -74,6 +74,8 @@
FUNCTION_NAME_MAP.put("tostring", "to-string"); // tostring, internal: to-string
FUNCTION_NAME_MAP.put("todouble", "to-double"); // todouble, internal: to-double
FUNCTION_NAME_MAP.put("tobigint", "to-bigint"); // tobigint, internal: to-bigint
+ FUNCTION_NAME_MAP.put("tonumber", "to-number"); // tonumber, internal: to-number
+ FUNCTION_NAME_MAP.put("tonum", "to-number"); // tonum, internal: to-number
// Object functions
// record-merge, internal: object-merge
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 761ddba..3e3cf43 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
@@ -106,6 +106,9 @@
import org.apache.asterix.om.typecomputer.impl.SubsetCollectionTypeComputer;
import org.apache.asterix.om.typecomputer.impl.SubstringTypeComputer;
import org.apache.asterix.om.typecomputer.impl.SwitchCaseComputer;
+import org.apache.asterix.om.typecomputer.impl.ToBigIntTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.ToDoubleTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.ToNumberTypeComputer;
import org.apache.asterix.om.typecomputer.impl.UnaryBinaryInt64TypeComputer;
import org.apache.asterix.om.typecomputer.impl.UnaryMinusTypeComputer;
import org.apache.asterix.om.typecomputer.impl.UnaryStringInt64TypeComputer;
@@ -871,6 +874,8 @@
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "to-double", 1);
public static final FunctionIdentifier TO_BIGINT =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "to-bigint", 1);
+ public static final FunctionIdentifier TO_NUMBER =
+ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "to-number", 1);
public static final FunctionIdentifier EXTERNAL_LOOKUP =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "external-lookup", FunctionIdentifier.VARARGS);
@@ -1057,8 +1062,9 @@
addFunction(TO_BOOLEAN, ABooleanTypeComputer.INSTANCE, true);
addFunction(TO_STRING, AStringTypeComputer.INSTANCE, true);
- addFunction(TO_DOUBLE, ADoubleTypeComputer.INSTANCE, true);
- addFunction(TO_BIGINT, AInt64TypeComputer.INSTANCE, true);
+ addFunction(TO_DOUBLE, ToDoubleTypeComputer.INSTANCE, true);
+ addFunction(TO_BIGINT, ToBigIntTypeComputer.INSTANCE, true);
+ addFunction(TO_NUMBER, ToNumberTypeComputer.INSTANCE, true);
// Aggregate Functions
addFunction(MAX, MinMaxAggTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToBigIntTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToBigIntTypeComputer.java
new file mode 100644
index 0000000..e7b6f42
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToBigIntTypeComputer.java
@@ -0,0 +1,53 @@
+/*
+ * 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 ToBigIntTypeComputer extends AbstractResultTypeComputer {
+
+ public static final ToBigIntTypeComputer INSTANCE = new ToBigIntTypeComputer();
+
+ private ToBigIntTypeComputer() {
+ }
+
+ @Override
+ protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
+ IAType strippedInputType = strippedInputTypes[0];
+ switch (strippedInputType.getTypeTag()) {
+ case BOOLEAN:
+ case TINYINT:
+ case SMALLINT:
+ case INTEGER:
+ case BIGINT:
+ case FLOAT:
+ case DOUBLE:
+ // these types cannot result in NULL output
+ return BuiltinType.AINT64;
+ default:
+ return AUnionType.createNullableType(BuiltinType.AINT64);
+ }
+ }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToDoubleTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToDoubleTypeComputer.java
new file mode 100644
index 0000000..7794aab
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToDoubleTypeComputer.java
@@ -0,0 +1,53 @@
+/*
+ * 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 ToDoubleTypeComputer extends AbstractResultTypeComputer {
+
+ public static final ToDoubleTypeComputer INSTANCE = new ToDoubleTypeComputer();
+
+ private ToDoubleTypeComputer() {
+ }
+
+ @Override
+ protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
+ IAType strippedInputType = strippedInputTypes[0];
+ switch (strippedInputType.getTypeTag()) {
+ case BOOLEAN:
+ case TINYINT:
+ case SMALLINT:
+ case INTEGER:
+ case BIGINT:
+ case FLOAT:
+ case DOUBLE:
+ // these types cannot result in NULL output
+ return BuiltinType.ADOUBLE;
+ default:
+ return AUnionType.createNullableType(BuiltinType.ADOUBLE);
+ }
+ }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToNumberTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToNumberTypeComputer.java
new file mode 100644
index 0000000..077a1eb
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ToNumberTypeComputer.java
@@ -0,0 +1,52 @@
+/*
+ * 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.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 ToNumberTypeComputer extends AbstractResultTypeComputer {
+ public static final ToNumberTypeComputer INSTANCE = new ToNumberTypeComputer();
+
+ private ToNumberTypeComputer() {
+ }
+
+ @Override
+ protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
+ IAType strippedInputType = strippedInputTypes[0];
+ switch (strippedInputType.getTypeTag()) {
+ case BOOLEAN:
+ return BuiltinType.AINT64;
+ case TINYINT:
+ case SMALLINT:
+ case INTEGER:
+ case BIGINT:
+ case FLOAT:
+ case DOUBLE:
+ return strippedInputType;
+ default:
+ // STRING can be parsed as either BIGINT or DOUBLE
+ return BuiltinType.ANY;
+ }
+ }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/AUnionType.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/AUnionType.java
index 007f072..9fdaca1 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/AUnionType.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/AUnionType.java
@@ -99,6 +99,14 @@
return createMissableType(t, s == null ? null : s + "?");
}
+ public static IAType createNullableType(IAType t) {
+ if (t != null && t.getTypeTag() == ATypeTag.NULL) {
+ return t;
+ }
+ String s = t != null ? t.getTypeName() : null;
+ return createNullableType(t, s == null ? null : s + "?");
+ }
+
public static IAType createNullableType(IAType type, String typeName) {
if (type != null && type.getTypeTag() == ATypeTag.NULL) {
return type;
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/NumberUtils.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/NumberUtils.java
new file mode 100644
index 0000000..0b2e94c
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/NumberUtils.java
@@ -0,0 +1,119 @@
+/*
+ * 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.common;
+
+import org.apache.asterix.om.base.AMutableDouble;
+import org.apache.asterix.om.base.AMutableInt64;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+
+/**
+ * Utility methods for number handling
+ */
+public final class NumberUtils {
+
+ public static final UTF8StringPointable POSITIVE_INF = UTF8StringPointable.generateUTF8Pointable("INF");
+
+ public static final UTF8StringPointable NEGATIVE_INF = UTF8StringPointable.generateUTF8Pointable("-INF");
+
+ public static final UTF8StringPointable NAN = UTF8StringPointable.generateUTF8Pointable("NaN");
+
+ public static final long NAN_BITS = Double.doubleToLongBits(Double.NaN);
+
+ public static final long POSITIVE_ZERO_BITS = Double.doubleToLongBits(+0.0d);
+
+ public static final long NEGATIVE_ZERO_BITS = Double.doubleToLongBits(-0.0d);
+
+ /**
+ * Parses string as double
+ * @param textPtr input string
+ * @param result placeholder for the result
+ * @return {@code true} if parsing was successful, {@code false} otherwise
+ */
+ public static boolean parseDouble(UTF8StringPointable textPtr, AMutableDouble result) {
+ double v;
+ if (POSITIVE_INF.compareTo(textPtr) == 0) {
+ v = Double.POSITIVE_INFINITY;
+ } else if (NEGATIVE_INF.compareTo(textPtr) == 0) {
+ v = Double.NEGATIVE_INFINITY;
+ } else if (NAN.compareTo(textPtr) == 0) {
+ v = Double.NaN;
+ } else {
+ try {
+ v = Double.parseDouble(textPtr.toString());
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ result.setValue(v);
+ return true;
+ }
+
+ /**
+ * Parses string as bigint
+ * @param textPtr input string
+ * @param result placeholder for the result
+ * @return {@code true} if parsing was successful, {@code false} otherwise
+ */
+ public static boolean parseInt64(UTF8StringPointable textPtr, AMutableInt64 result) {
+ byte[] bytes = textPtr.getByteArray();
+ int offset = textPtr.getCharStartOffset();
+ //accumulating value in negative domain
+ //otherwise Long.MIN_VALUE = -(Long.MAX_VALUE + 1) would have caused overflow
+ long value = 0;
+ boolean positive = true;
+ long limit = -Long.MAX_VALUE;
+ if (bytes[offset] == '+') {
+ offset++;
+ } else if (bytes[offset] == '-') {
+ offset++;
+ positive = false;
+ limit = Long.MIN_VALUE;
+ }
+ int end = textPtr.getStartOffset() + textPtr.getLength();
+ for (; offset < end; offset++) {
+ int digit;
+ if (bytes[offset] >= '0' && bytes[offset] <= '9') {
+ value *= 10;
+ digit = bytes[offset] - '0';
+ } else if (bytes[offset] == 'i' && bytes[offset + 1] == '6' && bytes[offset + 2] == '4'
+ && offset + 3 == end) {
+ break;
+ } else {
+ return false;
+ }
+ if (value < limit + digit) {
+ return false;
+ }
+ value -= digit;
+ }
+ if (value > 0) {
+ return false;
+ }
+ if (value < 0 && positive) {
+ value *= -1;
+ }
+
+ result.setValue(value);
+ return true;
+ }
+
+ private NumberUtils() {
+ }
+}
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 8c69671..b6f045e 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
@@ -21,7 +21,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.AFloat;
import org.apache.asterix.om.base.AMutableFloat;
@@ -31,13 +30,13 @@
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.evaluators.common.NumberUtils;
import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
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.algebricks.runtime.base.IScalarEvaluatorFactory;
import org.apache.hyracks.api.context.IHyracksTaskContext;
-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;
@@ -45,7 +44,6 @@
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 class AFloatConstructorDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
@@ -89,14 +87,11 @@
resultStorage.reset();
int utf8offset = offset + 1;
int utf8len = len - 1;
- if (AbstractDoubleConstructorEvaluator.POSITIVE_INF.compareTo(serString, utf8offset,
- utf8len) == 0) {
+ if (NumberUtils.POSITIVE_INF.compareTo(serString, utf8offset, utf8len) == 0) {
aFloat.setValue(Float.POSITIVE_INFINITY);
- } else if (AbstractDoubleConstructorEvaluator.NEGATIVE_INF.compareTo(serString,
- utf8offset, utf8len) == 0) {
+ } else if (NumberUtils.NEGATIVE_INF.compareTo(serString, utf8offset, utf8len) == 0) {
aFloat.setValue(Float.NEGATIVE_INFINITY);
- } else if (AbstractDoubleConstructorEvaluator.NAN.compareTo(serString, utf8offset,
- utf8len) == 0) {
+ } else if (NumberUtils.NAN.compareTo(serString, utf8offset, utf8len) == 0) {
aFloat.setValue(Float.NaN);
} else {
utf8Ptr.set(serString, utf8offset, utf8len);
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 e10bf68..456735f 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
@@ -27,6 +27,7 @@
import org.apache.asterix.om.base.AMutableDouble;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.runtime.evaluators.common.NumberUtils;
import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
import org.apache.asterix.runtime.exceptions.TypeMismatchException;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
@@ -44,10 +45,6 @@
protected static final ISerializerDeserializer<ADouble> DOUBLE_SERDE =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADOUBLE);
- 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;
protected final DataOutput out;
@@ -77,41 +74,25 @@
protected void evaluateImpl(IPointable result) throws IOException {
byte[] bytes = inputArg.getByteArray();
- int offset = inputArg.getStartOffset();
- byte tt = bytes[offset];
+ int startOffset = inputArg.getStartOffset();
+ byte tt = bytes[startOffset];
if (tt == ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG) {
result.set(inputArg);
} else if (tt == ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- int len = inputArg.getLength();
- int utf8offset = offset + 1;
- int utf8len = len - 1;
- if (POSITIVE_INF.compareTo(bytes, utf8offset, utf8len) == 0) {
- setDouble(result, Double.POSITIVE_INFINITY);
- } else if (NEGATIVE_INF.compareTo(bytes, utf8offset, utf8len) == 0) {
- setDouble(result, Double.NEGATIVE_INFINITY);
- } else if (NAN.compareTo(bytes, utf8offset, utf8len) == 0) {
- setDouble(result, Double.NaN);
+ utf8Ptr.set(bytes, startOffset + 1, inputArg.getLength() - 1);
+ if (NumberUtils.parseDouble(utf8Ptr, aDouble)) {
+ DOUBLE_SERDE.serialize(aDouble, out);
+ result.set(resultStorage);
} else {
- utf8Ptr.set(bytes, utf8offset, utf8len);
- try {
- setDouble(result, Double.parseDouble(utf8Ptr.toString()));
- } catch (NumberFormatException e) {
- handleUparseableString(result, e);
- }
+ handleUparseableString(result);
}
} else {
throw new TypeMismatchException(getIdentifier(), 0, tt, ATypeTag.SERIALIZED_STRING_TYPE_TAG);
}
}
- protected void handleUparseableString(IPointable result, NumberFormatException e) throws HyracksDataException {
- throw new InvalidDataFormatException(getIdentifier(), e, ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG);
- }
-
- protected void setDouble(IPointable result, double value) throws HyracksDataException {
- aDouble.setValue(value);
- DOUBLE_SERDE.serialize(aDouble, out);
- result.set(resultStorage);
+ protected void handleUparseableString(IPointable result) throws HyracksDataException {
+ throw new InvalidDataFormatException(getIdentifier(), ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG);
}
protected abstract FunctionIdentifier getIdentifier();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractInt64ConstructorEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractInt64ConstructorEvaluator.java
index 8cf9bed..2f9470d 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractInt64ConstructorEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/constructors/AbstractInt64ConstructorEvaluator.java
@@ -27,6 +27,7 @@
import org.apache.asterix.om.base.AMutableInt64;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.runtime.evaluators.common.NumberUtils;
import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
import org.apache.asterix.runtime.exceptions.TypeMismatchException;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
@@ -79,49 +80,13 @@
if (tt == ATypeTag.SERIALIZED_INT64_TYPE_TAG) {
result.set(inputArg);
} else if (tt == ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- int len = inputArg.getLength();
- utf8Ptr.set(bytes, startOffset + 1, len - 1);
- int offset = utf8Ptr.getCharStartOffset();
- //accumulating value in negative domain
- //otherwise Long.MIN_VALUE = -(Long.MAX_VALUE + 1) would have caused overflow
- long value = 0;
- boolean positive = true;
- long limit = -Long.MAX_VALUE;
- if (bytes[offset] == '+') {
- offset++;
- } else if (bytes[offset] == '-') {
- offset++;
- positive = false;
- limit = Long.MIN_VALUE;
- }
- int end = startOffset + len;
- for (; offset < end; offset++) {
- int digit;
- if (bytes[offset] >= '0' && bytes[offset] <= '9') {
- value *= 10;
- digit = bytes[offset] - '0';
- } else if (bytes[offset] == 'i' && bytes[offset + 1] == '6' && bytes[offset + 2] == '4'
- && offset + 3 == end) {
- break;
- } else {
- handleUnparseableString(result);
- return;
- }
- if (value < limit + digit) {
- handleUnparseableString(result);
- }
- value -= digit;
- }
- if (value > 0) {
+ utf8Ptr.set(bytes, startOffset + 1, inputArg.getLength() - 1);
+ if (NumberUtils.parseInt64(utf8Ptr, aInt64)) {
+ INT64_SERDE.serialize(aInt64, out);
+ result.set(resultStorage);
+ } else {
handleUnparseableString(result);
}
- if (value < 0 && positive) {
- value *= -1;
- }
-
- aInt64.setValue(value);
- INT64_SERDE.serialize(aInt64, out);
- result.set(resultStorage);
} else {
throw new TypeMismatchException(getIdentifier(), 0, tt, ATypeTag.SERIALIZED_STRING_TYPE_TAG);
}
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 11576aa..52d3bf6 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
@@ -30,6 +30,7 @@
import org.apache.asterix.dataflow.data.nontagged.serde.AInt64SerializerDeserializer;
import org.apache.asterix.dataflow.data.nontagged.serde.AInt8SerializerDeserializer;
import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.runtime.evaluators.common.NumberUtils;
import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
import org.apache.asterix.runtime.exceptions.UnsupportedTypeException;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
@@ -107,11 +108,11 @@
case DOUBLE: {
double d = ADoubleSerializerDeserializer.getDouble(serString, startOffset);
if (Double.isNaN(d)) {
- builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NAN);
+ builder.appendUtf8StringPointable(NumberUtils.NAN);
} else if (d == Double.POSITIVE_INFINITY) { // NOSONAR
- builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.POSITIVE_INF);
+ builder.appendUtf8StringPointable(NumberUtils.POSITIVE_INF);
} else if (d == Double.NEGATIVE_INFINITY) { // NOSONAR
- builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NEGATIVE_INF);
+ builder.appendUtf8StringPointable(NumberUtils.NEGATIVE_INF);
} else {
builder.appendString(String.valueOf(d));
}
@@ -120,11 +121,11 @@
case FLOAT: {
float f = AFloatSerializerDeserializer.getFloat(serString, startOffset);
if (Float.isNaN(f)) {
- builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NAN);
+ builder.appendUtf8StringPointable(NumberUtils.NAN);
} else if (f == Float.POSITIVE_INFINITY) { // NOSONAR
- builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.POSITIVE_INF);
+ builder.appendUtf8StringPointable(NumberUtils.POSITIVE_INF);
} else if (f == Float.NEGATIVE_INFINITY) { // NOSONAR
- builder.appendUtf8StringPointable(AbstractDoubleConstructorEvaluator.NEGATIVE_INF);
+ builder.appendUtf8StringPointable(NumberUtils.NEGATIVE_INF);
} else {
builder.appendString(String.valueOf(f));
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBigIntDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBigIntDescriptor.java
index 5cf9af7..2762d61 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBigIntDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBigIntDescriptor.java
@@ -22,13 +22,10 @@
import java.io.IOException;
import org.apache.asterix.dataflow.data.nontagged.serde.ABooleanSerializerDeserializer;
-import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.om.base.ANull;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.om.types.hierachy.ITypeConvertComputer;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
@@ -37,7 +34,6 @@
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.dataflow.value.ISerializerDeserializer;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.data.std.api.IPointable;
@@ -58,10 +54,6 @@
@Override
public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException {
return new AbstractInt64ConstructorEvaluator(args[0].createScalarEvaluator(ctx)) {
- @SuppressWarnings("unchecked")
- private final ISerializerDeserializer<ANull> nullSerde =
- SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ANULL);
-
@Override
protected void evaluateImpl(IPointable result) throws IOException {
byte[] bytes = inputArg.getByteArray();
@@ -94,7 +86,7 @@
case ARRAY:
case MULTISET:
case OBJECT:
- setNull(result);
+ PointableHelper.setNull(result);
break;
default:
@@ -104,13 +96,8 @@
}
@Override
- protected void handleUnparseableString(IPointable result) throws HyracksDataException {
- setNull(result);
- }
-
- private void setNull(IPointable result) throws HyracksDataException {
- nullSerde.serialize(ANull.NULL, out);
- result.set(resultStorage);
+ protected void handleUnparseableString(IPointable result) {
+ PointableHelper.setNull(result);
}
@Override
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBooleanDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBooleanDescriptor.java
index 704630e..fccd6d1 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBooleanDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToBooleanDescriptor.java
@@ -33,6 +33,7 @@
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.asterix.runtime.evaluators.common.NumberUtils;
import org.apache.asterix.runtime.evaluators.constructors.AbstractBooleanConstructorEvaluator;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
@@ -45,12 +46,6 @@
public class ToBooleanDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
- private static final long BITS_NAN = Double.doubleToLongBits(Double.NaN);
-
- private static final long BITS_ZERO_POS = Double.doubleToLongBits(+0.0d);
-
- private static final long BITS_ZERO_NEG = Double.doubleToLongBits(-0.0d);
-
public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
@Override
public IFunctionDescriptor createFunctionDescriptor() {
@@ -117,7 +112,8 @@
private void setDouble(double v, IPointable result) throws HyracksDataException {
long bits = Double.doubleToLongBits(v);
- boolean zeroOrNaN = bits == BITS_ZERO_POS || bits == BITS_ZERO_NEG || bits == BITS_NAN;
+ boolean zeroOrNaN = bits == NumberUtils.POSITIVE_ZERO_BITS
+ || bits == NumberUtils.NEGATIVE_ZERO_BITS || bits == NumberUtils.NAN_BITS;
setBoolean(result, !zeroOrNaN);
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToDoubleDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToDoubleDescriptor.java
index 71cdbe5..4fa33de 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToDoubleDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToDoubleDescriptor.java
@@ -22,13 +22,10 @@
import java.io.IOException;
import org.apache.asterix.dataflow.data.nontagged.serde.ABooleanSerializerDeserializer;
-import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.om.base.ANull;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.om.types.hierachy.ITypeConvertComputer;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
@@ -37,7 +34,6 @@
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.dataflow.value.ISerializerDeserializer;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.data.std.api.IPointable;
@@ -58,10 +54,6 @@
@Override
public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException {
return new AbstractDoubleConstructorEvaluator(args[0].createScalarEvaluator(ctx)) {
- @SuppressWarnings("unchecked")
- private final ISerializerDeserializer<ANull> nullSerde =
- SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ANULL);
-
@Override
protected void evaluateImpl(IPointable result) throws IOException {
byte[] bytes = inputArg.getByteArray();
@@ -88,7 +80,7 @@
case ARRAY:
case MULTISET:
case OBJECT:
- setNull(result);
+ PointableHelper.setNull(result);
break;
default:
@@ -98,14 +90,8 @@
}
@Override
- protected void handleUparseableString(IPointable result, NumberFormatException e)
- throws HyracksDataException {
- setNull(result);
- }
-
- private void setNull(IPointable result) throws HyracksDataException {
- nullSerde.serialize(ANull.NULL, out);
- result.set(resultStorage);
+ protected void handleUparseableString(IPointable result) {
+ PointableHelper.setNull(result);
}
@Override
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToNumberDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToNumberDescriptor.java
new file mode 100644
index 0000000..d044744
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ToNumberDescriptor.java
@@ -0,0 +1,149 @@
+/*
+ * 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 java.io.DataOutput;
+
+import org.apache.asterix.dataflow.data.nontagged.serde.ABooleanSerializerDeserializer;
+import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
+import org.apache.asterix.om.base.ADouble;
+import org.apache.asterix.om.base.AInt64;
+import org.apache.asterix.om.base.AMutableDouble;
+import org.apache.asterix.om.base.AMutableInt64;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptor;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.evaluators.common.NumberUtils;
+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.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class ToNumberDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+ public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+ @Override
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new ToNumberDescriptor();
+ }
+ };
+
+ @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 {
+
+ final IScalarEvaluator inputEval = args[0].createScalarEvaluator(ctx);
+ final IPointable inputArg = new VoidPointable();
+ final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
+ final DataOutput out = resultStorage.getDataOutput();
+ final AMutableInt64 aInt64 = new AMutableInt64(0);
+ final AMutableDouble aDouble = new AMutableDouble(0);
+ final UTF8StringPointable utf8Ptr = new UTF8StringPointable();
+
+ @SuppressWarnings("unchecked")
+ final ISerializerDeserializer<AInt64> INT64_SERDE =
+ SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT64);
+
+ @SuppressWarnings("unchecked")
+ final ISerializerDeserializer<ADouble> DOUBLE_SERDE =
+ SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADOUBLE);
+
+ return new IScalarEvaluator() {
+ @Override
+ public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+ inputEval.evaluate(tuple, inputArg);
+
+ resultStorage.reset();
+
+ byte[] bytes = inputArg.getByteArray();
+ int startOffset = inputArg.getStartOffset();
+ ATypeTag tt = ATypeTag.VALUE_TYPE_MAPPING[bytes[startOffset]];
+ switch (tt) {
+ case TINYINT:
+ case SMALLINT:
+ case INTEGER:
+ case BIGINT:
+ case FLOAT:
+ case DOUBLE:
+ result.set(inputArg);
+ break;
+
+ case BOOLEAN:
+ boolean b = ABooleanSerializerDeserializer.getBoolean(bytes, startOffset + 1);
+ aInt64.setValue(b ? 1 : 0);
+ INT64_SERDE.serialize(aInt64, out);
+ result.set(resultStorage);
+ break;
+
+ case STRING:
+ utf8Ptr.set(bytes, startOffset + 1, inputArg.getLength() - 1);
+ if (NumberUtils.parseInt64(utf8Ptr, aInt64)) {
+ INT64_SERDE.serialize(aInt64, out);
+ result.set(resultStorage);
+ } else if (NumberUtils.parseDouble(utf8Ptr, aDouble)) {
+ DOUBLE_SERDE.serialize(aDouble, out);
+ result.set(resultStorage);
+ } else {
+ PointableHelper.setNull(result);
+ }
+ break;
+
+ case ARRAY:
+ case MULTISET:
+ case OBJECT:
+ PointableHelper.setNull(result);
+ break;
+
+ default:
+ throw new TypeMismatchException(getIdentifier(), 0, bytes[startOffset],
+ ATypeTag.SERIALIZED_INT8_TYPE_TAG, ATypeTag.SERIALIZED_INT16_TYPE_TAG,
+ ATypeTag.SERIALIZED_INT32_TYPE_TAG, ATypeTag.SERIALIZED_INT64_TYPE_TAG,
+ ATypeTag.SERIALIZED_FLOAT_TYPE_TAG, ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG,
+ ATypeTag.SERIALIZED_BOOLEAN_TYPE_TAG, ATypeTag.SERIALIZED_STRING_TYPE_TAG,
+ ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG,
+ ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG,
+ ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
+ }
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return BuiltinFunctions.TO_NUMBER;
+ }
+}
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 c47a4de..b94f55e 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
@@ -257,6 +257,7 @@
import org.apache.asterix.runtime.evaluators.functions.ToBigIntDescriptor;
import org.apache.asterix.runtime.evaluators.functions.ToBooleanDescriptor;
import org.apache.asterix.runtime.evaluators.functions.ToDoubleDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.ToNumberDescriptor;
import org.apache.asterix.runtime.evaluators.functions.ToStringDescriptor;
import org.apache.asterix.runtime.evaluators.functions.UUIDDescriptor;
import org.apache.asterix.runtime.evaluators.functions.WordTokensDescriptor;
@@ -728,6 +729,7 @@
fc.addGenerated(ToStringDescriptor.FACTORY);
fc.addGenerated(ToDoubleDescriptor.FACTORY);
fc.addGenerated(ToBigIntDescriptor.FACTORY);
+ fc.addGenerated(ToNumberDescriptor.FACTORY);
// Cast function
fc.addGenerated(CastTypeDescriptor.FACTORY);