in kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/common/FastHiveDecimalImpl.java [4194:4348]
public static boolean fastScaleByPowerOfTen(
int fastSignum,
long fast0,
long fast1,
long fast2,
int fastIntegerDigitCount,
int fastScale,
int power,
FastHiveDecimal fastResult) {
if (fastSignum == 0) {
fastResult.fastReset();
return true;
}
if (power == 0) {
fastResult.fastSet(fastSignum, fast0, fast1, fast2, fastIntegerDigitCount, fastScale);
/*
if (!fastResult.fastIsValid()) {
fastResult.fastRaiseInvalidException();
}
*/
return true;
}
final int absPower = Math.abs(power);
if (power > 0) {
int integerRoom;
int fractionalRoom;
if (fastIntegerDigitCount > 0) {
// Is there integer room above?
integerRoom = HiveDecimal.MAX_PRECISION - fastIntegerDigitCount;
if (integerRoom < power) {
return false;
}
fastResult.fastSignum = fastSignum;
if (fastScale <= power) {
// All fractional digits become integer digits.
final int scaleUp = power - fastScale;
if (scaleUp > 0) {
if (!fastScaleUp(fast0, fast1, fast2, scaleUp, fastResult)) {
throw new RuntimeException("Unexpected");
}
} else {
fastResult.fast0 = fast0;
fastResult.fast1 = fast1;
fastResult.fast2 = fast2;
}
fastResult.fastIntegerDigitCount = fastIntegerDigitCount + fastScale + scaleUp;
fastResult.fastScale = 0;
} else {
// Only a scale adjustment is needed.
fastResult.fastSet(
fastSignum, fast0, fast1, fast2, fastIntegerDigitCount + power, fastScale - power);
}
} else {
// How much can the fraction be moved up?
final int rawPrecision = fastRawPrecision(fastSignum, fast0, fast1, fast2);
final int zeroesBelowDot = fastScale - rawPrecision;
// Our limit is max precision integer digits + "leading" zeros below the dot.
// E.g. 0.00021 has 3 zeroes below the dot.
//
if (power > HiveDecimal.MAX_PRECISION + zeroesBelowDot) {
// Fractional part powered up too high.
return false;
}
final int newIntegerDigitCount = Math.max(0, power - zeroesBelowDot);
if (newIntegerDigitCount > rawPrecision) {
fastResult.fastSignum = fastSignum;
final int scaleUp = newIntegerDigitCount - rawPrecision;
if (!fastScaleUp(fast0, fast1, fast2, scaleUp, fastResult)) {
throw new RuntimeException("Unexpected");
}
fastResult.fastIntegerDigitCount = newIntegerDigitCount;
fastResult.fastScale = 0;
} else {
final int newScale = Math.max(0, fastScale - power);
fastResult.fastSet(fastSignum, fast0, fast1, fast2, newIntegerDigitCount, newScale);
}
}
} else if (fastScale + absPower <= HiveDecimal.MAX_SCALE) {
// Negative power with range -- adjust the scale.
final int newScale = fastScale + absPower;
final int newIntegerDigitCount = Math.max(0, fastIntegerDigitCount - absPower);
final int trailingZeroCount =
fastTrailingDecimalZeroCount(fast0, fast1, fast2, newIntegerDigitCount, newScale);
if (trailingZeroCount > 0) {
fastResult.fastSignum = fastSignum;
doFastScaleDown(fast0, fast1, fast2, trailingZeroCount, fastResult);
fastResult.fastScale = newScale - trailingZeroCount;
fastResult.fastIntegerDigitCount = newIntegerDigitCount;
} else {
fastResult.fastSet(fastSignum, fast0, fast1, fast2, newIntegerDigitCount, newScale);
}
} else {
// fastScale + absPower > HiveDecimal.MAX_SCALE
// Look at getting rid of fractional digits that will now be below HiveDecimal.MAX_SCALE.
final int scaleDown = fastScale + absPower - HiveDecimal.MAX_SCALE;
if (scaleDown < HiveDecimal.MAX_SCALE) {
if (!fastRoundFractionalHalfUp(fastSignum, fast0, fast1, fast2, scaleDown, fastResult)) {
// Overflow.
return false;
}
if (fastResult.fastSignum != 0) {
fastResult.fastScale = HiveDecimal.MAX_SCALE;
fastResult.fastIntegerDigitCount =
Math.max(0, fastRawPrecision(fastResult) - fastResult.fastScale);
final int trailingZeroCount =
fastTrailingDecimalZeroCount(
fastResult.fast0,
fastResult.fast1,
fastResult.fast2,
fastResult.fastIntegerDigitCount,
fastResult.fastScale);
if (trailingZeroCount > 0) {
doFastScaleDown(fastResult, trailingZeroCount, fastResult);
fastResult.fastScale -= trailingZeroCount;
}
}
} else {
// All precision has been lost -- result is 0.
fastResult.fastReset();
}
}
/*
if (!fastResult.fastIsValid()) {
fastResult.fastRaiseInvalidException();
}
*/
return true;
}