【问题标题】:"String data, right truncation" via ODBC but not via SQL Server Manager with the same query“字符串数据,右截断”通过 ODBC 但不是通过具有相同查询的 SQL Server 管理器
【发布时间】:2014-02-06 14:44:40
【问题描述】:

我在一台服务器上有一个 LAPP 堆栈,而在另一台服务器上运行 MSSQL。前者通过微软的ODBC Driver 1.0 for Linux连接到后者,一般都运行良好。

如果查询字符串太长,我们的一个搜索页面失败并出现以下错误:

Couldn't execute statement: [unixODBC][Microsoft][SQL Server Native Client 11.0]String data, right truncation (SQL-22001)

但是,如果我复制查询,将其粘贴到连接到同一数据库的 MS SQL Server 管理器查询窗口中,将所有 ? 占位符替换为我的脚本传递给 $sth->execute() 的内容,然后运行它,它不会产生错误。

这是为什么? (这是否表明 ODBC 驱动程序或 SSM 中存在错误,或者只是两者之间的差异?)

更好的是,或者我想我的最终目标是:我怎样才能让我的脚本表现得像 SSM 一样?目前我能看到的唯一解决方法是遍历每一列(并且有很多,它是跨 5 个查询的联合,每个查询都有许多表连接)并找出每个 varchar 列的长度是查询字符串可能every 太长了,然后按长度区分所有占位符。 IE。我必须自己进行截断并且还有另一个代码依赖项——例如,当我们的数据库供应商决定延长一列时,我必须去减少该列出现的任何脚本中的截断。不能 ODBC司机像 SSM 一样“工作”,没有抱怨?

如果我启用跟踪,我会得到每个占位符中的一个:

-dbd_bind_ph=rebind_param
+rebind_param 7 '%aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%' (size svCUR=43/SvLEN=48/max=0) svtype:8, value type:1, sql type:0
+get_param_type(7f22ca950e88,7)
  bind 7 '%aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' value_len=43 maxlen=47 null=0)
  bind 7 value_type:1 VARCHAR cs=20 dd=0 bl=43
-rebind_param
+dbd_bind_ph(7f22ca950e88, name=8, value='%aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%', attribs=, sql_type=0(unknown), is_inout=0, maxlen=0
  First bind of this placeholder

似乎cs=... 有所不同,并且似乎对应于我在这种情况下可以避免的最大占位符大小。有没有办法访问那个cs 值,所以我可以在绑定它之前限制该值,但是动态地这样我就没有这些额外的代码依赖项?也许这就是 SSM 自动执行的操作?

更新:我发现在DBD::ODBC::FAQ under "Why am I getting errors with bound parameters?"下的“数据截断错误”下或多或少地描述了这个问题。我必须遍历每个参数以将其修复为 SQLDescribeParam 返回的长度(减 2,因此我可以在开头和结尾添加“%”符号以进行搜索),这真的是真的吗……但是如果我使用任何类型的连接,这甚至不能保证工作,因为它可能会弄错长度?这张图有什么问题?

UPDATE2:我刚刚发现here,“如果您正在使用 Microsoft SQL Server ODBC Driver 1.0 for Linux,您应该升级到 Microsoft ODBC Driver 11 for SQL Server。”去尝试一下...UPDATE2.5在最新的libmsodbcsql-11.0.so.2270.0 驱动程序上,它也表现出这种行为。

【问题讨论】:

  • 是否有另一个更新版本的 ODBC 驱动程序.. 尝试安装可能会解决问题。
  • 构建是 sqlncli-11.0.1790.0,但我在 ODBC 驱动程序团队的博客上没有看到任何更新。
  • 我认为你正在使用 Perl,因为你说的是​​ $sth->execute()。如果您是并且您正在使用相对较新的 DBI 和 DBD::ODBC,那么“export DBI_TRACE=DBD=x.log”然后运行您的脚本。如果 x.log 中没有任何内容,将“DBD”更改为 15 并重复。错误周围的日志是什么样的?字符串数据右截断不太可能是因为你的sql太长了。
  • @bohica 是的,对不起,我忘记了后者 P 不一定是 Perl。日志看起来很冗长,你在找什么?我不是说 SQL 太长,而是占位符数据太长,比如你把WHERE COLUMNA LIKE '...' 并让... 比COLUMNA 定义的要长。
  • 抱歉,日志不足以诊断问题。你能把完整的日志或帖子发给我(cpan dot org 的 mjevans)吗?

标签: sql sql-server linux perl odbc


【解决方案1】:

感谢 bohica,DBD::ODBC 现在导出了一个函数 odbc_describe_param,该函数公开了解决 uber-text-search 情况的必要信息:

# $sth is an already-prepared statement
for (1..(scalar keys %{$sth->{ParamTypes}})) {
    my @help = $sth->odbc_describe_param($_);
    if ($help[1]) { # like SQLDescribeParam API - i.e., type, size, decimal digital and nullable
        $sth->bind_param($_, '%' . substr($s, 0, $help[1] - 2) . '%');
    } else { # 0 = false = unlimited length allowed
        $sth->bind_param($_, '%' . $s . '%');
    }
}
$sth->execute();
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    相关资源
    最近更新 更多