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