1--TEST--
2int mysqli_poll() and kill
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('connect.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	// Killing connection - 1
26
27	$link = get_connection();
28	if (true !== ($tmp = mysqli_query($link, "SELECT 1 AS 'processed before killed'", MYSQLI_ASYNC |  MYSQLI_USE_RESULT)))
29		printf("[002] Expecting boolean/true got %s/%s\n", gettype($tmp), var_export($tmp, true));
30
31	// Sleep 0.1s - the asynchronous query should have been processed after the wait period
32	usleep(100000);
33	$thread_id = mysqli_thread_id($link);
34	mysqli_kill(get_connection(), $thread_id);
35
36	$links = array($link);
37	$errors = array($link);
38	$reject = array($link);
39
40	// Yes, 1 - the asynchronous query should have been processed
41	if (1 !== ($tmp = (mysqli_poll($links, $errors, $reject, 0, 10000))))
42		printf("[003] Expecting int/1 got %s/%s\n", gettype($tmp), var_export($tmp, true));
43
44	if (!is_array($links) || empty($links))
45		printf("[004] Expecting non-empty array got %s/%s\n", gettype($links), var_export($links, true));
46	else
47		foreach ($links as $link) {
48			if (is_object($res = mysqli_reap_async_query($link))) {
49				// Yes, you can fetch a result - the query has been processed
50				var_dump(mysqli_fetch_assoc($res));
51				mysqli_free_result($res);
52			} else if ($link->errno > 0) {
53				printf("[005] Error: %d\n", $link->errno);
54			}
55		}
56
57	// No error!
58	if (!is_array($errors) || !empty($errors))
59		printf("[006] Expecting non-empty array got %s/%s\n", gettype($errors), var_export($errors, true));
60
61	if (!is_array($reject) || !empty($reject))
62		printf("[007] Expecting empty array got %s/%s\n", gettype($reject), var_export($reject, true));
63
64	// Lets pass a dead connection
65	$links = array($link);
66	$errors = array($link);
67	$reject = array($link);
68	if (0 !== ($tmp = mysqli_poll($links, $errors, $reject, 1)))
69		printf("[008] There should be no connection ready! Returned %s/%s, expecting int/0.\n",
70			gettype($tmp), var_export($tmp, true));
71
72	if (!empty($errors))
73		printf("[009] There should be no errors but one rejected connection\n");
74
75	foreach ($reject as $mysqli)
76		if (mysqli_thread_id($mysqli) != $thread_id) {
77			printf("[010] Rejected thread %d should have rejected thread %d\n",
78				mysqli_thread_id($mysqli), $thread_id);
79		}
80
81	// Killing connection - 2
82
83	$link = get_connection();
84	if (true !== ($tmp = mysqli_query($link, "SELECT 1", MYSQLI_ASYNC |  MYSQLI_USE_RESULT)))
85		printf("[011] Expecting boolean/true got %s/%s\n", gettype($tmp), var_export($tmp, true));
86
87	usleep(100000);
88	$thread_id = mysqli_thread_id($link);
89	mysqli_kill(get_connection(), $thread_id);
90
91	// Yes, 1 - fetch OK packet of kill!
92	$processed = 0;
93	do {
94		$links = array($link, $link);
95		$errors = array($link, $link);
96		$reject = array($link, $link);
97		$ready = mysqli_poll($links, $errors, $reject, 1);
98
99		if (!empty($errors)) {
100			foreach ($errors as $mysqli) {
101				printf("[012] Error on thread %d: %s/%s\n",
102					mysqli_thread_id($mysqli),
103					mysqli_errno($mysqli),
104					mysqli_error($mysqli));
105			}
106			break;
107		}
108
109		if (!empty($reject)) {
110			foreach ($reject as $mysqli) {
111				printf("[013] Rejecting thread %d: %s/%s\n",
112					mysqli_thread_id($mysqli),
113					mysqli_errno($mysqli),
114					mysqli_error($mysqli));
115			}
116			$processed += count($reject);
117		}
118
119		foreach ($links as $mysqli) {
120			if (is_object($res = mysqli_reap_async_query($mysqli))) {
121				printf("Fetching from thread %d...\n", mysqli_thread_id($mysqli));
122				var_dump(mysqli_fetch_assoc($res));
123			} else if (mysqli_errno($mysqli) > 0) {
124				printf("[014] %d/%s\n", mysqli_errno($mysqli), mysqli_error($mysqli));
125			}
126			$processed++;
127		}
128
129	} while ($processed < 2);
130
131
132	// Killing connection - 3
133
134	$link = get_connection();
135	$thread_id = mysqli_thread_id($link);
136	mysqli_kill(get_connection(), $thread_id);
137	// Sleep 0.1s  to ensure the KILL gets recognized
138	usleep(100000);
139	if (false !== ($tmp = mysqli_query($link, "SELECT 1 AS 'processed before killed'", MYSQLI_ASYNC |  MYSQLI_USE_RESULT)))
140		printf("[015] Expecting boolean/false got %s/%s\n", gettype($tmp), var_export($tmp, true));
141
142	$links = array($link);
143	$errors = array($link);
144	$reject = array($link);
145
146	if (0 !== ($tmp = (mysqli_poll($links, $errors, $reject, 0, 10000))))
147		printf("[016] Expecting int/0 got %s/%s\n", gettype($tmp), var_export($tmp, true));
148
149	if (!is_array($links) || empty($links))
150		printf("[017] Expecting non-empty array got %s/%s\n", gettype($links), var_export($links, true));
151	else
152		foreach ($links as $link) {
153			if (is_object($res = mysqli_reap_async_query($link))) {
154				// No, you cannot fetch the result
155				var_dump(mysqli_fetch_assoc($res));
156				mysqli_free_result($res);
157			} else if ($link->errno > 0) {
158				// But you are supposed to handle the error the way its shown here!
159				printf("[018] Error: %d/%s\n", $link->errno, $link->error);
160			}
161		}
162
163	// None of these will indicate an error, check errno on the list of returned connections!
164	if (!is_array($errors) || !empty($errors))
165		printf("[019] Expecting non-empty array got %s/%s\n", gettype($errors), var_export($errors, true));
166
167	if (!is_array($reject) || !empty($reject))
168		printf("[020] Expecting empty array got %s/%s\n", gettype($reject), var_export($reject, true));
169
170
171	mysqli_close($link);
172	print "done!";
173?>
174--XFAIL--
175To be fixed later. Minor issue about fetching error message from killed line
176--EXPECTF--
177array(1) {
178  [%u|b%"processed before killed"]=>
179  %unicode|string%(1) "1"
180}
181Fetching from thread %d...
182array(1) {
183  [1]=>
184  %unicode|string%(1) "1"
185}
186
187Warning: mysqli_reap_async_query(): Premature end of data (mysqlnd_wireprotocol.c:%d) in %s on line %d
188
189Warning: mysqli_reap_async_query(): RSET_HEADER %s
190
191Warning: mysqli_reap_async_query(): Error reading result set's header in %s on line %d
192
193Warning: Error while sending QUERY packet. %s
194
195Warning: mysqli_reap_async_query(): %s
196
197Warning: mysqli_reap_async_query(): Error reading result set's header in %s on line %d
198[018] Error: %d/%s
199done!