Skip to content

Commit 4e67c9c

Browse files
committed
Fix the issue of handling negative big decimals
1 parent d0af95b commit 4e67c9c

File tree

3 files changed

+79
-14
lines changed

3 files changed

+79
-14
lines changed

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/util/ClickHouseRowBinaryStream.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -188,22 +188,24 @@ public void writeFloat64(double value) throws IOException {
188188
Utils.writeLong(out, Double.doubleToLongBits(value));
189189
}
190190

191-
public void writeDecimal128(BigDecimal num, int scale) throws IOException {
192-
BigInteger bi = Utils.toBigInteger(num, scale);
193-
byte[] r = bi.toByteArray();
194-
for (int i = r.length; i > 0; i--) {
195-
out.write(r[i - 1]);
191+
public void writeBigInteger(BigInteger value, int byteLength) throws IOException {
192+
byte empty = value.signum() == -1 ? (byte) 0xFF : 0x00;
193+
byte[] bytes = value.toByteArray();
194+
for (int i = bytes.length - 1; i >= 0; i--) {
195+
out.write(bytes[i]);
196+
}
197+
198+
for (int i = byteLength - bytes.length; i > 0; i--) {
199+
out.write(empty);
196200
}
197-
out.write(new byte[16 - r.length]);
201+
}
202+
203+
public void writeDecimal128(BigDecimal num, int scale) throws IOException {
204+
writeBigInteger(Utils.toBigInteger(num, scale), 16);
198205
}
199206

200207
public void writeDecimal256(BigDecimal num, int scale) throws IOException {
201-
BigInteger bi = Utils.toBigInteger(num, scale);
202-
byte[] r = bi.toByteArray();
203-
for (int i = r.length; i > 0; i--) {
204-
out.write(r[i - 1]);
205-
}
206-
out.write(new byte[32 - r.length]);
208+
writeBigInteger(Utils.toBigInteger(num, scale), 32);
207209
}
208210

209211
public void writeDecimal64(BigDecimal num, int scale) throws IOException {

clickhouse-jdbc/src/test/java/ru/yandex/clickhouse/integration/RowBinaryStreamTest.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import static org.testng.Assert.assertEquals;
44
import static org.testng.Assert.assertFalse;
5-
import static org.testng.Assert.assertThrows;
65
import static org.testng.Assert.assertTrue;
76

87
import java.io.EOFException;
98
import java.io.IOException;
9+
import java.math.BigDecimal;
1010
import java.math.BigInteger;
1111
import java.sql.Date;
1212
import java.sql.ResultSet;
@@ -276,6 +276,46 @@ public void testBitmap() throws Exception {
276276
}
277277
}
278278

279+
@Test
280+
public void testBigDecimals() throws Exception {
281+
try (ClickHouseStatement statement = connection.createStatement()) {
282+
statement.execute("set allow_experimental_bigint_types=1;"
283+
+ "create table if not exists test.test_big_decimals(d128 Decimal128(6), d256 Decimal256(12)) engine=Memory");
284+
} catch (SQLException e) {
285+
return;
286+
}
287+
288+
try (ClickHouseStatement statement = connection.createStatement()) {
289+
BigDecimal[] values = new BigDecimal[] {
290+
BigDecimal.valueOf(-123.123456789D),
291+
BigDecimal.ZERO,
292+
BigDecimal.valueOf(123.123456789D)
293+
};
294+
statement.sendRowBinaryStream("insert into table test.test_big_decimals", new ClickHouseStreamCallback() {
295+
@Override
296+
public void writeTo(ClickHouseRowBinaryStream stream) throws IOException {
297+
for (int i = 0; i < values.length; i++) {
298+
stream.writeDecimal128(values[i], 6);
299+
stream.writeDecimal256(values[i], 12);
300+
}
301+
}
302+
});
303+
304+
try (ResultSet rs = statement.executeQuery("select * from test.test_big_decimals order by d128")) {
305+
int rowCounter = 0;
306+
while (rs.next()) {
307+
rowCounter++;
308+
assertEquals(rs.getBigDecimal(1, 6), values[rowCounter - 1].setScale(6, BigDecimal.ROUND_DOWN));
309+
assertEquals(rs.getBigDecimal(2, 12), values[rowCounter - 1].setScale(12, BigDecimal.ROUND_DOWN));
310+
}
311+
312+
assertEquals(rowCounter, values.length);
313+
}
314+
315+
statement.execute("drop table if exists test.test_big_decimals");
316+
}
317+
}
318+
279319
private void testRowBinaryStream(boolean rowBinaryResult) throws Exception {
280320
createTable("test.raw_binary");
281321
ClickHouseStatement statement = connection.createStatement();

clickhouse-jdbc/src/test/java/ru/yandex/clickhouse/util/ClickHouseRowBinaryStreamTest.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,32 @@ public void testDecimal128() throws Exception {
112112
@Override
113113
public void write(ClickHouseRowBinaryStream stream) throws Exception {
114114
stream.writeDecimal128(new BigDecimal(10.23), 3);
115+
stream.writeDecimal128(new BigDecimal(-10.23), 3);
115116
}
116117
},
117-
new byte[]{-10, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
118+
new byte[] {
119+
-10, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120+
10, -40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
121+
}
122+
);
123+
}
124+
125+
@Test
126+
public void testDecimal256() throws Exception {
127+
check(
128+
new StreamWriter() {
129+
@Override
130+
public void write(ClickHouseRowBinaryStream stream) throws Exception {
131+
stream.writeDecimal256(new BigDecimal(10.23), 3);
132+
stream.writeDecimal256(new BigDecimal(-10.23), 3);
133+
}
134+
},
135+
new byte[] {
136+
-10, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
137+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138+
10, -40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
139+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
140+
}
118141
);
119142
}
120143

0 commit comments

Comments
 (0)