davido has asked for the wisdom of the Perl Monks concerning the following question:
This morning I was tinkering further with Hash lookups, Database lookups, and Scalability, trying to squeeze a little better performance out of the database query. In the CB, jZed mentioned that for my application, selectrow_array() might be an improvement over fetchrow_array(). I hadn't considered selectrow_array() because I hadn't noticed in the docs for DBI that you can pass it a statement handle to a pre-prepared SQL query. Perfect, that should be just the ticket. But when I made the change, I got a pretty little segfault.
I'm posting this question to see if anyone can shed any light on why the switch to selectrow_array() generated a segfault.
I am using DBI, DBD::SQLite version 1.07 (which is based on SQLite version 3.x), on a Win32 machine with ActiveState Perl 5.8.4. My DBI version is 1.45 (the latest). With respect to windows machines, the problem has been confirmed on both Win98 and WinXP. However, while collaborating in the CB with jZed and Corion, we discovered that the problem seems to exist cross-platform, including on Linux. jZed also discovered that the problem doesn't occur with DBD::SQLite2, which is based on the older SQLite 2.x engine.
Corion managed to determine that the problem occurs when placeholders are used, not when WHERE clause values are placed directly in the prepare() for the SQL statement.
The following is a snippet that Corion wrangled up, boiling the problem down to a simple test case. It is based loosely on my benchmarking code which originally produced the segfault. The failure appears to occur upon the second call to selectrow_array(), not the first call. Have a look at the code and see if any of you can cast additional light on the problem. I think it's a problem with the SQLite 3.x engine, but I'm not sure.
use strict; use warnings; use Test::More tests => 4; use DBI; my $database = 'allwords.sqlite-v3'; unlink $database; my( %forward, %backward ); my $dbh = DBI->connect( "DBI:SQLite:$database", '', '', { RaiseError => 1, AutoCommit => 0 } ); diag "Using DBD::SQLite $DBD::SQLite::VERSION"; diag "Creating database\n"; my @words = split /\s+/, <DATA>; @forward{ @words } = reverse @words; diag "Creating word-pair database...\n"; $dbh->do( "CREATE TABLE wordtable ( Left varchar, Right varchar ) " ); my $sth = $dbh->prepare( "INSERT INTO wordtable ( Left, Right ) VALUES ( ?, ? )" ); while ( my( $left, $right ) = each %forward ) { $sth->execute( $left, $right ); } $sth->finish; $dbh->commit; diag "Database created.\n"; diag "Selecting (static value, 1st)\n"; my $value; $sth = $dbh->prepare( "SELECT Right FROM wordtable WHERE Left = 'shine +'" ); undef $value; eval { $value = $dbh->selectrow_array( $sth, {}, ); }; is( $value, 'shine', 'Got "shine"'); diag "Selecting (static value, 2nd)\n"; undef $value; eval { $value = $dbh->selectrow_array( $sth, {}, ); }; is( $value, 'shine', "Got 'shine' and didn't crash"); diag "Selecting (placeholder, 1st round)\n"; $sth = $dbh->prepare( "SELECT Right FROM wordtable WHERE Left = ?" ); undef $value; eval { $value = $dbh->selectrow_array( $sth, {}, 'shine' ); }; diag $@ if $@; is( $value, 'shine', 'Got "shine"'); # This one crashes diag "Selecting (placeholder, 2nd round)\n"; undef $value; eval { $value = $dbh->selectrow_array( $sth, {}, 'shine' ); }; diag $@ if $@; is( $value, 'shine', "Got 'shine' and didn't crash"); $sth->finish(); $dbh->disconnect(); __DATA__ shine shine
Curiosity abounds..........
Update: selectrow_arrayref() and selectall_arrayref() are also both similarly contaminated.
Dave
|
|---|