问题
当至少有一个参数超过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)
插入<=的任何绑定字符串的工作长度为30个字符。
我对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表(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
研究
这篇文章详细介绍了一个类似的问题,即插入不符合最大列宽、时间戳格式或列类型。
- 时间戳格式已经过测试,并且确实有效,因为它少于30个字符
- 已经检查了超过30个字符的测试字符串,以确保它们的长度小于列的最大宽度
- 问题列的数据类型为
varchar
系统设置
- 操作系统:Debian喘息(64位(
- 数据库:Microsoft SQL Server 2014
- Web服务器:Apache 2.2.22(64位(
- PHP 5.6.24与Zend线程安全(64位(
- Microsoft ODBC驱动程序11.0.2270.0(Red Hat Linux((64位(
- 根据这个博客和spiceworks创建了合适的环境来与Debian合作
- unixODBC 2.3.0(64位(
- linux上的MS ODBC驱动程序所需
更新:我认为这是一个unixODBC问题,因为当我使用FreeTDS和unixODBC时,出现了30个字符的截断(因为这个问题,它被更改为MS ODBC和unixODBC.(。不同的是,使用FreeTDS时没有错误消息;它像CCD_ 14和CCD_。
为了与MS ODBC 11兼容,将unixODBC版本从2.3.4更改为2.3.0,如下所示。问题仍然存在。
所有需要ODBC共享库的程序都链接到了2011年的版本。它们现在都链接到unixODBC中最新的共享库。问题仍然存在。
您CAST到NVARCHAR,并且NVARCHAR在SQL Server 中限制为30个字符
制作演员阵容如下:CAST(colvarchar AS varchar(70((CAST(colnvarchar AS nvarchar(40((CAST(colnchar AS nchar(60((
问题在于SQL CAST
表达式。
来自MSDN-CAST&转换:
截断和舍入结果
当您转换字符或二进制表达式(char、nchar、,nvarchar、varchar、binary或varbinary(转换为不同的数据类型,数据可以被截断,仅部分显示,或者由于结果太短而无法显示而返回错误。
文档列出了保证不会被截断的特定例外情况。然而,它也没有详细说明将截断的长度数据。
指定数据类型长度以避免截断:
CAST (colvarchar AS varchar(70))
CAST (colnvarchar AS nvarchar(40))
CAST (colnchar AS nchar(60))