|
36 | 36 | #include "pgsql_driver_arginfo.h" |
37 | 37 |
|
38 | 38 | static bool pgsql_handle_in_transaction(pdo_dbh_t *dbh); |
| 39 | +void pgsql_stmt_finish(pdo_pgsql_stmt *S, int fin_mode); |
39 | 40 |
|
40 | 41 | static char * _pdo_pgsql_trim_message(const char *message, int persistent) |
41 | 42 | { |
@@ -109,6 +110,37 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char * |
109 | 110 | } |
110 | 111 | /* }}} */ |
111 | 112 |
|
| 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 | + |
112 | 144 | static void _pdo_pgsql_notice(void *context, const char *message) /* {{{ */ |
113 | 145 | { |
114 | 146 | pdo_dbh_t * dbh = (pdo_dbh_t *)context; |
@@ -258,6 +290,10 @@ static void pgsql_handle_closer(pdo_dbh_t *dbh) /* {{{ */ |
258 | 290 | PQfinish(H->server); |
259 | 291 | H->server = NULL; |
260 | 292 | } |
| 293 | + if (H->cached_table_name) { |
| 294 | + efree(H->cached_table_name); |
| 295 | + H->cached_table_name = NULL; |
| 296 | + } |
261 | 297 | if (H->einfo.errmsg) { |
262 | 298 | pefree(H->einfo.errmsg, dbh->is_persistent); |
263 | 299 | H->einfo.errmsg = NULL; |
@@ -351,6 +387,7 @@ static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) |
351 | 387 |
|
352 | 388 | bool in_trans = pgsql_handle_in_transaction(dbh); |
353 | 389 |
|
| 390 | + pgsql_finish_running_stmt(H); |
354 | 391 | if (!(res = PQexec(H->server, ZSTR_VAL(sql)))) { |
355 | 392 | /* fatal error */ |
356 | 393 | pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); |
@@ -426,6 +463,7 @@ static zend_string *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const zend_string * |
426 | 463 | PGresult *res; |
427 | 464 | ExecStatusType status; |
428 | 465 |
|
| 466 | + pgsql_finish_running_stmt(H); |
429 | 467 | if (name == NULL) { |
430 | 468 | res = PQexec(H->server, "SELECT LASTVAL()"); |
431 | 469 | } else { |
@@ -589,6 +627,7 @@ static bool pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh) |
589 | 627 | PGresult *res; |
590 | 628 | bool ret = true; |
591 | 629 |
|
| 630 | + pgsql_finish_running_stmt(H); |
592 | 631 | res = PQexec(H->server, cmd); |
593 | 632 |
|
594 | 633 | if (PQresultStatus(res) != PGRES_COMMAND_OK) { |
@@ -696,9 +735,8 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS) |
696 | 735 | /* Obtain db Handle */ |
697 | 736 | H = (pdo_pgsql_db_handle *)dbh->driver_data; |
698 | 737 |
|
699 | | - while ((pgsql_result = PQgetResult(H->server))) { |
700 | | - PQclear(pgsql_result); |
701 | | - } |
| 738 | + pgsql_discard_running_stmt(H); |
| 739 | + |
702 | 740 | pgsql_result = PQexec(H->server, query); |
703 | 741 |
|
704 | 742 | efree(query); |
@@ -820,9 +858,8 @@ void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS) |
820 | 858 |
|
821 | 859 | H = (pdo_pgsql_db_handle *)dbh->driver_data; |
822 | 860 |
|
823 | | - while ((pgsql_result = PQgetResult(H->server))) { |
824 | | - PQclear(pgsql_result); |
825 | | - } |
| 861 | + pgsql_discard_running_stmt(H); |
| 862 | + |
826 | 863 | pgsql_result = PQexec(H->server, query); |
827 | 864 |
|
828 | 865 | efree(query); |
@@ -916,9 +953,7 @@ void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS) |
916 | 953 | RETURN_FALSE; |
917 | 954 | } |
918 | 955 |
|
919 | | - while ((pgsql_result = PQgetResult(H->server))) { |
920 | | - PQclear(pgsql_result); |
921 | | - } |
| 956 | + pgsql_discard_running_stmt(H); |
922 | 957 |
|
923 | 958 | /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */ |
924 | 959 | if (pg_fields) { |
@@ -1007,9 +1042,7 @@ void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS) |
1007 | 1042 |
|
1008 | 1043 | H = (pdo_pgsql_db_handle *)dbh->driver_data; |
1009 | 1044 |
|
1010 | | - while ((pgsql_result = PQgetResult(H->server))) { |
1011 | | - PQclear(pgsql_result); |
1012 | | - } |
| 1045 | + pgsql_discard_running_stmt(H); |
1013 | 1046 |
|
1014 | 1047 | /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */ |
1015 | 1048 | if (pg_fields) { |
@@ -1461,6 +1494,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ |
1461 | 1494 |
|
1462 | 1495 | H->attached = 1; |
1463 | 1496 | H->pgoid = -1; |
| 1497 | + H->cached_table_oid = InvalidOid; |
1464 | 1498 |
|
1465 | 1499 | dbh->methods = &pgsql_methods; |
1466 | 1500 | dbh->alloc_own_columns = 1; |
|
0 commit comments