- Fixed bug #44861 (scrollable cursor don't work with pgsql)
This commit is contained in:
Matteo Beccati 2009-03-28 03:01:38 +00:00
parent dd6b8d4ceb
commit 61476ca182
3 changed files with 114 additions and 16 deletions

View file

@ -232,13 +232,13 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
if (S->cursor_name) { if (S->cursor_name) {
efree(S->cursor_name); efree(S->cursor_name);
} }
/* TODO: check how scrollable cursors related to prepared statements */
spprintf(&S->cursor_name, 0, "pdo_pgsql_cursor_%08x", (unsigned int) stmt); spprintf(&S->cursor_name, 0, "pdo_pgsql_cursor_%08x", (unsigned int) stmt);
emulate = 1;
} }
#if HAVE_PQPREPARE #if HAVE_PQPREPARE
if (driver_options) { else if (driver_options) {
if (pdo_attr_lval(driver_options, if (pdo_attr_lval(driver_options,
PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT, 0 TSRMLS_CC) == 1) { PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT, 0 TSRMLS_CC) == 1) {
emulate = 1; emulate = 1;

View file

@ -129,6 +129,24 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
S->current_row = 0; S->current_row = 0;
if (S->cursor_name) {
char *q = NULL;
spprintf(&q, 0, "DECLARE %s SCROLL CURSOR WITH HOLD FOR %s", S->cursor_name, stmt->active_query_string);
S->result = PQexec(H->server, q);
efree(q);
/* check if declare failed */
status = PQresultStatus(S->result);
if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
return 0;
}
/* fetch to be able to get the number of tuples later, but don't advance the cursor pointer */
spprintf(&q, 0, "FETCH FORWARD 0 FROM %s", S->cursor_name);
S->result = PQexec(H->server, q);
efree(q);
} else
#if HAVE_PQPREPARE #if HAVE_PQPREPARE
if (S->stmt_name) { if (S->stmt_name) {
/* using a prepared statement */ /* using a prepared statement */
@ -182,12 +200,7 @@ stmt_retry:
0); 0);
} else } else
#endif #endif
if (S->cursor_name) { {
char *q = NULL;
spprintf(&q, 0, "DECLARE %s CURSOR 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);
@ -350,19 +363,23 @@ 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) { if (S->cursor_name) {
char *ori_str; char *ori_str = NULL;
char *q = NULL; char *q = NULL;
ExecStatusType status; ExecStatusType status;
switch (ori) { switch (ori) {
case PDO_FETCH_ORI_NEXT: ori_str = "FORWARD"; break; case PDO_FETCH_ORI_NEXT: spprintf(&ori_str, 0, "NEXT"); break;
case PDO_FETCH_ORI_PRIOR: ori_str = "BACKWARD"; break; case PDO_FETCH_ORI_PRIOR: spprintf(&ori_str, 0, "BACKWARD"); break;
case PDO_FETCH_ORI_REL: ori_str = "RELATIVE"; break; case PDO_FETCH_ORI_FIRST: spprintf(&ori_str, 0, "FIRST"); break;
case PDO_FETCH_ORI_LAST: spprintf(&ori_str, 0, "LAST"); break;
case PDO_FETCH_ORI_ABS: spprintf(&ori_str, 0, "ABSOLUTE %ld", offset); break;
case PDO_FETCH_ORI_REL: spprintf(&ori_str, 0, "RELATIVE %ld", offset); break;
default: default:
return 0; return 0;
} }
spprintf(&q, 0, "FETCH %s %ld FROM %s", ori_str, offset, S->cursor_name); spprintf(&q, 0, "FETCH %s FROM %s", ori_str, S->cursor_name);
efree(ori_str);
S->result = PQexec(S->H->server, q); S->result = PQexec(S->H->server, q);
efree(q); efree(q);
status = PQresultStatus(S->result); status = PQresultStatus(S->result);
@ -372,9 +389,12 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
return 0; return 0;
} }
if (PQntuples(S->result)) {
S->current_row = 1; S->current_row = 1;
return 1; return 1;
} else {
return 0;
}
} else { } else {
if (S->current_row < stmt->row_count) { if (S->current_row < stmt->row_count) {
S->current_row++; S->current_row++;

View file

@ -0,0 +1,78 @@
--TEST--
Bug #44861 (scrollable cursor don't work with pgsql)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
$dbh = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = "SELECT 'row1' AS r UNION SELECT 'row2' UNION SELECT 'row3' UNION SELECT 'row4'";
$aParams = array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
$res = $dbh->prepare($query, $aParams);
$res->execute();
var_dump($res->fetchColumn());
var_dump($res->fetchColumn());
var_dump($res->fetchColumn());
var_dump($res->fetchColumn());
var_dump($res->fetchColumn());
var_dump($res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_ABS, 3));
var_dump($res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_PRIOR));
var_dump($res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_FIRST));
var_dump($res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_LAST));
var_dump($res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_REL, -1));
var_dump($res->fetchAll(PDO::FETCH_ASSOC));
// Test binding params via emulated prepared query
$res = $dbh->prepare("SELECT ?", $aParams);
$res->execute(array("it's working"));
var_dump($res->fetch(PDO::FETCH_NUM));
?>
--EXPECT--
string(4) "row1"
string(4) "row2"
string(4) "row3"
string(4) "row4"
bool(false)
array(1) {
[0]=>
string(4) "row3"
}
array(1) {
[0]=>
string(4) "row2"
}
array(1) {
[0]=>
string(4) "row1"
}
array(1) {
[0]=>
string(4) "row4"
}
array(1) {
[0]=>
string(4) "row3"
}
array(1) {
[0]=>
array(1) {
["r"]=>
string(4) "row4"
}
}
array(1) {
[0]=>
string(12) "it's working"
}