DBI::sql_type_cast:DBIstcf_DISCARD_STRING - 问题

发布于 2024-10-21 21:08:58 字数 865 浏览 4 评论 0原文

我的希望是,带有 DBIstcf_DISCARD_STRING 标志的 DBI::sql_type_cast 会将 $sv 从“4.8g”修改为 4.8。

DBIstcf_DISCARD_STRING: “如果指定了此标志,那么当驱动程序成功地将绑定的 perl 标量转换为非字符串类型时,标量的字符串部分将被丢弃。”)

返回值 sv 不能为 case 和DBIstcf_STRICT 没有使用 是什么意思?

#!/usr/bin/env perl
use warnings;
use 5.012;
use DBI qw(:sql_types);

my $dsn = "DBI:Proxy:hostname=horst;port=2000;dsn=DBI:ODBC:db1.mdb";
my $dbh = DBI->connect( $dsn, undef, undef, { RaiseError => 1, PrintError => 0 } )
or die $DBI::errstr;

my $sv = '4.8g';
my $sql_type = SQL_DOUBLE;
my $flags = DBIstcf_DISCARD_STRING;

my $sts = DBI::sql_type_cast( $sv, $sql_type, $flags );

say $sts; # 1 (sv could not be case and DBIstcf_STRICT was not used)

say $sv;


# Argument "4.8b" isn't numeric in subroutine entry at ./perl6.pl line 14.
# 1
# 4.8b

My hope was, that DBI::sql_type_cast with the DBIstcf_DISCARD_STRING-flag would modify $sv from '4.8g' to 4.8.

(DBIstcf_DISCARD_STRING:
"If this flag is specified then when the driver successfully casts the bound perl scalar to a non-string type then the string portion of the scalar will be discarded.")

What does the return-value sv could not be case and DBIstcf_STRICT was not used mean?

#!/usr/bin/env perl
use warnings;
use 5.012;
use DBI qw(:sql_types);

my $dsn = "DBI:Proxy:hostname=horst;port=2000;dsn=DBI:ODBC:db1.mdb";
my $dbh = DBI->connect( $dsn, undef, undef, { RaiseError => 1, PrintError => 0 } )
or die $DBI::errstr;

my $sv = '4.8g';
my $sql_type = SQL_DOUBLE;
my $flags = DBIstcf_DISCARD_STRING;

my $sts = DBI::sql_type_cast( $sv, $sql_type, $flags );

say $sts; # 1 (sv could not be case and DBIstcf_STRICT was not used)

say $sv;


# Argument "4.8b" isn't numeric in subroutine entry at ./perl6.pl line 14.
# 1
# 4.8b

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

多情癖 2024-10-28 21:08:58
  1. 文档包含一个拼写错误 - $sts == 1 的描述应该是“sv 无法cast” - 即强制转换为 SQL_DOUBLE 对于您提供的值来说是不可能的,因此没有执行任何操作。

  2. DBIstcf_DISCARD_STRING 的含义与您想要的不同。在 Perl 内部术语中,这意味着如果您传递带有 POKNOK 的 SV 以及 PV 部分 "1.23" 和 NV 部分 1.23,您将得到一个带有 !POKNOK 的 SV 以及 NV 部分 1.23——即存储的字符串部分标量的值将失效,而数字部分保持不变,因此以后任何将标量用作字符串的尝试都将强制其从数字重新转换为字符串。但请注意,它表示只有如果转换成功,才会发生这种情况,并且如果该值不是有效的开始数字,则转换为 SQL_DOUBLE 不会成功和。 “4.8g”未通过测试。

  3. 您可以通过执行 $sv = 0 + $sv; 来清除值的字符串部分,几乎与您自己的 DBI 一样有效,这将清除 < code>POK 并以相同的方式强制重新转换为字符串。这与 DBI 所做的不同之处在于,它实际上并没有像 DBI 那样清除 PV,而只是将其标记为无效。要以与 DBI 相同的方式强制立即清除该值,您需要执行类似

    的操作

    $sv = do { 我的 $tmp = 0 + $sv; undef $sv; $tmp };

    但是除非你对为什么需要它有一些非常好的解释,否则你不需要——所以不要使用它。 :)

  1. The documentation contains a typo -- the description for $sts == 1 should be "sv could not be cast" -- i.e. a cast to SQL_DOUBLE wasn't possible for the value you provided and so nothing was done.

  2. DBIstcf_DISCARD_STRING means something different from what you want. In Perl internal terms it means that if you pass an SV with POK and NOK and PV part "1.23" and NV part 1.23, you will get back an SV with !POK and NOK and NV part 1.23 -- that is, the stored string part of the scalar will be invalidated, leaving the numeric part intact, so any future attempt to use the scalar as a string will force it to be re-converted from a number to a string. But note that it says that this will only happen if the cast is successful, and a cast to SQL_DOUBLE isn't successful if the value isn't a valid number to begin with. "4.8g" doesn't pass the test.

  3. You can clean up the string part of the value almost as effectively as DBI on your own just by doing $sv = 0 + $sv; which will clear POK and force a reconversion to string in the same way. The difference between this and what DBI does is that it's not actually clearing the PV in the way that DBI would, only marking it invalid. To force the value to be cleared immediately in the same way as DBI, you need to do something like

    $sv = do { my $tmp = 0 + $sv; undef $sv; $tmp };

    but unless you have some really good explanation for why you need that, you don't -- so don't use it. :)

