]> granicus.if.org Git - php/commitdiff
- Fixed bug #44861 (scrollable cursor don't work with pgsql)
authorMatteo Beccati <mbeccati@php.net>
Sat, 28 Mar 2009 02:58:04 +0000 (02:58 +0000)
committerMatteo Beccati <mbeccati@php.net>
Sat, 28 Mar 2009 02:58:04 +0000 (02:58 +0000)
NEWS
ext/pdo_pgsql/pgsql_driver.c
ext/pdo_pgsql/pgsql_statement.c
ext/pdo_pgsql/tests/bug44861.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 961739a6e90d9a1fede8fa1dc7169b396a312130..11e221d766493eba305ef49aa194801986253568 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ PHP                                                                        NEWS
 ?? ??? 200?, PHP 5.3.0 RC 2
 - Undeprecated ticks. (Arnaud)
 
+- Fixed bug #44861 (scrollable cursor don't work with pgsql). (Matteo)
 - Fixed bug #47779 (Wrong value for SIG_UNBLOCK and SIG_SETMASK constants).
   (Matteo)
 - Fixed bug #47771 (Exception during object construction from arg call calls
index 04617d896886c8f719e1cb588832d3a4281e34ab..ed5b56f028b34624c0f5cc6a55bcc2a7f70bb701 100644 (file)
@@ -232,13 +232,13 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
                if (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);
+               emulate = 1;
        }
 
 #if HAVE_PQPREPARE
 
-       if (driver_options) {
+       else if (driver_options) {
                if (pdo_attr_lval(driver_options,
                                PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT, 0 TSRMLS_CC) == 1) {
                        emulate = 1;
index fb7d730a2e228348199669c29fd5719fd6956443..d711ecff299248f368277fb779d10e2e96fce2dd 100644 (file)
@@ -129,6 +129,24 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
        
        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 (S->stmt_name) {
                /* using a prepared statement */
@@ -182,12 +200,7 @@ stmt_retry:
                                0);
        } else
 #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);
        }
        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;
 
        if (S->cursor_name) {
-               char *ori_str;
+               char *ori_str = NULL;
                char *q = NULL;
                ExecStatusType status;
 
                switch (ori) {
-                       case PDO_FETCH_ORI_NEXT:        ori_str = "FORWARD"; break;
-                       case PDO_FETCH_ORI_PRIOR:       ori_str = "BACKWARD"; break;
-                       case PDO_FETCH_ORI_REL:         ori_str = "RELATIVE"; break;
+                       case PDO_FETCH_ORI_NEXT:        spprintf(&ori_str, 0, "NEXT"); break;
+                       case PDO_FETCH_ORI_PRIOR:       spprintf(&ori_str, 0, "BACKWARD"); 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:
                                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);
                efree(q);
                status = PQresultStatus(S->result);
@@ -372,9 +389,12 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
                        return 0;
                }
 
-               S->current_row = 1;
-               return 1;       
-               
+               if (PQntuples(S->result)) {
+                       S->current_row = 1;
+                       return 1;
+               } else {
+                       return 0;
+               }
        } else {
                if (S->current_row < stmt->row_count) {
                        S->current_row++;
diff --git a/ext/pdo_pgsql/tests/bug44861.phpt b/ext/pdo_pgsql/tests/bug44861.phpt
new file mode 100644 (file)
index 0000000..f6233f1
--- /dev/null
@@ -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"
+}