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!