summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c22
-rw-r--r--ext/pdo_pgsql/pgsql_statement.c60
-rw-r--r--ext/pdo_pgsql/php_pdo_pgsql_int.h1
3 files changed, 75 insertions, 8 deletions
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
index c5071e13fa..f0815cbada 100644
--- a/ext/pdo_pgsql/pgsql_driver.c
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -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_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt));
+ int ret = 1;
+ int scrollable;
S->H = H;
stmt->driver_data = S;
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)
diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c
index 2220cd986c..ce20503f9c 100644
--- a/ext/pdo_pgsql/pgsql_statement.c
+++ b/ext/pdo_pgsql/pgsql_statement.c
@@ -41,6 +41,20 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
PQclear(S->result);
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) {
efree(S->cols);
S->cols = NULL;
@@ -64,7 +78,14 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
}
}
- S->result = PQexec(H->server, stmt->active_query_string);
+ 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);
+ }
status = PQresultStatus(S->result);
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));
}
-
if (status == PGRES_COMMAND_OK) {
stmt->row_count = (long)atoi(PQcmdTuples(S->result));
} else {
@@ -98,11 +118,39 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
{
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
- if (S->current_row < stmt->row_count) {
- S->current_row++;
- return 1;
+ 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 {
- return 0;
+ if (S->current_row < stmt->row_count) {
+ S->current_row++;
+ return 1;
+ } else {
+ return 0;
+ }
}
}
diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h
index 27d84277b9..00a6e0d3b7 100644
--- a/ext/pdo_pgsql/php_pdo_pgsql_int.h
+++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h
@@ -50,6 +50,7 @@ typedef struct {
PGresult *result;
int current_row;
pdo_pgsql_column *cols;
+ char *cursor_name;
} pdo_pgsql_stmt;
typedef struct {