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 $begin = microtime(true); 94 do { 95 $links = array($link, $link); 96 $errors = array($link, $link); 97 $reject = array($link, $link); 98 $ready = mysqli_poll($links, $errors, $reject, 1); 99 100 if (!empty($errors)) { 101 foreach ($errors as $mysqli) { 102 printf("[012] Error on thread %d: %s/%s\n", 103 mysqli_thread_id($mysqli), 104 mysqli_errno($mysqli), 105 mysqli_error($mysqli)); 106 } 107 break; 108 } 109 110 if (FALSE === $ready) { 111 printf("[013] MySQLi indicates some error\n"); 112 break; 113 } 114 115 if (!empty($reject)) { 116 foreach ($reject as $mysqli) { 117 printf("[014] Rejecting thread %d: %s/%s\n", 118 mysqli_thread_id($mysqli), 119 mysqli_errno($mysqli), 120 mysqli_error($mysqli)); 121 } 122 $processed += count($reject); 123 } 124 125 foreach ($links as $mysqli) { 126 if (is_object($res = mysqli_reap_async_query($mysqli))) { 127 printf("Fetching from thread %d...\n", mysqli_thread_id($mysqli)); 128 var_dump(mysqli_fetch_assoc($res)); 129 } else if (mysqli_errno($mysqli) > 0) { 130 printf("[015] %d/%s\n", mysqli_errno($mysqli), mysqli_error($mysqli)); 131 } 132 $processed++; 133 } 134 135 if ((microtime(true) - $begin) > 5) { 136 printf("[016] Pulling the emergency break after 5s, something is wrong...\n"); 137 break; 138 } 139 140 } while ($processed < 2); 141 142 143 // Killing connection - 3 144 145 $link = get_connection(); 146 $thread_id = mysqli_thread_id($link); 147 mysqli_kill(get_connection(), $thread_id); 148 // Sleep 0.1s to ensure the KILL gets recognized 149 usleep(100000); 150 if (false !== ($tmp = mysqli_query($link, "SELECT 1 AS 'processed before killed'", MYSQLI_ASYNC | MYSQLI_USE_RESULT))) 151 printf("[017] Expecting boolean/false got %s/%s\n", gettype($tmp), var_export($tmp, true)); 152 153 $links = array($link); 154 $errors = array($link); 155 $reject = array($link); 156 157 if (0 !== ($tmp = (mysqli_poll($links, $errors, $reject, 0, 10000)))) 158 printf("[018] Expecting int/0 got %s/%s\n", gettype($tmp), var_export($tmp, true)); 159 160 if (!is_array($links) || empty($links)) 161 printf("[019] Expecting non-empty array got %s/%s\n", gettype($links), var_export($links, true)); 162 else 163 foreach ($links as $link) { 164 if (is_object($res = mysqli_reap_async_query($link))) { 165 // No, you cannot fetch the result 166 var_dump(mysqli_fetch_assoc($res)); 167 mysqli_free_result($res); 168 } else if ($link->errno > 0) { 169 // But you are supposed to handle the error the way its shown here! 170 printf("[020] Error: %d/%s\n", $link->errno, $link->error); 171 } 172 } 173 174 // None of these will indicate an error, check errno on the list of returned connections! 175 if (!is_array($errors) || !empty($errors)) 176 printf("[021] Expecting non-empty array got %s/%s\n", gettype($errors), var_export($errors, true)); 177 178 if (!is_array($reject) || !empty($reject)) 179 printf("[021] Expecting empty array got %s/%s\n", gettype($reject), var_export($reject, true)); 180 181 182 mysqli_close($link); 183 print "done!"; 184?> 185--XFAIL-- 186To be fixed later. Minor issue about fetching error message from killed line 187--EXPECTF-- 188array(1) { 189 [%u|b%"processed before killed"]=> 190 %unicode|string%(1) "1" 191} 192Fetching from thread %d... 193array(1) { 194 [1]=> 195 %unicode|string%(1) "1" 196} 197 198Warning: mysqli_reap_async_query(): Premature end of data (mysqlnd_wireprotocol.c:%d) in %s on line %d 199 200Warning: mysqli_reap_async_query(): RSET_HEADER %s 201 202Warning: mysqli_reap_async_query(): Error reading result set's header in %s on line %d 203 204Warning: Error while sending QUERY packet. %s 205 206Warning: mysqli_reap_async_query(): %s 207 208Warning: mysqli_reap_async_query(): Error reading result set's header in %s on line %d 209[018] Error: %d/%s 210done! 211