xref: /PHP-7.4/ext/mysqli/tests/mysqli_fork.phpt (revision e3e67b72)
1--TEST--
2Forking a child and using the same connection.
3--SKIPIF--
4<?php
5require_once('skipif.inc');
6require_once('skipifemb.inc');
7require_once('skipifconnectfailure.inc');
8
9if (!function_exists('pcntl_fork'))
10    die("skip Process Control Functions not available");
11
12if (!function_exists('posix_getpid'))
13    die("skip POSIX functions not available");
14
15require_once('connect.inc');
16if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
17    die(sprintf("skip Cannot connect, [%d] %s", mysqli_connect_errno(), mysqli_connect_error()));
18
19if (!have_innodb($link))
20    die(sprintf("skip Needs InnoDB support, [%d] %s", $link->errno, $link->error));
21?>
22--FILE--
23<?php
24    require_once("table.inc");
25
26    $res = mysqli_query($link, "SELECT 'dumped by the parent' AS message");
27    $pid = pcntl_fork();
28    switch ($pid) {
29        case -1:
30            printf("[001] Cannot fork child");
31            break;
32
33        case 0:
34            /* child */
35            exit(0);
36            break;
37
38        default:
39            /* parent */
40            $status = null;
41            $wait_id = pcntl_waitpid($pid, $status);
42            if (pcntl_wifexited($status) && (0 != ($tmp = pcntl_wexitstatus($status)))) {
43                printf("Exit code: %s\n", (pcntl_wifexited($status)) ? pcntl_wexitstatus($status) : 'n/a');
44                printf("Signal: %s\n", (pcntl_wifsignaled($status)) ? pcntl_wtermsig($status) : 'n/a');
45                printf("Stopped: %d\n", (pcntl_wifstopped($status)) ? pcntl_wstopsig($status) : 'n/a');
46            }
47            var_dump(mysqli_fetch_assoc($res));
48            mysqli_free_result($res);
49            break;
50    }
51
52    if (@mysqli_query($link, "SELECT id FROM test WHERE id = 1"))
53        printf("[003] Expecting error and closed connection, child exit should have closed connection\n");
54    else if ((($errno = mysqli_errno($link)) == 0) || ('' == ($error = mysqli_error($link))))
55        printf("[004] Expecting error string and error code from MySQL, got errno = %s/%s, error = %s/%s\n",
56            gettype($errno), $errno, gettype($error), $error);
57
58    mysqli_close($link);
59    if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
60        printf("[005] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
61            $host, $user, $db, $port, $socket);
62
63    /* non trivial tests require a message list for parent-child communication */
64    if (!mysqli_query($link, "DROP TABLE IF EXISTS messages"))
65        printf("[006] [%d] %s\n", mysqli_error($link), mysqli_errno($link));
66
67    if (!mysqli_query($link, "CREATE TABLE messages(
68        msg_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
69        msg_time TIMESTAMP,
70        pid INT NOT NULL,
71        sender ENUM('child', 'parent') NOT NULL,
72        msg TEXT) ENGINE = InnoDB"))
73        printf("[007] [%d] %s\n", mysqli_error($link), mysqli_errno($link));
74
75    mysqli_autocommit($link, false);
76    if (!$res = mysqli_query($link, "SELECT id, label FROM test ORDER BY id ASC LIMIT 3", MYSQLI_USE_RESULT))
77        printf("[008] [%d] %s\n", mysqli_error($link), mysqli_errno($link));
78
79    $pid = pcntl_fork();
80
81    switch ($pid) {
82        case -1:
83            printf("[009] Cannot fork child");
84            break;
85
86        case 0:
87            /* child */
88            if (!($plink = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) || !mysqli_autocommit($plink, true))
89                exit(mysqli_errno($plink));
90
91            $sql = sprintf("INSERT INTO messages(pid, sender, msg) VALUES (%d, 'child', '%%s')", posix_getpid());
92            if (!mysqli_query($plink, sprintf($sql, 'start')))
93                exit(mysqli_errno($plink));
94
95            $parent_sql = sprintf("SELECT msg_id, msg_time, msg FROM messages WHERE pid = %d  AND sender = 'parent' ORDER BY msg_id DESC LIMIT 1", posix_getppid());
96            $msg_id = 0;
97            while ($row = mysqli_fetch_assoc($res)) {
98                /* send row to parent */
99                ob_start();
100                var_dump($row);
101                $tmp = ob_get_contents();
102                ob_end_clean();
103                if (!mysqli_query($plink, sprintf($sql, $tmp)))
104                    exit(mysqli_errno($plink));
105
106                /* let the parent reply... */
107                $start = time();
108                do {
109                    usleep(100);
110                    if (!$pres = mysqli_query($plink, $parent_sql))
111                        continue;
112                    $tmp = mysqli_fetch_assoc($pres);
113                    mysqli_free_result($pres);
114                    if (!$tmp || $tmp['msg_id'] == $msg_id)
115                        /* no new message */
116                        continue;
117                    if ($tmp['msg'] == 'stop')
118                        break 2;
119                    $msg_id = $tmp['msg_id'];
120                    break;
121                } while ((time() - $start) < 5);
122
123            }
124
125            if (!mysqli_query($plink, sprintf($sql, 'stop')) || !mysqli_commit($link))
126                exit(mysqli_errno($plink));
127            exit(0);
128            break;
129
130        default:
131            /* parent */
132            if (!$plink = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
133                    printf("[010] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
134                    $host, $user, $db, $port, $socket);
135
136            $status = null;
137            $start = time();
138            $sql = sprintf("SELECT msg_id, msg_time, msg FROM messages WHERE pid = %d AND sender = 'child' ORDER BY msg_id DESC LIMIT 1", $pid);
139            $parent_sql = sprintf("INSERT INTO messages (pid, sender, msg) VALUES (%d, 'parent', '%%s')", posix_getpid());
140            $last_msg_id = 0;
141            $num_rows = 0;
142            do {
143                $wait_id = pcntl_waitpid($pid, $status, WNOHANG);
144                if ($pres = mysqli_query($plink, $sql)) {
145                    $row = mysqli_fetch_assoc($pres);
146                    if ($row && $row['msg_id'] != $last_msg_id) {
147                        $last_msg_id = $row['msg_id'];
148                        switch ($row['msg']) {
149                            case 'start':
150                                break;
151                            case 'stop':
152                                break 2;
153                            default:
154                                /* client has started fetching rows */
155                                $client_row = $row['msg'];
156
157                                $num_rows++;
158                                if ($num_rows > 3) {
159                                    printf("[011] Child has fetched more than three rows!\n");
160                                    var_dump($client_row);
161                                    if (!mysqli_query($plink, sprintf($parent_sql, 'stop'))) {
162                                        printf("[012] Parent cannot inform child\n", mysqli_errno($plink), mysqli_error($plink));
163                                    }
164                                    break 2;
165                                }
166
167                                if (!$parent_row = mysqli_fetch_assoc($res)) {
168                                    printf("[013] Parent cannot fetch row %d\n", $num_rows, mysqli_errno($link), mysqli_error($link));
169                                    if (!mysqli_query($plink, sprintf($parent_sql, 'stop'))) {
170                                        printf("[014] Parent cannot inform child\n", mysqli_errno($plink), mysqli_error($plink));
171                                    }
172                                    break 2;
173                                }
174
175                                ob_start();
176                                var_dump($parent_row);
177                                $parent_row = ob_get_contents();
178                                ob_end_clean();
179
180                                if ($parent_row != $client_row) {
181                                    printf("[015] Child indicates different results than parent.\n");
182                                    var_dump($client_row);
183                                    var_dump($parent_row);
184                                    if (!mysqli_query($plink, sprintf($parent_sql, 'stop'))) {
185                                        printf("[016] Parent cannot inform child\n", mysqli_errno($plink), mysqli_error($plink));
186                                    }
187                                    break 2;
188                                }
189
190                                if (!mysqli_query($plink, sprintf($parent_sql, 'continue'))) {
191                                    printf("[017] Parent cannot inform child to continue.\n", mysqli_errno($plink), mysqli_error($plink));
192                                }
193                                break;
194                        }
195                    }
196                    mysqli_free_result($pres);
197                }
198                usleep(100);
199            } while (((time() - $start) < 5) && ($num_rows < 3));
200            mysqli_close($plink);
201            $wait_id = pcntl_waitpid($pid, $status);
202            if (pcntl_wifexited($status) && (0 != ($tmp = pcntl_wexitstatus($status)))) {
203                printf("Exit code: %s\n", (pcntl_wifexited($status)) ? pcntl_wexitstatus($status) : 'n/a');
204                printf("Signal: %s\n", (pcntl_wifsignaled($status)) ? pcntl_wtermsig($status) : 'n/a');
205                printf("Stopped: %d\n", (pcntl_wifstopped($status)) ? pcntl_wstopsig($status) : 'n/a');
206            }
207            break;
208    }
209    mysqli_free_result($res);
210    mysqli_close($link);
211
212    if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
213        printf("[018] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
214            $host, $user, $db, $port, $socket);
215
216    if (!$res = mysqli_query($link, "SELECT sender, msg FROM messages ORDER BY msg_id ASC"))
217        printf("[019] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
218
219    while ($row = mysqli_fetch_assoc($res))
220        printf("%10s %s\n", $row['sender'], substr($row['msg'], 0, 5));
221    mysqli_free_result($res);
222
223    print "done!";
224?>
225--CLEAN--
226<?php
227require_once("connect.inc");
228if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
229   printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
230
231if (!mysqli_query($link, "DROP TABLE IF EXISTS test"))
232    printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
233
234if (!mysqli_query($link, "DROP TABLE IF EXISTS messages"))
235    printf("[c003] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
236
237mysqli_close($link);
238?>
239--EXPECT--
240array(1) {
241  ["message"]=>
242  string(20) "dumped by the parent"
243}
244     child start
245     child array
246    parent conti
247     child array
248    parent conti
249     child array
250    parent conti
251     child stop
252done!
253