Skip to content

Conversation

@divang
Copy link
Contributor

@divang divang commented Nov 18, 2025

Objective
• To solve the temp table scope requirement for PreparedStatements.
• Support seamless migration from Sybase ASE.
• Ensure temp table persistence across PreparedStatement boundaries.
• Maintain backward compatibility.

Background
• Sybase ASE’s JDBC driver uses the DYNAMIC_PREPARE option to control PreparedStatement behavior.
• When set to false, temp tables created in prepared statements persist across subsequent statements.
• Microsoft SQL Server JDBC driver does not support this, causing migration issues due to temp table scoping differences.
DYNAMIC_PREPARE=true (default): Traditional prepared statement behavior
DYNAMIC_PREPARE=false: Direct SQL execution without preparation
When DYNAMIC_PREPARE=false, temp tables created in PreparedStatements remain visible to subsequent statements.

Sybase driver POC
We analyzed the behavior through TCP packet traces and confirmed it by simulating the scenarios with a POC client.

When DYNAMIC_PREPARE=false:
The Sybase driver does NOT substitute parameter values into the SQL text. Instead:

  1. No statement caching - Each execution creates a new prepared statement handle on the server
  2. Still sends parameters separately - The SQL template INSERT INTO #WiresharkTest (id) VALUES (?) and the parameter value are sent separately
  3. Server-side preparation happens each time - The database server prepares the statement for each execution, then discards it
    When DYNAMIC_PREPARE=true:
  4. Statement is cached - Prepared once, reused for subsequent executions
  5. Only parameters are sent - After first preparation, only parameter values are transmitted

Solution
Introduce a new EXEC prepare method in the SQL Server JDBC Driver.
Findings on above approach:
• Extend the PrepareMethod enum with an EXEC option for direct SQL execution, bypassing sp_executesql and resolving temp table scoping issues by maintaining session-level scope.
• Use PKT_QUERY for direct execution, embedding parameters within the SQL string. This leverages existing parameter infrastructure for safe substitution and SQL injection protection.
• Disable statement handle caching for the EXEC method, as direct execution does not require prepared statement handles.

Testing

divang and others added 10 commits October 24, 2025 16:08
- 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");
- 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
@divang
Copy link
Contributor Author

divang commented Nov 21, 2025

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants