From: Evaldas Imbrasas Date: Fri, 24 Jun 2011 00:02:13 +0000 (-0700) Subject: Support index hints for mysql X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fpeople%2Fevaldas%2Findex-hint;p=dbsrgits%2FDBIx-Class.git Support index hints for mysql --- diff --git a/lib/DBIx/Class/ResultSource.pm b/lib/DBIx/Class/ResultSource.pm index 9489f49..96acbda 100644 --- a/lib/DBIx/Class/ResultSource.pm +++ b/lib/DBIx/Class/ResultSource.pm @@ -1186,6 +1186,10 @@ Explicitly specifies the type of join to use in the relationship. Any SQL join type is valid, e.g. C or C. It will be placed in the SQL command immediately before C. +=item index_hint + +Adds an index hint for the joined table. + =item proxy An arrayref containing a list of accessors in the foreign class to proxy in @@ -1509,6 +1513,7 @@ sub _resolve_join { ), -alias => $as, -relation_chain_depth => $seen->{-relation_chain_depth} || 0, + -index_hint => $rel_info->{attrs}{index_hint}, }, scalar $self->_resolve_condition($rel_info->{cond}, $as, $alias, $join) ]; diff --git a/lib/DBIx/Class/SQLMaker/MySQL.pm b/lib/DBIx/Class/SQLMaker/MySQL.pm index fdb2d6b..6357acb 100644 --- a/lib/DBIx/Class/SQLMaker/MySQL.pm +++ b/lib/DBIx/Class/SQLMaker/MySQL.pm @@ -46,4 +46,51 @@ sub _lock_select { return " $sql"; } +# Allow index hints. +# TBD: there must be a cleaner way to do this than overriding +# this entire method. The problem is that each DBMS implements +# index hints differently and puts them in different parts of the joins. +sub _gen_from_blocks { + my ($self, $from, @joins) = @_; + + my @fchunks = $self->_from_chunk_to_sql($from); + + for (@joins) { + my ($to, $on) = @$_; + + # check whether a join type exists + my $to_jt = ref($to) eq 'ARRAY' ? $to->[0] : $to; + my $join_type; + if (ref($to_jt) eq 'HASH' and defined($to_jt->{-join_type})) { + $join_type = $to_jt->{-join_type}; + $join_type =~ s/^\s+ | \s+$//xg; + } + + my @j = $self->_generate_join_clause( $join_type ); + + if (ref $to eq 'ARRAY') { + push(@j, '(', $self->_recurse_from(@$to), ')'); + } + else { + push(@j, $self->_from_chunk_to_sql($to)); + } + + # add index hint, if specified + my $index_hint; + if (ref($to_jt) eq 'HASH' and defined($to_jt->{-index_hint})) { + $index_hint = $to_jt->{-index_hint}; + $index_hint =~ s/^\s+ | \s+$//xg; + } + push(@j, ($index_hint ? " $index_hint" : '')); + + my ($sql, @bind) = $self->_join_condition($on); + push(@j, ' ON ', $sql); + push @{$self->{from_bind}}, @bind; + + push @fchunks, join '', @j; + } + + return @fchunks; +} + 1; diff --git a/t/71mysql.t b/t/71mysql.t index c624913..2f61e1b 100644 --- a/t/71mysql.t +++ b/t/71mysql.t @@ -240,6 +240,29 @@ lives_ok { $cd->set_producers ([ $producer ]) } 'set_relationship doesnt die'; ); } +{ + # Test support for index hints + my $cdsrc = $schema->source('CD'); + my $artrel_info = $cdsrc->relationship_info ('artist'); + $cdsrc->add_relationship( + 'artist_hinted', + $artrel_info->{class}, + $artrel_info->{cond}, + { %{$artrel_info->{attrs}}, index_hint => 'FORCE INDEX (rank)' }, + ); + is_same_sql_bind ( + $cdsrc->resultset->search({}, { prefetch => 'artist_hinted' })->as_query, + '( + SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track, + artist_hinted.artistid, artist_hinted.name, artist_hinted.rank, artist_hinted.charfield + FROM cd me + JOIN artist artist_hinted FORCE INDEX (rank) ON artist_hinted.artistid = me.artist + )', + [], + 'index hints supported for mysql' + ); +} + ## Can we properly deal with the null search problem? ## ## Only way is to do a SET SQL_AUTO_IS_NULL = 0; on connect