Part one of the sybase work by Caelum (mostly reviewed)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Pg.pm
index 61a8d5e..3d25b83 100644 (file)
@@ -20,15 +20,22 @@ sub with_deferred_fk_checks {
 }
 
 sub last_insert_id {
-  my ($self,$source,$col) = @_;
-  my $seq = ( $source->column_info($col)->{sequence} ||= $self->dbh_do('_dbh_get_autoinc_seq', $source, $col) )
+  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"
                                );
 
-  $self->_dbh_last_insert_id ($self->_dbh, $seq);
+    push @values, $self->_dbh_last_insert_id ($self->_dbh, $seq);
+  }
+
+  return @values;
 }
 
 # there seems to be absolutely no reason to have this as a separate method,
@@ -54,6 +61,48 @@ sub _dbh_get_autoinc_seq {
     ( $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 $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';
 
@@ -80,25 +129,9 @@ $where
 
 EOS
 
-  # 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 $1;
+  return $seq_expr;
 }
 
-sub get_autoinc_seq {
-  my ($self,$source,$col) = @_;
-
-}
 
 sub sqlt_type {
   return 'PostgreSQL';