Skip to content

Commit 1b632cf

Browse files
committed
Backport patch for bug #71820
Rev b4eedd1
1 parent eb40562 commit 1b632cf

File tree

4 files changed

+225
-2
lines changed

4 files changed

+225
-2
lines changed

ext/mysqli/mysqli.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,9 +1295,13 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags
12951295
zend_fcall_info fci;
12961296
zend_fcall_info_cache fcc;
12971297
zval *retval_ptr;
1298+
zend_bool props_merged = 0;
12981299

12991300
object_and_properties_init(return_value, ce, NULL);
1300-
zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
1301+
if (!ce->__set) {
1302+
props_merged = 1;
1303+
zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
1304+
}
13011305

13021306
if (ce->constructor) {
13031307
fci.size = sizeof(fci);
@@ -1331,6 +1335,10 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags
13311335

13321336
if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
13331337
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
1338+
if (fci.params) {
1339+
efree(fci.params);
1340+
}
1341+
return;
13341342
} else {
13351343
if (retval_ptr) {
13361344
zval_ptr_dtor(&retval_ptr);
@@ -1341,6 +1349,11 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags
13411349
}
13421350
} else if (ctor_params) {
13431351
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
1352+
return;
1353+
}
1354+
1355+
if (!props_merged) {
1356+
zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
13441357
}
13451358
}
13461359
}

ext/mysqli/tests/bug71820.phpt

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
--TEST--
2+
Bug #71820 __set has to be called after constructor, mysqli part
3+
--SKIPIF--
4+
<?php
5+
require_once('skipif.inc');
6+
require_once('skipifconnectfailure.inc');
7+
require_once("connect.inc");
8+
?>
9+
--FILE--
10+
<?php
11+
12+
include "connect.inc";
13+
14+
$tableName = 'test_mysqli_fetch_object';
15+
16+
class TestRow
17+
{
18+
19+
private $set_from_constructor;
20+
private $data;
21+
private $hello = "world";
22+
23+
public function __construct($set_from_constructor)
24+
{
25+
$this->set_from_constructor = $set_from_constructor;
26+
}
27+
28+
public function __set($name, $value)
29+
{
30+
if (!isset($this->data[$name])) {
31+
/* $this->set_from_constructor has an expected value */
32+
$this->data[$name] = 42 == $this->set_from_constructor ? $value : -1;
33+
return;
34+
}
35+
throw new \Exception('Duplicity column name.');
36+
}
37+
38+
}
39+
40+
41+
if (!($connection = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))) {
42+
printf("[001] Cannot connect to the server");
43+
}
44+
45+
$rc = mysqli_query($connection, "DROP TABLE IF EXISTS $tableName");
46+
if (!$rc)
47+
printf("[002] [%d] %s\n", mysqli_errno($connection), mysqli_error($connection));
48+
49+
$table = <<<SQL
50+
CREATE TABLE $tableName (
51+
id int NOT NULL auto_increment primary key,
52+
name varchar(255) NOT NULL
53+
);
54+
SQL;
55+
56+
$rc = mysqli_query($connection, $table);
57+
if (!$rc)
58+
printf("[003] [%d] %s\n", mysqli_errno($connection), mysqli_error($connection));
59+
60+
$rc = mysqli_query($connection, "INSERT INTO " . $tableName . " (name) VALUES ('Doe'), ('Joe')");
61+
if (!$rc)
62+
printf("[004] [%d] %s\n", mysqli_errno($connection), mysqli_error($connection));
63+
64+
$result = mysqli_query($connection, 'SELECT * FROM ' . $tableName . ' LIMIT 10');
65+
if (!$result)
66+
printf("[005] [%d] %s\n", mysqli_errno($result), mysqli_error($result));
67+
68+
69+
while ($row = mysqli_fetch_object($result, 'TestRow', [42])) {
70+
var_dump($row);
71+
}
72+
73+
mysqli_close($connection);
74+
75+
?>
76+
==DONE==
77+
--EXPECTF--
78+
object(TestRow)#%d (3) {
79+
["set_from_constructor":"TestRow":private]=>
80+
int(42)
81+
["data":"TestRow":private]=>
82+
array(2) {
83+
["id"]=>
84+
string(1) "1"
85+
["name"]=>
86+
string(3) "Doe"
87+
}
88+
["hello":"TestRow":private]=>
89+
string(5) "world"
90+
}
91+
object(TestRow)#%d (3) {
92+
["set_from_constructor":"TestRow":private]=>
93+
int(42)
94+
["data":"TestRow":private]=>
95+
array(2) {
96+
["id"]=>
97+
string(1) "2"
98+
["name"]=>
99+
string(3) "Joe"
100+
}
101+
["hello":"TestRow":private]=>
102+
string(5) "world"
103+
}
104+
==DONE==

