@@ -584,22 +584,6 @@ SQLDescribeParamFunc SQLDescribeParam_ptr = nullptr;
584584
585585namespace {
586586
587- // Ensures parameter bindings are always reset before local bound buffers go out
588- // of scope, preventing dangling APD pointers on error/exception paths.
589- struct ParamResetGuard {
590- SQLHSTMT hStmt;
591- bool active = false ;
592-
593- explicit ParamResetGuard (SQLHSTMT stmtHandle) : hStmt(stmtHandle) {}
594-
595- ~ParamResetGuard () {
596- if (active && SQLFreeStmt_ptr) {
597- SQLFreeStmt_ptr (hStmt, SQL_RESET_PARAMS );
598- }
599- }
600-
601- void arm () { active = true ; }
602- };
603587
604588const char * GetSqlCTypeAsString (const SQLSMALLINT cType) {
605589 switch (cType) {
@@ -2706,9 +2690,6 @@ SQLRETURN SQLExecuteLegacy_wrap(const SqlHandlePtr statementHandle, const std::u
27062690 if (!SQL_SUCCEEDED (rc)) {
27072691 return rc;
27082692 }
2709- ParamResetGuard resetGuard (hStmt);
2710- resetGuard.arm ();
2711-
27122693 {
27132694 // Release the GIL during the blocking SQLExecute network call.
27142695 py::gil_scoped_release release;
@@ -2850,6 +2831,10 @@ SQLRETURN SQLExecuteLegacy_wrap(const SqlHandlePtr statementHandle, const std::u
28502831 rc, (void *)hStmt);
28512832 return rc;
28522833 }
2834+
2835+ // Unbind parameter buffers before they go out of scope.
2836+ // Not called on error paths — diagnostics must remain readable.
2837+ SQLFreeStmt_ptr (hStmt, SQL_RESET_PARAMS );
28532838 return rc;
28542839 }
28552840}
@@ -2933,8 +2918,6 @@ SQLRETURN SQLExecute_wrap(const SqlHandlePtr statementHandle,
29332918 std::vector<std::shared_ptr<void >> paramBuffers;
29342919 rc = BindParameters (*statementHandle, hStmt, params, paramInfos, paramBuffers, charEncoding);
29352920 if (!SQL_SUCCEEDED (rc)) return rc;
2936- ParamResetGuard resetGuard (hStmt);
2937- resetGuard.arm ();
29382921
29392922 {
29402923 py::gil_scoped_release release;
@@ -3045,7 +3028,11 @@ SQLRETURN SQLExecute_wrap(const SqlHandlePtr statementHandle,
30453028
30463029 if (!SQL_SUCCEEDED (rc) && rc != SQL_NO_DATA ) return rc;
30473030
3048- return rc;
3031+ // Unbind parameter buffers before they go out of scope.
3032+ // Not called on error paths — diagnostics must remain readable.
3033+ SQLRETURN exec_rc = rc;
3034+ SQLFreeStmt_ptr (hStmt, SQL_RESET_PARAMS );
3035+ return exec_rc;
30493036}
30503037
30513038SQLRETURN BindParameterArray (SqlHandle& handle, SQLHANDLE hStmt, const py::list& columnwise_params,
0 commit comments