6060#define FIN_CLOSE 0x2
6161#define FIN_ABORT 0x4
6262
63+ #ifndef HAVE_PQCLOSEPORTAL
64+ static bool pdo_pgsql_try_cmd (const char * cmd , const char * ok_sqlstate , pdo_pgsql_db_handle * H )
65+ {
66+ bool result = false;
67+ char * q = NULL ;
68+ PGresult * res = NULL ;
69+
70+ PGTransactionStatusType status = PQtransactionStatus (H -> server );
71+
72+ switch (status ) {
73+ case PQTRANS_ACTIVE :
74+ case PQTRANS_INERROR :
75+ break ;
76+ case PQTRANS_INTRANS : /* failure must not abort the caller's transaction */
77+ /* PQexec does not run the statements following a failed one */
78+ spprintf (& q , 0 , "SAVEPOINT pdo_pgsql_savepoint; %s; RELEASE SAVEPOINT pdo_pgsql_savepoint;" , cmd );
79+ res = PQexec (H -> server , q );
80+
81+ if (PQresultStatus (res ) != PGRES_COMMAND_OK ) {
82+ PQclear (PQexec (H -> server , "ROLLBACK TO SAVEPOINT pdo_pgsql_savepoint; RELEASE SAVEPOINT pdo_pgsql_savepoint" ));
83+ }
84+
85+ break ;
86+ default :
87+ res = PQexec (H -> server , cmd );
88+ }
89+
90+ if (PQresultStatus (res ) == PGRES_COMMAND_OK ) {
91+ result = true;
92+ } else if (res ) {
93+ const char * sqlstate = pdo_pgsql_sqlstate (res );
94+
95+ result = sqlstate && !strcmp (sqlstate , ok_sqlstate );
96+ }
97+
98+ if (q ) efree (q );
99+ if (res ) PQclear (res );
100+
101+ return result ;
102+ }
103+ #endif
63104
64105
65106static void pgsql_stmt_finish (pdo_pgsql_stmt * S , int fin_mode )
@@ -180,15 +221,16 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt)
180221 }
181222
182223 if (S -> cursor_name ) {
183- if (server_obj_usable ) {
224+ if (S -> is_cursor_declared && server_obj_usable ) {
184225 pdo_pgsql_db_handle * H = S -> H ;
185- char * q = NULL ;
186- PGresult * res ;
187-
226+ #ifndef HAVE_PQCLOSEPORTAL
227+ char * q ;
188228 spprintf (& q , 0 , "CLOSE %s" , S -> cursor_name );
189- res = PQexec ( H -> server , q );
229+ pdo_pgsql_try_cmd ( q , "34000" , H ); /* 34000: invalid_cursor_name */
190230 efree (q );
191- if (res ) PQclear (res );
231+ #else
232+ PQclear (PQclosePortal (H -> server , S -> cursor_name ));
233+ #endif
192234 }
193235 efree (S -> cursor_name );
194236 S -> cursor_name = NULL ;
@@ -228,10 +270,25 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt)
228270 if (S -> cursor_name ) {
229271 char * q = NULL ;
230272
231- if (S -> is_prepared ) {
273+ if (S -> is_cursor_declared ) {
274+ #ifndef HAVE_PQCLOSEPORTAL
232275 spprintf (& q , 0 , "CLOSE %s" , S -> cursor_name );
233- PQclear (PQexec (H -> server , q ));
276+
277+ /* 34000: invalid_cursor_name */
278+ if (pdo_pgsql_try_cmd (q , "34000" , H )) {
279+ S -> is_cursor_declared = false;
280+ }
281+
234282 efree (q );
283+ #else
284+ PGresult * res = PQclosePortal (H -> server , S -> cursor_name );
285+
286+ if (PQresultStatus (res ) == PGRES_COMMAND_OK ) {
287+ S -> is_cursor_declared = false;
288+ }
289+
290+ PQclear (res );
291+ #endif
235292 }
236293
237294 spprintf (& q , 0 , "DECLARE %s SCROLL CURSOR WITH HOLD FOR %s" , S -> cursor_name , ZSTR_VAL (stmt -> active_query_string ));
@@ -247,7 +304,7 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt)
247304 PQclear (S -> result );
248305
249306 /* the cursor was declared correctly */
250- S -> is_prepared = 1 ;
307+ S -> is_cursor_declared = true ;
251308
252309 /* fetch to be able to get the number of tuples later, but don't advance the cursor pointer */
253310 spprintf (& q , 0 , "FETCH FORWARD 0 FROM %s" , S -> cursor_name );
0 commit comments