1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-12767: Fixed to be able to change autocommit mode using setAttribute

Signed-off-by: Gina Peter Banyard <girgias@php.net>
This commit is contained in:
SakiTakamachi
2023-11-25 21:22:50 +09:00
committed by Gina Peter Banyard
parent abf4c116b1
commit 933dccb79b
4 changed files with 200 additions and 0 deletions

4
NEWS
View File

@@ -20,6 +20,10 @@ PHP NEWS
. Added workaround for SELinux mprotect execheap issue.
See https://bugzilla.kernel.org/show_bug.cgi?id=218258. (ilutov)
- PDO_ODBC:
. Fixed bug GH-12767 (Unable to turn on autocommit mode with setAttribute()).
(SakiTakamachi)
- PHPDBG:
. Fixed bug GH-12962 (Double free of init_file in phpdbg_prompt.c). (nielsdos)

View File

@@ -344,6 +344,30 @@ static bool odbc_handle_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
}
H->assume_utf8 = bval;
return true;
case PDO_ATTR_AUTOCOMMIT:
if (!pdo_get_bool_param(&bval, val)) {
return false;
}
if (dbh->in_txn) {
pdo_raise_impl_error(dbh, NULL, "HY000", "Cannot change autocommit mode while a transaction is already open");
return false;
}
if (dbh->auto_commit ^ bval) {
dbh->auto_commit = bval;
RETCODE rc = SQLSetConnectAttr(
H->dbc,
SQL_ATTR_AUTOCOMMIT,
dbh->auto_commit ? (SQLPOINTER) SQL_AUTOCOMMIT_ON : (SQLPOINTER) SQL_AUTOCOMMIT_OFF,
SQL_IS_INTEGER
);
if (rc != SQL_SUCCESS) {
pdo_odbc_drv_error(
dbh->auto_commit ? "SQLSetConnectAttr AUTOCOMMIT = ON" : "SQLSetConnectAttr AUTOCOMMIT = OFF"
);
return false;
}
}
return true;
default:
strcpy(H->einfo.last_err_msg, "Unknown Attribute");
H->einfo.what = "setAttribute";

View File

@@ -0,0 +1,53 @@
--TEST--
PDO ODBC auto commit mode
--EXTENSIONS--
pdo_odbc
--SKIPIF--
<?php
require 'ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--XLEAK--
A bug in msodbcsql causes a memory leak when reconnecting after closing. See GH-12306
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$table = 'autocommit_pdo_odbc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("CREATE TABLE {$table} (id INT, name VARCHAR(255))");
unset($db);
$db = new PDO(getenv('PDOTEST_DSN'), getenv('PDOTEST_USER'), getenv('PDOTEST_PASS'), [
PDO::ATTR_AUTOCOMMIT => 0,
]);
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
$db->query("INSERT INTO {$table} (id, name) VALUES (1, 'test')");
unset($db);
$db = new PDO(getenv('PDOTEST_DSN'), getenv('PDOTEST_USER'), getenv('PDOTEST_PASS'));
$r = $db->query("SELECT * FROM {$table}");
var_dump($r->fetchAll(PDO::FETCH_ASSOC));
echo "done!";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("DROP TABLE IF EXISTS autocommit_pdo_odbc");
?>
--EXPECT--
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["name"]=>
string(4) "test"
}
}
done!

View File

@@ -0,0 +1,119 @@
--TEST--
PDO ODBC auto commit mode
--EXTENSIONS--
pdo_odbc
--SKIPIF--
<?php
require 'ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "========== not in transaction ==========\n";
echo "auto commit ON from ON\n";
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
echo "Success\n\n";
echo "auto commit OFF from ON\n";
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
echo "Success\n\n";
echo "auto commit OFF from OFF\n";
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
echo "Success\n\n";
echo "auto commit ON from OFF\n";
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
echo "Success\n\n";
echo "========== in transaction ==========\n";
echo "begin transaction\n";
$db->beginTransaction();
echo "\n";
echo "auto commit ON from ON, expect error\n";
try {
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
} catch (PDOException $e) {
echo $e->getMessage()."\n\n";
}
echo "auto commit OFF from ON, expect error\n";
try {
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
} catch (PDOException $e) {
echo $e->getMessage()."\n\n";
}
echo "end transaction\n";
$db->rollback();
echo "auto commit OFF\n";
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
echo "begin transaction\n";
$db->beginTransaction();
echo "\n";
echo "auto commit ON from OFF, expect error\n";
try {
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
} catch (PDOException $e) {
echo $e->getMessage()."\n\n";
}
echo "auto commit OFF from OFF, expect error\n";
try {
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
} catch (PDOException $e) {
echo $e->getMessage()."\n\n";
}
echo "end transaction\n";
$db->rollback();
echo "\n";
echo "done!";
?>
--EXPECT--
========== not in transaction ==========
auto commit ON from ON
Success
auto commit OFF from ON
Success
auto commit OFF from OFF
Success
auto commit ON from OFF
Success
========== in transaction ==========
begin transaction
auto commit ON from ON, expect error
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open
auto commit OFF from ON, expect error
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
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open
auto commit OFF from OFF, expect error
SQLSTATE[HY000]: General error: Cannot change autocommit mode while a transaction is already open
end transaction
done!