Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jdbc/src/main/java/tech/ydb/jdbc/YdbConst.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public final class YdbConst {
public static final String UNABLE_TO_CONVERT = "Cannot cast [%s] with value [%s] to [%s]";
public static final String UNABLE_TO_CONVERT_AS_URL = "Cannot cast as URL: ";
public static final String UNABLE_TO_CAST_TO_CLASS = "Cannot cast [%s] to class [%s]";
public static final String UNABLE_TO_CAST_TO_DECIMAL = "Cannot cast to decimal type %s: [%s] is %s";

public static final String MISSING_VALUE_FOR_PARAMETER = "Missing value for parameter: ";
public static final String MISSING_REQUIRED_VALUE = "Missing required value for parameter: ";
Expand Down
28 changes: 1 addition & 27 deletions jdbc/src/main/java/tech/ydb/jdbc/common/MappingGetters.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,6 @@
import tech.ydb.table.values.Type;
import tech.ydb.table.values.Value;

import static tech.ydb.table.values.PrimitiveType.Bool;
import static tech.ydb.table.values.PrimitiveType.Bytes;
import static tech.ydb.table.values.PrimitiveType.Date;
import static tech.ydb.table.values.PrimitiveType.Datetime;
import static tech.ydb.table.values.PrimitiveType.Double;
import static tech.ydb.table.values.PrimitiveType.Float;
import static tech.ydb.table.values.PrimitiveType.Int16;
import static tech.ydb.table.values.PrimitiveType.Int32;
import static tech.ydb.table.values.PrimitiveType.Int64;
import static tech.ydb.table.values.PrimitiveType.Int8;
import static tech.ydb.table.values.PrimitiveType.Interval;
import static tech.ydb.table.values.PrimitiveType.Json;
import static tech.ydb.table.values.PrimitiveType.JsonDocument;
import static tech.ydb.table.values.PrimitiveType.Text;
import static tech.ydb.table.values.PrimitiveType.Timestamp;
import static tech.ydb.table.values.PrimitiveType.TzDate;
import static tech.ydb.table.values.PrimitiveType.TzDatetime;
import static tech.ydb.table.values.PrimitiveType.TzTimestamp;
import static tech.ydb.table.values.PrimitiveType.Uint16;
import static tech.ydb.table.values.PrimitiveType.Uint32;
import static tech.ydb.table.values.PrimitiveType.Uint64;
import static tech.ydb.table.values.PrimitiveType.Uint8;
import static tech.ydb.table.values.PrimitiveType.Uuid;
import static tech.ydb.table.values.PrimitiveType.Yson;
import static tech.ydb.table.values.Type.Kind.PRIMITIVE;

public class MappingGetters {
private MappingGetters() { }

Expand Down Expand Up @@ -95,7 +69,7 @@ static Getters buildGetters(Type type) {
value -> value.getDecimal().toBigDecimal().floatValue(),
value -> value.getDecimal().toBigDecimal().doubleValue(),
castToBytesNotSupported(clazz),
PrimitiveReader::getDecimal,
value -> value.getDecimal().toBigDecimal(),
castToClassNotSupported(clazz),
castToInstantNotSupported(clazz),
castToNStringNotSupported(clazz),
Expand Down
29 changes: 21 additions & 8 deletions jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java
Original file line number Diff line number Diff line change
Expand Up @@ -466,23 +466,36 @@ private static PrimitiveValue castToTimestamp(PrimitiveType type, Object x) thro
throw castNotSupported(type, x);
}

private static DecimalValue validateValue(DecimalType type, DecimalValue value, Object x) throws SQLException {
if (value.isInf()) {
throw new SQLException(String.format(YdbConst.UNABLE_TO_CAST_TO_DECIMAL, type, toString(x), "Infinite"));
}
if (value.isNegativeInf()) {
throw new SQLException(String.format(YdbConst.UNABLE_TO_CAST_TO_DECIMAL, type, toString(x), "-Infinite"));
}
if (value.isNan()) {
throw new SQLException(String.format(YdbConst.UNABLE_TO_CAST_TO_DECIMAL, type, toString(x), "NaN"));
}
return value;
}

private static DecimalValue castToDecimalValue(DecimalType type, Object x) throws SQLException {
if (x instanceof DecimalValue) {
return (DecimalValue) x;
return validateValue(type, (DecimalValue) x, x);
} else if (x instanceof BigDecimal) {
return type.newValue((BigDecimal) x);
return validateValue(type, type.newValue((BigDecimal) x), x);
} else if (x instanceof BigInteger) {
return type.newValue((BigInteger) x);
return validateValue(type, type.newValue((BigInteger) x), x);
} else if (x instanceof Long) {
return type.newValue((Long) x);
return validateValue(type, type.newValue((Long) x), x);
} else if (x instanceof Integer) {
return type.newValue((Integer) x);
return validateValue(type, type.newValue((Integer) x), x);
} else if (x instanceof Short) {
return type.newValue((Short) x);
return validateValue(type, type.newValue((Short) x), x);
} else if (x instanceof Byte) {
return type.newValue((Byte) x);
return validateValue(type, type.newValue((Byte) x), x);
} else if (x instanceof String) {
return type.newValue((String) x);
return validateValue(type, type.newValue((String) x), x);
}
throw castNotSupported(type.getKind(), x);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1636,7 +1636,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(311111156, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(311111, 223342000))
.typedValue(21, "c_Interval", Duration.parse("PT3.111113S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("3.335000000"));
.typedValue(22, "c_Decimal", new BigDecimal("3.335000000"));

checker.nextRow()
.typedValue(1, "key", 2)
Expand All @@ -1660,7 +1660,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(211211100, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(111111, 223342000))
.typedValue(21, "c_Interval", Duration.parse("PT3.112113S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("-3.335000000"));
.typedValue(22, "c_Decimal", new BigDecimal("-3.335000000"));

checker.nextRow()
.typedValue(1, "key", 3)
Expand All @@ -1684,7 +1684,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(0, 0))
.typedValue(21, "c_Interval", Duration.parse("PT0.000000S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("0.00000000"));
.typedValue(22, "c_Decimal", new BigDecimal("0.000000000"));

checker.nextRow()
.typedValue(1, "key", 4)
Expand All @@ -1708,7 +1708,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(1, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(0, 1000))
.typedValue(21, "c_Interval", Duration.parse("PT0.000001S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("1.00000000"));
.typedValue(22, "c_Decimal", new BigDecimal("1.000000000"));

checker.nextRow()
.value(1, "key", 5)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tech.ydb.jdbc.impl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
Expand Down Expand Up @@ -982,4 +983,74 @@ private void assertNextDate(ResultSet rs, int key, LocalDate ld) throws SQLExcep
Assertions.assertEquals(ld.atStartOfDay(), rs.getObject("c_Date", LocalDateTime.class));
Assertions.assertEquals(ld.atStartOfDay(ZoneId.systemDefault()).toInstant(), rs.getObject("c_Date", Instant.class));
}

@ParameterizedTest(name = "with {0}")
@EnumSource(SqlQueries.JdbcQuery.class)
public void decimalTest(SqlQueries.JdbcQuery query) throws SQLException {
String upsert = TEST_TABLE.upsertOne(query, "c_Decimal", "Decimal(22, 9)");

// YDB partially ignores Decimal(22, 9) limit, but have hard limit to 35 digits
String maxValue = "9999999999" + "9999999999" + "9999999999" + "99999";
BigDecimal closeToInf = new BigDecimal(new BigInteger(maxValue), 9);
BigDecimal closeToNegInf = new BigDecimal(new BigInteger(maxValue).negate(), 9);
try (PreparedStatement ps = jdbc.connection().prepareStatement(upsert)) {
ps.setInt(1, 1);
ps.setBigDecimal(2, BigDecimal.valueOf(1.5d));
ps.execute();

ps.setInt(1, 2);
ps.setBigDecimal(2, BigDecimal.valueOf(-12345, 10)); // will be rounded to -0.000001234
ps.execute();

ps.setInt(1, 3);
ps.setBigDecimal(2, closeToInf);
ps.execute();

ps.setInt(1, 4);
ps.setBigDecimal(2, closeToNegInf);
ps.execute();

ps.setInt(1, 5);
ExceptionAssert.sqlException(""
+ "Cannot cast to decimal type Decimal(22, 9): "
+ "[class java.math.BigDecimal: 100000000000000000000000000.000000000] is Infinite",
() -> ps.setBigDecimal(2, closeToInf.add(BigDecimal.valueOf(1, 9)))
);

ExceptionAssert.sqlException(""
+ "Cannot cast to decimal type Decimal(22, 9): "
+ "[class java.math.BigDecimal: -100000000000000000000000000.000000000] is -Infinite",
() -> ps.setBigDecimal(2, closeToNegInf.subtract(BigDecimal.valueOf(1, 9)))
);

ExceptionAssert.sqlException(""
+ "Cannot cast to decimal type Decimal(22, 9): "
+ "[class java.math.BigDecimal: 100000000000000000000000000.000000001] is NaN",
() -> ps.setBigDecimal(2, closeToInf.add(BigDecimal.valueOf(2, 9)))
);
}

try (Statement st = jdbc.connection().createStatement()) {
try (ResultSet rs = st.executeQuery(TEST_TABLE.selectColumn("c_Decimal"))) {
assertNextDecimal(rs, 1, BigDecimal.valueOf(1.5d).setScale(9));
assertNextDecimal(rs, 2, BigDecimal.valueOf(-1234, 9));
assertNextDecimal(rs, 3, closeToInf);
assertNextDecimal(rs, 4, closeToNegInf);

Assertions.assertFalse(rs.next());
}
}
};

private void assertNextDecimal(ResultSet rs, int key, BigDecimal bg) throws SQLException {
Assertions.assertTrue(rs.next());
Assertions.assertEquals(key, rs.getInt("key"));

Object obj = rs.getObject("c_Decimal");
Assertions.assertTrue(obj instanceof BigDecimal);
Assertions.assertEquals(bg, obj);

BigDecimal decimal = rs.getBigDecimal("c_Decimal");
Assertions.assertEquals(bg, decimal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(311111156, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(311111, 223342000))
.typedValue(21, "c_Interval", Duration.parse("PT3.111113S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("3.335000000"));
.typedValue(22, "c_Decimal", new BigDecimal("3.335000000"));

checker.nextRow()
.typedValue(1, "key", 2)
Expand All @@ -1821,7 +1821,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(211211100, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(111111, 223342000))
.typedValue(21, "c_Interval", Duration.parse("PT3.112113S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("-3.335000000"));
.typedValue(22, "c_Decimal", new BigDecimal("-3.335000000"));

checker.nextRow()
.typedValue(1, "key", 3)
Expand All @@ -1845,7 +1845,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(0, 0))
.typedValue(21, "c_Interval", Duration.parse("PT0.000000S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("0.00000000"));
.typedValue(22, "c_Decimal", new BigDecimal("0.000000000"));

checker.nextRow()
.typedValue(1, "key", 4)
Expand All @@ -1869,7 +1869,7 @@ public void getObject() throws SQLException {
.typedValue(19, "c_Datetime", LocalDateTime.ofEpochSecond(1, 0, ZoneOffset.UTC))
.typedValue(20, "c_Timestamp", Instant.ofEpochSecond(0, 1000))
.typedValue(21, "c_Interval", Duration.parse("PT0.000001S"))
.typedValue(22, "c_Decimal", DecimalType.getDefault().newValue("1.00000000"));
.typedValue(22, "c_Decimal", new BigDecimal("1.000000000"));

checker.nextRow()
.value(1, "key", 5)
Expand Down