X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FSQL%2FAbstract.pm;h=238d86930629fe2498cf713abe750652699a9cb7;hb=e82e648a6dd74bc04c2424b7b4a183115ab3de10;hp=f6467905e8bc2cd10694ca48176d8e6b229ec037;hpb=b8db59b809f637a299f69e7718edc831b6192373;p=dbsrgits%2FSQL-Abstract.git diff --git a/lib/SQL/Abstract.pm b/lib/SQL/Abstract.pm index f646790..238d869 100644 --- a/lib/SQL/Abstract.pm +++ b/lib/SQL/Abstract.pm @@ -15,7 +15,7 @@ use Scalar::Util (); # GLOBALS #====================================================================== -our $VERSION = '1.68'; +our $VERSION = '1.71'; # This would confuse some packagers $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases @@ -118,22 +118,26 @@ sub insert { my ($sql, @bind) = $self->$method($data); $sql = join " ", $self->_sqlcase('insert into'), $table, $sql; - if (my $ret = $options->{returning}) { - $sql .= $self->_insert_returning ($ret); + if ($options->{returning}) { + my ($s, @b) = $self->_insert_returning ($options); + $sql .= $s; + push @bind, @b; } return wantarray ? ($sql, @bind) : $sql; } sub _insert_returning { - my ($self, $fields) = @_; + my ($self, $options) = @_; - my $f = $self->_SWITCH_refkind($fields, { - ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$fields;}, - SCALAR => sub {$self->_quote($fields)}, - SCALARREF => sub {$$fields}, + my $f = $options->{returning}; + + my $fieldlist = $self->_SWITCH_refkind($f, { + ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$f;}, + SCALAR => sub {$self->_quote($f)}, + SCALARREF => sub {$$f}, }); - return join (' ', $self->_sqlcase(' returning'), $f); + return $self->_sqlcase(' returning ') . $fieldlist; } sub _insert_HASHREF { # explicit list of fields and then values @@ -280,7 +284,19 @@ sub update { }, SCALARREF => sub { # literal SQL without bind push @set, "$label = $$v"; - }, + }, + HASHREF => sub { + my ($op, $arg, @rest) = %$v; + + puke 'Operator calls in update must be in the form { -op => $arg }' + if (@rest or not $op =~ /^\-(.+)/); + + local $self->{_nested_func_lhs} = $k; + my ($sql, @bind) = $self->_where_unary_op ($1, $arg); + + push @set, "$label = $sql"; + push @all_bind, @bind; + }, SCALAR_or_UNDEF => sub { push @set, "$label = ?"; push @all_bind, $self->_bindtype($k, $v); @@ -471,29 +487,16 @@ sub _where_HASHREF { $op =~ s/^not_/NOT /i; $self->_debug("Unary OP(-$op) within hashref, recursing..."); - - my $op_entry = List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}; - if (my $handler = $op_entry->{handler}) { - if (not ref $handler) { - if ($op =~ s/ [_\s]? \d+ $//x ) { - belch 'Use of [and|or|nest]_N modifiers is deprecated and will be removed in SQLA v2.0. ' - . "You probably wanted ...-and => [ -$op => COND1, -$op => COND2 ... ]"; - } - $self->$handler ($op, $v); - } - elsif (ref $handler eq 'CODE') { - $handler->($self, $op, $v); - } - else { - puke "Illegal handler for operator $k - expecting a method name or a coderef"; - } - } - else { - $self->debug("Generic unary OP: $k - recursing as function"); - my ($s, @b) = $self->_where_func_generic ($op, $v); - $s = "($s)" unless (defined($self->{_nested_func_lhs}) && ($self->{_nested_func_lhs} eq $k)); # top level vs nested - ($s, @b); - } + my ($s, @b) = $self->_where_unary_op ($op, $v); + + # top level vs nested + # we assume that handled unary ops will take care of their ()s + $s = "($s)" unless ( + List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}} + or + defined($self->{_nested_func_lhs}) && ($self->{_nested_func_lhs} eq $k) + ); + ($s, @b); } else { my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $v); @@ -508,9 +511,29 @@ sub _where_HASHREF { return $self->_join_sql_clauses('and', \@sql_clauses, \@all_bind); } -sub _where_func_generic { +sub _where_unary_op { my ($self, $op, $rhs) = @_; + if (my $op_entry = List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}) { + my $handler = $op_entry->{handler}; + + if (not ref $handler) { + if ($op =~ s/ [_\s]? \d+ $//x ) { + belch 'Use of [and|or|nest]_N modifiers is deprecated and will be removed in SQLA v2.0. ' + . "You probably wanted ...-and => [ -$op => COND1, -$op => COND2 ... ]"; + } + return $self->$handler ($op, $rhs); + } + elsif (ref $handler eq 'CODE') { + return $handler->($self, $op, $rhs); + } + else { + puke "Illegal handler for operator $op - expecting a method name or a coderef"; + } + } + + $self->debug("Generic unary OP: $op - recursing as function"); + my ($sql, @bind) = $self->_SWITCH_refkind ($rhs, { SCALAR => sub { puke "Illegal use of top-level '$op'" @@ -714,7 +737,7 @@ sub _where_hashpair_HASHREF { # retain for proper column type bind $self->{_nested_func_lhs} ||= $k; - ($sql, @bind) = $self->_where_func_generic ($op, $val); + ($sql, @bind) = $self->_where_unary_op ($op, $val); $sql = join (' ', $self->_convert($self->_quote($k)), @@ -871,7 +894,7 @@ sub _where_field_BETWEEN { foreach my $val (@$vals) { my ($sql, @bind) = $self->_SWITCH_refkind($val, { SCALAR => sub { - return ($placeholder, $val); + return ($placeholder, $self->_bindtype($k, $val) ); }, SCALARREF => sub { return $$val; @@ -886,7 +909,7 @@ sub _where_field_BETWEEN { puke ("Only simple { -func => arg } functions accepted as sub-arguments to BETWEEN") if (@rest or $func !~ /^ \- (.+)/x); local $self->{_nested_func_lhs} = $k; - $self->_where_func_generic ($1 => $arg); + $self->_where_unary_op ($1 => $arg); } }); push @all_sql, $sql; @@ -895,7 +918,7 @@ sub _where_field_BETWEEN { return ( (join $and, @all_sql), - $self->_bindtype($k, @all_bind), + @all_bind ); }, FALLBACK => sub { @@ -941,8 +964,11 @@ sub _where_field_IN { puke ("Only simple { -func => arg } functions accepted as sub-arguments to IN") if (@rest or $func !~ /^ \- (.+)/x); local $self->{_nested_func_lhs} = $k; - $self->_where_func_generic ($1 => $arg); - } + $self->_where_unary_op ($1 => $arg); + }, + UNDEF => sub { + return $self->_sqlcase('null'); + }, }); push @all_sql, $sql; push @all_bind, @bind; @@ -2682,6 +2708,15 @@ a fast interface to returning and formatting data. I frequently use these three modules together to write complex database query apps in under 50 lines. +=head1 REPO + +=over + +=item * gitweb: L + +=item * git: L + +=back =head1 CHANGES