[go: up one dir, main page]

Skip to content

Commit

Permalink
ext/pdo: Fixed PDO::setAttribute() and PDO::getAttribute() (#12793)
Browse files Browse the repository at this point in the history
  • Loading branch information
SakiTakamachi authored Dec 4, 2023
1 parent e502aaf commit 866aa12
Show file tree
Hide file tree
Showing 17 changed files with 104 additions and 46 deletions.
12 changes: 12 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ Opcache:
. If JIT is enabled, PHP will now exit with a fatal error on startup in case
of JIT startup initialization issues. (danog)

PDO:
. Fixed setAttribute and getAttribute (SakiTakamachi)

PDO_DBLIB:
. Fixed setAttribute and getAttribute (SakiTakamachi)

PDO_FIREBIRD:
. Fixed setAttribute and getAttribute (SakiTakamachi)

PDO_MYSQL:
. Fixed setAttribute and getAttribute (SakiTakamachi)

PDO_PGSQL:
. Fixed GH-12423, DSN credentials being prioritized over the user/password
PDO constructor arguments. (SakiTakamachi)
Expand Down
21 changes: 21 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ PHP 8.4 UPGRADE NOTES
Consult sections 2. New Features and 6. New Functions for a list of
newly implemented methods and constants.

- PDO_DBLIB:
. setAttribute, DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER and DBLIB_ATTR_DATETIME_CONVERT
have been changed to set value as a bool.

- PDO_FIREBIRD:
. getAttribute, ATTR_AUTOCOMMIT has been changed to get the value as a bool.

- PDO_MYSQL:
. getAttribute, ATTR_AUTOCOMMIT, ATTR_EMULATE_PREPARES, MYSQL_ATTR_DIRECT_QUERY have
been changed to get values ​​as bool.

- PDO_PGSQL:
. The DSN's credentials, when set, are given priority over their PDO
constructor counterparts, being closer to the documentation states.
Expand Down Expand Up @@ -139,6 +150,16 @@ PHP 8.4 UPGRADE NOTES
. The behavior of mb_strcut is more consistent now on invalid UTF-8 and UTF-16
strings. (For valid UTF-8 and UTF-16 strings, there is no change.)

- PDO:
. getAttribute, enabled to get the value of ATTR_STRINGIFY_FETCHES.

- PDO_FIREBIRD:
. getAttribute, enabled to get values ​​of FB_ATTR_DATE_FORMAT, FB_ATTR_TIME_FORMAT,
FB_ATTR_TIMESTAMP_FORMAT.

- PDO_MYSQL:
. getAttribute, enabled to get the value of ATTR_FETCH_TABLE_NAMES.

- PGSQL:
. pg_select, the conditions arguments accepts an empty array and is optional.

Expand Down
5 changes: 5 additions & 0 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -911,8 +911,13 @@ PHP_METHOD(PDO, getAttribute)
add_next_index_zval(return_value, &dbh->def_stmt_ctor_args);
}
return;

case PDO_ATTR_DEFAULT_FETCH_MODE:
RETURN_LONG(dbh->default_fetch_type);

case PDO_ATTR_STRINGIFY_FETCHES:
RETURN_BOOL(dbh->stringify);

