DBI :: sql_type_cast:DBIstcf_DISCARD_STRING - 问题

时间:2011-03-12 08:52:20

标签: sql perl casting dbi

我的希望是DBI::sql_type_cast DBIstcf_DISCARD_STRING - 标志会将$ sv从'4.8g'修改为4.8。

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

返回值sv could not be case and DBIstcf_STRICT was not used是什么意思?

#!/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

3 个答案:

答案 0 :(得分:5)

  1. 文档中包含一个拼写错误 - $sts == 1的描述应为“sv无法强制转换” - 即转换为{{1}你所提供的价值是不可能的,所以什么都没做。

  2. SQL_DOUBLE意味着与您想要的不同。在Perl内部术语中,这意味着如果您通过带有DBIstcf_DISCARD_STRINGPOK以及PV部分NOK和NV部分"1.23"的SV,您将获得带有{{的SV 1}}和1.23以及NV部分!POK - 也就是说,标量的存储字符串部分将无效,数字部分保持不变,因此将来尝试将标量用作字符串将强制它从数字重新转换为字符串。但请注意,它表示只有如果演员表成功才会发生,如果该值不是一个有效的数字,则NOK的演员表不会成功。 “4.8g”未通过测试。

  3. 您只需执行1.23清除SQL_DOUBLE并强制执行$sv = 0 + $sv;,就可以自行清除值几乎的字符串部分与DBI一样有效以相同的方式重新转换为字符串。这与DBI之间的区别在于,它实际上并不像DBI那样清除 PV,只是标记它无效。要以与DBI相同的方式立即强制值清除,您需要执行类似

    的操作

    POK

    但除非你有一些非常好的解释,为什么你需要它,你没有 - 所以不要使用它。 :)

答案 1 :(得分:1)

阅读文档和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之前使用正则表达式去除该输入。

答案 2 :(得分:0)

文档中的拼写错误现已在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中。