From 299ef7aebae9cd5733266f7cc4d1f7b873a893d2 Mon Sep 17 00:00:00 2001 From: Sreekanth Vadigi Date: Mon, 23 Feb 2026 21:30:23 +0530 Subject: [PATCH 1/2] cross catalog metadata operations in comparator Signed-off-by: Sreekanth Vadigi --- .../com/jayant/JDBCDriverComparisonTest.java | 10 +-- .../java/com/jayant/ResultSetComparator.java | 12 ++- .../DatabaseMetaDataTestParams.java | 86 +++++++++++++++++++ 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/jayant/JDBCDriverComparisonTest.java b/src/test/java/com/jayant/JDBCDriverComparisonTest.java index e4c7ce6776..3d5882ac1a 100644 --- a/src/test/java/com/jayant/JDBCDriverComparisonTest.java +++ b/src/test/java/com/jayant/JDBCDriverComparisonTest.java @@ -174,7 +174,7 @@ private static Stream withResultSetPairs(Stream baseProvid return combined.stream(); } - @ParameterizedTest + @ParameterizedTest(autoCloseArguments = false) @MethodSource("provideSQLQueries") @DisplayName("Compare SQL Query Results") void compareSQLQueryResults( @@ -197,7 +197,7 @@ void compareSQLQueryResults( }); } - @ParameterizedTest + @ParameterizedTest(autoCloseArguments = false) @MethodSource("provideMetadataMethods") @DisplayName("Compare Metadata API Results") void compareMetadataResults( @@ -227,7 +227,7 @@ void compareMetadataResults( }); } - @ParameterizedTest + @ParameterizedTest(autoCloseArguments = false) @MethodSource("provideResultSetMethods") @DisplayName("Compare ResultSet API Results") void compareResultSetResults( @@ -254,7 +254,7 @@ void compareResultSetResults( }); } - @ParameterizedTest + @ParameterizedTest(autoCloseArguments = false) @MethodSource("provideResultSetMetaDataMethods") @DisplayName("Compare ResultSetMetaData API Results") void compareResultSetMetaDataResults( @@ -283,7 +283,7 @@ void compareResultSetMetaDataResults( }); } - @ParameterizedTest + @ParameterizedTest(autoCloseArguments = false) @MethodSource("provideConnectionMethods") @DisplayName("Compare Connection API Results") void compareConnectionResults( diff --git a/src/test/java/com/jayant/ResultSetComparator.java b/src/test/java/com/jayant/ResultSetComparator.java index cae00ebf9c..f315b51348 100644 --- a/src/test/java/com/jayant/ResultSetComparator.java +++ b/src/test/java/com/jayant/ResultSetComparator.java @@ -22,11 +22,15 @@ public static ComparisonResult compare( if (result1 instanceof ResultSet && result2 instanceof ResultSet) { ResultSet rs1 = (ResultSet) result1; ResultSet rs2 = (ResultSet) result2; - // Compare metadata - result.metadataDifferences = compareMetadata(rs1.getMetaData(), rs2.getMetaData()); + try { + // Compare metadata + result.metadataDifferences = compareMetadata(rs1.getMetaData(), rs2.getMetaData()); - // Compare data - result.dataDifferences = compareData(rs1, rs2); + // Compare data + result.dataDifferences = compareData(rs1, rs2); + } catch (SQLException e) { + result.dataDifferences.add("ResultSet iteration error: " + e.getMessage()); + } } else if (!(result1 instanceof ResultSet) && !(result2 instanceof ResultSet)) { // Both are not of type ResultSet if (result1 == null || !resultIsSame(result1, result2)) { diff --git a/src/test/java/com/jayant/testparams/DatabaseMetaDataTestParams.java b/src/test/java/com/jayant/testparams/DatabaseMetaDataTestParams.java index 486700e71c..33cd6be1ab 100644 --- a/src/test/java/com/jayant/testparams/DatabaseMetaDataTestParams.java +++ b/src/test/java/com/jayant/testparams/DatabaseMetaDataTestParams.java @@ -95,6 +95,87 @@ public Map, Set> getFunctionToArgsMap() { Map.entry("getAttributes", 4), new String[] {"main", "tpcds_sf100_delta", "%", "%"}); + // Cross-catalog tests: null catalog (match all catalogs) + putInMapForKey( + functionToArgsMap, + Map.entry("getTables", 4), + new String[] {null, "tpcds_sf100_delta", "%", null}); + putInMapForKey( + functionToArgsMap, + Map.entry("getTablePrivileges", 3), + new String[] {null, "tpcds_sf100_delta", "%"}); + putInMapForKey(functionToArgsMap, Map.entry("getSchemas", 2), new String[] {null, "tpcds_%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getColumns", 4), + new String[] {null, "tpcds_sf100_delta", "catalog_sales", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getPseudoColumns", 4), + new String[] {null, "tpcds_sf100_delta", "catalog_sales", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getColumnPrivileges", 4), + new String[] {null, "tpcds_sf100_delta", "catalog_sales", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getVersionColumns", 3), + new String[] {null, "tpcds_sf100_delta", "catalog_sales"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getFunctions", 3), + new String[] {null, "tpcds_sf100_delta", "aggregate"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getFunctionColumns", 4), + new String[] {null, "tpcds_sf100_delta", "aggregate", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getProcedures", 3), + new String[] {null, "tpcds_sf100_delta", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getProcedureColumns", 4), + new String[] {null, "tpcds_sf100_delta", "%", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getPrimaryKeys", 3), + new String[] {null, "oss_jdbc_tests", "test_result_set_types"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getImportedKeys", 3), + new String[] {null, "tpcds_sf100_delta", "catalog_sales"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getExportedKeys", 3), + new String[] {null, "tpcds_sf100_delta", "catalog_sales"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getCrossReference", 6), + new String[] { + null, "tpcds_sf100_delta", "catalog_sales", null, "tpcds_sf100_delta", "catalog_sales" + }); + putInMapForKey( + functionToArgsMap, + Map.entry("getIndexInfo", 5), + new Object[] {null, "tpcds_sf100_delta", "catalog_sales", true, false}); + putInMapForKey( + functionToArgsMap, + Map.entry("getUDTs", 4), + new String[] {null, "tpcds_sf100_delta", "%", null}); + putInMapForKey( + functionToArgsMap, + Map.entry("getSuperTypes", 3), + new String[] {null, "tpcds_sf100_delta", "%"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getSuperTables", 3), + new String[] {null, "tpcds_sf100_delta", "catalog_sales"}); + putInMapForKey( + functionToArgsMap, + Map.entry("getAttributes", 4), + new String[] {null, "tpcds_sf100_delta", "%", "%"}); + // Methods for ResultSet concurrency and visibility for (Integer type : getResultSetTypes()) { putInMapForKey( @@ -129,6 +210,11 @@ public Map, Set> getFunctionToArgsMap() { functionToArgsMap, Map.entry("getBestRowIdentifier", 5), new Object[] {"main", "tpcds_sf100_delta", "catalog_sales", i, true}); + // Cross-catalog: null catalog + putInMapForKey( + functionToArgsMap, + Map.entry("getBestRowIdentifier", 5), + new Object[] {null, "tpcds_sf100_delta", "catalog_sales", i, true}); } for (Integer i : getResultSetHoldability()) { putInMapForKey( From 0c9a3aa0d200a78ffcf896b5e142bf7977d530e1 Mon Sep 17 00:00:00 2001 From: Sreekanth Vadigi Date: Tue, 24 Feb 2026 15:59:12 +0530 Subject: [PATCH 2/2] comparator - statement interface tests Signed-off-by: Sreekanth Vadigi --- .../com/jayant/JDBCDriverComparisonTest.java | 77 ++++++++++++++++ .../testparams/StatementTestParams.java | 92 +++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 src/test/java/com/jayant/testparams/StatementTestParams.java diff --git a/src/test/java/com/jayant/JDBCDriverComparisonTest.java b/src/test/java/com/jayant/JDBCDriverComparisonTest.java index 3d5882ac1a..2762536e12 100644 --- a/src/test/java/com/jayant/JDBCDriverComparisonTest.java +++ b/src/test/java/com/jayant/JDBCDriverComparisonTest.java @@ -6,6 +6,7 @@ import com.jayant.testparams.DatabaseMetaDataTestParams; import com.jayant.testparams.ResultSetMetaDataTestParams; import com.jayant.testparams.ResultSetTestParams; +import com.jayant.testparams.StatementTestParams; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -42,6 +43,12 @@ public class JDBCDriverComparisonTest { // ResultSets for Thrift vs SEA comparison private static ResultSet ossThriftResultSet; private static ResultSet ossSeaResultSet2; + // Statements for Old vs SEA comparison + private static Statement oldDriverStatement; + private static Statement ossSeaStatement1; + // Statements for Thrift vs SEA comparison + private static Statement ossThriftStatement; + private static Statement ossSeaStatement2; @BeforeAll static void setup() throws Exception { @@ -89,6 +96,12 @@ static void setup() throws Exception { ossThriftResultSet = ossThriftConnection.createStatement().executeQuery(queryResultSetTypesTable); ossSeaResultSet2 = ossSeaConnection.createStatement().executeQuery(queryResultSetTypesTable); + + // Create separate Statements for each comparison pair + oldDriverStatement = oldDriverConnection.createStatement(); + ossSeaStatement1 = ossSeaConnection.createStatement(); + ossThriftStatement = ossThriftConnection.createStatement(); + ossSeaStatement2 = ossSeaConnection.createStatement(); } @AfterAll @@ -174,6 +187,37 @@ private static Stream withResultSetPairs(Stream baseProvid return combined.stream(); } + /** + * Helper method for tests that need Statements. Prepends Statement pair info (name, stmt1, stmt2) + * to original arguments. + */ + private static Stream withStatementPairs(Stream baseProvider) { + List base = baseProvider.collect(Collectors.toList()); + List combined = new ArrayList<>(); + + // Define Statement pairs - each with separate instances to avoid reuse + Object[][] statementPairs = { + {"Old(2.7.6) vs OSS-SEA", oldDriverStatement, ossSeaStatement1}, + {"OSS-Thrift vs OSS-SEA", ossThriftStatement, ossSeaStatement2} + }; + + // Combine each pair with each base argument + for (Object[] pair : statementPairs) { + for (Arguments arg : base) { + Object[] originalArgs = arg.get(); + // Create new array: [name, stmt1, stmt2, ...originalArgs] + Object[] newArgs = new Object[3 + originalArgs.length]; + newArgs[0] = pair[0]; // comparison name + newArgs[1] = pair[1]; // statement 1 + newArgs[2] = pair[2]; // statement 2 + System.arraycopy(originalArgs, 0, newArgs, 3, originalArgs.length); + combined.add(Arguments.of(newArgs)); + } + } + + return combined.stream(); + } + @ParameterizedTest(autoCloseArguments = false) @MethodSource("provideSQLQueries") @DisplayName("Compare SQL Query Results") @@ -310,6 +354,33 @@ void compareConnectionResults( }); } + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("provideStatementMethods") + @DisplayName("Compare Statement API Results") + void compareStatementResults( + String comparisonName, Statement stmt1, Statement stmt2, String methodName, Object[] args) { + assertDoesNotThrow( + () -> { + Object result1 = ReflectionUtils.executeMethod(stmt1, methodName, args); + Object result2 = ReflectionUtils.executeMethod(stmt2, methodName, args); + + ComparisonResult result = + ResultSetComparator.compare( + "Statement [" + comparisonName + "]", methodName, args, result1, result2); + reporter.addResult(result); + + if (result.hasDifferences()) { + System.err.println( + "[" + + comparisonName + + "] Differences found in Statement results for method: " + + methodName); + System.err.println("Args: " + getStringForArgs(args)); + System.err.println(result); + } + }); + } + private static Stream provideSQLQueries() { Stream base = Stream.of( @@ -343,6 +414,12 @@ private static Stream provideConnectionMethods() { return withConnectionPairs(base); } + private static Stream provideStatementMethods() { + StatementTestParams params = new StatementTestParams(); + Stream base = ReflectionUtils.provideMethodsForClass(Statement.class, params); + return withStatementPairs(base); + } + private static URL extractJarToTemp(String jarName, Path tempDir) { try { try (InputStream in = JDBCDriverComparisonTest.class.getResourceAsStream("/" + jarName)) { diff --git a/src/test/java/com/jayant/testparams/StatementTestParams.java b/src/test/java/com/jayant/testparams/StatementTestParams.java new file mode 100644 index 0000000000..ee07cacd6c --- /dev/null +++ b/src/test/java/com/jayant/testparams/StatementTestParams.java @@ -0,0 +1,92 @@ +package com.jayant.testparams; + +import static com.jayant.testparams.ParamUtils.putInMapForKey; + +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.*; + +public class StatementTestParams implements TestParams { + + @Override + public Set> getAcceptedKnownDiffs() { + Set> set = new HashSet<>(); + + // Do not close the shared statement + set.add(Map.entry("close", 0)); + + // Cancel needs an active query + set.add(Map.entry("cancel", 0)); + + // Void side effects on shared object + set.add(Map.entry("clearWarnings", 0)); + set.add(Map.entry("closeOnCompletion", 0)); + set.add(Map.entry("clearBatch", 0)); + + // Returns object references (not comparable across drivers) + set.add(Map.entry("getConnection", 0)); + + // Execution methods - tested via SQL query comparator tests + set.add(Map.entry("executeQuery", 1)); + set.add(Map.entry("executeUpdate", 1)); + set.add(Map.entry("execute", 1)); + set.add(Map.entry("executeLargeUpdate", 1)); + set.add(Map.entry("executeUpdate", 2)); + set.add(Map.entry("execute", 2)); + set.add(Map.entry("executeLargeUpdate", 2)); + + // Batch operations - DML side effects + set.add(Map.entry("executeBatch", 0)); + set.add(Map.entry("executeLargeBatch", 0)); + set.add(Map.entry("addBatch", 1)); + + // Not implemented / throws + set.add(Map.entry("setCursorName", 1)); + + // Driver-specific wrapper methods + set.add(Map.entry("unwrap", 1)); + set.add(Map.entry("isWrapperFor", 1)); + + return set; + } + + @Override + public Map, Set> getFunctionToArgsMap() { + Map, Set> functionToArgsMap = new HashMap<>(); + + // SQL quoting methods + putInMapForKey( + functionToArgsMap, Map.entry("enquoteLiteral", 1), new Object[] {"test's value"}); + putInMapForKey( + functionToArgsMap, Map.entry("enquoteIdentifier", 2), new Object[] {"my column", true}); + putInMapForKey( + functionToArgsMap, Map.entry("enquoteIdentifier", 2), new Object[] {"simple", false}); + putInMapForKey(functionToArgsMap, Map.entry("isSimpleIdentifier", 1), new Object[] {"simple"}); + putInMapForKey( + functionToArgsMap, Map.entry("isSimpleIdentifier", 1), new Object[] {"has space"}); + putInMapForKey( + functionToArgsMap, Map.entry("enquoteNCharLiteral", 1), new Object[] {"test string"}); + + // Setter methods (compare void returns + catch exception differences) + putInMapForKey(functionToArgsMap, Map.entry("setMaxRows", 1), new Object[] {10}); + putInMapForKey(functionToArgsMap, Map.entry("setLargeMaxRows", 1), new Object[] {10L}); + putInMapForKey(functionToArgsMap, Map.entry("setMaxFieldSize", 1), new Object[] {100}); + putInMapForKey(functionToArgsMap, Map.entry("setQueryTimeout", 1), new Object[] {30}); + putInMapForKey(functionToArgsMap, Map.entry("setFetchSize", 1), new Object[] {100}); + putInMapForKey( + functionToArgsMap, + Map.entry("setFetchDirection", 1), + new Object[] {ResultSet.FETCH_FORWARD}); + putInMapForKey(functionToArgsMap, Map.entry("setPoolable", 1), new Object[] {false}); + putInMapForKey(functionToArgsMap, Map.entry("setEscapeProcessing", 1), new Object[] {true}); + putInMapForKey(functionToArgsMap, Map.entry("setEscapeProcessing", 1), new Object[] {false}); + + // getMoreResults with flag + putInMapForKey( + functionToArgsMap, + Map.entry("getMoreResults", 1), + new Object[] {Statement.CLOSE_CURRENT_RESULT}); + + return functionToArgsMap; + } +}