Skip to content

Commit 30e42d8

Browse files
committed
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.
1 parent 456d559 commit 30e42d8

File tree

5 files changed

+92
-5
lines changed

5 files changed

+92
-5
lines changed

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/jdbc/JdbcResultSet.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
344344
throw new SQLException("type is null");
345345
}
346346

347-
return getObject(columnIndex, type);
347+
return convert(columnIndex, type);
348348
}
349349

350350
private <T> T convert(int columnIndex, Class<T> type) throws SQLException {

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/jdbc/TypeConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static Object convert(Object v, JDBCType columnType) throws SQLException {
254254
case REAL:
255255
return floatValue(v); // Float might be represented as string for infinity and NaN values
256256
case TIMESTAMP:
257-
return ((Number) v).longValue();
257+
return new Timestamp(((Number) v).longValue());
258258
default:
259259
throw new SQLException("Unexpected column type [" + columnType.getName() + "]");
260260

x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/jdbc/TypeConverterTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.joda.time.ReadableDateTime;
1515

1616
import java.sql.JDBCType;
17+
import java.sql.Timestamp;
1718

1819
import static org.hamcrest.Matchers.instanceOf;
1920

@@ -41,8 +42,8 @@ public void testDoubleAsNative() throws Exception {
4142

4243
public void testTimestampAsNative() throws Exception {
4344
DateTime now = DateTime.now();
44-
assertThat(convertAsNative(now, JDBCType.TIMESTAMP), instanceOf(Long.class));
45-
assertEquals(now.getMillis(), convertAsNative(now, JDBCType.TIMESTAMP));
45+
assertThat(convertAsNative(now, JDBCType.TIMESTAMP), instanceOf(Timestamp.class));
46+
assertEquals(now.getMillis(), ((Timestamp) convertAsNative(now, JDBCType.TIMESTAMP)).getTime());
4647
}
4748

4849
private Object convertAsNative(Object value, JDBCType type) throws Exception {

x-pack/qa/sql/src/main/java/org/elasticsearch/xpack/qa/sql/jdbc/JdbcIntegrationTestCase.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ protected Connection useDataSource() throws SQLException {
8282
}
8383

8484
public static void index(String index, CheckedConsumer<XContentBuilder, IOException> body) throws IOException {
85-
Request request = new Request("PUT", "/" + index + "/doc/1");
85+
index(index, "1", body);
86+
}
87+
88+
public static void index(String index, String documentId, CheckedConsumer<XContentBuilder, IOException> body) throws IOException {
89+
Request request = new Request("PUT", "/" + index + "/doc/" + documentId);
8690
request.addParameter("refresh", "true");
8791
XContentBuilder builder = JsonXContent.contentBuilder().startObject();
8892
body.accept(builder);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.qa.sql.jdbc;
7+
8+
import java.io.IOException;
9+
import java.sql.Connection;
10+
import java.sql.PreparedStatement;
11+
import java.sql.ResultSet;
12+
import java.sql.ResultSetMetaData;
13+
import java.sql.SQLException;
14+
import java.sql.Timestamp;
15+
import java.util.Date;
16+
17+
public class ResultSetTestCase extends JdbcIntegrationTestCase {
18+
public void testGettingTimestamp() throws Exception {
19+
long randomMillis = randomLongBetween(0, System.currentTimeMillis());
20+
21+
index("library", "1", builder -> {
22+
builder.field("name", "Don Quixote");
23+
builder.field("page_count", 1072);
24+
builder.timeField("release_date", new Date(randomMillis));
25+
builder.timeField("republish_date", null);
26+
});
27+
index("library", "2", builder -> {
28+
builder.field("name", "1984");
29+
builder.field("page_count", 328);
30+
builder.timeField("release_date", new Date(-649036800000L));
31+
builder.timeField("republish_date", new Date(599616000000L));
32+
});
33+
34+
try (Connection connection = esJdbc()) {
35+
try (PreparedStatement statement = connection.prepareStatement("SELECT name, release_date, republish_date FROM library")) {
36+
try (ResultSet results = statement.executeQuery()) {
37+
ResultSetMetaData resultSetMetaData = results.getMetaData();
38+
39+
results.next();
40+
assertEquals(3, resultSetMetaData.getColumnCount());
41+
assertEquals(randomMillis, results.getTimestamp("release_date").getTime());
42+
assertEquals(randomMillis, results.getTimestamp(2).getTime());
43+
assertTrue(results.getObject(2) instanceof Timestamp);
44+
assertEquals(randomMillis, ((Timestamp) results.getObject("release_date")).getTime());
45+
46+
assertNull(results.getTimestamp(3));
47+
assertNull(results.getObject("republish_date"));
48+
49+
assertTrue(results.next());
50+
assertEquals(599616000000L, results.getTimestamp("republish_date").getTime());
51+
assertEquals(-649036800000L, ((Timestamp) results.getObject(2)).getTime());
52+
53+
assertFalse(results.next());
54+
}
55+
}
56+
}
57+
}
58+
59+
/*
60+
* Checks StackOverflowError fix for https://github.com/elastic/elasticsearch/pull/31735
61+
*/
62+
public void testNoInfiniteRecursiveGetObjectCalls() throws SQLException, IOException {
63+
index("library", "1", builder -> {
64+
builder.field("name", "Don Quixote");
65+
builder.field("page_count", 1072);
66+
});
67+
Connection conn = esJdbc();
68+
PreparedStatement statement = conn.prepareStatement("SELECT * FROM library");
69+
ResultSet results = statement.executeQuery();
70+
71+
try {
72+
results.next();
73+
results.getObject("name");
74+
results.getObject("page_count");
75+
results.getObject(1);
76+
results.getObject(1, String.class);
77+
results.getObject("page_count", Integer.class);
78+
} catch (StackOverflowError soe) {
79+
fail("Infinite recursive call on getObject() method");
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)