Skip to content

Commit 5668b16

Browse files
committed
Revert "Pdo\Pgsql: Fix getColumnMeta() for GH-15287 Pdo\Pgsql::setAttribute(PDO::ATTR_PREFETCH, 0)"
This reverts commit 8982351.
1 parent f566312 commit 5668b16

File tree

5 files changed

+26
-109
lines changed

5 files changed

+26
-109
lines changed

NEWS

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,4 @@ PHP NEWS
77
with a given skeleton, locale, collapse type and identity fallback.
88
(BogdanUngureanu)
99

10-
- PDO_PGSQL:
11-
. Fixed Pdo\Pgsql::getColumnMeta() when Pdo\Pgsql::setAttribute(PDO::ATTR_PREFETCH, 0).
12-
(outtersg)
13-
1410
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>

ext/pdo_pgsql/pgsql_driver.c

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
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);
4039

4140
static char * _pdo_pgsql_trim_message(const char *message, int persistent)
4241
{
@@ -110,37 +109,6 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *
110109
}
111110
/* }}} */
112111

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(NULL, 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-
144112
static void _pdo_pgsql_notice(void *context, const char *message) /* {{{ */
145113
{
146114
pdo_dbh_t * dbh = (pdo_dbh_t *)context;
@@ -290,10 +258,6 @@ static void pgsql_handle_closer(pdo_dbh_t *dbh) /* {{{ */
290258
PQfinish(H->server);
291259
H->server = NULL;
292260
}
293-
if (H->cached_table_name) {
294-
efree(H->cached_table_name);
295-
H->cached_table_name = NULL;
296-
}
297261
if (H->einfo.errmsg) {
298262
pefree(H->einfo.errmsg, dbh->is_persistent);
299263
H->einfo.errmsg = NULL;
@@ -387,7 +351,6 @@ static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const zend_string *sql)
387351

388352
bool in_trans = pgsql_handle_in_transaction(dbh);
389353

390-
pgsql_finish_running_stmt(H);
391354
if (!(res = PQexec(H->server, ZSTR_VAL(sql)))) {
392355
/* fatal error */
393356
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
@@ -463,7 +426,6 @@ static zend_string *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const zend_string *
463426
PGresult *res;
464427
ExecStatusType status;
465428

466-
pgsql_finish_running_stmt(H);
467429
if (name == NULL) {
468430
res = PQexec(H->server, "SELECT LASTVAL()");
469431
} else {
@@ -627,7 +589,6 @@ static bool pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh)
627589
PGresult *res;
628590
bool ret = true;
629591

630-
pgsql_finish_running_stmt(H);
631592
res = PQexec(H->server, cmd);
632593

633594
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
@@ -735,8 +696,9 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
735696
/* Obtain db Handle */
736697
H = (pdo_pgsql_db_handle *)dbh->driver_data;
737698

738-
pgsql_discard_running_stmt(H);
739-
699+
while ((pgsql_result = PQgetResult(H->server))) {
700+
PQclear(pgsql_result);
701+
}
740702
pgsql_result = PQexec(H->server, query);
741703

742704
efree(query);
@@ -858,8 +820,9 @@ void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS)
858820

859821
H = (pdo_pgsql_db_handle *)dbh->driver_data;
860822

861-
pgsql_discard_running_stmt(H);
862-
823+
while ((pgsql_result = PQgetResult(H->server))) {
824+
PQclear(pgsql_result);
825+
}
863826
pgsql_result = PQexec(H->server, query);
864827

865828
efree(query);
@@ -953,7 +916,9 @@ void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS)
953916
RETURN_FALSE;
954917
}
955918

956-
pgsql_discard_running_stmt(H);
919+
while ((pgsql_result = PQgetResult(H->server))) {
920+
PQclear(pgsql_result);
921+
}
957922

958923
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
959924
if (pg_fields) {
@@ -1042,7 +1007,9 @@ void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS)
10421007

10431008
H = (pdo_pgsql_db_handle *)dbh->driver_data;
10441009

1045-
pgsql_discard_running_stmt(H);
1010+
while ((pgsql_result = PQgetResult(H->server))) {
1011+
PQclear(pgsql_result);
1012+
}
10461013

10471014
/* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
10481015
if (pg_fields) {
@@ -1494,7 +1461,6 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{
14941461

14951462
H->attached = 1;
14961463
H->pgoid = -1;
1497-
H->cached_table_oid = InvalidOid;
14981464

14991465
dbh->methods = &pgsql_methods;
15001466
dbh->alloc_own_columns = 1;

ext/pdo_pgsql/pgsql_statement.c

Lines changed: 14 additions & 36 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
5962

6063

61-
void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode)
62-
{
63-
if (!S) {
64-
return;
65-
}
6664

65+
static void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode)
66+
{
6767
pdo_pgsql_db_handle *H = S->H;
6868

6969
if (S->is_running_unbuffered && S->result && (fin_mode & FIN_ABORT)) {
@@ -113,10 +113,9 @@ void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode)
113113
}
114114

115115
S->is_prepared = false;
116-
}
117-
118-
if (H->running_stmt == S && (fin_mode & (FIN_CLOSE|FIN_ABORT))) {
119-
H->running_stmt = NULL;
116+
if (H->running_stmt == S) {
117+
H->running_stmt = NULL;
118+
}
120119
}
121120
}
122121

@@ -189,8 +188,9 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt)
189188
* and returns a PGRES_FATAL_ERROR when PQgetResult gets called for stmt 2 if DEALLOCATE
190189
* was called for stmt 1 inbetween
191190
* (maybe it will change with pipeline mode in libpq 14?) */
192-
if (H->running_stmt && H->running_stmt->is_unbuffered) {
191+
if (S->is_unbuffered && H->running_stmt) {
193192
pgsql_stmt_finish(H->running_stmt, FIN_CLOSE);
193+
H->running_stmt = NULL;
194194
}
195195
/* ensure that we free any previous unfetched results */
196196
pgsql_stmt_finish(S, 0);
@@ -702,29 +702,12 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pd
702702
return 1;
703703
}
704704

