2011-07-06 33 views
3

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

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 
+0

我不使用DBD :: Sybase,但使用其他DBD的负载。如果没有更多的信息,我怀疑有人会回答这个问题,除非它是一个已知的错误。至少在发布一些调用该过程的Perl后,列出应该返回的数据的模式和示例以及如何获取它。 – bohica

+0

这是一个FreeTDS警告。我们不知道的是DBD :: Sybase是否在内部做出错误的假设,是否可以用聪明的SQL来包装存储过程调用以强制进行正确的类型转换等等。 打开[“function trace and信息“](http://www.freetds.org/userguide/freetdsconf.htm)在您的驱动程序中进行调试,您应该了解哪些源类型和八位字节长度正在转换为目标类型和八位字节长度。 – pilcrow

+1

嗨,我已经做了你所问的,我相信我找到了罪魁祸首。 FreeTDS试图做的是试图将BigInt值(它是一个10位数字)转换为长度为9个字节的字符串。由于数值超过9位,所以会出现溢出。我不知道这个错误是来自数据库端还是它是FreeTDS中的错误。对于我使用FreeTDS 0.82的记录 – Dan

回答

2

的问题是在freetds的一面。我以前遇到过同样的问题,并通过在select语句中将返回的字段转换为varchar来成功解决此问题。

由于您无权修改原始查询,因此您可以执行一些正则表达式搜索并替换代码中返回的$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(或有权访问存储过程的任何人)直接修改实际查询。

希望这会有所帮助。