The Date/Time related query params of a JDBC prepared statement serialized using java.util.Date. The rules for serializing `java.util.Date` objects though reside in `XContentElasticsearchExtension` which is not available in the jdbc jar as this class is in `server` module. Therefore, a custom extension of the `XContentBuilderExtension` iface has been added to the jdbc module/jar. Moreover the sql's `qa` project had as dependency the `sql-action` module which depends on `server` so the `XContentBuilderExtension` was available for the integ tests hiding the real problem. Previously, when a user was setting a `java.sql.Time` to the prepStmt, the DataType used was `DATETIME` instead of `TIME` and therefore prevented from filtering with a `TIME` casted field: ``` SELECT * FROM test WHERE date::TIME = ? ``` Fixes: #56084 (cherry picked from commit f8d8e971bd2c85fa4aea44b5b3ba0cdcc950a4ed)
This commit is contained in:
parent
376f46f953
commit
575cafb8da
|
@ -39,7 +39,10 @@ import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static java.time.ZoneOffset.UTC;
|
||||||
|
|
||||||
class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||||
|
|
||||||
final PreparedQuery query;
|
final PreparedQuery query;
|
||||||
|
|
||||||
JdbcPreparedStatement(JdbcConnection con, JdbcConfiguration info, String sql) throws SQLException {
|
JdbcPreparedStatement(JdbcConnection con, JdbcConfiguration info, String sql) throws SQLException {
|
||||||
|
@ -149,7 +152,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTime(int parameterIndex, Time x) throws SQLException {
|
public void setTime(int parameterIndex, Time x) throws SQLException {
|
||||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
setObject(parameterIndex, x, Types.TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -257,15 +260,15 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||||
@Override
|
@Override
|
||||||
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
|
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
|
||||||
if (cal == null) {
|
if (cal == null) {
|
||||||
setObject(parameterIndex, x, Types.TIMESTAMP);
|
setObject(parameterIndex, x, Types.TIME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
setNull(parameterIndex, Types.TIMESTAMP);
|
setNull(parameterIndex, Types.TIME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// converting to UTC since this is what ES is storing internally
|
// converting to UTC since this is what ES is storing internally
|
||||||
setObject(parameterIndex, new Time(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)), Types.TIMESTAMP);
|
setObject(parameterIndex, new Time(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)), Types.TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -372,7 +375,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||||
|| x instanceof Time
|
|| x instanceof Time
|
||||||
|| x instanceof java.util.Date)
|
|| x instanceof java.util.Date)
|
||||||
{
|
{
|
||||||
if (dataType == EsType.DATETIME) {
|
if (dataType == EsType.DATETIME || dataType == EsType.TIME) {
|
||||||
// converting to {@code java.util.Date} because this is the type supported by {@code XContentBuilder} for serialization
|
// converting to {@code java.util.Date} because this is the type supported by {@code XContentBuilder} for serialization
|
||||||
java.util.Date dateToSet;
|
java.util.Date dateToSet;
|
||||||
if (x instanceof Timestamp) {
|
if (x instanceof Timestamp) {
|
||||||
|
@ -383,10 +386,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
|
||||||
dateToSet = new java.util.Date(((Date) x).getTime());
|
dateToSet = new java.util.Date(((Date) x).getTime());
|
||||||
} else if (x instanceof LocalDateTime) {
|
} else if (x instanceof LocalDateTime) {
|
||||||
LocalDateTime ldt = (LocalDateTime) x;
|
LocalDateTime ldt = (LocalDateTime) x;
|
||||||
Calendar cal = getDefaultCalendar();
|
dateToSet = new java.util.Date(ldt.toInstant(UTC).toEpochMilli());
|
||||||
cal.set(ldt.getYear(), ldt.getMonthValue() - 1, ldt.getDayOfMonth(), ldt.getHour(), ldt.getMinute(), ldt.getSecond());
|
|
||||||
|
|
||||||
dateToSet = cal.getTime();
|
|
||||||
} else if (x instanceof Time) {
|
} else if (x instanceof Time) {
|
||||||
dateToSet = new java.util.Date(((Time) x).getTime());
|
dateToSet = new java.util.Date(((Time) x).getTime());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -60,7 +60,7 @@ final class TypeUtils {
|
||||||
aMap.put(GregorianCalendar.class, EsType.DATETIME);
|
aMap.put(GregorianCalendar.class, EsType.DATETIME);
|
||||||
aMap.put(java.util.Date.class, EsType.DATETIME);
|
aMap.put(java.util.Date.class, EsType.DATETIME);
|
||||||
aMap.put(java.sql.Date.class, EsType.DATETIME);
|
aMap.put(java.sql.Date.class, EsType.DATETIME);
|
||||||
aMap.put(java.sql.Time.class, EsType.DATETIME);
|
aMap.put(java.sql.Time.class, EsType.TIME);
|
||||||
aMap.put(LocalDateTime.class, EsType.DATETIME);
|
aMap.put(LocalDateTime.class, EsType.DATETIME);
|
||||||
CLASS_TO_TYPE = Collections.unmodifiableMap(aMap);
|
CLASS_TO_TYPE = Collections.unmodifiableMap(aMap);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilderExtension;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension for SQL's JDBC specific classes that need to be
|
||||||
|
* encoded by {@link XContentBuilder} in a specific way.
|
||||||
|
*/
|
||||||
|
public class XContentSqlExtension implements XContentBuilderExtension {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Class<?>, XContentBuilder.Writer> getXContentWriters() {
|
||||||
|
Map<Class<?>, XContentBuilder.Writer> map = new HashMap<>();
|
||||||
|
map.put(Date.class, (b, v) -> b.value(((Date) v).getTime()));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Class<?>, XContentBuilder.HumanReadableTransformer> getXContentHumanReadableTransformers() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Class<?>, Function<Object, Object>> getDateTransformers() {
|
||||||
|
Map<Class<?>, Function<Object, Object>> map = new HashMap<>();
|
||||||
|
map.put(Date.class, d -> ((Date) d).getTime());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.elasticsearch.xpack.sql.jdbc.XContentSqlExtension
|
|
@ -37,6 +37,7 @@ import static org.elasticsearch.xpack.sql.jdbc.EsType.INTEGER;
|
||||||
import static org.elasticsearch.xpack.sql.jdbc.EsType.KEYWORD;
|
import static org.elasticsearch.xpack.sql.jdbc.EsType.KEYWORD;
|
||||||
import static org.elasticsearch.xpack.sql.jdbc.EsType.LONG;
|
import static org.elasticsearch.xpack.sql.jdbc.EsType.LONG;
|
||||||
import static org.elasticsearch.xpack.sql.jdbc.EsType.SHORT;
|
import static org.elasticsearch.xpack.sql.jdbc.EsType.SHORT;
|
||||||
|
import static org.elasticsearch.xpack.sql.jdbc.EsType.TIME;
|
||||||
|
|
||||||
public class JdbcPreparedStatementTests extends ESTestCase {
|
public class JdbcPreparedStatementTests extends ESTestCase {
|
||||||
|
|
||||||
|
@ -401,10 +402,15 @@ public class JdbcPreparedStatementTests extends ESTestCase {
|
||||||
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
JdbcPreparedStatement jps = createJdbcPreparedStatement();
|
||||||
|
|
||||||
Time time = new Time(4675000);
|
Time time = new Time(4675000);
|
||||||
|
jps.setTime(1, time);
|
||||||
|
assertEquals(time, value(jps));
|
||||||
|
assertEquals(TIME, jdbcType(jps));
|
||||||
|
assertTrue(value(jps) instanceof java.util.Date);
|
||||||
|
|
||||||
Calendar nonDefaultCal = randomCalendar();
|
Calendar nonDefaultCal = randomCalendar();
|
||||||
jps.setTime(1, time, nonDefaultCal);
|
jps.setTime(1, time, nonDefaultCal);
|
||||||
assertEquals(4675000, convertFromUTCtoCalendar(((Date)value(jps)), nonDefaultCal));
|
assertEquals(4675000, convertFromUTCtoCalendar(((Date)value(jps)), nonDefaultCal));
|
||||||
assertEquals(DATETIME, jdbcType(jps));
|
assertEquals(TIME, jdbcType(jps));
|
||||||
assertTrue(value(jps) instanceof java.util.Date);
|
assertTrue(value(jps) instanceof java.util.Date);
|
||||||
|
|
||||||
jps.setObject(1, time, Types.VARCHAR);
|
jps.setObject(1, time, Types.VARCHAR);
|
||||||
|
|
|
@ -9,7 +9,6 @@ dependencies {
|
||||||
// JDBC testing dependencies
|
// JDBC testing dependencies
|
||||||
compile project(path: xpackModule('sql:jdbc'))
|
compile project(path: xpackModule('sql:jdbc'))
|
||||||
|
|
||||||
compile project(path: xpackModule('sql:sql-action'))
|
|
||||||
compile "net.sourceforge.csvjdbc:csvjdbc:${csvjdbcVersion}"
|
compile "net.sourceforge.csvjdbc:csvjdbc:${csvjdbcVersion}"
|
||||||
|
|
||||||
// CLI testing dependencies
|
// CLI testing dependencies
|
||||||
|
|
|
@ -31,8 +31,10 @@ import java.sql.Time;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.jar.JarInputStream;
|
import java.util.jar.JarInputStream;
|
||||||
|
@ -46,6 +48,7 @@ final class JdbcTestUtils {
|
||||||
|
|
||||||
private static final int MAX_WIDTH = 20;
|
private static final int MAX_WIDTH = 20;
|
||||||
|
|
||||||
|
static final ZoneId UTC = ZoneId.of("Z");
|
||||||
static final String SQL_TRACE = "org.elasticsearch.xpack.sql:TRACE";
|
static final String SQL_TRACE = "org.elasticsearch.xpack.sql:TRACE";
|
||||||
static final String JDBC_TIMEZONE = "timezone";
|
static final String JDBC_TIMEZONE = "timezone";
|
||||||
static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
|
static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
|
||||||
|
@ -240,4 +243,18 @@ final class JdbcTestUtils {
|
||||||
return new Time(ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), zoneId)
|
return new Time(ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), zoneId)
|
||||||
.toLocalTime().atDate(JdbcTestUtils.EPOCH).atZone(zoneId).toInstant().toEpochMilli());
|
.toLocalTime().atDate(JdbcTestUtils.EPOCH).atZone(zoneId).toInstant().toEpochMilli());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,12 @@
|
||||||
package org.elasticsearch.xpack.sql.qa.jdbc;
|
package org.elasticsearch.xpack.sql.qa.jdbc;
|
||||||
|
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.Date;
|
||||||
import java.sql.JDBCType;
|
import java.sql.JDBCType;
|
||||||
import java.sql.ParameterMetaData;
|
import java.sql.ParameterMetaData;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
|
@ -16,13 +19,24 @@ import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.SQLSyntaxErrorException;
|
import java.sql.SQLSyntaxErrorException;
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.UTC;
|
||||||
|
import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.asDate;
|
||||||
|
import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.asTime;
|
||||||
|
import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.convertFromCalendarToUTC;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
|
|
||||||
public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
||||||
|
|
||||||
public void testSupportedTypes() throws Exception {
|
public void testSupportedTypes() throws SQLException {
|
||||||
String stringVal = randomAlphaOfLength(randomIntBetween(0, 1000));
|
String stringVal = randomAlphaOfLength(randomIntBetween(0, 1000));
|
||||||
int intVal = randomInt();
|
int intVal = randomInt();
|
||||||
long longVal = randomLong();
|
long longVal = randomLong();
|
||||||
|
@ -32,10 +46,23 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
||||||
byte byteVal = randomByte();
|
byte byteVal = randomByte();
|
||||||
short shortVal = randomShort();
|
short shortVal = randomShort();
|
||||||
BigDecimal bigDecimalVal = BigDecimal.valueOf(randomDouble());
|
BigDecimal bigDecimalVal = BigDecimal.valueOf(randomDouble());
|
||||||
|
long millis = randomNonNegativeLong();
|
||||||
|
Calendar calendarVal = Calendar.getInstance(randomTimeZone(), Locale.ROOT);
|
||||||
|
Timestamp timestampVal = new Timestamp(millis);
|
||||||
|
Timestamp timestampValWithCal = new Timestamp(convertFromCalendarToUTC(timestampVal.getTime(), calendarVal));
|
||||||
|
Date dateVal = asDate(millis, UTC);
|
||||||
|
Date dateValWithCal = asDate(convertFromCalendarToUTC(dateVal.getTime(), calendarVal), UTC);
|
||||||
|
Time timeVal = asTime(millis, UTC);
|
||||||
|
Time timeValWithCal = asTime(convertFromCalendarToUTC(timeVal.getTime(), calendarVal), UTC);
|
||||||
|
java.util.Date utilDateVal = new java.util.Date(millis);
|
||||||
|
LocalDateTime localDateTimeVal = LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), UTC);
|
||||||
|
|
||||||
try (Connection connection = esJdbc()) {
|
try (Connection connection = esJdbc()) {
|
||||||
try (PreparedStatement statement = connection.prepareStatement(
|
StringJoiner sql = new StringJoiner(",", "SELECT ", "");
|
||||||
"SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?")) {
|
for (int i = 0; i < 19; i++) {
|
||||||
|
sql.add("?");
|
||||||
|
}
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(sql.toString())) {
|
||||||
statement.setString(1, stringVal);
|
statement.setString(1, stringVal);
|
||||||
statement.setInt(2, intVal);
|
statement.setInt(2, intVal);
|
||||||
statement.setLong(3, longVal);
|
statement.setLong(3, longVal);
|
||||||
|
@ -46,6 +73,15 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
||||||
statement.setByte(8, byteVal);
|
statement.setByte(8, byteVal);
|
||||||
statement.setShort(9, shortVal);
|
statement.setShort(9, shortVal);
|
||||||
statement.setBigDecimal(10, bigDecimalVal);
|
statement.setBigDecimal(10, bigDecimalVal);
|
||||||
|
statement.setTimestamp(11, timestampVal);
|
||||||
|
statement.setTimestamp(12, timestampVal, calendarVal);
|
||||||
|
statement.setDate(13, dateVal);
|
||||||
|
statement.setDate(14, dateVal, calendarVal);
|
||||||
|
statement.setTime(15, timeVal);
|
||||||
|
statement.setTime(16, timeVal, calendarVal);
|
||||||
|
statement.setObject(17, calendarVal);
|
||||||
|
statement.setObject(18, utilDateVal);
|
||||||
|
statement.setObject(19, localDateTimeVal);
|
||||||
|
|
||||||
try (ResultSet results = statement.executeQuery()) {
|
try (ResultSet results = statement.executeQuery()) {
|
||||||
ResultSetMetaData resultSetMetaData = results.getMetaData();
|
ResultSetMetaData resultSetMetaData = results.getMetaData();
|
||||||
|
@ -66,13 +102,77 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
||||||
assertEquals(byteVal, results.getByte(8));
|
assertEquals(byteVal, results.getByte(8));
|
||||||
assertEquals(shortVal, results.getShort(9));
|
assertEquals(shortVal, results.getShort(9));
|
||||||
assertEquals(bigDecimalVal, results.getBigDecimal(10));
|
assertEquals(bigDecimalVal, results.getBigDecimal(10));
|
||||||
|
assertEquals(timestampVal, results.getTimestamp(11));
|
||||||
|
assertEquals(timestampValWithCal, results.getTimestamp(12));
|
||||||
|
assertEquals(dateVal, results.getDate(13));
|
||||||
|
assertEquals(dateValWithCal, results.getDate(14));
|
||||||
|
assertEquals(timeVal, results.getTime(15));
|
||||||
|
assertEquals(timeValWithCal, results.getTime(16));
|
||||||
|
assertEquals(new Timestamp(calendarVal.getTimeInMillis()), results.getObject(17));
|
||||||
|
assertEquals(timestampVal, results.getObject(18));
|
||||||
|
assertEquals(timestampVal, results.getObject(19));
|
||||||
assertFalse(results.next());
|
assertFalse(results.next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOutOfRangeBigDecimal() throws Exception {
|
public void testDatetime() throws IOException, SQLException {
|
||||||
|
long randomMillis = randomNonNegativeLong();
|
||||||
|
setupIndexForDateTimeTests(randomMillis);
|
||||||
|
|
||||||
|
try (Connection connection = esJdbc()) {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement("SELECT id, birth_date FROM emps WHERE birth_date = ?")) {
|
||||||
|
Object dateTimeParam = randomFrom(new Timestamp(randomMillis), new Date(randomMillis));
|
||||||
|
statement.setObject(1, dateTimeParam);
|
||||||
|
try (ResultSet results = statement.executeQuery()) {
|
||||||
|
assertTrue(results.next());
|
||||||
|
assertEquals(1002, results.getInt(1));
|
||||||
|
assertEquals(new Timestamp(randomMillis), results.getTimestamp(2));
|
||||||
|
assertFalse(results.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDate() throws IOException, SQLException {
|
||||||
|
long randomMillis = randomNonNegativeLong();
|
||||||
|
setupIndexForDateTimeTests(randomMillis);
|
||||||
|
|
||||||
|
try (Connection connection = esJdbc()) {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement("SELECT id, birth_date FROM emps WHERE birth_date::date = ?")) {
|
||||||
|
statement.setDate(1, new Date(asDate(randomMillis, UTC).getTime()));
|
||||||
|
try (ResultSet results = statement.executeQuery()) {
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
assertTrue(results.next());
|
||||||
|
assertEquals(1000 + i, results.getInt(1));
|
||||||
|
assertEquals(new Timestamp(testMillis(randomMillis, i)), results.getTimestamp(2));
|
||||||
|
}
|
||||||
|
assertFalse(results.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTime() throws IOException, SQLException {
|
||||||
|
long randomMillis = randomNonNegativeLong();
|
||||||
|
setupIndexForDateTimeTests(randomMillis);
|
||||||
|
|
||||||
|
try (Connection connection = esJdbc()) {
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement("SELECT id, birth_date FROM emps WHERE birth_date::time = ?")) {
|
||||||
|
Time time = JdbcTestUtils.asTime(randomMillis, UTC);
|
||||||
|
statement.setObject(1, time);
|
||||||
|
try (ResultSet results = statement.executeQuery()) {
|
||||||
|
assertTrue(results.next());
|
||||||
|
assertEquals(1002, results.getInt(1));
|
||||||
|
assertEquals(new Timestamp(randomMillis), results.getTimestamp(2));
|
||||||
|
assertFalse(results.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOutOfRangeBigDecimal() throws SQLException {
|
||||||
try (Connection connection = esJdbc()) {
|
try (Connection connection = esJdbc()) {
|
||||||
try (PreparedStatement statement = connection.prepareStatement("SELECT ?")) {
|
try (PreparedStatement statement = connection.prepareStatement("SELECT ?")) {
|
||||||
BigDecimal tooLarge = BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.ONE);
|
BigDecimal tooLarge = BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.ONE);
|
||||||
|
@ -198,7 +298,7 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tuple<Integer, Object> execute(PreparedStatement statement) throws SQLException {
|
private Tuple<Integer, Object> execute(PreparedStatement statement) throws Exception {
|
||||||
try (ResultSet results = statement.executeQuery()) {
|
try (ResultSet results = statement.executeQuery()) {
|
||||||
ResultSetMetaData resultSetMetaData = results.getMetaData();
|
ResultSetMetaData resultSetMetaData = results.getMetaData();
|
||||||
assertTrue(results.next());
|
assertTrue(results.next());
|
||||||
|
@ -207,4 +307,21 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static long testMillis(long randomMillis, int i) {
|
||||||
|
return randomMillis - 2 + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupIndexForDateTimeTests(long randomMillis) throws IOException {
|
||||||
|
String mapping = "\"properties\":{\"id\":{\"type\":\"integer\"},\"birth_date\":{\"type\":\"date\"}}";
|
||||||
|
createIndex("emps", Settings.EMPTY, mapping);
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
int id = 1000 + i;
|
||||||
|
long testMillis = testMillis(randomMillis, i);
|
||||||
|
index("emps", "" + i, builder -> {
|
||||||
|
builder.field("id", id);
|
||||||
|
builder.field("birth_date", testMillis);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ public final class DateUtils {
|
||||||
.optionalEnd()
|
.optionalEnd()
|
||||||
.toFormatter().withZone(UTC);
|
.toFormatter().withZone(UTC);
|
||||||
|
|
||||||
private static final DateFormatter UTC_DATE_TIME_FORMATTER = DateFormatter.forPattern("date_optional_time").withZone(UTC);
|
private static final DateFormatter UTC_DATE_TIME_FORMATTER = DateFormatter.forPattern("strict_date_optional_time").withZone(UTC);
|
||||||
private static final int DEFAULT_PRECISION_FOR_CURRENT_FUNCTIONS = 3;
|
private static final int DEFAULT_PRECISION_FOR_CURRENT_FUNCTIONS = 3;
|
||||||
|
|
||||||
private DateUtils() {}
|
private DateUtils() {}
|
||||||
|
|
Loading…
Reference in New Issue