Skip Menu |

This queue is for tickets about the DBD-PgPP CPAN distribution.

Report information
The Basics
Id: 18733
Status: resolved
Priority: 0/
Queue: DBD-PgPP

People
Owner: Nobody in particular
Requestors: crew@cs.stanford.edu (no email address)
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.05
Fixed in: 0.06



To make a long story short, row_description, a field of DBD::PgPP::Protocol (the internal connection handle) really needs to live on DBD::PgPP::ProtocolStatement, (the internal statement handle) instead. Basically, whenever you have multiple select handles on the same connection and you're fetching from both at the same time, the one executed latest has its row_description applied to the earlier one and data gets corrupted. But it's actually worse than that because the row_description is also being applied to things that aren't even select statements -- often harmlessly but sometimes not: DB<1> $stmt=$dbh->prepare('SELECT * FROM EightColumnTable'); DB<2> p $stmt->execute 0E0 DB<3> p $stmt->{NUM_OF_FIELDS} 8 DB<4> $istmt=$dbh->prepare('INSERT into Whatever values(?,?,?)') DB<5> p $istmt->execute(1,2,3); 1 DB<6> p $istmt->{NUM_OF_FIELDS} 8 ## oops. but so far this is harmless, since nothing cares about ## the number of fields on INSERT statements. However, we continue... DB<7> $stmt=$dbh->prepare('SELECT * FROM FourColumnTable'); DB<8> p $stmt->execute 1 DB<9> p $stmt->{NUM_OF_FIELDS} 4 DB<10> p $istmt->execute(1,3,2); DBD::PgPP::st execute failed: NUM_OF_FIELDS already set to 8 at C:/prgfiles/perl/site/lib/DBD/PgPP.pm line 454. at (eval 63)[C:/prgfiles/perl/lib/perl5db.pl:628] line 2 eval '($@, $!, $^E, $,, $/, $\\, $^W) = @saved;package main; $^D = $^D | $DB::db_stop; print {$DB::OUT} $istmt->execute(1,3,2);; ;' called at C:/prgfiles/perl/lib/perl5db.pl line 628 DB::eval called at C:/prgfiles/perl/lib/perl5db.pl line 3410 DB::DB called at -e line 1 The error arises because it's trying to (pointlessly) set NUM_OF_FIELDS on $istmt to 4 Here's an example of data corruption: DB<1> $stmt=$dbh->prepare('SELECT varchar_column FROM t0'); DB<2> p $stmt->execute; 1 DB<3> x $stmt->fetch; 0 ARRAY(0x22c674c) 0 'T' DB<4> $stmt1=$dbh->prepare('SELECT boolean_column FROM t1'); DB<5> p $stmt1->execute; 1 DB<6> x $stmt1->fetch; 0 ARRAY(0x22c6530) 0 1 DB<7> x $stmt->fetch; 0 ARRAY(0x22c674c) 0 1 In all fetches from $stmt from now on, any string not eq to 'f' will gets converted to 1 while 'f' becomes 0, which is proper for a boolean column, but the t0 column isn't boolean. I've attached a patch that appears to fix things Examples above were run on v5.8.7 MSWin32-x86-multi-thread (Active Perl build 815), but I'm pretty sure that doesn't matter a whole lot.
Subject: ppat.txt
Download ppat.txt
application/octet-stream 2.4k

Message body not shown because it is not plain text.

Subject: Multiple statement handle confusion/corruption
From: crew [...] cs.stanford.edu
(sort of annoying that I can't fix the title/severity after the fact.) Since there's data corruption, I'd count this one as "Critical" also, here's the patch again, hopefully in a form that looks less like a virus
--- DBD/PgPP.pm~ Sun May 09 13:07:59 2004 +++ DBD/PgPP.pm Sun Jul 23 04:10:30 2006 @@ -365,6 +365,7 @@ my $result; eval { $sth->{pgpp_record_iterator} = undef; + undef $pgsql->{row_description}; my $pgsql_sth = $pgsql->prepare($statement); $pgsql_sth->execute(); $sth->{pgpp_record_iterator} = $pgsql_sth; @@ -378,9 +379,9 @@ $sth->{pgpp_rows} = 0; $result = $pgsql->{affected_rows}; } - if ($pgsql->{row_description}) { - $sth->STORE(NUM_OF_FIELDS => scalar @{$pgsql->{row_description}}); - $sth->STORE(NAME => [ map {$_->{name}} @{$pgsql->{row_description}} ]); + if ($pgsql_sth->{st_row_description}) { + $sth->STORE(NUM_OF_FIELDS => scalar @{$pgsql_sth->{st_row_description}}); + $sth->STORE(NAME => [ map {$_->{name}} @{$pgsql_sth->{st_row_description}} ]); } # $pgsql->get_affected_rows_length; }; @@ -667,6 +668,7 @@ statement => $statement, stream => undef, finish => undef, + st_row_description => undef, }, $class; } @@ -709,9 +711,10 @@ $row_info->compute($pgsql); $self->{stream} = DBD::PgPP::ReadOnlyPacketStream->new($handle); $self->{stream}->set_buffer($stream->get_buffer); + $self->{st_row_description} = $pgsql->{row_description}; while (1) { my $tmp_packet = $self->{stream}->each(); printf "-Recieve %s\n", ref($tmp_packet) if $DBD::PgPP::Protocol::DEBUG; if ($tmp_packet->is_error()) { $self->_to_end_of_response($stream); croak $tmp_packet->get_message(); @@ -760,9 +763,10 @@ return undef if $self->{finish}; + local $pgsql->{row_description} = $self->{st_row_description}; while (1) { my $packet = $stream->each(); printf "%s\n", ref $packet if $DBD::PgPP::Protocol::DEBUG; warn $packet->get_message() if $packet->is_error; return undef if $packet->is_end_of_response; $packet->compute($pgsql);
Subject: Interleaving fetch and execute
This issue is believed to be fixed in DBD::PgPP 0.06. Please reopen this ticket if you can still reproduce the problem in that version. Apologies for the absurdly long delay, and thanks for the patch. -- Aaron Crane