1--TEST--
2Persistent connections and mysqli.max_links
3--EXTENSIONS--
4mysqli
5--SKIPIF--
6<?php
7    require_once 'skipifconnectfailure.inc';
8    require_once 'table.inc';
9
10    mysqli_query($link, 'DROP USER pcontest');
11    mysqli_query($link, 'DROP USER pcontest@localhost');
12
13    if (!mysqli_query($link, 'CREATE USER pcontest@"%" IDENTIFIED BY "pcontest"') ||
14        !mysqli_query($link, 'CREATE USER pcontest@localhost IDENTIFIED BY "pcontest"')) {
15        printf("skip Cannot create second DB user [%d] %s", mysqli_errno($link), mysqli_error($link));
16        mysqli_close($link);
17        die("skip CREATE USER failed");
18    }
19
20    // we might be able to specify the host using CURRENT_USER(), but...
21    if (!mysqli_query($link, sprintf("GRANT SELECT ON TABLE %s.test TO pcontest@'%%'", $db)) ||
22        !mysqli_query($link, sprintf("GRANT SELECT ON TABLE %s.test TO pcontest@'localhost'", $db))) {
23        printf("skip Cannot GRANT SELECT to second DB user [%d] %s", mysqli_errno($link), mysqli_error($link));
24        mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest');
25        mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest@localhost');
26        mysqli_query($link, 'DROP USER pcontest@localhost');
27        mysqli_query($link, 'DROP USER pcontest');
28        mysqli_close($link);
29        die("skip GRANT failed");
30    }
31
32    if (!@my_mysqli_connect($host, 'pcontest', 'pcontest', $db, $port, $socket)) {
33        mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest');
34        mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest@localhost');
35        mysqli_query($link, 'DROP USER pcontest@localhost');
36        mysqli_query($link, 'DROP USER pcontest');
37        mysqli_close($link);
38        die("skip CONNECT using new user failed");
39    }
40    mysqli_close($link);
41?>
42--INI--
43mysqli.allow_persistent=1
44mysqli.max_persistent=2
45mysqli.rollback_on_cached_plink=1
46--FILE--
47<?php
48    require_once 'connect.inc';
49    require_once 'table.inc';
50
51
52    if (!mysqli_query($link, 'DROP USER pcontest') ||
53        !mysqli_query($link, 'DROP USER pcontest@localhost') ||
54        !mysqli_query($link, 'CREATE USER pcontest@"%" IDENTIFIED BY "pcontest"') ||
55        !mysqli_query($link, 'CREATE USER pcontest@localhost IDENTIFIED BY "pcontest"') ||
56        !mysqli_query($link, sprintf("GRANT SELECT ON TABLE %s.test TO pcontest@'%%'", $db)) ||
57        !mysqli_query($link, sprintf("GRANT SELECT ON TABLE %s.test TO pcontest@'localhost'", $db))) {
58        printf("[000] Init failed, [%d] %s\n",
59            mysqli_errno($link), mysqli_error($link));
60    }
61
62    try {
63        mysqli_get_links_stats(1);
64    } catch (ArgumentCountError $exception) {
65        echo $exception->getMessage() . "\n";
66    }
67
68    echo "Before pconnect:";
69    var_dump(mysqli_get_links_stats());
70
71    if (!$plink = my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket))
72        printf("[001] Cannot connect using the second DB user created during SKIPIF, [%d] %s\n",
73            mysqli_connect_errno(), mysqli_connect_error());
74
75    echo "After pconnect:";
76    var_dump(mysqli_get_links_stats());
77
78    ob_start();
79    phpinfo();
80    $phpinfo = strip_tags(ob_get_contents());
81    ob_end_clean();
82
83    $phpinfo = substr($phpinfo, strpos($phpinfo, 'MysqlI Support => enabled'), 500);
84    if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
85        printf("[002] Cannot get # active persistent links from phpinfo()\n");
86    $num_plinks = $matches[1];
87
88    if (!$res = mysqli_query($plink, 'SELECT id, label FROM test WHERE id = 1'))
89        printf("[003] Cannot run query on persistent connection of second DB user, [%d] %s\n",
90            mysqli_errno($plink), mysqli_error($plink));
91
92    if (!$row = mysqli_fetch_assoc($res))
93        printf("[004] Cannot run fetch result, [%d] %s\n",
94            mysqli_errno($plink), mysqli_error($plink));
95    mysqli_free_result($res);
96    var_dump($row);
97
98    // change the password for the second DB user and kill the persistent connection
99    if ((!mysqli_query($link, 'SET PASSWORD FOR pcontest = "newpass"') &&
100            !mysqli_query($link, 'SET PASSWORD FOR pcontest = PASSWORD("newpass")'))||
101            !mysqli_query($link, 'FLUSH PRIVILEGES'))
102        printf("[005] Cannot change PW of second DB user, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
103
104        // change the password for the second DB user and kill the persistent connection
105    if ((!mysqli_query($link, 'SET PASSWORD FOR pcontest@localhost = "newpass"') &&
106        !mysqli_query($link, 'SET PASSWORD FOR pcontest@localhost = PASSWORD("newpass")')) ||
107            !mysqli_query($link, 'FLUSH PRIVILEGES'))
108        printf("[006] Cannot change PW of second DB user, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
109
110    // persistent connections cannot be closed but only be killed
111    $pthread_id = mysqli_thread_id($plink);
112    if (!mysqli_query($link, sprintf('KILL %d', $pthread_id)))
113        printf("[007] Cannot KILL persistent connection of second DB user, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
114    // give the server a second to really kill the thread
115    sleep(1);
116
117    if (!$res = mysqli_query($link, "SHOW FULL PROCESSLIST"))
118        printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
119
120    $running_threads = array();
121    while ($row = mysqli_fetch_assoc($res))
122        $running_threads[$row['Id']] = $row;
123    mysqli_free_result($res);
124
125    if (isset($running_threads[$pthread_id]))
126        printf("[009] Persistent connection has not been killed\n");
127
128    echo "Before second pconnect:";
129    var_dump(mysqli_get_links_stats());
130
131    // this fails and we have 0 (<= $num_plinks) connections
132    // Do not remove the variable assignment as it is important that we have 2 active connections
133    if ($plink = @my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket))
134        printf("[010] Can connect using the old password, [%d] %s\n",
135            mysqli_connect_errno(), mysqli_connect_error());
136
137    echo "After second pconnect:";
138    var_dump(mysqli_get_links_stats());
139
140    ob_start();
141    phpinfo();
142    $phpinfo = strip_tags(ob_get_contents());
143    ob_end_clean();
144    $phpinfo = substr($phpinfo, stripos($phpinfo, 'MysqlI Support => enabled'), 500);
145    if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
146        printf("[010] Cannot get # of active persistent links from phpinfo()\n");
147
148    var_dump(mysqli_get_links_stats());
149
150    $num_plinks_kill = $matches[1];
151    $sstats = mysqli_get_links_stats();
152    if ($sstats['active_plinks'] != $num_plinks_kill) {
153        printf("[010.2] Num of active plinks differ %s %s\n", $sstats['active_plinks'], $num_plinks_kill);
154    }
155    if ($num_plinks_kill > $num_plinks)
156        printf("[011] Expecting Active Persistent Links < %d, got %d\n", $num_plinks, $num_plinks_kill);
157
158    if (!$plink = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket))
159        printf("[012] Cannot connect using the new password, [%d] %s\n",
160            mysqli_connect_errno(), mysqli_connect_error());
161
162    if (!$res = mysqli_query($plink, 'SELECT id, label FROM test WHERE id = 1'))
163        printf("[013] Cannot run query on persistent connection of second DB user, [%d] %s\n",
164            mysqli_errno($plink), mysqli_error($plink));
165
166    if (!$row = mysqli_fetch_assoc($res))
167        printf("[014] Cannot run fetch result, [%d] %s\n",
168            mysqli_errno($plink), mysqli_error($plink));
169    mysqli_free_result($res);
170    var_dump($row);
171
172    // Do not remove the variable assignment as it is important that we have 2 active connections
173    if ($plink2 = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket)) {
174        printf("[015] Can open more persistent connections than allowed, [%d] %s\n",
175            mysqli_connect_errno(), mysqli_connect_error());
176        var_dump(mysqli_get_links_stats());
177    }
178
179    ob_start();
180    phpinfo();
181    $phpinfo = strip_tags(ob_get_contents());
182    ob_end_clean();
183    $phpinfo = substr($phpinfo, stripos($phpinfo, 'MysqlI Support => enabled'), 500);
184    if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
185        printf("[016] Cannot get # of active persistent links from phpinfo()\n");
186
187    $num_plinks = $matches[1];
188    if ($num_plinks > (int)ini_get('mysqli.max_persistent'))
189        printf("[017] mysqli.max_persistent=%d allows %d open connections!\n", ini_get('mysqli.max_persistent'),$num_plinks);
190
191    mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest');
192    mysqli_query($link, 'DROP USER pcontest');
193    mysqli_close($link);
194    print "done!";
195?>
196--CLEAN--
197<?php
198require_once 'connect.inc';
199if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
200   printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
201
202if (!mysqli_query($link, "DROP TABLE IF EXISTS test"))
203	printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
204
205mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest');
206mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest@localhost');
207mysqli_query($link, 'DROP USER pcontest@localhost');
208mysqli_query($link, 'DROP USER pcontest');
209
210mysqli_close($link);
211?>
212--EXPECT--
213mysqli_get_links_stats() expects exactly 0 arguments, 1 given
214Before pconnect:array(3) {
215  ["total"]=>
216  int(1)
217  ["active_plinks"]=>
218  int(0)
219  ["cached_plinks"]=>
220  int(0)
221}
222After pconnect:array(3) {
223  ["total"]=>
224  int(2)
225  ["active_plinks"]=>
226  int(1)
227  ["cached_plinks"]=>
228  int(0)
229}
230array(2) {
231  ["id"]=>
232  string(1) "1"
233  ["label"]=>
234  string(1) "a"
235}
236Before second pconnect:array(3) {
237  ["total"]=>
238  int(2)
239  ["active_plinks"]=>
240  int(1)
241  ["cached_plinks"]=>
242  int(0)
243}
244After second pconnect:array(3) {
245  ["total"]=>
246  int(1)
247  ["active_plinks"]=>
248  int(0)
249  ["cached_plinks"]=>
250  int(0)
251}
252array(3) {
253  ["total"]=>
254  int(1)
255  ["active_plinks"]=>
256  int(0)
257  ["cached_plinks"]=>
258  int(0)
259}
260array(2) {
261  ["id"]=>
262  string(1) "1"
263  ["label"]=>
264  string(1) "a"
265}
266[015] Can open more persistent connections than allowed, [0]
267array(3) {
268  ["total"]=>
269  int(3)
270  ["active_plinks"]=>
271  int(2)
272  ["cached_plinks"]=>
273  int(0)
274}
275done!
276