Skip to content

Commit

Permalink
Fix GH-11587 PDO::ATTR_STRINGIFY_FETCHES should return strings even i…
Browse files Browse the repository at this point in the history
…n if PDO::ATTR_EMULATE_PREPARES is enabled

This also includes a fix for the MySQL ND driver to actually respect the user decided behaviour.

Closes GH-11622

Signed-off-by: George Peter Banyard <girgias@php.net>
  • Loading branch information
SakiTakamachi authored and Girgias committed Jul 17, 2023
1 parent 5c26258 commit e0aadc1
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 6 deletions.
5 changes: 5 additions & 0 deletions NEWS
Expand Up @@ -56,6 +56,11 @@ PHP NEWS
- PCRE:
. Mangle PCRE regex cache key with JIT option. (mvorisek)

- PDO:
. Fix GH-11587 (After php8.1, when PDO::ATTR_EMULATE_PREPARES is true
and PDO::ATTR_STRINGIFY_FETCHES is true, decimal zeros are no longer
filled). (SakiTakamachi)

- PDO SQLite:
. Fix GH-11492 (Make test failure: ext/pdo_sqlite/tests/bug_42589.phpt).
(KapitanOczywisty, CViniciusSDias)
Expand Down
3 changes: 3 additions & 0 deletions ext/pdo/pdo_dbh.c
Expand Up @@ -792,6 +792,9 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
return false;
}
dbh->stringify = bval;
if (dbh->methods->set_attribute) {
dbh->methods->set_attribute(dbh, attr, value);
}
return true;

