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

Reply via email to