@@ -73,6 +73,47 @@ static bool pgsql_result_status_ok(ExecStatusType status)
7373 }
7474}
7575
76+ #ifndef HAVE_PQCLOSEPORTAL
77+ static bool pdo_pgsql_try_cmd (const char * cmd , const char * ok_sqlstate , pdo_pgsql_db_handle * H )
78+ {
79+ bool result = false;
80+ char * q = NULL ;
81+ PGresult * res = NULL ;
82+
83+ PGTransactionStatusType status = PQtransactionStatus (H -> server );
84+
85+ switch (status ) {
86+ case PQTRANS_ACTIVE :
87+ case PQTRANS_INERROR :
88+ break ;
89+ case PQTRANS_INTRANS : /* failure must not abort the caller's transaction */
90+ /* PQexec does not run the statements following a failed one */
91+ spprintf (& q , 0 , "SAVEPOINT pdo_pgsql_savepoint; %s; RELEASE SAVEPOINT pdo_pgsql_savepoint;" , cmd );
92+ res = PQexec (H -> server , q );
93+
94+ if (PQresultStatus (res ) != PGRES_COMMAND_OK ) {
95+ PQclear (PQexec (H -> server , "ROLLBACK TO SAVEPOINT pdo_pgsql_savepoint; RELEASE SAVEPOINT pdo_pgsql_savepoint" ));
96+ }
97+
98+ break ;
99+ default :
100+ res = PQexec (H -> server , cmd );
101+ }
102+
103+ if (PQresultStatus (res ) == PGRES_COMMAND_OK ) {
104+ result = true;
105+ } else if (res ) {
106+ const char * sqlstate = pdo_pgsql_sqlstate (res );
107+
108+ result = sqlstate && !strcmp (sqlstate , ok_sqlstate );
109+ }
110+
111+ if (q ) efree (q );
112+ if (res ) PQclear (res );
113+
114+ return result ;
115+ }
116+ #endif
76117
77118
78119static void pgsql_stmt_finish (pdo_pgsql_stmt * S , int fin_mode )
@@ -193,15 +234,16 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt)
193234 }
194235
195236 if (S -> cursor_name ) {
196- if (server_obj_usable ) {
237+ if (S -> is_cursor_declared && server_obj_usable ) {
197238 pdo_pgsql_db_handle * H = S -> H ;
198- char * q = NULL ;
199- PGresult * res ;
200-
239+ #ifndef HAVE_PQCLOSEPORTAL
240+ char * q ;
201241 spprintf (& q , 0 , "CLOSE %s" , S -> cursor_name );
202- res = PQexec ( H -> server , q );
242+ pdo_pgsql_try_cmd ( q , "34000" , H ); /* 34000: invalid_cursor_name */
203243 efree (q );
204- if (res ) PQclear (res );
244+ #else
245+ PQclear (PQclosePortal (H -> server , S -> cursor_name ));
246+ #endif
205247 }
206248 efree (S -> cursor_name );
207249 S -> cursor_name = NULL ;
@@ -241,10 +283,25 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt)
241283 if (S -> cursor_name ) {
242284 char * q = NULL ;
243285
244- if (S -> is_prepared ) {
286+ if (S -> is_cursor_declared ) {
287+ #ifndef HAVE_PQCLOSEPORTAL
245288 spprintf (& q , 0 , "CLOSE %s" , S -> cursor_name );
246- PQclear (PQexec (H -> server , q ));
289+
290+ /* 34000: invalid_cursor_name */
291+ if (pdo_pgsql_try_cmd (q , "34000" , H )) {
292+ S -> is_cursor_declared = false;
293+ }
294+
247295 efree (q );
296+ #else
297+ PGresult * res = PQclosePortal (H -> server , S -> cursor_name );
298+
299+ if (PQresultStatus (res ) == PGRES_COMMAND_OK ) {
300+ S -> is_cursor_declared = false;
301+ }
302+
303+ PQclear (res );
304+ #endif
248305 }
249306
250307 spprintf (& q , 0 , "DECLARE %s SCROLL CURSOR WITH HOLD FOR %s" , S -> cursor_name , ZSTR_VAL (stmt -> active_query_string ));
@@ -260,7 +317,7 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt)
260317 PQclear (S -> result );
261318
262319 /* the cursor was declared correctly */
263- S -> is_prepared = true;
320+ S -> is_cursor_declared = true;
264321
265322 /* fetch to be able to get the number of tuples later, but don't advance the cursor pointer */
266323 spprintf (& q , 0 , "FETCH FORWARD 0 FROM %s" , S -> cursor_name );
0 commit comments