default:
break;
}
Expand Down
8 changes: 4 additions & 4 deletions ext/pdo_dblib/dblib_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,10 @@ static bool dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
}
return SUCCEED == dbsettime(lval);
case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER:
if (!pdo_get_long_param(&lval, val)) {
if (!pdo_get_bool_param(&bval, val)) {
return false;
}
H->stringify_uniqueidentifier = lval;
H->stringify_uniqueidentifier = bval;
return true;
case PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS:
if (!pdo_get_bool_param(&bval, val)) {
Expand All @@ -302,10 +302,10 @@ static bool dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
H->skip_empty_rowsets = bval;
return true;
case PDO_DBLIB_ATTR_DATETIME_CONVERT:
if (!pdo_get_long_param(&lval, val)) {
if (!pdo_get_bool_param(&bval, val)) {
return false;
}
H->datetime_convert = lval;
H->datetime_convert = bval;
return true;
default:
return false;
Expand Down
14 changes: 13 additions & 1 deletion ext/pdo_firebird/firebird_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ static int pdo_firebird_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
char tmp[INFO_BUF_LEN];

case PDO_ATTR_AUTOCOMMIT:
ZVAL_LONG(val,dbh->auto_commit);
ZVAL_BOOL(val,dbh->auto_commit);
return 1;

case PDO_ATTR_CONNECTION_STATUS:
Expand Down Expand Up @@ -1124,6 +1124,18 @@ static int pdo_firebird_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
case PDO_ATTR_FETCH_TABLE_NAMES:
ZVAL_BOOL(val, H->fetch_table_names);
return 1;

case PDO_FB_ATTR_DATE_FORMAT:
ZVAL_STRING(val, H->date_format);
return 1;

case PDO_FB_ATTR_TIME_FORMAT:
ZVAL_STRING(val, H->time_format);
return 1;

case PDO_FB_ATTR_TIMESTAMP_FORMAT:
ZVAL_STRING(val, H->timestamp_format);
return 1;
}
return 0;
}
Expand Down
16 changes: 8 additions & 8 deletions ext/pdo_firebird/tests/autocommit_change_mode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -91,42 +91,42 @@ echo "done!";
--EXPECT--
========== not in manually transaction ==========
auto commit ON from ON
int(1)
bool(true)
Success

auto commit OFF from ON
int(0)
bool(false)
Success

auto commit OFF from OFF
int(0)
bool(false)
Success

auto commit ON from OFF
int(1)
bool(true)
Success

========== in manually transaction ==========
begin transaction

auto commit ON from ON, expect error
int(1)
bool(true)
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open

auto commit OFF from ON, expect error
int(1)
bool(true)
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open

end transaction
auto commit OFF
begin transaction

auto commit ON from OFF, expect error
int(0)
bool(false)
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open

auto commit OFF from OFF, expect error
int(0)
bool(false)
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open

end transaction
Expand Down
8 changes: 6 additions & 2 deletions ext/pdo_mysql/mysql_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_
break;

case PDO_ATTR_AUTOCOMMIT:
ZVAL_LONG(return_value, dbh->auto_commit);
ZVAL_BOOL(return_value, dbh->auto_commit);
break;

case PDO_ATTR_DEFAULT_STR_PARAM:
Expand All @@ -545,7 +545,7 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_

case PDO_ATTR_EMULATE_PREPARES:
case PDO_MYSQL_ATTR_DIRECT_QUERY:
ZVAL_LONG(return_value, H->emulate_prepare);
ZVAL_BOOL(return_value, H->emulate_prepare);
break;

#ifndef PDO_USE_MYSQLND
Expand Down Expand Up @@ -576,6 +576,10 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_
}
#endif

case PDO_ATTR_FETCH_TABLE_NAMES:
ZVAL_BOOL(return_value, H->fetch_table_names);
break;

default:
PDO_DBG_RETURN(0);
}
Expand Down
14 changes: 7 additions & 7 deletions ext/pdo_mysql/tests/bug68371.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ $pdo->setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

