diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 4c8af0597a28c..9544a7215bbf7 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -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: { diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c index adccb5e3d0f00..2d098bffa8724 100644 --- a/ext/pdo_mysql/mysql_driver.c +++ b/ext/pdo_mysql/mysql_driver.c @@ -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) { @@ -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; @@ -446,7 +446,7 @@ 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; @@ -454,12 +454,24 @@ static bool pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) 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); @@ -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; diff --git a/ext/pdo_mysql/tests/gh-11587.phpt b/ext/pdo_mysql/tests/gh-11587.phpt new file mode 100644 index 0000000000000..45aecba794ab3 --- /dev/null +++ b/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-- + +--FILE-- +exec('DROP TABLE IF EXISTS test'); + +$createTestTable = <<exec($createTestTable); + +$insertTestTable = <<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-- + +--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!