gutted Pg storage driver's sequence discovery to just rely on DBD::Pg's last_insert_i...
Robert Buels [Wed, 21 Oct 2009 01:10:38 +0000 (01:10 +0000)]
lib/DBIx/Class/Storage/DBI/Pg.pm

index 3d25b83..a3788e6 100644 (file)
@@ -22,117 +22,37 @@ sub with_deferred_fk_checks {
 sub last_insert_id {
   my ($self,$source,@cols) = @_;
 
-  my @values;
-
-  for my $col (@cols) {
-    my $seq = ( $source->column_info($col)->{sequence} ||= $self->dbh_do('_dbh_get_autoinc_seq', $source, $col) )
-      or $self->throw_exception( "could not determine sequence for "
-                                 . $source->name
-                                 . ".$col, please consider adding a "
-                                 . "schema-qualified sequence to its column info"
-                               );
-
-    push @values, $self->_dbh_last_insert_id ($self->_dbh, $seq);
-  }
-
-  return @values;
+  return map $self->dbh_do('_dbh_last_insert_id', $source, $_ ), @cols;
 }
 
-# there seems to be absolutely no reason to have this as a separate method,
-# but leaving intact in case someone is already overriding it
 sub _dbh_last_insert_id {
-  my ($self, $dbh, $seq) = @_;
-  $dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
-}
+  my ($self, $dbh, $source, $col ) = @_;
 
+  # if a sequence is defined, explicitly specify it to DBD::Pg's last_insert_id()
+  if( my $seq = $source->column_info($col)->{sequence} ) {
+      return $dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
 
-sub _dbh_get_autoinc_seq {
-  my ($self, $dbh, $source, $col) = @_;
+  }
+  # if not, parse out the schema and table names, pass them to
+  # DBD::Pg, and let it figure out (and cache) the sequence name
+  # itself.
+  else {
 
-  my $schema;
-  my $table = $source->name;
+    my $schema;
+    my $table = $source->name;
 
-  # deref table name if it needs it
-  $table = $$table
-      if ref $table eq 'SCALAR';
+    # deref table name if necessary
+    $table = $$table if ref $table eq 'SCALAR';
 
-  # parse out schema name if present
-  if( $table =~ /^(.+)\.(.+)$/ ) {
-    ( $schema, $table ) = ( $1, $2 );
-  }
+    # parse out schema name if present
+    if ( $table =~ /^(.+)\.(.+)$/ ) {
+        ( $schema, $table ) = ( $1, $2 );
+    }
 
-  # use DBD::Pg to fetch the column info if it is recent enough to
-  # work. otherwise, use custom SQL
-  my $seq_expr =  $DBD::Pg::VERSION >= 2.015001
-      ? eval{ $dbh->column_info(undef,$schema,$table,$col)->fetchrow_hashref->{COLUMN_DEF} }
-      : $self->_dbh_get_column_default( $dbh, $schema, $table, $col );
-
-  # if no default value is set on the column, or if we can't parse the
-  # default value as a sequence, throw.
-  unless ( defined $seq_expr and $seq_expr =~ /^nextval\(+'([^']+)'::(?:text|regclass)\)/i ){
-    $seq_expr = '' unless defined $seq_expr;
-    $schema = "$schema." if defined $schema && length $schema;
-    $self->throw_exception( "no sequence found for $schema$table.$col, check table definition, "
-                            . "or explicitly set the 'sequence' for this column in the "
-                            . $source->source_name
-                            . " class"
-                          );
+    return $dbh->last_insert_id( undef, $schema, $table, undef );
   }
-
-  return $1;
 }
 
-# custom method for fetching column default, since column_info has a
-# bug with older versions of DBD::Pg
-sub _dbh_get_column_default {
-  my ( $self, $dbh, $schema, $table, $col ) = @_;
-
-  # Build and execute a query into the pg_catalog to find the Pg
-  # expression for the default value for this column in this table.
-  # If the table name is schema-qualified, query using that specific
-  # schema name.
-
-  # Otherwise, find the table in the standard Postgres way, using the
-  # search path.  This is done with the pg_catalog.pg_table_is_visible
-  # function, which returns true if a given table is 'visible',
-  # meaning the first table of that name to be found in the search
-  # path.
-
-  # I *think* we can be assured that this query will always find the
-  # correct column according to standard Postgres semantics.
-  #
-  # -- rbuels
-
-  my $sqlmaker = $self->sql_maker;
-  local $sqlmaker->{bindtype} = 'normal';
-
-  my ($where, @bind) = $sqlmaker->where ({
-    'a.attnum' => {'>', 0},
-    'c.relname' => $table,
-    'a.attname' => $col,
-    -not_bool => 'a.attisdropped',
-    (defined $schema && length $schema)
-      ? ( 'n.nspname' => $schema )
-      : ( -bool => \'pg_catalog.pg_table_is_visible(c.oid)' )
-  });
-
-  my ($seq_expr) = $dbh->selectrow_array(<<EOS,undef,@bind);
-
-SELECT
-  (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid)
-   FROM pg_catalog.pg_attrdef d
-   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
-FROM pg_catalog.pg_class c
-     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
-     JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
-$where
-
-EOS
-
-  return $seq_expr;
-}
-
-
 sub sqlt_type {
   return 'PostgreSQL';
 }