Skip to content

tests: rowset fetches on every fetch path and binding layout - #305

Open
fdcastel wants to merge 3 commits into
FirebirdSQL:masterfrom
fdcastel:tests/block-cursor-coverage
Open

tests: rowset fetches on every fetch path and binding layout#305
fdcastel wants to merge 3 commits into
FirebirdSQL:masterfrom
fdcastel:tests/block-cursor-coverage

Conversation

@fdcastel

@fdcastel fdcastel commented Sep 6, 2026

Copy link
Copy Markdown
Member

Builds on #303: the first four cases in tests/test_block_cursor.cpp come from there, and GitHub shows both commits until it merges.

Before #303 nothing in the suite set SQL_ATTR_ROW_ARRAY_SIZE. This adds eight cases for the other entry points, layouts and cursor kinds a block cursor goes through. Each asserts the rows-fetched counter, the status array and the bound values on every rowset, and a zero counter on SQL_NO_DATA:

  • FetchScrollNextRowsets: SQLFetchScroll(SQL_FETCH_NEXT) on a forward-only cursor.
  • ExtendedFetchRowsets: SQLExtendedFetch, which receives the counter and the status array as arguments.
  • ArraySizeLargerThanResultSet: one partial rowset (6 rows of 10), the unused slots SQL_ROW_NOROW and untouched, then SQL_NO_DATA.
  • RowWiseBinding: SQL_ATTR_ROW_BIND_TYPE set to the size of a two-column row structure.
  • StaticCursorRowsets: SQL_CURSOR_STATIC + SQL_SCROLLABLE, rowsets fetched with NEXT, FIRST, ABSOLUTE, LAST and RELATIVE.
  • CatalogRowsetsViaSqlTables and CatalogRowsetsViaSqlGetTypeInfo: the two catalog paths (SQLTables results are static cursors, SQLGetTypeInfo results are not), checked against a row count taken with the default rowset.
  • ColumnWiseBindingWithOffset: skipped, see below.

The eleven active cases pass on Windows x64 against Firebird 5.0.3 with the Microsoft driver manager. Full suite: 400 ran, 234 passed, 166 skipped, 0 failed.

Found on the way

Column-wise binding combined with SQL_ATTR_ROW_BIND_OFFSET_PTR writes every row of a rowset to the same address. getSchemaFetchData() sends any statement that has a bind-offset pointer down the row-wise branch of fetchData (and of its static-cursor twin), which advances the bound addresses by SQL_ATTR_ROW_BIND_TYPE per row; that is 0 for column-wise binding. The counter and the status array still report a full rowset, so the application gets SQL_SUCCESS, "4 rows fetched", and only the last row's data in the first element. Row-wise binding with the same offset pointer works.

The test for it is included with a GTEST_SKIP that states the defect, so it turns green the day the fetch path is fixed. Not fixed here: the fix touches the row stepping in both fetch functions and returnDataFromExtendedFetch, which deserves its own PR.

…Prepare

OdbcDesc::setDefaultImplDesc rebuilds the implementation row descriptor
on every prepare and, while doing so, reset SQL_DESC_ROWS_PROCESSED_PTR
and SQL_DESC_ARRAY_STATUS_PTR to NULL. An application that set
SQL_ATTR_ROWS_FETCHED_PTR / SQL_ATTR_ROW_STATUS_PTR before SQLPrepare or
SQLExecDirect never had them written by SQLFetch, so a block cursor could
not tell how many rows the last rowset held. The same attributes set
after the prepare worked, and the parameter descriptor never reset its
own counterparts. Statement attributes persist until the statement is
freed or the attribute is set again; SQLPrepare must not clear them.

Reported in FirebirdSQL#301.
Three cases fail on master: SQL_ATTR_ROWS_FETCHED_PTR and
SQL_ATTR_ROW_STATUS_PTR set before SQLPrepare, before SQLExecDirect, and
kept across SQLFreeStmt(SQL_CLOSE) on a reused handle. The fourth sets
them between SQLPrepare and SQLExecute and is the control that already
passed.
Eight more block-cursor cases: SQLFetchScroll(SQL_FETCH_NEXT) and
SQLExtendedFetch on a forward-only cursor, a rowset larger than the
result set, row-wise binding, a static scrollable cursor in every
orientation, and the two catalog paths (SQLTables results are static
cursors, SQLGetTypeInfo results are not). Each asserts the rows-fetched
counter, the status array and the bound values on every rowset, and a
zero counter on SQL_NO_DATA.

ColumnWiseBindingWithOffset is skipped with the reason: any bind-offset
pointer sends the statement down the row-wise fetch path, which steps by
SQL_ATTR_ROW_BIND_TYPE per row, and that is 0 for column-wise binding,
so every row of the rowset lands on the same address.
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