Skip to content

Commit d0e2286

Browse files
committed
pdo_pgsql: unbuffered fetching: now invokable
use Pdo::setAttribute(PDO::ATTR_PREFETCH, 0)
1 parent c45b3f3 commit d0e2286

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

ext/pdo_pgsql/pgsql_driver.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ static bool pgsql_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *
303303
stmt->named_rewrite_template = "$%d";
304304
}
305305

306+
S->is_unbuffered = H->default_fetching_laziness;
307+
306308
ret = pdo_parse_params(stmt, sql, &nsql);
307309

308310
if (ret == -1) {
@@ -1301,6 +1303,12 @@ static bool pdo_pgsql_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
13011303
}
13021304
H->disable_prepares = bval;
13031305
return true;
1306+
case PDO_ATTR_PREFETCH:
1307+
if (!pdo_get_bool_param(&bval, val)) {
1308+
return false;
1309+
}
1310+
H->default_fetching_laziness = !bval;
1311+
return true;
13041312
default:
13051313
return false;
13061314
}

ext/pdo_pgsql/pgsql_statement.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,28 @@
6060

6161
static void pgsql_stmt_cancel(pdo_pgsql_stmt *S)
6262
{
63+
if (S->result) {
64+
PQclear(S->result);
65+
S->result = NULL;
66+
}
67+
6368
if (S->is_running_unbuffered) {
6469
PGcancel *cancel = PQgetCancel(S->H->server);
6570
char errbuf[256];
6671
PQcancel(cancel, errbuf, 256);
6772
PQfreeCancel(cancel);
6873
S->is_running_unbuffered = false;
6974
}
75+
76+
if (S->is_unbuffered) {
77+
/* https://postgresql.org/docs/current/libpq-async.html:
78+
* "PQsendQuery cannot be called again until PQgetResult has returned NULL"
79+
*/
80+
while ((S->result = PQgetResult(S->H->server))) {
81+
PQclear(S->result);
82+
S->result = NULL;
83+
}
84+
}
7085
}
7186

7287
static int pgsql_stmt_dtor(pdo_stmt_t *stmt)
@@ -76,12 +91,6 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt)
7691
&& IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE(stmt->database_object_handle)])
7792
&& !(OBJ_FLAGS(Z_OBJ(stmt->database_object_handle)) & IS_OBJ_FREE_CALLED);
7893

79-
if (S->result) {
80-
/* free the resource */
81-
PQclear(S->result);
82-
S->result = NULL;
83-
}
84-
8594
if (S->stmt_name) {
8695
if (S->is_prepared && server_obj_usable) {
8796
pdo_pgsql_db_handle *H = S->H;
@@ -156,10 +165,6 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt)
156165

157166
/* ensure that we free any previous unfetched results */
158167
pgsql_stmt_cancel(S);
159-
if(S->result) {
160-
PQclear(S->result);
161-
S->result = NULL;
162-
}
163168

164169
S->current_row = 0;
165170

@@ -541,10 +546,10 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
541546
S->current_row = 0;
542547

543548
if (!stmt->row_count) {
544-
/* libpq requires looping until getResult returns null */
545-
PQgetResult(S->H->server);
546549
/* @todo receiving a result here is unexpected and should throw an error */
547550
S->is_running_unbuffered = false;
551+
/* libpq requires looping until getResult returns null */
552+
pgsql_stmt_cancel(S);
548553
}
549554
}
550555
if (S->current_row < stmt->row_count) {

ext/pdo_pgsql/php_pdo_pgsql_int.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ typedef struct {
4747
bool disable_prepares;
4848
HashTable *lob_streams;
4949
zend_fcall_info_cache *notice_callback;
50+
bool default_fetching_laziness;
5051
} pdo_pgsql_db_handle;
5152

5253
typedef struct {

0 commit comments

Comments
 (0)