--- DBD/PgPP.pm.~1~ Sun Apr 16 01:07:34 2006
+++ DBD/PgPP.pm Sun Jul 23 02:47:20 2006
@@ -325,6 +325,138 @@
}
+#--- lifted from from DBD::Pg.pm
+
+sub _server_version
+{
+ my ($dbh) = @_;
+ unless (defined $dbh->{pgpp_server_version}) {
+ my $sth = $dbh->prepare('SELECT version()');
+ my $count = $sth->execute();
+ if (!defined $count or $count eq '0E0') {
+ $sth->finish();
+ $dbh->STORE('pgpp_server_version', 0);
+ }
+ elsif ($sth->fetchall_arrayref()->[0][0] =~ /^PostgreSQL (\d+)\.(\d+)\.?(\d*)/) {
+ $dbh->STORE('pgpp_server_version', ($1 * 100 + $2) * 100 + ($3 || 0));
+ }
+ }
+ return $dbh->{pgpp_server_version};
+}
+
+sub last_insert_id
+{
+ my ($dbh, $catalog, $schema, $table, $col, $attr) = @_;
+
+ ## Our ultimate goal is to get a sequence
+ my ($sth, $count, $SQL, $sequence);
+
+ ## Cache all of our table lookups? Default is yes
+ my $use_cache = 1;
+
+ ## Catalog and col are not used
+ $schema = '' if ! defined $schema;
+ $table = '' if ! defined $table;
+ my $cachename = "$schema.$table";
+
+ if (defined $attr and length $attr) {
+ ## If not a hash, assume it is a sequence name
+ if (! ref $attr) {
+ $attr = {sequence => $attr};
+ }
+ elsif (ref $attr ne 'HASH') {
+ return $dbh->set_err(1, "last_insert_id must be passed a hashref as the final argument");
+ }
+ ## Named sequence overrides any table or schema settings
+ if (exists $attr->{sequence} and length $attr->{sequence}) {
+ $sequence = $attr->{sequence};
+ }
+ if (exists $attr->{pg_cache}) {
+ $use_cache = $attr->{pg_cache};
+ }
+ }
+
+ if (! defined $sequence and exists $dbh->{pgpp_liicache}{$cachename} and $use_cache) {
+ $sequence = $dbh->{pgpp_liicache}{$cachename};
+ }
+ elsif (! defined $sequence) {
+ ## At this point, we must have a valid table name
+ if (! length $table) {
+ return $dbh->set_err(1, "last_insert_id needs at least a sequence or table name");
+ }
+ my @args = ($table);
+
+ ## Only 7.3 and up can use schemas
+ my $pg_catalog;
+ if (_server_version($dbh) < 70300) {
+ $schema = '';
+ $pg_catalog = '';
+ }
+ else {
+ $pg_catalog = 'pg_catalog.';
+ }
+
+ ## Make sure the table in question exists and grab its oid
+ my ($schemajoin,$schemawhere) = ('','');
+ if (length $schema) {
+ $schemajoin = "\n JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)";
+ $schemawhere = "\n AND n.nspname = ?";
+ push @args, $schema;
+ }
+ $SQL = "SELECT c.oid FROM ${pg_catalog}pg_class c $schemajoin\n WHERE relname = ?$schemawhere";
+ $sth = $dbh->prepare($SQL);
+ $count = $sth->execute(@args);
+ if (!defined $count or $count eq '0E0') {
+ $sth->finish();
+ my $message = qq{Could not find the table "$table"};
+ length $schema and $message .= qq{ in the schema "$schema"};
+ return $dbh->set_err(1, $message);
+ }
+ my $oid = $sth->fetchall_arrayref()->[0][0];
+ ## This table has a primary key. Is there a sequence associated with it via a unique, indexed column?
+ $SQL = "SELECT a.attname, i.indisprimary, substring(d.adsrc for 128) AS def\n".
+ "FROM ${pg_catalog}pg_index i, ${pg_catalog}pg_attribute a, ${pg_catalog}pg_attrdef d\n ".
+ "WHERE i.indrelid = $oid AND d.adrelid=a.attrelid AND d.adnum=a.attnum\n".
+ " AND a.attrelid=$oid AND i.indisunique IS TRUE\n".
+ " AND a.atthasdef IS TRUE AND i.indkey[0]=a.attnum\n".
+ " AND d.adsrc ~ '^nextval'";
+ $sth = $dbh->prepare($SQL);
+ $count = $sth->execute();
+ if (!defined $count or $count eq '0E0') {
+ $sth->finish();
+ $dbh->set_err(1, qq{No suitable column found for last_insert_id of table "$table"});
+ }
+ my $info = $sth->fetchall_arrayref();
+
+ ## We have at least one with a default value. See if we can determine sequences
+ my @def;
+ for (@$info) {
+ next unless $_->[2] =~ /^nextval\('([^']+)'::/o;
+ push @$_, $1;
+ push @def, $_;
+ }
+ if (!@def) {
+ $dbh->set_err(1, qq{No suitable column found for last_insert_id of table "$table"\n});
+ }
+ ## Tiebreaker goes to the primary keys
+ if (@def > 1) {
+ my @pri = grep { $_->[1] } @def;
+ if (1 != @pri) {
+ $dbh->set_err(1, qq{No suitable column found for last_insert_id of table "$table"\n});
+ }
+ @def = @pri;
+ }
+ $sequence = $def[0]->[3];
+ ## Cache this information for subsequent calls
+ $dbh->{pgpp_liicache}{$cachename} = $sequence;
+ }
+
+ $sth = $dbh->prepare("SELECT currval(?)");
+ $sth->execute($sequence);
+ return $sth->fetchall_arrayref()->[0][0];
+}
+#--- end of last_insert_id
+
package DBD::PgPP::st;
$DBD::PgPP::st::imp_data_size = 0;