X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FSQL%2FAbstract.pm;h=343f1f5cab231de7888d77169ae35433fc09ea17;hb=7563d96fae43dda0b2176429af661b7cbd47d495;hp=e50b2068b8fd8b6631436953d6bb2df07bf29257;hpb=a4009a841df44a883a1150228e93baab4c323ab7;p=scpubgit%2FQ-Branch.git diff --git a/lib/SQL/Abstract.pm b/lib/SQL/Abstract.pm index e50b206..343f1f5 100644 --- a/lib/SQL/Abstract.pm +++ b/lib/SQL/Abstract.pm @@ -38,7 +38,6 @@ our $AUTOLOAD; # See section WHERE: BUILTIN SPECIAL OPERATORS below for implementation my @BUILTIN_SPECIAL_OPS = ( {regex => qr/^ (?: not \s )? between $/ix, handler => sub { die "NOPE" }}, - {regex => qr/^ (?: not \s )? in $/ix, handler => sub { die "NOPE" }}, {regex => qr/^ is (?: \s+ not )? $/ix, handler => sub { die "NOPE" }}, ); @@ -68,6 +67,15 @@ sub is_literal_value ($) { : undef; } +sub is_undef_value ($) { + !defined($_[0]) + or ( + ref($_[0]) eq 'HASH' + and exists $_[0]->{-value} + and not defined $_[0]->{-value} + ); +} + # FIXME XSify - this can be done so much more efficiently sub is_plain_value ($) { no strict 'refs'; @@ -162,7 +170,7 @@ sub new { if ($class->isa('DBIx::Class::SQLMaker')) { push @{$opt{special_ops}}, our $DBIC_Compat_Op ||= { - regex => qr/^(?:ident|value)$/i, handler => sub { die "NOPE" } + regex => qr/^(?:ident|value|(?:not\s)?in)$/i, handler => sub { die "NOPE" } }; $opt{is_dbic_sqlmaker} = 1; } @@ -192,6 +200,7 @@ sub new { -and => '_expand_op_andor', -or => '_expand_op_andor', -nest => '_expand_nest', + -bind => sub { shift; +{ @_ } }, }; $opt{expand_op} = { @@ -212,11 +221,9 @@ sub new { my ($op) = $name =~ /^-(.*)$/; $opt{expand_op}{$op} = sub { my ($self, $op, $arg, $k) = @_; - return +{ -op => [ - $self->{cmp}, - $self->_expand_ident(-ident => $k), - $self->_expand_expr({ '-'.$op => $arg }), - ] }; + return $self->_expand_expr_hashpair_cmp( + $k, { "-${op}" => $arg } + ); }; } } @@ -596,10 +603,7 @@ sub _expand_expr { return +{ -literal => $literal }; } if (!ref($expr) or Scalar::Util::blessed($expr)) { - if (my $d = our $Default_Scalar_To) { - return $self->_expand_expr({ $d => $expr }); - } - return $self->_expand_value(-value => $expr); + return $self->_expand_expr_scalar($expr); } die "notreached"; } @@ -622,6 +626,8 @@ sub _expand_expr_hashpair { sub _expand_expr_hashpair_ident { my ($self, $k, $v) = @_; + local our $Cur_Col_Meta = $k; + # hash with multiple or no elements is andor if (ref($v) eq 'HASH' and keys %$v != 1) { @@ -630,33 +636,24 @@ sub _expand_expr_hashpair_ident { # undef needs to be re-sent with cmp to achieve IS/IS NOT NULL - if ( - !defined($v) - or ( - ref($v) eq 'HASH' - and exists $v->{-value} - and not defined $v->{-value} - ) - ) { - return $self->_expand_expr({ $k => { $self->{cmp} => undef } }); + if (is_undef_value($v)) { + return $self->_expand_expr_hashpair_cmp($k => undef); } # scalars and objects get expanded as whatever requested or values if (!ref($v) or Scalar::Util::blessed($v)) { - my $d = our $Default_Scalar_To; - local our $Cur_Col_Meta = $k; - return $self->_expand_expr_hashpair_ident( - $k, - ($d - ? $self->_expand_expr($d => $v) - : { -value => $v } - ) - ); + return $self->_expand_expr_hashpair_scalar($k, $v); } + + # single key hashref is a hashtriple + if (ref($v) eq 'HASH') { return $self->_expand_expr_hashtriple($k, %$v); } + + # arrayref needs re-engineering over the elements + if (ref($v) eq 'ARRAY') { return $self->sqlfalse unless @$v; $self->_debug("ARRAY($k) means distribute over elements"); @@ -669,6 +666,7 @@ sub _expand_expr_hashpair_ident { $logic => $v, $k ); } + if (my $literal = is_literal_value($v)) { unless (length $k) { belch 'Hash-pairs consisting of an empty string with a literal are deprecated, and will be removed in 2.0: use -and => [ $literal ] instead'; @@ -685,6 +683,23 @@ sub _expand_expr_hashpair_ident { die "notreached"; } +sub _expand_expr_scalar { + my ($self, $expr) = @_; + + if (my $d = our $Default_Scalar_To) { + return $self->_expand_expr({ $d => $expr }); + } + return $self->_expand_value(-value => $expr); +} + +sub _expand_expr_hashpair_scalar { + my ($self, $k, $v) = @_; + + return $self->_expand_expr_hashpair_cmp( + $k, $self->_expand_expr_scalar($v), + ); +} + sub _expand_expr_hashpair_op { my ($self, $k, $v) = @_; @@ -701,19 +716,23 @@ sub _expand_expr_hashpair_op { ] }; } - # the old special op system requires illegality for top-level use - if ( - (our $Expand_Depth) == 1 - and List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}} - ) { - puke "Illegal use of top-level '-$op'" - } + { # Old SQLA compat - # the old unary op system means we should touch nothing and let it work + # the old special op system requires illegality for top-level use - if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) { - return { -op => [ $op, $v ] }; + if ( + (our $Expand_Depth) == 1 + and List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}} + ) { + puke "Illegal use of top-level '-$op'" + } + + # the old unary op system means we should touch nothing and let it work + + if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) { + return { -op => [ $op, $v ] }; + } } # an explicit node type is currently assumed to be expanded (this is almost @@ -731,8 +750,10 @@ sub _expand_expr_hashpair_op { and (keys %$v)[0] =~ /^-/ ) { my ($func) = $k =~ /^-(.*)$/; - if (List::Util::first { $func =~ $_->{regex} } @{$self->{special_ops}}) { - return +{ -op => [ $func, $self->_expand_expr($v) ] }; + { # Old SQLA compat + if (List::Util::first { $func =~ $_->{regex} } @{$self->{special_ops}}) { + return +{ -op => [ $func, $self->_expand_expr($v) ] }; + } } return +{ -func => [ $func, $self->_expand_expr($v) ] }; } @@ -746,6 +767,11 @@ sub _expand_expr_hashpair_op { die "notreached"; } +sub _expand_expr_hashpair_cmp { + my ($self, $k, $v) = @_; + $self->_expand_expr_hashtriple($k, $self->{cmp}, $v); +} + sub _expand_expr_hashtriple { my ($self, $k, $vk, $vv) = @_; @@ -760,15 +786,17 @@ sub _expand_expr_hashtriple { local our $Cur_Col_Meta = $k; return $self->$x($op, $vv, $k); } - if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}) { - return { -op => [ $op, $ik, $vv ] }; - } - if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) { - return { -op => [ - $self->{cmp}, - $ik, - { -op => [ $op, $vv ] } - ] }; + { # Old SQLA compat + if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}) { + return { -op => [ $op, $ik, $vv ] }; + } + if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) { + return { -op => [ + $self->{cmp}, + $ik, + { -op => [ $op, $vv ] } + ] }; + } } if (ref($vv) eq 'ARRAY') { my @raw = @$vv; @@ -795,14 +823,7 @@ sub _expand_expr_hashtriple { } return $self->_expand_op_andor($logic => \@values, $k); } - if ( - !defined($vv) - or ( - ref($vv) eq 'HASH' - and exists $vv->{-value} - and not defined $vv->{-value} - ) - ) { + if (is_undef_value($vv)) { my $is = ($self->_dwim_op_to_is($op, "Supplying an undefined argument to '%s' is deprecated", "unexpected operator '%s' with undef operand", @@ -1061,6 +1082,37 @@ sub _render_literal { return @$literal; } +sub _render_op { + my ($self, $v) = @_; + my ($op, @args) = @$v; + if (my $r = $self->{render_op}{$op}) { + return $self->$r($op, \@args); + } + + { # Old SQLA compat + + my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}; + if ($us and @args > 1) { + puke "Special op '${op}' requires first value to be identifier" + unless my ($ident) = map $_->{-ident}, grep ref($_) eq 'HASH', $args[0]; + my $k = join(($self->{name_sep}||'.'), @$ident); + local our $Expand_Depth = 1; + return $self->${\($us->{handler})}($k, $op, $args[1]); + } + if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) { + return $self->${\($us->{handler})}($op, $args[0]); + } + + } + if (@args == 1) { + return $self->_render_unop_prefix($op, \@args); + } else { + return $self->_render_op_multop($op, \@args); + } + die "notreached"; +} + + sub _render_op_between { my ($self, $op, $args) = @_; my ($left, $low, $high) = @$args; @@ -1123,32 +1175,6 @@ sub _render_op_multop { map @{$_}[1..$#$_], @parts ); } - -sub _render_op { - my ($self, $v) = @_; - my ($op, @args) = @$v; - if (my $r = $self->{render_op}{$op}) { - return $self->$r($op, \@args); - } - my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}; - if ($us and @args > 1) { - puke "Special op '${op}' requires first value to be identifier" - unless my ($ident) = map $_->{-ident}, grep ref($_) eq 'HASH', $args[0]; - my $k = join(($self->{name_sep}||'.'), @$ident); - local our $Expand_Depth = 1; - return $self->${\($us->{handler})}($k, $op, $args[1]); - } - if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) { - return $self->${\($us->{handler})}($op, $args[0]); - } - if (@args == 1) { - return $self->_render_unop_prefix($op, \@args); - } else { - return $self->_render_op_multop($op, \@args); - } - die "notreached"; -} - sub _render_op_not { my ($self, $op, $v) = @_; my ($sql, @bind) = $self->_render_unop_prefix($op, $v);