1--TEST--
2mysqli_poll() & INSERT SELECT
3--SKIPIF--
4<?php
5require_once('skipif.inc');
6require_once('skipifemb.inc');
7require_once('connect.inc');
8require_once('skipifconnectfailure.inc');
9
10if (!$IS_MYSQLND)
11	die("skip mysqlnd only feature, compile PHP using --with-mysqli=mysqlnd");
12?>
13--FILE--
14<?php
15	require_once('table.inc');
16
17	function get_connection() {
18		global $host, $user, $passwd, $db, $port, $socket;
19
20		if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
21			printf("[001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
22		return $link;
23	}
24
25
26	// Note: some queries will fail! They are supposed to fail.
27	$queries = array(
28			'CREATE TABLE IF NOT EXISTS bogus(id INT)',
29			'SET @a = 1',
30			'SELECT * FROM test ORDER BY id ASC LIMIT 2',
31			"INSERT INTO test(id, label) VALUES (100, 'z')",
32			'SELECT * FROM test ORDER BY id ASC LIMIT 2',
33			'SELECT',
34			'UPDATE test SET id = 101 WHERE id > 3',
35			'UPDATE_FIX test SET id = 101 WHERE id > 3',
36			'DROP TABLE IF EXISTS bogus',
37			'DELETE FROM test WHERE id = @a',
38			'DELETE FROM test WHERE id = 1',
39	);
40
41	$link = get_connection();
42	$have_proc = false;
43	mysqli_real_query($link, "DROP PROCEDURE IF EXISTS p");
44	if (mysqli_real_query($link, 'CREATE PROCEDURE p(IN ver_in VARCHAR(25), OUT ver_out VARCHAR(25)) BEGIN SELECT ver_in INTO ver_out; END;')) {
45			$have_proc = true;
46			$queries[] = "CALL p('myversion', @version)";
47	}
48	mysqli_close($link);
49
50	$links = array();
51	for ($i = 0; $i < count($queries); $i++) {
52
53		$link = get_connection();
54
55		if (true !== ($tmp = mysqli_query($link, $queries[$i], MYSQLI_ASYNC |  MYSQLI_USE_RESULT)))
56			printf("[002] Expecting true got %s/%s\n", gettype($tmp), var_export($tmp, true));
57
58		// WARNING KLUDGE NOTE
59		// Add a tiny delay to ensure that queries get executed in a certain order
60		// If your MySQL server is very slow the test may randomly fail!
61		usleep(20000);
62
63		$links[mysqli_thread_id($link)] = array(
64			'query' => $queries[$i],
65			'link' => $link,
66			'processed' => false,
67		);
68	}
69
70	$saved_errors = array();
71	do {
72		$poll_links = $poll_errors = $poll_reject = array();
73		foreach ($links as $thread_id => $link) {
74			if (!$link['processed']) {
75				$poll_links[] = $link['link'];
76				$poll_errors[] = $link['link'];
77				$poll_reject[] = $link['link'];
78			}
79		}
80		if (0 == count($poll_links))
81			break;
82
83		if (0 === ($num_ready = mysqli_poll($poll_links, $poll_errors, $poll_reject, 0, 200000)))
84			continue;
85
86		if (!empty($poll_errors)) {
87			die(var_dump($poll_errors));
88		}
89
90		if (FALSE === $num_ready) {
91			die("Some mysqli indicated error");
92		}
93
94		foreach ($poll_links as $link) {
95			$thread_id = mysqli_thread_id($link);
96			$links[$thread_id]['processed'] = true;
97
98			if (is_object($res = mysqli_reap_async_query($link))) {
99				// result set object
100				while ($row = mysqli_fetch_assoc($res)) {
101					// eat up all results
102					;
103				}
104				mysqli_free_result($res);
105			} else {
106				// either there is no result (no SELECT) or there is an error
107				if (mysqli_errno($link) > 0) {
108					$saved_errors[$thread_id] = mysqli_errno($link);
109					printf("[003] '%s' caused %d\n", $links[$thread_id]['query'],	mysqli_errno($link));
110				}
111			}
112		}
113
114	} while (true);
115
116	// Checking if all lines are still usable
117	foreach ($links as $thread_id => $link) {
118		if (isset($saved_errors[$thread_id]) &&
119			$saved_errors[$thread_id] != mysqli_errno($link['link'])) {
120			printf("[004] Error state not saved for query '%s', %d != %d\n", $link['query'],
121					$saved_errors[$thread_id], mysqli_errno($link['link']));
122		}
123
124		if (!$res = mysqli_query($link['link'], 'SELECT * FROM test WHERE id = 100'))
125			printf("[005] Expecting true got %s/%s\n", gettype($tmp), var_export($tmp, true));
126		if (!$row = mysqli_fetch_row($res))
127			printf("[006] Expecting true got %s/%s\n", gettype($tmp), var_export($tmp, true));
128
129		mysqli_free_result($res);
130	}
131
132	if ($res = mysqli_query($link['link'], "SELECT * FROM test WHERE id = 100")) {
133		$row = mysqli_fetch_assoc($res);
134		var_dump($row);
135		mysqli_free_result($res);
136	}
137
138	if ($have_proc && ($res = mysqli_query($link['link'], "SELECT @version as _version"))) {
139		$row = mysqli_fetch_assoc($res);
140		if ($row['_version'] != 'myversion') {
141			printf("[007] Check procedures\n");
142		}
143		mysqli_free_result($res);
144	}
145
146	foreach ($links as $link)
147		mysqli_close($link['link']);
148
149	$link = get_connection();
150	if (!mysqli_query($link, 'SELECT 1', MYSQLI_ASYNC))
151		printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
152
153	if (!mysqli_query($link, 'SELECT 1', MYSQLI_ASYNC))
154		printf("[009] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
155
156	mysqli_close($link);
157
158	print "done!";
159?>
160--CLEAN--
161<?php
162require_once("connect.inc");
163if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
164   printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
165
166if (!mysqli_query($link, "DROP TABLE IF EXISTS test"))
167	printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
168
169if (!mysqli_query($link, "DROP TABLE IF EXISTS bogus"))
170	printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
171
172mysqli_query($link, "DROP PROCEDURE IF EXISTS p");
173
174mysqli_close($link);
175?>
176--EXPECTF--
177[003] 'SELECT' caused 1064
178[003] 'UPDATE test SET id = 101 WHERE id > 3' caused 1062
179[003] 'UPDATE_FIX test SET id = 101 WHERE id > 3' caused 1064
180array(2) {
181  ["id"]=>
182  string(3) "100"
183  ["label"]=>
184  string(1) "z"
185}
186[009] [2014] %s
187done!
188