ext/pgsql/pgsql.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2784,9 +2784,13 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type,
27842784
zend_fcall_info fci;
27852785
zend_fcall_info_cache fcc;
27862786
zval *retval_ptr;
2787+
zend_bool props_merged = 0;
27872788

27882789
object_and_properties_init(return_value, ce, NULL);
2789-
zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
2790+
if (!ce->__set) {
2791+
props_merged = 1;
2792+
zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
2793+
}
27902794

27912795
if (ce->constructor) {
27922796
fci.size = sizeof(fci);
@@ -2820,6 +2824,10 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type,
28202824

28212825
if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
28222826
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
2827+
if (fci.params) {
2828+
efree(fci.params);
2829+
}
2830+
return;
28232831
} else {
28242832
if (retval_ptr) {
28252833
zval_ptr_dtor(&retval_ptr);
@@ -2830,6 +2838,11 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type,
28302838
}
28312839
} else if (ctor_params) {
28322840
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
2841+
return;
2842+
}
2843+
2844+
if (!props_merged) {
2845+
zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
28332846
}
28342847
}
28352848
}

ext/pgsql/tests/bug71820.phpt

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
--TEST--
2+
Bug #71820 pg_fetch_object bind parameters before call constructor
3+
--SKIPIF--
4+
<?php
5+
require_once('skipif.inc');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
require_once('config.inc');
11+
12+
$tableName = 'test_pg_fetch_object';
13+
14+
class TestRow
15+
{
16+
17+
private $set_from_constructor;
18+
private $data;
19+
private $hello = 42;
20+
21+
public function __construct($set_from_constructor)
22+
{
23+
$this->set_from_constructor = $set_from_constructor;
24+
}
25+
26+
public function __set($name, $value)
27+
{
28+
if (!isset($this->data[$name])) {
29+
/* $this->set_from_constructor has an expected value */
30+
$this->data[$name] = 42 == $this->set_from_constructor ? $value : -1;
31+
return;
32+
}
33+
throw new \Exception('Duplicity column name.');
34+
}
35+
36+
}
37+
38+
$connection = pg_connect($conn_str);
39+
40+
if (!$connection) {
41+
die('Connection faild.');
42+
}
43+
44+
$table = <<<SQL
45+
CREATE TABLE IF NOT EXISTS $tableName (
46+
id serial NOT NULL,
47+
name character varying NOT NULL
48+
);
49+
SQL;
50+
pg_query($connection, $table);
51+
52+
pg_query_params('INSERT INTO ' . $tableName . ' (name) VALUES ($1), ($2);', ['$1' => 'Doe', '$2' => 'Joe']);
53+
54+
$result = pg_query('SELECT * FROM ' . $tableName . ' LIMIT 10;');
55+
56+
while ($row = pg_fetch_object($result, NULL, 'TestRow', [42])) {
57+
var_dump($row);
58+
}
59+
60+
pg_query($connection, "DROP TABLE $tableName");
61+
62+
pg_close($connection);
63+
64+
?>
65+
==DONE==
66+
--EXPECTF--
67+
object(TestRow)#%d (3) {
68+
["set_from_constructor":"TestRow":private]=>
69+
int(42)
70+
["data":"TestRow":private]=>
71+
array(2) {
72+
["id"]=>
73+
string(1) "1"
74+
["name"]=>
75+
string(3) "Doe"
76+
}
77+
["hello":"TestRow":private]=>
78+
int(42)
79+
}
80+
object(TestRow)#%d (3) {
81+
["set_from_constructor":"TestRow":private]=>
82+
int(42)
83+
["data":"TestRow":private]=>
84+
array(2) {
85+
["id"]=>
86+
string(1) "2"
87+
["name"]=>
88+
string(3) "Joe"
89+
}
90+
["hello":"TestRow":private]=>
91+
int(42)
92+
}
93+
==DONE==

0 commit comments

Comments
 (0)