Skip to content

Commit a10ef19

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 3a7874b commit a10ef19

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;
@@ -348,6 +380,7 @@ static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const zend_string *sql)
348380

349381
bool in_trans = pgsql_handle_in_transaction(dbh);
350382

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

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

615+
pgsql_finish_running_stmt(H);
581616
res = PQexec(H->server, cmd);
582617

583618
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
@@ -683,9 +718,8 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
683718
/* Obtain db Handle */
684719
H = (pdo_pgsql_db_handle *)dbh->driver_data;
685720

686-
while ((pgsql_result = PQgetResult(H->server))) {
687-
PQclear(pgsql_result);
688-
}
721+
pgsql_discard_running_stmt(H);
722+
689723
pgsql_result = PQexec(H->server, query);
690724

691725
efree(query);
@@ -807,9 +841,8 @@ void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS)
807841

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

810-
while ((pgsql_result = PQgetResult(H->server))) {
811-
PQclear(pgsql_result);
812-
}
844+
pgsql_discard_running_stmt(H);
845+
813846
pgsql_result = PQexec(H->server, query);
814847

815848
efree(query);
@@ -903,9 +936,7 @@ void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS)
903936
RETURN_FALSE;
904937
}
905938

906-
while ((pgsql_result = PQgetResult(H->server))) {
907-
PQclear(pgsql_result);
908-
}
939+
pgsql_discard_running_stmt(H);
909940

910941
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
911942
if (pg_fields) {
@@ -994,9 +1025,7 @@ void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS)
9941025

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

997-
while ((pgsql_result = PQgetResult(H->server))) {
998-
PQclear(pgsql_result);
999-
}
1028+
pgsql_discard_running_stmt(H);
10001029

10011030
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
10021031
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)