Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Confusion over B::PV

by mje (Curate)
on May 19, 2012 at 11:17 UTC ( #971411=perlquestion: print w/replies, xml ) Need Help??
mje has asked for the wisdom of the Perl Monks concerning the following question:

I am attempting to fix some XS code and have reached a point where I'm slightly confused with the output of B::PV. The XS code now does a sv_setsv(sv, 100) (it used to do a sv_setpvn) and the test code is:

use Devel::Peek; use B qw( svref_2object SVf_IOK SVf_NOK SVf_POK ); sub is_iv { my $sv = svref_2object(my $ref = \$_[0]); my $flags = $sv->FLAGS; my $x = $sv->PV; if (wantarray) { return ($flags & SVf_IOK, $x); } else { return $flags & SVf_IOK; } } # code to connect to database here $sth = $dbh->prepare(q/select a from PERL_DBD_drop_me/); $sth->execute; $sth->bind_col(1, \$r, {TYPE => SQL_INTEGER}); $sth->fetch; # this will do a sv_setiv($r, 100) is($r, 100, "correct value returned SQL_INTEGER") or Dump($r); my ($iv, $pv) = is_iv($r); ok($iv, "ivok bind integer") or Dump($r); ok($pv, "pv not null bind integer") or Dump($r);

The output is:

not ok 10 - pv not null bind integer # Failed test 'pv not null bind integer' # at t/sql_type_cast.t line 149. SV = PVIV(0x9f81420) at 0xa1353f4 REFCNT = 2 FLAGS = (PADMY,IOK,pIOK) IV = 100 PV = 0xa23fd88 "100"\0 # <--- should this be set? CUR = 3 LEN = 4

I am unsure why B::PV returns undef. Could someone explain this? Thanks.

Replies are listed 'Best First'.
Re: Confusion over B::PV
by ikegami (Pope) on May 19, 2012 at 16:52 UTC
    PV checks whether the scalar is a string. Use PVX to get the string buffer regardless of whether the scalar is a string. Since PV and PVX can only be called on subclasses of B::PV, you might want to check if you have the right class first.
    my $x = $sv->can('PVX') ? $sv->PVX : undef;

    But why are you checking that?! It's equally correct for it to be present and absent.

    use strict; use warnings; use Test::More tests => 3; use Devel::Peek; use B qw( svref_2object SVf_IOK SVf_NOK SVf_POK ); sub is_iv { my $sv = svref_2object(my $ref = \$_[0]); my $flags = $sv->FLAGS; my $pv = $sv->can('PVX') ? $sv->PVX : undef; if (wantarray) { return ($flags & SVf_IOK, $pv); } else { return $flags & SVf_IOK; } } my $r = "100"; $r = 100; Dump($r); my ($iv, $pv) = is_iv($r); is($r, 100, "correct value returned SQL_INTEGER"); ok($iv, "ivok bind integer"); ok($pv, "pv not null bind integer");

      Thank you for the explanation. The test is looking to see that the scalar does not look like a string because it wants to behave like a number because it was a number in the database. The test is simply ensuring the scalar was either created with sv_setiv or sql_type_cast_svpv was run on it.

      Before sql_type_cast_svpv or DBDs like DBD::ODBC (here) set the scalar with sv_setiv the scalar looks like a string then you have to add 0 to all your numbers retrieved from the database before passing them to modules like JSON::XS or they will be turned into "NNN" instead of NNN. Another example was people doing select a_int, b_int from table then performing a_int & b_int which gives the wrong answer unless you add 0 to them first. See and various discussions on dbi-dev mailing list.

        The test is looking to see that the scalar does not look like a string

        You want SvPOK(sv) which is defined to be SvFLAGS(sv) & SVf_POK and is available as $sv->POK.

Re: Confusion over B::PV (POK)
by tye (Sage) on May 19, 2012 at 17:03 UTC

    So you want $sv->PV() to return a true value while you also want PV to not be set in the Dump() output? I am going to assume that your "should this be set?" comment just gave me an incorrect impression.

    DB<1> $x= 100 DB<2> Dump $x SV = IV(0x2f10ee0) at 0x2f10ee4 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 100 DB<3> $y = "$x" DB<4> Dump $x SV = PVIV(0x424424) at 0x2f10ee4 REFCNT = 1 FLAGS = (IOK,POK,pIOK,pPOK) IV = 100 # ^^^ ^^^^ These are important PV = 0x2eeda6c "100"\0 CUR = 3 LEN = 4 DB<5>

    $sv->PV() is not returning a value because your scalar isn't marked as having a valid PV value (no POK nor pPOK flags set). I don't know what $sv->PV() actually translates to in C code.

    It appears that the scalar had previously been upgraded to type PVIV and Perl doesn't waste resources to downgrade it to type IV when sv_setiv() marks the IV as the only value currently in sync with the SV's value. Perl doesn't even waste time free()ing the PV's buffer or putting a '\0' character at the front of it.

    You don't show enough code for me to be able to determine why the "100" string was already sitting cached (it appears) in that SV. You might want to Dump($r) in between each of your steps to gain better insights.

    If you want a PV to be cached in the SV, then it looks like $sv->PV() doesn't do that work so you should use the scalar as a string before that.

    - tye        

      Also, to explain why there was 100 already in the pv it was because a previous test (prior to the one I showed) did a sv_setpvn. Sorry, I tried to omit other stuff for brevity and in this case probably added to the confusion.

      I think ikegami answered my question. I thought PV simply returned the string pointer which is really what PVX does. As such I was surprised PV was false but the scalar had a pv.

      The should be set test comment was left over from the fact that another bug masked the fact that test should have failed. Now that is fixed I am expecting PV to return undef and don't care there is a pv pointer.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://971411]
Approved by moritz
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (8)
As of 2017-02-25 16:55 GMT
Find Nodes?
    Voting Booth?
    Before electricity was invented, what was the Electric Eel called?

    Results (366 votes). Check out past polls.