Skip to content

Commit d4104f0

Browse files
authored
Merge pull request #921 from zhicwu/grpc-patch
Avoid losing precision when converting Float and Double to BigDecimal
2 parents 2988a42 + 192e7a7 commit d4104f0

File tree

7 files changed

+94
-13
lines changed

7 files changed

+94
-13
lines changed

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseEnum.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.clickhouse.client;
22

3+
import java.io.Serializable;
34
import java.util.Arrays;
45
import java.util.Collection;
56
import java.util.Collections;
67

7-
public class ClickHouseEnum {
8+
public class ClickHouseEnum implements Serializable {
9+
private static final long serialVersionUID = -978231193821209918L;
10+
811
public static final ClickHouseEnum EMPTY = new ClickHouseEnum(Collections.emptyList());
912

1013
public static ClickHouseEnum of(Class<? extends Enum> clazz) {

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValues.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.time.temporal.ChronoField;
2424
import java.util.Collection;
2525
import java.util.Enumeration;
26+
import java.util.List;
2627
import java.util.Map;
2728
import java.util.TimeZone;
2829
import java.util.UUID;
@@ -107,6 +108,7 @@ public final class ClickHouseValues {
107108
public static final String INF_EXPR = "Inf";
108109
public static final String NINF_EXPR = "-Inf";
109110

111+
public static final String ERROR_INF_OR_NAN = "Infinite or NaN";
110112
public static final String ERROR_INVALID_POINT = "A point should have two and only two double values, but we got: ";
111113
public static final String ERROR_SINGLETON_ARRAY = "Only singleton array is allowed, but we got: ";
112114
public static final String ERROR_SINGLETON_COLLECTION = "Only singleton collection is allowed, but we got: ";
@@ -970,6 +972,46 @@ public static Object extractSingleValue(Map<?, ?> value) {
970972
return value.values().iterator().next();
971973
}
972974

975+
/**
976+
* Creates multiple values based on given columns.
977+
*
978+
* @param config non-null configuration
979+
* @param columns non-null columns
980+
* @return non-null values with default value, either null or empty
981+
*/
982+
public static ClickHouseValue[] newValues(ClickHouseConfig config, List<ClickHouseColumn> columns) {
983+
if (columns == null || columns.isEmpty()) {
984+
return EMPTY_VALUES;
985+
}
986+
987+
ClickHouseValue[] values = new ClickHouseValue[columns.size()];
988+
int index = 0;
989+
for (ClickHouseColumn c : columns) {
990+
values[index++] = newValue(config, c);
991+
}
992+
return values;
993+
}
994+
995+
/**
996+
* Creates multiple values based on given columns.
997+
*
998+
* @param config non-null configuration
999+
* @param columns non-null columns
1000+
* @return non-null values with default value, either null or empty
1001+
*/
1002+
public static ClickHouseValue[] newValues(ClickHouseConfig config, ClickHouseColumn[] columns) {
1003+
if (columns == null || columns.length == 0) {
1004+
return EMPTY_VALUES;
1005+
}
1006+
1007+
int len = columns.length;
1008+
ClickHouseValue[] values = new ClickHouseValue[len];
1009+
for (int i = 0; i < len; i++) {
1010+
values[i] = newValue(config, columns[i]);
1011+
}
1012+
return values;
1013+
}
1014+
9731015
/**
9741016
* Creates a value object based on given column.
9751017
*

clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseDoubleValue.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,26 @@ public double asDouble() {
125125
return value;
126126
}
127127

128+
@Override
129+
public BigDecimal asBigDecimal() {
130+
if (isNull) {
131+
return null;
132+
} else if (Double.isNaN(value) || value == Double.POSITIVE_INFINITY || value == Double.NEGATIVE_INFINITY) {
133+
throw new NumberFormatException(ClickHouseValues.ERROR_INF_OR_NAN);
134+
} else if (value == 0D) {
135+
return BigDecimal.ZERO;
136+
} else if (value == 1D) {
137+
return BigDecimal.ONE;
138+
}
139+
return new BigDecimal(Double.toString(value));
140+
}
141+
128142
@Override
129143
public BigDecimal asBigDecimal(int scale) {
130144
if (isNull) {
131145
return null;
146+
} else if (Double.isNaN(value) || value == Double.POSITIVE_INFINITY || value == Double.NEGATIVE_INFINITY) {
147+
throw new NumberFormatException(ClickHouseValues.ERROR_INF_OR_NAN);
132148
}
133149

134150
BigDecimal dec = BigDecimal.valueOf(value);

clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseFloatValue.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,26 @@ public double asDouble() {
143143
return value;
144144
}
145145

146+
@Override
147+
public BigDecimal asBigDecimal() {
148+
if (isNull) {
149+
return null;
150+
} else if (Float.isNaN(value) || value == Float.POSITIVE_INFINITY || value == Float.NEGATIVE_INFINITY) {
151+
throw new NumberFormatException(ClickHouseValues.ERROR_INF_OR_NAN);
152+
} else if (value == 0F) {
153+
return BigDecimal.ZERO;
154+
} else if (value == 1F) {
155+
return BigDecimal.ONE;
156+
}
157+
return new BigDecimal(Float.toString(value));
158+
}
159+
146160
@Override
147161
public BigDecimal asBigDecimal(int scale) {
148162
if (isNull) {
149163
return null;
164+
} else if (Float.isNaN(value) || value == Float.POSITIVE_INFINITY || value == Float.NEGATIVE_INFINITY) {
165+
throw new NumberFormatException(ClickHouseValues.ERROR_INF_OR_NAN);
150166
}
151167

152168
BigDecimal dec = new BigDecimal(Float.toString(value));

clickhouse-client/src/test/java/com/clickhouse/client/data/ClickHouseDoubleValueTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void testValue() throws Exception {
132132
0L, // long
133133
0F, // float
134134
0D, // double
135-
BigDecimal.valueOf(0L), // BigDecimal
135+
BigDecimal.ZERO, // BigDecimal
136136
new BigDecimal(BigInteger.ZERO, 3), // BigDecimal
137137
BigInteger.ZERO, // BigInteger
138138
ClickHouseDataType.values()[0].name(), // Enum<ClickHouseDataType>
@@ -164,7 +164,7 @@ public void testValue() throws Exception {
164164
1L, // long
165165
1F, // float
166166
1D, // double
167-
BigDecimal.valueOf(1L), // BigDecimal
167+
BigDecimal.ONE, // BigDecimal
168168
new BigDecimal(BigInteger.ONE, 3), // BigDecimal
169169
BigInteger.ONE, // BigInteger
170170
ClickHouseDataType.values()[1].name(), // Enum<ClickHouseDataType>
@@ -196,7 +196,7 @@ public void testValue() throws Exception {
196196
2L, // long
197197
2F, // float
198198
2D, // double
199-
BigDecimal.valueOf(2L), // BigDecimal
199+
BigDecimal.valueOf(2D), // BigDecimal
200200
new BigDecimal(BigInteger.valueOf(2L), 3), // BigDecimal
201201
BigInteger.valueOf(2L), // BigInteger
202202
ClickHouseDataType.values()[2].name(), // Enum<ClickHouseDataType>
@@ -229,7 +229,7 @@ public void testValue() throws Exception {
229229
-1L, // long
230230
-1F, // float
231231
-1D, // double
232-
BigDecimal.valueOf(-1L), // BigDecimal
232+
BigDecimal.valueOf(-1D), // BigDecimal
233233
new BigDecimal(BigInteger.valueOf(-1L), 3), // BigDecimal
234234
BigInteger.valueOf(-1L), // BigInteger
235235
IllegalArgumentException.class, // Enum<ClickHouseDataType>
@@ -262,7 +262,7 @@ public void testValue() throws Exception {
262262
1L, // long
263263
1.3333334F, // float
264264
1.3333333333333333D, // double
265-
BigDecimal.valueOf(1L), // BigDecimal
265+
BigDecimal.valueOf(4D / 3), // BigDecimal
266266
BigDecimal.valueOf(1333, 3), // BigDecimal
267267
BigInteger.ONE, // BigInteger
268268
ClickHouseDataType.values()[1].name(), // Enum<ClickHouseDataType>
@@ -294,7 +294,7 @@ public void testValue() throws Exception {
294294
-1L, // long
295295
-1.3333334F, // float
296296
-1.3333333333333333D, // double
297-
BigDecimal.valueOf(-1L), // BigDecimal
297+
BigDecimal.valueOf(-4D / 3), // BigDecimal
298298
BigDecimal.valueOf(-1333, 3), // BigDecimal
299299
BigInteger.valueOf(-1L), // BigInteger
300300
IllegalArgumentException.class, // Enum<ClickHouseDataType>

clickhouse-client/src/test/java/com/clickhouse/client/data/ClickHouseFloatValueTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public void testValue() throws Exception {
131131
0L, // long
132132
0F, // float
133133
0D, // double
134-
BigDecimal.valueOf(0L), // BigDecimal
134+
BigDecimal.ZERO, // BigDecimal
135135
new BigDecimal(BigInteger.ZERO, 3), // BigDecimal
136136
BigInteger.ZERO, // BigInteger
137137
ClickHouseDataType.values()[0].name(), // Enum<ClickHouseDataType>
@@ -163,7 +163,7 @@ public void testValue() throws Exception {
163163
1L, // long
164164
1F, // float
165165
1D, // double
166-
BigDecimal.valueOf(1L), // BigDecimal
166+
BigDecimal.ONE, // BigDecimal
167167
new BigDecimal(BigInteger.ONE, 3), // BigDecimal
168168
BigInteger.ONE, // BigInteger
169169
ClickHouseDataType.values()[1].name(), // Enum<ClickHouseDataType>
@@ -195,7 +195,7 @@ public void testValue() throws Exception {
195195
2L, // long
196196
2F, // float
197197
2D, // double
198-
BigDecimal.valueOf(2L), // BigDecimal
198+
BigDecimal.valueOf(2F), // BigDecimal
199199
new BigDecimal(BigInteger.valueOf(2L), 3), // BigDecimal
200200
BigInteger.valueOf(2L), // BigInteger
201201
ClickHouseDataType.values()[2].name(), // Enum<ClickHouseDataType>
@@ -228,7 +228,7 @@ public void testValue() throws Exception {
228228
-1L, // long
229229
-1F, // float
230230
-1D, // double
231-
BigDecimal.valueOf(-1L), // BigDecimal
231+
BigDecimal.valueOf(-1F), // BigDecimal
232232
new BigDecimal(BigInteger.valueOf(-1L), 3), // BigDecimal
233233
BigInteger.valueOf(-1L), // BigInteger
234234
IllegalArgumentException.class, // Enum<ClickHouseDataType>
@@ -261,7 +261,7 @@ public void testValue() throws Exception {
261261
1L, // long
262262
1.3333334F, // float
263263
(double) (4F / 3), // double
264-
BigDecimal.valueOf(1L), // BigDecimal
264+
new BigDecimal(Float.toString(4F / 3)), // BigDecimal
265265
BigDecimal.valueOf(1333, 3), // BigDecimal
266266
BigInteger.ONE, // BigInteger
267267
ClickHouseDataType.values()[1].name(), // Enum<ClickHouseDataType>
@@ -293,7 +293,7 @@ public void testValue() throws Exception {
293293
-1L, // long
294294
-1.3333334F, // float
295295
(double) (-4F / 3), // double
296-
BigDecimal.valueOf(-1L), // BigDecimal
296+
new BigDecimal(Float.toString(-4F / 3)), // BigDecimal
297297
BigDecimal.valueOf(-1333, 3), // BigDecimal
298298
BigInteger.valueOf(-1L), // BigInteger
299299
IllegalArgumentException.class, // Enum<ClickHouseDataType>

clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseResultSetTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ public void testFloatToBigDecimal() throws SQLException {
9797
+ "toDecimal64(-1.35, 1) n1, toDecimal64(-1.35, 2) n2")) {
9898
while (rs.next()) {
9999
ClickHouseRecord r = rs.unwrap(ClickHouseRecord.class);
100+
Assert.assertEquals(r.getValue("fp").asBigDecimal(), r.getValue("p2").asObject());
101+
Assert.assertEquals(r.getValue("fn").asBigDecimal(), r.getValue("n2").asObject());
102+
Assert.assertEquals(r.getValue("dp").asBigDecimal(), r.getValue("p2").asObject());
103+
Assert.assertEquals(r.getValue("dn").asBigDecimal(), r.getValue("n2").asObject());
100104
for (int i = 1; i <= 2; i++) {
101105
Assert.assertEquals(r.getValue("fp").asBigDecimal(i), r.getValue("p" + i).asObject());
102106
Assert.assertEquals(r.getValue("fn").asBigDecimal(i), r.getValue("n" + i).asObject());

0 commit comments

Comments
 (0)