Skip to content

Commit 5c6f33d

Browse files
committed
GH-15750 Pdo\Pgsql with ATTR_PREFETCH = 0: handle handle's internal queries
not only the statements, but the driver, love to make internal queries. We make sure no unfinished query still runs when having to pass an internal one. by the way factorize the loops that consumed the preceding query's results
1 parent d677c52 commit 5c6f33d

File tree

3 files changed

+52
-17
lines changed

3 files changed

+52
-17
lines changed

ext/pdo_pgsql/pgsql_driver.c

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "pgsql_driver_arginfo.h"
3737

3838
static bool pgsql_handle_in_transaction(pdo_dbh_t *dbh);
39+
void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode);
3940

4041
static char * _pdo_pgsql_trim_message(const char *message, int persistent)
4142
{
@@ -103,6 +104,37 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *
103104
}
104105
/* }}} */
105106

107+
static zend_always_inline void pgsql_finish_running_stmt(pdo_pgsql_db_handle *H)
108+
{
109+
if (H->running_stmt) {
110+
pgsql_stmt_finish(H->running_stmt, 0);
111+
}
112+
}
113+
114+
static zend_always_inline void pgsql_discard_running_stmt(pdo_pgsql_db_handle *H)
115+
{
116+
if (H->running_stmt) {
117+
pgsql_stmt_finish(H->running_stmt, FIN_DISCARD);
118+
}
119+
120+
PGresult *pgsql_result;
121+
bool first = true;
122+
while ((pgsql_result = PQgetResult(H->server))) {
123+
/* We should not arrive here, where libpq has a result to deliver without us
124+
* having registered a running statement:
125+
* every result discarding should go through the unified pgsql_stmt_finish,
126+
* but maybe there still is an internal query that we omitted to adapt.
127+
* So instead of asserting let's just emit an informational notice,
128+
* and consume anyway (results consumption is handle-wise, so we have no formal
129+
* need for the statement). */
130+
if (first) {
131+
php_error_docref("ref.pgsql", E_NOTICE, "Internal error: unable to link a libpq result to consume, to its origin statement");
132+
first = false;
133+
}
134+
PQclear(pgsql_result);
135+
}
136+
}
137+
106138
static void _pdo_pgsql_notice(void *context, const char *message) /* {{{ */
107139
{
108140
pdo_dbh_t * dbh = (pdo_dbh_t *)context;
@@ -349,6 +381,7 @@ static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const zend_string *sql)
349381

350382
bool in_trans = pgsql_handle_in_transaction(dbh);
351383

384+
pgsql_finish_running_stmt(H);
352385
if (!(res = PQexec(H->server, ZSTR_VAL(sql)))) {
353386
/* fatal error */
354387
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
@@ -416,6 +449,7 @@ static zend_string *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const zend_string *
416449
PGresult *res;
417450
ExecStatusType status;
418451

452+
pgsql_finish_running_stmt(H);
419453
if (name == NULL) {
420454
res = PQexec(H->server, "SELECT LASTVAL()");
421455
} else {
@@ -579,6 +613,7 @@ static bool pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh)
579613
PGresult *res;
580614
bool ret = true;
581615

616+
pgsql_finish_running_stmt(H);
582617
res = PQexec(H->server, cmd);
583618

584619
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
@@ -684,9 +719,8 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
684719
/* Obtain db Handle */
685720
H = (pdo_pgsql_db_handle *)dbh->driver_data;
686721

687-
while ((pgsql_result = PQgetResult(H->server))) {
688-
PQclear(pgsql_result);
689-
}
722+
pgsql_discard_running_stmt(H);
723+
690724
pgsql_result = PQexec(H->server, query);
691725

692726
efree(query);
@@ -808,9 +842,8 @@ void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS)
808842

809843
H = (pdo_pgsql_db_handle *)dbh->driver_data;
810844

811-
while ((pgsql_result = PQgetResult(H->server))) {
812-
PQclear(pgsql_result);
813-
}
845+
pgsql_discard_running_stmt(H);
846+
814847
pgsql_result = PQexec(H->server, query);
815848

816849
efree(query);
@@ -904,9 +937,7 @@ void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS)
904937
RETURN_FALSE;
905938
}
906939

907-
while ((pgsql_result = PQgetResult(H->server))) {
908-
PQclear(pgsql_result);
909-
}
940+
pgsql_discard_running_stmt(H);
910941

911942
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
912943
if (pg_fields) {
@@ -995,9 +1026,7 @@ void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS)
9951026

9961027
H = (pdo_pgsql_db_handle *)dbh->driver_data;
9971028

998-
while ((pgsql_result = PQgetResult(H->server))) {
999-
PQclear(pgsql_result);
1000-
}
1029+
pgsql_discard_running_stmt(H);
10011030

10021031
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
10031032
if (pg_fields) {

ext/pdo_pgsql/pgsql_statement.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@
5656
#define FLOAT8LABEL "float8"
5757
#define FLOAT8OID 701
5858

59-
#define FIN_DISCARD 0x1
60-
#define FIN_CLOSE 0x2
61-
#define FIN_ABORT 0x4
6259

6360

64-
65-
static void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode)
61+
void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode)
6662
{
63+
if (!S) {
64+
return;
65+
}
66+
6767
pdo_pgsql_db_handle *H = S->H;
6868

6969
if (S->is_running_unbuffered && S->result && (fin_mode & FIN_ABORT)) {

ext/pdo_pgsql/php_pdo_pgsql_int.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const
9595

9696
extern const struct pdo_stmt_methods pgsql_stmt_methods;
9797

98+
#define FIN_DISCARD 0x1
99+
#define FIN_CLOSE 0x2
100+
#define FIN_ABORT 0x4
101+
102+
extern void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode);
103+
98104
#define pdo_pgsql_sqlstate(r) PQresultErrorField(r, PG_DIAG_SQLSTATE)
99105

100106
enum {

0 commit comments

Comments
 (0)