我们正在从FreeTDS迁移到Doctrine PDOSQLSrv或SQLSrv(同时尝试两者)并且遇到了未更新字段的数据截断问题。
我们的更新语句类似于
update tbl set field1 = isnull(?, field1), field2 = isnull(?, field2) where id = ?
我们调查过它是由数据类型转换引起的。 FreeTDS按原样运行查询,因此当您传递NULL值时,将使用NULL。但是,PDOSQLSrv和SQLSrv使用sp_prepexec存储过程运行查询,因此它不再是NULL,而是NULL值变量。
不幸的是,两个库都将PHP空值转换为char(1)(在文档https://docs.microsoft.com/en-us/sql/connect/php/default-sql-server-data-types中,它被称为varchar(1),但它仍然没有帮助,我可以看到char(1)在Profiler),所以当字段没有更新并且我们传递NULL时,它会截断数据。
完整代码示例:
use Doctrine\DBAL\DriverManager;
include_once __DIR__ . '/vendor/autoload.php';
$connectionOptions = array_merge(
['driverClass' => '\Doctrine\DBAL\Driver\PDOSqlsrv\Driver'],
['host' => '127.0.0.1', 'port' => 1433, 'dbname' => 'users', 'user' => '', 'password' => '']
);
try {
$conn = DriverManager::getConnection($connectionOptions);
} catch (\Exception $e) {
die($e->getMessage());
}
$userId = 1;
$nick = 'test';
try {
$result = $conn->executeUpdate(
'UPDATE users.users SET user_nick = isnull(:nick, user_nick) WHERE user_id = :userId',
['nick' => $nick, 'userId' => $userId],
['nick' => \PDO::NULL_EMPTY_STRING, 'userId' => \PDO::PARAM_INT]
);
} catch (\Exception $e) {
die($e->getMessage());
}
所以问题是如何正确传递null?