Skip to content

Commit 519c24b

Browse files
author
Shiwani Gupta
committed
mssql-odbc: declare and bound data-at-execution parameters from ParameterType
SQLBindParameter's ParameterType and ColumnSize were ignored for data-at-execution parameters: every value streamed as a `max` type whatever the application declared, and no length bound was enforced. Declaration follows ParameterType. `dae_plan` decides stream-vs-buffer from the SQL type's PLP-ability, mirroring msodbcsql's IsPartialLenType (sqlcprot.h:1421), which keys on the SQL type alone rather than on ColumnSize. A fixed-width target is now collected and converted whole through the materializing path instead of being forced into a `max` stream it cannot represent. ColumnSize bounds the value. `dae_streamed_declaration` narrows the @params declaration and `dae_length_limit` enforces the accumulated total in SQLPutData, applied before the streamed/buffered split and against the application buffer -- where msodbcsql runs ValidatePutDataLength (sqlccmd.cpp:4571), so 22001 lands on the call that overflows rather than at close. Trailing pad units are trimmed rather than rejected, including one split across two calls, and trimmed padding does not consume the declaration's budget. A narrow buffer is measured in UTF-16 units, the unit the materialized path uses, so the two paths agree on what fits. The declaration is only narrowed when that bound can be enforced: a streamed parameter never reaches a close-time conversion, so promising a length nothing checks would leave the overflow to the server. Transcoding is streamed, not deferred. `DaeTranscode` converts each chunk on the way out, carrying a trailing partial character into the next call -- the shape of msodbcsql's ConvertLongData (sqlccnvt.cpp:841) with its cbTruncatedCharsInConvBuf carry and end-of-value flush (sqlccmd.cpp:5999-6001). Narrow encoding reuses encode_narrow, so the streamed and materialized paths agree on the wire bytes. A mixed sequence collects only what it must. Parameters are offered in bind order, as msodbcsql offers them, and the RPC opens as soon as no parameter still to be visited needs collecting -- so a PLP-capable value bound after a fixed-width one streams rather than being held whole. text/ntext/image keep their `max` substitution, tracked under AB#47592. AB#47590
1 parent ce029d8 commit 519c24b

14 files changed

Lines changed: 2926 additions & 628 deletions

File tree

mssql-odbc/docs/parameters_plan.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,20 @@ transparent reconnects.
138138
moved from `SQLBindParameter` to execute - the DAE indicator is only read
139139
while building the parameter list - so an application gets `HYC00` from
140140
`SQLExecute` after setting up its `SQLParamData` loop rather than at bind.
141-
msodbcsql returns `SQL_NEED_DATA` for this pairing at `SQLExecute` rather
142-
than refusing there, but it does not actually stream it: `SQLPutData`
143-
itself then rejects with `HY019` ("Processing of fixed length targets
144-
cannot be spread over multiple calls to SQLPutData",
145-
`sqlccmd.cpp:11079-11082`, `:11185-11188`) once the streamed value's
146-
integer target is a fixed-length one. So the two drivers agree that this
147-
pairing cannot stream a value through, they just detect it one call apart
148-
-- msodbcsql at `SQLPutData`, this driver at `SQLExecute` -- which is why
149-
the parity run stays skipped rather than comparing error codes that
150-
differ by construction.
151-
Pinned by `CrossFamilyDataAtExecutionIsRejectedAtExecute` and, for the
141+
142+
**Superseded.** The pairing is no longer refused at all: the chunks are
143+
collected and the complete value goes through the same conversion the
144+
materialized path uses, so text supplied in pieces parses to an integer
145+
exactly as it does when bound in one buffer. Measured against the
146+
reference driver, which accepts the `SQLPutData` and returns the same
147+
value, so `CrossFamilyDataAtExecutionConvertsToInteger` runs on the
148+
comparison leg rather than opting out.
149+
150+
An earlier note here claimed the reference driver rejects this pairing
151+
once the value is supplied in pieces. It does not: the claim came from
152+
reading its source rather than running it, and probing both drivers
153+
disproved it.
154+
Pinned by `CrossFamilyDataAtExecutionConvertsToInteger` and, for the
152155
wideness-mismatch fix, `NarrowCTypeAgainstWideSqlTypeDataAtExecutionTranscodes`
153156
/ `WideCTypeAgainstNarrowSqlTypeDataAtExecutionTranscodes` in
154157
`execute_test.cpp`.

mssql-odbc/src/api/cancel.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,13 @@ unsafe fn sql_cancel_impl(statement_handle: SqlHandle) -> SqlReturn {
8787
#[cfg(test)]
8888
mod tests {
8989
use super::*;
90-
use crate::api::odbc_types::{SQL_C_CHAR, SQL_INVALID_HANDLE, SQL_VARCHAR};
90+
use crate::api::odbc_types::SQL_INVALID_HANDLE;
9191
use crate::handles::stmt::{DaeParam, DaeState, STMT_STATE_EXEC_STARTED};
9292
use crate::test_support::TestHandles;
9393

9494
fn dae_with_one_param(cursor: Option<usize>) -> DaeState {
9595
DaeState::for_test(
96-
vec![DaeParam {
97-
value_ptr: std::ptr::null_mut(),
98-
expected_len: None,
99-
needs_transcode: false,
100-
c_type: SQL_C_CHAR,
101-
sql_type: SQL_VARCHAR,
102-
}],
96+
vec![DaeParam::unbounded(0, std::ptr::null_mut(), None)],
10397
cursor,
10498
)
10599
}

0 commit comments

Comments
 (0)