mysqli_poll_kill.phpt 7.3 KB

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