Repository navigation
Step a column-wise SQL_C_TYPE_DATE parameter array by the C struct - #1478
Open
singhpratech wants to merge 1 commit into
Open
singhpratech wants to merge 1 commit into
singhpratech wants to merge 1 commit into
Conversation
sqlc_sizeof_1 () lists SQL_C_DATE, SQL_C_TIME and SQL_C_TIMESTAMP but not their ODBC 3 spellings SQL_C_TYPE_DATE, SQL_C_TYPE_TIME and SQL_C_TYPE_TIMESTAMP, so a parameter bound with one of those falls into the default clause and its element size becomes the ColumnSize argument of SQLBindParameter. With SQL_ATTR_PARAMSET_SIZE greater than 1 and column-wise binding, stmt_param_place_ptr () then steps through the array by ColumnSize: ColumnSize 0 makes every set read the first element, and any other value that is not the size of the C struct reads from the wrong offsets and past the end of the buffer. Every set is still reported as SQL_PARAM_SUCCESS. Add the three ODBC 3 identifiers to the cases that already return the size of the C struct, in the same way as the other switches in this file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1473.
With
SQL_ATTR_PARAMSET_SIZEgreater than 1 and column-wise binding, aSQL_C_TYPE_DATEparameter array is walked by theColumnSizeargument ofSQLBindParameterrather than by the size of the C type. Every set executes,SQLRowCountreports the right number of rows and every parameter status isSQL_PARAM_SUCCESS, so nothing tells the caller which dates were sent:ColumnSize0 — a natural way to bind a date, the type having a fixed size — makes every set read the first element; any other value that is notsizeof (SQL_DATE_STRUCT)reads from the wrong offsets and past the end of the buffer.SQL_C_TYPE_TIMEandSQL_C_TYPE_TIMESTAMPbehave the same way;SQL_C_CHAR,SQL_C_DOUBLEandSQL_C_SLONGarrays walk correctly, and so does row-wise binding throughSQL_ATTR_PARAM_BIND_TYPE.The cause is in
sqlc_sizeof_1 (),libsrc/Wi/CLIuti.c:1586. The switch listsSQL_C_TIMESTAMP,SQL_C_DATEandSQL_C_TIME, but not the ODBC 3 spellingsSQL_C_TYPE_TIMESTAMP,SQL_C_TYPE_DATEandSQL_C_TYPE_TIME, so those fall through todefault: return cbColDef;and the element size becomesColumnSize.stmt_parm_to_dv ()passes that size tostmt_param_place_ptr ()(CLIuti.c:1613andCLIuti.c:39), which multiplies it by the set number wheneverSQL_ATTR_PARAM_BIND_TYPEis 0.The change. The three ODBC 3 identifiers are added to the cases that already return the size of the C struct, guarded by
#if (ODBCVER >= 0x0300)in the same shape as the other switches in this file (sql_type_to_sqlc_default (),buffer_to_dv ()anddv_to_place ()all list both spellings that way). A column-wise array of a fixed-length C type is then stepped by that type's size, as the specification prescribes, andSQL_C_TYPE_DATEbehaves exactly likeSQL_C_DATEdoes today. One consequence worth naming: a set whose elements are further apart than the struct — bound column-wise and relying onColumnSizeas the stride — is now read from the packed offsets instead.SQL_ATTR_PARAM_BIND_TYPEis the supported way to keep a wider stride, and it is correct before and after this change.Test. I built the four driver flavours from this tree before and after (
make -C binsrc/driver, exit 0, no new warnings) and ran the reproduction from #1473 againstopenlink/virtuoso-opensource-7in Docker through unixODBC 2.3.12. Before:ColumnSize0 inserts row 0's date four times andColumnSize10 over a packed array inserts0197-08-05,0014-07-03and-002-11-30for the other three. After: all three packed-array variants insert2024-01-01 2024-02-29 2024-03-15 2024-12-31, and a row-wise variant I added to the program (SQL_ATTR_PARAM_BIND_TYPE= the row struct size) is correct in both runs. As a regression pass I also ran a pyodbc script over the same server with both drivers — connect,SQLGetInfo, DDL, single-row andexecutemanyinserts of int/varchar/double/DATE/DATETIME, ordered fetch,COUNT(*), a date parameter, a UTF-8 round trip,SQLTables,SQLColumns— and the output is byte-identical. I did not runbinsrc/tests/suite, which needs a full server build.Found while verifying Virtuoso for adbcBridge, an ADBC driver over ODBC, which sends batches as column-wise parameter arrays and binds dates as
SQL_C_TYPE_DATE.One note for a possible follow-up, not part of this PR:
sqlc_sizeof ()just above has the same three names missing, which is whySQLBindColwithSQL_C_TYPE_DATEandBufferLength0 leaves the column stride at 0. I have not changed it here, since #1473 is about parameters and I have not measured the fetch side.