我们目前在内存数据库中遇到一个使用PDO和SQLite的奇怪错误。
这是重现问题的代码的和平。
执行以下PHP代码
<?php
// Gets a PDO reference with in memory SQLite (i.e using the 'sqlite::memory:' dsn)
$pdo = new \PDO('sqlite::memory:', 'sa', '');
$pdo->exec(
'CREATE TABLE IF NOT EXISTS scheduled_task' .
'(' .
'id INTEGER NOT NULL,' .
'date_and_time INTEGER NOT NULL,' .
'task_class VARCHAR(256) NOT NULL,' .
'task_parameters VARCHAR(1024) NOT NULL' .
')'
);
// Just a statement to count rows in our table
$pdoStatementCount = $pdo->prepare('select count(*) from scheduled_task');
// At first ensure our table is empty
$pdoStatementCount->execute();
var_dump('At beginning table has size \'' . intval($pdoStatementCount->fetchColumn()) . '\'.');
// Insert 2 rows inside our table
$pdoStatementInsert = $pdo->prepare(
'insert into scheduled_task(id, task_class, date_and_time, task_parameters) values(?,?,?,?)'
);
$pdoStatementInsert->execute([1, 'tk1', '2015-01-01', '{}']);
$pdoStatementInsert->execute([2, 'tk2', '2015-01-02', '{}']);
// Ensure the 2 rows were inserted
$pdoStatementCount->execute();
var_dump('Then table has size \'' . intval($pdoStatementCount->fetchColumn()) . '\'.');
// Now create a statement to select only the first row
$pdoStatementSelect1 = $pdo->query('select * from scheduled_task where date_and_time < \'2015-01-02\'');
// Here it seems their is a bug with the Iterator associated to the PDO Statement
foreach($pdoStatementSelect1 as $row) {
var_dump($row['id']);
// Inserts a new row inside our table
$pdoStatementInsert = $pdo->prepare(
'insert into scheduled_task(id, task_class, date_and_time, task_parameters) values(?,?,?,?)'
);
if($pdoStatementInsert->execute([3, 'tk3', '2015-01-01', '{}']) === false) {
var_dump('Fail inserting row in loop !');
var_dump($pdoStatementInsert->errorCode());
var_dump($pdoStatementInsert->errorInfo());
}
// Deletes the first row
$pdo->query('delete from scheduled_task where id = ' . $row['id']);
}
// This fails with SQLite, we should have 2 rows inside our table here
$pdoStatementCount->execute();
var_dump('At the end table has size \'' . intval($pdoStatementCount->fetchColumn()) . '\'.');
此测试的输出如下:
string(32) "At beginning table has size '0'."
string(24) "Then table has size '2'."
string(1) "1"
string(1) "3"
string(30) "At the end table has size '1'."
结论,PDO SQLite中的错误?
请注意,我们的foreach循环执行2次而不是1次。因此我们循环中使用的PDOStatement对象似乎已更新(不知道如何),因为我们在循环中插入了一个新行。
如果我们将PDO实例更改为使用MySQL,那么它可以工作,所以我认为这个bug只与SQLite有关。
虽然如果我将循环内部的插入指令更改为此(即日期与我们的选择不匹配),那么它可以正常工作。
$pdoStatementInsert->execute([3, 'tk3', '2015-01-02', '{}'])
因此它与SQLite PDOStatement一样透明地执行新的选择查询......
你知道为什么我们会遇到这种行为吗?你认为这是正常的吗?如果不是,我们必须在https://bugs.php.ne报告?
最终答案 - 这不是一个错误 见https://bugs.php.net/bug.php?id=72267&edit=2 谢谢你的帮助!
感谢。