Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDBC driver prepared statement set* methods #31494

Merged
merged 9 commits into from
Jun 27, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,13 +23,24 @@
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;
Expand Down Expand Up @@ -74,67 +87,67 @@ public void setNull(int parameterIndex, int sqlType) throws SQLException {

@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
Expand All @@ -161,12 +174,22 @@ public void clearParameters() throws SQLException {

@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
Expand All @@ -181,22 +204,22 @@ public void setCharacterStream(int parameterIndex, Reader reader, int length) th

@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
Expand All @@ -206,17 +229,44 @@ public ResultSetMetaData getMetaData() throws SQLException {

@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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

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
Expand All @@ -226,7 +276,7 @@ public void setNull(int parameterIndex, int sqlType, String typeName) throws SQL

@Override
public void setURL(int parameterIndex, URL x) throws SQLException {
throw new SQLFeatureNotSupportedException("Datalink not supported");
setObject(parameterIndex, x);
}

@Override
Expand All @@ -236,7 +286,7 @@ public ParameterMetaData getParameterMetaData() throws SQLException {

@Override
public void setRowId(int parameterIndex, RowId x) throws SQLException {
throw new SQLFeatureNotSupportedException("RowId not supported");
setObject(parameterIndex, x);
}

@Override
Expand All @@ -251,7 +301,7 @@ public void setNCharacterStream(int parameterIndex, Reader value, long length) t

@Override
public void setNClob(int parameterIndex, NClob value) throws SQLException {
throw new SQLFeatureNotSupportedException("NClob not supported");
setObject(parameterIndex, value);
}

@Override
Expand All @@ -271,12 +321,108 @@ public void setNClob(int parameterIndex, Reader reader, long length) throws SQLE

@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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to be a final field, why was it moved to a method?

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,6 @@ private <T> T convert(int columnIndex, Class<T> type) throws SQLException {
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);
Expand Down
Loading