Fix long relationship/column names in oracle for good
Peter Rabbitson [Sun, 20 Mar 2011 11:25:55 +0000 (12:25 +0100)]
Do not pass in the relname as "keyword" anymore - it will interfere
with the aliasing since ::Storage::Oracle and SQLMaker::Oracle will
produce different results

Changes
lib/DBIx/Class/SQLMaker/Oracle.pm
lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm
t/73oracle.t

diff --git a/Changes b/Changes
index 49460cd..debc2ad 100644 (file)
--- a/Changes
+++ b/Changes
@@ -15,6 +15,8 @@ Revision history for DBIx::Class
           DBD::mysql versions
         - Fix dropped bind values in select/group_by on Oracle (omission
           from 0542ec57 and 4c2b30d6)
+        - Fix remaining errors with Oracle and identifiers longer than the
+          Oracle-imposed maximum of 30 characters (RT#66390)
         - Fix problems with M.A.D. under CGI::SpeedyCGI (RT#65131)
         - Better error handling when prepare() fails silently
         - Fixes skipped lines when a comment is followed by a statement
index 400fc63..3285811 100644 (file)
@@ -109,6 +109,19 @@ sub _where_field_PRIOR {
   return ($sql, @bind);
 }
 
+# use this codepath to hook all identifiers and mangle them if necessary
+# this is invoked regardless of quoting being on or off
+sub _quote {
+  my ($self, $label) = @_;
+
+  return '' unless defined $label;
+  return ${$label} if ref($label) eq 'SCALAR';
+
+  $label =~ s/ ( [^\.]{31,} ) /$self->_shorten_identifier($1)/gxe;
+
+  $self->next::method($label);
+}
+
 # this takes an identifier and shortens it if necessary
 # optionally keywords can be passed as an arrayref to generate useful
 # identifiers
index d049d6c..8e769b6 100644 (file)
@@ -468,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
index d41538b..50235b7 100644 (file)
@@ -220,11 +220,51 @@ sub _run_tests {
     is $query->first->cds_very_very_very_long_relationship_name->first->cdid, 1
   } 'query with rel name over 30 chars survived and worked';
 
+# test rel names over the 30 char limit using group_by and join
+  {
+    my @group_cols = ( 'me.name' );
+    my $query = $schema->resultset('Artist')->search({
+      artistid => 1
+    }, {
+      select => \@group_cols,
+      as => [map { /^\w+\.(\w+)$/ } @group_cols],
+      join => [qw( cds_very_very_very_long_relationship_name )],
+      group_by => \@group_cols,
+    });
+
+    lives_and {
+      my @got = $query->get_column('name')->all();
+      is_deeply \@got, [$new_artist->name];
+    } 'query with rel name over 30 chars worked on join, group_by for me col';
+
+    lives_and {
+      is $query->count(), 1
+    } 'query with rel name over 30 chars worked on join, group_by, count for me col';
+  }
+  {
+    my @group_cols = ( 'cds_very_very_very_long_relationship_name.title' );
+    my $query = $schema->resultset('Artist')->search({
+      artistid => 1
+    }, {
+      select => \@group_cols,
+      as => [map { /^\w+\.(\w+)$/ } @group_cols],
+      join => [qw( cds_very_very_very_long_relationship_name )],
+      group_by => \@group_cols,
+    });
+
+    lives_and {
+      my @got = $query->get_column('title')->all();
+      is_deeply \@got, [$new_cd->title];
+    } 'query with rel name over 30 chars worked on join, group_by for long rel col';
+
+    lives_and {
+      is $query->count(), 1
+    } 'query with rel name over 30 chars worked on join, group_by, count for long rel col';
+  }
+
   # rel name over 30 char limit with user condition
   # This requires walking the SQLA data structure.
   {
-    local $TODO = 'user condition on rel longer than 30 chars';
-
     $query = $schema->resultset('Artist')->search({
       'cds_very_very_very_long_relationship_name.title' => 'EP C'
     }, {