Skip to content

Commit 7cbcf7d

Browse files
committed
Fix GH-16314 "Pdo\Mysql object is uninitialized" when opening a persistent connection
1 parent c80949e commit 7cbcf7d

File tree

5 files changed

+151
-7
lines changed

5 files changed

+151
-7
lines changed

ext/pdo/pdo_dbh.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,16 @@ PDO_API void php_pdo_internal_construct_driver(INTERNAL_FUNCTION_PARAMETERS, zen
431431

432432
if (pdbh) {
433433
efree(dbh);
434+
435+
pdo_dbh_object_t *pdo_obj;
436+
if (new_zval_object) {
437+
pdo_obj = Z_PDO_OBJECT_P(new_zval_object);
438+
} else {
439+
pdo_obj = php_pdo_dbh_fetch_object(object);
440+
}
441+
434442
/* switch over to the persistent one */
435-
php_pdo_dbh_fetch_object(object)->inner = pdbh;
443+
pdo_obj->inner = pdbh;
436444
pdbh->refcount++;
437445
dbh = pdbh;
438446
}

ext/pdo/tests/pdo_test.inc

+8-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ if (getenv('PDOTEST_DSN') === false) {
1818
class PDOTest {
1919
// create an instance of the PDO driver, based on
2020
// the current environment
21-
static function factory($classname = PDO::class) {
21+
static function factory($classname = PDO::class, bool $useConnectMethod = false) {
2222
$dsn = getenv('PDOTEST_DSN');
2323
$user = getenv('PDOTEST_USER');
2424
$pass = getenv('PDOTEST_PASS');
@@ -32,7 +32,11 @@ class PDOTest {
3232
if ($user === false) $user = NULL;
3333
if ($pass === false) $pass = NULL;
3434

35-
$db = new $classname($dsn, $user, $pass, $attr);
35+
if ($useConnectMethod) {
36+
$db = $classname::connect($dsn, $user, $pass, $attr);
37+
} else {
38+
$db = new $classname($dsn, $user, $pass, $attr);
39+
}
3640

3741
if (!$db) {
3842
die("Could not create PDO object (DSN=$dsn, user=$user)\n");
@@ -54,12 +58,12 @@ class PDOTest {
5458
}
5559
}
5660

57-
static function test_factory($file, $classname = PDO::class) {
61+
static function test_factory($file, $classname = PDO::class, bool $useConnectMethod = false) {
5862
$config = self::get_config($file);
5963
foreach ($config['ENV'] as $k => $v) {
6064
putenv("$k=$v");
6165
}
62-
return self::factory($classname);
66+
return self::factory($classname, $useConnectMethod);
6367
}
6468

6569
static function get_config($file) {

ext/pdo_mysql/tests/gh16314.phpt

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
GH-16314 "Pdo\Mysql object is uninitialized" when opening a persistent connection
3+
--EXTENSIONS--
4+
pdo_mysql
5+
--SKIPIF--
6+
<?php
7+
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
8+
MySQLPDOTest::skip();
9+
?>
10+
--FILE--
11+
<?php
12+
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
13+
14+
$pdo = MySQLPDOTest::factory(Pdo\Mysql::class, null, [PDO::ATTR_PERSISTENT => true], false);
15+
var_dump($pdo->query('SELECT 1;')->fetchAll());
16+
17+
$pdo = MySQLPDOTest::factory(Pdo\Mysql::class, null, [PDO::ATTR_PERSISTENT => true], true);
18+
var_dump($pdo->query('SELECT 1;')->fetchAll());
19+
20+
$pdo = MySQLPDOTest::factory(Pdo::class, null, [PDO::ATTR_PERSISTENT => true], false);
21+
var_dump($pdo->query('SELECT 1;')->fetchAll());
22+
23+
$pdo = MySQLPDOTest::factory(Pdo::class, null, [PDO::ATTR_PERSISTENT => true], true);
24+
var_dump($pdo->query('SELECT 1;')->fetchAll());
25+
?>
26+
--EXPECT--
27+
array(1) {
28+
[0]=>
29+
array(2) {
30+
[1]=>
31+
int(1)
32+
[0]=>
33+
int(1)
34+
}
35+
}
36+
array(1) {
37+
[0]=>
38+
array(2) {
39+
[1]=>
40+
int(1)
41+
[0]=>
42+
int(1)
43+
}
44+
}
45+
array(1) {
46+
[0]=>
47+
array(2) {
48+
[1]=>
49+
int(1)
50+
[0]=>
51+
int(1)
52+
}
53+
}
54+
array(1) {
55+
[0]=>
56+
array(2) {
57+
[1]=>
58+
int(1)
59+
[0]=>
60+
int(1)
61+
}
62+
}

ext/pdo_mysql/tests/inc/mysql_pdo_test.inc

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ foreach ($env as $k => $v) {
88

99
class MySQLPDOTest extends PDOTest {
1010

11-
static function factory($classname = PDO::class, $mydsn = null, $myAttr = null) {
11+
static function factory($classname = PDO::class, $mydsn = null, $myAttr = null, bool $useConnectMethod = false) {
1212
$dsn = self::getDSN($mydsn);
1313
$user = PDO_MYSQL_TEST_USER;
1414
$pass = PDO_MYSQL_TEST_PASS;
@@ -20,7 +20,12 @@ class MySQLPDOTest extends PDOTest {
2020
$attr = is_string($attr) && strlen($attr) ? unserialize($attr) : null;
2121
}
2222

23-
$db = new $classname($dsn, $user, $pass, $attr);
23+
if ($useConnectMethod) {
24+
$db = $classname::connect($dsn, $user, $pass, $attr);
25+
} else {
26+
$db = new $classname($dsn, $user, $pass, $attr);
27+
}
28+
2429
if (!$db) {
2530
die("Could not create PDO object (DSN=$dsn, user=$user)\n");
2631
}

ext/pdo_pgsql/tests/gh16314.phpt

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
GH-16314 "Pdo\Pgsql object is uninitialized" when opening a persistent connection
3+
--EXTENSIONS--
4+
pdo_pgsql
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
9+
PDOTest::skip();
10+
?>
11+
--FILE--
12+
<?php
13+
putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true]));
14+
15+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
16+
17+
$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo\Pgsql::class, false);
18+
var_dump($pdo->query('SELECT 1;')->fetchAll());
19+
20+
$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo\Pgsql::class, true);
21+
var_dump($pdo->query('SELECT 1;')->fetchAll());
22+
23+
$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo::class, false);
24+
var_dump($pdo->query('SELECT 1;')->fetchAll());
25+
26+
$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo::class, true);
27+
var_dump($pdo->query('SELECT 1;')->fetchAll());
28+
?>
29+
--EXPECT--
30+
array(1) {
31+
[0]=>
32+
array(2) {
33+
["?column?"]=>
34+
string(1) "1"
35+
[0]=>
36+
string(1) "1"
37+
}
38+
}
39+
array(1) {
40+
[0]=>
41+
array(2) {
42+
["?column?"]=>
43+
string(1) "1"
44+
[0]=>
45+
string(1) "1"
46+
}
47+
}
48+
array(1) {
49+
[0]=>
50+
array(2) {
51+
["?column?"]=>
52+
string(1) "1"
53+
[0]=>
54+
string(1) "1"
55+
}
56+
}
57+
array(1) {
58+
[0]=>
59+
array(2) {
60+
["?column?"]=>
61+
string(1) "1"
62+
[0]=>
63+
string(1) "1"
64+
}
65+
}

0 commit comments

Comments
 (0)