Clean up numeric type conversion code - Add new conversion methods to ITypeConvertorComputer interface - Move remaining type conversion code from ATypeHierarchy to ITypeConvertorComputer implementations - Add type demotion parameter to chose whether it fails if input value is out of range for the target type ('strict' mode) or not ('lax' mode) - Clean up error messages
Change-Id: I68b78e2dc9ebf78799698a1c90bcd7cb5150137d Reviewed-on: https://asterix-gerrit.ics.uci.edu/1800 Sonar-Qube: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> BAD: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Yingyi Bu <buyin...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/ce062ba2 Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/ce062ba2 Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/ce062ba2 Branch: refs/heads/master Commit: ce062ba29edc39563a2ee87a4a1205056426a21c Parents: d26141d Author: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Authored: Fri Jun 2 17:34:21 2017 -0700 Committer: Till Westmann <ti...@apache.org> Committed: Sat Jun 3 11:17:33 2017 -0700 ---------------------------------------------------------------------- .../optimizer/rules/SimilarityCheckRule.java | 4 +- .../optimizer/rules/am/AccessMethodUtils.java | 9 +- .../rules/am/InvertedIndexAccessMethod.java | 6 +- .../asterix/common/exceptions/ErrorCode.java | 4 + .../main/resources/asx_errormsg/en.properties | 4 + .../external/library/ExternalFunction.java | 2 +- .../asterix/external/parser/ADMDataParser.java | 3 +- .../dataflow/data/common/SerializationUtil.java | 35 - .../AMurmurHash3BinaryHashFunctionFamily.java | 4 +- .../om/pointables/cast/ACastVisitor.java | 2 +- .../om/types/hierachy/ATypeHierarchy.java | 722 +++++-------------- .../AbstractIntegerTypeConvertComputer.java | 248 +++++-- .../DoubleToFloatTypeConvertComputer.java | 55 +- .../DoubleToInt16TypeConvertComputer.java | 63 +- .../DoubleToInt32TypeConvertComputer.java | 66 +- .../DoubleToInt64TypeConvertComputer.java | 71 +- .../DoubleToInt8TypeConvertComputer.java | 63 +- .../FloatToDoubleTypeConvertComputer.java | 22 +- .../FloatToInt16TypeConvertComputer.java | 63 +- .../FloatToInt32TypeConvertComputer.java | 66 +- .../FloatToInt64TypeConvertComputer.java | 66 +- .../FloatToInt8TypeConvertComputer.java | 62 +- .../om/types/hierachy/ITypeConvertComputer.java | 5 + .../IntegerToDoubleTypeConvertComputer.java | 84 ++- .../IntegerToFloatTypeConvertComputer.java | 80 +- .../IntegerToInt16TypeConvertComputer.java | 17 +- .../IntegerToInt32TypeConvertComputer.java | 18 +- .../IntegerToInt64TypeConvertComputer.java | 13 +- .../IntegerToInt8TypeConvertComputer.java | 16 +- 29 files changed, 1041 insertions(+), 832 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SimilarityCheckRule.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SimilarityCheckRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SimilarityCheckRule.java index 585bc71..1e445e5 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SimilarityCheckRule.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SimilarityCheckRule.java @@ -21,7 +21,6 @@ package org.apache.asterix.optimizer.rules; import java.util.ArrayList; import java.util.List; -import org.apache.asterix.common.exceptions.AsterixException; import org.apache.asterix.lang.common.util.FunctionUtil; import org.apache.asterix.om.base.ADouble; import org.apache.asterix.om.base.AFloat; @@ -50,6 +49,7 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogi import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator; import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator; import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule; +import org.apache.hyracks.api.exceptions.HyracksDataException; /** * Looks for a select operator, containing a condition: @@ -289,7 +289,7 @@ public class SimilarityCheckRule implements IAlgebraicRewriteRule { AInt32 aInt = new AInt32(0); try { aInt = (AInt32) ATypeHierarchy.convertNumericTypeObject(constVal.getObject(), ATypeTag.INTEGER); - } catch (AsterixException e) { + } catch (HyracksDataException e) { throw new AlgebricksException(e); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java index 59cb373..48367a7 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java @@ -80,6 +80,7 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOpe import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities; import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl; import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil; +import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.DelimitedUTF8StringBinaryTokenizer; /** @@ -419,8 +420,12 @@ public class AccessMethodUtils { // if the constant type and target type does not match, we do a type conversion if (constantValueTag != fieldType.getTypeTag() && constantValue != null) { - replacedConstantValue = ATypeHierarchy.getAsterixConstantValueFromNumericTypeObject( - constantValue.getObject(), fieldType.getTypeTag()); + try { + replacedConstantValue = ATypeHierarchy.getAsterixConstantValueFromNumericTypeObject( + constantValue.getObject(), fieldType.getTypeTag(), true); + } catch (HyracksDataException e) { + throw new AlgebricksException(e); + } if (replacedConstantValue != null) { typeCastingApplied = true; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java index 0752979..341bda3 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java @@ -27,7 +27,6 @@ import java.util.Map; import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation; import org.apache.asterix.common.config.DatasetConfig.IndexType; -import org.apache.asterix.common.exceptions.AsterixException; import org.apache.asterix.common.exceptions.CompilationException; import org.apache.asterix.common.exceptions.ErrorCode; import org.apache.asterix.dataflow.data.common.ExpressionTypeComputer; @@ -82,6 +81,7 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperat import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.LogicalOperatorDeepCopyWithNewVariablesVisitor; import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities; import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil; +import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.storage.am.lsm.invertedindex.api.IInvertedIndexSearchModifierFactory; import org.apache.hyracks.storage.am.lsm.invertedindex.search.ConjunctiveEditDistanceSearchModifierFactory; import org.apache.hyracks.storage.am.lsm.invertedindex.search.ConjunctiveListEditDistanceSearchModifierFactory; @@ -989,7 +989,7 @@ public class InvertedIndexAccessMethod implements IAccessMethod { // Apply type casting based on numeric types of the input to INTEGER type. try { edThresh = (AInt32) ATypeHierarchy.convertNumericTypeObject(intObj, ATypeTag.INTEGER); - } catch (AsterixException e) { + } catch (HyracksDataException e) { throw new AlgebricksException(e); } int mergeThreshold = 0; @@ -1243,7 +1243,7 @@ public class InvertedIndexAccessMethod implements IAccessMethod { try { edThresh = ((AInt32) ATypeHierarchy.convertNumericTypeObject(simThresh, ATypeTag.INTEGER)) .getIntegerValue(); - } catch (AsterixException e) { + } catch (HyracksDataException e) { throw new AlgebricksException(e); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java ---------------------------------------------------------------------- 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 eb73e5e..df647d5 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 @@ -58,6 +58,10 @@ public class ErrorCode { public static final int ROOT_LOCAL_RESOURCE_EXISTS = 15; public static final int ROOT_LOCAL_RESOURCE_COULD_NOT_BE_CREATED = 16; public static final int UNKNOWN_EXTERNAL_FILE_PENDING_OP = 17; + public static final int TYPE_CONVERT = 18; + public static final int TYPE_CONVERT_INTEGER_SOURCE = 19; + public static final int TYPE_CONVERT_INTEGER_TARGET = 20; + public static final int TYPE_CONVERT_OUT_OF_BOUND = 21; public static final int INSTANTIATION_ERROR = 100; // Compilation errors http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties ---------------------------------------------------------------------- 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 026f71a..7204e34 100644 --- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties +++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties @@ -51,6 +51,10 @@ 15 = Storage metadata directory of %1$s in %2$s already exists 16 = Storage metadata directory of %1$s in %2$s couldn't be created 17 = Unknown external file pending operation %1$s +18 = Cannot convert the %1$s type to the %2$s type. +19 = Can't convert integer types. The source type should be one of %1$s. +20 = Can't convert integer types. The target type should be one of %1$s. +21 = Source value %1$s is out of range that %2$s can hold - %2$s.MAX_VALUE: %3$s, %2$s.MIN_VALUE: %4$s 100 = Unable to instantiate class %1$s # Compile-time check errors http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalFunction.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalFunction.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalFunction.java index 493a0bf..c644413 100755 --- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalFunction.java +++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalFunction.java @@ -102,7 +102,7 @@ public abstract class ExternalFunction implements IExternalFunction { if (sourceTypeTag != targetTypeTag) { castBuffer.reset(); ATypeHierarchy.convertNumericTypeByteArray(inputVal.getByteArray(), inputVal.getStartOffset(), - inputVal.getLength(), targetTypeTag, castBuffer.getDataOutput()); + inputVal.getLength(), targetTypeTag, castBuffer.getDataOutput(), true); functionHelper.setArgument(i, castBuffer); } else { functionHelper.setArgument(i, inputVal); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ADMDataParser.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ADMDataParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ADMDataParser.java index 18bf52c..44766ff 100644 --- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ADMDataParser.java +++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/ADMDataParser.java @@ -850,7 +850,8 @@ public class ADMDataParser extends AbstractDataParser implements IStreamDataPars castBuffer.getLength() - 1, out); } else if (ATypeHierarchy.canDemote(typeTag, targetTypeTag)) { // can demote source type to the target type - ITypeConvertComputer demoteComputer = ATypeHierarchy.getTypeDemoteComputer(typeTag, targetTypeTag); + ITypeConvertComputer demoteComputer = + ATypeHierarchy.getTypeDemoteComputer(typeTag, targetTypeTag, true); if (demoteComputer == null) { throw new ParseException(ErrorCode.PARSER_ADM_DATA_PARSER_CAST_ERROR, typeTag, targetTypeTag); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/SerializationUtil.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/SerializationUtil.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/SerializationUtil.java deleted file mode 100644 index 7482b47..0000000 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/SerializationUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.dataflow.data.common; - -public final class SerializationUtil { - - public static void writeIntToByteArray(byte[] array, int value, int offset) { - array[offset] = (byte) (0xff & (value >> 24)); - array[offset + 1] = (byte) (0xff & (value >> 16)); - array[offset + 2] = (byte) (0xff & (value >> 8)); - array[offset + 3] = (byte) (0xff & value); - } - - public static void writeShortToByteArray(byte[] array, short value, int offset) { - array[offset] = (byte) (0xff & (value >> 8)); - array[offset + 1] = (byte) (0xff & value); - } - -} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/hash/AMurmurHash3BinaryHashFunctionFamily.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/hash/AMurmurHash3BinaryHashFunctionFamily.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/hash/AMurmurHash3BinaryHashFunctionFamily.java index 5a43d21..5f5ff76 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/hash/AMurmurHash3BinaryHashFunctionFamily.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/hash/AMurmurHash3BinaryHashFunctionFamily.java @@ -66,7 +66,7 @@ public class AMurmurHash3BinaryHashFunctionFamily implements IBinaryHashFunction case INTEGER: case BIGINT: try { - IntegerToDoubleTypeConvertComputer.INSTANCE.convertType(bytes, offset + 1, length - 1, + IntegerToDoubleTypeConvertComputer.getInstance().convertType(bytes, offset + 1, length - 1, fieldValueBufferOutput); } catch (IOException e) { throw new HyracksDataException( @@ -78,7 +78,7 @@ public class AMurmurHash3BinaryHashFunctionFamily implements IBinaryHashFunction case FLOAT: try { - FloatToDoubleTypeConvertComputer.INSTANCE.convertType(bytes, offset + 1, length - 1, + FloatToDoubleTypeConvertComputer.getInstance().convertType(bytes, offset + 1, length - 1, fieldValueBufferOutput); } catch (IOException e) { throw new HyracksDataException( http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java index 5f0b0a9..b161365 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java @@ -110,7 +110,7 @@ public class ACastVisitor implements IVisitablePointableVisitor<Void, Triple<IVi try { castBuffer.reset(); ATypeHierarchy.convertNumericTypeByteArray(accessor.getByteArray(), accessor.getStartOffset(), - accessor.getLength(), reqTypeTag, castBuffer.getDataOutput()); + accessor.getLength(), reqTypeTag, castBuffer.getDataOutput(), true); arg.first.set(castBuffer); } catch (IOException e1) { throw new HyracksDataException( http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/ATypeHierarchy.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/ATypeHierarchy.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/ATypeHierarchy.java index f899bbf..2a47337 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/ATypeHierarchy.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/ATypeHierarchy.java @@ -20,38 +20,32 @@ package org.apache.asterix.om.types.hierachy; import java.io.DataOutput; import java.io.IOException; +import java.util.Arrays; import java.util.BitSet; +import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -import org.apache.asterix.common.exceptions.AsterixException; import org.apache.asterix.common.exceptions.ErrorCode; import org.apache.asterix.common.exceptions.RuntimeDataException; -import org.apache.asterix.om.base.ADouble; -import org.apache.asterix.om.base.AFloat; -import org.apache.asterix.om.base.AInt16; -import org.apache.asterix.om.base.AInt32; -import org.apache.asterix.om.base.AInt64; -import org.apache.asterix.om.base.AInt8; import org.apache.asterix.om.base.IAObject; import org.apache.asterix.om.constants.AsterixConstantValue; import org.apache.asterix.om.types.ATypeTag; import org.apache.asterix.om.types.EnumDeserializer; -import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.commons.lang3.tuple.Pair; import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.data.std.primitive.DoublePointable; -import org.apache.hyracks.data.std.primitive.FloatPointable; import org.apache.hyracks.data.std.primitive.IntegerPointable; import org.apache.hyracks.data.std.primitive.LongPointable; -import org.apache.hyracks.data.std.primitive.ShortPointable; public class ATypeHierarchy { - private static BitSet typePromotionHierachyMap = new BitSet(ATypeTag.TYPE_COUNT * ATypeTag.TYPE_COUNT); - private static BitSet typeDemotionHierachyMap = new BitSet(ATypeTag.TYPE_COUNT * ATypeTag.TYPE_COUNT); - private static HashMap<Integer, ITypeConvertComputer> promoteComputerMap = new HashMap<Integer, ITypeConvertComputer>(); - private static HashMap<Integer, ITypeConvertComputer> demoteComputerMap = new HashMap<Integer, ITypeConvertComputer>(); - private static Map<ATypeTag, Domain> hierarchyDomains = new HashMap<ATypeTag, Domain>(); + private static final BitSet typePromotionHierachyMap = new BitSet(ATypeTag.TYPE_COUNT * ATypeTag.TYPE_COUNT); + private static final BitSet typeDemotionHierachyMap = new BitSet(ATypeTag.TYPE_COUNT * ATypeTag.TYPE_COUNT); + private static final Map<Integer, ITypeConvertComputer> promoteComputerMap = new HashMap<>(); + private static final Map<Integer, Pair<ITypeConvertComputer, ITypeConvertComputer>> demoteComputerMap = + new HashMap<>(); + private static Map<ATypeTag, Domain> hierarchyDomains = new EnumMap<>(ATypeTag.class); // allow type promotion or demotion to the type itself static { @@ -65,42 +59,58 @@ public class ATypeHierarchy { static { // Promotion (widening): TINYINT -> SMALLINT -> INTEGER -> BIGINT -> FLOAT -> DOUBLE // No precision and range loss - addPromotionRule(ATypeTag.TINYINT, ATypeTag.SMALLINT, IntegerToInt16TypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.TINYINT, ATypeTag.INTEGER, IntegerToInt32TypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.TINYINT, ATypeTag.BIGINT, IntegerToInt64TypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.SMALLINT, ATypeTag.INTEGER, IntegerToInt32TypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.SMALLINT, ATypeTag.BIGINT, IntegerToInt64TypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.INTEGER, ATypeTag.BIGINT, IntegerToInt64TypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.TINYINT, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.SMALLINT, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.INTEGER, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.BIGINT, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.FLOAT, ATypeTag.DOUBLE, FloatToDoubleTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.TINYINT, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.SMALLINT, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.INTEGER, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.INSTANCE); - addPromotionRule(ATypeTag.BIGINT, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.INSTANCE); + addPromotionRule(ATypeTag.TINYINT, ATypeTag.SMALLINT, IntegerToInt16TypeConvertComputer.getInstance(true)); + addPromotionRule(ATypeTag.TINYINT, ATypeTag.INTEGER, IntegerToInt32TypeConvertComputer.getInstance(true)); + addPromotionRule(ATypeTag.TINYINT, ATypeTag.BIGINT, IntegerToInt64TypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.SMALLINT, ATypeTag.INTEGER, IntegerToInt32TypeConvertComputer.getInstance(true)); + addPromotionRule(ATypeTag.SMALLINT, ATypeTag.BIGINT, IntegerToInt64TypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.INTEGER, ATypeTag.BIGINT, IntegerToInt64TypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.TINYINT, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.SMALLINT, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.INTEGER, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.BIGINT, ATypeTag.DOUBLE, IntegerToDoubleTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.FLOAT, ATypeTag.DOUBLE, FloatToDoubleTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.TINYINT, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.SMALLINT, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.INTEGER, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.getInstance()); + addPromotionRule(ATypeTag.BIGINT, ATypeTag.FLOAT, IntegerToFloatTypeConvertComputer.getInstance()); } static { // Demotion (narrowing): DOUBLE -> FLOAT -> BIGINT -> INTEGER -> SMALLINT -> TINYINT // Possible precision loss (e.g., FLOAT to INT) - // This may produce an exception (if source value is greater than target.MAX or less than target.MIN) - addDemotionRule(ATypeTag.SMALLINT, ATypeTag.TINYINT, IntegerToInt8TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.INTEGER, ATypeTag.TINYINT, IntegerToInt8TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.BIGINT, ATypeTag.TINYINT, IntegerToInt8TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.INTEGER, ATypeTag.SMALLINT, IntegerToInt16TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.BIGINT, ATypeTag.SMALLINT, IntegerToInt16TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.BIGINT, ATypeTag.INTEGER, IntegerToInt32TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.FLOAT, ATypeTag.TINYINT, FloatToInt8TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.FLOAT, ATypeTag.SMALLINT, FloatToInt16TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.FLOAT, ATypeTag.INTEGER, FloatToInt32TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.FLOAT, ATypeTag.BIGINT, FloatToInt64TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.DOUBLE, ATypeTag.TINYINT, DoubleToInt8TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.DOUBLE, ATypeTag.SMALLINT, DoubleToInt16TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.DOUBLE, ATypeTag.INTEGER, DoubleToInt32TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.DOUBLE, ATypeTag.BIGINT, DoubleToInt64TypeConvertComputer.INSTANCE); - addDemotionRule(ATypeTag.DOUBLE, ATypeTag.FLOAT, DoubleToFloatTypeConvertComputer.INSTANCE); + // 'strict' mode produces an exception if source value is greater than target.MAX or less than target.MIN + // 'lax' mode does not fail. it returns target.MAX/target.MIN if source value is out of range + addDemotionRule(ATypeTag.SMALLINT, ATypeTag.TINYINT, IntegerToInt8TypeConvertComputer.getInstance(true), + IntegerToInt8TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.INTEGER, ATypeTag.TINYINT, IntegerToInt8TypeConvertComputer.getInstance(true), + IntegerToInt8TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.BIGINT, ATypeTag.TINYINT, IntegerToInt8TypeConvertComputer.getInstance(true), + IntegerToInt8TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.INTEGER, ATypeTag.SMALLINT, IntegerToInt16TypeConvertComputer.getInstance(true), + IntegerToInt16TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.BIGINT, ATypeTag.SMALLINT, IntegerToInt16TypeConvertComputer.getInstance(true), + IntegerToInt16TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.BIGINT, ATypeTag.INTEGER, IntegerToInt32TypeConvertComputer.getInstance(true), + IntegerToInt32TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.FLOAT, ATypeTag.TINYINT, FloatToInt8TypeConvertComputer.getInstance(true), + FloatToInt8TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.FLOAT, ATypeTag.SMALLINT, FloatToInt16TypeConvertComputer.getInstance(true), + FloatToInt16TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.FLOAT, ATypeTag.INTEGER, FloatToInt32TypeConvertComputer.getInstance(true), + FloatToInt32TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.FLOAT, ATypeTag.BIGINT, FloatToInt64TypeConvertComputer.getInstance(true), + FloatToInt64TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.DOUBLE, ATypeTag.TINYINT, DoubleToInt8TypeConvertComputer.getInstance(true), + DoubleToInt8TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.DOUBLE, ATypeTag.SMALLINT, DoubleToInt16TypeConvertComputer.getInstance(true), + DoubleToInt16TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.DOUBLE, ATypeTag.INTEGER, DoubleToInt32TypeConvertComputer.getInstance(true), + DoubleToInt32TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.DOUBLE, ATypeTag.BIGINT, DoubleToInt64TypeConvertComputer.getInstance(true), + DoubleToInt64TypeConvertComputer.getInstance(false)); + addDemotionRule(ATypeTag.DOUBLE, ATypeTag.FLOAT, DoubleToFloatTypeConvertComputer.getInstance(true), + DoubleToFloatTypeConvertComputer.getInstance(false)); } static { @@ -135,16 +145,17 @@ public class ATypeHierarchy { return tagHierarchy1.equals(tagHierarchy2) && !useListDomain; } - public static void addPromotionRule(ATypeTag type1, ATypeTag type2, ITypeConvertComputer promoteComputer) { + private static void addPromotionRule(ATypeTag type1, ATypeTag type2, ITypeConvertComputer promoteComputer) { int index = type1.ordinal() * ATypeTag.TYPE_COUNT + type2.ordinal(); typePromotionHierachyMap.set(index); promoteComputerMap.put(index, promoteComputer); } - public static void addDemotionRule(ATypeTag type1, ATypeTag type2, ITypeConvertComputer demoteComputer) { + private static void addDemotionRule(ATypeTag type1, ATypeTag type2, ITypeConvertComputer demoteStrictComputer, + ITypeConvertComputer demoteLenientComputer) { int index = type1.ordinal() * ATypeTag.TYPE_COUNT + type2.ordinal(); typeDemotionHierachyMap.set(index); - demoteComputerMap.put(index, demoteComputer); + demoteComputerMap.put(index, Pair.of(demoteStrictComputer, demoteLenientComputer)); } public static ITypeConvertComputer getTypePromoteComputer(ATypeTag type1, ATypeTag type2) { @@ -154,9 +165,11 @@ public class ATypeHierarchy { return null; } - public static ITypeConvertComputer getTypeDemoteComputer(ATypeTag type1, ATypeTag type2) { + public static ITypeConvertComputer getTypeDemoteComputer(ATypeTag type1, ATypeTag type2, boolean strict) { if (canDemote(type1, type2)) { - return demoteComputerMap.get(type1.ordinal() * ATypeTag.TYPE_COUNT + type2.ordinal()); + Pair<ITypeConvertComputer, ITypeConvertComputer> pair = + demoteComputerMap.get(type1.ordinal() * ATypeTag.TYPE_COUNT + type2.ordinal()); + return strict ? pair.getLeft() : pair.getRight(); } return null; } @@ -179,559 +192,169 @@ public class ATypeHierarchy { // Get an AsterixConstantValue from a source Object public static AsterixConstantValue getAsterixConstantValueFromNumericTypeObject(IAObject sourceObject, - ATypeTag targetTypeTag) throws AlgebricksException { - ATypeTag sourceTypeTag = sourceObject.getType().getTypeTag(); - AsterixConstantValue asterixNewConstantValue = null; - short tmpShortValue; - int tmpIntValue; - long tmpLongValue; - float tmpFloatValue; - double tmpDoubleValue; - - // if the constant type and target type does not match, we do a type conversion - if (sourceTypeTag != targetTypeTag) { - - switch (targetTypeTag) { - //Target Field Type:BIGINT - case BIGINT: - - // Change the Constant Type to BIGINT Type - switch (sourceTypeTag) { - case TINYINT: - asterixNewConstantValue = new AsterixConstantValue( - new AInt64((long) ((AInt8) sourceObject).getByteValue())); - break; - - case SMALLINT: - asterixNewConstantValue = new AsterixConstantValue( - new AInt64((long) ((AInt16) sourceObject).getShortValue())); - break; - - case INTEGER: - asterixNewConstantValue = new AsterixConstantValue( - new AInt64((long) ((AInt32) sourceObject).getIntegerValue())); - break; - - case FLOAT: - tmpFloatValue = ((AFloat) sourceObject).getFloatValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.FLOAT, ATypeTag.BIGINT, tmpFloatValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt64((long) tmpFloatValue)); - break; - - case DOUBLE: - tmpDoubleValue = ((ADouble) sourceObject).getDoubleValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.DOUBLE, ATypeTag.BIGINT, tmpDoubleValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt64((long) tmpDoubleValue)); - break; - - default: - break; - } - - break; - - //Target Field Type:INTEGER - case INTEGER: - - // Change the Constant Type to INTEGER Type - switch (sourceTypeTag) { - case TINYINT: - asterixNewConstantValue = new AsterixConstantValue( - new AInt32(((AInt8) sourceObject).getByteValue())); - break; - - case SMALLINT: - asterixNewConstantValue = new AsterixConstantValue( - new AInt32(((AInt16) sourceObject).getShortValue())); - break; - - case BIGINT: - tmpLongValue = ((AInt64) sourceObject).getLongValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.BIGINT, ATypeTag.INTEGER, tmpLongValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt32((int) tmpLongValue)); - break; - - case FLOAT: - tmpFloatValue = ((AFloat) sourceObject).getFloatValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.FLOAT, ATypeTag.INTEGER, tmpFloatValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt32((int) tmpFloatValue)); - break; - - case DOUBLE: - tmpDoubleValue = ((ADouble) sourceObject).getDoubleValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.FLOAT, ATypeTag.INTEGER, tmpDoubleValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt32((int) tmpDoubleValue)); - break; - - default: - break; - } - - break; - - //Target Field Type:TINYINT - case TINYINT: - - // Change the Constant Type to TINYINT Type - switch (sourceTypeTag) { - case SMALLINT: - tmpShortValue = ((AInt16) sourceObject).getShortValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.SMALLINT, ATypeTag.TINYINT, tmpShortValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt8((byte) tmpShortValue)); - break; - - case INTEGER: - tmpIntValue = ((AInt32) sourceObject).getIntegerValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.INTEGER, ATypeTag.TINYINT, tmpIntValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt8((byte) tmpIntValue)); - break; - - case BIGINT: - tmpLongValue = ((AInt64) sourceObject).getLongValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.BIGINT, ATypeTag.TINYINT, tmpLongValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt8((byte) tmpLongValue)); - break; - - case FLOAT: - tmpFloatValue = ((AFloat) sourceObject).getFloatValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.FLOAT, ATypeTag.TINYINT, tmpFloatValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt8((byte) tmpFloatValue)); - break; - - case DOUBLE: - tmpDoubleValue = ((ADouble) sourceObject).getDoubleValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.DOUBLE, ATypeTag.TINYINT, tmpDoubleValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt8((byte) tmpDoubleValue)); - break; - - default: - break; - } - break; - - //Target Field Type:SMALLINT - case SMALLINT: - // Change the Constant Type to SMALLINT Type - switch (sourceTypeTag) { - case TINYINT: - asterixNewConstantValue = new AsterixConstantValue( - new AInt16(((AInt8) sourceObject).getByteValue())); - break; - - case INTEGER: - tmpIntValue = ((AInt32) sourceObject).getIntegerValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.INTEGER, ATypeTag.SMALLINT, tmpIntValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt16((short) tmpIntValue)); - break; - - case BIGINT: - tmpLongValue = ((AInt64) sourceObject).getLongValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.BIGINT, ATypeTag.SMALLINT, tmpLongValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt16((short) tmpLongValue)); - break; - - case FLOAT: - tmpFloatValue = ((AFloat) sourceObject).getFloatValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.FLOAT, ATypeTag.SMALLINT, tmpFloatValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt16((short) tmpFloatValue)); - break; - - case DOUBLE: - tmpDoubleValue = ((ADouble) sourceObject).getDoubleValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.DOUBLE, ATypeTag.SMALLINT, tmpDoubleValue); - asterixNewConstantValue = new AsterixConstantValue(new AInt16((short) tmpDoubleValue)); - break; - - default: - break; - } - break; - - //Target Field Type:FLOAT - case FLOAT: - // Change the Constant Type to FLOAT Type - switch (sourceTypeTag) { - case TINYINT: - asterixNewConstantValue = new AsterixConstantValue( - new AFloat(((AInt8) sourceObject).getByteValue())); - break; - - case SMALLINT: - asterixNewConstantValue = new AsterixConstantValue( - new AFloat(((AInt16) sourceObject).getShortValue())); - break; - - case INTEGER: - asterixNewConstantValue = new AsterixConstantValue( - new AFloat(((AInt32) sourceObject).getIntegerValue())); - break; - - case BIGINT: - asterixNewConstantValue = new AsterixConstantValue( - new AFloat(((AInt64) sourceObject).getLongValue())); - break; - - case DOUBLE: - tmpDoubleValue = ((ADouble) sourceObject).getDoubleValue(); - // Check whether this value is within the range of the field type - valueSanitycheck(ATypeTag.DOUBLE, ATypeTag.FLOAT, tmpDoubleValue); - asterixNewConstantValue = new AsterixConstantValue(new AFloat((float) tmpDoubleValue)); - break; - - default: - break; - } - break; - - //Target Field Type:DOUBLE - case DOUBLE: - // Change the Constant Type to DOUBLE Type - switch (sourceTypeTag) { - case TINYINT: - asterixNewConstantValue = new AsterixConstantValue( - new ADouble(((AInt8) sourceObject).getByteValue())); - break; - - case SMALLINT: - asterixNewConstantValue = new AsterixConstantValue( - new ADouble(((AInt16) sourceObject).getShortValue())); - break; - - case INTEGER: - asterixNewConstantValue = new AsterixConstantValue( - new ADouble(((AInt32) sourceObject).getIntegerValue())); - break; - - case BIGINT: - asterixNewConstantValue = new AsterixConstantValue( - new ADouble(((AInt64) sourceObject).getLongValue())); - break; - - case FLOAT: - asterixNewConstantValue = new AsterixConstantValue( - new ADouble(((AFloat) sourceObject).getFloatValue())); - break; - - default: - break; - } - break; - - default: - break; - } - - return asterixNewConstantValue; - - } else { + ATypeTag targetTypeTag) throws HyracksDataException { + return getAsterixConstantValueFromNumericTypeObject(sourceObject, targetTypeTag, false); + } + // Get an AsterixConstantValue from a source Object + public static AsterixConstantValue getAsterixConstantValueFromNumericTypeObject(IAObject sourceObject, + ATypeTag targetTypeTag, boolean strictDemote) throws HyracksDataException { + ATypeTag sourceTypeTag = sourceObject.getType().getTypeTag(); + if (sourceTypeTag == targetTypeTag) { return new AsterixConstantValue(sourceObject); } - } - - // checks whether the source value is within the range of the target type - private static void valueSanitycheck(ATypeTag sourceType, ATypeTag targetType, double sourceValue) - throws AlgebricksException { - boolean canConvert = true; - - switch (targetType) { - case TINYINT: - if (sourceValue > Byte.MAX_VALUE || sourceValue < Byte.MIN_VALUE) { - canConvert = false; - } - break; - - case SMALLINT: - if (sourceValue > Short.MAX_VALUE || sourceValue < Short.MIN_VALUE) { - canConvert = false; - } - break; - case INTEGER: - if (sourceValue > Integer.MAX_VALUE || sourceValue < Integer.MIN_VALUE) { - canConvert = false; - } - break; - case BIGINT: - if (sourceValue > Long.MAX_VALUE || sourceValue < Long.MIN_VALUE) { - canConvert = false; - } - break; - case FLOAT: - if (sourceValue > Float.MAX_VALUE || sourceValue < Float.MIN_VALUE) { - canConvert = false; - } - break; - default: - break; + // if the constant type and target type does not match, we do a type conversion + ITypeConvertComputer convertComputer = null; + if (canPromote(sourceTypeTag, targetTypeTag)) { + convertComputer = ATypeHierarchy.getTypePromoteComputer(sourceTypeTag, targetTypeTag); + } else if (canDemote(sourceTypeTag, targetTypeTag)) { + convertComputer = ATypeHierarchy.getTypeDemoteComputer(sourceTypeTag, targetTypeTag, strictDemote); } - - if (!canConvert) { - throw new AlgebricksException("Can't cast a value: " + sourceValue + " from " + sourceType + " type to " - + targetType + " type because of the out-of-range error."); + if (convertComputer == null) { + return null; } + + IAObject targetObject = convertComputer.convertType(sourceObject); + return new AsterixConstantValue(targetObject); } // Type Casting from source Object to an Object with Target type public static IAObject convertNumericTypeObject(IAObject sourceObject, ATypeTag targetTypeTag) - throws AsterixException { - ATypeTag sourceTypeTag = sourceObject.getType().getTypeTag(); - - switch (sourceTypeTag) { - case TINYINT: - switch (targetTypeTag) { - case TINYINT: - return sourceObject; - case SMALLINT: - return new AInt16(((AInt8) sourceObject).getByteValue()); - case INTEGER: - return new AInt32(((AInt8) sourceObject).getByteValue()); - case BIGINT: - return new AInt64((long) ((AInt8) sourceObject).getByteValue()); - case FLOAT: - return new AFloat(((AInt8) sourceObject).getByteValue()); - case DOUBLE: - return new ADouble(((AInt8) sourceObject).getByteValue()); - default: - throw new AsterixException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); - } - case SMALLINT: - switch (targetTypeTag) { - case TINYINT: - // an exception can happen because of a type demotion from SMALLINT to TINYINT - return new AInt8((byte) ((AInt16) sourceObject).getShortValue()); - case SMALLINT: - return sourceObject; - case INTEGER: - return new AInt32(((AInt16) sourceObject).getShortValue()); - case BIGINT: - return new AInt64((long) ((AInt16) sourceObject).getShortValue()); - case FLOAT: - return new AFloat(((AInt16) sourceObject).getShortValue()); - case DOUBLE: - return new ADouble(((AInt16) sourceObject).getShortValue()); - default: - throw new AsterixException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); - } - - case INTEGER: - switch (targetTypeTag) { - case TINYINT: - // an exception can happen because of a type demotion from INTEGER to TINYINT - return new AInt8((byte) ((AInt32) sourceObject).getIntegerValue()); - case SMALLINT: - // an exception can happen because of a type demotion from INTEGER to SMALLINT - return new AInt16((short) ((AInt32) sourceObject).getIntegerValue()); - case INTEGER: - return sourceObject; - case BIGINT: - return new AInt64((long) ((AInt32) sourceObject).getIntegerValue()); - case FLOAT: - return new AFloat(((AInt32) sourceObject).getIntegerValue()); - case DOUBLE: - return new ADouble(((AInt32) sourceObject).getIntegerValue()); - default: - throw new AsterixException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); - } + throws HyracksDataException { + return convertNumericTypeObject(sourceObject, targetTypeTag, false); + } - case BIGINT: - switch (targetTypeTag) { - case TINYINT: - // an exception can happen because of a type demotion from BIGINT to TINYINT - return new AInt8((byte) ((AInt64) sourceObject).getLongValue()); - case SMALLINT: - // an exception can happen because of a type demotion from BIGINT to SMALLINT - return new AInt16((short) ((AInt64) sourceObject).getLongValue()); - case INTEGER: - // an exception can happen because of a type demotion from BIGINT to INTEGER - return new AInt32((int) ((AInt64) sourceObject).getLongValue()); - case BIGINT: - return sourceObject; - case FLOAT: - return new AFloat(((AInt64) sourceObject).getLongValue()); - case DOUBLE: - return new ADouble(((AInt64) sourceObject).getLongValue()); - default: - throw new AsterixException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); - } - case FLOAT: - switch (targetTypeTag) { - case TINYINT: - // an exception can happen because of a type demotion from FLOAT to TINYINT - return new AInt8((byte) ((AFloat) sourceObject).getFloatValue()); - case SMALLINT: - // an exception can happen because of a type demotion from FLOAT to SMALLINT - return new AInt16((short) ((AFloat) sourceObject).getFloatValue()); - case INTEGER: - // an exception can happen because of a type demotion from FLOAT to INTEGER - return new AInt32((int) ((AFloat) sourceObject).getFloatValue()); - case BIGINT: - // an exception can happen because of a type demotion from FLOAT to BIGINT - return new AInt64((long) ((AFloat) sourceObject).getFloatValue()); - case FLOAT: - return sourceObject; - case DOUBLE: - return new ADouble(((AFloat) sourceObject).getFloatValue()); - default: - throw new AsterixException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); - } - case DOUBLE: - switch (targetTypeTag) { - case TINYINT: - // an exception can happen because of a type demotion from DOUBLE to TINYINT - return new AInt8((byte) ((ADouble) sourceObject).getDoubleValue()); - case SMALLINT: - // an exception can happen because of a type demotion from DOUBLE to SMALLINT - return new AInt16((short) ((ADouble) sourceObject).getDoubleValue()); - case INTEGER: - // an exception can happen because of a type demotion from DOUBLE to INTEGER - return new AInt32((int) ((ADouble) sourceObject).getDoubleValue()); - case BIGINT: - // an exception can happen because of a type demotion from DOUBLE to BIGINT - return new AInt64((long) ((ADouble) sourceObject).getDoubleValue()); - case FLOAT: - // an exception can happen because of a type demotion from DOUBLE to FLOAT - return new AFloat((float) ((ADouble) sourceObject).getDoubleValue()); - case DOUBLE: - return sourceObject; - default: - throw new AsterixException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); - } - default: - throw new AsterixException("Source type is not a numeric type."); + // Type Casting from source Object to an Object with Target type + public static IAObject convertNumericTypeObject(IAObject sourceObject, ATypeTag targetTypeTag, boolean strictDemote) + throws HyracksDataException { + ATypeTag sourceTypeTag = sourceObject.getType().getTypeTag(); + if (sourceTypeTag == targetTypeTag) { + return sourceObject; + } + ITypeConvertComputer convertComputer = null; + if (canPromote(sourceTypeTag, targetTypeTag)) { + convertComputer = ATypeHierarchy.getTypePromoteComputer(sourceTypeTag, targetTypeTag); + } else if (canDemote(sourceTypeTag, targetTypeTag)) { + convertComputer = ATypeHierarchy.getTypeDemoteComputer(sourceTypeTag, targetTypeTag, strictDemote); + } + if (convertComputer == null) { + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT, sourceTypeTag, targetTypeTag); } + return convertComputer.convertType(sourceObject); } // convert a numeric value in a byte array to the target type value public static void convertNumericTypeByteArray(byte[] sourceByteArray, int s1, int l1, ATypeTag targetTypeTag, DataOutput out) throws IOException { + convertNumericTypeByteArray(sourceByteArray, s1, l1, targetTypeTag, out, false); + } + + // convert a numeric value in a byte array to the target type value + public static void convertNumericTypeByteArray(byte[] sourceByteArray, int s1, int l1, ATypeTag targetTypeTag, + DataOutput out, boolean strictDemote) throws IOException { ATypeTag sourceTypeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(sourceByteArray[s1]); if (sourceTypeTag != targetTypeTag) { // source tag can be promoted to target tag (e.g. tag1: SMALLINT, tag2: INTEGER) - if (ATypeHierarchy.canPromote(sourceTypeTag, targetTypeTag)) { + if (canPromote(sourceTypeTag, targetTypeTag)) { ITypeConvertComputer convertComputer = ATypeHierarchy.getTypePromoteComputer(sourceTypeTag, targetTypeTag); convertComputer.convertType(sourceByteArray, s1 + 1, l1 - 1, out); // source tag can be demoted to target tag - } else if (ATypeHierarchy.canDemote(sourceTypeTag, targetTypeTag)) { + } else if (canDemote(sourceTypeTag, targetTypeTag)) { ITypeConvertComputer convertComputer = - ATypeHierarchy.getTypeDemoteComputer(sourceTypeTag, targetTypeTag); + ATypeHierarchy.getTypeDemoteComputer(sourceTypeTag, targetTypeTag, strictDemote); convertComputer.convertType(sourceByteArray, s1 + 1, l1 - 1, out); } else { - throw new IOException( - "Can't convert the " + sourceTypeTag + " type to the " + targetTypeTag + " type."); + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT, sourceTypeTag, targetTypeTag); } } - } - // Get an INT value from numeric types array. We assume the first byte contains the type tag. public static int getIntegerValue(String name, int argIndex, byte[] bytes, int offset) throws HyracksDataException { - return getIntegerValueWithDifferentTypeTagPosition(name, argIndex, bytes, offset + 1, offset); + return getIntegerValue(name, argIndex, bytes, offset, false); + } + + // Get an INT value from numeric types array. We assume the first byte contains the type tag. + public static int getIntegerValue(String name, int argIndex, byte[] bytes, int offset, boolean strictDemote) + throws HyracksDataException { + return getIntegerValueWithDifferentTypeTagPosition(name, argIndex, bytes, offset + 1, offset, strictDemote); } // Get an INT value from numeric types array. We assume the specific location of a byte array contains the type tag. public static int getIntegerValueWithDifferentTypeTagPosition(String name, int argIndex, byte[] bytes, int offset, int typeTagPosition) throws HyracksDataException { - int value; - ATypeTag sourceTypeTag = ATypeTag.VALUE_TYPE_MAPPING[bytes[typeTagPosition]]; + return getIntegerValueWithDifferentTypeTagPosition(name, argIndex, bytes, offset, typeTagPosition, false); + } + // Get an INT value from numeric types array. We assume the specific location of a byte array contains the type tag. + public static int getIntegerValueWithDifferentTypeTagPosition(String name, int argIndex, byte[] bytes, int offset, + int typeTagPosition, boolean strictDemote) throws HyracksDataException { + ATypeTag sourceTypeTag = ATypeTag.VALUE_TYPE_MAPPING[bytes[typeTagPosition]]; if (sourceTypeTag == null) { throw new RuntimeDataException(ErrorCode.INVALID_FORMAT, name, argIndex); } switch (sourceTypeTag) { - case BIGINT: - value = (int) LongPointable.getLong(bytes, offset); - break; case INTEGER: - value = IntegerPointable.getInteger(bytes, offset); - break; + return IntegerPointable.getInteger(bytes, offset); case TINYINT: - value = bytes[offset]; - break; case SMALLINT: - value = ShortPointable.getShort(bytes, offset); - break; + case BIGINT: + return (int) IntegerToInt32TypeConvertComputer.getInstance(strictDemote).convertIntegerType(bytes, + offset, sourceTypeTag, ATypeTag.INTEGER); case FLOAT: - value = (int) FloatPointable.getFloat(bytes, offset); - break; + return FloatToInt32TypeConvertComputer.getInstance(strictDemote).convertType(bytes, offset); case DOUBLE: - value = (int) DoublePointable.getDouble(bytes, offset); - break; + return DoubleToInt32TypeConvertComputer.getInstance(strictDemote).convertType(bytes, offset); default: - throw new RuntimeDataException(ErrorCode.TYPE_MISMATCH, name, argIndex, sourceTypeTag, - ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT, ATypeTag.FLOAT, - ATypeTag.DOUBLE); - + throw new RuntimeDataException(ErrorCode.TYPE_MISMATCH, name, argIndex, + Arrays.toString(new Object[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, + ATypeTag.BIGINT, ATypeTag.FLOAT, ATypeTag.DOUBLE }), + sourceTypeTag); } - - return value; } // Get a LONG (bigint) value from numeric types array. We assume the first byte contains the type tag. public static long getLongValue(String name, int argIndex, byte[] bytes, int offset) throws HyracksDataException { - return getLongValueWithDifferentTypeTagPosition(name, argIndex, bytes, offset + 1, offset); + return getLongValue(name, argIndex, bytes, offset, false); + } + + // Get a LONG (bigint) value from numeric types array. We assume the first byte contains the type tag. + public static long getLongValue(String name, int argIndex, byte[] bytes, int offset, boolean strictDemote) + throws HyracksDataException { + return getLongValueWithDifferentTypeTagPosition(name, argIndex, bytes, offset + 1, offset, strictDemote); } // Get a LONG (bigint) value from numeric types array. We assume the specific location of a byte array // contains the type tag. private static long getLongValueWithDifferentTypeTagPosition(String name, int argIndex, byte[] bytes, int offset, - int typeTagPosition) throws HyracksDataException { - long value; + int typeTagPosition, boolean strictDemote) throws HyracksDataException { ATypeTag sourceTypeTag = ATypeTag.VALUE_TYPE_MAPPING[bytes[typeTagPosition]]; if (sourceTypeTag == null) { throw new RuntimeDataException(ErrorCode.INVALID_FORMAT, name, argIndex); } switch (sourceTypeTag) { case BIGINT: - value = LongPointable.getLong(bytes, offset); - break; - case INTEGER: - value = IntegerPointable.getInteger(bytes, offset); - break; + return LongPointable.getLong(bytes, offset); case TINYINT: - value = bytes[offset]; - break; case SMALLINT: - value = ShortPointable.getShort(bytes, offset); - break; + case INTEGER: + return IntegerToInt64TypeConvertComputer.getInstance().convertIntegerType(bytes, offset, sourceTypeTag, + ATypeTag.BIGINT); case FLOAT: - value = (long) FloatPointable.getFloat(bytes, offset); - break; + return FloatToInt64TypeConvertComputer.getInstance(strictDemote).convertType(bytes, offset); case DOUBLE: - value = (long) DoublePointable.getDouble(bytes, offset); - break; + return DoubleToInt64TypeConvertComputer.getInstance(strictDemote).convertType(bytes, offset); default: - throw new RuntimeDataException(ErrorCode.TYPE_MISMATCH, name, argIndex, sourceTypeTag, - ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT, ATypeTag.FLOAT, - ATypeTag.DOUBLE); + throw new RuntimeDataException(ErrorCode.TYPE_MISMATCH, name, argIndex, + Arrays.toString(new Object[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, + ATypeTag.BIGINT, ATypeTag.FLOAT, ATypeTag.DOUBLE }), + sourceTypeTag); } - - return value; } // Get a DOUBLE value from numeric types array. We assume the first byte contains the type tag. @@ -742,46 +365,33 @@ public class ATypeHierarchy { // Get a DOUBLE value from numeric types array. We assume the specific location of a byte array contains the type tag. private static double getDoubleValueWithDifferentTypeTagPosition(String name, int argIndex, byte[] bytes, - int offset, int typeTagPosition) - throws HyracksDataException { - double value; + int offset, int typeTagPosition) throws HyracksDataException { ATypeTag sourceTypeTag = ATypeTag.VALUE_TYPE_MAPPING[bytes[typeTagPosition]]; if (sourceTypeTag == null) { throw new RuntimeDataException(ErrorCode.INVALID_FORMAT, name, argIndex); } switch (sourceTypeTag) { - case BIGINT: - value = LongPointable.getLong(bytes, offset); - break; - case INTEGER: - value = IntegerPointable.getInteger(bytes, offset); - break; + case DOUBLE: + return DoublePointable.getDouble(bytes, offset); + case FLOAT: + return FloatToDoubleTypeConvertComputer.getInstance().convertType(bytes, offset); case TINYINT: - value = bytes[offset]; - break; case SMALLINT: - value = ShortPointable.getShort(bytes, offset); - break; - case FLOAT: - value = FloatPointable.getFloat(bytes, offset); - break; - case DOUBLE: - value = DoublePointable.getDouble(bytes, offset); - break; + case INTEGER: + case BIGINT: + return IntegerToDoubleTypeConvertComputer.getInstance().convertType(bytes, offset, sourceTypeTag); default: - throw new RuntimeDataException(ErrorCode.TYPE_MISMATCH, name, argIndex, sourceTypeTag, - ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT, ATypeTag.FLOAT, - ATypeTag.DOUBLE); + throw new RuntimeDataException(ErrorCode.TYPE_MISMATCH, name, argIndex, + Arrays.toString(new ATypeTag[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, + ATypeTag.BIGINT, ATypeTag.FLOAT, ATypeTag.DOUBLE }), + sourceTypeTag); } - - return value; } - public static enum Domain { + public enum Domain { SPATIAL, NUMERIC, LIST, ANY } - } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/AbstractIntegerTypeConvertComputer.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/AbstractIntegerTypeConvertComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/AbstractIntegerTypeConvertComputer.java index c646288..88100c6 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/AbstractIntegerTypeConvertComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/AbstractIntegerTypeConvertComputer.java @@ -20,128 +20,216 @@ package org.apache.asterix.om.types.hierachy; import java.io.DataOutput; import java.io.IOException; - +import java.util.Arrays; + +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.exceptions.RuntimeDataException; +import org.apache.asterix.om.base.AInt16; +import org.apache.asterix.om.base.AInt32; +import org.apache.asterix.om.base.AInt64; +import org.apache.asterix.om.base.AInt8; +import org.apache.asterix.om.base.IAObject; import org.apache.asterix.om.types.ATypeTag; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.primitive.BytePointable; +import org.apache.hyracks.data.std.primitive.IntegerPointable; +import org.apache.hyracks.data.std.primitive.LongPointable; +import org.apache.hyracks.data.std.primitive.ShortPointable; public abstract class AbstractIntegerTypeConvertComputer implements ITypeConvertComputer { + private final boolean strict; + + protected AbstractIntegerTypeConvertComputer(boolean strict) { + this.strict = strict; + } + // Refer to the following to convert byte array to integer types, and vice versa. // https://docs.oracle.com/javase/7/docs/api/java/io/DataOutput.html // https://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html - public void convertIntegerType(byte[] data, int start, int length, DataOutput out, ATypeTag targetType, + protected void convertIntegerType(byte[] data, int start, int length, DataOutput out, ATypeTag targetType, int targetTypeLength) throws IOException { - long num = 0; - // for (int i = start; i < start + length; i++) { - // num += (data[i] & 0xff) << ((length - 1 - (i - start)) * 8); - // } + long num = asLong(data, start, length); + num = validate(num, targetType); + out.writeByte(targetType.serialize()); + writeTargetValue(num, out, targetTypeLength); + } - // Read source values + static long asLong(byte[] data, int start, int length) throws RuntimeDataException { switch (length) { - case 1: - // TINYINT - num = (data[start] & 0xff); - break; + case 1: // TINYINT + return BytePointable.getByte(data, start); + case 2: // SMALLINT + return ShortPointable.getShort(data, start); + case 4: // INTEGER + return IntegerPointable.getInteger(data, start); + case 8: // BIGINT + return LongPointable.getLong(data, start); + default: + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_INTEGER_SOURCE, Arrays.toString( + new ATypeTag[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT })); + } + } - case 2: - // SMALLINT - num = (short) ((data[start] << 8) | (data[start + 1] & 0xff)); + private void writeTargetValue(long num, DataOutput out, int targetTypeLength) throws IOException { + // Write actual target value + switch (targetTypeLength) { + case 1: // TINYINT + out.writeByte((byte) (num & 0xff)); break; - case 4: - // INTEGER - num = (int) (((data[start] & 0xff) << 24) | ((data[start + 1] & 0xff) << 16) - | ((data[start + 2] & 0xff) << 8) | (data[start + 3] & 0xff)); + case 2: // SMALLINT + out.writeByte((byte) ((num >> 8) & 0xff)); + out.writeByte((byte) (num & 0xff)); break; - case 8: - // BIGINT - num = (((long) (data[start] & 0xff) << 56) | ((long) (data[start + 1] & 0xff) << 48) - | ((long) (data[start + 2] & 0xff) << 40) | ((long) (data[start + 3] & 0xff) << 32) - | ((long) (data[start + 4] & 0xff) << 24) | ((long) (data[start + 5] & 0xff) << 16) - | ((long) (data[start + 6] & 0xff) << 8) | ((long) (data[start + 7] & 0xff))); + case 4: // INTEGER + out.writeByte((byte) ((num >> 24) & 0xff)); + out.writeByte((byte) ((num >> 16) & 0xff)); + out.writeByte((byte) ((num >> 8) & 0xff)); + out.writeByte((byte) (num & 0xff)); + break; + case 8: // BIGINT + out.writeByte((byte) ((num >> 56) & 0xff)); + out.writeByte((byte) ((num >> 48) & 0xff)); + out.writeByte((byte) ((num >> 40) & 0xff)); + out.writeByte((byte) ((num >> 32) & 0xff)); + out.writeByte((byte) ((num >> 24) & 0xff)); + out.writeByte((byte) ((num >> 16) & 0xff)); + out.writeByte((byte) ((num >> 8) & 0xff)); + out.writeByte((byte) (num & 0xff)); break; default: - throw new IOException("Can't convert integer types. The source type should be one of " - + "tinyint/smallint/integer/bigint."); - + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_INTEGER_TARGET, Arrays.toString( + new ATypeTag[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT })); } + } - // Boundary check - switch (targetType) { + protected IAObject convertIntegerType(IAObject sourceObject, ATypeTag targetType) throws HyracksDataException { + long num; + + switch (sourceObject.getType().getTypeTag()) { case TINYINT: - if (num > Byte.MAX_VALUE || num < Byte.MIN_VALUE) { - throw new IOException("Source value " + num - + " is out of range that TINYINT can hold - TINYINT.MAX_VALUE:" + Byte.MAX_VALUE - + ", TINYINT.MIN_VALUE:" + Byte.MIN_VALUE); - } + num = ((AInt8) sourceObject).getByteValue(); break; - case SMALLINT: - if (num > Short.MAX_VALUE || num < Short.MIN_VALUE) { - throw new IOException("Source value " + num - + " is out of range that SMALLINT can hold - SMALLINT.MAX_VALUE:" + Short.MAX_VALUE - + ", SMALLINT.MIN_VALUE:" + Short.MIN_VALUE); - } + num = ((AInt16) sourceObject).getShortValue(); break; - case INTEGER: - if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE) { - throw new IOException("Source value " + num - + " is out of range that INTEGER can hold - INTEGER.MAX_VALUE:" + Integer.MAX_VALUE - + ", INTEGER.MIN_VALUE:" + Integer.MIN_VALUE); - } + num = ((AInt32) sourceObject).getIntegerValue(); break; - case BIGINT: - default: + num = ((AInt64) sourceObject).getLongValue(); break; + default: + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_INTEGER_SOURCE, Arrays.toString( + new ATypeTag[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT })); } - out.writeByte(targetType.serialize()); + num = validate(num, targetType); - // Write actual target value - switch (targetTypeLength) { - case 1: - // TINYINT - out.writeByte((byte) (num & 0xff)); + switch (targetType) { + case TINYINT: + return new AInt8((byte) num); + case SMALLINT: + return new AInt16((short) num); + case INTEGER: + return new AInt32((int) num); + case BIGINT: + return new AInt64(num); + default: + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_INTEGER_TARGET, Arrays.toString( + new ATypeTag[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT })); + } + } + + protected long convertIntegerType(byte[] data, int start, ATypeTag sourceTypeTag, ATypeTag targetType) + throws HyracksDataException { + long num; + switch (sourceTypeTag) { + case TINYINT: + num = BytePointable.getByte(data, start); break; + case SMALLINT: + num = ShortPointable.getShort(data, start); + break; + case INTEGER: + num = IntegerPointable.getInteger(data, start); + break; + case BIGINT: + num = LongPointable.getLong(data, start); + break; + default: + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_INTEGER_SOURCE, Arrays.toString( + new ATypeTag[] { ATypeTag.TINYINT, ATypeTag.SMALLINT, ATypeTag.INTEGER, ATypeTag.BIGINT })); + } - case 2: - // SMALLINT - out.writeByte((byte) ((num >> 8) & 0xff)); - out.writeByte((byte) (num & 0xff)); + return validate(num, targetType); + } + + private long validate(long num, ATypeTag targetType) throws HyracksDataException { + // Boundary check + switch (targetType) { + case TINYINT: + if (num > Byte.MAX_VALUE) { + if (strict) { + raiseBoundaryException(num, targetType, Byte.MAX_VALUE, Byte.MIN_VALUE); + } else { + return Byte.MAX_VALUE; + } + } else if (num < Byte.MIN_VALUE) { + if (strict) { + raiseBoundaryException(num, targetType, Byte.MAX_VALUE, Byte.MIN_VALUE); + } else { + return Byte.MIN_VALUE; + } + } break; - case 4: - // INTEGER - out.writeByte((byte) ((num >> 24) & 0xff)); - out.writeByte((byte) ((num >> 16) & 0xff)); - out.writeByte((byte) ((num >> 8) & 0xff)); - out.writeByte((byte) (num & 0xff)); + case SMALLINT: + if (num > Short.MAX_VALUE) { + if (strict) { + raiseBoundaryException(num, targetType, Short.MAX_VALUE, Short.MIN_VALUE); + } else { + return Short.MAX_VALUE; + } + } else if (num < Short.MIN_VALUE) { + if (strict) { + raiseBoundaryException(num, targetType, Short.MAX_VALUE, Short.MIN_VALUE); + } else { + return Short.MIN_VALUE; + } + } break; - case 8: - // BIGINT - out.writeByte((byte) ((num >> 56) & 0xff)); - out.writeByte((byte) ((num >> 48) & 0xff)); - out.writeByte((byte) ((num >> 40) & 0xff)); - out.writeByte((byte) ((num >> 32) & 0xff)); - out.writeByte((byte) ((num >> 24) & 0xff)); - out.writeByte((byte) ((num >> 16) & 0xff)); - out.writeByte((byte) ((num >> 8) & 0xff)); - out.writeByte((byte) (num & 0xff)); + case INTEGER: + if (num > Integer.MAX_VALUE) { + if (strict) { + raiseBoundaryException(num, targetType, Integer.MAX_VALUE, Integer.MIN_VALUE); + } else { + return Integer.MAX_VALUE; + } + } else if (num < Integer.MIN_VALUE) { + if (strict) { + raiseBoundaryException(num, targetType, Integer.MAX_VALUE, Integer.MIN_VALUE); + } else { + return Integer.MIN_VALUE; + } + } break; + case BIGINT: default: - throw new IOException("Can't convert integer types. The target type should be one of " - + "tinyint/smallint/integer/bigint."); - + break; } -// for (int i = targetTypeLength - 1; i >= 0; i--) { -// out.writeByte((byte) ((num >>> (i * 8)) & 0xFF)); -// } + return num; + } + + private void raiseBoundaryException(long num, ATypeTag targetType, long maxValue, long minValue) + throws HyracksDataException { + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_OUT_OF_BOUND, num, targetType, maxValue, minValue); } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ce062ba2/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToFloatTypeConvertComputer.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToFloatTypeConvertComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToFloatTypeConvertComputer.java index e6c450c..1792ce5 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToFloatTypeConvertComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToFloatTypeConvertComputer.java @@ -21,28 +21,67 @@ package org.apache.asterix.om.types.hierachy; import java.io.DataOutput; import java.io.IOException; +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.exceptions.RuntimeDataException; +import org.apache.asterix.om.base.ADouble; +import org.apache.asterix.om.base.AFloat; +import org.apache.asterix.om.base.IAObject; import org.apache.asterix.om.types.ATypeTag; +import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.data.std.primitive.DoublePointable; public class DoubleToFloatTypeConvertComputer implements ITypeConvertComputer { - public static final DoubleToFloatTypeConvertComputer INSTANCE = new DoubleToFloatTypeConvertComputer(); + private static final DoubleToFloatTypeConvertComputer INSTANCE_STRICT = new DoubleToFloatTypeConvertComputer(true); - private DoubleToFloatTypeConvertComputer() { + private static final DoubleToFloatTypeConvertComputer INSTANCE_LAX = new DoubleToFloatTypeConvertComputer(false); + private final boolean strict; + + private DoubleToFloatTypeConvertComputer(boolean strict) { + this.strict = strict; + } + + public static DoubleToFloatTypeConvertComputer getInstance(boolean strict) { + return strict ? INSTANCE_STRICT : INSTANCE_LAX; } @Override public void convertType(byte[] data, int start, int length, DataOutput out) throws IOException { double sourceValue = DoublePointable.getDouble(data, start); + float targetValue = convert(sourceValue); + out.writeByte(ATypeTag.FLOAT.serialize()); + out.writeFloat(targetValue); + } + + @Override + public IAObject convertType(IAObject sourceObject) throws HyracksDataException { + double sourceValue = ((ADouble) sourceObject).getDoubleValue(); + float targetValue = convert(sourceValue); + return new AFloat(targetValue); + } + + private float convert(double sourceValue) throws HyracksDataException { // Boundary check - if (sourceValue > Float.MAX_VALUE || sourceValue < Float.MIN_VALUE) { - throw new IOException("Cannot convert Double to Float - Double value " + sourceValue - + " is out of range that Float type can hold: Float.MAX_VALUE:" + Float.MAX_VALUE - + ", Float.MIN_VALUE: " + Float.MIN_VALUE); + if (sourceValue > Float.MAX_VALUE) { + if (strict) { + raiseBoundaryCheckException(sourceValue); + } else { + return Float.MAX_VALUE; + } + } else if (sourceValue < Float.MIN_VALUE) { + if (strict) { + raiseBoundaryCheckException(sourceValue); + } else { + return Float.MIN_VALUE; + } } - out.writeByte(ATypeTag.FLOAT.serialize()); - out.writeFloat((float) sourceValue); + + return (float) sourceValue; } + private void raiseBoundaryCheckException(double sourceValue) throws HyracksDataException { + throw new RuntimeDataException(ErrorCode.TYPE_CONVERT_OUT_OF_BOUND, sourceValue, ATypeTag.FLOAT, + Float.MAX_VALUE, Float.MIN_VALUE); + } }