1--TEST--
2Persistent connections and mysqli.max_links
3--SKIPIF--
4<?php
5	require_once('skipif.inc');
6	require_once('skipifemb.inc');
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 (!($link_pcontest = @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($plink), mysqli_error($plink));
60	}
61
62	var_dump(mysqli_get_links_stats(1));
63
64	echo "Before pconnect:";
65	var_dump(mysqli_get_links_stats());
66
67	if (!$plink = my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket))
68		printf("[001] Cannot connect using the second DB user created during SKIPIF, [%d] %s\n",
69			mysqli_connect_errno(), mysqli_connect_error());
70
71	echo "After pconnect:";
72	var_dump(mysqli_get_links_stats());
73
74	ob_start();
75	phpinfo();
76	$phpinfo = strip_tags(ob_get_contents());
77	ob_end_clean();
78
79	$phpinfo = substr($phpinfo, strpos($phpinfo, 'MysqlI Support => enabled'), 500);
80	if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
81		printf("[002] Cannot get # active persistent links from phpinfo()\n");
82	$num_plinks = $matches[1];
83
84	if (!$res = mysqli_query($plink, 'SELECT id, label FROM test WHERE id = 1'))
85		printf("[003] Cannot run query on persistent connection of second DB user, [%d] %s\n",
86			mysqli_errno($plink), mysqli_error($plink));
87
88	if (!$row = mysqli_fetch_assoc($res))
89		printf("[004] Cannot run fetch result, [%d] %s\n",
90			mysqli_errno($plink), mysqli_error($plink));
91	mysqli_free_result($res);
92	var_dump($row);
93
94	// change the password for the second DB user and kill the persistent connection
95	if (!mysqli_query($link, 'SET PASSWORD FOR pcontest = PASSWORD("newpass")') ||
96			!mysqli_query($link, 'FLUSH PRIVILEGES'))
97		printf("[005] Cannot change PW of second DB user, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
98
99        // change the password for the second DB user and kill the persistent connection
100	if (!mysqli_query($link, 'SET PASSWORD FOR pcontest@localhost = PASSWORD("newpass")') ||
101			!mysqli_query($link, 'FLUSH PRIVILEGES'))
102		printf("[006] Cannot change PW of second DB user, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
103
104	// persistent connections cannot be closed but only be killed
105	$pthread_id = mysqli_thread_id($plink);
106	if (!mysqli_query($link, sprintf('KILL %d', $pthread_id)))
107		printf("[007] Cannot KILL persistent connection of second DB user, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
108	// give the server a second to really kill the thread
109	sleep(1);
110
111	if (!$res = mysqli_query($link, "SHOW FULL PROCESSLIST"))
112		printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
113
114	$running_threads = array();
115	while ($row = mysqli_fetch_assoc($res))
116		$running_threads[$row['Id']] = $row;
117	mysqli_free_result($res);
118
119	if (isset($running_threads[$pthread_id]))
120		printf("[009] Persistent connection has not been killed\n");
121
122	echo "Before second pconnect:";
123	var_dump(mysqli_get_links_stats());
124
125	// this fails and we have 0 (<= $num_plinks) connections
126	if ($plink = @my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket))
127		printf("[010] Can connect using the old password, [%d] %s\n",
128			mysqli_connect_errno($link), mysqli_connect_error($link));
129
130	echo "After second pconnect:";
131	var_dump(mysqli_get_links_stats());
132
133	ob_start();
134	phpinfo();
135	$phpinfo = strip_tags(ob_get_contents());
136	ob_end_clean();
137	$phpinfo = substr($phpinfo, stripos($phpinfo, 'MysqlI Support => enabled'), 500);
138	if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
139		printf("[010] Cannot get # of active persistent links from phpinfo()\n");
140
141	var_dump(mysqli_get_links_stats());
142
143	$num_plinks_kill = $matches[1];
144	$sstats = mysqli_get_links_stats();
145	if ($sstats['active_plinks'] != $num_plinks_kill) {
146		printf("[010.2] Num of active plinks differ %s %s\n", $sstats['active_plinks'], $num_plinks_kill);
147	}
148	if ($num_plinks_kill > $num_plinks)
149		printf("[011] Expecting Active Persistent Links < %d, got %d\n", $num_plinks, $num_plinks_kill);
150
151	if (!$plink = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket))
152		printf("[012] Cannot connect using the new password, [%d] %s\n",
153			mysqli_connect_errno(), mysqli_connect_error());
154
155	if (!$res = mysqli_query($plink, 'SELECT id, label FROM test WHERE id = 1'))
156		printf("[013] Cannot run query on persistent connection of second DB user, [%d] %s\n",
157			mysqli_errno($plink), mysqli_error($plink));
158
159	if (!$row = mysqli_fetch_assoc($res))
160		printf("[014] Cannot run fetch result, [%d] %s\n",
161			mysqli_errno($plink), mysqli_error($plink));
162	mysqli_free_result($res);
163	var_dump($row);
164
165	if ($plink2 = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket)) {
166		printf("[015] Can open more persistent connections than allowed, [%d] %s\n",
167			mysqli_connect_errno(), mysqli_connect_error());
168		var_dump(mysqli_get_links_stats());
169	}
170
171	ob_start();
172	phpinfo();
173	$phpinfo = strip_tags(ob_get_contents());
174	ob_end_clean();
175	$phpinfo = substr($phpinfo, stripos($phpinfo, 'MysqlI Support => enabled'), 500);
176	if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
177		printf("[016] Cannot get # of active persistent links from phpinfo()\n");
178
179	$num_plinks = $matches[1];
180	if ($num_plinks > (int)ini_get('mysqli.max_persistent'))
181		printf("[017] mysqli.max_persistent=%d allows %d open connections!\n", ini_get('mysqli.max_persistent'),$num_plinks);
182
183	mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest');
184	mysqli_query($link, 'DROP USER pcontest');
185	mysqli_close($link);
186	print "done!";
187?>
188--CLEAN--
189<?php
190require_once("connect.inc");
191if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
192   printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
193
194if (!mysqli_query($link, "DROP TABLE IF EXISTS test"))
195	printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
196
197mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest');
198mysqli_query($link, 'REVOKE ALL PRIVILEGES, GRANT OPTION FROM pcontest@localhost');
199mysqli_query($link, 'DROP USER pcontest@localhost');
200mysqli_query($link, 'DROP USER pcontest');
201
202mysqli_close($link);
203?>
204--EXPECTF--
205Warning: mysqli_get_links_stats(): no parameters expected in %s on line %d
206NULL
207Before pconnect:array(3) {
208  ["total"]=>
209  int(1)
210  ["active_plinks"]=>
211  int(0)
212  ["cached_plinks"]=>
213  int(0)
214}
215After pconnect:array(3) {
216  ["total"]=>
217  int(2)
218  ["active_plinks"]=>
219  int(1)
220  ["cached_plinks"]=>
221  int(0)
222}
223array(2) {
224  ["id"]=>
225  string(1) "1"
226  ["label"]=>
227  string(1) "a"
228}
229Before second pconnect:array(3) {
230  ["total"]=>
231  int(2)
232  ["active_plinks"]=>
233  int(1)
234  ["cached_plinks"]=>
235  int(0)
236}
237
238Warning: main(): MySQL server has gone away in %s on line %d
239
240Warning: main(): Error reading result set's header in %s line %d
241After second pconnect:array(3) {
242  ["total"]=>
243  int(1)
244  ["active_plinks"]=>
245  int(0)
246  ["cached_plinks"]=>
247  int(0)
248}
249array(3) {
250  ["total"]=>
251  int(1)
252  ["active_plinks"]=>
253  int(0)
254  ["cached_plinks"]=>
255  int(0)
256}
257array(2) {
258  ["id"]=>
259  string(1) "1"
260  ["label"]=>
261  string(1) "a"
262}
263[015] Can open more persistent connections than allowed, [0]
264array(3) {
265  ["total"]=>
266  int(3)
267  ["active_plinks"]=>
268  int(2)
269  ["cached_plinks"]=>
270  int(0)
271}
272done!