Skip to content

Keep SQL_ATTR_KEYSET_SIZE apart from the rowset size; HY007 for an unprepared IRD (#307) - #314

Open
fdcastel wants to merge 3 commits into
FirebirdSQL:masterfrom
fdcastel:fix/issue-307-keyset-size-hy007
Open

Keep SQL_ATTR_KEYSET_SIZE apart from the rowset size; HY007 for an unprepared IRD (#307)#314
fdcastel wants to merge 3 commits into
FirebirdSQL:masterfrom
fdcastel:fix/issue-307-keyset-size-hy007

Conversation

@fdcastel

@fdcastel fdcastel commented Sep 7, 2026

Copy link
Copy Markdown
Member

Fixes #307. Three commits on current master, independent of the other open PRs: the sqlGetStmtAttr case sits next to SQL_ROWSET_SIZE, fifty lines away from the block #304 adds.

1. SQL_ATTR_KEYSET_SIZE overwrote the rowset size

sqlSetStmtAttr handled SQL_ATTR_KEYSET_SIZE in the same case as the ODBC 2 SQL_ROWSET_SIZE and stored it in the ARD's array size, so an application that set a keyset size got a rowset of that size and the next SQLFetch wrote that many rows into buffers bound for one. Reading SQL_ATTR_KEYSET_SIZE back answered HYC00.

The value now goes to its own field and comes back from sqlGetStmtAttr. The driver has no keyset-driven cursors, so storing and returning the number is what the specification allows; SQL_ROWSET_SIZE still sets the rowset size.

2. SQLGetDescField on an unprepared IRD answered HY091

sqlGetDescField refused every field of an undefined descriptor with HY091. For the IRD that state means "not prepared yet", and the header fields do not depend on the result set, including the two pointers the application itself just set through SQLSetStmtAttr.

The header fields (SQL_DESC_ALLOC_TYPE, SQL_DESC_ARRAY_SIZE, SQL_DESC_ARRAY_STATUS_PTR, SQL_DESC_BIND_OFFSET_PTR, SQL_DESC_BIND_TYPE, SQL_DESC_ROWS_PROCESSED_PTR) are now returned regardless of the prepared state. SQL_DESC_COUNT and the record fields of an unprepared IRD answer HY007; other descriptor types keep the HY091 they gave before.

Tests

  • ScrollableCursorTest.KeysetSizeDoesNotChangeRowArraySize: keyset size 7 leaves the rowset at 1 and reads back as 7; SQL_ROWSET_SIZE 3 then sets the rowset and leaves the keyset size alone.
  • DescriptorTest.IrdHeaderFieldsReadableBeforePrepare: the two pointers and the alloc type come back from the IRD of an unprepared statement.
  • DescriptorTest.IrdRecordFieldsBeforePrepareAreHY007: SQL_DESC_COUNT and a record field answer HY007 before SQLPrepare and succeed after it.

All three fail against the master driver (HYC00 from the keyset read-back, the rowset at 7, HY091 for both descriptor reads) and pass with this branch. Through unixODBC the driver manager answers HY007 for an unprepared IRD before the driver sees the call, so the header-field case skips there and runs through the Microsoft driver manager; the HY007 case holds under both. Full suite with this branch, CHARSET=UTF8 and NONE: 391 ran, 226 passed, 165 skipped, 0 failed.

Still open

  • SQLSetScrollOptions maps crowKeyset > 0 to SQL_ATTR_KEYSET_SIZE and only otherwise sets SQL_ROWSET_SIZE from crowRowset; with this change a keyset-driven request no longer alters the rowset size at all. The ODBC 1 entry point is left as it is.
  • SQLGetDescRec and SQLSetDescField keep the HY091 answer for an undefined descriptor.

@fdcastel
fdcastel force-pushed the fix/issue-307-keyset-size-hy007 branch from eab3f08 to c0da6ac Compare September 7, 2026 06:09
KeysetSizeDoesNotChangeRowArraySize sets SQL_ATTR_KEYSET_SIZE and reads
both it and SQL_ATTR_ROW_ARRAY_SIZE back, then sets SQL_ROWSET_SIZE and
checks the two stay independent.

IrdHeaderFieldsReadableBeforePrepare reads SQL_DESC_ROWS_PROCESSED_PTR,
SQL_DESC_ARRAY_STATUS_PTR and SQL_DESC_ALLOC_TYPE from the IRD of a
statement that has not been prepared. IrdRecordFieldsBeforePrepareAreHY007
expects HY007 for SQL_DESC_COUNT and a record field in that state, and
success for both once the statement is prepared.
sqlSetStmtAttr handled SQL_ATTR_KEYSET_SIZE in the same case as the ODBC 2
SQL_ROWSET_SIZE and stored it in the ARD's array size. An application that
set a keyset size (ODBC 2 applications and generic layers do, with values
such as 100) silently got a rowset of that size, and the next SQLFetch
wrote that many rows into buffers bound for one, with no rows-fetched
counter or status array to warn it.

The value now goes to its own field, read back by sqlGetStmtAttr; the
driver has no keyset-driven cursors, so the number is stored and returned
as the specification allows.
sqlGetDescField refused every field of an undefined descriptor with
HY091 "Invalid descriptor field identifier". For the IRD that state means
"not prepared yet", and the header fields (the array-status and
rows-processed pointers among them, which the application itself set
through SQLSetStmtAttr) do not depend on the result set at all.

The header fields are now returned regardless of the prepared state.
SQL_DESC_COUNT and the record fields of an unprepared IRD answer HY007
"Associated statement is not prepared"; other descriptor types keep the
HY091 they gave before.
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.

SQL_ATTR_KEYSET_SIZE overwrites the rowset size; SQLGetDescField on an unprepared IRD answers HY091 instead of HY007

1 participant