1--TEST--
2MySQL PDOStatement->closeCursor()
3--SKIPIF--
4<?php
5require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
6require_once(dirname(__FILE__) . 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(dirname(__FILE__) . 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 dirname(__FILE__) . '/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