DBI :: Sybase数据转换导致溢出

时间:2011-07-06 20:45:01

标签: perl sybase dbi freetds

我正在编写一个使用DBI模块并连接到Sybase DB的Perl脚本。我正在调用一个存储过程(一个我无法访问的存储过程,所以我无法发布示例代码),当我收到数据时,我收到一条错误,上面写着“error_handler:数据转换导致溢出”。我仍然得到数据,经过一些深入的研究后,似乎列中的一些数据类型(如BigInt,nvarchar等)是罪魁祸首。现在的问题是,我该如何解决这个问题?这可以在客户端修复,还是只能在服务器端修复?

my $dbh = DBI->connect("DBI:Sybase:server=$server", $username, $password, {PrintError => 0}) or die;
$dbh->do("use $database") or die;
my $sql = &getQuery;
my $sth = $dbh->prepare($sql) or die;
$sth->execute() or die;
while ($rowRef = $sth->fetchrow_arrayref) #Error seems to occur here
{
     #Parse through each row
}

解释问题的FreeTDS 0.82日志的一部分:

_ct_bind_data(): column 7 is type 38 and has length 8
_ct_get_server_type(0)
_ct_get_client_type(type 38, user 0, size 8)
cs_convert(0x18dfed40, 0x7fff73216050, 0x18e44250, 0x7fff73215fa0, 0x18e387c0, 0x18e45a64)
_ct_get_server_type(30)
_ct_get_server_type(0)
converting type 127 (8 bytes) to type = 47 (9 bytes)
cs_convert() calling tds_convert
cs_convert() tds_convert returned 10
cs_prretcode(0)
cs_convert() returning  CS_FAIL
cs_convert-result = 1

1 个答案:

答案 0 :(得分:2)

问题出在FreeTDS方面。我之前遇到过同样的问题,并通过将返回的字段转换为varchar语句中的select来成功修复它。

鉴于您无权修改原始查询,您可以执行一些正则表达式搜索并替换代码中返回的$sql变量。特别是,如果原始查询的部分看起来像

SELECT field1, field2, field3 FROM ...

检索查询语句后,您可以运行

my $new_sql;
if ($sql =~ /SELECT\s+(.*)\s+FROM/i) {  # match selected field string
    my $field_str = $1;
    my @fields = split ",", $field_str; # parse individual fields
    map s/\s//g, @fields;               # get rid of spaces
    my $new_str = join ", ", (map {sprintf "convert(varchar, $_)"} @fields);    # construct new query string
    my $quoted_field_str = quotemeta($field_str);   # prepare regex replacement string
    $new_sql = $sql;    
    $new_sql =~ s/$quoted_field_str/$new_str/i  # actual replacement
}
print $new_sql;

当然,如果您的原始陈述更复杂,您应该将其打印出来并检查如何使用具有相同精神的通用替换来修改它。或者,您可以要求您的DBA(或有权访问存储过程的人)直接修改实际查询。

希望这会有所帮助。