Skip to content

Commit d63db6e

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 a7e00b1 commit d63db6e

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
{
@@ -109,6 +110,37 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *
109110
}
110111
/* }}} */
111112

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

356388
bool in_trans = pgsql_handle_in_transaction(dbh);
357389

390+
pgsql_finish_running_stmt(H);
358391
if (!(res = PQexec(H->server, ZSTR_VAL(sql)))) {
359392
/* fatal error */
360393
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
@@ -430,6 +463,7 @@ static zend_string *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const zend_string *
430463
PGresult *res;
431464
ExecStatusType status;
432465

466+
pgsql_finish_running_stmt(H);
433467
if (name == NULL) {
434468
res = PQexec(H->server, "SELECT LASTVAL()");
435469
} else {
@@ -593,6 +627,7 @@ static bool pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh)
593627
PGresult *res;
594628
bool ret = true;
595629

630+
pgsql_finish_running_stmt(H);
596631
res = PQexec(H->server, cmd);
597632

598633
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
@@ -700,9 +735,8 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
700735
/* Obtain db Handle */
701736
H = (pdo_pgsql_db_handle *)dbh->driver_data;
702737

703-
while ((pgsql_result = PQgetResult(H->server))) {
704-
PQclear(pgsql_result);
705-
}
738+
pgsql_discard_running_stmt(H);
739+
706740
pgsql_result = PQexec(H->server, query);
707741

708742
efree(query);
@@ -824,9 +858,8 @@ void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS)
824858

825859
H = (pdo_pgsql_db_handle *)dbh->driver_data;
826860

827-
while ((pgsql_result = PQgetResult(H->server))) {
828-
PQclear(pgsql_result);
829-
}
861+
pgsql_discard_running_stmt(H);
862+
830863
pgsql_result = PQexec(H->server, query);
831864

832865
efree(query);
@@ -920,9 +953,7 @@ void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS)
920953
RETURN_FALSE;
921954
}
922955

923-
while ((pgsql_result = PQgetResult(H->server))) {
924-
PQclear(pgsql_result);
925-
}
956+
pgsql_discard_running_stmt(H);
926957

927958
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
928959
if (pg_fields) {
@@ -1011,9 +1042,7 @@ void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS)
10111042

10121043
H = (pdo_pgsql_db_handle *)dbh->driver_data;
10131044

1014-
while ((pgsql_result = PQgetResult(H->server))) {
1015-
PQclear(pgsql_result);
1016-
}
1045+
pgsql_discard_running_stmt(H);
10171046

10181047
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
10191048
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
@@ -92,6 +92,12 @@ extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const
9292

9393
extern const struct pdo_stmt_methods pgsql_stmt_methods;
9494

95+
#define FIN_DISCARD 0x1
96+
#define FIN_CLOSE 0x2
97+
#define FIN_ABORT 0x4
98+
99+
extern void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode);
100+
95101
#define pdo_pgsql_sqlstate(r) PQresultErrorField(r, PG_DIAG_SQLSTATE)
96102

97103
enum {

0 commit comments

Comments
 (0)