|
12 | 12 |
|
13 | 13 | /** |
14 | 14 | * The Algorithm for turning a BigDecimal into a Postgres Numeric is heavily inspired by the Intermine Implementation: |
15 | | - * |
| 15 | + * <p> |
16 | 16 | * https://github.com/intermine/intermine/blob/master/intermine/objectstore/main/src/org/intermine/sql/writebatch/BatchWriterPostgresCopyImpl.java |
17 | | - * |
18 | 17 | */ |
19 | 18 | public class BigDecimalValueHandler<T extends Number> extends BaseValueHandler<T> { |
20 | 19 |
|
21 | 20 | private static final int DECIMAL_DIGITS = 4; |
22 | | - |
23 | | - protected static final BigInteger TEN = new BigInteger("10"); |
24 | | - protected static final BigInteger TEN_THOUSAND = new BigInteger("10000"); |
| 21 | + private static final BigInteger TEN_THOUSAND = new BigInteger("10000"); |
25 | 22 |
|
26 | 23 | @Override |
27 | | - protected void internalHandle(DataOutputStream buffer, final T value) throws Exception { |
28 | | - |
29 | | - BigDecimal tmpValue = getNumericAsBigDecimal(value); |
30 | | - |
31 | | - BigInteger unscaledValue = tmpValue.unscaledValue(); |
32 | | - |
33 | | - int sign = tmpValue.signum(); |
34 | | - |
35 | | - if (sign == -1) { |
36 | | - unscaledValue = unscaledValue.negate(); |
37 | | - } |
| 24 | + protected void internalHandle(final DataOutputStream buffer, final T value) throws Exception { |
| 25 | + final BigDecimal tmpValue = getNumericAsBigDecimal(value); |
38 | 26 |
|
39 | 27 | // Number of fractional digits: |
40 | | - int fractionDigits = tmpValue.scale(); |
| 28 | + final int fractionDigits = tmpValue.scale(); |
41 | 29 |
|
42 | 30 | // Number of Fraction Groups: |
43 | | - int fractionGroups = (fractionDigits + 3) / 4; |
44 | | - |
45 | | - List<Integer> digits = new ArrayList<>(); |
46 | | - |
47 | | - // The scale needs to be a multiple of 4: |
48 | | - int scaleRemainder = fractionDigits % 4; |
49 | | - |
50 | | - // Scale the first value: |
51 | | - if(scaleRemainder != 0) |
52 | | - { |
53 | | - BigInteger[] result = unscaledValue.divideAndRemainder(TEN.pow(scaleRemainder)); |
54 | | - |
55 | | - int digit = result[1].intValue() * (int) Math.pow(10, DECIMAL_DIGITS - scaleRemainder); |
56 | | - |
57 | | - digits.add(digit); |
58 | | - |
59 | | - unscaledValue = result[0]; |
60 | | - } |
| 31 | + final int fractionGroups = (fractionDigits + 3) / 4; |
61 | 32 |
|
62 | | - while (!unscaledValue.equals(BigInteger.ZERO)) { |
63 | | - BigInteger[] result = unscaledValue.divideAndRemainder(TEN_THOUSAND); |
64 | | - digits.add(result[1].intValue()); |
65 | | - unscaledValue = result[0]; |
66 | | - } |
| 33 | + final List<Integer> digits = digits(tmpValue); |
67 | 34 |
|
68 | 35 | buffer.writeInt(8 + (2 * digits.size())); |
69 | 36 | buffer.writeShort(digits.size()); |
70 | 37 | buffer.writeShort(digits.size() - fractionGroups - 1); |
71 | | - buffer.writeShort(sign == 1 ? 0x0000 : 0x4000); |
| 38 | + buffer.writeShort(tmpValue.signum() == 1 ? 0x0000 : 0x4000); |
72 | 39 | buffer.writeShort(fractionDigits); |
73 | 40 |
|
74 | 41 | // Now write each digit: |
75 | 42 | for (int pos = digits.size() - 1; pos >= 0; pos--) { |
76 | | - int valueToWrite = digits.get(pos); |
| 43 | + final int valueToWrite = digits.get(pos); |
77 | 44 | buffer.writeShort(valueToWrite); |
78 | 45 | } |
79 | 46 | } |
80 | 47 |
|
81 | | - private static BigDecimal getNumericAsBigDecimal(Number source) { |
| 48 | + @Override |
| 49 | + public int getLength(final T value) { |
| 50 | + final List<Integer> digits = digits(getNumericAsBigDecimal(value)); |
| 51 | + return (8 + (2 * digits.size())); |
| 52 | + } |
82 | 53 |
|
| 54 | + private static BigDecimal getNumericAsBigDecimal(final Number source) { |
83 | 55 | if (!(source instanceof BigDecimal)) { |
84 | 56 | return BigDecimalUtils.toBigDecimal(source.doubleValue()); |
85 | 57 | } |
86 | 58 |
|
87 | 59 | return (BigDecimal) source; |
88 | 60 | } |
89 | 61 |
|
90 | | - @Override |
91 | | - public int getLength(T value) { |
92 | | - BigDecimal tmpValue = getNumericAsBigDecimal(value); |
| 62 | + private List<Integer> digits(final BigDecimal value) { |
| 63 | + BigInteger unscaledValue = value.unscaledValue(); |
93 | 64 |
|
94 | | - BigInteger unscaledValue = tmpValue.unscaledValue(); |
95 | | - |
96 | | - int sign = tmpValue.signum(); |
97 | | - |
98 | | - if (sign == -1) { |
| 65 | + if (value.signum() == -1) { |
99 | 66 | unscaledValue = unscaledValue.negate(); |
100 | 67 | } |
101 | 68 |
|
102 | | - // Number of fractional digits: |
103 | | - int fractionDigits = tmpValue.scale(); |
104 | | - |
105 | | - List<Integer> digits = new ArrayList<>(); |
| 69 | + final List<Integer> digits = new ArrayList<>(); |
106 | 70 |
|
107 | 71 | // The scale needs to be a multiple of 4: |
108 | | - int scaleRemainder = fractionDigits % 4; |
| 72 | + int scaleRemainder = value.scale() % 4; |
109 | 73 |
|
110 | 74 | // Scale the first value: |
111 | | - if(scaleRemainder != 0) |
112 | | - { |
113 | | - BigInteger[] result = unscaledValue.divideAndRemainder(TEN.pow(scaleRemainder)); |
114 | | - |
115 | | - int digit = result[1].intValue() * (int) Math.pow(10, DECIMAL_DIGITS - scaleRemainder); |
116 | | - |
| 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); |
117 | 78 | digits.add(digit); |
118 | | - |
119 | 79 | unscaledValue = result[0]; |
120 | 80 | } |
121 | 81 |
|
122 | 82 | while (!unscaledValue.equals(BigInteger.ZERO)) { |
123 | | - BigInteger[] result = unscaledValue.divideAndRemainder(TEN_THOUSAND); |
| 83 | + final BigInteger[] result = unscaledValue.divideAndRemainder(TEN_THOUSAND); |
124 | 84 | digits.add(result[1].intValue()); |
125 | 85 | unscaledValue = result[0]; |
126 | 86 | } |
127 | 87 |
|
128 | | - return (8 + (2 * digits.size())); |
| 88 | + return digits; |
129 | 89 | } |
130 | 90 | } |
0 commit comments