705-
static zend_always_inline char * pdo_pgsql_translate_oid_to_table(Oid oid, pdo_pgsql_db_handle *H)
705+
static zend_always_inline char * pdo_pgsql_translate_oid_to_table(Oid oid, PGconn *conn)
706706
{
707-
PGconn *conn = H->server;
708707
char *table_name = NULL;
709708
PGresult *tmp_res;
710709
char *querystr = NULL;
711710

712-
if (oid == H->cached_table_oid) {
713-
return H->cached_table_name;
714-
}
715-
716-
if (H->running_stmt && H->running_stmt->is_unbuffered) {
717-
/* in single-row mode, libpq forbids passing a new query
718-
* while we're still flushing the current one's result */
719-
return NULL;
720-
}
721-
722-
if (H->cached_table_name) {
723-
efree(H->cached_table_name);
724-
H->cached_table_name = NULL;
725-
H->cached_table_oid = InvalidOid;
726-
}
727-
728711
spprintf(&querystr, 0, "SELECT RELNAME FROM PG_CLASS WHERE OID=%d", oid);
729712

730713
if ((tmp_res = PQexec(conn, querystr)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
@@ -741,8 +724,6 @@ static zend_always_inline char * pdo_pgsql_translate_oid_to_table(Oid oid, pdo_p
741724
return 0;
742725
}
743726

744-
H->cached_table_oid = oid;
745-
H->cached_table_name = estrdup(table_name);
746727
table_name = estrdup(table_name);
747728

748729
PQclear(tmp_res);
@@ -771,9 +752,10 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *r
771752

772753
table_oid = PQftable(S->result, colno);
773754
add_assoc_long(return_value, "pgsql:table_oid", table_oid);
774-
table_name = pdo_pgsql_translate_oid_to_table(table_oid, S->H);
755+
table_name = pdo_pgsql_translate_oid_to_table(table_oid, S->H->server);
775756
if (table_name) {
776-
add_assoc_string(return_value, "table", S->H->cached_table_name);
757+
add_assoc_string(return_value, "table", table_name);
758+
efree(table_name);
777759
}
778760

779761
switch (S->cols[colno].pgsql_type) {
@@ -812,10 +794,6 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *r
812794
break;
813795
default:
814796
/* Fetch metadata from Postgres system catalogue */
815-
if (S->H->running_stmt && S->H->running_stmt->is_unbuffered) {
816-
/* libpq forbids calling a query while we're still reading the preceding one's */
817-
break;
818-
}
819797
spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type);
820798
res = PQexec(S->H->server, q);
821799
efree(q);

ext/pdo_pgsql/php_pdo_pgsql_int.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ typedef struct {
4343
unsigned _reserved:31;
4444
pdo_pgsql_error_info einfo;
4545
Oid pgoid;
46-
Oid cached_table_oid;
47-
char *cached_table_name;
4846
unsigned int stmt_counter;
4947
bool emulate_prepares;
5048
bool disable_prepares;
@@ -92,12 +90,6 @@ extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const
9290

9391
extern const struct pdo_stmt_methods pgsql_stmt_methods;
9492

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-
10193
#define pdo_pgsql_sqlstate(r) PQresultErrorField(r, PG_DIAG_SQLSTATE)
10294

10395
enum {

ext/pdo_pgsql/tests/gh15287.phpt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,6 @@ $res = []; while (($re = $stmt->fetch())) $res[] = $re; display($res);
132132
$stmt->execute([ 0 ]);
133133
$res = []; for ($i = -1; ++$i < 2;) $res[] = $stmt->fetch(); display($res);
134134
display($pdo->query("select * from t2")->fetchAll());
135-
136-
// Metadata calls the server for some operations (notably table oid-to-name conversion).
137-
// This will break libpq (that forbids a second PQexec before we consumed the first one).
138-
// Instead of either letting libpq return an error, or blindly forbid this call, we expect
139-
// being transparently provided at least attributes which do not require a server roundtrip.
140-
// And good news: column name is one of those "local" attributes.
141-
echo "=== meta ===\n";
142-
$stmt = $pdo->query("select * from t limit 2");
143-
echo "Starting with column " . $stmt->getColumnMeta(0)['name'] . ":\n";
144-
display($stmt->fetchAll());
145-
146135
?>
147136
--EXPECTF--
148137
=== non regression ===
@@ -192,7 +181,3 @@ multiple calls to the same prepared statement, some interrupted before having re
192181
0
193182
1
194183
678 ok
195-
=== meta ===
196-
Starting with column n:
197-
0 original
198-
1 non original

0 commit comments

Comments
 (0)