Subject: Re: [postgresql-interfaces/psqlodbc] PR #12: during call SQLFreeHandle, if the connection is broken the client is not notified

From: "KKKaneki (@KKKaneki)" <[email-masked]>
Date: Fri, 27 Jun 2025 12:57:33 +0000

Hi @davecramer, 
I have an application which basically maintains a ODBC connection across the thread lifecycle and assuming that the connection breaks due to communication link breakage I would get an error on SQLExecute and on this error, I am cleaning up the old connection resources SQLFreeStmt being one of them and on SQL_ERROR of SQLFreeStmt I tried to get the diagnostic data using SQLError (I am still using ODBC version 2 functions :) ).  

Order of cleanup and on each cleanup function I am checking for rc != SQL_SUCCESS and calling SQLError.
1. SQLFreeStmt
2. SQLDisconnect
3. SQLFreeConnect
4. SQLFreeEnv

With this change the SQLFreeStmt will basically return SQL_ERROR and when I am retrieving the SQLError the STMT is not null (maybe dangling as SQLFreeStmt already frees it) and as it is a dangling pointer it is resulting in intermittent application crashes.

I was using postgresql-odbc-12.02.0000 earlier and hence I was not observing this issue earlier. Now I am using unixODBC-2.9.3 and upgraded to postgresql16-odbc-17.00.0004, what would you suggest should be the right approach here?

Attaching the trace logs here and the weird thing is SQLError when called should try to get diagnostic data from SQL_HANDLE_STMT but it tries SQL_HANDLE_DBC and I am not even sure why it should call PGAPI_GetDiagRec for 2 things with a single call. 

```
[7f29d1142640]odbcapi30.[SQLFreeHandle]250: Entering
[7f29d1142640]statement.[PGAPI_FreeStmt]248: entering...hstmt=0x7f29c8034860, fOption=1
[7f29d1142640] qresult.c[QR_Destructor]354: entering
[7f29d1142640]statement.[SC_init_Result]555: leaving(0x7f29c8034860)
[7f29d1142640]statement.[SC_Destructor]491: entering self=0x7f29c8034860, self->result=(nil), self->hdbc=0x7f29c801f570
[7f29d1142640]statement.[SC_log_error]2496: STATEMENT ERROR: func=SC_Destructor, desc='', errnum=35, errmsg='connection error.'
[7f29d1142640]connection[CC_log_error]2628: CONN ERROR: func=SC_Destructor, desc='', errnum=0, errmsg='(NULL)'
[7f29d1142640]    bind.c[reset_a_column_binding]772: entering ... self=0x7f29c8034960, bindings_allocated=6, icol=1
[7f29d1142640]    bind.c[reset_a_column_binding]772: entering ... self=0x7f29c8034960, bindings_allocated=6, icol=2
[7f29d1142640]    bind.c[reset_a_column_binding]772: entering ... self=0x7f29c8034960, bindings_allocated=6, icol=3
[7f29d1142640]    bind.c[reset_a_column_binding]772: entering ... self=0x7f29c8034960, bindings_allocated=6, icol=4
[7f29d1142640]    bind.c[reset_a_column_binding]772: entering ... self=0x7f29c8034960, bindings_allocated=6, icol=5
[7f29d1142640]    bind.c[reset_a_column_binding]772: entering ... self=0x7f29c8034960, bindings_allocated=6, icol=6
[7f29d1142640]    bind.c[APD_free_params]643: entering self=0x7f29c8034a40
[7f29d1142640]    bind.c[IPD_free_params]698: entering self=0x7f29c8034ab0
[7f29d1142640]    bind.c[PDATA_free_params]663: entering self=0x7f29c8034ba8
[7f29d1142640]statement.[SC_Destructor]545: leaving
[7f29d1142640]odbcapi30w[SQLGetDiagRecW]227: Entering
[7f29d1142640] pgapi30.c[PGAPI_GetDiagRec]43: entering type=2 rec=1 buffer=512
[7f29d1142640] environ.c[PGAPI_ConnectError]287: entering hdbc=0x7f29c801f570 <512>
[7f29d1142640]connection[CC_get_error]1436: entering
[7f29d1142640]connection[CC_get_error]1449: leaving
[7f29d1142640] environ.c[PGAPI_ConnectError]294: CC_Get_error returned nothing.
[7f29d1142640] pgapi30.c[PGAPI_GetDiagRec]70: leaving 100
[7f29d1142640]odbcapi30w[SQLGetDiagRecW]227: Entering
[7f29d1142640] pgapi30.c[PGAPI_GetDiagRec]43: entering type=3 rec=1 buffer=512
```