Massive rewrite of bind handling, and overall simplification of ::Storage::DBI
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Oracle / Generic.pm
index b255e53..8c6b9d3 100644 (file)
@@ -8,6 +8,7 @@ use Try::Tiny;
 use namespace::clean;
 
 __PACKAGE__->sql_limit_dialect ('RowNum');
+__PACKAGE__->sql_quote_char ('"');
 
 =head1 NAME
 
@@ -79,6 +80,21 @@ use base qw/DBIx::Class::Storage::DBI/;
 use mro 'c3';
 
 __PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::Oracle');
+__PACKAGE__->datetime_parser_type('DateTime::Format::Oracle');
+
+sub _determine_supports_insert_returning {
+  my $self = shift;
+
+# TODO find out which version supports the RETURNING syntax
+# 8i has it and earlier docs are a 404 on oracle.com
+
+  return 1
+    if $self->_server_info->{normalized_dbms_version} >= 8.001;
+
+  return 0;
+}
+
+__PACKAGE__->_use_insert_returning_bound (1);
 
 sub deployment_statements {
   my $self = shift;;
@@ -136,9 +152,12 @@ sub _dbh_get_autoinc_seq {
   # disable default bindtype
   local $sql_maker->{bindtype} = 'normal';
 
-
   # look up the correct sequence automatically
   my ( $schema, $table ) = $source_name =~ /( (?:${ql})? \w+ (?:${qr})? ) \. ( (?:${ql})? \w+ (?:${qr})? )/x;
+
+  # if no explicit schema was requested - use the default schema (which in the case of Oracle is the db user)
+  $schema ||= uc( ($self->_dbi_connect_info||[])->[1] || '');
+
   my ($sql, @bind) = $sql_maker->select (
     'ALL_TRIGGERS',
     [qw/TRIGGER_BODY TABLE_OWNER TRIGGER_NAME/],
@@ -253,20 +272,19 @@ sub _ping {
 }
 
 sub _dbh_execute {
-  my $self = shift;
-  my ($dbh, $op, $extra_bind, $ident, $bind_attributes, @args) = @_;
+  my ($self, $dbh, $sql, @args) = @_;
 
   my (@res, $tried);
-  my $wantarray = wantarray();
+  my $want = wantarray;
   my $next = $self->next::can;
   do {
     try {
-      my $exec = sub { $self->$next($dbh, $op, $extra_bind, $ident, $bind_attributes, @args) };
+      my $exec = sub { $self->$next($dbh, $sql, @args) };
 
-      if (!defined $wantarray) {
+      if (!defined $want) {
         $exec->();
       }
-      elsif (! $wantarray) {
+      elsif (! $want) {
         $res[0] = $exec->();
       }
       else {
@@ -279,7 +297,6 @@ sub _dbh_execute {
       if (! $tried and $_ =~ /ORA-01003/) {
         # ORA-01003: no statement parsed (someone changed the table somehow,
         # invalidating your cursor.)
-        my ($sql, $bind) = $self->_prep_for_execute($op, $extra_bind, $ident, \@args);
         delete $dbh->{CachedKids}{$sql};
       }
       else {
@@ -288,7 +305,16 @@ sub _dbh_execute {
     };
   } while (! $tried++);
 
-  return $wantarray ? @res : $res[0];
+  return wantarray ? @res : $res[0];
+}
+
+sub _dbh_execute_array {
+  #my ($self, $sth, $tuple_status, @extra) = @_;
+
+  # DBD::Oracle warns loudly on partial execute_array failures
+  local $_[1]->{PrintWarn} = 0;
+
+  shift->next::method(@_);
 }
 
 =head2 get_autoinc_seq
@@ -308,10 +334,6 @@ sub get_autoinc_seq {
 This sets the proper DateTime::Format module for use with
 L<DBIx::Class::InflateColumn::DateTime>.
 
-=cut
-
-sub datetime_parser_type { return "DateTime::Format::Oracle"; }
-
 =head2 connect_call_datetime_setup
 
 Used as:
@@ -360,56 +382,57 @@ sub connect_call_datetime_setup {
   );
 }
 
-=head2 source_bind_attributes
-
-Handle LOB types in Oracle.  Under a certain size (4k?), you can get away
-with the driver assuming your input is the deprecated LONG type if you
-encode it as a hex string.  That ain't gonna fly at larger values, where
-you'll discover you have to do what this does.
-
-This method had to be overridden because we need to set ora_field to the
-actual column, and that isn't passed to the call (provided by Storage) to
-bind_attribute_by_data_type.
-
-According to L<DBD::Oracle>, the ora_field isn't always necessary, but
-adding it doesn't hurt, and will save your bacon if you're modifying a
-table with more than one LOB column.
-
-=cut
-
-sub source_bind_attributes
-{
-  require DBD::Oracle;
-  my $self = shift;
-  my($source) = @_;
-
-  my %bind_attributes;
-
-  foreach my $column ($source->columns) {
-    my $data_type = $source->column_info($column)->{data_type}
-      or next;
+### Note originally by Ron "Quinn" Straight <quinnfazigu@gmail.org>
+### http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git;a=commitdiff;h=5db2758de644d53e07cd3e05f0e9037bf40116fc
+#
+# Handle LOB types in Oracle.  Under a certain size (4k?), you can get away
+# with the driver assuming your input is the deprecated LONG type if you
+# encode it as a hex string.  That ain't gonna fly at larger values, where
+# you'll discover you have to do what this does.
+#
+# This method had to be overridden because we need to set ora_field to the
+# actual column, and that isn't passed to the call (provided by Storage) to
+# bind_attribute_by_data_type.
+#
+# According to L<DBD::Oracle>, the ora_field isn't always necessary, but
+# adding it doesn't hurt, and will save your bacon if you're modifying a
+# table with more than one LOB column.
+#
+sub _dbi_attrs_for_bind {
+  my ($self, $ident, $bind) = @_;
+  my $attrs = $self->next::method($ident, $bind);
+
+  for my $i (0 .. $#$attrs) {
+    if (keys %{$attrs->[$i]||{}} and my $col = $bind->[$i][0]{dbic_colname}) {
+      $attrs->[$i]{ora_field} = $col;
+    }
+  }
 
-    my %column_bind_attrs = $self->bind_attribute_by_data_type($data_type);
+  $attrs;
+}
 
-    if ($data_type =~ /^[BC]LOB$/i) {
-      if ($DBD::Oracle::VERSION eq '1.23') {
-        $self->throw_exception(
-"BLOB/CLOB support in DBD::Oracle == 1.23 is broken, use an earlier or later ".
-"version.\n\nSee: https://rt.cpan.org/Public/Bug/Display.html?id=46016\n"
-        );
-      }
+my $dbd_loaded;
+sub bind_attribute_by_data_type {
+  my ($self, $dt) = @_;
+
+  $dbd_loaded ||= do {
+    require DBD::Oracle;
+    if ($DBD::Oracle::VERSION eq '1.23') {
+      $self->throw_exception(
+        "BLOB/CLOB support in DBD::Oracle == 1.23 is broken, use an earlier or later ".
+        "version.\n\nSee: https://rt.cpan.org/Public/Bug/Display.html?id=46016\n"
+      );
+    }
+    1;
+  };
 
-      $column_bind_attrs{'ora_type'} = uc($data_type) eq 'CLOB'
+  if ($self->_is_lob_type($dt)) {
+    return {
+      ora_type => $self->_is_text_lob_type($dt)
         ? DBD::Oracle::ORA_CLOB()
         : DBD::Oracle::ORA_BLOB()
-      ;
-      $column_bind_attrs{'ora_field'} = $column;
-    }
-
-    $bind_attributes{$column} = \%column_bind_attrs;
+    };
   }
-
-  return \%bind_attributes;
 }
 
 sub _svp_begin {
@@ -445,7 +468,9 @@ sub relname_to_table_alias {
 
   my $alias = $self->next::method(@_);
 
-  return $self->sql_maker->_shorten_identifier($alias, [$relname]);
+  # we need to shorten here in addition to the shortening in SQLA itself,
+  # since the final relnames are a crucial for the join optimizer
+  return $self->sql_maker->_shorten_identifier($alias);
 }
 
 =head2 with_deferred_fk_checks