1--TEST--
2mysqli_poll() & INSERT SELECT
3--EXTENSIONS--
4mysqli
5--SKIPIF--
6<?php
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('table.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
26    // Note: some queries will fail! They are supposed to fail.
27    $queries = array(
28            'CREATE TABLE IF NOT EXISTS bogus(id INT)',
29            'SET @a = 1',
30            'SELECT * FROM test ORDER BY id ASC LIMIT 2',
31            "INSERT INTO test(id, label) VALUES (100, 'z')",
32            'SELECT * FROM test ORDER BY id ASC LIMIT 2',
33            'SELECT',
34            'UPDATE test SET id = 101 WHERE id > 3',
35            'UPDATE_FIX test SET id = 101 WHERE id > 3',
36            'DROP TABLE IF EXISTS bogus',
37            'DELETE FROM test WHERE id = @a',
38            'DELETE FROM test WHERE id = 1',
39    );
40
41    $link = get_connection();
42    $have_proc = false;
43    mysqli_real_query($link, "DROP PROCEDURE IF EXISTS p");
44    if (mysqli_real_query($link, 'CREATE PROCEDURE p(IN ver_in VARCHAR(25), OUT ver_out VARCHAR(25)) BEGIN SELECT ver_in INTO ver_out; END;')) {
45            $have_proc = true;
46            $queries[] = "CALL p('myversion', @version)";
47    }
48    mysqli_close($link);
49
50    $links = array();
51    for ($i = 0; $i < count($queries); $i++) {
52
53        $link = get_connection();
54
55        if (true !== ($tmp = mysqli_query($link, $queries[$i], MYSQLI_ASYNC |  MYSQLI_USE_RESULT)))
56            printf("[002] Expecting true got %s/%s\n", gettype($tmp), var_export($tmp, true));
57
58        // WARNING KLUDGE NOTE
59        // Add a tiny delay to ensure that queries get executed in a certain order
60        // If your MySQL server is very slow the test may randomly fail!
61        usleep(20000);
62
63        $links[mysqli_thread_id($link)] = array(
64            'query' => $queries[$i],
65            'link' => $link,
66            'processed' => false,
67        );
68    }
69
70    $saved_errors = array();
71    do {
72        $poll_links = $poll_errors = $poll_reject = array();
73        foreach ($links as $thread_id => $link) {
74            if (!$link['processed']) {
75                $poll_links[] = $link['link'];
76                $poll_errors[] = $link['link'];
77                $poll_reject[] = $link['link'];
78            }
79        }
80        if (0 == count($poll_links))
81            break;
82
83        if (0 === ($num_ready = mysqli_poll($poll_links, $poll_errors, $poll_reject, 0, 200000)))
84            continue;
85
86        if (!empty($poll_errors)) {
87            die(var_dump($poll_errors));
88        }
89
90        if (FALSE === $num_ready) {
91            die("Some mysqli indicated error");
92        }
93
94        foreach ($poll_links as $link) {
95            $thread_id = mysqli_thread_id($link);
96            $links[$thread_id]['processed'] = true;
97
98            if (is_object($res = mysqli_reap_async_query($link))) {
99                // result set object
100                while ($row = mysqli_fetch_assoc($res)) {
101                    // eat up all results
102                    ;
103                }
104                mysqli_free_result($res);
105            } else {
106                // either there is no result (no SELECT) or there is an error
107                if (mysqli_errno($link) > 0) {
108                    $saved_errors[$thread_id] = mysqli_errno($link);
109                }
110            }
111        }
112
113    } while (true);
114
115    // Checking if all lines are still usable
116    foreach ($links as $thread_id => $link) {
117        if (isset($saved_errors[$thread_id])) {
118            printf("[003] '%s' caused %d\n",
119                $links[$thread_id]['query'], $saved_errors[$thread_id]);
120            if ($saved_errors[$thread_id] != mysqli_errno($link['link'])) {
121                printf("[004] Error state not saved for query '%s', %d != %d\n", $link['query'],
122                    $saved_errors[$thread_id], mysqli_errno($link['link']));
123            }
124        }
125
126        if (!$res = mysqli_query($link['link'], 'SELECT * FROM test WHERE id = 100'))
127            printf("[005] Expecting true got %s/%s\n", gettype($tmp), var_export($tmp, true));
128        if (!$row = mysqli_fetch_row($res))
129            printf("[006] Expecting true got %s/%s\n", gettype($tmp), var_export($tmp, true));
130
131        mysqli_free_result($res);
132    }
133
134    if ($res = mysqli_query($link['link'], "SELECT * FROM test WHERE id = 100")) {
135        $row = mysqli_fetch_assoc($res);
136        var_dump($row);
137        mysqli_free_result($res);
138    }
139
140    if ($have_proc && ($res = mysqli_query($link['link'], "SELECT @version as _version"))) {
141        $row = mysqli_fetch_assoc($res);
142        if ($row['_version'] != 'myversion') {
143            printf("[007] Check procedures\n");
144        }
145        mysqli_free_result($res);
146    }
147
148    foreach ($links as $link)
149        mysqli_close($link['link']);
150
151    $link = get_connection();
152    if (!mysqli_query($link, 'SELECT 1', MYSQLI_ASYNC))
153        printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
154
155    if (!mysqli_query($link, 'SELECT 1', MYSQLI_ASYNC))
156        printf("[009] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
157
158    mysqli_close($link);
159
160    print "done!";
161?>
162--CLEAN--
163<?php
164require_once("connect.inc");
165if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
166   printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
167
168if (!mysqli_query($link, "DROP TABLE IF EXISTS test"))
169    printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
170
171if (!mysqli_query($link, "DROP TABLE IF EXISTS bogus"))
172    printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
173
174mysqli_query($link, "DROP PROCEDURE IF EXISTS p");
175
176mysqli_close($link);
177?>
178--EXPECTF--
179[003] 'SELECT' caused 1064
180[003] 'UPDATE test SET id = 101 WHERE id > 3' caused 1062
181[003] 'UPDATE_FIX test SET id = 101 WHERE id > 3' caused 1064
182array(2) {
183  ["id"]=>
184  string(3) "100"
185  ["label"]=>
186  string(1) "z"
187}
188[009] [2014] %s
189done!
190