我在一台服务器上有一个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 Manager查询窗口中,则将所有?
占位符替换为我的脚本传递给$sth->execute()
的所有占位符,并且运行它,它不会产生错误。
这是为什么? (这是表示ODBC驱动程序或SSM中的错误,还是两者之间存在差异?)
更好的是,或者我认为我的最终目标是:我怎样才能使我的脚本像SSM那样行事?目前我能看到的唯一修复是遍历每一列(并且有很多,它是5个查询之间的联合,每个查询都有许多表连接)并找出每个varchar列的长度是查询字符串可能的长度每个都太长,然后按长度区分所有占位符。即我必须自己进行截断并且还有另一个代码依赖 - 例如,当我们的数据库供应商决定延长列时,我必须去减少列出现的任何脚本中的截断。不能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,“如果您使用的是用于Linux的Microsoft SQL Server ODBC驱动程序1.0,则应升级到SQL Server的Microsoft ODBC驱动程序11。 “关于在最新的libmsodbcsql-11.0.so.2270.0
驱动程序上尝试... UPDATE2.5 ,它也会出现此行为。
答案 0 :(得分:0)
感谢bohica,DBD :: ODBC现在导出一个函数odbc_describe_param
,它为超文本搜索情况的变通方法公开了必要的信息:
# $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();
...