SQL: Add BigDecimal support to JDBC (#56015) (#56220)

* SQL: Add BigDecimal support to JDBC (#56015)

* Introduce BigDecimal support to JDBC -- fetching

This commit adds support for the getBigDecimal() methods.

* Allow BigDecimal params in double range

A prepared statement will now accept a BigDecimal parameter as a proxy
for a double, if the conversion is lossless.

(cherry picked from commit e9a873ad7f387682e3472110b1d7c0514bd347c9)

* Fix compilation error

Dimond notation with anonymous inner classes not avail in Java8.
This commit is contained in:
Bogdan Pintea 2020-05-05 23:19:36 +02:00 committed by GitHub
parent f159fd8a20
commit 47250b14a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 330 additions and 140 deletions

View File

@ -123,7 +123,13 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
setObject(parameterIndex, x, Types.BIGINT);
// ES lacks proper BigDecimal support, so this function simply maps a BigDecimal to a double, while verifying that no definition
// is lost (i.e. the original value can be conveyed as a double).
// While long (i.e. BIGINT) has a larger scale (than double), double has the higher precision more appropriate for BigDecimal.
if (x.compareTo(BigDecimal.valueOf(x.doubleValue())) != 0) {
throw new SQLException("BigDecimal value [" + x + "] out of supported double's range.");
}
setDouble(parameterIndex, x.doubleValue());
}
@Override

View File

@ -5,6 +5,8 @@
*/
package org.elasticsearch.xpack.sql.jdbc;
import org.elasticsearch.common.SuppressForbidden;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
@ -300,7 +302,6 @@ class JdbcResultSet implements ResultSet, JdbcWrapper {
}
try {
return JdbcDateUtils.asDate(val.toString());
} catch (Exception e) {
throw new SQLException(
@ -525,7 +526,11 @@ class JdbcResultSet implements ResultSet, JdbcWrapper {
@Override
@Deprecated
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
throw new SQLFeatureNotSupportedException("BigDecimal not supported");
BigDecimal bd = getBigDecimal(columnIndex);
// The API doesn't allow for specifying a rounding behavior, although BigDecimals did have a way of controlling rounding, even
// before the API got deprecated => default to fail if scaling can't return an exactly equal value, since this behavior was
// expected by (old) callers as well.
return bd == null ? null : bd.setScale(scale);
}
@Override
@ -546,8 +551,9 @@ class JdbcResultSet implements ResultSet, JdbcWrapper {
@Override
@Deprecated
@SuppressForbidden(reason="implementing deprecated method")
public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException {
throw new SQLFeatureNotSupportedException("BigDecimal not supported");
return getBigDecimal(column(columnLabel), scale);
}
@Override
@ -594,12 +600,12 @@ class JdbcResultSet implements ResultSet, JdbcWrapper {
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
throw new SQLFeatureNotSupportedException("BigDecimal not supported");
return convert(columnIndex, BigDecimal.class);
}
@Override
public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
throw new SQLFeatureNotSupportedException("BigDecimal not supported");
return getBigDecimal(column(columnLabel));
}
@Override

View File

@ -10,6 +10,7 @@ import org.elasticsearch.geometry.utils.WellKnownText;
import org.elasticsearch.xpack.sql.proto.StringUtils;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
@ -178,6 +179,9 @@ final class TypeConverter {
if (type == byte[].class) {
return (T) asByteArray(val, columnType, typeString);
}
if (type == BigDecimal.class) {
return (T) asBigDecimal(val, columnType, typeString);
}
//
// JDK 8 types
//
@ -537,6 +541,36 @@ final class TypeConverter {
throw new SQLFeatureNotSupportedException();
}
private static BigDecimal asBigDecimal(Object val, EsType columnType, String typeString) throws SQLException {
switch (columnType) {
case BOOLEAN:
return (Boolean) val ? BigDecimal.ONE : BigDecimal.ZERO;
case BYTE:
case SHORT:
case INTEGER:
case LONG:
return BigDecimal.valueOf(((Number) val).longValue());
case FLOAT:
case HALF_FLOAT:
// floats are passed in as doubles here, so we need to dip into string to keep original float's (reduced) precision.
return new BigDecimal(String.valueOf(((Number) val).floatValue()));
case DOUBLE:
case SCALED_FLOAT:
return BigDecimal.valueOf(((Number) val).doubleValue());
case KEYWORD:
case TEXT:
case CONSTANT_KEYWORD:
try {
return new BigDecimal((String) val);
} catch (NumberFormatException nfe) {
return failConversion(val, columnType, typeString, BigDecimal.class, nfe);
}
// TODO: should we implement numeric - interval types conversions too; ever needed? ODBC does mandate it
// https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/converting-data-from-c-to-sql-data-types
}
return failConversion(val, columnType, typeString, BigDecimal.class);
}
private static LocalDate asLocalDate(Object val, EsType columnType, String typeString) throws SQLException {
throw new SQLFeatureNotSupportedException();
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.qa.jdbc;
import org.elasticsearch.common.collect.Tuple;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.ParameterMetaData;
@ -16,16 +17,12 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
public void testSupportedTypes() throws Exception {
index("library", builder -> {
builder.field("name", "Don Quixote");
builder.field("page_count", 1072);
});
String stringVal = randomAlphaOfLength(randomIntBetween(0, 1000));
int intVal = randomInt();
long longVal = randomLong();
@ -34,10 +31,11 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
boolean booleanVal = randomBoolean();
byte byteVal = randomByte();
short shortVal = randomShort();
BigDecimal bigDecimalVal = BigDecimal.valueOf(randomDouble());
try (Connection connection = esJdbc()) {
try (PreparedStatement statement = connection.prepareStatement(
"SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, name FROM library WHERE page_count=?")) {
"SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?")) {
statement.setString(1, stringVal);
statement.setInt(2, intVal);
statement.setLong(3, longVal);
@ -47,7 +45,7 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
statement.setBoolean(7, booleanVal);
statement.setByte(8, byteVal);
statement.setShort(9, shortVal);
statement.setInt(10, 1072);
statement.setBigDecimal(10, bigDecimalVal);
try (ResultSet results = statement.executeQuery()) {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -67,13 +65,23 @@ public class PreparedStatementTestCase extends JdbcIntegrationTestCase {
assertEquals(booleanVal, results.getBoolean(7));
assertEquals(byteVal, results.getByte(8));
assertEquals(shortVal, results.getShort(9));
assertEquals("Don Quixote", results.getString(10));
assertEquals(bigDecimalVal, results.getBigDecimal(10));
assertFalse(results.next());
}
}
}
}
public void testOutOfRangeBigDecimal() throws Exception {
try (Connection connection = esJdbc()) {
try (PreparedStatement statement = connection.prepareStatement("SELECT ?")) {
BigDecimal tooLarge = BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.ONE);
SQLException ex = expectThrows(SQLException.class, () -> statement.setBigDecimal(1, tooLarge));
assertThat(ex.getMessage(), equalTo("BigDecimal value [" + tooLarge + "] out of supported double's range."));
}
}
}
public void testUnsupportedParameterUse() throws Exception {
index("library", builder -> {
builder.field("name", "Don Quixote");

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.sql.qa.jdbc;
import org.elasticsearch.client.Request;
import org.elasticsearch.common.CheckedBiConsumer;
import org.elasticsearch.common.CheckedBiFunction;
import org.elasticsearch.common.CheckedConsumer;
import org.elasticsearch.common.CheckedFunction;
@ -14,12 +15,14 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.sql.jdbc.EsType;
import org.junit.Before;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
@ -41,6 +44,7 @@ import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
@ -153,12 +157,11 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
// Byte values testing
public void testGettingValidByteWithoutCasting() throws Exception {
byte random1 = randomByte();
byte random2 = randomValueOtherThan(random1, () -> randomByte());
byte random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, () -> randomByte());
createTestDataForByteValueTests(random1, random2, random3);
List<Byte> byteTestValues = createTestDataForNumericValueTests(ESTestCase::randomByte);
byte random1 = byteTestValues.get(0);
byte random2 = byteTestValues.get(1);
byte random3 = byteTestValues.get(2);
doWithQuery("SELECT test_byte, test_null_byte, test_keyword FROM test", (results) -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -282,12 +285,11 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
// Short values testing
public void testGettingValidShortWithoutCasting() throws Exception {
short random1 = randomShort();
short random2 = randomValueOtherThan(random1, () -> randomShort());
short random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, () -> randomShort());
createTestDataForShortValueTests(random1, random2, random3);
List<Short> shortTestValues = createTestDataForNumericValueTests(ESTestCase::randomShort);
short random1 = shortTestValues.get(0);
short random2 = shortTestValues.get(1);
short random3 = shortTestValues.get(2);
doWithQuery("SELECT test_short, test_null_short, test_keyword FROM test", (results) -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -405,12 +407,11 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
// Integer values testing
public void testGettingValidIntegerWithoutCasting() throws Exception {
int random1 = randomInt();
int random2 = randomValueOtherThan(random1, () -> randomInt());
int random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, () -> randomInt());
createTestDataForIntegerValueTests(random1, random2, random3);
List<Integer> integerTestValues = createTestDataForNumericValueTests(ESTestCase::randomInt);
int random1 = integerTestValues.get(0);
int random2 = integerTestValues.get(1);
int random3 = integerTestValues.get(2);
doWithQuery("SELECT test_integer,test_null_integer,test_keyword FROM test", (results) -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -520,12 +521,11 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
// Long values testing
public void testGettingValidLongWithoutCasting() throws Exception {
long random1 = randomLong();
long random2 = randomValueOtherThan(random1, () -> randomLong());
long random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, () -> randomLong());
createTestDataForLongValueTests(random1, random2, random3);
List<Long> longTestValues = createTestDataForNumericValueTests(ESTestCase::randomLong);
long random1 = longTestValues.get(0);
long random2 = longTestValues.get(1);
long random3 = longTestValues.get(2);
doWithQuery("SELECT test_long, test_null_long, test_keyword FROM test", (results) -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -622,12 +622,11 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
// Double values testing
public void testGettingValidDoubleWithoutCasting() throws Exception {
double random1 = randomDouble();
double random2 = randomValueOtherThan(random1, () -> randomDouble());
double random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, () -> randomDouble());
createTestDataForDoubleValueTests(random1, random2, random3);
List<Double> doubleTestValues = createTestDataForNumericValueTests(ESTestCase::randomDouble);
double random1 = doubleTestValues.get(0);
double random2 = doubleTestValues.get(1);
double random3 = doubleTestValues.get(2);
doWithQuery("SELECT test_double, test_null_double, test_keyword FROM test", (results) -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -711,12 +710,11 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
// Float values testing
public void testGettingValidFloatWithoutCasting() throws Exception {
float random1 = randomFloat();
float random2 = randomValueOtherThan(random1, () -> randomFloat());
float random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, () -> randomFloat());
createTestDataForFloatValueTests(random1, random2, random3);
List<Float> floatTestValues = createTestDataForNumericValueTests(ESTestCase::randomFloat);
float random1 = floatTestValues.get(0);
float random2 = floatTestValues.get(1);
float random3 = floatTestValues.get(2);
doWithQuery("SELECT test_float, test_null_float, test_keyword FROM test", (results) -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
@ -791,7 +789,188 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
sqle.getMessage());
});
}
//
// BigDecimal fetching testing
//
static final Map<Class<? extends Number>, Integer> JAVA_TO_SQL_NUMERIC_TYPES_MAP = new HashMap<Class<? extends Number>, Integer>() {{
put(Byte.class, Types.TINYINT);
put(Short.class, Types.SMALLINT);
put(Integer.class, Types.INTEGER);
put(Long.class, Types.BIGINT);
put(Float.class, Types.REAL);
put(Double.class, Types.DOUBLE);
// TODO: no half & scaled float testing
}};
private static <T extends Number> void validateBigDecimalWithoutCasting(ResultSet results, List<T> testValues)
throws SQLException {
ResultSetMetaData resultSetMetaData = results.getMetaData();
Class<? extends Number> clazz = testValues.get(0).getClass();
String primitiveName = clazz.getSimpleName().toLowerCase(Locale.ROOT);
BigDecimal testVal1 = new BigDecimal(testValues.get(0).toString());
BigDecimal testVal2 = new BigDecimal(testValues.get(1).toString());
BigDecimal testVal3 = new BigDecimal(testValues.get(2).toString());
assertEquals(3, resultSetMetaData.getColumnCount());
assertEquals(JAVA_TO_SQL_NUMERIC_TYPES_MAP.get(clazz).longValue(), resultSetMetaData.getColumnType(1));
assertEquals(JAVA_TO_SQL_NUMERIC_TYPES_MAP.get(clazz).longValue(), resultSetMetaData.getColumnType(2));
assertTrue(results.next());
assertEquals(testVal1, results.getBigDecimal(1));
assertEquals(testVal1, results.getBigDecimal("test_" + primitiveName));
assertEquals(testVal1, results.getObject("test_" + primitiveName, BigDecimal.class));
assertEquals(results.getObject(1).getClass(), clazz);
assertNull(results.getBigDecimal(2));
assertTrue(results.wasNull());
assertNull(results.getObject("test_null_" + primitiveName));
assertTrue(results.wasNull());
assertTrue(results.next());
assertEquals(testVal2, results.getBigDecimal(1));
assertEquals(testVal2, results.getBigDecimal("test_" + primitiveName));
assertEquals(results.getObject(1).getClass(), clazz);
assertEquals(testVal3, results.getBigDecimal("test_keyword"));
assertFalse(results.next());
}
public void testGettingValidBigDecimalFromBooleanWithoutCasting() throws Exception {
createTestDataForBooleanValueTests();
doWithQuery("SELECT test_boolean, test_null_boolean, test_keyword FROM test", results -> {
ResultSetMetaData resultSetMetaData = results.getMetaData();
assertEquals(3, resultSetMetaData.getColumnCount());
assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(1));
assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(2));
assertTrue(results.next());
assertEquals(BigDecimal.ONE, results.getBigDecimal(1));
assertEquals(BigDecimal.ONE, results.getBigDecimal("test_boolean"));
assertEquals(BigDecimal.ONE, results.getObject(1, BigDecimal.class));
assertNull(results.getBigDecimal(2));
assertTrue(results.wasNull());
assertNull(results.getBigDecimal("test_null_boolean"));
assertTrue(results.wasNull());
assertEquals(BigDecimal.ONE, results.getBigDecimal(3));
assertEquals(BigDecimal.ONE, results.getBigDecimal("test_keyword"));
assertTrue(results.next());
assertEquals(BigDecimal.ZERO, results.getBigDecimal(1));
assertEquals(BigDecimal.ZERO, results.getBigDecimal("test_boolean"));
assertEquals(BigDecimal.ZERO, results.getObject(1, BigDecimal.class));
assertNull(results.getBigDecimal(2));
assertTrue(results.wasNull());
assertNull(results.getBigDecimal("test_null_boolean"));
assertTrue(results.wasNull());
assertEquals(BigDecimal.ZERO, results.getBigDecimal(3));
assertEquals(BigDecimal.ZERO, results.getBigDecimal("test_keyword"));
assertFalse(results.next());
});
}
public void testGettingValidBigDecimalFromByteWithoutCasting() throws Exception {
List<Byte> byteTestValues = createTestDataForNumericValueTests(ESTestCase::randomByte);
doWithQuery("SELECT test_byte, test_null_byte, test_keyword FROM test", byteTestValues,
ResultSetTestCase::validateBigDecimalWithoutCasting);
}
public void testGettingValidBigDecimalFromShortWithoutCasting() throws Exception {
List<Short> shortTestValues = createTestDataForNumericValueTests(ESTestCase::randomShort);
doWithQuery("SELECT test_short, test_null_short, test_keyword FROM test", shortTestValues,
ResultSetTestCase::validateBigDecimalWithoutCasting);
}
public void testGettingValidBigDecimalFromIntegerWithoutCasting() throws Exception {
List<Integer> integerTestValues = createTestDataForNumericValueTests(ESTestCase::randomInt);
doWithQuery("SELECT test_integer, test_null_integer, test_keyword FROM test", integerTestValues,
ResultSetTestCase::validateBigDecimalWithoutCasting);
}
public void testGettingValidBigDecimalFromLongWithoutCasting() throws Exception {
List<Long> longTestValues = createTestDataForNumericValueTests(ESTestCase::randomLong);
doWithQuery("SELECT test_long, test_null_long, test_keyword FROM test", longTestValues,
ResultSetTestCase::validateBigDecimalWithoutCasting);
}
public void testGettingValidBigDecimalFromFloatWithoutCasting() throws Exception {
List<Float> floatTestValues = createTestDataForNumericValueTests(ESTestCase::randomFloat);
doWithQuery("SELECT test_float, test_null_float, test_keyword FROM test", floatTestValues,
ResultSetTestCase::validateBigDecimalWithoutCasting);
}
public void testGettingValidBigDecimalFromDoubleWithoutCasting() throws Exception {
List<Double> doubleTestValues = createTestDataForNumericValueTests(ESTestCase::randomDouble);
doWithQuery("SELECT test_double, test_null_double, test_keyword FROM test", doubleTestValues,
ResultSetTestCase::validateBigDecimalWithoutCasting);
}
public void testGettingValidBigDecimalWithCasting() throws Exception {
Map<String,Number> map = createTestDataForNumericValueTypes(() -> randomDouble());
doWithQuery(SELECT_WILDCARD, (results) -> {
results.next();
for (Entry<String, Number> e : map.entrySet()) {
BigDecimal actualByObj = results.getObject(e.getKey(), BigDecimal.class);
BigDecimal actualByType = results.getBigDecimal(e.getKey());
BigDecimal expected;
if (e.getValue() instanceof Double) {
expected = BigDecimal.valueOf(e.getValue().doubleValue());
} else if (e.getValue() instanceof Float) {
expected = new BigDecimal(String.valueOf(e.getValue().floatValue()));
} else {
expected = BigDecimal.valueOf(e.getValue().longValue());
}
assertEquals("For field " + e.getKey(), expected, actualByObj);
assertEquals("For field " + e.getKey(), expected, actualByType);
}
});
}
public void testGettingInvalidBigDecimal() throws Exception {
createIndex("test");
updateMappingForNumericValuesTests("test");
updateMapping("test", builder -> {
builder.startObject("test_keyword").field("type", "keyword").endObject();
builder.startObject("test_date").field("type", "date").endObject();
});
String randomString = randomUnicodeOfCodepointLengthBetween(128, 256);
long randomDate = randomNonNegativeLong();
index("test", "1", builder -> {
builder.field("test_keyword", randomString);
builder.field("test_date", randomDate);
});
doWithQuery(SELECT_WILDCARD, (results) -> {
results.next();
SQLException sqle = expectThrows(SQLException.class, () -> results.getBigDecimal("test_keyword"));
assertEquals(format(Locale.ROOT, "Unable to convert value [%.128s] of type [KEYWORD] to [BigDecimal]", randomString),
sqle.getMessage());
sqle = expectThrows(SQLException.class, () -> results.getObject("test_keyword", BigDecimal.class));
assertEquals(format(Locale.ROOT, "Unable to convert value [%.128s] of type [KEYWORD] to [BigDecimal]", randomString),
sqle.getMessage());
sqle = expectThrows(SQLException.class, () -> results.getBigDecimal("test_date"));
assertEquals(format(Locale.ROOT, "Unable to convert value [%.128s] of type [DATETIME] to [BigDecimal]",
asDateString(randomDate)), sqle.getMessage());
sqle = expectThrows(SQLException.class, () -> results.getObject("test_date", BigDecimal.class));
assertEquals(format(Locale.ROOT, "Unable to convert value [%.128s] of type [DATETIME] to [BigDecimal]",
asDateString(randomDate)), sqle.getMessage());
});
}
public void testGettingBooleanValues() throws Exception {
createIndex("test");
updateMappingForNumericValuesTests("test");
@ -1361,8 +1540,6 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getAsciiStream(1), "AsciiStream not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getArray("test"), "Array not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getArray(1), "Array not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getBigDecimal("test"), "BigDecimal not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getBigDecimal("test"), "BigDecimal not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getBinaryStream("test"), "BinaryStream not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getBinaryStream(1), "BinaryStream not supported");
assertThrowsUnsupportedAndExpectErrorMessage(() -> r.getBlob("test"), "Blob not supported");
@ -1543,7 +1720,24 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
}
}
}
private <T extends Number> void doWithQuery(String query, List<T> testValues,
CheckedBiConsumer<ResultSet, List<T>, SQLException> biConsumer) throws SQLException {
doWithQuery(() -> esJdbc(timeZoneId), query, testValues, biConsumer);
}
private <T extends Number> void doWithQuery(CheckedSupplier<Connection, SQLException> con, String query, List<T> testValues,
CheckedBiConsumer<ResultSet, List<T>, SQLException> biConsumer)
throws SQLException {
try (Connection connection = con.get()) {
try (PreparedStatement statement = connection.prepareStatement(query)) {
try (ResultSet results = statement.executeQuery()) {
biConsumer.accept(results, testValues);
}
}
}
}
protected static void createIndex(String index) throws Exception {
Request request = new Request("PUT", "/" + index);
XContentBuilder createIndex = JsonXContent.contentBuilder().startObject();
@ -1636,111 +1830,53 @@ public class ResultSetTestCase extends JdbcIntegrationTestCase {
});
}
private void createTestDataForByteValueTests(byte random1, byte random2, byte random3) throws Exception {
/**
* Creates test data for type specific get* method. It returns a list with the randomly generated test values.
*/
private <T extends Number> List<T> createTestDataForNumericValueTests(Supplier<T> numberGenerator) throws Exception {
T random1 = numberGenerator.get();
T random2 = randomValueOtherThan(random1, numberGenerator);
T random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, numberGenerator);
Class<? extends Number> clazz = random1.getClass();
String primitiveName = clazz.getSimpleName().toLowerCase(Locale.ROOT);
createIndex("test");
updateMapping("test", builder -> {
builder.startObject("test_byte").field("type", "byte").endObject();
builder.startObject("test_null_byte").field("type", "byte").endObject();
builder.startObject("test_" + primitiveName).field("type", primitiveName).endObject();
builder.startObject("test_null_" + primitiveName).field("type", primitiveName).endObject();
builder.startObject("test_keyword").field("type", "keyword").endObject();
});
index("test", "1", builder -> {
builder.field("test_byte", random1);
builder.field("test_null_byte", (Byte) null);
builder.field("test_" + primitiveName, random1);
builder.field("test_null_" + primitiveName, (Byte) null);
});
index("test", "2", builder -> {
builder.field("test_byte", random2);
builder.field("test_" + primitiveName, random2);
builder.field("test_keyword", random3);
});
return Arrays.asList(random1, random2, random3);
}
private void createTestDataForShortValueTests(short random1, short random2, short random3) throws Exception {
private void createTestDataForBooleanValueTests() throws Exception {
createIndex("test");
updateMapping("test", builder -> {
builder.startObject("test_short").field("type", "short").endObject();
builder.startObject("test_null_short").field("type", "short").endObject();
builder.startObject("test_boolean").field("type", "boolean").endObject();
builder.startObject("test_null_boolean").field("type", "boolean").endObject();
builder.startObject("test_keyword").field("type", "keyword").endObject();
});
index("test", "1", builder -> {
builder.field("test_short", random1);
builder.field("test_null_short", (Short) null);
builder.field("test_boolean", Boolean.TRUE);
builder.field("test_null_boolean", (Boolean) null);
builder.field("test_keyword", "1");
});
index("test", "2", builder -> {
builder.field("test_short", random2);
builder.field("test_keyword", random3);
});
}
private void createTestDataForIntegerValueTests(int random1, int random2, int random3) throws Exception {
createIndex("test");
updateMapping("test", builder -> {
builder.startObject("test_integer").field("type", "integer").endObject();
builder.startObject("test_null_integer").field("type", "integer").endObject();
builder.startObject("test_keyword").field("type", "keyword").endObject();
});
index("test", "1", builder -> {
builder.field("test_integer", random1);
builder.field("test_null_integer", (Integer) null);
});
index("test", "2", builder -> {
builder.field("test_integer", random2);
builder.field("test_keyword", random3);
});
}
private void createTestDataForLongValueTests(long random1, long random2, long random3) throws Exception {
createIndex("test");
updateMapping("test", builder -> {
builder.startObject("test_long").field("type", "long").endObject();
builder.startObject("test_null_long").field("type", "long").endObject();
builder.startObject("test_keyword").field("type", "keyword").endObject();
});
index("test", "1", builder -> {
builder.field("test_long", random1);
builder.field("test_null_long", (Long) null);
});
index("test", "2", builder -> {
builder.field("test_long", random2);
builder.field("test_keyword", random3);
});
}
private void createTestDataForDoubleValueTests(double random1, double random2, double random3) throws Exception {
createIndex("test");
updateMapping("test", builder -> {
builder.startObject("test_double").field("type", "double").endObject();
builder.startObject("test_null_double").field("type", "double").endObject();
builder.startObject("test_keyword").field("type", "keyword").endObject();
});
index("test", "1", builder -> {
builder.field("test_double", random1);
builder.field("test_null_double", (Double) null);
});
index("test", "2", builder -> {
builder.field("test_double", random2);
builder.field("test_keyword", random3);
});
}
private void createTestDataForFloatValueTests(float random1, float random2, float random3) throws Exception {
createIndex("test");
updateMapping("test", builder -> {
builder.startObject("test_float").field("type", "float").endObject();
builder.startObject("test_null_float").field("type", "float").endObject();
builder.startObject("test_keyword").field("type", "keyword").endObject();
});
index("test", "1", builder -> {
builder.field("test_float", random1);
builder.field("test_null_float", (Double) null);
});
index("test", "2", builder -> {
builder.field("test_float", random2);
builder.field("test_keyword", random3);
builder.field("test_boolean", Boolean.FALSE);
builder.field("test_null_boolean", (Boolean) null);
builder.field("test_keyword", "0");
});
}