-
Notifications
You must be signed in to change notification settings - Fork 451
Introduce new prepareMethod exec for PreparedStatement #2844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add EXEC enum value to PrepareMethod for direct execution without preparation
- Implement Sybase DYNAMIC_PREPARE=false equivalent functionality
- Update reuseCachedHandle to disable caching for exec method
- Modify doPrepExec to bypass statement preparation when using exec method
- Add comprehensive tests for temp table persistence and parameter binding
- Update resource strings for proper documentation
This enables seamless migration from Sybase applications by providing
direct statement execution without preparation, ensuring temp tables
persist across executions as expected by legacy Sybase applications.
Connection usage:
String url = "jdbc:sqlserver://server:1433;databaseName=mydb;prepareMethod=exec";
DataSource usage:
SQLServerDataSource ds = new SQLServerDataSource();
ds.setPrepareMethod("exec");
This reverts commit f8811ea.
- Implemented SqlServerPreparedStatementExpander utility class for expanding prepared statement placeholders with actual parameter values - Added support for prepareMethod=exec to enable direct execution mode similar to Sybase's DYNAMIC_PREPARE=false - Handles proper SQL syntax parsing to avoid replacing placeholders inside strings, comments, or delimited identifiers - Implements smart NULL handling with operator rewrites (= ? -> IS NULL, <> ? -> IS NOT NULL, != ? -> IS NOT NULL, IS ? -> IS NULL, IS NOT ? -> IS NOT NULL) - Formats various data types: strings (with single quote escaping), numbers, booleans (as 1/0), dates/times, byte arrays (as hex), CLOBs, BLOBs - Added comprehensive JUnit test suite (23 test cases) covering all scenarios - Added demo class for manual testing and verification - Updated SQLServerConnection to use the new expander when useDirectValues=true in replaceParameterMarkers
- Fix operator detection to check for two-char operators (!=, <>) before single-char
- Fix spacing issues when replacing operators with IS NULL/IS NOT NULL
- Fix string literal parsing to properly handle escaped quotes ('')
- All 23 tests now pass successfully
…ev/divang/sybase-migration-dynamic-prepare
* Add comprehensive test coverage for EXEC prepare method * commented testFourPartSyntaxCallEscapeSyntax due to linked server error
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
| createTempTable(tableName); | ||
|
|
||
| // Insert test data with NULL | ||
| try (PreparedStatement pstmt = execMethodConnection.prepareStatement( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to have tests which use addBatch and preapreMethod exec and cause constrain voilations in the middle of the batch e.g. 5th batch out of a 10 record batch causing PK violation. Post that, how do the update counts look like.
The bahavior should be same as prepareMethod prepare for update counts.
The test can do both mode executions and compare update counts here.
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SqlServerPreparedStatementExpander.java
Outdated
Show resolved
Hide resolved
- Moved expandSQLWithParameters() and helper methods from SqlServerPreparedStatementExpander to SQLServerConnection - Converted from static utility class pattern to instance methods - Deleted obsolete SqlServerPreparedStatementExpander class and associated test files - Simplified replaceParameterMarkers() to call expandSQLWithParameters() directly - Reduced code duplication by ~280 lines
…improve numeric formatting - Check sendStringParametersAsUnicode config before adding N prefix to string literals - Improve Float/Double formatting using BigDecimal to avoid precision loss - Separate integer type handling from floating-point types for better precision control
…g formatting - Updated Clob value formatting to respect sendStringParametersAsUnicode setting - Updated fallback case (toString) to respect sendStringParametersAsUnicode setting
- Simplified replaceParameterMarkers when useDirectValues=true by directly iterating paramPositions array instead of complex SQL parsing - Removed expandSQLWithParameters() method which is no longer needed - Uses existing paramPositions array to replace ? markers with formatted values
…rely after encountering a single statement error, instead of marking the failed statement with EXECUTE_FAILED (-3) and continuing with remaining statements.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2844 +/- ##
============================================
+ Coverage 56.36% 56.49% +0.13%
- Complexity 4523 4613 +90
============================================
Files 151 151
Lines 34442 34793 +351
Branches 5738 5845 +107
============================================
+ Hits 19412 19656 +244
- Misses 12408 12484 +76
- Partials 2622 2653 +31 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| private static final int ENGINE_EDITION_SQL_AZURE_SYNAPSE_SERVERLESS_SQL_POOL = 11; | ||
|
|
||
| // --- SQL Parameter Expansion Methods --- | ||
| private static final SimpleDateFormat DATE_FMT = new SimpleDateFormat("yyyy-MM-dd"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did we confirm if client-side formatting is really needed or can SQL Server's cast can handle formats automatically?
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
Outdated
Show resolved
Hide resolved
| // notation | ||
| if (value instanceof Float) { | ||
| // Convert Float to BigDecimal for precise representation | ||
| return new java.math.BigDecimal(value.toString()).toPlainString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should test cases for MIN and MAX values of decimal, BigDecimal, Float, Double, Integer, BigInteger.
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
Outdated
Show resolved
Hide resolved
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java
Outdated
Show resolved
Hide resolved
| * | ||
| * @return true if optimization can be applied | ||
| */ | ||
| private boolean canUseOptimizedBatchExecution() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is optimizedbatchexecutiion and why do we need it for EXEC method ?
| // assert null != tdsWriter; | ||
| tdsWriter.writeByte((byte) NBATCH_STATEMENT_DELIMITER); | ||
| if (isPrepareMethodExec) { | ||
| // For EXEC method with batching, each statement must be sent separately |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unnecessary. For EXEC mode, we intend to prepare a semicolon separate sql string sequence one stmt per param row.
| continue; | ||
| } else { | ||
| // Check if this is a timeout during batch preparation for exec method | ||
| String sqlState = e.getSQLState(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this differential treatment for EXEC mode
Objective
Introduce a new way to execute prepared statements using a single batch execution method.
Solution
Added a new prepareMethod option value: exec. When selected, this method substitutes parameters directly into the SQL and executes the statement as a single batch, rather than preparing and executing in separate steps.
Testing
Unit and integration tests have been added to validate the correct behavior of the exec prepare method. The tests ensure that statements execute successfully and that parameters are substituted as expected.