From: Dagfinn Ilmari Mannsåker Date: Sat, 12 Apr 2014 17:29:47 +0000 (+0100) Subject: Refactor _recurse_fields to return the bind values X-Git-Tag: v0.082800~216 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FDBIx-Class.git;a=commitdiff_plain;h=ad1d374e603e34f4f58d1004d0bf4e2b9982422d Refactor _recurse_fields to return the bind values Only ->select actually wants it in $self->{select_bind}, the others either don't care or want them somewhere else. --- diff --git a/lib/DBIx/Class/ResultSetColumn.pm b/lib/DBIx/Class/ResultSetColumn.pm index 1e2a0eb..b083b46 100644 --- a/lib/DBIx/Class/ResultSetColumn.pm +++ b/lib/DBIx/Class/ResultSetColumn.pm @@ -494,7 +494,7 @@ sub _resultset { # collapse the selector to a literal so that it survives the distinct parse # if it turns out to be an aggregate - at least the user will get a proper exception # instead of silent drop of the group_by altogether - $select = \ $rsrc->storage->sql_maker->_recurse_fields($select); + $select = \[ $rsrc->storage->sql_maker->_recurse_fields($select) ]; } } diff --git a/lib/DBIx/Class/SQLMaker.pm b/lib/DBIx/Class/SQLMaker.pm index e863a0f..319d3fb 100644 --- a/lib/DBIx/Class/SQLMaker.pm +++ b/lib/DBIx/Class/SQLMaker.pm @@ -110,7 +110,7 @@ sub select { my ($self, $table, $fields, $where, $rs_attrs, $limit, $offset) = @_; - $fields = $self->_recurse_fields($fields); + ($fields, @{$self->{select_bind}}) = $self->_recurse_fields($fields); if (defined $offset) { $self->throw_exception('A supplied offset must be a non-negative integer') @@ -231,42 +231,48 @@ sub _recurse_fields { return $$fields if $ref eq 'SCALAR'; if ($ref eq 'ARRAY') { - return join(', ', map { $self->_recurse_fields($_) } @$fields); + my (@select, @bind); + for my $field (@$fields) { + my ($select, @new_bind) = $self->_recurse_fields($field); + push @select, $select; + push @bind, @new_bind; + } + return (join(', ', @select), @bind); } elsif ($ref eq 'HASH') { my %hash = %$fields; # shallow copy my $as = delete $hash{-as}; # if supplied - my ($func, $args, @toomany) = %hash; + my ($func, $rhs, @toomany) = %hash; # there should be only one pair if (@toomany) { $self->throw_exception( "Malformed select argument - too many keys in hash: " . join (',', keys %$fields ) ); } - if (lc ($func) eq 'distinct' && ref $args eq 'ARRAY' && @$args > 1) { + if (lc ($func) eq 'distinct' && ref $rhs eq 'ARRAY' && @$rhs > 1) { $self->throw_exception ( 'The select => { distinct => ... } syntax is not supported for multiple columns.' - .' Instead please use { group_by => [ qw/' . (join ' ', @$args) . '/ ] }' - .' or { select => [ qw/' . (join ' ', @$args) . '/ ], distinct => 1 }' + .' Instead please use { group_by => [ qw/' . (join ' ', @$rhs) . '/ ] }' + .' or { select => [ qw/' . (join ' ', @$rhs) . '/ ], distinct => 1 }' ); } + my ($rhs_sql, @rhs_bind) = $self->_recurse_fields($rhs); my $select = sprintf ('%s( %s )%s', $self->_sqlcase($func), - $self->_recurse_fields($args), + $rhs_sql, $as ? sprintf (' %s %s', $self->_sqlcase('as'), $self->_quote ($as) ) : '' ); - return $select; + return ($select, @rhs_bind); } # Is the second check absolutely necessary? elsif ( $ref eq 'REF' and ref($$fields) eq 'ARRAY' ) { - push @{$self->{select_bind}}, @{$$fields}[1..$#$$fields]; - return $$fields->[0]; + return @{$$fields}; } else { $self->throw_exception( $ref . qq{ unexpected in _recurse_fields()} ); @@ -288,11 +294,9 @@ sub _parse_rs_attrs { my $sql = ''; if ($arg->{group_by}) { - # horrible horrible, waiting for refactor - local $self->{select_bind}; - if (my $g = $self->_recurse_fields($arg->{group_by}) ) { - $sql .= $self->_sqlcase(' group by ') . $g; - push @{$self->{group_bind} ||= []}, @{$self->{select_bind}||[]}; + if ( my ($group_sql, @group_bind) = $self->_recurse_fields($arg->{group_by}) ) { + $sql .= $self->_sqlcase(' group by ') . $group_sql; + push @{$self->{group_bind}}, @group_bind; } } diff --git a/lib/DBIx/Class/SQLMaker/LimitDialects.pm b/lib/DBIx/Class/SQLMaker/LimitDialects.pm index 9abaded..da65b7c 100644 --- a/lib/DBIx/Class/SQLMaker/LimitDialects.pm +++ b/lib/DBIx/Class/SQLMaker/LimitDialects.pm @@ -725,23 +725,22 @@ sub _subqueried_limit_attrs { my ($re_sep, $re_alias) = map { quotemeta $_ } ( $self->{name_sep}, $rs_attrs->{alias} ); - # insulate from the multiple _recurse_fields calls below - local $self->{select_bind}; - # correlate select and as, build selection index my (@sel, $in_sel_index); for my $i (0 .. $#{$rs_attrs->{select}}) { my $s = $rs_attrs->{select}[$i]; - my $sql_sel = $self->_recurse_fields ($s); my $sql_alias = (ref $s) eq 'HASH' ? $s->{-as} : undef; + # we throw away the @bind here deliberately + my ($sql_sel) = $self->_recurse_fields ($s); + push @sel, { arg => $s, sql => $sql_sel, unquoted_sql => do { local $self->{quote_char}; - $self->_recurse_fields ($s); + ($self->_recurse_fields ($s))[0]; # ignore binds again }, as => $sql_alias diff --git a/lib/DBIx/Class/Storage/DBIHacks.pm b/lib/DBIx/Class/Storage/DBIHacks.pm index 80283dc..3c7d1c4 100644 --- a/lib/DBIx/Class/Storage/DBIHacks.pm +++ b/lib/DBIx/Class/Storage/DBIHacks.pm @@ -389,7 +389,6 @@ sub _resolve_aliastypes_from_select_args { my $sql_maker = $self->sql_maker; # these are throw away results, do not pollute the bind stack - local $sql_maker->{select_bind}; local $sql_maker->{where_bind}; local $sql_maker->{group_bind}; local $sql_maker->{having_bind}; @@ -429,7 +428,7 @@ sub _resolve_aliastypes_from_select_args { ), ], selecting => [ - map { $sql_maker->_recurse_fields($_) } @{$attrs->{select}}, + map { ($sql_maker->_recurse_fields($_))[0] } @{$attrs->{select}}, ], ordering => [ map { $_->[0] } $self->_extract_order_criteria ($attrs->{order_by}, $sql_maker),