From 8261b0d4eee82f4d02ee2a422b272b827cfd850a Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Wed, 12 Sep 2012 07:19:34 +0000 Subject: [PATCH] refactored primary_key_info to support attached databases --- Changes | 2 ++ lib/DBD/SQLite.pm | 58 ++++++++++++++++++++----------------- t/42_primary_key_info.t | 64 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/Changes b/Changes index 08c84e9..9ef1cbd 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,8 @@ Changes for Perl extension DBD-SQLite - Resolved #64177: ping() wipes out the errstr (ISHIGAKI) - Resolved #79576: (patch) bind_param don't work with PADTMP scalars (VOVKASM) + - Refactored primary_key_info to support attached databases + (ISHIGAKI) 1.37 Thu 12 Jun 2012 - Updated to SQLite 3.7.12.1 (ISHIGAKI) diff --git a/lib/DBD/SQLite.pm b/lib/DBD/SQLite.pm index 75ec4b6..487fe9a 100644 --- a/lib/DBD/SQLite.pm +++ b/lib/DBD/SQLite.pm @@ -377,40 +377,46 @@ END_SQL sub primary_key_info { my ($dbh, $catalog, $schema, $table, $attr) = @_; - unless ($schema) { - # for backward compat - my $table_info = $dbh->table_info($catalog, $schema, $table); - while(my $info = $table_info->fetchrow_hashref) { - next unless uc $info->{TABLE_TYPE} eq 'TABLE'; - if ($info->{TABLE_NAME} eq $table) { - $schema = $info->{TABLE_SCHEM}; - last; - } - } - } - - # placeholder doesn't seem to work here - my $quoted_table = $dbh->quote($table); - my $psth = $dbh->prepare("PRAGMA table_info($quoted_table)"); - $psth->execute; + my $databases = $dbh->selectall_arrayref("PRAGMA database_list", {Slice => {}}); my @pk_info; - while(my $col = $psth->fetchrow_hashref) { - if ($col->{pk}) { # we now have this! - push @pk_info, { - TABLE_SCHEM => $schema, - TABLE_NAME => $table, - COLUMN_NAME => $col->{name}, - KEY_SEQ => scalar @pk_info + 1, - PK_NAME => 'PRIMARY KEY', - }; + for my $database (@$databases) { + my $dbname = $database->{name}; + next if defined $schema && $schema ne '%' && $schema ne $dbname; + + my $quoted_dbname = $dbh->quote_identifier($dbname); + + my $master_table = + ($dbname eq 'main') ? 'sqlite_master' : + ($dbname eq 'temp') ? 'sqlite_temp_master' : + $quoted_dbname.'.sqlite_master'; + + my $sth = $dbh->prepare("SELECT name FROM $master_table WHERE type = ?"); + $sth->execute("table"); + while(my $row = $sth->fetchrow_hashref) { + my $tbname = $row->{name}; + next if defined $table && $table ne '%' && $table ne $tbname; + + my $quoted_tbname = $dbh->quote_identifier($tbname); + my $t_sth = $dbh->prepare("PRAGMA $quoted_dbname.table_info($quoted_tbname)"); + $t_sth->execute; + while(my $col = $t_sth->fetchrow_hashref) { + next unless $col->{pk}; + push @pk_info, { + TABLE_SCHEM => $dbname, + TABLE_NAME => $tbname, + COLUMN_NAME => $col->{name}, + KEY_SEQ => scalar @pk_info + 1, + PK_NAME => 'PRIMARY KEY', + }; + } } } my $sponge = DBI->connect("DBI:Sponge:", '','') or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr"); my @names = qw(TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME KEY_SEQ PK_NAME); - my $sth = $sponge->prepare( "primary_key_info $table", { + my $sth = $sponge->prepare( "primary_key_info", { rows => [ map { [ @{$_}{@names} ] } @pk_info ], NUM_OF_FIELDS => scalar @names, NAME => \@names, diff --git a/t/42_primary_key_info.t b/t/42_primary_key_info.t index 5d7108f..a87d5af 100644 --- a/t/42_primary_key_info.t +++ b/t/42_primary_key_info.t @@ -10,7 +10,7 @@ use t::lib::Test qw/connect_ok/; use Test::More; use Test::NoWarnings; -plan tests => 5 * 5 + 1; +plan tests => (5 * 5) + (3 * 6 + 1) + 1; for my $quote ('', qw/' " ` []/) { my ($begin_quote, $end_quote) = (substr($quote, 0, 1), substr($quote, -1, 1)); @@ -26,3 +26,65 @@ for my $quote ('', qw/' " ` []/) { ($pk) = $dbh->primary_key(undef, undef, 'foo'); ok $pk eq 'id'; } + +{ + my $dbh = connect_ok(); + $dbh->do("create table foo (id integer primary key)"); + $dbh->do("attach database ':memory:' as remote"); + $dbh->do("create table remote.bar (name text, primary key(name))"); + $dbh->do("create temporary table baz (tmp primary key)"); + + { + my $sth = $dbh->primary_key_info(undef, undef, 'foo'); + my @pk_info; + while(my $row = $sth->fetchrow_hashref) { push @pk_info, $row }; + is @pk_info => 1, "found 1 pk in a table"; + is $pk_info[0]{TABLE_SCHEM} => 'main', "scheme is correct"; + is $pk_info[0]{COLUMN_NAME} => 'id', "pk name is correct"; + } + + { + my $sth = $dbh->primary_key_info(undef, 'main', undef); + my @pk_info; + while(my $row = $sth->fetchrow_hashref) { push @pk_info, $row }; + is @pk_info => 1, "found 1 pk in a table"; + is $pk_info[0]{TABLE_SCHEM} => 'main', "scheme is correct"; + is $pk_info[0]{COLUMN_NAME} => 'id', "pk name is correct"; + } + + { + my $sth = $dbh->primary_key_info(undef, undef, 'bar'); + my @pk_info; + while(my $row = $sth->fetchrow_hashref) { push @pk_info, $row }; + is @pk_info => 1, "found 1 pk in an attached table"; + is $pk_info[0]{TABLE_SCHEM} => 'remote', "scheme is correct"; + is $pk_info[0]{COLUMN_NAME} => 'name', "pk name is correct"; + } + + { + my $sth = $dbh->primary_key_info(undef, 'remote', undef); + my @pk_info; + while(my $row = $sth->fetchrow_hashref) { push @pk_info, $row }; + is @pk_info => 1, "found 1 pk in an attached table"; + is $pk_info[0]{TABLE_SCHEM} => 'remote', "scheme is correct"; + is $pk_info[0]{COLUMN_NAME} => 'name', "pk name is correct"; + } + + { + my $sth = $dbh->primary_key_info(undef, 'temp', undef); + my @pk_info; + while(my $row = $sth->fetchrow_hashref) { push @pk_info, $row }; + is @pk_info => 1, "found 1 pk in a table"; + is $pk_info[0]{TABLE_SCHEM} => 'temp', "scheme is correct"; + is $pk_info[0]{COLUMN_NAME} => 'tmp', "pk name is correct"; + } + + { + my $sth = $dbh->primary_key_info(undef, undef, 'baz'); + my @pk_info; + while(my $row = $sth->fetchrow_hashref) { push @pk_info, $row }; + is @pk_info => 1, "found 1 pk in an attached table"; + is $pk_info[0]{TABLE_SCHEM} => 'temp', "scheme is correct"; + is $pk_info[0]{COLUMN_NAME} => 'tmp', "pk name is correct"; + } +} \ No newline at end of file