More problems with bound parameters in DBD::ODBC

"Martin J. Evans" <[email protected]>
Newsgroups gmane.comp.lang.perl.modules.dbi.sybase.devel
Organization Easysoft Limited
Message-ID <[email protected]>
This issue cropped up because runrig posted a "DBI bind_param_inout trick" node (http://perlmonks.org/?node_id=989136) on perl monks which when I ran through DBD::ODBC did not work. The code is basically:

my $dbh = DBI->connect;
my @cols = qw(foo bar);
my $sql = <<SQL;
SELECT :foo, :bar
SQL

my $sth = $dbh->prepare($sql);
my %hsh;
for (@cols) {
   $sth->bind_param_inout( "$_" => \$hsh{$_}, 0 );
}

# Set constants...
$hsh{foo} = 'abc';

# Set changing values
$hsh{bar} = 123;

$sth->execute();
while (my @arr = $sth->fetchrow_array) {
   print "@arr\n";
}

$hsh{bar} = 456;
$sth->execute();
while (my @arr = $sth->fetchrow_array) {
   print "@arr\n";
}
$dbh->disconnect();

which should output:

abc 123
abc 456

but actually outputs:

Use of uninitialized value $arr[0] in join or string at /tmp/x.pl line 33.
  123
Use of uninitialized value $arr[0] in join or string at /tmp/x.pl line 39.
  456

The problem is that DBD::ODBC binds the parameter initially when bind_param_inout is called then when execute is called it needs to determine if the parameters need to be rebound (if something significant has changed). It uses the following test:

if (SvTYPE(phs->sv) != phs->sv_type /* has the type changed? */
     || (SvOK(phs->sv) && !SvPOK(phs->sv)) /* is there still a string? */
     || (SvPVX(phs->sv) != phs->sv_buf) /* has the string buffer moved? */
    ) {
       /* rebind the parameter */
      }

I have some issues with this (in addition to it not working):

1. DBD::ODBC always calls SvUPGRADE(phs->sv, SVt_PVNV) on output parameters so the type is unlikely to change.

2. DBD::ODBC always calls SvGROW on output parameters to grow them to 28 chrs (some magic about 28 I don't know) to avoid mutation in most cases. As a result, if you change the test code so the first param is bigger than 28 chrs it works.

3. I don't understand what the (SvOK(phs->sv) && !SvPOK(phs->sv)) is for. I know what those macros do but not why that test is present. Any ideas? It is in other DBDs too.

4. I'm unsure how to make this work although if I simply add a test to say has SvOK(phs->sv) changed since binding it makes this example work. Anyone any ideas if this is sufficient?

Thanks.

Martin
-- 
Martin J. Evans
Easysoft Limited
http://www.easysoft.com
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.