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