Context
Follow-up from PR #436 (AB#47437 — descriptor records as the binding/metadata source of truth), flagged by code review.
Problem
Now that the ARD/APD records are the binding storage (AB#47437), SQLSetDescRec and SQLSetDescFieldW can rewrite SQL_DESC_DATA_PTR / SQL_DESC_OCTET_LENGTH / SQL_DESC_CONCISE_TYPE on a descriptor a fetch is actively using, with no STMT_STATE_FETCH_IN_PROGRESS guard. Every other entry point that touches the same records refuses in that window:
SQLBindCol (bind_col.rs:109)
SQLFreeStmt(SQL_UNBIND) (bind_col.rs:315)
SQLSetStmtAttr (set_stmt_attr.rs:164)
fetch_scroll_safe snapshots ColumnBinding::all_from_ard_state before its fill loop, so the loop itself can't read a half-written record — but that snapshot is precisely why the guard exists on SQLBindCol in the first place: the point is that the application must not be able to hand the driver a new binding (and free the old buffer) while the fill loop is still writing through the snapshotted pointers. The descriptor-field API is now a second door into the same records, and before PR #436 it wasn't.
Why this wasn't fixed directly in #436
A DescHandle has no back-pointer to the statement(s) it is associated with, so adding the guard to SQLSetDescRec/SQLSetDescFieldW needs a DBC → STMT walk, the same shape free_desc already uses to reset associations on free. Doing that walk for one door (the descriptor-field API) and not the others inconsistently, or rushing a partial version of it, risks being worse than the current, at-least-consistent gap. It needs the same careful DBC→STMT-ordered treatment as the rest of this crate's locking rules, not a quick patch alongside an already large PR.
Suggested approach
Give SQLSetDescRec/SQLSetDescFieldW (set_desc_rec.rs, set_desc_field.rs) the same DBC → STMT walk free_desc uses (.github/instructions/mssql-odbc.instructions.md's "Locking rules" section) to find every statement currently associated with the descriptor being modified (an explicit ARD/APD can be shared across statements via SQL_ATTR_APP_ROW_DESC/SQL_ATTR_APP_PARAM_DESC reassociation), and refuse with ERR_FUNCTION_SEQUENCE if any of them has STMT_STATE_FETCH_IN_PROGRESS set — matching SQLBindCol's existing check.
References
Context
Follow-up from PR #436 (AB#47437 — descriptor records as the binding/metadata source of truth), flagged by code review.
Problem
Now that the ARD/APD records are the binding storage (AB#47437),
SQLSetDescRecandSQLSetDescFieldWcan rewriteSQL_DESC_DATA_PTR/SQL_DESC_OCTET_LENGTH/SQL_DESC_CONCISE_TYPEon a descriptor a fetch is actively using, with noSTMT_STATE_FETCH_IN_PROGRESSguard. Every other entry point that touches the same records refuses in that window:SQLBindCol(bind_col.rs:109)SQLFreeStmt(SQL_UNBIND)(bind_col.rs:315)SQLSetStmtAttr(set_stmt_attr.rs:164)fetch_scroll_safesnapshotsColumnBinding::all_from_ard_statebefore its fill loop, so the loop itself can't read a half-written record — but that snapshot is precisely why the guard exists onSQLBindColin the first place: the point is that the application must not be able to hand the driver a new binding (and free the old buffer) while the fill loop is still writing through the snapshotted pointers. The descriptor-field API is now a second door into the same records, and before PR #436 it wasn't.Why this wasn't fixed directly in #436
A
DescHandlehas no back-pointer to the statement(s) it is associated with, so adding the guard toSQLSetDescRec/SQLSetDescFieldWneeds a DBC → STMT walk, the same shapefree_descalready uses to reset associations on free. Doing that walk for one door (the descriptor-field API) and not the others inconsistently, or rushing a partial version of it, risks being worse than the current, at-least-consistent gap. It needs the same careful DBC→STMT-ordered treatment as the rest of this crate's locking rules, not a quick patch alongside an already large PR.Suggested approach
Give
SQLSetDescRec/SQLSetDescFieldW(set_desc_rec.rs,set_desc_field.rs) the same DBC → STMT walkfree_descuses (.github/instructions/mssql-odbc.instructions.md's "Locking rules" section) to find every statement currently associated with the descriptor being modified (an explicit ARD/APD can be shared across statements viaSQL_ATTR_APP_ROW_DESC/SQL_ATTR_APP_PARAM_DESCreassociation), and refuse withERR_FUNCTION_SEQUENCEif any of them hasSTMT_STATE_FETCH_IN_PROGRESSset — matchingSQLBindCol's existing check.References