获取行时,DBI可以推断或了解数字列类型吗?

时间:2014-03-27 19:14:18

标签: perl dbi

假设我正在使用以下内容查询表:

$dbh->selectrow_hashref('SELECT id, name FROM foos WHERE name = "bar"');

当然,id将是一个整数,但生成的hashref将在内部存储一个值作为Perl PV而不是IV。反过来,当将数据序列化为例如JSON时,这将产生不希望的结果。

当然,可以手动调用值0+,但有没有办法让DBI自动将其存储为实际整数,而不仅仅是一个看起来像数字的字符串?同样,DBIx::Class和朋友可以解决这个问题,但DBI寂寞呢?

2 个答案:

答案 0 :(得分:7)

根据您的数据库驱动程序, * 可以使用bind_col中的类型提示:

use DBI qw(:sql_types);

...

my $sth = $dbh->prepare('SELECT id, name FROM foos WHERE name = "bar"');
$sth->execute;

$sth->bind_col(1, undef, {
    TYPE => SQL_INTEGER,
    StrictlyTyped => 1,
    DiscardString => 1
});

while (my $hr = $sth->fetchrow_hashref) {
    say to_json $hr;
}

这会尝试将第一列(从一个索引)绑定到SQL_INTEGER类型,如果转换为任何值失败,则会抛出错误。作为bohica notesDiscardString属性是必需的,因为它会丢弃数据的字符串部分(pv)。"


*根据DBI文档:

  

很少有驱动程序支持通过bind_col调用指定数据类型(大多数会忽略数据类型)。

DBD::OracleDBD::ODBC支持它,而DBD::Pg 可能支持它,根据this thread(虽然我无法验证)它),而DBD::mysql没有。我不确定其他司机。

答案 1 :(得分:6)

虽然ThisSuitlsBlack几乎不正确,但他的回答有一些重要的遗漏。作为大多数StrictlyTyped和DiscardString属性的作者,我可以告诉你,事实上,DiscardString属性在这种情况下更为重要。

DBI将尝试将您的数据转换为指定的TYPE,如果失败,您的数据将保持不变,不会产生错误。如果强制转换失败并且指定了StrictlyTyped,则会生成错误。

DiscardString属性抛弃数据的字符串部分(pv)被丢弃。当使用JSON :: XS和其他JSON模块时,这一点尤为重要,因为JSON :: XS特别关注pv。

所以你至少应该这样做:

$sth->bind_col(1, undef, {TYPE => SQL_INTEGER, DiscardString => 1});

注意,很少有DBD实际关注bind_col中的绑定类型。 DBD :: ODBC是因为我维护它。 DBD :: Oracle通常不会注意TYPE,除非与StrictlyTyped和/或DiscardString一起使用(因为我为你提供了完全相同的问题而添加了该功能)。

驱动程序是否支持这些属性只能通过搜索代码使用sql_type_cast及其xs等价物sql_type_cast_svpv等来确定(除非文档说明),我不相信DBD: :Pg支持StrictlyTyped或DiscardString;事实上我相信在这个时候只有DBD :: ODBC和DBD :: Oracle做(因为我添加了它们)。

您可能还会发现this有趣。