X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FSQL%2FAbstract.pm;h=65dc20426aa5808f4f9f125a1869da59bc6d2348;hb=1279622f9ff55dd447a3e5a2e99f35cacfe667bb;hp=baf9bb82b43f6f26a69e68678918e780e0e25d69;hpb=2809a2ff9b013f84dc872b28fec7116c8c3dc3b1;p=scpubgit%2FQ-Branch.git diff --git a/lib/SQL/Abstract.pm b/lib/SQL/Abstract.pm index baf9bb8..65dc204 100644 --- a/lib/SQL/Abstract.pm +++ b/lib/SQL/Abstract.pm @@ -39,6 +39,9 @@ our $AUTOLOAD; my @BUILTIN_SPECIAL_OPS = ( {regex => qr/^ (?: not \s )? between $/ix, handler => sub { die "NOPE" }}, {regex => qr/^ is (?: \s+ not )? $/ix, handler => sub { die "NOPE" }}, + {regex => qr/^ (?: not \s )? in $/ix, handler => sub { die "NOPE" }}, + {regex => qr/^ ident $/ix, handler => sub { die "NOPE" }}, + {regex => qr/^ value $/ix, handler => sub { die "NOPE" }}, ); #====================================================================== @@ -169,10 +172,8 @@ sub new { push @{$opt{special_ops}}, @BUILTIN_SPECIAL_OPS; if ($class->isa('DBIx::Class::SQLMaker')) { - push @{$opt{special_ops}}, our $DBIC_Compat_Op ||= { - regex => qr/^(?:ident|value|(?:not\s)?in)$/i, handler => sub { die "NOPE" } - }; $opt{is_dbic_sqlmaker} = 1; + $opt{disable_old_special_ops} = 1; } # unary operators @@ -201,6 +202,20 @@ sub new { -or => '_expand_op_andor', -nest => '_expand_nest', -bind => sub { shift; +{ @_ } }, + -in => '_expand_in', + -not_in => '_expand_in', + -tuple => sub { + my ($self, $node, $args) = @_; + +{ $node => [ map $self->expand_expr($_), @$args ] }; + }, + -between => '_expand_between', + -not_between => '_expand_between', + -op => sub { + my ($self, $node, $args) = @_; + my ($op, @opargs) = @$args; + +{ $node => [ $op, map $self->expand_expr($_), @opargs ] }; + }, + (map +($_ => '_expand_op_is'), ('-is', '-is_not')), }; $opt{expand_op} = { @@ -229,7 +244,7 @@ sub new { } $opt{render} = { - (map +("-$_", "_render_$_"), qw(op func bind ident literal list)), + (map +("-$_", "_render_$_"), qw(op func bind ident literal tuple)), %{$opt{render}||{}} }; @@ -241,6 +256,7 @@ sub new { ), (not => '_render_op_not'), (map +($_ => '_render_op_andor'), qw(and or)), + ',' => '_render_op_multop', }; return bless \%opt, $class; @@ -292,7 +308,7 @@ sub _returning { my $f = $options->{returning}; my ($sql, @bind) = $self->render_aqt( - $self->_expand_maybe_list_expr($f, undef, -ident) + $self->_expand_maybe_list_expr($f, -ident) ); return wantarray ? $self->_sqlcase(' returning ') . $sql @@ -494,7 +510,7 @@ sub _select_fields { my ($self, $fields) = @_; return $fields unless ref($fields); return $self->render_aqt( - $self->_expand_maybe_list_expr($fields, undef, '-ident') + $self->_expand_maybe_list_expr($fields, '-ident') ); } @@ -729,6 +745,7 @@ sub _expand_expr_hashpair_op { if ( (our $Expand_Depth) == 1 + and $self->{disable_old_special_ops} and List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}} ) { puke "Illegal use of top-level '-$op'" @@ -961,6 +978,8 @@ sub _expand_op_andor { sub _expand_op_is { my ($self, $op, $vv, $k) = @_; + $op =~ s/^-//; + ($k, $vv) = @$vv unless defined $k; puke "$op can only take undef as argument" if defined($vv) and not ( @@ -968,12 +987,13 @@ sub _expand_op_is { and exists($vv->{-value}) and !defined($vv->{-value}) ); - return +{ -op => [ $op.'_null', $self->_expand_ident(-ident => $k) ] }; + return +{ -op => [ $op.'_null', $self->expand_expr($k, -ident) ] }; } sub _expand_between { my ($self, $op, $vv, $k) = @_; - local our $Cur_Col_Meta = $k; + $op =~ s/^-//; + $k = shift @{$vv = [ @$vv ]} unless defined $k; my @rhs = map $self->_expand_expr($_), ref($vv) eq 'ARRAY' ? @$vv : $vv; unless ( @@ -985,18 +1005,20 @@ sub _expand_between { } return +{ -op => [ $op, - $self->_expand_ident(-ident => $k), + $self->expand_expr(ref($k) ? $k : { -ident => $k }), @rhs ] } } sub _expand_in { - my ($self, $op, $vv, $k) = @_; + my ($self, $raw, $vv, $k) = @_; + $k = shift @{$vv = [ @$vv ]} unless defined $k; + my $op = $self->_normalize_op($raw); if (my $literal = is_literal_value($vv)) { my ($sql, @bind) = @$literal; my $opened_sql = $self->_open_outer_paren($sql); return +{ -op => [ - $op, $self->_expand_ident(-ident => $k), + $op, $self->expand_expr($k, -ident), [ { -literal => [ $opened_sql, @bind ] } ] ] }; } @@ -1008,15 +1030,14 @@ sub _expand_in { ; puke("Argument passed to the '${\uc($op)}' operator can not be undefined") if !defined($vv); - my @rhs = map $self->_expand_expr($_), - map { ref($_) ? $_ : { -bind => [ $k, $_ ] } } + my @rhs = map $self->expand_expr($_, -value), map { defined($_) ? $_: puke($undef_err) } (ref($vv) eq 'ARRAY' ? @$vv : $vv); return $self->${\($op =~ /^not/ ? 'sqltrue' : 'sqlfalse')} unless @rhs; return +{ -op => [ $op, - $self->_expand_ident(-ident => $k), + $self->expand_expr($k, -ident), \@rhs ] }; } @@ -1066,10 +1087,10 @@ sub _render_ident { return $self->_convert($self->_quote($ident)); } -sub _render_list { - my ($self, $list) = @_; - my @parts = grep length($_->[0]), map [ $self->render_aqt($_) ], @$list; - return join(', ', map $_->[0], @parts), map @{$_}[1..$#$_], @parts; +sub _render_tuple { + my ($self, $values) = @_; + my ($sql, @bind) = $self->_render_op([ ',', @$values ]); + return "($sql)", @bind; } sub _render_func { @@ -1186,7 +1207,7 @@ sub _render_op_multop { return '' unless @parts; return @{$parts[0]} if @parts == 1; my ($final_sql) = join( - ' '.$self->_sqlcase(join ' ', split '_', $op).' ', + ($op eq ',' ? '' : ' ').$self->_sqlcase(join ' ', split '_', $op).' ', map $_->[0], @parts ); return ( @@ -1272,7 +1293,9 @@ sub _expand_order_by { ), map $self->expand_expr($_, -ident), map ref($_) eq 'ARRAY' ? @$_ : $_, @to_expand; - return (@exp > 1 ? { -list => \@exp } : $exp[0]); + return undef unless @exp; + return undef if @exp == 1 and not defined($exp[0]); + return +{ -op => [ ',', @exp ] }; }; local @{$self->{expand}}{qw(-asc -desc)} = (($expander) x 2); @@ -1311,8 +1334,9 @@ sub _chunkify_order_by { if $expanded->{-ident} or @{$expanded->{-literal}||[]} == 1; for ($expanded) { - if (ref() eq 'HASH' and my $l = $_->{-list}) { - return map $self->_chunkify_order_by($_), @$l; + if (ref() eq 'HASH' and $_->{-op} and $_->{-op}[0] eq ',') { + my ($comma, @list) = @{$_->{-op}}; + return map $self->_chunkify_order_by($_), @list; } return [ $self->render_aqt($_) ]; } @@ -1326,7 +1350,7 @@ sub _table { my $self = shift; my $from = shift; ($self->render_aqt( - $self->_expand_maybe_list_expr($from, undef, -ident) + $self->_expand_maybe_list_expr($from, -ident) ))[0]; } @@ -1336,18 +1360,11 @@ sub _table { #====================================================================== sub _expand_maybe_list_expr { - my ($self, $expr, $logic, $default) = @_; - my $e = do { - if (ref($expr) eq 'ARRAY') { - return { -list => [ - map $self->expand_expr($_, $default), @$expr - ] } if @$expr > 1; - $expr->[0] - } else { - $expr - } - }; - return $self->expand_expr($e, $default); + my ($self, $expr, $default) = @_; + return +{ -op => [ ',', + map $self->expand_expr($_, $default), + ref($expr) eq 'ARRAY' ? @$expr : $expr + ] }; } # highly optimized, as it's called way too often