Skip to content

Return the settable pointer attributes and SQL_ATTR_CURSOR_SCROLLABLE from SQLGetStmtAttr - #304

Open
fdcastel wants to merge 2 commits into
FirebirdSQL:masterfrom
fdcastel:fix/stmt-attr-readback
Open

Return the settable pointer attributes and SQL_ATTR_CURSOR_SCROLLABLE from SQLGetStmtAttr#304
fdcastel wants to merge 2 commits into
FirebirdSQL:masterfrom
fdcastel:fix/stmt-attr-readback

Conversation

@fdcastel

@fdcastel fdcastel commented Sep 6, 2026

Copy link
Copy Markdown
Member

Every statement attribute that SQLSetStmtAttr accepts should come back from SQLGetStmtAttr. Eight did not: the getter's switch had no case for them, so they fell through to default: and returned HYC00 "Optional feature not implemented", although the setter had stored the value and the driver was using it.

attribute stored in
SQL_ATTR_ROWS_FETCHED_PTR IRD rows-processed pointer
SQL_ATTR_ROW_BIND_OFFSET_PTR ARD bind-offset pointer
SQL_ATTR_ROW_OPERATION_PTR ARD array-status pointer
SQL_ATTR_PARAMS_PROCESSED_PTR IPD rows-processed pointer
SQL_ATTR_PARAM_BIND_OFFSET_PTR APD bind-offset pointer
SQL_ATTR_PARAM_OPERATION_PTR APD array-status pointer
SQL_ATTR_PARAM_STATUS_PTR IPD array-status pointer
SQL_ATTR_CURSOR_SCROLLABLE cursorScrollable

Noticed while working on #303: an application cannot even check which rows-fetched pointer it set. Generic ODBC consumers that save and restore statement attributes hit the error as well.

The fix

One case per attribute in OdbcStatement::sqlGetStmtAttr, each mirroring the existing SQL_ATTR_ROW_STATUS_PTR case: read the same descriptor header field the setter writes. SQL_ATTR_CURSOR_SCROLLABLE returns what the setter stored (default SQL_NONSCROLLABLE).

Tests

tests/test_stmt_attrs.cpp: one set-then-get round trip per pointer attribute (a pointer, then NULL), SQL_ATTR_ROW_STATUS_PTR as the control that already passed, and a SQL_ATTR_CURSOR_SCROLLABLE case checking the default, both values, and that SQL_SCROLLABLE moves SQL_ATTR_CURSOR_TYPE off forward-only. Eight of the nine fail on master; all pass with this branch.

Verified on Windows x64 against Firebird 5.0.3 with the Microsoft driver manager. Full suite: 397 ran, 232 passed, 165 skipped, 0 failed.

Independent of #303: the tests set and read without a prepare in between.

Still open

SQL_ATTR_KEYSET_SIZE is also settable without a getter, but the setter stores it in the ARD array size, which is not what that attribute means, so a getter would only document the wrong behaviour. Left alone.

… from SQLGetStmtAttr

sqlGetStmtAttr had no case for SQL_ATTR_ROWS_FETCHED_PTR,
SQL_ATTR_ROW_BIND_OFFSET_PTR, SQL_ATTR_ROW_OPERATION_PTR,
SQL_ATTR_PARAMS_PROCESSED_PTR, SQL_ATTR_PARAM_BIND_OFFSET_PTR,
SQL_ATTR_PARAM_OPERATION_PTR, SQL_ATTR_PARAM_STATUS_PTR or
SQL_ATTR_CURSOR_SCROLLABLE, so reading any of them fell through to the
default branch and returned HYC00 although sqlSetStmtAttr had stored the
value and the driver was using it. Each new case reads back the same
field the setter writes, mirroring the existing SQL_ATTR_ROW_STATUS_PTR
case.
…mtAttr

One set-then-get case per pointer attribute (a pointer, then NULL),
SQL_ATTR_ROW_STATUS_PTR as the control that already passed, and
SQL_ATTR_CURSOR_SCROLLABLE with its default, both values, and the cursor
type it implies. Eight of the nine fail on master.
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.

1 participant