case PDO_ATTR_STATEMENT_CLASS: {
Expand Down
24 changes: 18 additions & 6 deletions ext/pdo_mysql/mysql_driver.c
Expand Up @@ -417,7 +417,7 @@ static bool pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
switch (attr) {
case PDO_ATTR_AUTOCOMMIT:
if (!pdo_get_bool_param(&bval, val)) {
return false;
PDO_DBG_RETURN(false);
}
/* ignore if the new value equals the old one */
if (dbh->auto_commit ^ bval) {
Expand All @@ -437,7 +437,7 @@ static bool pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)

case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
if (!pdo_get_bool_param(&bval, val)) {
return false;
PDO_DBG_RETURN(false);
}
/* ignore if the new value equals the old one */
((pdo_mysql_db_handle *)dbh->driver_data)->buffered = bval;
Expand All @@ -446,20 +446,32 @@ static bool pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
case PDO_MYSQL_ATTR_DIRECT_QUERY:
case PDO_ATTR_EMULATE_PREPARES:
if (!pdo_get_bool_param(&bval, val)) {
return false;
PDO_DBG_RETURN(false);
}
/* ignore if the new value equals the old one */
((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = bval;
PDO_DBG_RETURN(true);

case PDO_ATTR_FETCH_TABLE_NAMES:
if (!pdo_get_bool_param(&bval, val)) {
return false;
PDO_DBG_RETURN(false);
}
((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = bval;
PDO_DBG_RETURN(true);

#ifndef PDO_USE_MYSQLND
#ifdef PDO_USE_MYSQLND
case PDO_ATTR_STRINGIFY_FETCHES:
if (!pdo_get_bool_param(&bval, val)) {
PDO_DBG_RETURN(false);
}
unsigned int int_and_float_native = !bval;
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
if (mysql_options(H->server, MYSQLND_OPT_INT_AND_FLOAT_NATIVE, (const char *) &int_and_float_native)) {
pdo_mysql_error(dbh);
PDO_DBG_RETURN(false);
}
PDO_DBG_RETURN(true);
#else
case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
if (!pdo_get_long_param(&lval, val)) {
PDO_DBG_RETURN(false);
Expand Down Expand Up @@ -891,7 +903,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
}

#ifdef PDO_USE_MYSQLND
unsigned int int_and_float_native = 1;
unsigned int int_and_float_native = !pdo_attr_lval(driver_options, PDO_ATTR_STRINGIFY_FETCHES, dbh->stringify);
if (mysql_options(H->server, MYSQLND_OPT_INT_AND_FLOAT_NATIVE, (const char *) &int_and_float_native)) {
pdo_mysql_error(dbh);
goto cleanup;
Expand Down
163 changes: 163 additions & 0 deletions ext/pdo_mysql/tests/gh-11587.phpt
@@ -0,0 +1,163 @@
--TEST--
GH-11587 PHP8.1: Fixed the condition for result set values to be of native type, making it compatible with previous versions. #11622
--EXTENSIONS--
pdo_mysql
--SKIPIF--
<?php
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
if (!extension_loaded('mysqlnd')) die('skip: This test requires the loading of mysqlnd');
?>
--FILE--
<?php
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();

$db->exec('DROP TABLE IF EXISTS test');

$createTestTable = <<<SQL
CREATE TABLE test(
id INT,
`float_col` FLOAT(3,2) DEFAULT NULL,
`double_col` DOUBLE(3,2) DEFAULT NULL,
`decimal_col` DECIMAL(3,2) DEFAULT NULL
)
SQL;

$db->exec($createTestTable);

$insertTestTable = <<<SQL
INSERT INTO test(id, float_col, double_col, decimal_col) VALUES(1, 2.60, 3.60, 4.60)
SQL;

$db->exec($insertTestTable);

echo "PDO::ATTR_EMULATE_PREPARES = true, PDO::ATTR_STRINGIFY_FETCHES = true\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$results = $db->query('SELECT * FROM test');
foreach ($results as $result) {
var_dump($result);
}

echo "\n";

echo "PDO::ATTR_EMULATE_PREPARES = true, PDO::ATTR_STRINGIFY_FETCHES = false\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$results = $db->query('SELECT * FROM test');
foreach ($results as $result) {
var_dump($result);
}

echo "\n";

echo "PDO::ATTR_EMULATE_PREPARES = false, PDO::ATTR_STRINGIFY_FETCHES = true\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$results = $db->query('SELECT * FROM test');
foreach ($results as $result) {
var_dump($result);
}

echo "\n";

echo "PDO::ATTR_EMULATE_PREPARES = false, PDO::ATTR_STRINGIFY_FETCHES = false\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$results = $db->query('SELECT * FROM test');
foreach ($results as $result) {
var_dump($result);
}

echo "\n";

echo 'done!';
?>
--CLEAN--
<?php
require __DIR__ . '/mysql_pdo_test.inc';
MySQLPDOTest::dropTestTable();
?>
--EXPECT--
PDO::ATTR_EMULATE_PREPARES = true, PDO::ATTR_STRINGIFY_FETCHES = true
array(8) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
["float_col"]=>
string(4) "2.60"
[1]=>
string(4) "2.60"
["double_col"]=>
string(4) "3.60"
[2]=>
string(4) "3.60"
["decimal_col"]=>
string(4) "4.60"
[3]=>
string(4) "4.60"
}

PDO::ATTR_EMULATE_PREPARES = true, PDO::ATTR_STRINGIFY_FETCHES = false
array(8) {
["id"]=>
int(1)
[0]=>
int(1)
["float_col"]=>
float(2.6)
[1]=>
float(2.6)
["double_col"]=>
float(3.6)
[2]=>
float(3.6)
["decimal_col"]=>
string(4) "4.60"
[3]=>
string(4) "4.60"
}

PDO::ATTR_EMULATE_PREPARES = false, PDO::ATTR_STRINGIFY_FETCHES = true
array(8) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
["float_col"]=>
string(3) "2.6"
[1]=>
string(3) "2.6"
["double_col"]=>
string(3) "3.6"
[2]=>
string(3) "3.6"
["decimal_col"]=>
string(4) "4.60"
[3]=>
string(4) "4.60"
}

PDO::ATTR_EMULATE_PREPARES = false, PDO::ATTR_STRINGIFY_FETCHES = false
array(8) {
["id"]=>
int(1)
[0]=>
int(1)
["float_col"]=>
float(2.6)
[1]=>
float(2.6)
["double_col"]=>
float(3.6)
[2]=>
float(3.6)
["decimal_col"]=>
string(4) "4.60"
[3]=>
string(4) "4.60"
}

done!

0 comments on commit e0aadc1

Please sign in to comment.