假设我正在使用以下内容查询表:
$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它的寂寞呢?
根据您的数据库驱动程序,您可以*在以下位置使用类型提示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::Oracle并DBD::ODBC支持它,并DBD::Pg 可能支持它,根据这个线程(虽然我无法验证它),而DBD::mysql不是.我不确定其他车手.
虽然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做(因为我添加了它们).
您可能也会发现这很有趣.
| 归档时间: |
|
| 查看次数: |
473 次 |
| 最近记录: |