由于自动数据类型转换导致的NULL值和数据截断

时间:2018-01-22 08:22:40

标签: php sql-server pdo doctrine-orm sqlsrv

我们正在从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?

0 个答案:

没有答案