diff options
-rw-r--r-- | ext/pdo_pgsql/pgsql_driver.c | 22 | ||||
-rw-r--r-- | ext/pdo_pgsql/pgsql_statement.c | 60 | ||||
-rw-r--r-- | ext/pdo_pgsql/php_pdo_pgsql_int.h | 1 |
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 { |