【问题标题】:Error during insert with parameter(s) over 30 characters插入参数超过 30 个字符时出错
【发布时间】: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 查询我没有任何问题。

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 执行插入,但在表格中选择显示字符串被截断为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 位)
  • unixODBC 2.3.0(64 位)
    • Linux 上的 MS ODBC 驱动程序需要

更新: 我认为这是一个 unixODBC 问题,因为在我使用 FreeTDS 和 unixODBC 时出现了 30 个字符的截断(由于这个问题,它已更改为 MS ODBC 和 unixODBC)。不同的是使用 FreeTDS 时没有错误消息;它像isqlsqlcmd 目前正在做的那样默默地失败了。

将 unixODBC 版本从 2.3.4 更改为 2.3.0,以便与 MS ODBC 11 兼容,如图 here。问题仍然存在。

所有需要 ODBC 共享库的程序都链接到 2011 年的版本。它们现在都链接到来自 unixODBC 的最新共享库的更新。问题仍然存在。

【问题讨论】:

  • 您能否展示一个引发错误的代码的最小示例?以及问题列的定义?它是“varchar”还是“nvarchar”列?
  • @erg 我按照您的建议添加了一个最小示例。 unixODBC 配置也有用吗?

标签: php sql-server linux odbc unixodbc


【解决方案1】:

您 CAST 到 NVARCHAR 并且 NVARCHAR 在 SQL-Server 中被限制为 30 个字符

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

【讨论】:

  • 这是由于转换中未指定数据类型长度,尽管它不仅限于 nvarchar。请参阅此处:msdn.microsoft.com/en-CA/library/ms187928.aspx。
【解决方案2】:

问题在于 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))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多