summaryrefslogtreecommitdiff
path: root/ext/pgsql
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2016-03-17 12:39:31 +0100
committerAnatol Belski <ab@php.net>2016-03-17 12:41:55 +0100
commitb4eedd128ba9f61be08a50c94afd72837d7cf70b (patch)
tree5781b60e54438c633a65b7edfb5b7b2f6f95fc2e /ext/pgsql
parentdae086040ecdefcd616c6592679f87f03dc62e00 (diff)
downloadphp-git-b4eedd128ba9f61be08a50c94afd72837d7cf70b.tar.gz
Fixed bug #71820 pg_fetch_object bind parameters before call constructor
If we want to fetch into an object of a custom class that implemens __set handler, the corstructor has to be called first. The data passed to the constructor can be possibly required in __set handler.
Diffstat (limited to 'ext/pgsql')
-rw-r--r--ext/pgsql/pgsql.c24
-rw-r--r--ext/pgsql/tests/bug71820.phpt93
2 files changed, 114 insertions, 3 deletions
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 86421e9531..cb6f4cac49 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -2777,14 +2777,13 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_
zend_fcall_info fci;
zend_fcall_info_cache fcc;
zval retval;
+ zend_bool props_handled = 0;
ZVAL_COPY_VALUE(&dataset, return_value);
object_and_properties_init(return_value, ce, NULL);
if (!ce->default_properties_count && !ce->__set) {
Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
- } else {
- zend_merge_properties(return_value, Z_ARRVAL(dataset));
- zval_ptr_dtor(&dataset);
+ props_handled = 1;
}
if (ce->constructor) {
@@ -2807,6 +2806,9 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_
* argument passed by reference.
*/
zend_throw_exception(zend_ce_exception, "Parameter ctor_params must be an array", 0);
+ if (!props_handled) {
+ zval_ptr_dtor(&dataset);
+ }
return;
}
}
@@ -2819,6 +2821,13 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_
if (zend_call_function(&fci, &fcc) == FAILURE) {
zend_throw_exception_ex(zend_ce_exception, 0, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
+ if (fci.params) {
+ efree(fci.params);
+ }
+ if (!props_handled) {
+ zval_ptr_dtor(&dataset);
+ }
+ return;
} else {
zval_ptr_dtor(&retval);
}
@@ -2827,6 +2836,15 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_
}
} else if (ctor_params) {
zend_throw_exception_ex(zend_ce_exception, 0, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
+ if (!props_handled) {
+ zval_ptr_dtor(&dataset);
+ }
+ return;
+ }
+
+ if (!props_handled) {
+ zend_merge_properties(return_value, Z_ARRVAL(dataset));
+ zval_ptr_dtor(&dataset);
}
}
}
diff --git a/ext/pgsql/tests/bug71820.phpt b/ext/pgsql/tests/bug71820.phpt
new file mode 100644
index 0000000000..4d99e3468e
--- /dev/null
+++ b/ext/pgsql/tests/bug71820.phpt
@@ -0,0 +1,93 @@
+--TEST--
+Bug #71820 pg_fetch_object bind parameters before call constructor
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+?>
+--FILE--
+<?php
+
+require_once('config.inc');
+
+$tableName = 'test_pg_fetch_object';
+
+class TestRow
+{
+
+ private $set_from_constructor;
+ private $data;
+ private $hello = 42;
+
+ public function __construct($set_from_constructor)
+ {
+ $this->set_from_constructor = $set_from_constructor;
+ }
+
+ public function __set($name, $value)
+ {
+ if (!isset($this->data[$name])) {
+ /* $this->set_from_constructor has an expected value */
+ $this->data[$name] = 42 == $this->set_from_constructor ? $value : -1;
+ return;
+ }
+ throw new \Exception('Duplicity column name.');
+ }
+
+}
+
+$connection = pg_connect($conn_str);
+
+if (!$connection) {
+ die('Connection faild.');
+}
+
+$table = <<<SQL
+CREATE TABLE IF NOT EXISTS $tableName (
+ id serial NOT NULL,
+ name character varying NOT NULL
+);
+SQL;
+pg_query($connection, $table);
+
+pg_query_params('INSERT INTO ' . $tableName . ' (name) VALUES ($1), ($2);', ['$1' => 'Doe', '$2' => 'Joe']);
+
+$result = pg_query('SELECT * FROM ' . $tableName . ' LIMIT 10;');
+
+while ($row = pg_fetch_object($result, NULL, 'TestRow', [42])) {
+ var_dump($row);
+}
+
+pg_query($connection, "DROP TABLE $tableName");
+
+pg_close($connection);
+
+?>
+==DONE==
+--EXPECTF--
+object(TestRow)#%d (3) {
+ ["set_from_constructor":"TestRow":private]=>
+ int(42)
+ ["data":"TestRow":private]=>
+ array(2) {
+ ["id"]=>
+ string(1) "1"
+ ["name"]=>
+ string(3) "Doe"
+ }
+ ["hello":"TestRow":private]=>
+ int(42)
+}
+object(TestRow)#%d (3) {
+ ["set_from_constructor":"TestRow":private]=>
+ int(42)
+ ["data":"TestRow":private]=>
+ array(2) {
+ ["id"]=>
+ string(1) "2"
+ ["name"]=>
+ string(3) "Joe"
+ }
+ ["hello":"TestRow":private]=>
+ int(42)
+}
+==DONE==