/** * 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.hadoop.hive.common.type; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; /** * FastHiveDecimal is a mutable fast decimal object. It is the base class for both the * HiveDecimal and HiveDecimalWritable classes. All fast* methods are protected so they * cannot be accessed by clients of HiveDecimal and HiveDecimalWritable. HiveDecimal ensures * it creates new objects when the value changes since it provides immutable semantics; * HiveDecimalWritable does not create new objects since it provides mutable semantics. * * The methods in this class are shells that pickup the member variables from FastHiveDecimal * parameters and pass them as individual parameters to static methods in the FastHiveDecimalImpl * class that do the real work. * * NOTE: The rationale for fast decimal is in FastHiveDecimalImpl. */ public class FastHiveDecimal { /* * We use protected for the fields so the FastHiveDecimalImpl class can access them. Other * classes including HiveDecimal should not access these fields directly. */ // See FastHiveDecimalImpl for more details on these fields. // -1 when negative; 0 when decimal is zero; 1 when positive. protected int fastSignum; // Decimal longwords. protected long fast2; protected long fast1; protected long fast0; // The number of integer digits in the decimal. When the integer portion is zero, this is 0. protected int fastIntegerDigitCount; // The scale of the decimal. protected int fastScale; // Used for legacy HiveDecimalV1 setScale compatibility for binary / display serialization of // trailing zeroes (or rounding). protected int fastSerializationScale; protected FastHiveDecimal() { fastReset(); } protected FastHiveDecimal(FastHiveDecimal fastDec) { this(); fastSignum = fastDec.fastSignum; fast0 = fastDec.fast0; fast1 = fastDec.fast1; fast2 = fastDec.fast2; fastIntegerDigitCount = fastDec.fastIntegerDigitCount; fastScale = fastDec.fastScale; // Not propagated. fastSerializationScale = -1; } protected FastHiveDecimal(int fastSignum, FastHiveDecimal fastDec) { this(); this.fastSignum = fastSignum; fast0 = fastDec.fast0; fast1 = fastDec.fast1; fast2 = fastDec.fast2; fastIntegerDigitCount = fastDec.fastIntegerDigitCount; fastScale = fastDec.fastScale; // Not propagated. fastSerializationScale = -1; } protected FastHiveDecimal( int fastSignum, long fast0, long fast1, long fast2, int fastIntegerDigitCount, int fastScale) { this(); this.fastSignum = fastSignum; this.fast0 = fast0; this.fast1 = fast1; this.fast2 = fast2; this.fastIntegerDigitCount = fastIntegerDigitCount; this.fastScale = fastScale; fastSerializationScale = -1; } protected FastHiveDecimal(long longValue) { this(); FastHiveDecimalImpl.fastSetFromLong(longValue, this); } protected FastHiveDecimal(String string) { this(); FastHiveDecimalImpl.fastSetFromString(string, false, this); } protected void fastReset() { fastSignum = 0; fast0 = 0; fast1 = 0; fast2 = 0; fastIntegerDigitCount = 0; fastScale = 0; fastSerializationScale = -1; } protected void fastSet(FastHiveDecimal fastDec) { fastSignum = fastDec.fastSignum; fast0 = fastDec.fast0; fast1 = fastDec.fast1; fast2 = fastDec.fast2; fastIntegerDigitCount = fastDec.fastIntegerDigitCount; fastScale = fastDec.fastScale; fastSerializationScale = fastDec.fastSerializationScale; } protected void fastSet( int fastSignum, long fast0, long fast1, long fast2, int fastIntegerDigitCount, int fastScale) { this.fastSignum = fastSignum; this.fast0 = fast0; this.fast1 = fast1; this.fast2 = fast2; this.fastIntegerDigitCount = fastIntegerDigitCount; this.fastScale = fastScale; // Not specified. fastSerializationScale = -1; } protected void fastSetSerializationScale(int fastSerializationScale) { this.fastSerializationScale = fastSerializationScale; } protected int fastSerializationScale() { return fastSerializationScale; } protected static final String STRING_ENFORCE_PRECISION_OUT_OF_RANGE = "Decimal precision out of allowed range [1," + HiveDecimal.MAX_PRECISION + "]"; protected static final String STRING_ENFORCE_SCALE_OUT_OF_RANGE = "Decimal scale out of allowed range [0," + HiveDecimal.MAX_SCALE + "]"; protected static final String STRING_ENFORCE_SCALE_LESS_THAN_EQUAL_PRECISION = "Decimal scale must be less than or equal to precision"; protected boolean fastSetFromBigDecimal( BigDecimal bigDecimal, boolean allowRounding) { return FastHiveDecimalImpl.fastSetFromBigDecimal( bigDecimal, allowRounding, this); } protected boolean fastSetFromBigInteger( BigInteger bigInteger) { return FastHiveDecimalImpl.fastSetFromBigInteger( bigInteger, this); } protected boolean fastSetFromBigIntegerAndScale( BigInteger bigInteger, int scale) { return FastHiveDecimalImpl.fastSetFromBigInteger( bigInteger, scale, this); } protected boolean fastSetFromString(String string, boolean trimBlanks) { byte[] bytes = string.getBytes(); return fastSetFromBytes( bytes, 0, bytes.length, trimBlanks); } protected boolean fastSetFromBytes(byte[] bytes, int offset, int length, boolean trimBlanks) { return FastHiveDecimalImpl.fastSetFromBytes( bytes, offset, length, trimBlanks, this); } protected boolean fastSetFromDigitsOnlyBytesAndScale( boolean isNegative, byte[] bytes, int offset, int length, int scale) { return FastHiveDecimalImpl.fastSetFromDigitsOnlyBytesAndScale( isNegative, bytes, offset, length, scale, this); } protected void fastSetFromInt(int intValue) { FastHiveDecimalImpl.fastSetFromInt(intValue, this); } protected void fastSetFromLong(long longValue) { FastHiveDecimalImpl.fastSetFromLong(longValue, this); } protected boolean fastSetFromLongAndScale(long longValue, int scale) { return FastHiveDecimalImpl.fastSetFromLongAndScale( longValue, scale, this); } protected boolean fastSetFromFloat(float floatValue) { return FastHiveDecimalImpl.fastSetFromFloat( floatValue, this); } protected boolean fastSetFromDouble(double doubleValue) { return FastHiveDecimalImpl.fastSetFromDouble( doubleValue, this); } protected void fastFractionPortion() { FastHiveDecimalImpl.fastFractionPortion( fastSignum, fast0, fast1, fast2, fastScale, this); } protected void fastIntegerPortion() { FastHiveDecimalImpl.fastIntegerPortion( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, this); } protected static final int FAST_SCRATCH_BUFFER_LEN_SERIALIZATION_UTILS_READ = 8 * 3; protected boolean fastSerializationUtilsRead( InputStream inputStream, int scale, byte[] scratchBytes) throws IOException, EOFException { return FastHiveDecimalImpl.fastSerializationUtilsRead( inputStream, scale, scratchBytes, this); } protected boolean fastSetFromBigIntegerBytesAndScale( byte[] bytes, int offset, int length, int scale) { return FastHiveDecimalImpl.fastSetFromBigIntegerBytesAndScale( bytes, offset, length, scale, this); } protected static final int SCRATCH_LONGS_LEN_FAST_SERIALIZATION_UTILS_WRITE = 6; protected boolean fastSerializationUtilsWrite(OutputStream outputStream, long[] scratchLongs) throws IOException { return FastHiveDecimalImpl.fastSerializationUtilsWrite( outputStream, fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, scratchLongs); } // The fastBigIntegerBytes method returns 3 56 bit (7 byte) words and a possible sign byte. // However, the fastBigIntegerBytes can take on trailing zeroes -- so make it larger. protected static final int FAST_SCRATCH_BUFFER_LEN_BIG_INTEGER_BYTES = 1 + 48; protected static final int FAST_SCRATCH_LONGS_LEN = 6; protected int fastBigIntegerBytes( long[] scratchLongs, byte[] buffer) { return FastHiveDecimalImpl.fastBigIntegerBytes( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastSerializationScale, scratchLongs, buffer); } protected int fastBigIntegerBytesScaled( int serializationScale, long[] scratchLongs, byte[] buffer) { return FastHiveDecimalImpl.fastBigIntegerBytesScaled( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, serializationScale, scratchLongs, buffer); } protected boolean fastIsByte() { return FastHiveDecimalImpl.fastIsByte( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected byte fastByteValueClip() { return FastHiveDecimalImpl.fastByteValueClip( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected boolean fastIsShort() { return FastHiveDecimalImpl.fastIsShort( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected short fastShortValueClip() { return FastHiveDecimalImpl.fastShortValueClip( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected boolean fastIsInt() { return FastHiveDecimalImpl.fastIsInt( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected int fastIntValueClip() { return FastHiveDecimalImpl.fastIntValueClip( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected boolean fastIsLong() { return FastHiveDecimalImpl.fastIsLong( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected long fastLongValueClip() { return FastHiveDecimalImpl.fastLongValueClip( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected float fastFloatValue() { return FastHiveDecimalImpl.fastFloatValue( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected double fastDoubleValue() { return FastHiveDecimalImpl.fastDoubleValue( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected BigInteger fastBigIntegerValue() { return FastHiveDecimalImpl.fastBigIntegerValue( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastSerializationScale); } protected BigDecimal fastBigDecimalValue() { return FastHiveDecimalImpl.fastBigDecimalValue( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected int fastScale() { return fastScale; } protected int fastSignum() { return fastSignum; } protected int fastCompareTo(FastHiveDecimal right) { return FastHiveDecimalImpl.fastCompareTo( fastSignum, fast0, fast1, fast2, fastScale, right.fastSignum, right.fast0, right.fast1, right.fast2, right.fastScale); } protected static int fastCompareTo(FastHiveDecimal left, FastHiveDecimal right) { return FastHiveDecimalImpl.fastCompareTo( left.fastSignum, left.fast0, left.fast1, left.fast2, left.fastScale, right.fastSignum, right.fast0, right.fast1, right.fast2, right.fastScale); } protected boolean fastEquals(FastHiveDecimal that) { return FastHiveDecimalImpl.fastEquals( fastSignum, fast0, fast1, fast2, fastScale, that.fastSignum, that.fast0, that.fast1, that.fast2, that.fastScale); } protected void fastAbs() { fastSignum = 1; } protected void fastNegate() { if (fastSignum == 0) { return; } fastSignum = (fastSignum == 1 ? -1 : 1); } protected int fastNewFasterHashCode() { return FastHiveDecimalImpl.fastNewFasterHashCode( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected int fastHashCode() { return FastHiveDecimalImpl.fastHashCode( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected int fastIntegerDigitCount() { return fastIntegerDigitCount; } protected int fastSqlPrecision() { return FastHiveDecimalImpl.fastSqlPrecision( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale); } protected int fastRawPrecision() { return FastHiveDecimalImpl.fastRawPrecision( fastSignum, fast0, fast1, fast2); } protected boolean fastScaleByPowerOfTen( int n, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastScaleByPowerOfTen( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, n, fastResult); } protected static String fastRoundingModeToString(int roundingMode) { String roundingModeString; switch (roundingMode) { case BigDecimal.ROUND_DOWN: roundingModeString = "ROUND_DOWN"; break; case BigDecimal.ROUND_UP: roundingModeString = "ROUND_UP"; break; case BigDecimal.ROUND_FLOOR: roundingModeString = "ROUND_FLOOR"; break; case BigDecimal.ROUND_CEILING: roundingModeString = "ROUND_CEILING"; break; case BigDecimal.ROUND_HALF_UP: roundingModeString = "ROUND_HALF_UP"; break; case BigDecimal.ROUND_HALF_EVEN: roundingModeString = "ROUND_HALF_EVEN"; break; default: roundingModeString = "Unknown"; } return roundingModeString + " (" + roundingMode + ")"; } protected boolean fastRound( int newScale, int roundingMode, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastRound( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, newScale, roundingMode, fastResult); } protected boolean isAllZeroesBelow( int power) { return FastHiveDecimalImpl.isAllZeroesBelow( fastSignum, fast0, fast1, fast2, power); } protected boolean fastEnforcePrecisionScale( int maxPrecision, int maxScale) { if (maxPrecision <= 0 || maxPrecision > HiveDecimal.MAX_PRECISION) { return false; } if (maxScale < 0 || maxScale > HiveDecimal.MAX_SCALE) { return false; } /* if (!fastIsValid()) { fastRaiseInvalidException(); } */ FastCheckPrecisionScaleStatus status = FastHiveDecimalImpl.fastCheckPrecisionScale( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, maxPrecision, maxScale); switch (status) { case NO_CHANGE: return true; case OVERFLOW: return false; case UPDATE_SCALE_DOWN: { if (!FastHiveDecimalImpl.fastUpdatePrecisionScale( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, maxPrecision, maxScale, status, this)) { return false; } /* if (!fastIsValid()) { fastRaiseInvalidException(); } */ return true; } default: throw new RuntimeException("Unknown fast decimal check precision and scale status " + status); } } protected FastCheckPrecisionScaleStatus fastCheckPrecisionScale( int maxPrecision, int maxScale) { return FastHiveDecimalImpl.fastCheckPrecisionScale( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, maxPrecision, maxScale); } protected static enum FastCheckPrecisionScaleStatus { NO_CHANGE, OVERFLOW, UPDATE_SCALE_DOWN; } protected boolean fastUpdatePrecisionScale( int maxPrecision, int maxScale, FastCheckPrecisionScaleStatus status, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastUpdatePrecisionScale( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, maxPrecision, maxScale, status, fastResult); } protected boolean fastAdd( FastHiveDecimal fastRight, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastAdd( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastRight.fastSignum, fastRight.fast0, fastRight.fast1, fastRight.fast2, fastRight.fastIntegerDigitCount, fastRight.fastScale, fastResult); } protected boolean fastSubtract( FastHiveDecimal fastRight, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastSubtract( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastRight.fastSignum, fastRight.fast0, fastRight.fast1, fastRight.fast2, fastRight.fastIntegerDigitCount, fastRight.fastScale, fastResult); } protected boolean fastMultiply( FastHiveDecimal fastRight, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastMultiply( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastRight.fastSignum, fastRight.fast0, fastRight.fast1, fastRight.fast2, fastRight.fastIntegerDigitCount, fastRight.fastScale, fastResult); } protected boolean fastRemainder( FastHiveDecimal fastRight, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastRemainder( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastRight.fastSignum, fastRight.fast0, fastRight.fast1, fastRight.fast2, fastRight.fastIntegerDigitCount, fastRight.fastScale, fastResult); } protected boolean fastDivide( FastHiveDecimal fastRight, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastDivide( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, fastRight.fastSignum, fastRight.fast0, fastRight.fast1, fastRight.fast2, fastRight.fastIntegerDigitCount, fastRight.fastScale, fastResult); } protected boolean fastPow( int exponent, FastHiveDecimal fastResult) { return FastHiveDecimalImpl.fastPow( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, exponent, fastResult); } protected String fastToString( byte[] scratchBuffer) { return FastHiveDecimalImpl.fastToString( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, -1, scratchBuffer); } protected String fastToString() { return FastHiveDecimalImpl.fastToString( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, -1); } protected String fastToFormatString(int formatScale) { return FastHiveDecimalImpl.fastToFormatString( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, formatScale); } protected String fastToFormatString( int formatScale, byte[] scratchBuffer) { return FastHiveDecimalImpl.fastToFormatString( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, formatScale, scratchBuffer); } protected String fastToDigitsOnlyString() { return FastHiveDecimalImpl.fastToDigitsOnlyString( fast0, fast1, fast2, fastIntegerDigitCount); } // Sign, zero, dot, 2 * digits (to support toFormatString which can add a lot of trailing zeroes). protected final static int FAST_SCRATCH_BUFFER_LEN_TO_BYTES = 1 + 1 + 1 + 2 * FastHiveDecimalImpl.MAX_DECIMAL_DIGITS; protected int fastToBytes( byte[] scratchBuffer) { return FastHiveDecimalImpl.fastToBytes( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, -1, scratchBuffer); } protected int fastToFormatBytes( int formatScale, byte[] scratchBuffer) { return FastHiveDecimalImpl.fastToFormatBytes( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, formatScale, scratchBuffer); } protected int fastToDigitsOnlyBytes( byte[] scratchBuffer) { return FastHiveDecimalImpl.fastToDigitsOnlyBytes( fast0, fast1, fast2, fastIntegerDigitCount, scratchBuffer); } @Override public String toString() { return FastHiveDecimalImpl.fastToString( fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale, -1); } protected boolean fastIsValid() { return FastHiveDecimalImpl.fastIsValid(this); } protected void fastRaiseInvalidException() { FastHiveDecimalImpl.fastRaiseInvalidException(this); } protected void fastRaiseInvalidException(String parameters) { FastHiveDecimalImpl.fastRaiseInvalidException(this, parameters); } }