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