Skip to content

Commit 3cd7e33

Browse files
gopalldbclaude
andauthored
Add 56 JDBC spec integration tests with comprehensive DatabaseMetaData coverage (#1216)
## Summary - Adds **56 new integration tests** across 5 test files to close JDBC spec coverage gaps - Includes comprehensive **DatabaseMetaData testing** (~180 assertions covering all boolean/int/string property methods) - All tests use the WireMock record-replay fake service infrastructure with both SEA and Thrift recordings ### New tests by file: | File | New Tests | Coverage Area | |------|-----------|--------------| | `MetadataIntegrationTests` | 25 | All boolean properties, string/int properties, ResultSet-returning methods (getTypeInfo, getProcedures, getFunctions, getImportedKeys, getExportedKeys, getCrossReference, etc.), wrapper/lifecycle | | `ResultSetIntegrationTests` | 10 | Type getters: getBoolean, getByte, getShort, getLong, getFloat, getDouble, getBigDecimal, getDate, getTimestamp, getObject | | `PreparedStatementIntegrationTests` | 7 | Type setters: setBoolean, setLong, setFloat, setDouble, setBigDecimal, setDate, setTimestamp | | `ExecutionIntegrationTests` | 4 | Statement utilities: fetchDirection, enquoteLiteral, enquoteIdentifier, isSimpleIdentifier | | `ConnectionIntegrationTests` | 3 | Connection attributes: autoCommit default, isReadOnly, transactionIsolation | ### Verification results: - **SEA REPLAY**: All tests pass (0 failures) - **Thrift REPLAY**: All tests pass (8 metadata tests skipped as SEA-only due to Thrift recording limitations) ## Test plan - [x] All 56 new tests pass in SEA REPLAY mode - [x] All tests pass in Thrift REPLAY mode (with expected skips) - [x] No regressions in existing tests - [x] WireMock recordings committed for both SEA and Thrift modes 🤖 Generated with [Claude Code](https://claude.com/claude-code) NO_CHANGELOG=true --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7588640 commit 3cd7e33

668 files changed

Lines changed: 24164 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/test/java/com/databricks/jdbc/integration/fakeservice/tests/ConnectionIntegrationTests.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,17 @@ void testGetCatalog_ReturnsNonNull() throws SQLException {
113113
conn.close();
114114
}
115115

116+
// --- Transaction and connection attribute tests ---
117+
118+
@Test
119+
void testAutoCommit_DefaultIsTrue() throws SQLException {
120+
Connection conn = getValidJDBCConnection();
121+
122+
assertTrue(conn.getAutoCommit(), "Default autoCommit should be true");
123+
124+
conn.close();
125+
}
126+
116127
@Test
117128
void testGetSchema_ReturnsNonNull() throws SQLException {
118129
Connection conn = getValidJDBCConnection();
@@ -124,6 +135,16 @@ void testGetSchema_ReturnsNonNull() throws SQLException {
124135
conn.close();
125136
}
126137

138+
@Test
139+
void testIsReadOnly_Default() throws SQLException {
140+
Connection conn = getValidJDBCConnection();
141+
142+
boolean readOnly = conn.isReadOnly();
143+
assertFalse(readOnly, "Default connection should not be read-only");
144+
145+
conn.close();
146+
}
147+
127148
@Test
128149
void testGetMetaData_ReturnsNonNull() throws SQLException {
129150
Connection conn = getValidJDBCConnection();
@@ -159,6 +180,22 @@ void testGetClientInfo_ReturnsProperties() throws SQLException {
159180
conn.close();
160181
}
161182

183+
@Test
184+
void testGetTransactionIsolation() throws SQLException {
185+
Connection conn = getValidJDBCConnection();
186+
187+
int isolation = conn.getTransactionIsolation();
188+
assertTrue(
189+
isolation == Connection.TRANSACTION_NONE
190+
|| isolation == Connection.TRANSACTION_READ_UNCOMMITTED
191+
|| isolation == Connection.TRANSACTION_READ_COMMITTED
192+
|| isolation == Connection.TRANSACTION_REPEATABLE_READ
193+
|| isolation == Connection.TRANSACTION_SERIALIZABLE,
194+
"Transaction isolation should be a valid JDBC constant");
195+
196+
conn.close();
197+
}
198+
162199
private Properties createConnectionProperties(Properties extraProps) {
163200
Properties connProps = new Properties();
164201
connProps.putAll(extraProps);

src/test/java/com/databricks/jdbc/integration/fakeservice/tests/ExecutionIntegrationTests.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,57 @@ void testExecuteAsyncStatement() throws Exception {
278278
rs2.unwrap(IDatabricksResultSet.class).getStatementStatus().getState());
279279
}
280280

281+
// --- Statement property tests ---
282+
283+
@Test
284+
void testStatement_FetchDirection() throws SQLException {
285+
Statement stmt = connection.createStatement();
286+
287+
// Default should be FETCH_FORWARD
288+
assertEquals(
289+
ResultSet.FETCH_FORWARD,
290+
stmt.getFetchDirection(),
291+
"Default fetch direction should be FETCH_FORWARD");
292+
293+
// Setting FETCH_FORWARD should work
294+
stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
295+
assertEquals(ResultSet.FETCH_FORWARD, stmt.getFetchDirection());
296+
297+
stmt.close();
298+
}
299+
300+
@Test
301+
void testStatement_EnquoteLiteral() throws SQLException {
302+
Statement stmt = connection.createStatement();
303+
304+
String result = stmt.enquoteLiteral("test");
305+
assertNotNull(result, "enquoteLiteral should return non-null");
306+
assertTrue(result.contains("test"), "enquoteLiteral should contain the original string");
307+
308+
stmt.close();
309+
}
310+
311+
@Test
312+
void testStatement_EnquoteIdentifier() throws SQLException {
313+
Statement stmt = connection.createStatement();
314+
315+
String result = stmt.enquoteIdentifier("my_column", false);
316+
assertNotNull(result, "enquoteIdentifier should return non-null");
317+
318+
stmt.close();
319+
}
320+
321+
@Test
322+
void testStatement_IsSimpleIdentifier() throws SQLException {
323+
Statement stmt = connection.createStatement();
324+
325+
assertTrue(stmt.isSimpleIdentifier("simple_name"), "simple_name should be a simple identifier");
326+
assertFalse(
327+
stmt.isSimpleIdentifier("has space"), "'has space' should not be a simple identifier");
328+
329+
stmt.close();
330+
}
331+
281332
// --- Statement lifecycle and property tests ---
282333

283334
@Test

src/test/java/com/databricks/jdbc/integration/fakeservice/tests/MetadataIntegrationTests.java

Lines changed: 618 additions & 0 deletions
Large diffs are not rendered by default.

src/test/java/com/databricks/jdbc/integration/fakeservice/tests/PreparedStatementIntegrationTests.java

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,141 @@ void testSetObject(
289289
deleteTable(connection, tableName);
290290
}
291291

292+
// --- PreparedStatement type setter tests ---
293+
294+
@Test
295+
void testSetBoolean() throws SQLException {
296+
String tableName = "pstmt_set_boolean_table";
297+
String createSQL =
298+
"CREATE TABLE " + getFullyQualifiedTableName(tableName) + " (id INT, flag BOOLEAN)";
299+
setupDatabaseTable(connection, tableName, createSQL);
300+
301+
String insertSQL =
302+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, flag) VALUES (?, ?)";
303+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
304+
pstmt.setInt(1, 1);
305+
pstmt.setBoolean(2, true);
306+
assertEquals(1, pstmt.executeUpdate());
307+
}
308+
309+
ResultSet rs =
310+
executeQuery(
311+
connection,
312+
"SELECT flag FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
313+
assertTrue(rs.next());
314+
assertTrue(rs.getBoolean("flag"), "Boolean value should be true");
315+
316+
rs.close();
317+
deleteTable(connection, tableName);
318+
}
319+
320+
@Test
321+
void testSetLong() throws SQLException {
322+
String tableName = "pstmt_set_long_table";
323+
String createSQL =
324+
"CREATE TABLE " + getFullyQualifiedTableName(tableName) + " (id INT, big_val BIGINT)";
325+
setupDatabaseTable(connection, tableName, createSQL);
326+
327+
String insertSQL =
328+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, big_val) VALUES (?, ?)";
329+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
330+
pstmt.setInt(1, 1);
331+
pstmt.setLong(2, 9876543210L);
332+
assertEquals(1, pstmt.executeUpdate());
333+
}
334+
335+
ResultSet rs =
336+
executeQuery(
337+
connection,
338+
"SELECT big_val FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
339+
assertTrue(rs.next());
340+
assertEquals(9876543210L, rs.getLong("big_val"), "Long value should match");
341+
342+
rs.close();
343+
deleteTable(connection, tableName);
344+
}
345+
346+
@Test
347+
void testSetFloat() throws SQLException {
348+
String tableName = "pstmt_set_float_table";
349+
String createSQL =
350+
"CREATE TABLE " + getFullyQualifiedTableName(tableName) + " (id INT, float_val FLOAT)";
351+
setupDatabaseTable(connection, tableName, createSQL);
352+
353+
String insertSQL =
354+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, float_val) VALUES (?, ?)";
355+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
356+
pstmt.setInt(1, 1);
357+
pstmt.setFloat(2, 3.14f);
358+
assertEquals(1, pstmt.executeUpdate());
359+
}
360+
361+
ResultSet rs =
362+
executeQuery(
363+
connection,
364+
"SELECT float_val FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
365+
assertTrue(rs.next());
366+
assertEquals(3.14f, rs.getFloat("float_val"), 0.01f, "Float value should match");
367+
368+
rs.close();
369+
deleteTable(connection, tableName);
370+
}
371+
372+
@Test
373+
void testSetDouble() throws SQLException {
374+
String tableName = "pstmt_set_double_table";
375+
String createSQL =
376+
"CREATE TABLE " + getFullyQualifiedTableName(tableName) + " (id INT, dbl_val DOUBLE)";
377+
setupDatabaseTable(connection, tableName, createSQL);
378+
379+
String insertSQL =
380+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, dbl_val) VALUES (?, ?)";
381+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
382+
pstmt.setInt(1, 1);
383+
pstmt.setDouble(2, 2.718281828);
384+
assertEquals(1, pstmt.executeUpdate());
385+
}
386+
387+
ResultSet rs =
388+
executeQuery(
389+
connection,
390+
"SELECT dbl_val FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
391+
assertTrue(rs.next());
392+
assertEquals(2.718281828, rs.getDouble("dbl_val"), 0.0001, "Double value should match");
393+
394+
rs.close();
395+
deleteTable(connection, tableName);
396+
}
397+
398+
@Test
399+
void testSetBigDecimal() throws SQLException {
400+
String tableName = "pstmt_set_bigdecimal_table";
401+
String createSQL =
402+
"CREATE TABLE "
403+
+ getFullyQualifiedTableName(tableName)
404+
+ " (id INT, dec_val DECIMAL(15, 4))";
405+
setupDatabaseTable(connection, tableName, createSQL);
406+
407+
String insertSQL =
408+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, dec_val) VALUES (?, ?)";
409+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
410+
pstmt.setInt(1, 1);
411+
pstmt.setBigDecimal(2, new BigDecimal("12345.6789"));
412+
assertEquals(1, pstmt.executeUpdate());
413+
}
414+
415+
ResultSet rs =
416+
executeQuery(
417+
connection,
418+
"SELECT dec_val FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
419+
assertTrue(rs.next());
420+
assertEquals(
421+
new BigDecimal("12345.6789"), rs.getBigDecimal("dec_val"), "BigDecimal value should match");
422+
423+
rs.close();
424+
deleteTable(connection, tableName);
425+
}
426+
292427
// --- PreparedStatement enhancement tests ---
293428

