【发布时间】:2016-08-08 20:30:15
【问题描述】:
问题
当至少一个参数超过 30 个字符时,使用 PDO 和 ODBC 驱动程序使用准备好的语句执行插入会产生以下错误:
SQLSTATE[HY010]: Function sequence error: 0
[unixODBC][Driver Manager]Function sequence error (SQLExecute[0] at /usr/src/builddir/ext/pdo_odbc/odbc_stmt.c:254)
插入适用于长度为
SELECT 查询我没有任何问题。
将INSERT 与isql 和sqlcmd 一起使用不会产生错误,但如果列值超过30 个字符,则会在数据库中截断。
这似乎是驱动程序问题。
关于导致问题的原因以及如何解决问题的任何想法?
示例
以下是在我的系统上用 PHP、isql 和 sqlcmd 复制错误的最小示例。
使用的表(称为table)有三列:
colvarchar varchar(70)colnvarchar nvarchar(40)colnchar nchar(60)
以及产生错误的代码:
<?php
$dns = 'odbc:testdb';
$username = 'user';
$password = 'pass';
$pdo = new PDO($dns, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = <<<'QUERY'
INSERT INTO table
(colvarchar, colnvarchar, colnchar)
VALUES
(CAST(:colvarchar AS varchar)
CAST(:colnvarchar AS nvarchar),
CAST(:colnchar AS nchar));
QUERY;
$prepStmt = $pdo->prepare($sql);
// Add one more characters to any of the following strings to cause the error
$prepStmt->bindValue('colvarchar', '012345678901234567890123456789');
$prepStmt->bindValue('colnvarchar', '012345678901234567890123456789');
$prepStmt->bindValue('colnchar', '012345678901234567890123456789');
$prepStmt->execute();
?>
在 30 个字符串中的任何一个中添加额外的字符都会导致以下错误:
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY010]: Function sequence error: 0 [unixODBC][Driver Manager]Function sequence error (SQLExecute[0] at /usr/src/builddir/ext/pdo_odbc/odbc_stmt.c:254)' in ...
在命令行中使用isql 和sqlcmd 执行插入,但在表格中选择显示字符串被截断为30 个字符。
slqcmd:
sqlcmd -D -S testdb -U user -P pass -q "INSERT INTO table (colvarchar, colnvarchar, colnchar) 值 (CAST('012345678901234567890123456789xxx' AS varchar), CAST('012345678901234567890123456789xxx' AS nvarchar), CAST('012345678901234567890123456789xxx' AS nchar))"
(受影响的 1 行)
isql:
isql testdb -U 用户 -P 通过
SQL> INSERT INTO 表(colvarchar, colnvarchar, colnchar) 值 (CAST('012345678901234567890123456789xxx' AS varchar), CAST('012345678901234567890123456789xxx' AS nvarchar), CAST('012345678901234567890123456789xxx' AS nchar))"
SQLRowCount 返回 1
结果:
SELECT colvarchar, colnvarchar, colnchar FROM table;
colvarchar | colnvarchar | colnchar
012345678901234567890123456789 | 012345678901234567890123456789 | 012345678901234567890123456789
012345678901234567890123456789 | 012345678901234567890123456789 | 012345678901234567890123456789
研究
此post 详细介绍了与不符合最大列宽、时间戳格式或列类型的插入类似的问题。
- 时间戳格式已经过测试并且可以正常工作,因为它少于 30 个字符。
- 已检查超过 30 个字符的测试字符串,以确保其长度小于其列的最大宽度。
- 有问题的列的数据类型是
varchar。
系统设置
- 操作系统:Debian wheezy(64 位)
- 数据库:Microsoft SQL Server 2014
- 网络服务器:Apache 2.2.22(64 位)
- 带有 Zend 线程安全的 PHP 5.6.24(64 位)
- Microsoft ODBC 驱动程序 11.0.2270.0(红帽 Linux)(64 位)
- 根据this blog和spiceworks创建了合适的环境来使用Debian
- unixODBC 2.3.0(64 位)
- Linux 上的 MS ODBC 驱动程序需要
更新:
我认为这是一个 unixODBC 问题,因为在我使用 FreeTDS 和 unixODBC 时出现了 30 个字符的截断(由于这个问题,它已更改为 MS ODBC 和 unixODBC)。不同的是使用 FreeTDS 时没有错误消息;它像isql 和sqlcmd 目前正在做的那样默默地失败了。
将 unixODBC 版本从 2.3.4 更改为 2.3.0,以便与 MS ODBC 11 兼容,如图 here。问题仍然存在。
所有需要 ODBC 共享库的程序都链接到 2011 年的版本。它们现在都链接到来自 unixODBC 的最新共享库的更新。问题仍然存在。
【问题讨论】:
-
您能否展示一个引发错误的代码的最小示例?以及问题列的定义?它是“varchar”还是“nvarchar”列?
-
@erg 我按照您的建议添加了一个最小示例。 unixODBC 配置也有用吗?
标签: php sql-server linux odbc unixodbc