1--TEST--
2MySQL PDOStatement->closeCursor()
3--EXTENSIONS--
4pdo_mysql
5--SKIPIF--
6<?php
7require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
8MySQLPDOTest::skip();
9$db = MySQLPDOTest::factory();
10?>
11--FILE--
12<?php
13    /* TODO the results look wrong, why do we get 2014 with buffered AND unbuffered queries */
14    require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
15    $db = MySQLPDOTest::factory();
16
17    function pdo_mysql_stmt_closecursor($db) {
18
19        // This one should fail. I let it fail to prove that closeCursor() makes a difference.
20        // If no error messages gets printed do not know if proper usage of closeCursor() makes any
21        // difference or not. That's why we need to cause an error here.
22        $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
23        $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
24        // query() shall fail!
25        $stmt2 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
26        $stmt1->closeCursor();
27
28        // This is proper usage of closeCursor(). It shall prevent any further error messages.
29        if (MySQLPDOTest::isPDOMySQLnd()) {
30            $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
31        } else {
32            // see pdo_mysql_stmt_unbuffered_2050.phpt for an explanation
33            unset($stmt1);
34            $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
35        }
36        // fetch only the first rows and let closeCursor() clean up
37        $row1 = $stmt1->fetch(PDO::FETCH_ASSOC);
38        $stmt1->closeCursor();
39
40        $stmt2 = $db->prepare('UPDATE test SET label = ? WHERE id = ?');
41        $stmt2->bindValue(1, "z");
42
43        $stmt2->bindValue(2, $row1['id']);
44        $stmt2->execute();
45        $stmt2->closeCursor();
46
47        $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
48        // check if changing the fetch mode from unbuffered to buffered will
49        // cause any harm to a statement created prior to the change
50        $stmt1->execute();
51        $row2 = $stmt1->fetch(PDO::FETCH_ASSOC);
52        $stmt1->closeCursor();
53        if (!isset($row2['label']) || ('z' !== $row2['label']))
54            printf("Expecting array(id => 1, label => z) got %s\n", var_export($row2, true));
55        unset($stmt1);
56
57        $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
58        // should work
59        $stmt2 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
60        $stmt1->closeCursor();
61
62        $stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
63        // fetch only the first rows and let closeCursor() clean up
64        $row3 = $stmt1->fetch(PDO::FETCH_ASSOC);
65        $stmt1->closeCursor();
66        assert($row3 == $row2);
67
68        $stmt2 = $db->prepare('UPDATE test SET label = ? WHERE id = ?');
69        $stmt2->bindValue(1, "a");
70        $stmt2->bindValue(2, $row1['id']);
71        $stmt2->execute();
72        $stmt2->closeCursor();
73
74        $stmt1->execute();
75        $row4 = $stmt1->fetch(PDO::FETCH_ASSOC);
76        $stmt1->closeCursor();
77        assert($row4 == $row1);
78
79        $offset = 0;
80        $stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2');
81        $in = 0;
82        if (!$stmt->bindParam(1, $in))
83            printf("[%03d + 1] Cannot bind parameter, %s %s\n", $offset,
84                $stmt->errorCode(), var_export($stmt->errorInfo(), true));
85
86        $stmt->execute();
87        $id = $label = null;
88
89        if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
90            printf("[%03d + 2] Cannot bind integer column, %s %s\n", $offset,
91                $stmt->errorCode(), var_export($stmt->errorInfo(), true));
92
93        if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
94            printf("[%03d + 3] Cannot bind string column, %s %s\n", $offset,
95                $stmt->errorCode(), var_export($stmt->errorInfo(), true));
96
97        while ($stmt->fetch(PDO::FETCH_BOUND))
98            printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
99                $in,
100                var_export($id, true), gettype($id),
101                var_export($label, true), gettype($label));
102
103        $stmt->closeCursor();
104        $stmt->execute();
105
106    }
107
108
109    try {
110
111        printf("Testing emulated PS...\n");
112        $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
113        if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
114            printf("[002] Unable to turn on emulated prepared statements\n");
115
116        printf("Buffered...\n");
117        $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
118        MySQLPDOTest::createTestTable($db);
119        pdo_mysql_stmt_closecursor($db);
120
121        printf("Unbuffered...\n");
122        $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
123        MySQLPDOTest::createTestTable($db);
124        pdo_mysql_stmt_closecursor($db);
125
126        printf("Testing native PS...\n");
127        $db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
128        if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
129            printf("[002] Unable to turn off emulated prepared statements\n");
130
131        printf("Buffered...\n");
132        MySQLPDOTest::createTestTable($db);
133        $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
134        pdo_mysql_stmt_closecursor($db);
135
136        printf("Unbuffered...\n");
137        MySQLPDOTest::createTestTable($db);
138        $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
139        pdo_mysql_stmt_closecursor($db);
140
141    } catch (PDOException $e) {
142        printf("[001] %s [%s] %s\n",
143            $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
144    }
145
146    print "done!";
147?>
148--CLEAN--
149<?php
150require __DIR__ . '/mysql_pdo_test.inc';
151$db = MySQLPDOTest::factory();
152$db->exec('DROP TABLE IF EXISTS test');
153?>
154--EXPECTF--
155Testing emulated PS...
156Buffered...
157
158Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
159in = 0 -> id = 1 (integer) / label = 'a' (string)
160in = 0 -> id = 2 (integer) / label = 'b' (string)
161Unbuffered...
162
163Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
164in = 0 -> id = 1 (integer) / label = 'a' (string)
165in = 0 -> id = 2 (integer) / label = 'b' (string)
166Testing native PS...
167Buffered...
168
169Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
170in = 0 -> id = 1 (integer) / label = 'a' (string)
171in = 0 -> id = 2 (integer) / label = 'b' (string)
172Unbuffered...
173
174Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
175in = 0 -> id = 1 (integer) / label = 'a' (string)
176in = 0 -> id = 2 (integer) / label = 'b' (string)
177done!
178