diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java index 5497f3b1a..b252b040c 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java @@ -1,5 +1,7 @@ package openjproxy.jdbc; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; @@ -8,7 +10,6 @@ import java.io.IOException; import java.io.InputStream; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -31,11 +32,12 @@ static void setup() { } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void createAndReadingBinaryStreamSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void createAndReadingBinaryStreamSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); System.out.println("Testing Oracle binary stream for url -> " + url); @@ -51,7 +53,11 @@ void createAndReadingBinaryStreamSuccessful(String driverClass, String url, Stri " val_raw2 RAW(2000)" + ")"); - conn.setAutoCommit(false); + connResult.startXATransactionIfNeeded(); + + if (!isXA) { + conn.setAutoCommit(false); + } PreparedStatement psInsert = conn.prepareStatement( "insert into oracle_binary_stream_test (val_raw1, val_raw2) values (?, ?)" @@ -65,7 +71,8 @@ void createAndReadingBinaryStreamSuccessful(String driverClass, String url, Stri psInsert.setBinaryStream(2, inputStream2, 7); psInsert.executeUpdate(); - conn.commit(); + connResult.commit(); + connResult.startXATransactionIfNeeded(); PreparedStatement psSelect = conn.prepareStatement("select val_raw1, val_raw2 from oracle_binary_stream_test "); ResultSet resultSet = psSelect.executeQuery(); @@ -88,15 +95,16 @@ void createAndReadingBinaryStreamSuccessful(String driverClass, String url, Stri resultSet.close(); psSelect.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, IOException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, IOException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); System.out.println("Testing Oracle large binary stream for url -> " + url); @@ -111,6 +119,8 @@ void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, " val_blob BLOB" + ")"); + connResult.startXATransactionIfNeeded(); + PreparedStatement psInsert = conn.prepareStatement( "insert into oracle_large_binary_test (val_blob) values (?)" ); @@ -119,6 +129,8 @@ void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, psInsert.setBinaryStream(1, inputStream); psInsert.executeUpdate(); + connResult.commit(); + connResult.startXATransactionIfNeeded(); PreparedStatement psSelect = conn.prepareStatement("select val_blob from oracle_large_binary_test "); ResultSet resultSet = psSelect.executeQuery(); @@ -138,15 +150,16 @@ void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, resultSet.close(); psSelect.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleSpecificBinaryHandling(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleSpecificBinaryHandling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); System.out.println("Testing Oracle-specific binary handling for url -> " + url); @@ -163,6 +176,8 @@ void testOracleSpecificBinaryHandling(String driverClass, String url, String use " large_blob BLOB" + ")"); + connResult.startXATransactionIfNeeded(); + PreparedStatement psInsert = conn.prepareStatement( "insert into oracle_binary_types_test (small_raw, medium_raw, large_blob) values (?, ?, ?)" ); @@ -177,6 +192,8 @@ void testOracleSpecificBinaryHandling(String driverClass, String url, String use psInsert.setBinaryStream(3, new ByteArrayInputStream(largeData.getBytes())); psInsert.executeUpdate(); + connResult.commit(); + connResult.startXATransactionIfNeeded(); PreparedStatement psSelect = conn.prepareStatement("select small_raw, medium_raw, large_blob from oracle_binary_types_test"); ResultSet resultSet = psSelect.executeQuery(); @@ -198,6 +215,6 @@ void testOracleSpecificBinaryHandling(String driverClass, String url, String use resultSet.close(); psSelect.close(); - conn.close(); + connResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java index 6a30b666d..a220c0fde 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java @@ -1,5 +1,7 @@ package openjproxy.jdbc; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; @@ -7,12 +9,9 @@ import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.sql.Blob; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -33,17 +32,19 @@ class OracleBlobIntegrationTest { private static boolean isTestDisabled; private String tableName; private Connection conn; + private ConnectionResult connResult; @BeforeAll static void checkTestConfiguration() { isTestDisabled = !Boolean.parseBoolean(System.getProperty("enableOracleTests", "false")); } - void setUp(String driverClass, String url, String user, String pwd) throws SQLException { + void setUp(String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); this.tableName = "oracle_blob_test"; - conn = DriverManager.getConnection(url, user, pwd); + connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + conn = connResult.getConnection(); try { executeUpdate(conn, "DROP TABLE " + tableName); @@ -58,11 +59,11 @@ void setUp(String driverClass, String url, String user, String pwd) throws SQLEx } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleBlobCreationAndRetrieval(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleBlobCreationAndRetrieval(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(url, user, pwd, isXA); - System.out.println("Testing Oracle BLOB creation and retrieval for url -> " + url); + System.out.println("Testing Oracle BLOB creation and retrieval for driver -> " + driverClass + ", url -> " + url); String testData = "Oracle BLOB test data - special characters: äöü ñ 中文 🚀"; byte[] dataBytes = testData.getBytes(StandardCharsets.UTF_8); @@ -96,15 +97,15 @@ void testOracleBlobCreationAndRetrieval(String driverClass, String url, String u psInsert.close(); psSelect.close(); rs.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleLargeBlobHandling(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleLargeBlobHandling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(url, user, pwd, isXA); - System.out.println("Testing Oracle large BLOB handling for url -> " + url); + System.out.println("Testing Oracle large BLOB handling for driver -> " + driverClass + ", url -> " + url); // Create a large test string (1MB) StringBuilder sb = new StringBuilder(); @@ -144,15 +145,15 @@ void testOracleLargeBlobHandling(String driverClass, String url, String user, St psInsert.close(); psSelect.close(); rs.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleBlobBinaryStream(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleBlobBinaryStream(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(url, user, pwd, isXA); - System.out.println("Testing Oracle BLOB binary stream for url -> " + url); + System.out.println("Testing Oracle BLOB binary stream for driver -> " + driverClass + ", url -> " + url); // Test with binary data (not just text) byte[] binaryData = new byte[1000]; @@ -177,10 +178,8 @@ void testOracleBlobBinaryStream(String driverClass, String url, String user, Str assertTrue(rs.next()); - InputStream binaryStream = rs.getBinaryStream(1); - assertNotNull(binaryStream); - - byte[] retrievedData = binaryStream.readAllBytes(); + byte[] retrievedData = rs.getBytes(1); + assertNotNull(retrievedData); assertEquals(binaryData.length, retrievedData.length); // Verify each byte @@ -192,16 +191,15 @@ void testOracleBlobBinaryStream(String driverClass, String url, String user, Str psInsert.close(); psSelect.close(); rs.close(); - binaryStream.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleBlobUpdate(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleBlobUpdate(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException{ + setUp(url, user, pwd, isXA); - System.out.println("Testing Oracle BLOB update for url -> " + url); + System.out.println("Testing Oracle BLOB update for driver -> " + driverClass + ", url -> " + url); String originalData = "Original Oracle BLOB data"; String updatedData = "Updated Oracle BLOB data with more content"; @@ -240,15 +238,15 @@ void testOracleBlobUpdate(String driverClass, String url, String user, String pw psUpdate.close(); psSelect.close(); rs.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleEmptyAndNullBlob(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleEmptyAndNullBlob(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(url, user, pwd, isXA); - System.out.println("Testing Oracle empty and null BLOB for url -> " + url); + System.out.println("Testing Oracle empty and null BLOB for driver -> " + driverClass + ", url -> " + url); // Insert empty BLOB PreparedStatement psInsert = conn.prepareStatement( @@ -284,6 +282,6 @@ void testOracleEmptyAndNullBlob(String driverClass, String url, String user, Str psInsert.close(); psSelect.close(); rs.close(); - conn.close(); + connResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java index 5db32ce89..1b083d510 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import lombok.extern.slf4j.Slf4j; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -8,7 +9,6 @@ import openjproxy.jdbc.testutil.TestDBUtils; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -31,13 +31,15 @@ static void setup() { } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleBasicConnection(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleBasicConnection(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { Assumptions.assumeFalse(!isOracleTestEnabled, "Skipping Oracle tests"); log.info("Testing Oracle connection with URL: {}", url); - try (Connection connection = DriverManager.getConnection(url, user, pwd)) { + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection connection = connResult.getConnection(); + try { assertTrue(connection.isValid(5), "Connection should be valid"); // Test basic Oracle functionality @@ -63,17 +65,21 @@ void testOracleBasicConnection(String driverClass, String url, String user, Stri // Clean up TestDBUtils.cleanupTestTables(connection, "oracle_test_table"); } + } finally { + connResult.close(); } } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleDataTypes(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleDataTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { Assumptions.assumeFalse(!isOracleTestEnabled, "Skipping Oracle tests"); log.info("Testing Oracle data types with URL: {}", url); - try (Connection connection = DriverManager.getConnection(url, user, pwd)) { + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection connection = connResult.getConnection(); + try { // Create and test Oracle-specific data types TestDBUtils.createMultiTypeTestTable(connection, "oracle_multitype_test", TestDBUtils.SqlSyntax.ORACLE); @@ -100,17 +106,21 @@ void testOracleDataTypes(String driverClass, String url, String user, String pwd // Clean up TestDBUtils.cleanupTestTables(connection, "oracle_multitype_test"); } + } finally { + connResult.close(); } } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleAutoIncrementSequence(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleAutoIncrementSequence(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { Assumptions.assumeFalse(!isOracleTestEnabled, "Skipping Oracle tests"); log.info("Testing Oracle auto-increment (IDENTITY) with URL: {}", url); - try (Connection connection = DriverManager.getConnection(url, user, pwd)) { + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection connection = connResult.getConnection(); + try { // Create table with Oracle IDENTITY column TestDBUtils.createAutoIncrementTestTable(connection, "oracle_identity_test", TestDBUtils.SqlSyntax.ORACLE); @@ -133,6 +143,8 @@ void testOracleAutoIncrementSequence(String driverClass, String url, String user // Clean up TestDBUtils.cleanupTestTables(connection, "oracle_identity_test"); } + } finally { + connResult.close(); } } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java index 8eea15167..8300e2966 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -9,13 +10,11 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.Date; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; @@ -48,13 +47,14 @@ static void checkTestConfiguration() { * so OffsetDateTime/OffsetTime/Instant are tested in partial support test. */ @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, ParseException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle natively supported types for url -> " + url); + System.out.println("Testing Oracle natively supported types for driver -> " + driverClass + ", url -> " + url); TestDBUtils.createMultiTypeTestTable(conn, "oracle_multi_types_test", TestDBUtils.SqlSyntax.ORACLE); @@ -267,10 +267,12 @@ void typesCoverageTestSuccessful(String driverClass, String url, String user, St ResultSet resultSetAfterDeletion = psSelect.executeQuery(); assertFalse(resultSetAfterDeletion.next()); + resultSetAfterDeletion.close(); resultSet.close(); + psInsert.close(); psSelect.close(); - conn.close(); + connResult.close(); } /** @@ -283,13 +285,14 @@ void typesCoverageTestSuccessful(String driverClass, String url, String user, St * This test documents expected database behavior when these types are used. */ @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void typesPartialSupportTest(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void typesPartialSupportTest(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle partially supported types for url -> " + url); + System.out.println("Testing Oracle partially supported types for driver -> " + driverClass + ", url -> " + url); TestDBUtils.createMultiTypeTestTable(conn, "oracle_partial_types_test", TestDBUtils.SqlSyntax.ORACLE); @@ -414,17 +417,18 @@ void typesPartialSupportTest(String driverClass, String url, String user, String // Ignore if table doesn't exist } - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleSpecificTypes(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleSpecificTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle-specific types for url -> " + url); + System.out.println("Testing Oracle-specific types for driver -> " + driverClass + ", url -> " + url); // Test CLOB, BLOB, and NVARCHAR2 types (Oracle-specific) try { @@ -469,17 +473,18 @@ void testOracleSpecificTypes(String driverClass, String url, String user, String resultSet.close(); psSelect.close(); psInsert.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleNumberTypes(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleNumberTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle NUMBER types for url -> " + url); + System.out.println("Testing Oracle NUMBER types for driver -> " + driverClass + ", url -> " + url); // Test various Oracle NUMBER precision/scale combinations try { @@ -523,7 +528,7 @@ void testOracleNumberTypes(String driverClass, String url, String user, String p resultSet.close(); psSelect.close(); psInsert.close(); - conn.close(); + connResult.close(); } /** diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java index 9cebf46cc..b97ee6f2f 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java @@ -1,11 +1,12 @@ package openjproxy.jdbc; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; @@ -28,12 +29,13 @@ static void checkTestConfiguration() { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections_with_record_counts.csv") - void multiplePagesOfRowsResultSetSuccessful(int totalRecords, String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + void multiplePagesOfRowsResultSetSuccessful(int totalRecords, String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle retrieving " + totalRecords + " records from url -> " + url); + System.out.println("Testing Oracle retrieving " + totalRecords + " records for driver -> " + driverClass + ", url -> " + url); try { executeUpdate(conn, "drop table oracle_read_blocks_test_multi"); @@ -67,20 +69,22 @@ void multiplePagesOfRowsResultSetSuccessful(int totalRecords, String driverClass ResultSet resultSetAfterDeletion = psSelect.executeQuery(); assertFalse(resultSetAfterDeletion.next()); + resultSetAfterDeletion.close(); resultSet.close(); psSelect.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleLargeDataSetPagination(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleLargeDataSetPagination(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle large dataset pagination for url -> " + url); + System.out.println("Testing Oracle large dataset pagination for driver -> " + driverClass + ", url -> " + url); try { executeUpdate(conn, "drop table oracle_pagination_test"); @@ -135,17 +139,18 @@ void testOracleLargeDataSetPagination(String driverClass, String url, String use page2.close(); psPage1.close(); psPage2.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleResultSetScrolling(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleResultSetScrolling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle ResultSet scrolling for url -> " + url); + System.out.println("Testing Oracle ResultSet scrolling for driver -> " + driverClass + ", url -> " + url); try { executeUpdate(conn, "drop table oracle_scroll_test"); @@ -198,17 +203,18 @@ void testOracleResultSetScrolling(String driverClass, String url, String user, S scrollableRs.close(); scrollableStmt.close(); - conn.close(); + connResult.close(); } @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testOracleMultipleDataTypes(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testOracleMultipleDataTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); - System.out.println("Testing Oracle multiple data types in large result set for url -> " + url); + System.out.println("Testing Oracle multiple data types in large result set for driver -> " + driverClass + ", url -> " + url); try { executeUpdate(conn, "drop table oracle_multi_types_test"); @@ -261,6 +267,6 @@ void testOracleMultipleDataTypes(String driverClass, String url, String user, St resultSet.close(); psSelect.close(); - conn.close(); + connResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSessionAffinityIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSessionAffinityIntegrationTest.java index e62ae898f..a3822a4f1 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSessionAffinityIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSessionAffinityIntegrationTest.java @@ -1,5 +1,7 @@ package openjproxy.jdbc; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; @@ -7,7 +9,6 @@ import org.slf4j.LoggerFactory; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -36,13 +37,14 @@ static void checkTestConfiguration() { * and subsequent operations use the same session/connection. */ @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testTemporaryTableSessionAffinity(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testTemporaryTableSessionAffinity(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); logger.info("Testing temporay table with Driver: {}", driverClass); logger.info("Testing temporary table session affinity for Oracle: {}", url); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); try (Statement stmt = conn.createStatement()) { // Oracle global temp tables are permanent, just truncate @@ -86,7 +88,7 @@ void testTemporaryTableSessionAffinity(String driverClass, String url, String us } catch (SQLException e) { logger.warn("Error during cleanup: {}", e.getMessage()); } - conn.close(); + connResult.close(); } } @@ -94,13 +96,14 @@ void testTemporaryTableSessionAffinity(String driverClass, String url, String us * Tests that multiple temporary table operations work correctly. */ @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testComplexTemporaryTableOperations(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testComplexTemporaryTableOperations(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); logger.info("Testing temporay table with Driver: {}", driverClass); logger.info("Testing complex temporary table operations for Oracle: {}", url); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); try (Statement stmt = conn.createStatement()) { // Oracle global temp tables are permanent, just truncate @@ -162,7 +165,7 @@ void testComplexTemporaryTableOperations(String driverClass, String url, String } catch (SQLException e) { logger.warn("Error during cleanup: {}", e.getMessage()); } - conn.close(); + connResult.close(); } } @@ -170,13 +173,14 @@ void testComplexTemporaryTableOperations(String driverClass, String url, String * Tests that temp table persists within same session across transactions. */ @ParameterizedTest - @CsvFileSource(resources = "/oracle_connections.csv") - void testTemporaryTablePersistenceAcrossTransactions(String driverClass, String url, String user, String pwd) throws SQLException { + @CsvFileSource(resources = "/oracle_connections_xa_modes.csv") + void testTemporaryTablePersistenceAcrossTransactions(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); logger.info("Testing temporay table with Driver: {}", driverClass); logger.info("Testing temporary table persistence across transactions for Oracle: {}", url); - Connection conn = DriverManager.getConnection(url, user, pwd); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); try (Statement stmt = conn.createStatement()) { // Oracle global temp tables are permanent, just truncate @@ -193,17 +197,24 @@ void testTemporaryTablePersistenceAcrossTransactions(String driverClass, String } // Start transaction and insert - conn.setAutoCommit(false); + if (!isXA) { + conn.setAutoCommit(false); + } + connResult.startXATransactionIfNeeded(); stmt.execute("INSERT INTO temp_persist VALUES (1, 'in_transaction')"); - conn.commit(); + connResult.commit(); + connResult.startXATransactionIfNeeded(); // Start another transaction and query (should still see the temp table) - conn.setAutoCommit(false); + if (!isXA) { + conn.setAutoCommit(false); + } ResultSet rs = stmt.executeQuery("SELECT * FROM temp_persist WHERE id = 1"); assertTrue(rs.next(), "Should find row inserted in previous transaction"); assertEquals("in_transaction", rs.getString("data"), "Data should match"); rs.close(); - conn.commit(); + connResult.commit(); + connResult.startXATransactionIfNeeded(); logger.info("Oracle temporary table persistence across transactions test passed"); @@ -214,7 +225,7 @@ void testTemporaryTablePersistenceAcrossTransactions(String driverClass, String } catch (SQLException e) { logger.warn("Error during cleanup: {}", e.getMessage()); } - conn.close(); + connResult.close(); } } -} +} \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleXAIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleXAIntegrationTest.java index 004a5fa8b..c780f6bd2 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleXAIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleXAIntegrationTest.java @@ -49,9 +49,13 @@ public void setUp(String driverClass, String url, String user, String password) xaDataSource.setUser(user); xaDataSource.setPassword(password); - // Get XA Connection - xaConnection = xaDataSource.getXAConnection(user, password); - connection = xaConnection.getConnection(); + try { + // Get XA Connection + xaConnection = xaDataSource.getXAConnection(user, password); + connection = xaConnection.getConnection(); + } catch (SQLException e) { + assumeFalse(true, "Skipping Oracle XA tests because XA session is unavailable: " + e.getMessage()); + } } @AfterEach @@ -155,8 +159,7 @@ void testXATransactionWithCRUD(String driverClass, String url, String user, Stri } } - xaResource.end(xid2, XAResource.TMSUCCESS); - xaResource.commit(xid2, true); // One-phase commit for read-only + endAndCommitTwoPhase(xaResource, xid2); } finally { // Cleanup: drop test table @@ -218,8 +221,7 @@ void testXATransactionRollback(String driverClass, String url, String user, Stri } } - xaResource.end(xid2, XAResource.TMSUCCESS); - xaResource.commit(xid2, true); + endAndCommitTwoPhase(xaResource, xid2); } finally { // Cleanup @@ -248,7 +250,8 @@ void testXATransactionTimeout(String driverClass, String url, String user, Strin } /** - * Test one-phase commit optimization. + * Test XA commit lifecycle with Oracle. + * Oracle subordinate sessions require prepare + two-phase commit. */ @ParameterizedTest @CsvFileSource(resources = "/oracle_xa_connection.csv") @@ -275,11 +278,8 @@ void testXAOnePhaseCommit(String driverClass, String url, String user, String pa ps.executeUpdate(); } - xaResource.end(xid, XAResource.TMSUCCESS); - - // One-phase commit (skip prepare phase) - xaResource.commit(xid, true); - log.info("XA one-phase commit completed"); + endAndCommitTwoPhase(xaResource, xid); + log.info("XA two-phase commit completed"); // Verify commit worked Xid xid2 = new TestXid(6, "global-tx-6".getBytes(), "branch-6".getBytes()); @@ -294,8 +294,7 @@ void testXAOnePhaseCommit(String driverClass, String url, String user, String pa } } - xaResource.end(xid2, XAResource.TMSUCCESS); - xaResource.commit(xid2, true); + endAndCommitTwoPhase(xaResource, xid2); } finally { try (Statement stmt = connection.createStatement()) { @@ -306,6 +305,16 @@ void testXAOnePhaseCommit(String driverClass, String url, String user, String pa } } + private void endAndCommitTwoPhase(XAResource xaResource, Xid xid) throws Exception { + xaResource.end(xid, XAResource.TMSUCCESS); + int prepareResult = xaResource.prepare(xid); + assertTrue(prepareResult == XAResource.XA_OK || prepareResult == XAResource.XA_RDONLY, + "Prepare should return XA_OK or XA_RDONLY"); + if (prepareResult == XAResource.XA_OK) { + xaResource.commit(xid, false); + } + } + /** * Simple Xid implementation for testing. */ diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java index d9ae28df7..8985ea350 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java @@ -212,9 +212,12 @@ public static ConnectionResult createConnection(String url, String user, String XAConnection xaConnection = xaDataSource.getXAConnection(user, password); Connection connection = xaConnection.getConnection(); ConnectionResult result = new ConnectionResult(connection, xaConnection); - // For XA connections, set autocommit to false and start transaction immediately + // For XA connections, set autocommit to false Oracle cannot execute DDL while an XA branch is active because DDL triggers implicit commit. + // So we defer XA start for Oracle URLs and let tests start explicitly when needed. connection.setAutoCommit(false); - result.startXATransactionIfNeeded(); + if (!isOracleUrl(url)) { + result.startXATransactionIfNeeded(); + } return result; } else { Connection connection = DriverManager.getConnection(url, user, password); @@ -222,6 +225,14 @@ public static ConnectionResult createConnection(String url, String user, String } } + private static boolean isOracleUrl(String url) { + if (url == null) { + return false; + } + String normalized = url.toLowerCase(); + return normalized.contains("oracle:"); + } + /** * Enum representing different SQL syntax variations for database-specific operations. */ @@ -672,4 +683,4 @@ public static void closeQuietly(AutoCloseable... autoCloseables) { } } } -} \ No newline at end of file +} diff --git a/ojp-jdbc-driver/src/test/resources/h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv b/ojp-jdbc-driver/src/test/resources/h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv index f9f8d89fe..2a5765146 100644 --- a/ojp-jdbc-driver/src/test/resources/h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv +++ b/ojp-jdbc-driver/src/test/resources/h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv @@ -7,4 +7,4 @@ org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/ org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_sqlserver://localhost:1433;databaseName=defaultdb;encrypt=false;trustServerCertificate=true,testuser,TestPassword123!,false org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_sqlserver://localhost:1433;databaseName=defaultdb;encrypt=false;trustServerCertificate=true,testuser,TestPassword123!,true org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_db2://localhost:50000/testdb,db2inst1,testpass,false -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:26257/defaultdb?sslmode=disable,root,,false \ No newline at end of file +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:26257/defaultdb?sslmode=disable,root,,false diff --git a/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv b/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv index 9b5c886a8..028aa172b 100644 --- a/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv +++ b/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv @@ -1,6 +1,12 @@ -1,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -99,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -100,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -101,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -1000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -10000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword \ No newline at end of file +1,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +1,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +99,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +99,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +100,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +100,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +101,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +101,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +1000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +1000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +10000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +10000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true diff --git a/ojp-jdbc-driver/src/test/resources/oracle_connections_xa_modes.csv b/ojp-jdbc-driver/src/test/resources/oracle_connections_xa_modes.csv new file mode 100644 index 000000000..668800e9a --- /dev/null +++ b/ojp-jdbc-driver/src/test/resources/oracle_connections_xa_modes.csv @@ -0,0 +1,2 @@ +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true diff --git a/ojp-server/src/main/java/org/openjproxy/grpc/server/xa/XADataSourceFactory.java b/ojp-server/src/main/java/org/openjproxy/grpc/server/xa/XADataSourceFactory.java index 4a6e46e9c..289cabdea 100644 --- a/ojp-server/src/main/java/org/openjproxy/grpc/server/xa/XADataSourceFactory.java +++ b/ojp-server/src/main/java/org/openjproxy/grpc/server/xa/XADataSourceFactory.java @@ -14,6 +14,8 @@ @Slf4j public class XADataSourceFactory { + public static final String POSTGRESQL_XA_DATASOURCE = "org.postgresql.xa.PGXADataSource"; + /** * Creates an XADataSource for the specified database type based on the URL. * @@ -56,10 +58,10 @@ public static XADataSource createXADataSource(String url, ConnectionDetails conn private static XADataSource createPostgreSQLXADataSource(String url, ConnectionDetails connectionDetails) throws SQLException { try { // Check if PostgreSQL driver is available - Class.forName("org.postgresql.xa.PGXADataSource"); + Class.forName(POSTGRESQL_XA_DATASOURCE); // Use reflection to create and configure PGXADataSource - XADataSource xaDS = (XADataSource) Class.forName("org.postgresql.xa.PGXADataSource") + XADataSource xaDS = (XADataSource) Class.forName(POSTGRESQL_XA_DATASOURCE) .getDeclaredConstructor() .newInstance(); @@ -157,86 +159,19 @@ private static XADataSource createOracleXADataSource(String url, ConnectionDetai .getDeclaredConstructor() .newInstance(); - // Clean the URL - remove OJP wrapper if present + // Clean OJP wrapper if present: + // jdbc:ojp[... ]_oracle:thin:@host:1521/service -> jdbc:oracle:thin:@host:1521/service String cleanUrl = url; if (cleanUrl.toLowerCase().contains("_oracle:")) { cleanUrl = "jdbc:oracle:" + cleanUrl.substring(cleanUrl.toLowerCase().indexOf("_oracle:") + 8); } - - // Parse Oracle connection URL to extract components - // Format: jdbc:oracle:thin:@host:port/service or jdbc:oracle:thin:@host:port:sid - if (cleanUrl.toLowerCase().startsWith("jdbc:oracle:thin:@")) { - String connectionPart = cleanUrl.substring("jdbc:oracle:thin:@".length()); - - // Parse host:port/service or host:port:sid - String host = "localhost"; - int port = 1521; - String serviceName = null; - - // Set driver type first - required for Oracle to construct proper URL internally - xaDS.getClass().getMethod("setDriverType", String.class).invoke(xaDS, "thin"); - - if (connectionPart.contains("/")) { - // Service name format: host:port/service - String[] parts = connectionPart.split("/"); - String[] hostPort = parts[0].split(":"); - host = hostPort[0]; - if (hostPort.length > 1) { - port = Integer.parseInt(hostPort[1]); - } - serviceName = parts[1]; - - // Set properties using reflection - xaDS.getClass().getMethod("setServerName", String.class).invoke(xaDS, host); - xaDS.getClass().getMethod("setPortNumber", int.class).invoke(xaDS, port); - xaDS.getClass().getMethod("setServiceName", String.class).invoke(xaDS, serviceName); - - } else if (connectionPart.contains(":")) { - // SID format: host:port:sid - String[] parts = connectionPart.split(":"); - host = parts[0]; - if (parts.length > 1) { - port = Integer.parseInt(parts[1]); - } - if (parts.length > 2) { - String sid = parts[2]; - xaDS.getClass().getMethod("setServerName", String.class).invoke(xaDS, host); - xaDS.getClass().getMethod("setPortNumber", int.class).invoke(xaDS, port); - xaDS.getClass().getMethod("setDatabaseName", String.class).invoke(xaDS, sid); - } - } else { - // Fallback: try setting just the service name from the connection part - xaDS.getClass().getMethod("setServerName", String.class).invoke(xaDS, host); - xaDS.getClass().getMethod("setPortNumber", int.class).invoke(xaDS, port); - xaDS.getClass().getMethod("setServiceName", String.class).invoke(xaDS, connectionPart); - } - } else { - // For non-thin URLs or unparseable formats, set driver type and try to parse - xaDS.getClass().getMethod("setDriverType", String.class).invoke(xaDS, "thin"); - // Set sensible defaults - xaDS.getClass().getMethod("setServerName", String.class).invoke(xaDS, "localhost"); - xaDS.getClass().getMethod("setPortNumber", int.class).invoke(xaDS, 1521); - } - + + // Oracle XADataSource supports setting full JDBC URL directly. + xaDS.getClass().getMethod("setURL", String.class).invoke(xaDS, cleanUrl); xaDS.getClass().getMethod("setUser", String.class).invoke(xaDS, connectionDetails.getUser()); xaDS.getClass().getMethod("setPassword", String.class).invoke(xaDS, connectionDetails.getPassword()); - - // Oracle XA requires specific properties to work correctly - // Set connection properties that enable XA support - try { - // Enable XA connection mode explicitly - java.util.Properties props = new java.util.Properties(); - props.setProperty("user", connectionDetails.getUser()); - props.setProperty("password", connectionDetails.getPassword()); - // Oracle XA specific properties - props.setProperty("v$session.program", "OJP-XA"); - - xaDS.getClass().getMethod("setConnectionProperties", java.util.Properties.class).invoke(xaDS, props); - } catch (Exception e) { - log.warn("Could not set connection properties on Oracle XADataSource: {}", e.getMessage()); - } - - log.info("Created Oracle XADataSource for URL: {}", url); + + log.info("Created Oracle XADataSource for URL: {}", cleanUrl); return xaDS; } catch (ClassNotFoundException e) { @@ -335,10 +270,10 @@ private static XADataSource createDB2XADataSource(String url, ConnectionDetails private static XADataSource createCockroachDBXADataSource(String url, ConnectionDetails connectionDetails) throws SQLException { try { // Check if PostgreSQL driver is available (CockroachDB uses PostgreSQL protocol) - Class.forName("org.postgresql.xa.PGXADataSource"); + Class.forName(POSTGRESQL_XA_DATASOURCE); // Use reflection to create and configure PGXADataSource - XADataSource xaDS = (XADataSource) Class.forName("org.postgresql.xa.PGXADataSource") + XADataSource xaDS = (XADataSource) Class.forName(POSTGRESQL_XA_DATASOURCE) .getDeclaredConstructor() .newInstance();