in kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/common/FastHiveDecimalImpl.java [2298:2454]
public static boolean fastSetFromBigIntegerBytesAndScale(
byte[] bytes, int offset, int length, int scale, FastHiveDecimal fastResult) {
final int bytesLength = bytes.length;
if (offset < 0 || offset >= bytesLength) {
return false;
}
final int end = offset + length;
if (end <= offset || end > bytesLength) {
return false;
}
final int startOffset = offset;
// Roughly based on BigInteger code.
boolean isNegative = (bytes[offset] < 0);
if (isNegative) {
// Find first non-sign (0xff) byte of input.
while (offset < end) {
if (bytes[offset] != -1) {
break;
}
offset++;
}
if (offset > end) {
return false;
}
} else {
// Strip leading zeroes -- although there shouldn't be any for a decimal.
while (offset < end && bytes[offset] == 0) {
offset++;
}
if (offset >= end) {
// Zero.
return true;
}
}
long lowerWord56 = 0;
long middleWord56 = 0;
long highWord56 = 0;
int reverseIndex = end;
long work;
int shift;
final int lowestCount = Math.min(reverseIndex - offset, 7);
shift = 0;
for (int i = 0; i < lowestCount; i++) {
work = bytes[--reverseIndex] & 0xFF;
lowerWord56 |= work << shift;
shift += 8;
}
if (reverseIndex <= offset) {
if (isNegative) {
lowerWord56 = ~lowerWord56 & ((1L << shift) - 1);
}
} else {
// Go on to middle word.
final int middleCount = Math.min(reverseIndex - offset, 7);
shift = 0;
for (int i = 0; i < middleCount; i++) {
work = bytes[--reverseIndex] & 0xFF;
middleWord56 |= work << shift;
shift += 8;
}
if (reverseIndex <= offset) {
if (isNegative) {
lowerWord56 = ~lowerWord56 & LONG_56_BIT_MASK;
middleWord56 = ~middleWord56 & ((1L << shift) - 1);
}
} else {
// Go on to high word.
final int highCount = Math.min(reverseIndex - offset, 7);
shift = 0;
for (int i = 0; i < highCount; i++) {
work = bytes[--reverseIndex] & 0xFF;
highWord56 |= work << shift;
shift += 8;
}
if (isNegative) {
// We only need to apply negation to all 3 words when there are 3 words, etc.
lowerWord56 = ~lowerWord56 & LONG_56_BIT_MASK;
middleWord56 = ~middleWord56 & LONG_56_BIT_MASK;
highWord56 = ~highWord56 & ((1L << shift) - 1);
}
}
}
if (!doBinaryToDecimalConversion(
lowerWord56,
middleWord56,
highWord56,
FAST_HIVE_DECIMAL_TWO_POWER_56,
FAST_HIVE_DECIMAL_TWO_POWER_112, // 2^(56 + 56)
fastResult)) {
// Overflow. Use slower alternate.
return doAlternateSetFromBigIntegerBytesAndScale(
bytes, startOffset, length, scale, fastResult);
}
// System.out.println("fastSetFromBigIntegerBytesAndScale fast0 " + fastResult.fast0 + " fast1 "
// + fastResult.fast1 + " fast2 " + fastResult.fast2);
if (isNegative) {
if (!doAddSameScaleSameSign(
/* resultSignum */ 1,
fastResult.fast0,
fastResult.fast1,
fastResult.fast2,
1,
0,
0,
fastResult)) {
// Overflow. Use slower alternate.
return doAlternateSetFromBigIntegerBytesAndScale(
bytes, startOffset, length, scale, fastResult);
}
}
if (fastResult.fast0 == 0 && fastResult.fast1 == 0 && fastResult.fast2 == 0) {
fastResult.fastSignum = 0;
} else {
fastResult.fastSignum = (isNegative ? -1 : 1);
fastResult.fastScale = scale;
final int rawPrecision = fastRawPrecision(fastResult);
fastResult.fastIntegerDigitCount = Math.max(0, rawPrecision - scale);
/*
* Just in case we deserialize a decimal with trailing zeroes...
*/
final int resultTrailingZeroCount =
fastTrailingDecimalZeroCount(
fastResult.fast0,
fastResult.fast1,
fastResult.fast2,
fastResult.fastIntegerDigitCount,
fastResult.fastScale);
if (resultTrailingZeroCount > 0) {
doFastScaleDown(fastResult, resultTrailingZeroCount, fastResult);
fastResult.fastScale -= resultTrailingZeroCount;
}
}
return true;
}