mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 10:25:15 +00:00
JDBC driver prepared statement set* methods (#31494)
Added setObject functionality and tests for it
This commit is contained in:
parent
a35b5341c4
commit
400db4f37d
@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.jdbc.jdbc;
|
||||
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
@ -21,13 +23,24 @@ import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Struct;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.OffsetTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
final PreparedQuery query;
|
||||
@ -74,67 +87,67 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.BOOLEAN);
|
||||
setObject(parameterIndex, x, Types.BOOLEAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setByte(int parameterIndex, byte x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.TINYINT);
|
||||
setObject(parameterIndex, x, Types.TINYINT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShort(int parameterIndex, short x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.SMALLINT);
|
||||
setObject(parameterIndex, x, Types.SMALLINT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInt(int parameterIndex, int x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.INTEGER);
|
||||
setObject(parameterIndex, x, Types.INTEGER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLong(int parameterIndex, long x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.BIGINT);
|
||||
setObject(parameterIndex, x, Types.BIGINT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloat(int parameterIndex, float x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.REAL);
|
||||
setObject(parameterIndex, x, Types.REAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDouble(int parameterIndex, double x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.DOUBLE);
|
||||
setObject(parameterIndex, x, Types.DOUBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("BigDecimal not supported");
|
||||
setObject(parameterIndex, x, Types.BIGINT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setString(int parameterIndex, String x) throws SQLException {
|
||||
setParam(parameterIndex, x, Types.VARCHAR);
|
||||
setObject(parameterIndex, x, Types.VARCHAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
|
||||
throw new UnsupportedOperationException("Bytes not implemented yet");
|
||||
setObject(parameterIndex, x, Types.VARBINARY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x) throws SQLException {
|
||||
throw new UnsupportedOperationException("Date/Time not implemented yet");
|
||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x) throws SQLException {
|
||||
throw new UnsupportedOperationException("Date/Time not implemented yet");
|
||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
|
||||
throw new UnsupportedOperationException("Date/Time not implemented yet");
|
||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,12 +174,22 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
|
||||
throw new UnsupportedOperationException("Object not implemented yet");
|
||||
// the value of scaleOrLength parameter doesn't matter, as it's not used in the called method below
|
||||
setObject(parameterIndex, x, targetSqlType, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("CharacterStream not supported");
|
||||
if (x == null) {
|
||||
setParam(parameterIndex, null, Types.NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// check also here the unsupported types so that any unsupported interfaces ({@code java.sql.Struct},
|
||||
// {@code java.sql.Array} etc) will generate the correct exception message. Otherwise, the method call
|
||||
// {@code TypeConverter.fromJavaToJDBC(x.getClass())} will report the implementing class as not being supported.
|
||||
checkKnownUnsupportedTypes(x);
|
||||
setObject(parameterIndex, x, TypeConverter.fromJavaToJDBC(x.getClass()).getVendorTypeNumber(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,22 +204,22 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setRef(int parameterIndex, Ref x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("Ref not supported");
|
||||
setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, Blob x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("Blob not supported");
|
||||
setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Clob x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("Clob not supported");
|
||||
setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArray(int parameterIndex, Array x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("Array not supported");
|
||||
setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -206,17 +229,44 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
|
||||
throw new UnsupportedOperationException("Dates not implemented yet");
|
||||
if (cal == null) {
|
||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
||||
return;
|
||||
}
|
||||
if (x == null) {
|
||||
setNull(parameterIndex, Types.TIMESTAMP);
|
||||
return;
|
||||
}
|
||||
// converting to UTC since this is what ES is storing internally
|
||||
setObject(parameterIndex, new Date(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)), Types.TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
|
||||
throw new UnsupportedOperationException("Dates not implemented yet");
|
||||
if (cal == null) {
|
||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
||||
return;
|
||||
}
|
||||
if (x == null) {
|
||||
setNull(parameterIndex, Types.TIMESTAMP);
|
||||
return;
|
||||
}
|
||||
// converting to UTC since this is what ES is storing internally
|
||||
setObject(parameterIndex, new Time(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)), Types.TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
|
||||
throw new UnsupportedOperationException("Dates not implemented yet");
|
||||
if (cal == null) {
|
||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
||||
return;
|
||||
}
|
||||
if (x == null) {
|
||||
setNull(parameterIndex, Types.TIMESTAMP);
|
||||
return;
|
||||
}
|
||||
// converting to UTC since this is what ES is storing internally
|
||||
setObject(parameterIndex, new Timestamp(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)), Types.TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -226,7 +276,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setURL(int parameterIndex, URL x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("Datalink not supported");
|
||||
setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -236,7 +286,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setRowId(int parameterIndex, RowId x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("RowId not supported");
|
||||
setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,7 +301,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, NClob value) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("NClob not supported");
|
||||
setObject(parameterIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -271,12 +321,108 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||
|
||||
@Override
|
||||
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("SQLXML not supported");
|
||||
setObject(parameterIndex, xmlObject);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
|
||||
throw new UnsupportedOperationException("Object not implemented yet");
|
||||
checkOpen();
|
||||
|
||||
JDBCType targetJDBCType;
|
||||
try {
|
||||
// this is also a way to check early for the validity of the desired sql type
|
||||
targetJDBCType = JDBCType.valueOf(targetSqlType);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SQLDataException(e.getMessage());
|
||||
}
|
||||
|
||||
// set the null value on the type and exit
|
||||
if (x == null) {
|
||||
setParam(parameterIndex, null, targetSqlType);
|
||||
return;
|
||||
}
|
||||
|
||||
checkKnownUnsupportedTypes(x);
|
||||
if (x instanceof byte[]) {
|
||||
if (targetJDBCType != JDBCType.VARBINARY) {
|
||||
throw new SQLFeatureNotSupportedException(
|
||||
"Conversion from type byte[] to " + targetJDBCType + " not supported");
|
||||
}
|
||||
setParam(parameterIndex, x, Types.VARBINARY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (x instanceof Timestamp
|
||||
|| x instanceof Calendar
|
||||
|| x instanceof Date
|
||||
|| x instanceof LocalDateTime
|
||||
|| x instanceof Time
|
||||
|| x instanceof java.util.Date)
|
||||
{
|
||||
if (targetJDBCType == JDBCType.TIMESTAMP) {
|
||||
// converting to {@code java.util.Date} because this is the type supported by {@code XContentBuilder} for serialization
|
||||
java.util.Date dateToSet;
|
||||
if (x instanceof Timestamp) {
|
||||
dateToSet = new java.util.Date(((Timestamp) x).getTime());
|
||||
} else if (x instanceof Calendar) {
|
||||
dateToSet = ((Calendar) x).getTime();
|
||||
} else if (x instanceof Date) {
|
||||
dateToSet = new java.util.Date(((Date) x).getTime());
|
||||
} else if (x instanceof LocalDateTime){
|
||||
LocalDateTime ldt = (LocalDateTime) x;
|
||||
Calendar cal = getDefaultCalendar();
|
||||
cal.set(ldt.getYear(), ldt.getMonthValue() - 1, ldt.getDayOfMonth(), ldt.getHour(), ldt.getMinute(), ldt.getSecond());
|
||||
|
||||
dateToSet = cal.getTime();
|
||||
} else if (x instanceof Time) {
|
||||
dateToSet = new java.util.Date(((Time) x).getTime());
|
||||
} else {
|
||||
dateToSet = (java.util.Date) x;
|
||||
}
|
||||
|
||||
setParam(parameterIndex, dateToSet, Types.TIMESTAMP);
|
||||
return;
|
||||
} else if (targetJDBCType == JDBCType.VARCHAR) {
|
||||
setParam(parameterIndex, String.valueOf(x), Types.VARCHAR);
|
||||
return;
|
||||
}
|
||||
// anything else other than VARCHAR and TIMESTAMP is not supported in this JDBC driver
|
||||
throw new SQLFeatureNotSupportedException(
|
||||
"Conversion from type " + x.getClass().getName() + " to " + targetJDBCType + " not supported");
|
||||
}
|
||||
|
||||
if (x instanceof Boolean
|
||||
|| x instanceof Byte
|
||||
|| x instanceof Short
|
||||
|| x instanceof Integer
|
||||
|| x instanceof Long
|
||||
|| x instanceof Float
|
||||
|| x instanceof Double
|
||||
|| x instanceof String) {
|
||||
setParam(parameterIndex,
|
||||
TypeConverter.convert(x, TypeConverter.fromJavaToJDBC(x.getClass()), DataType.fromJdbcTypeToJava(targetJDBCType)),
|
||||
targetSqlType);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new SQLFeatureNotSupportedException(
|
||||
"Conversion from type " + x.getClass().getName() + " to " + targetJDBCType + " not supported");
|
||||
}
|
||||
|
||||
private void checkKnownUnsupportedTypes(Object x) throws SQLFeatureNotSupportedException {
|
||||
List<Class<?>> unsupportedTypes = new ArrayList<Class<?>>(Arrays.asList(Struct.class, Array.class, SQLXML.class,
|
||||
RowId.class, Ref.class, Blob.class, NClob.class, Clob.class, LocalDate.class, LocalTime.class,
|
||||
OffsetTime.class, OffsetDateTime.class, URL.class, BigDecimal.class));
|
||||
|
||||
for (Class<?> clazz:unsupportedTypes) {
|
||||
if (clazz.isAssignableFrom(x.getClass())) {
|
||||
throw new SQLFeatureNotSupportedException("Objects of type " + clazz.getName() + " are not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Calendar getDefaultCalendar() {
|
||||
return Calendar.getInstance(cfg.timeZone(), Locale.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -359,14 +359,6 @@ class JdbcResultSet implements ResultSet, JdbcWrapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type != null && type.isInstance(val)) {
|
||||
try {
|
||||
return type.cast(val);
|
||||
} catch (ClassCastException cce) {
|
||||
throw new SQLException("unable to convert column " + columnIndex + " to " + type, cce);
|
||||
}
|
||||
}
|
||||
|
||||
JDBCType columnType = cursor.columns().get(columnIndex - 1).type;
|
||||
|
||||
return TypeConverter.convert(val, columnType, type);
|
||||
|
@ -10,7 +10,9 @@ import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.JDBCType;
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDate;
|
||||
@ -18,10 +20,17 @@ import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.OffsetTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Calendar.DAY_OF_MONTH;
|
||||
@ -48,6 +57,22 @@ final class TypeConverter {
|
||||
}
|
||||
|
||||
private static final long DAY_IN_MILLIS = 60 * 60 * 24;
|
||||
private static final Map<Class<?>, JDBCType> javaToJDBC;
|
||||
|
||||
static {
|
||||
Map<Class<?>, JDBCType> aMap = Arrays.stream(DataType.values())
|
||||
.filter(dataType -> dataType.javaClass() != null
|
||||
&& dataType != DataType.HALF_FLOAT
|
||||
&& dataType != DataType.SCALED_FLOAT
|
||||
&& dataType != DataType.TEXT)
|
||||
.collect(Collectors.toMap(dataType -> dataType.javaClass(), dataType -> dataType.jdbcType));
|
||||
// apart from the mappings in {@code DataType} three more Java classes can be mapped to a {@code JDBCType.TIMESTAMP}
|
||||
// according to B-4 table from the jdbc4.2 spec
|
||||
aMap.put(Calendar.class, JDBCType.TIMESTAMP);
|
||||
aMap.put(java.util.Date.class, JDBCType.TIMESTAMP);
|
||||
aMap.put(LocalDateTime.class, JDBCType.TIMESTAMP);
|
||||
javaToJDBC = Collections.unmodifiableMap(aMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts millisecond after epoc to date
|
||||
@ -94,6 +119,20 @@ final class TypeConverter {
|
||||
c.setTimeInMillis(initial);
|
||||
}
|
||||
}
|
||||
|
||||
static long convertFromCalendarToUTC(long value, Calendar cal) {
|
||||
if (cal == null) {
|
||||
return value;
|
||||
}
|
||||
Calendar c = (Calendar) cal.clone();
|
||||
c.setTimeInMillis(value);
|
||||
|
||||
ZonedDateTime convertedDateTime = ZonedDateTime
|
||||
.ofInstant(c.toInstant(), c.getTimeZone().toZoneId())
|
||||
.withZoneSameLocal(ZoneOffset.UTC);
|
||||
|
||||
return convertedDateTime.toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts object val from columnType to type
|
||||
@ -103,6 +142,15 @@ final class TypeConverter {
|
||||
if (type == null) {
|
||||
return (T) convert(val, columnType);
|
||||
}
|
||||
|
||||
if (type.isInstance(val)) {
|
||||
try {
|
||||
return type.cast(val);
|
||||
} catch (ClassCastException cce) {
|
||||
throw new SQLDataException("Unable to convert " + val.getClass().getName() + " to " + columnType, cce);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == String.class) {
|
||||
return (T) asString(convert(val, columnType));
|
||||
}
|
||||
@ -174,10 +222,10 @@ final class TypeConverter {
|
||||
// Convert unsupported exception to JdbcSQLException
|
||||
throw new JdbcSQLException(ex, ex.getMessage());
|
||||
}
|
||||
if (dataType.javaName == null) {
|
||||
if (dataType.javaClass() == null) {
|
||||
throw new JdbcSQLException("Unsupported JDBC type [" + jdbcType + "]");
|
||||
}
|
||||
return dataType.javaName;
|
||||
return dataType.javaClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,6 +276,18 @@ final class TypeConverter {
|
||||
}
|
||||
return dataType.isSigned();
|
||||
}
|
||||
|
||||
|
||||
static JDBCType fromJavaToJDBC(Class<?> clazz) throws SQLException {
|
||||
for (Entry<Class<?>, JDBCType> e : javaToJDBC.entrySet()) {
|
||||
// java.util.Calendar from {@code javaToJDBC} is an abstract class and this method can be used with concrete classes as well
|
||||
if (e.getKey().isAssignableFrom(clazz)) {
|
||||
return e.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
throw new SQLFeatureNotSupportedException("Objects of type " + clazz.getName() + " are not supported");
|
||||
}
|
||||
|
||||
private static Double doubleValue(Object v) {
|
||||
if (v instanceof String) {
|
||||
@ -275,7 +335,7 @@ final class TypeConverter {
|
||||
case REAL:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
return Boolean.valueOf(Integer.signum(((Number) val).intValue()) == 0);
|
||||
return Boolean.valueOf(Integer.signum(((Number) val).intValue()) != 0);
|
||||
default:
|
||||
throw new SQLException("Conversion from type [" + columnType + "] to [Boolean] not supported");
|
||||
|
||||
@ -454,28 +514,28 @@ final class TypeConverter {
|
||||
|
||||
private static byte safeToByte(long x) throws SQLException {
|
||||
if (x > Byte.MAX_VALUE || x < Byte.MIN_VALUE) {
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %d out of range", Long.toString(x)));
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Long.toString(x)));
|
||||
}
|
||||
return (byte) x;
|
||||
}
|
||||
|
||||
private static short safeToShort(long x) throws SQLException {
|
||||
if (x > Short.MAX_VALUE || x < Short.MIN_VALUE) {
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %d out of range", Long.toString(x)));
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Long.toString(x)));
|
||||
}
|
||||
return (short) x;
|
||||
}
|
||||
|
||||
private static int safeToInt(long x) throws SQLException {
|
||||
if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) {
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %d out of range", Long.toString(x)));
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Long.toString(x)));
|
||||
}
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
private static long safeToLong(double x) throws SQLException {
|
||||
if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) {
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %d out of range", Double.toString(x)));
|
||||
throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Double.toString(x)));
|
||||
}
|
||||
return Math.round(x);
|
||||
}
|
||||
|
@ -0,0 +1,582 @@
|
||||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.jdbc.jdbc;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.JDBCType;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Struct;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.sql.JDBCType.BIGINT;
|
||||
import static java.sql.JDBCType.BOOLEAN;
|
||||
import static java.sql.JDBCType.DOUBLE;
|
||||
import static java.sql.JDBCType.FLOAT;
|
||||
import static java.sql.JDBCType.INTEGER;
|
||||
import static java.sql.JDBCType.REAL;
|
||||
import static java.sql.JDBCType.SMALLINT;
|
||||
import static java.sql.JDBCType.TIMESTAMP;
|
||||
import static java.sql.JDBCType.TINYINT;
|
||||
import static java.sql.JDBCType.VARBINARY;
|
||||
import static java.sql.JDBCType.VARCHAR;
|
||||
|
||||
public class JdbcPreparedStatementTests extends ESTestCase {
|
||||
|
||||
public void testSettingBooleanValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
jps.setBoolean(1, true);
|
||||
assertEquals(true, value(jps));
|
||||
assertEquals(BOOLEAN, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, false);
|
||||
assertEquals(false, value(jps));
|
||||
assertEquals(BOOLEAN, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, true, Types.BOOLEAN);
|
||||
assertEquals(true, value(jps));
|
||||
assertEquals(BOOLEAN, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Boolean);
|
||||
|
||||
jps.setObject(1, true, Types.INTEGER);
|
||||
assertEquals(1, value(jps));
|
||||
assertEquals(INTEGER, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, true, Types.VARCHAR);
|
||||
assertEquals("true", value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingBooleanValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, true, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [BOOLEAN] to [Timestamp] not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingStringValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
jps.setString(1, "foo bar");
|
||||
assertEquals("foo bar", value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, "foo bar");
|
||||
assertEquals("foo bar", value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, "foo bar", Types.VARCHAR);
|
||||
assertEquals("foo bar", value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof String);
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingStringValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, "foo bar", Types.INTEGER));
|
||||
assertEquals("Conversion from type [VARCHAR] to [Integer] not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingByteTypeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
jps.setByte(1, (byte) 6);
|
||||
assertEquals((byte) 6, value(jps));
|
||||
assertEquals(TINYINT, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, (byte) 6);
|
||||
assertEquals((byte) 6, value(jps));
|
||||
assertEquals(TINYINT, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Byte);
|
||||
|
||||
jps.setObject(1, (byte) 0, Types.BOOLEAN);
|
||||
assertEquals(false, value(jps));
|
||||
assertEquals(BOOLEAN, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, (byte) 123, Types.BOOLEAN);
|
||||
assertEquals(true, value(jps));
|
||||
assertEquals(BOOLEAN, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, (byte) 123, Types.INTEGER);
|
||||
assertEquals(123, value(jps));
|
||||
assertEquals(INTEGER, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, (byte) -128, Types.DOUBLE);
|
||||
assertEquals(-128.0, value(jps));
|
||||
assertEquals(DOUBLE, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingByteTypeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, (byte) 6, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [TINYINT] to [Timestamp] not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingShortTypeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
short someShort = randomShort();
|
||||
jps.setShort(1, someShort);
|
||||
assertEquals(someShort, value(jps));
|
||||
assertEquals(SMALLINT, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someShort);
|
||||
assertEquals(someShort, value(jps));
|
||||
assertEquals(SMALLINT, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Short);
|
||||
|
||||
jps.setObject(1, (short) 1, Types.BOOLEAN);
|
||||
assertEquals(true, value(jps));
|
||||
assertEquals(BOOLEAN, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, (short) -32700, Types.DOUBLE);
|
||||
assertEquals(-32700.0, value(jps));
|
||||
assertEquals(DOUBLE, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someShort, Types.INTEGER);
|
||||
assertEquals((int) someShort, value(jps));
|
||||
assertEquals(INTEGER, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingShortTypeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, (short) 6, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [SMALLINT] to [Timestamp] not supported", sqle.getMessage());
|
||||
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, 256, Types.TINYINT));
|
||||
assertEquals("Numeric " + 256 + " out of range", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingIntegerValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
int someInt = randomInt();
|
||||
jps.setInt(1, someInt);
|
||||
assertEquals(someInt, value(jps));
|
||||
assertEquals(INTEGER, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someInt);
|
||||
assertEquals(someInt, value(jps));
|
||||
assertEquals(INTEGER, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Integer);
|
||||
|
||||
jps.setObject(1, someInt, Types.VARCHAR);
|
||||
assertEquals(String.valueOf(someInt), value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someInt, Types.FLOAT);
|
||||
assertEquals(Double.valueOf(someInt), value(jps));
|
||||
assertTrue(value(jps) instanceof Double);
|
||||
assertEquals(FLOAT, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingIntegerValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
int someInt = randomInt();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, someInt, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [INTEGER] to [Timestamp] not supported", sqle.getMessage());
|
||||
|
||||
Integer randomIntNotShort = randomIntBetween(32768, Integer.MAX_VALUE);
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, randomIntNotShort, Types.SMALLINT));
|
||||
assertEquals("Numeric " + randomIntNotShort + " out of range", sqle.getMessage());
|
||||
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, randomIntNotShort, Types.TINYINT));
|
||||
assertEquals("Numeric " + randomIntNotShort + " out of range", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingLongValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
long someLong = randomLong();
|
||||
jps.setLong(1, someLong);
|
||||
assertEquals(someLong, value(jps));
|
||||
assertEquals(BIGINT, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someLong);
|
||||
assertEquals(someLong, value(jps));
|
||||
assertEquals(BIGINT, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Long);
|
||||
|
||||
jps.setObject(1, someLong, Types.VARCHAR);
|
||||
assertEquals(String.valueOf(someLong), value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someLong, Types.DOUBLE);
|
||||
assertEquals((double) someLong, value(jps));
|
||||
assertEquals(DOUBLE, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someLong, Types.FLOAT);
|
||||
assertEquals((double) someLong, value(jps));
|
||||
assertEquals(FLOAT, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingLongValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
long someLong = randomLong();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, someLong, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [BIGINT] to [Timestamp] not supported", sqle.getMessage());
|
||||
|
||||
Long randomLongNotShort = randomLongBetween(Integer.MAX_VALUE + 1, Long.MAX_VALUE);
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, randomLongNotShort, Types.INTEGER));
|
||||
assertEquals("Numeric " + randomLongNotShort + " out of range", sqle.getMessage());
|
||||
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, randomLongNotShort, Types.SMALLINT));
|
||||
assertEquals("Numeric " + randomLongNotShort + " out of range", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingFloatValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
float someFloat = randomFloat();
|
||||
jps.setFloat(1, someFloat);
|
||||
assertEquals(someFloat, value(jps));
|
||||
assertEquals(REAL, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someFloat);
|
||||
assertEquals(someFloat, value(jps));
|
||||
assertEquals(REAL, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Float);
|
||||
|
||||
jps.setObject(1, someFloat, Types.VARCHAR);
|
||||
assertEquals(String.valueOf(someFloat), value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someFloat, Types.DOUBLE);
|
||||
assertEquals((double) someFloat, value(jps));
|
||||
assertEquals(DOUBLE, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someFloat, Types.FLOAT);
|
||||
assertEquals((double) someFloat, value(jps));
|
||||
assertEquals(FLOAT, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingFloatValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
float someFloat = randomFloat();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, someFloat, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [REAL] to [Timestamp] not supported", sqle.getMessage());
|
||||
|
||||
Float floatNotInt = 5_155_000_000f;
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, floatNotInt, Types.INTEGER));
|
||||
assertEquals(String.format(Locale.ROOT, "Numeric %s out of range",
|
||||
Long.toString(Math.round(floatNotInt.doubleValue()))), sqle.getMessage());
|
||||
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, floatNotInt, Types.SMALLINT));
|
||||
assertEquals(String.format(Locale.ROOT, "Numeric %s out of range",
|
||||
Long.toString(Math.round(floatNotInt.doubleValue()))), sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingDoubleValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
double someDouble = randomDouble();
|
||||
jps.setDouble(1, someDouble);
|
||||
assertEquals(someDouble, value(jps));
|
||||
assertEquals(DOUBLE, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someDouble);
|
||||
assertEquals(someDouble, value(jps));
|
||||
assertEquals(DOUBLE, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof Double);
|
||||
|
||||
jps.setObject(1, someDouble, Types.VARCHAR);
|
||||
assertEquals(String.valueOf(someDouble), value(jps));
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, someDouble, Types.REAL);
|
||||
assertEquals(new Float(someDouble), value(jps));
|
||||
assertEquals(REAL, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingDoubleValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
double someDouble = randomDouble();
|
||||
|
||||
SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, someDouble, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type [DOUBLE] to [Timestamp] not supported", sqle.getMessage());
|
||||
|
||||
Double doubleNotInt = 5_155_000_000d;
|
||||
sqle = expectThrows(SQLException.class, () -> jps.setObject(1, doubleNotInt, Types.INTEGER));
|
||||
assertEquals(String.format(Locale.ROOT, "Numeric %s out of range",
|
||||
Long.toString(((Number) doubleNotInt).longValue())), sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testUnsupportedClasses() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
SQLFeatureNotSupportedException sfnse = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, new Struct() {
|
||||
@Override
|
||||
public String getSQLTypeName() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object[] getAttributes(Map<String, Class<?>> map) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object[] getAttributes() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
assertEquals("Objects of type java.sql.Struct are not supported", sfnse.getMessage());
|
||||
|
||||
sfnse = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, new URL("http://test")));
|
||||
assertEquals("Objects of type java.net.URL are not supported", sfnse.getMessage());
|
||||
|
||||
sfnse = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setURL(1, new URL("http://test")));
|
||||
assertEquals("Objects of type java.net.URL are not supported", sfnse.getMessage());
|
||||
|
||||
sfnse = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, this, Types.TIMESTAMP));
|
||||
assertEquals("Conversion from type " + this.getClass().getName() + " to TIMESTAMP not supported", sfnse.getMessage());
|
||||
|
||||
SQLException se = expectThrows(SQLException.class, () -> jps.setObject(1, this, 1_000_000));
|
||||
assertEquals("Type:1000000 is not a valid Types.java value.", se.getMessage());
|
||||
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> jps.setObject(1, randomShort(), Types.CHAR));
|
||||
assertEquals("Unsupported JDBC type [CHAR]", iae.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingTimestampValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
Timestamp someTimestamp = new Timestamp(randomMillisSinceEpoch());
|
||||
jps.setTimestamp(1, someTimestamp);
|
||||
assertEquals(someTimestamp.getTime(), ((Date)value(jps)).getTime());
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
|
||||
Calendar nonDefaultCal = randomCalendar();
|
||||
// February 29th, 2016. 01:17:55 GMT = 1456708675000 millis since epoch
|
||||
jps.setTimestamp(1, new Timestamp(1456708675000L), nonDefaultCal);
|
||||
assertEquals(1456708675000L, convertFromUTCtoCalendar(((Date)value(jps)), nonDefaultCal));
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
|
||||
long beforeEpochTime = -randomMillisSinceEpoch();
|
||||
jps.setTimestamp(1, new Timestamp(beforeEpochTime), nonDefaultCal);
|
||||
assertEquals(beforeEpochTime, convertFromUTCtoCalendar(((Date)value(jps)), nonDefaultCal));
|
||||
assertTrue(value(jps) instanceof java.util.Date);
|
||||
|
||||
jps.setObject(1, someTimestamp, Types.VARCHAR);
|
||||
assertEquals(someTimestamp.toString(), value(jps).toString());
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingTimestampValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
Timestamp someTimestamp = new Timestamp(randomMillisSinceEpoch());
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, someTimestamp, Types.INTEGER));
|
||||
assertEquals("Conversion from type java.sql.Timestamp to INTEGER not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingTimeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
Time time = new Time(4675000);
|
||||
Calendar nonDefaultCal = randomCalendar();
|
||||
jps.setTime(1, time, nonDefaultCal);
|
||||
assertEquals(4675000, convertFromUTCtoCalendar(((Date)value(jps)), nonDefaultCal));
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof java.util.Date);
|
||||
|
||||
jps.setObject(1, time, Types.VARCHAR);
|
||||
assertEquals(time.toString(), value(jps).toString());
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingTimeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
Time time = new Time(4675000);
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, time, Types.INTEGER));
|
||||
assertEquals("Conversion from type java.sql.Time to INTEGER not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingSqlDateValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
java.sql.Date someSqlDate = new java.sql.Date(randomMillisSinceEpoch());
|
||||
jps.setDate(1, someSqlDate);
|
||||
assertEquals(someSqlDate.getTime(), ((Date)value(jps)).getTime());
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
|
||||
someSqlDate = new java.sql.Date(randomMillisSinceEpoch());
|
||||
Calendar nonDefaultCal = randomCalendar();
|
||||
jps.setDate(1, someSqlDate, nonDefaultCal);
|
||||
assertEquals(someSqlDate.getTime(), convertFromUTCtoCalendar(((Date)value(jps)), nonDefaultCal));
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof java.util.Date);
|
||||
|
||||
jps.setObject(1, someSqlDate, Types.VARCHAR);
|
||||
assertEquals(someSqlDate.toString(), value(jps).toString());
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingSqlDateValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
java.sql.Date someSqlDate = new java.sql.Date(randomMillisSinceEpoch());
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class,
|
||||
() -> jps.setObject(1, new java.sql.Date(randomMillisSinceEpoch()), Types.DOUBLE));
|
||||
assertEquals("Conversion from type " + someSqlDate.getClass().getName() + " to DOUBLE not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingCalendarValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
Calendar someCalendar = randomCalendar();
|
||||
someCalendar.setTimeInMillis(randomMillisSinceEpoch());
|
||||
|
||||
jps.setObject(1, someCalendar);
|
||||
assertEquals(someCalendar.getTime(), (Date) value(jps));
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof java.util.Date);
|
||||
|
||||
jps.setObject(1, someCalendar, Types.VARCHAR);
|
||||
assertEquals(someCalendar.toString(), value(jps).toString());
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
|
||||
Calendar nonDefaultCal = randomCalendar();
|
||||
jps.setObject(1, nonDefaultCal);
|
||||
assertEquals(nonDefaultCal.getTime(), (Date) value(jps));
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingCalendarValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
Calendar someCalendar = randomCalendar();
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, someCalendar, Types.DOUBLE));
|
||||
assertEquals("Conversion from type " + someCalendar.getClass().getName() + " to DOUBLE not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingDateValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
Date someDate = new Date(randomMillisSinceEpoch());
|
||||
|
||||
jps.setObject(1, someDate);
|
||||
assertEquals(someDate, (Date) value(jps));
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof java.util.Date);
|
||||
|
||||
jps.setObject(1, someDate, Types.VARCHAR);
|
||||
assertEquals(someDate.toString(), value(jps).toString());
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingDateValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
Date someDate = new Date(randomMillisSinceEpoch());
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, someDate, Types.BIGINT));
|
||||
assertEquals("Conversion from type " + someDate.getClass().getName() + " to BIGINT not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingLocalDateTimeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
LocalDateTime ldt = LocalDateTime.now(Clock.systemDefaultZone());
|
||||
|
||||
jps.setObject(1, ldt);
|
||||
assertEquals(Date.class, value(jps).getClass());
|
||||
assertEquals(TIMESTAMP, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof java.util.Date);
|
||||
|
||||
jps.setObject(1, ldt, Types.VARCHAR);
|
||||
assertEquals(ldt.toString(), value(jps).toString());
|
||||
assertEquals(VARCHAR, jdbcType(jps));
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingLocalDateTimeValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
LocalDateTime ldt = LocalDateTime.now(Clock.systemDefaultZone());
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, ldt, Types.BIGINT));
|
||||
assertEquals("Conversion from type " + ldt.getClass().getName() + " to BIGINT not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testSettingByteArrayValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
|
||||
byte[] buffer = "some data".getBytes(StandardCharsets.UTF_8);
|
||||
jps.setBytes(1, buffer);
|
||||
assertEquals(byte[].class, value(jps).getClass());
|
||||
assertEquals(VARBINARY, jdbcType(jps));
|
||||
|
||||
jps.setObject(1, buffer);
|
||||
assertEquals(byte[].class, value(jps).getClass());
|
||||
assertEquals(VARBINARY, jdbcType(jps));
|
||||
assertTrue(value(jps) instanceof byte[]);
|
||||
|
||||
jps.setObject(1, buffer, Types.VARBINARY);
|
||||
assertEquals((byte[]) value(jps), buffer);
|
||||
assertEquals(VARBINARY, jdbcType(jps));
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, buffer, Types.VARCHAR));
|
||||
assertEquals("Conversion from type byte[] to VARCHAR not supported", sqle.getMessage());
|
||||
|
||||
sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, buffer, Types.DOUBLE));
|
||||
assertEquals("Conversion from type byte[] to DOUBLE not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
public void testThrownExceptionsWhenSettingByteArrayValues() throws SQLException {
|
||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||
byte[] buffer = "foo".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, buffer, Types.VARCHAR));
|
||||
assertEquals("Conversion from type byte[] to VARCHAR not supported", sqle.getMessage());
|
||||
|
||||
sqle = expectThrows(SQLFeatureNotSupportedException.class, () -> jps.setObject(1, buffer, Types.DOUBLE));
|
||||
assertEquals("Conversion from type byte[] to DOUBLE not supported", sqle.getMessage());
|
||||
}
|
||||
|
||||
private long randomMillisSinceEpoch() {
|
||||
return randomLongBetween(0, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private JdbcPreparedStatement createJdbcPreparedStatement() throws SQLException {
|
||||
return new JdbcPreparedStatement(null, JdbcConfiguration.create("jdbc:es://l:1", null, 0), "?");
|
||||
}
|
||||
|
||||
private JDBCType jdbcType(JdbcPreparedStatement jps) throws SQLException {
|
||||
return jps.query.getParam(1).type;
|
||||
}
|
||||
|
||||
private Object value(JdbcPreparedStatement jps) throws SQLException {
|
||||
return jps.query.getParam(1).value;
|
||||
}
|
||||
|
||||
private Calendar randomCalendar() {
|
||||
return Calendar.getInstance(randomTimeZone(), Locale.ROOT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts from UTC to the provided Calendar.
|
||||
* Helps checking if the converted date/time values using Calendars in set*(...,Calendar) methods did convert
|
||||
* the values correctly to UTC.
|
||||
*/
|
||||
private long convertFromUTCtoCalendar(Date date, Calendar nonDefaultCal) throws SQLException {
|
||||
return ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC)
|
||||
.withZoneSameLocal(nonDefaultCal.getTimeZone().toZoneId())
|
||||
.toInstant().toEpochMilli();
|
||||
}
|
||||
}
|
@ -61,11 +61,6 @@ public enum DataType {
|
||||
*/
|
||||
public final JDBCType jdbcType;
|
||||
|
||||
/**
|
||||
* Name of corresponding java class
|
||||
*/
|
||||
public final String javaName;
|
||||
|
||||
/**
|
||||
* Size of the type in bytes
|
||||
* <p>
|
||||
@ -105,10 +100,12 @@ public enum DataType {
|
||||
*/
|
||||
public final boolean defaultDocValues;
|
||||
|
||||
private final Class<?> javaClass;
|
||||
|
||||
DataType(JDBCType jdbcType, Class<?> javaClass, int size, int defaultPrecision, int displaySize, boolean isInteger, boolean isRational,
|
||||
boolean defaultDocValues) {
|
||||
this.esType = name().toLowerCase(Locale.ROOT);
|
||||
this.javaName = javaClass == null ? null : javaClass.getName();
|
||||
this.javaClass = javaClass;
|
||||
this.jdbcType = jdbcType;
|
||||
this.size = size;
|
||||
this.defaultPrecision = defaultPrecision;
|
||||
@ -125,6 +122,10 @@ public enum DataType {
|
||||
public String sqlName() {
|
||||
return jdbcType.getName();
|
||||
}
|
||||
|
||||
public Class<?> javaClass() {
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
public boolean isNumeric() {
|
||||
return isInteger || isRational;
|
||||
@ -152,6 +153,13 @@ public enum DataType {
|
||||
}
|
||||
return jdbcToEs.get(jdbcType);
|
||||
}
|
||||
|
||||
public static Class<?> fromJdbcTypeToJava(JDBCType jdbcType) {
|
||||
if (jdbcToEs.containsKey(jdbcType) == false) {
|
||||
throw new IllegalArgumentException("Unsupported JDBC type [" + jdbcType + "]");
|
||||
}
|
||||
return jdbcToEs.get(jdbcType).javaClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates returns DataType enum coresponding to the specified es type
|
||||
|
Loading…
x
Reference in New Issue
Block a user