插入参数超过30个字符时出错

时间:2016-08-08 20:30:15

标签: php sql-server linux odbc unixodbc

问题

使用带有PDO和ODBC驱动程序的预准备语句执行插入时,如果至少有一个参数超过30个字符,则会出现以下错误:

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查询没有任何问题。

INSERTisqlsqlcmd一起使用不会产生错误,但如果超过30个字符,则会在数据库中截断列值。

这似乎是一个驱动程序问题。

关于导致问题的原因以及如何解决问题的任何想法?

示例

以下是使用PHP isqlsqlcmd复制系统错误的最小示例。

使用的表(称为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 ...

从命令行使用isqlsqlcmd执行插入,但表中的select显示字符串被截断为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))“

     

(受影响的一行)

ISQL:

  

isql testdb -U user -P pass

     

SQL&GT; 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位)
  • PHP 5.6.24,Zend线程安全(64位)
  • Microsoft ODBC驱动程序11.0.2270.0(Red Hat Linux)(64位)
  • unixODBC 2.3.0(64位)
    • Linux上的MS ODBC驱动程序所需

更新 我相信这是一个unixODBC问题,因为当我使用FreeTDS和unixODBC(因为这个问题而改为MS ODBC和unixODBC)时出现了30个字符的截断。不同之处在于使用FreeTDS时没有错误消息;它像isqlsqlcmd目前一样无声地失败。

将unixODBC版本从2.3.4更改为2.3.0,因为它与MS ODBC 11兼容,如here所示。问题仍然存在。

所有需要ODBC共享库的程序都链接到2011年的版本。它们现在都与unixODBC的日期更新共享库相关联。问题仍然存在。

2 个答案:

答案 0 :(得分:1)

您在SQL-Server

中CAST到NVARCHAR和NVARCHAR限制为30个字符

像这样制作演员:      CAST(colvarchar AS varchar(70))      CAST(colnvarchar AS nvarchar(40))      CAST(colnchar AS nchar(60))

答案 1 :(得分:0)

问题在于SQL CAST表达式。

来自MSDN - CAST & CONVERT

  

截断和舍入结果

     

转换字符或二进制表达式时(char,nchar,   nvarchar,varchar,binary或varbinary)到a的表达式   不同的数据类型,数据可以被截断,只能部分显示,   或者返回错误,因为结果太短而无法显示。

文档列出了保证不会被截断的特定异常。但是,它没有详细说明将截断的长度数据。

指定数据类型长度以避免截断:

CAST (colvarchar  AS varchar(70))
CAST (colnvarchar AS nvarchar(40))
CAST (colnchar    AS nchar(60))