JDBC: Fix stackoverflow on getObject and timestamp conversion (#31735)

StackOverflowError fix in JdbcResultSet getObject method.
Fix Timestamp conversion bug when getting the value of a time column.
This commit is contained in:
Andrei Stefan 2018-07-03 13:55:33 +03:00 committed by GitHub
parent 49b977ba7c
commit ce78925732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 5 deletions

View File

@ -344,7 +344,7 @@ class JdbcResultSet implements ResultSet, JdbcWrapper {
throw new SQLException("type is null"); throw new SQLException("type is null");
} }
return getObject(columnIndex, type); return convert(columnIndex, type);
} }
private <T> T convert(int columnIndex, Class<T> type) throws SQLException { private <T> T convert(int columnIndex, Class<T> type) throws SQLException {

View File

@ -254,7 +254,7 @@ final class TypeConverter {
case REAL: case REAL:
return floatValue(v); // Float might be represented as string for infinity and NaN values return floatValue(v); // Float might be represented as string for infinity and NaN values
case TIMESTAMP: case TIMESTAMP:
return ((Number) v).longValue(); return new Timestamp(((Number) v).longValue());
default: default:
throw new SQLException("Unexpected column type [" + columnType.getName() + "]"); throw new SQLException("Unexpected column type [" + columnType.getName() + "]");

View File

@ -14,6 +14,7 @@ import org.joda.time.DateTime;
import org.joda.time.ReadableDateTime; import org.joda.time.ReadableDateTime;
import java.sql.JDBCType; import java.sql.JDBCType;
import java.sql.Timestamp;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
@ -41,8 +42,8 @@ public class TypeConverterTests extends ESTestCase {
public void testTimestampAsNative() throws Exception { public void testTimestampAsNative() throws Exception {
DateTime now = DateTime.now(); DateTime now = DateTime.now();
assertThat(convertAsNative(now, JDBCType.TIMESTAMP), instanceOf(Long.class)); assertThat(convertAsNative(now, JDBCType.TIMESTAMP), instanceOf(Timestamp.class));
assertEquals(now.getMillis(), convertAsNative(now, JDBCType.TIMESTAMP)); assertEquals(now.getMillis(), ((Timestamp) convertAsNative(now, JDBCType.TIMESTAMP)).getTime());
} }
private Object convertAsNative(Object value, JDBCType type) throws Exception { private Object convertAsNative(Object value, JDBCType type) throws Exception {

View File

@ -82,7 +82,11 @@ public abstract class JdbcIntegrationTestCase extends ESRestTestCase {
} }
public static void index(String index, CheckedConsumer<XContentBuilder, IOException> body) throws IOException { public static void index(String index, CheckedConsumer<XContentBuilder, IOException> body) throws IOException {
Request request = new Request("PUT", "/" + index + "/doc/1"); index(index, "1", body);
}
public static void index(String index, String documentId, CheckedConsumer<XContentBuilder, IOException> body) throws IOException {
Request request = new Request("PUT", "/" + index + "/doc/" + documentId);
request.addParameter("refresh", "true"); request.addParameter("refresh", "true");
XContentBuilder builder = JsonXContent.contentBuilder().startObject(); XContentBuilder builder = JsonXContent.contentBuilder().startObject();
body.accept(builder); body.accept(builder);

View File

@ -0,0 +1,82 @@
/*
* 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.qa.sql.jdbc;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
public class ResultSetTestCase extends JdbcIntegrationTestCase {
public void testGettingTimestamp() throws Exception {
long randomMillis = randomLongBetween(0, System.currentTimeMillis());
index("library", "1", builder -> {
builder.field("name", "Don Quixote");
builder.field("page_count", 1072);
builder.timeField("release_date", new Date(randomMillis));
builder.timeField("republish_date", null);
});
index("library", "2", builder -> {
builder.field("name", "1984");
builder.field("page_count", 328);
builder.timeField("release_date", new Date(-649036800000L));
builder.timeField("republish_date", new Date(599616000000L));
});
try (Connection connection = esJdbc()) {
try (PreparedStatement statement = connection.prepareStatement("SELECT name, release_date, republish_date FROM library")) {
try (ResultSet results = statement.executeQuery()) {
ResultSetMetaData resultSetMetaData = results.getMetaData();
results.next();
assertEquals(3, resultSetMetaData.getColumnCount());
assertEquals(randomMillis, results.getTimestamp("release_date").getTime());
assertEquals(randomMillis, results.getTimestamp(2).getTime());
assertTrue(results.getObject(2) instanceof Timestamp);
assertEquals(randomMillis, ((Timestamp) results.getObject("release_date")).getTime());
assertNull(results.getTimestamp(3));
assertNull(results.getObject("republish_date"));
assertTrue(results.next());
assertEquals(599616000000L, results.getTimestamp("republish_date").getTime());
assertEquals(-649036800000L, ((Timestamp) results.getObject(2)).getTime());
assertFalse(results.next());
}
}
}
}
/*
* Checks StackOverflowError fix for https://github.com/elastic/elasticsearch/pull/31735
*/
public void testNoInfiniteRecursiveGetObjectCalls() throws SQLException, IOException {
index("library", "1", builder -> {
builder.field("name", "Don Quixote");
builder.field("page_count", 1072);
});
Connection conn = esJdbc();
PreparedStatement statement = conn.prepareStatement("SELECT * FROM library");
ResultSet results = statement.executeQuery();
try {
results.next();
results.getObject("name");
results.getObject("page_count");
results.getObject(1);
results.getObject(1, String.class);
results.getObject("page_count", Integer.class);
} catch (StackOverflowError soe) {
fail("Infinite recursive call on getObject() method");
}
}
}