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