Skip to content

Commit

Permalink
[CONJ-994] supporting setObject with data type not corresponding to S…
Browse files Browse the repository at this point in the history
…QLType
  • Loading branch information
rusher committed Jul 26, 2022
1 parent fec0708 commit 40e52c2
Show file tree
Hide file tree
Showing 13 changed files with 348 additions and 15 deletions.
173 changes: 163 additions & 10 deletions src/main/java/org/mariadb/jdbc/BasePreparedStatement.java
Expand Up @@ -605,7 +605,7 @@ public void clearParameters() throws SQLException {
*/
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
setInternalObject(parameterIndex, x, null);
setInternalObject(parameterIndex, x, targetSqlType, null);
}

/**
Expand Down Expand Up @@ -641,7 +641,7 @@ public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQ
*/
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
setInternalObject(parameterIndex, x, null);
setInternalObject(parameterIndex, x, null, null);
}

/**
Expand Down Expand Up @@ -1080,27 +1080,172 @@ private ExceptionFactory exceptionFactory() {
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
throws SQLException {
setInternalObject(parameterIndex, x, (long) scaleOrLength);
setInternalObject(parameterIndex, x, targetSqlType, (long) scaleOrLength);
}

@SuppressWarnings({"unchecked", "rawtypes"})
private void setInternalObject(int parameterIndex, Object x, Long scaleOrLength)
private void setInternalObject(
int parameterIndex, Object obj, Integer targetSqlType, Long scaleOrLength)
throws SQLException {
checkIndex(parameterIndex);
if (x == null) {
if (obj == null) {
parameters.set(parameterIndex - 1, Parameter.NULL_PARAMETER);
return;
}

if (targetSqlType != null) {
// target type is defined.
// in case of not corresponding data type, converting
switch (targetSqlType) {
case Types.ARRAY:
case Types.DATALINK:
case Types.JAVA_OBJECT:
case Types.REF:
case Types.ROWID:
case Types.SQLXML:
case Types.STRUCT:
throw exceptionFactory().notSupported("Type not supported");
default:
break;
}

if (obj instanceof String || obj instanceof Character) {
if (targetSqlType == Types.BLOB) {
throw exceptionFactory()
.create(
String.format(
"Cannot convert a %s to a Blob",
obj instanceof String ? "string" : "character"));
}
String str = obj instanceof String ? (String) obj : ((Character) obj).toString();
try {
switch (targetSqlType) {
case Types.BIT:
case Types.BOOLEAN:
setBoolean(parameterIndex, !("false".equalsIgnoreCase(str) || "0".equals(str)));
return;
case Types.TINYINT:
setByte(parameterIndex, Byte.parseByte(str));
return;
case Types.SMALLINT:
setShort(parameterIndex, Short.parseShort(str));
return;
case Types.INTEGER:
setInt(parameterIndex, Integer.parseInt(str));
return;
case Types.DOUBLE:
case Types.FLOAT:
setDouble(parameterIndex, Double.valueOf(str));
return;
case Types.REAL:
setFloat(parameterIndex, Float.valueOf(str));
return;
case Types.BIGINT:
setLong(parameterIndex, Long.valueOf(str));
return;
case Types.DECIMAL:
case Types.NUMERIC:
setBigDecimal(parameterIndex, new BigDecimal(str));
return;
case Types.CLOB:
case Types.NCLOB:
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.NCHAR:
case Types.NVARCHAR:
case Types.LONGNVARCHAR:
setString(parameterIndex, str);
return;
case Types.TIMESTAMP:
if (str.startsWith("0000-00-00")) {
setTimestamp(parameterIndex, null);
} else {
setTimestamp(parameterIndex, Timestamp.valueOf(str));
}
return;
case Types.TIME:
setTime(parameterIndex, Time.valueOf((String) obj));
return;
default:
throw exceptionFactory()
.create(String.format("Could not convert [%s] to %s", str, targetSqlType));
}
} catch (IllegalArgumentException e) {
throw exceptionFactory()
.create(
String.format("Could not convert [%s] to java.sql.Type %s", str, targetSqlType),
"HY000",
e);
}
} else if (obj instanceof Number) {
Number bd = (Number) obj;
switch (targetSqlType) {
case Types.TINYINT:
setByte(parameterIndex, bd.byteValue());
return;
case Types.SMALLINT:
setShort(parameterIndex, bd.shortValue());
return;
case Types.INTEGER:
setInt(parameterIndex, bd.intValue());
return;
case Types.BIGINT:
setLong(parameterIndex, bd.longValue());
return;
case Types.FLOAT:
case Types.DOUBLE:
setDouble(parameterIndex, bd.doubleValue());
return;
case Types.REAL:
setFloat(parameterIndex, bd.floatValue());
return;
case Types.DECIMAL:
case Types.NUMERIC:
if (obj instanceof BigDecimal) {
setBigDecimal(parameterIndex, (BigDecimal) obj);
} else if (obj instanceof Double || obj instanceof Float) {
setDouble(parameterIndex, bd.doubleValue());
} else {
setLong(parameterIndex, bd.longValue());
}
return;
case Types.BIT:
setBoolean(parameterIndex, bd.shortValue() != 0);
return;
case Types.CHAR:
case Types.VARCHAR:
setString(parameterIndex, bd.toString());
return;
default:
throw exceptionFactory()
.create(String.format("Could not convert [%s] to %s", bd, targetSqlType));
}
} else if (obj instanceof byte[]) {
if (targetSqlType == Types.BINARY
|| targetSqlType == Types.VARBINARY
|| targetSqlType == Types.LONGVARBINARY) {
setBytes(parameterIndex, (byte[]) obj);
return;
} else if (targetSqlType == Types.BLOB) {
setBlob(parameterIndex, new MariaDbBlob((byte[]) obj));
} else {
throw exceptionFactory()
.create("Can only convert a byte[] to BINARY, VARBINARY, LONGVARBINARY or BLOB type");
}
}
}

// in case parameter still not set, defaulting to object type
for (Codec<?> codec : con.getContext().getConf().codecs()) {
if (codec.canEncode(x)) {
Parameter p = new Parameter(codec, x, scaleOrLength);
if (codec.canEncode(obj)) {
Parameter p = new Parameter(codec, obj, scaleOrLength);
parameters.set(parameterIndex - 1, p);
return;
}
}

throw new SQLException(String.format("Type %s not supported type", x.getClass().getName()));
throw new SQLException(String.format("Type %s not supported type", obj.getClass().getName()));
}

/**
Expand Down Expand Up @@ -1401,7 +1546,11 @@ public void setNClob(int parameterIndex, Reader reader) throws SQLException {
@Override
public void setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength)
throws SQLException {
setInternalObject(parameterIndex, x, (long) scaleOrLength);
setInternalObject(
parameterIndex,
x,
targetSqlType == null ? null : targetSqlType.getVendorTypeNumber(),
(long) scaleOrLength);
}

/**
Expand All @@ -1426,6 +1575,10 @@ public void setObject(int parameterIndex, Object x, SQLType targetSqlType, int s
*/
@Override
public void setObject(int parameterIndex, Object x, SQLType targetSqlType) throws SQLException {
setInternalObject(parameterIndex, x, null);
setInternalObject(
parameterIndex,
x,
targetSqlType == null ? null : targetSqlType.getVendorTypeNumber(),
null);
}
}
Expand Up @@ -916,7 +916,7 @@ public void useNoDatabase() throws SQLException {
try (Connection con = createCon()) {
con.getCatalog();
Statement stmt = con.createStatement();
stmt.execute("CREATE DATABASE someDb");
stmt.execute("CREATE DATABASE IF NOT EXISTS someDb");
con.setCatalog("someDb");
stmt.execute("DROP DATABASE someDb");
if (minVersion(10, 4, 0)
Expand Down
18 changes: 18 additions & 0 deletions src/test/java/org/mariadb/jdbc/integration/StatementTest.java
Expand Up @@ -131,6 +131,24 @@ public void getConnection() throws SQLException {
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, stmt.getResultSetHoldability());
}

@Test
public void setObjectError() throws SQLException {
try (PreparedStatement prep = sharedConn.prepareStatement("SELECT ?")) {
assertThrowsContains(
SQLException.class, () -> prep.setObject(1, "", Types.ARRAY), "Type not supported");
assertThrowsContains(
SQLException.class, () -> prep.setObject(1, "", JDBCType.ARRAY), "Type not supported");
assertThrowsContains(
SQLException.class,
() -> prep.setObject(1, "a", JDBCType.BLOB),
"Cannot convert a string to a Blob");
assertThrowsContains(
SQLException.class,
() -> prep.setObject(1, 'a', JDBCType.BLOB),
"Cannot convert a character to a Blob");
}
}

@Test
public void conj956() throws SQLException {
StringBuilder sb = new StringBuilder();
Expand Down
Expand Up @@ -694,6 +694,10 @@ private void sendParam(Connection con) throws SQLException {
prep.execute();
prep.setObject(1, null, Types.BINARY);
prep.execute();
prep.setObject(1, 0, Types.BIT);
prep.execute();
prep.setObject(1, 1, Types.BIT);
prep.execute();
}

ResultSet rs =
Expand Down Expand Up @@ -722,6 +726,10 @@ private void sendParam(Connection con) throws SQLException {
rs.updateObject("t1", BitSet.valueOf(new byte[] {0x04, 0x00}), Types.BINARY);
rs.updateRow();
assertEquals("b'100'", rs.getString(2));
assertTrue(rs.next());
assertEquals("b''", rs.getString(2));
assertTrue(rs.next());
assertEquals("b'1'", rs.getString(2));

rs = stmt.executeQuery("SELECT * FROM BitCodec2");
assertTrue(rs.next());
Expand Down
Expand Up @@ -1046,6 +1046,10 @@ private void sendParam(Connection con) throws SQLException {
prep.execute();
prep.setObject(1, LocalDateTime.parse("2010-01-12T01:55:12.987765"), Types.TIMESTAMP);
prep.execute();
prep.setObject(1, "2010-01-12 01:55:12.987765", Types.TIMESTAMP);
prep.execute();
prep.setObject(1, "0000-00-00 00:00:00", Types.TIMESTAMP);
prep.execute();
prep.setObject(1, LocalDateTime.parse("2010-01-12T01:56:12.456"), Types.TIMESTAMP);
prep.execute();
prep.setObject(
Expand Down Expand Up @@ -1082,6 +1086,10 @@ private void sendParam(Connection con) throws SQLException {
prep.execute();
prep.setObject(1, offsetDtCurrent);
prep.execute();
assertThrowsContains(
SQLException.class,
() -> prep.setObject(1, "2010-aaa", Types.TIMESTAMP),
"Could not convert [2010-aaa] to java.sql.Type 93");
}

ResultSet rs =
Expand Down Expand Up @@ -1128,6 +1136,11 @@ private void sendParam(Connection con) throws SQLException {
rs.updateTimestamp("t1", Timestamp.valueOf("2015-12-12 01:55:12.654321"));
rs.updateRow();
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654321"), rs.getTimestamp(2));
assertTrue(rs.next());
assertEquals(
LocalDateTime.parse("2010-01-12T01:55:12.987765"), rs.getObject(2, LocalDateTime.class));
assertTrue(rs.next());
assertNull(rs.getObject(2, LocalDateTime.class));

rs = stmt.executeQuery("SELECT * FROM DateTimeCodec2");
assertTrue(rs.next());
Expand All @@ -1147,6 +1160,9 @@ private void sendParam(Connection con) throws SQLException {
assertTrue(rs.next());
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654321"), rs.getTimestamp(2));
assertTrue(rs.next());
assertEquals(Timestamp.valueOf("2010-01-12 01:55:12.987765"), rs.getTimestamp(2));
assertTrue(rs.next());
assertTrue(rs.next());
assertEquals(
LocalDateTime.parse("2010-01-12T01:56:12.456"), rs.getObject(2, LocalDateTime.class));

Expand Down
Expand Up @@ -818,6 +818,14 @@ private void sendParam(Connection con) throws SQLException {
prep.execute();
prep.setObject(1, BigDecimal.valueOf(3), Types.DECIMAL);
prep.execute();
prep.setObject(1, "4", Types.DECIMAL);
prep.execute();
prep.setObject(1, "5", Types.NUMERIC);
prep.execute();
prep.setObject(1, 7D, JDBCType.NUMERIC);
prep.execute();
prep.setObject(1, "6", Types.BIGINT);
prep.execute();
prep.setObject(1, null, Types.DECIMAL);
prep.execute();
}
Expand Down Expand Up @@ -856,6 +864,18 @@ private void sendParam(Connection con) throws SQLException {
rs.updateRow();
assertNull(rs.getBigDecimal(2));

assertTrue(rs.next());
assertEquals("4", rs.getBigDecimal(2).toString());

assertTrue(rs.next());
assertEquals("5", rs.getBigDecimal(2).toString());

assertTrue(rs.next());
assertEquals("7", rs.getBigDecimal(2).toString());

assertTrue(rs.next());
assertEquals("6", rs.getBigDecimal(2).toString());

assertTrue(rs.next());
assertNull(rs.getString(2));
rs.updateObject(2, BigDecimal.valueOf(30), Types.DECIMAL);
Expand All @@ -879,6 +899,15 @@ private void sendParam(Connection con) throws SQLException {
assertTrue(rs.next());
assertNull(rs.getBigDecimal(2));

assertTrue(rs.next());
assertEquals("4", rs.getBigDecimal(2).toString());
assertTrue(rs.next());
assertEquals("5", rs.getBigDecimal(2).toString());
assertTrue(rs.next());
assertEquals("7", rs.getBigDecimal(2).toString());
assertTrue(rs.next());
assertEquals("6", rs.getBigDecimal(2).toString());

assertTrue(rs.next());
assertEquals(BigDecimal.valueOf(30), rs.getBigDecimal(2));
}
Expand Down

0 comments on commit 40e52c2

Please sign in to comment.