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