薄凉少年不暖心 2024-10-28 21:08:58

阅读完文档和 DBI.xs 中的代码后(实现位于 sql_type_cast_svpv 中),返回值 1 表示“无法干净地转换该值并且未使用 DBIstcf_STRICT”。

根据您的情况,采用该功能的关键部分:

case SQL_DOUBLE:
    sv_2nv(sv);
    /* SvNOK should be set but won't if sv is not numeric (in which
     * case perl would have warn'd already if -w or warnings are in effect)
     */
    cast_ok = SvNOK(sv);
    break;

....

if (cast_ok) {

    if (flags & DBIstcf_DISCARD_STRING
    && SvNIOK(sv)  /* we set a numeric value */
    && SvPVX(sv)   /* we have a buffer to discard */
    ) {
        SvOOK_off(sv);
        if (SvLEN(sv))
            Safefree(SvPVX(sv));
        SvPOK_off(sv);
        SvPV_set(sv, NULL);
        SvLEN_set(sv, 0);
        SvCUR_set(sv, 0);
    }
}

if (cast_ok)
    return 2;

应该为您设置 SvNOK。在不进一步深入研究 sv_2nv 的情况下,问题的核心是“4.8g”不是数字类型,因为标量值中的数字标志未设置(这是 SvNOK 检查的内容)。

我的建议是,在调用 sql_type_cast 之前使用正则表达式去除该输入。

After reading through the documentation and the code in DBI.xs (the implementation is in sql_type_cast_svpv), the return value of 1 means 'the value could not be cast cleanly and DBIstcf_STRICT was not used'.

Taking the key part of that function, in your case:

case SQL_DOUBLE:
    sv_2nv(sv);
    /* SvNOK should be set but won't if sv is not numeric (in which
     * case perl would have warn'd already if -w or warnings are in effect)
     */
    cast_ok = SvNOK(sv);
    break;

....

if (cast_ok) {

    if (flags & DBIstcf_DISCARD_STRING
    && SvNIOK(sv)  /* we set a numeric value */
    && SvPVX(sv)   /* we have a buffer to discard */
    ) {
        SvOOK_off(sv);
        if (SvLEN(sv))
            Safefree(SvPVX(sv));
        SvPOK_off(sv);
        SvPV_set(sv, NULL);
        SvLEN_set(sv, 0);
        SvCUR_set(sv, 0);
    }
}

if (cast_ok)
    return 2;

SvNOK should be set for you. Without digging in further into sv_2nv, the core of the problem is that "4.8g" is not a numeric type, as the numeric flag in the scalar value is not set (this is what SvNOK checks for).

My suggestion, use a regular expression to strip that input before calling sql_type_cast.

情绪操控生活 2024-10-28 21:08:58

文档中的拼写错误现已在 subversion 主干中修复。

这里简单解释一下为什么要添加sql_type_cast。

尽管没有什么可以阻止您使用 sql_type_cast,但它是专门为驱动程序 (DBD) 添加的,用于转换从数据库返回的数据。它解决的最初问题是整数大多被绑定为字符串,因此当从数据库返回数据时,标量的 pv 被设置。像 JSON::XS 这样的一些模块很聪明,可以查看 pv 来帮助确定标量是否是一个数字。如果没有 sql_type_cast,JSON::XS 会转换包含 1 的标量,但 pv 设置为“1”,而不是 JSON 转换中较短的 1。

据我所知,目前只有 DBD::Oracle 执行此操作,尽管它位于 DBD::ODBC 的 TODO 中。

The typo in the documentation is now fixed in the subversion trunk.

Here is a brief explanation of why sql_type_cast was added.

Although there is nothing to stop you using sql_type_cast it was specifically added for drivers (DBDs) to cast data returned from the database. The original issue it solved was that integers are mostly bound as strings so when the data is returned from the database the scalar's pv is set. Some modules like JSON::XS are clever and look at the pv to help decide if the scalar is a number of not. Without the sql_type_cast JSON::XS was converting a scalar containing a 1 but with the pv set to "1" instead of the shorter 1 in JSON conversions.

To my knowledge only DBD::Oracle does this right now although it is in the TODO for DBD::ODBC.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文