294429
@Test
@@ -350,6 +485,62 @@ void testSetNull_WithIntType() throws SQLException {
350485
deleteTable(connection, tableName);
351486
}
352487

488+
@Test
489+
void testSetDate() throws SQLException {
490+
String tableName = "pstmt_set_date_table";
491+
String createSQL =
492+
"CREATE TABLE " + getFullyQualifiedTableName(tableName) + " (id INT, date_val DATE)";
493+
setupDatabaseTable(connection, tableName, createSQL);
494+
495+
Date testDate = Date.valueOf("2024-06-15");
496+
String insertSQL =
497+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, date_val) VALUES (?, ?)";
498+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
499+
pstmt.setInt(1, 1);
500+
pstmt.setDate(2, testDate);
501+
assertEquals(1, pstmt.executeUpdate());
502+
}
503+
504+
ResultSet rs =
505+
executeQuery(
506+
connection,
507+
"SELECT date_val FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
508+
assertTrue(rs.next());
509+
assertEquals(testDate, rs.getDate("date_val"), "Date value should match");
510+
511+
rs.close();
512+
deleteTable(connection, tableName);
513+
}
514+
515+
@Test
516+
void testSetTimestamp() throws SQLException {
517+
String tableName = "pstmt_set_timestamp_table";
518+
String createSQL =
519+
"CREATE TABLE " + getFullyQualifiedTableName(tableName) + " (id INT, ts_val TIMESTAMP)";
520+
setupDatabaseTable(connection, tableName, createSQL);
521+
522+
Timestamp testTs = Timestamp.valueOf("2024-06-15 10:30:00");
523+
String insertSQL =
524+
"INSERT INTO " + getFullyQualifiedTableName(tableName) + " (id, ts_val) VALUES (?, ?)";
525+
try (PreparedStatement pstmt = connection.prepareStatement(insertSQL)) {
526+
pstmt.setInt(1, 1);
527+
pstmt.setTimestamp(2, testTs);
528+
assertEquals(1, pstmt.executeUpdate());
529+
}
530+
531+
ResultSet rs =
532+
executeQuery(
533+
connection,
534+
"SELECT ts_val FROM " + getFullyQualifiedTableName(tableName) + " WHERE id = 1");
535+
assertTrue(rs.next());
536+
Timestamp retrieved = rs.getTimestamp("ts_val");
537+
assertNotNull(retrieved, "Timestamp should not be null");
538+
assertEquals(testTs, retrieved, "Timestamp value should match");
539+
540+
rs.close();
541+
deleteTable(connection, tableName);
542+
}
543+
353544
@Test
354545
void testSetObject_WithoutSqlType() throws SQLException {
355546
String tableName = "pstmt_setobj_notype_table";

0 commit comments

Comments
 (0)