From: Peter Rabbitson Date: Sun, 20 Mar 2011 11:25:55 +0000 (+0100) Subject: Fix long relationship/column names in oracle for good X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=19c4cc62860c3d1d497dd2a3f119a72085caa61d;p=dbsrgits%2FDBIx-Class-Historic.git Fix long relationship/column names in oracle for good 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 --- diff --git a/Changes b/Changes index 49460cd..debc2ad 100644 --- 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 diff --git a/lib/DBIx/Class/SQLMaker/Oracle.pm b/lib/DBIx/Class/SQLMaker/Oracle.pm index 400fc63..3285811 100644 --- a/lib/DBIx/Class/SQLMaker/Oracle.pm +++ b/lib/DBIx/Class/SQLMaker/Oracle.pm @@ -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 diff --git a/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm b/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm index d049d6c..8e769b6 100644 --- a/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm +++ b/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm @@ -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 diff --git a/t/73oracle.t b/t/73oracle.t index d41538b..50235b7 100644 --- a/t/73oracle.t +++ b/t/73oracle.t @@ -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' }, {