$attrs = [
// Extensive test: default value and set+get values
PDO::ATTR_EMULATE_PREPARES => array(null, 1, 0),
PDO::MYSQL_ATTR_DIRECT_QUERY => array(null, 0, 1),
PDO::ATTR_EMULATE_PREPARES => array(null, true, false),
PDO::MYSQL_ATTR_DIRECT_QUERY => array(null, false, true),
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => array(null, false, true),

// Just test the default
Expand Down Expand Up @@ -67,16 +67,16 @@ foreach ($attrs as $a => $vals) {

?>
--EXPECTF--
int(1)
bool(true)
OK
OK
int(0)
bool(false)
OK
OK
bool(true)
OK
OK
int(1)
bool(true)
ERR
ERR
int(2)
Expand All @@ -93,9 +93,9 @@ array(1) {
[0]=>
string(12) "PDOStatement"
}
ERR
bool(false)
ERR
string(5) "mysql"
ERR
bool(false)
ERR
int(4)
10 changes: 5 additions & 5 deletions ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ MySQLPDOTest::skip();

$defaults = [
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_AUTOCOMMIT => 1,
PDO::ATTR_AUTOCOMMIT => true,
/* TODO - why is this a valid option if getAttribute() does not support it?! */
PDO::ATTR_TIMEOUT => false,
PDO::ATTR_EMULATE_PREPARES => 1,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
/* TODO getAttribute() does not handle it */
PDO::MYSQL_ATTR_LOCAL_INFILE => false,
/* TODO getAttribute() does not handle it */
PDO::MYSQL_ATTR_DIRECT_QUERY => 1,
PDO::MYSQL_ATTR_DIRECT_QUERY => true,
PDO::MYSQL_ATTR_INIT_COMMAND => '',
];

Expand Down Expand Up @@ -151,8 +151,8 @@ MySQLPDOTest::skip();
set_option_and_check(24, PDO::MYSQL_ATTR_INIT_COMMAND, '', 'PDO::MYSQL_ATTR_INIT_COMMAND');
set_option_and_check(25, PDO::MYSQL_ATTR_INIT_COMMAND, 'INSERT INTO nonexistent(invalid) VALUES (1)', 'PDO::MYSQL_ATTR_INIT_COMMAND');

set_option_and_check(33, PDO::MYSQL_ATTR_DIRECT_QUERY, 1, 'PDO::MYSQL_ATTR_DIRECT_QUERY');
set_option_and_check(34, PDO::MYSQL_ATTR_DIRECT_QUERY, 0, 'PDO::MYSQL_ATTR_DIRECT_QUERY');
set_option_and_check(33, PDO::MYSQL_ATTR_DIRECT_QUERY, true, 'PDO::MYSQL_ATTR_DIRECT_QUERY');
set_option_and_check(34, PDO::MYSQL_ATTR_DIRECT_QUERY, false, 'PDO::MYSQL_ATTR_DIRECT_QUERY');

if (defined('PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY')) {
set_option_and_check(35, PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY, null, 'PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY');
Expand Down
6 changes: 3 additions & 3 deletions ext/pdo_mysql/tests/pdo_mysql_attr_autocommit.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();

// autocommit should be on by default
if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
if (true !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[001] Expecting int/1 got %s\n", var_export($tmp, true));

// lets see if the server agrees to that
Expand All @@ -33,7 +33,7 @@ MySQLPDOTest::skip();
if (!$db->query('SET autocommit = 1'))
printf("[005] Cannot turn on server autocommit mode, %s\n", var_export($db->errorInfo(), true));

if (0 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
if (false !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[006] Expecting int/0 got %s\n", var_export($tmp, true));

// off -> on
Expand All @@ -47,7 +47,7 @@ MySQLPDOTest::skip();
if (!$row['_autocommit'])
printf("[009] Server autocommit mode should be on, got '%s'\n", var_export($row['_autocommit']));

if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
if (true !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[010] Expecting int/1 got %s\n", var_export($tmp, true));

$table = 'pdo_mysql_attr_autocommit';
Expand Down
8 changes: 6 additions & 2 deletions ext/pdo_mysql/tests/pdo_mysql_attr_fetch_table_names.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ MySQLPDOTest::skip();
$table = 'pdo_mysql_attr_fetch_table_names';
MySQLPDOTest::createTestTable($table, $db);

$db->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, 1);
$db->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, true);
var_dump($db->getAttribute(PDO::ATTR_FETCH_TABLE_NAMES));
$stmt = $db->query("SELECT label FROM {$table} LIMIT 1");
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();

$db->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, 0);
$db->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, false);
var_dump($db->getAttribute(PDO::ATTR_FETCH_TABLE_NAMES));
$stmt = $db->query("SELECT label FROM {$table} LIMIT 1");
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();
Expand All @@ -34,13 +36,15 @@ $db = MySQLPDOTest::factory();
$db->query('DROP TABLE IF EXISTS pdo_mysql_attr_fetch_table_names');
?>
--EXPECT--
bool(true)
array(1) {
[0]=>
array(1) {
["pdo_mysql_attr_fetch_table_names.label"]=>
string(1) "a"
}
}
bool(false)
array(1) {
[0]=>
array(1) {
Expand Down
12 changes: 6 additions & 6 deletions ext/pdo_mysql/tests/pdo_mysql_begintransaction.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ MySQLPDOTest::skipNotTransactionalEngine();

MySQLPDOTest::createTestTable($table, $db, MySQLPDOTest::detect_transactional_mysql_engine($db));

if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
if (true !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[001] Autocommit should be on by default\n");

if (false == $db->beginTransaction())
printf("[002] Cannot start a transaction, [%s] [%s]\n",
$db->errorCode(), implode(' ', $db->errorInfo()));

if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
if (true !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[003] Autocommit should be on by default, beginTransaction() shall not impact it\n");

if (0 == $db->exec("DELETE FROM {$table}"))
Expand All @@ -50,7 +50,7 @@ MySQLPDOTest::skipNotTransactionalEngine();
if (!$db->commit())
printf("[008] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));

if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
if (true !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[009] Autocommit should be on after commit()\n");

if (!($stmt = $db->query(sprintf('SELECT id, label FROM %s WHERE id = %d', $table, $row['id']))))
Expand Down Expand Up @@ -91,7 +91,7 @@ MySQLPDOTest::skipNotTransactionalEngine();
if (!$db->rollback())
printf("[018] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));

if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
if (true !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[019] Autocommit should be on after rollback\n");

if (!($stmt = $db->query(sprintf('SELECT id, label FROM %s WHERE id = %d', $table, $row['id']))))
Expand Down Expand Up @@ -132,7 +132,7 @@ MySQLPDOTest::skipNotTransactionalEngine();

// Turn off autocommit using a server variable
$db->exec('SET @@autocommit = 0');
if (1 === $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
if (true === $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[028] I'm confused, how can autocommit be on? Didn't I say I want to manually control transactions?\n");

if (!$db->beginTransaction())
Expand All @@ -155,7 +155,7 @@ MySQLPDOTest::skipNotTransactionalEngine();
printf("[031] Cannot start a transaction, [%s] [%s]\n",
$db->errorCode(), implode(' ', $db->errorInfo()));

if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
if (true !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[032] Autocommit should be on my default, beginTransaction() should not change that\n");

if (0 == $db->exec("DELETE FROM {$table}"))
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_mysql/tests/pdo_mysql_commit.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ MySQLPDOTest::skipNotTransactionalEngine();

// pdo_transaction_transitions should check this as well...
// ... just to be sure the most basic stuff really works we check it again...
if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
if (true !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[003] According to the manual we should be back to autocommit mode, got %s/%s\n",
gettype($tmp), var_export($tmp, true));

Expand Down
Loading

0 comments on commit 866aa12

Please sign in to comment.