mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Take a blind stab at implementing scrollable cursors for pgsql.
We allocate a unique cursor name for each statement, so that we don't interfere with other open statement handles on the same dbh. Note, however, that we force a new transaction for each open scrollable cursor (postgres requires cursors to be used inside a transaction). This is okay, except for the case where a scrollable cursor is opened, an update is made and the cursor is closed; closing the cursor commits the transaction that was begun when it was opened. It might well be better to avoid the transaction in PDO and force the user to be aware of the requirements of cursors and explicitly initiate the transaction themselves. This is all untested code; it compiles and looks like it will work, but I encourage someone with a real postgres setup to actually sit down and try to use it.
This commit is contained in:
parent
10cba41a70
commit
ef0de01b62
3 changed files with 75 additions and 8 deletions
|
@ -124,12 +124,30 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
|
||||||
{
|
{
|
||||||
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
|
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
|
||||||
pdo_pgsql_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt));
|
pdo_pgsql_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt));
|
||||||
|
int ret = 1;
|
||||||
|
int scrollable;
|
||||||
|
|
||||||
S->H = H;
|
S->H = H;
|
||||||
stmt->driver_data = S;
|
stmt->driver_data = S;
|
||||||
stmt->methods = &pgsql_stmt_methods;
|
stmt->methods = &pgsql_stmt_methods;
|
||||||
|
|
||||||
return 1;
|
scrollable = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
|
||||||
|
PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL;
|
||||||
|
|
||||||
|
if (scrollable) {
|
||||||
|
PGresult *res;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
spprintf(&S->cursor_name, 0, "pdo_pgsql_cursor_%08x", stmt);
|
||||||
|
|
||||||
|
res = PQexec(H->server, "BEGIN");
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long pgsql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
|
static long pgsql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
|
||||||
|
|
|
@ -41,6 +41,20 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
|
||||||
PQclear(S->result);
|
PQclear(S->result);
|
||||||
S->result = NULL;
|
S->result = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (S->cursor_name) {
|
||||||
|
pdo_pgsql_db_handle *H = S->H;
|
||||||
|
char *q = NULL;
|
||||||
|
spprintf(&q, 0, "CLOSE %s", S->cursor_name);
|
||||||
|
PGresult *res = PQexec(H->server, q);
|
||||||
|
efree(q);
|
||||||
|
if (res) PQclear(res);
|
||||||
|
res = PQexec(H->server, "COMMIT");
|
||||||
|
if (res) PQclear(res);
|
||||||
|
efree(S->cursor_name);
|
||||||
|
S->cursor_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(S->cols) {
|
if(S->cols) {
|
||||||
efree(S->cols);
|
efree(S->cols);
|
||||||
S->cols = NULL;
|
S->cols = NULL;
|
||||||
|
@ -64,7 +78,14 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (S->cursor_name) {
|
||||||
|
char *q = NULL;
|
||||||
|
spprintf(&q, 0, "DECLARE %s FOR %s", S->cursor_name, stmt->active_query_string);
|
||||||
|
S->result = PQexec(H->server, q);
|
||||||
|
efree(q);
|
||||||
|
} else {
|
||||||
S->result = PQexec(H->server, stmt->active_query_string);
|
S->result = PQexec(H->server, stmt->active_query_string);
|
||||||
|
}
|
||||||
status = PQresultStatus(S->result);
|
status = PQresultStatus(S->result);
|
||||||
|
|
||||||
if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
|
if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
|
||||||
|
@ -77,7 +98,6 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
|
||||||
S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column));
|
S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (status == PGRES_COMMAND_OK) {
|
if (status == PGRES_COMMAND_OK) {
|
||||||
stmt->row_count = (long)atoi(PQcmdTuples(S->result));
|
stmt->row_count = (long)atoi(PQcmdTuples(S->result));
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,12 +118,40 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
|
||||||
{
|
{
|
||||||
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
|
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
|
||||||
|
|
||||||
|
if (S->cursor_name) {
|
||||||
|
char *ori_str = NULL;
|
||||||
|
char *q = NULL;
|
||||||
|
ExecStatusType status;
|
||||||
|
|
||||||
|
switch (ori) {
|
||||||
|
case PDO_FETCH_ORI_NEXT: ori_str = "NEXT"; break;
|
||||||
|
case PDO_FETCH_ORI_PRIOR: ori_str = "PRIOR"; break;
|
||||||
|
case PDO_FETCH_ORI_REL: ori_str = "RELATIVE"; break;
|
||||||
|
}
|
||||||
|
if (!ori_str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
spprintf(&q, 0, "FETCH %s %d FROM %s", ori_str, offset, S->cursor_name);
|
||||||
|
S->result = PQexec(S->H->server, q);
|
||||||
|
status = PQresultStatus(S->result);
|
||||||
|
|
||||||
|
if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
|
||||||
|
pdo_pgsql_error_stmt(stmt, status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
S->current_row = 1;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
if (S->current_row < stmt->row_count) {
|
if (S->current_row < stmt->row_count) {
|
||||||
S->current_row++;
|
S->current_row++;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
|
static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
|
||||||
|
|
|
@ -50,6 +50,7 @@ typedef struct {
|
||||||
PGresult *result;
|
PGresult *result;
|
||||||
int current_row;
|
int current_row;
|
||||||
pdo_pgsql_column *cols;
|
pdo_pgsql_column *cols;
|
||||||
|
char *cursor_name;
|
||||||
} pdo_pgsql_stmt;
|
} pdo_pgsql_stmt;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue