Skip to content

Commit 12db65c

Browse files
authored
adapt the writing of BigDecimal of large positive integer type to PG
1 parent 87e7306 commit 12db65c

1 file changed

Lines changed: 29 additions & 17 deletions

File tree

PgBulkInsert/src/main/java/de/bytefish/pgbulkinsert/pgsql/handlers/BigDecimalValueHandler.java

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
* The Algorithm for turning a BigDecimal into a Postgres Numeric is heavily inspired by the Intermine Implementation:
1515
* <p>
1616
* https://github.com/intermine/intermine/blob/master/intermine/objectstore/main/src/org/intermine/sql/writebatch/BatchWriterPostgresCopyImpl.java
17+
* <p>
18+
* please see struct definition of @{link NumericVar} for numeric data type byte structure at:
19+
* https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/numeric.c
1720
*/
1821
public class BigDecimalValueHandler<T extends Number> extends BaseValueHandler<T> {
1922

@@ -28,15 +31,15 @@ protected void internalHandle(final DataOutputStream buffer, final T value) thro
2831
final int fractionDigits = tmpValue.scale();
2932

3033
// Number of Fraction Groups:
31-
final int fractionGroups = (fractionDigits + 3) / 4;
34+
final int fractionGroups = fractionDigits > 0 ? (fractionDigits + 3) / 4 : 0;
3235

3336
final List<Integer> digits = digits(tmpValue);
3437

3538
buffer.writeInt(8 + (2 * digits.size()));
3639
buffer.writeShort(digits.size());
3740
buffer.writeShort(digits.size() - fractionGroups - 1);
3841
buffer.writeShort(tmpValue.signum() == 1 ? 0x0000 : 0x4000);
39-
buffer.writeShort(fractionDigits);
42+
buffer.writeShort(fractionDigits > 0 ? fractionDigits : 0);
4043

4144
// Now write each digit:
4245
for (int pos = digits.size() - 1; pos >= 0; pos--) {
@@ -68,21 +71,30 @@ private List<Integer> digits(final BigDecimal value) {
6871

6972
final List<Integer> digits = new ArrayList<>();
7073

71-
// The scale needs to be a multiple of 4:
72-
int scaleRemainder = value.scale() % 4;
73-
74-
// Scale the first value:
75-
if (scaleRemainder != 0) {
76-
final BigInteger[] result = unscaledValue.divideAndRemainder(BigInteger.TEN.pow(scaleRemainder));
77-
final int digit = result[1].intValue() * (int) Math.pow(10, DECIMAL_DIGITS - scaleRemainder);
78-
digits.add(digit);
79-
unscaledValue = result[0];
80-
}
81-
82-
while (!unscaledValue.equals(BigInteger.ZERO)) {
83-
final BigInteger[] result = unscaledValue.divideAndRemainder(TEN_THOUSAND);
84-
digits.add(result[1].intValue());
85-
unscaledValue = result[0];
74+
if (value.scale() > 0) {
75+
// The scale needs to be a multiple of 4:
76+
int scaleRemainder = value.scale() % 4;
77+
78+
// Scale the first value:
79+
if (scaleRemainder != 0) {
80+
final BigInteger[] result = unscaledValue.divideAndRemainder(BigInteger.TEN.pow(scaleRemainder));
81+
final int digit = result[1].intValue() * (int) Math.pow(10, DECIMAL_DIGITS - scaleRemainder);
82+
digits.add(digit);
83+
unscaledValue = result[0];
84+
}
85+
86+
while (!unscaledValue.equals(BigInteger.ZERO)) {
87+
final BigInteger[] result = unscaledValue.divideAndRemainder(TEN_THOUSAND);
88+
digits.add(result[1].intValue());
89+
unscaledValue = result[0];
90+
}
91+
} else {
92+
BigInteger originalValue = unscaledValue.multiply(BigInteger.TEN.pow(Math.abs(value.scale())));
93+
while (!originalValue.equals(BigInteger.ZERO)) {
94+
final BigInteger[] result = originalValue.divideAndRemainder(TEN_THOUSAND);
95+
digits.add(result[1].intValue());
96+
originalValue = result[0];
97+
}
8698
}
8799

88100
return digits;

0 commit comments

Comments
 (0)