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

Ric*_*ões 7 perl dbi

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

$dbh->selectrow_hashref('SELECT id, name FROM foos WHERE name = "bar"');
Run Code Online (Sandbox Code Playgroud)

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

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

Thi*_*Not 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;
}
Run Code Online (Sandbox Code Playgroud)

这会尝试将第一列(从一个索引)绑定到该SQL_INTEGER类型,并在转换为任何值失败时抛出错误.正如bohica所说,该DiscardString属性是必要的,因为它"抛弃了数据的字符串部分(pv)."


*根据DBI文档:

很少有驱动程序支持通过bind_col调用指定数据类型(大多数将简单地忽略数据类型).

DBD::OracleDBD::ODBC支持它,并DBD::Pg 可能支持它,根据这个线程(虽然我无法验证它),而DBD::mysql不是.我不确定其他车手.


boh*_*ica 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});
Run Code Online (Sandbox Code Playgroud)

注意几乎没有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做(因为我添加了它们).

您可能也会发现很有趣.