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 */
1821public 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