File Coverage

blib/lib/SQL/Abstract/Classic.pm
Criterion Covered Total %
statement 552 635 86.9
branch 180 240 75.0
condition 95 141 67.3
subroutine 112 130 86.1
pod 8 10 80.0
total 947 1156 81.9


line stmt bran cond sub pod time code
1             package SQL::Abstract::Classic;
2              
3 13     13   1229612 use strict;
  13         69  
  13         316  
4 13     13   55 use warnings;
  13         21  
  13         262  
5 13     13   55 use Carp ();
  13         20  
  13         174  
6 13     13   50 use List::Util ();
  13         21  
  13         157  
7 13     13   51 use Scalar::Util ();
  13         37  
  13         160  
8 13     13   4367 use SQL::Abstract::Util ();
  13         27  
  13         101295  
9              
10             #======================================================================
11             # GLOBALS
12             #======================================================================
13              
14             our $VERSION = '1.91';
15              
16             # This would confuse some packagers
17             $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
18              
19             our $AUTOLOAD;
20              
21             # special operators (-in, -between). May be extended/overridden by user.
22             # See section WHERE: BUILTIN SPECIAL OPERATORS below for implementation
23             my @BUILTIN_SPECIAL_OPS = (
24             {regex => qr/^ (?: not \s )? between $/ix, handler => '_where_field_BETWEEN'},
25             {regex => qr/^ (?: not \s )? in $/ix, handler => '_where_field_IN'},
26             {regex => qr/^ ident $/ix, handler => '_where_op_IDENT'},
27             {regex => qr/^ value $/ix, handler => '_where_op_VALUE'},
28             {regex => qr/^ is (?: \s+ not )? $/ix, handler => '_where_field_IS'},
29             );
30              
31             # unaryish operators - key maps to handler
32             my @BUILTIN_UNARY_OPS = (
33             # the digits are backcompat stuff
34             { regex => qr/^ and (?: [_\s]? \d+ )? $/xi, handler => '_where_op_ANDOR' },
35             { regex => qr/^ or (?: [_\s]? \d+ )? $/xi, handler => '_where_op_ANDOR' },
36             { regex => qr/^ nest (?: [_\s]? \d+ )? $/xi, handler => '_where_op_NEST' },
37             { regex => qr/^ (?: not \s )? bool $/xi, handler => '_where_op_BOOL' },
38             { regex => qr/^ ident $/xi, handler => '_where_op_IDENT' },
39             { regex => qr/^ value $/xi, handler => '_where_op_VALUE' },
40             );
41              
42             #======================================================================
43             # DEBUGGING AND ERROR REPORTING
44             #======================================================================
45              
46             sub _debug {
47 1148 50   1148   2318 return unless $_[0]->{debug}; shift; # a little faster
  0         0  
48 0         0 my $func = (caller(1))[3];
49 0         0 warn "[$func] ", @_, "\n";
50             }
51              
52             sub belch (@) {
53             # Fugly as hell - allow calls as functions ( backcompat ) and as methods ( subclassing )
54             shift
55 148 50 33 148 0 620 if @_ > 1 and length( ref ( $_[0] ) );
56              
57 148         419 my($func) = (caller(1))[3];
58 148         6932 Carp::carp "[$func] Warning: ", @_;
59             }
60              
61             sub puke (@) {
62             # Fugly as hell - allow calls as functions ( backcompat ) and as methods ( subclassing )
63             shift
64 116 50 33 116 0 457 if @_ > 1 and length( ref ( $_[0] ) );
65              
66 116         340 my($func) = (caller(1))[3];
67 116         4750 Carp::croak "[$func] Fatal: ", @_;
68             }
69              
70              
71             #======================================================================
72             # NEW
73             #======================================================================
74              
75             sub new {
76 599     599 1 8137 my $self = shift;
77 599   33     2094 my $class = ref($self) || $self;
78 599 100       1866 my %opt = (ref $_[0] eq 'HASH') ? %{$_[0]} : @_;
  101         274  
79              
80             # choose our case by keeping an option around
81 599 100 100     1447 delete $opt{case} if $opt{case} && $opt{case} ne 'lower';
82              
83             # default logic for interpreting arrayrefs
84 599 100       1285 $opt{logic} = $opt{logic} ? uc $opt{logic} : 'OR';
85              
86             # how to return bind vars
87 599   100     2022 $opt{bindtype} ||= 'normal';
88              
89             # default comparison is "=", but can be overridden
90 599   100     1790 $opt{cmp} ||= '=';
91              
92             # try to recognize which are the 'equality' and 'inequality' ops
93             # (temporary quickfix (in 2007), should go through a more seasoned API)
94 599         3210 $opt{equality_op} = qr/^( \Q$opt{cmp}\E | \= )$/ix;
95 599         1317 $opt{inequality_op} = qr/^( != | <> )$/ix;
96              
97 599         1308 $opt{like_op} = qr/^ (is\s+)? r?like $/xi;
98 599         1077 $opt{not_like_op} = qr/^ (is\s+)? not \s+ r?like $/xi;
99              
100             # SQL booleans
101 599   50     2256 $opt{sqltrue} ||= '1=1';
102 599   50     1846 $opt{sqlfalse} ||= '0=1';
103              
104             # special operators
105 599   100     2000 $opt{special_ops} ||= [];
106             # regexes are applied in order, thus push after user-defines
107 599         778 push @{$opt{special_ops}}, @BUILTIN_SPECIAL_OPS;
  599         1459  
108              
109             # unary operators
110 599   50     1901 $opt{unary_ops} ||= [];
111 599         683 push @{$opt{unary_ops}}, @BUILTIN_UNARY_OPS;
  599         1223  
112              
113             # rudimentary sanity-check for user supplied bits treated as functions/operators
114             # If a purported function matches this regular expression, an exception is thrown.
115             # Literal SQL is *NOT* subject to this check, only functions (and column names
116             # when quoting is not in effect)
117              
118             # FIXME
119             # need to guard against ()'s in column names too, but this will break tons of
120             # hacks... ideas anyone?
121 599   33     2727 $opt{injection_guard} ||= qr/
122             \;
123             |
124             ^ \s* go \s
125             /xmi;
126              
127 599         1655 return bless \%opt, $class;
128             }
129              
130              
131             sub _assert_pass_injection_guard {
132 1778 100   1778   8929 if ($_[1] =~ $_[0]->{injection_guard}) {
133 5         10 my $class = ref $_[0];
134 5         19 $_[0]->puke(
135             "Possible SQL injection attempt '$_[1]'. If this is indeed a part of the "
136             . "desired SQL use literal SQL ( \'...' or \[ '...' ] ) or supply your own "
137             . "{injection_guard} attribute to ${class}->new()"
138             );
139             }
140             }
141              
142              
143             #======================================================================
144             # INSERT methods
145             #======================================================================
146              
147             sub insert {
148 49     49 1 3656 my $self = shift;
149 49         120 my $table = $self->_table(shift);
150 49   50     299 my $data = shift || return;
151 49         68 my $options = shift;
152              
153 49         114 my $method = $self->_METHOD_FOR_refkind("_insert", $data);
154 49         114 my ($sql, @bind) = $self->$method($data);
155 47         111 $sql = join " ", $self->_sqlcase('insert into'), $table, $sql;
156              
157 47 100       129 if ($options->{returning}) {
158 10         19 my ($s, @b) = $self->_insert_returning ($options);
159 10         17 $sql .= $s;
160 10         17 push @bind, @b;
161             }
162              
163 47 50       289 return wantarray ? ($sql, @bind) : $sql;
164             }
165              
166             sub _insert_returning {
167 10     10   18 my ($self, $options) = @_;
168              
169 10         14 my $f = $options->{returning};
170              
171             my $fieldlist = $self->_SWITCH_refkind($f, {
172 2     2   3 ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$f;},
  6         12  
173 4     4   7 SCALAR => sub {$self->_quote($f)},
174 4     4   10 SCALARREF => sub {$$f},
175 10         54 });
176 10         51 return $self->_sqlcase(' returning ') . $fieldlist;
177             }
178              
179             sub _insert_HASHREF { # explicit list of fields and then values
180 28     28   49 my ($self, $data) = @_;
181              
182 28         131 my @fields = sort keys %$data;
183              
184 28         87 my ($sql, @bind) = $self->_insert_values($data);
185              
186             # assemble SQL
187 26         75 $_ = $self->_quote($_) foreach @fields;
188 26         80 $sql = "( ".join(", ", @fields).") ".$sql;
189              
190 26         88 return ($sql, @bind);
191             }
192              
193             sub _insert_ARRAYREF { # just generate values(?,?) part (no list of fields)
194 21     21   44 my ($self, $data) = @_;
195              
196             # no names (arrayref) so can't generate bindtype
197 21 50       52 $self->{bindtype} ne 'columns'
198             or $self->belch( "can't do 'columns' bindtype when called with arrayref" );
199              
200             # fold the list of values into a hash of column name - value pairs
201             # (where the column names are artificially generated, and their
202             # lexicographical ordering keep the ordering of the original list)
203 21         31 my $i = "a"; # incremented values will be in lexicographical order
204 21         37 my $data_in_hash = { map { ($i++ => $_) } @$data };
  106         221  
205              
206 21         58 return $self->_insert_values($data_in_hash);
207             }
208              
209             sub _insert_ARRAYREFREF { # literal SQL with bind
210 0     0   0 my ($self, $data) = @_;
211              
212 0         0 my ($sql, @bind) = @${$data};
  0         0  
213 0         0 $self->_assert_bindval_matches_bindtype(@bind);
214              
215 0         0 return ($sql, @bind);
216             }
217              
218              
219             sub _insert_SCALARREF { # literal SQL without bind
220 0     0   0 my ($self, $data) = @_;
221              
222 0         0 return ($$data);
223             }
224              
225             sub _insert_values {
226 49     49   84 my ($self, $data) = @_;
227              
228 49         78 my (@values, @all_bind);
229 49         167 foreach my $column (sort keys %$data) {
230 201         353 my $v = $data->{$column};
231              
232             $self->_SWITCH_refkind($v, {
233              
234             ARRAYREF => sub {
235 5 100   5   13 if ($self->{array_datatypes}) { # if array datatype are activated
236 4         5 push @values, '?';
237 4         8 push @all_bind, $self->_bindtype($column, $v);
238             }
239             else { # else literal SQL with bind
240 1         2 my ($sql, @bind) = @$v;
241 1         4 $self->_assert_bindval_matches_bindtype(@bind);
242 1         1 push @values, $sql;
243 1         35 push @all_bind, @bind;
244             }
245             },
246              
247             ARRAYREFREF => sub { # literal SQL with bind
248 11     11   17 my ($sql, @bind) = @${$v};
  11         28  
249 11         37 $self->_assert_bindval_matches_bindtype(@bind);
250 9         16 push @values, $sql;
251 9         70 push @all_bind, @bind;
252             },
253              
254             # THINK: anything useful to do with a HASHREF ?
255             HASHREF => sub { # (nothing, but old SQLA passed it through)
256             #TODO in SQLA >= 2.0 it will die instead
257 2     2   8 $self->belch( "HASH ref as bind value in insert is not supported" );
258 2         2263 push @values, '?';
259 2         74 push @all_bind, $self->_bindtype($column, $v);
260             },
261              
262             SCALARREF => sub { # literal SQL without bind
263 6     6   46 push @values, $$v;
264             },
265              
266             SCALAR_or_UNDEF => sub {
267 177     177   245 push @values, '?';
268 177         299 push @all_bind, $self->_bindtype($column, $v);
269             },
270              
271 201         1402 });
272              
273             }
274              
275 47         132 my $sql = $self->_sqlcase('values')." ( ".join(", ", @values)." )";
276 47         185 return ($sql, @all_bind);
277             }
278              
279              
280              
281             #======================================================================
282             # UPDATE methods
283             #======================================================================
284              
285              
286             sub update {
287 32     32 1 12805 my $self = shift;
288 32         82 my $table = $self->_table(shift);
289 32   50     195 my $data = shift || return;
290 32         61 my $where = shift;
291              
292             # first build the 'SET' part of the sql statement
293 32         55 my (@set, @all_bind);
294 32 50       81 $self->puke( "Unsupported data type specified to \$sql->update" )
295             unless ref $data eq 'HASH';
296              
297 32         150 for my $k (sort keys %$data) {
298 72         121 my $v = $data->{$k};
299 72         100 my $r = ref $v;
300 72         129 my $label = $self->_quote($k);
301              
302             $self->_SWITCH_refkind($v, {
303             ARRAYREF => sub {
304 4 50   4   13 if ($self->{array_datatypes}) { # array datatype
305 4         9 push @set, "$label = ?";
306 4         9 push @all_bind, $self->_bindtype($k, $v);
307             }
308             else { # literal SQL with bind
309 0         0 my ($sql, @bind) = @$v;
310 0         0 $self->_assert_bindval_matches_bindtype(@bind);
311 0         0 push @set, "$label = $sql";
312 0         0 push @all_bind, @bind;
313             }
314             },
315             ARRAYREFREF => sub { # literal SQL with bind
316 10     10   13 my ($sql, @bind) = @${$v};
  10         24  
317 10         31 $self->_assert_bindval_matches_bindtype(@bind);
318 8         20 push @set, "$label = $sql";
319 8         78 push @all_bind, @bind;
320             },
321             SCALARREF => sub { # literal SQL without bind
322 0     0   0 push @set, "$label = $$v";
323             },
324             HASHREF => sub {
325 4     4   12 my ($op, $arg, @rest) = %$v;
326              
327 4 50 33     28 $self->puke( 'Operator calls in update must be in the form { -op => $arg }' )
328             if (@rest or not $op =~ /^\-(.+)/);
329              
330 4         10 local $self->{_nested_func_lhs} = $k;
331 4         12 my ($sql, @bind) = $self->_where_unary_op ($1, $arg);
332              
333 4         15 push @set, "$label = $sql";
334 4         48 push @all_bind, @bind;
335             },
336             SCALAR_or_UNDEF => sub {
337 54     54   136 push @set, "$label = ?";
338 54         99 push @all_bind, $self->_bindtype($k, $v);
339             },
340 72         688 });
341             }
342              
343             # generate sql
344 30         79 my $sql = $self->_sqlcase('update') . " $table " . $self->_sqlcase('set ')
345             . join ', ', @set;
346              
347 30 100       92 if ($where) {
348 24         55 my($where_sql, @where_bind) = $self->where($where);
349 24         55 $sql .= $where_sql;
350 24         45 push @all_bind, @where_bind;
351             }
352              
353 30 50       210 return wantarray ? ($sql, @all_bind) : $sql;
354             }
355              
356              
357              
358              
359             #======================================================================
360             # SELECT
361             #======================================================================
362              
363              
364             sub select {
365 102     102 1 20933 my $self = shift;
366 102         253 my $table = $self->_table(shift);
367 102   50     584 my $fields = shift || '*';
368 102         153 my $where = shift;
369 102         121 my $order = shift;
370              
371 102         200 my($where_sql, @bind) = $self->where($where, $order);
372              
373 89 100       223 my $f = (ref $fields eq 'ARRAY') ? join ', ', map { $self->_quote($_) } @$fields
  17         26  
374             : $fields;
375 89         183 my $sql = join(' ', $self->_sqlcase('select'), $f,
376             $self->_sqlcase('from'), $table)
377             . $where_sql;
378              
379 89 100       533 return wantarray ? ($sql, @bind) : $sql;
380             }
381              
382             #======================================================================
383             # DELETE
384             #======================================================================
385              
386              
387             sub delete {
388 4     4 1 162 my $self = shift;
389 4         10 my $table = $self->_table(shift);
390 4         20 my $where = shift;
391              
392              
393 4         8 my($where_sql, @bind) = $self->where($where);
394 4         8 my $sql = $self->_sqlcase('delete from ') . $table . $where_sql;
395              
396 4 50       23 return wantarray ? ($sql, @bind) : $sql;
397             }
398              
399              
400             #======================================================================
401             # WHERE: entry point
402             #======================================================================
403              
404              
405              
406             # Finally, a separate routine just to handle WHERE clauses
407             sub where {
408 607     607 1 160125 my ($self, $where, $order) = @_;
409              
410             # where ?
411 607         1202 my ($sql, @bind) = $self->_recurse_where($where);
412 497 100 66     1774 $sql = (defined $sql and length $sql) ? $self->_sqlcase(' where ') . "( $sql )" : '';
413              
414             # order by?
415 497 100       945 if ($order) {
416 50         100 my ($order_sql, @order_bind) = $self->_order_by($order);
417 50         103 $sql .= $order_sql;
418 50         79 push @bind, @order_bind;
419             }
420              
421 497 50       2374 return wantarray ? ($sql, @bind) : $sql;
422             }
423              
424              
425             sub _recurse_where {
426 1459     1459   2332 my ($self, $where, $logic) = @_;
427              
428             # dispatch on appropriate method according to refkind of $where
429 1459         2570 my $method = $self->_METHOD_FOR_refkind("_where", $where);
430              
431 1459         2954 my ($sql, @bind) = $self->$method($where, $logic);
432              
433             # DBIx::Class used to call _recurse_where in scalar context
434             # something else might too...
435 1335 50       2754 if (wantarray) {
436 1335         4280 return ($sql, @bind);
437             }
438             else {
439 0         0 $self->belch( "Calling _recurse_where in scalar context is deprecated and will go away before 2.0" );
440 0         0 return $sql;
441             }
442             }
443              
444              
445              
446             #======================================================================
447             # WHERE: top-level ARRAYREF
448             #======================================================================
449              
450              
451             sub _where_ARRAYREF {
452 395     395   710 my ($self, $where, $logic) = @_;
453              
454 395   66     1127 $logic = uc($logic || $self->{logic});
455 395 50 66     1187 $logic eq 'AND' or $logic eq 'OR' or $self->puke( "unknown logic: $logic" );
456              
457 395         734 my @clauses = @$where;
458              
459 395         534 my (@sql_clauses, @all_bind);
460             # need to use while() so can shift() for pairs
461 395         696 while (@clauses) {
462 688         977 my $el = shift @clauses;
463              
464 688 100 100     2094 $el = undef if (defined $el and ! length $el);
465              
466             # switch according to kind of $el and get corresponding ($sql, @bind)
467             my ($sql, @bind) = $self->_SWITCH_refkind($el, {
468              
469             # skip empty elements, otherwise get invalid trailing AND stuff
470 15 50   15   53 ARRAYREF => sub {$self->_recurse_where($el) if @$el},
471              
472             ARRAYREFREF => sub {
473 1     1   2 my ($s, @b) = @$$el;
474 1         4 $self->_assert_bindval_matches_bindtype(@b);
475 1         3 ($s, @b);
476             },
477              
478 273 100   273   811 HASHREF => sub {$self->_recurse_where($el, 'and') if %$el},
479              
480 0     0   0 SCALARREF => sub { ($$el); },
481              
482             SCALAR => sub {
483             # top-level arrayref with scalars, recurse in pairs
484 347     347   862 $self->_recurse_where({$el => shift(@clauses)})
485             },
486              
487 52     52   95 UNDEF => sub { $self->puke( "Supplying an empty left hand side argument is not supported in array-pairs" ) },
488 688         5463 });
489              
490 624 100       4042 if ($sql) {
491 623         937 push @sql_clauses, $sql;
492 623         1509 push @all_bind, @bind;
493             }
494             }
495              
496 331         650 return $self->_join_sql_clauses($logic, \@sql_clauses, \@all_bind);
497             }
498              
499             #======================================================================
500             # WHERE: top-level ARRAYREFREF
501             #======================================================================
502              
503             sub _where_ARRAYREFREF {
504 6     6   13 my ($self, $where) = @_;
505 6         15 my ($sql, @bind) = @$$where;
506 6         14 $self->_assert_bindval_matches_bindtype(@bind);
507 6         19 return ($sql, @bind);
508             }
509              
510             #======================================================================
511             # WHERE: top-level HASHREF
512             #======================================================================
513              
514             sub _where_HASHREF {
515 1152     1152   1759 my ($self, $where) = @_;
516 1152         1518 my (@sql_clauses, @all_bind);
517              
518 1152         3331 for my $k (sort keys %$where) {
519 1380         2077 my $v = $where->{$k};
520              
521             # ($k => $v) is either a special unary op or a regular hashpair
522 1380         1617 my ($sql, @bind) = do {
523 1380 100       2906 if ($k =~ /^-./) {
524             # put the operator in canonical form
525 225         321 my $op = $k;
526 225         470 $op = substr $op, 1; # remove initial dash
527 225         678 $op =~ s/^\s+|\s+$//g;# remove leading/trailing space
528 225         372 $op =~ s/\s+/ /g; # compress whitespace
529              
530             # so that -not_foo works correctly
531 225         323 $op =~ s/^not_/NOT /i;
532              
533 225         662 $self->_debug("Unary OP(-$op) within hashref, recursing...");
534 225         480 my ($s, @b) = $self->_where_unary_op ($op, $v);
535              
536             # top level vs nested
537             # we assume that handled unary ops will take care of their ()s
538             $s = "($s)" unless (
539 505     505   1961 List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}
  201         549  
540             or
541 201 50 66     722 ( defined $self->{_nested_func_lhs} and $self->{_nested_func_lhs} eq $k )
      66        
542             );
543 201         742 ($s, @b);
544             }
545             else {
546 1155 100       2029 if (! length $k) {
547 44 100       121 if ( SQL::Abstract::Util::is_literal_value( $v ) ) {
548 20         45 $self->belch( 'Hash-pairs consisting of an empty string with a literal are deprecated, and will be removed in 2.0: use -and => [ $literal ] instead' );
549             }
550             else {
551 24         43 $self->puke( "Supplying an empty left hand side argument is not supported in hash-pairs" );
552             }
553             }
554              
555 1131         15909 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $v);
556 1131         2168 $self->$method($k, $v);
557             }
558             };
559              
560 1300         2306 push @sql_clauses, $sql;
561 1300         2418 push @all_bind, @bind;
562             }
563              
564 1072         2338 return $self->_join_sql_clauses('and', \@sql_clauses, \@all_bind);
565             }
566              
567             sub _where_unary_op {
568 446     446   839 my ($self, $op, $rhs) = @_;
569              
570             # top level special ops are illegal in general
571             # this includes the -ident/-value ops (dual purpose unary and special)
572             $self->puke( "Illegal use of top-level '-$op'" )
573 446 100 100 1028   1311 if ! defined $self->{_nested_func_lhs} and List::Util::first {$op =~ $_->{regex}} @{$self->{special_ops}};
  1028         2875  
  207         572  
574              
575 444 100   1873   1280 if (my $op_entry = List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}) {
  1873         5011  
  444         1036  
576 204         360 my $handler = $op_entry->{handler};
577              
578 204 50       378 if (not ref $handler) {
    0          
579 204 100       679 if ($op =~ s/ [_\s]? \d+ $//x ) {
580 9         31 $self->belch(
581             'Use of [and|or|nest]_N modifiers is deprecated and will be removed in SQLA v2.0. '
582             . "You probably wanted ...-and => [ -$op => COND1, -$op => COND2 ... ]"
583             );
584             }
585 204         2897 return $self->$handler ($op, $rhs);
586             }
587             elsif (ref $handler eq 'CODE') {
588 0         0 return $handler->($self, $op, $rhs);
589             }
590             else {
591 0         0 $self->puke( "Illegal handler for operator $op - expecting a method name or a coderef" );
592             }
593             }
594              
595 240         1079 $self->_debug("Generic unary OP: $op - recursing as function");
596              
597 240         575 $self->_assert_pass_injection_guard($op);
598              
599             my ($sql, @bind) = $self->_SWITCH_refkind ($rhs, {
600             SCALAR => sub {
601             $self->puke( "Illegal use of top-level '-$op'" )
602 207 50   207   417 unless defined $self->{_nested_func_lhs};
603              
604             return (
605             $self->_convert('?'),
606 207         374 $self->_bindtype($self->{_nested_func_lhs}, $rhs)
607             );
608             },
609             FALLBACK => sub {
610 31     31   68 $self->_recurse_where ($rhs)
611             },
612 238         1258 });
613              
614 236         1087 $sql = sprintf ('%s %s',
615             $self->_sqlcase($op),
616             $sql,
617             );
618              
619 236         681 return ($sql, @bind);
620             }
621              
622             sub _where_op_ANDOR {
623 146     146   312 my ($self, $op, $v) = @_;
624              
625             $self->_SWITCH_refkind($v, {
626             ARRAYREF => sub {
627 76     76   157 return $self->_where_ARRAYREF($v, $op);
628             },
629              
630             HASHREF => sub {
631             return ( $op =~ /^or/i )
632 70 100   70   321 ? $self->_where_ARRAYREF( [ map { $_ => $v->{$_} } ( sort keys %$v ) ], $op )
  67         242  
633             : $self->_where_HASHREF($v);
634             },
635              
636             SCALARREF => sub {
637 0 0   0   0 $self->puke(
638             "-$op => \\\$scalar makes little sense, use " .
639             ($op =~ /^or/i
640             ? '[ \$scalar, \%rest_of_conditions ] instead'
641             : '-and => [ \$scalar, \%rest_of_conditions ] instead'
642             )
643             );
644             },
645              
646             ARRAYREFREF => sub {
647 0 0   0   0 $self->puke(
648             "-$op => \\[...] makes little sense, use " .
649             ($op =~ /^or/i
650             ? '[ \[...], \%rest_of_conditions ] instead'
651             : '-and => [ \[...], \%rest_of_conditions ] instead'
652             )
653             );
654             },
655              
656             SCALAR => sub { # permissively interpreted as SQL
657 0     0   0 $self->puke( "-$op => \$value makes little sense, use -bool => \$value instead" );
658             },
659              
660             UNDEF => sub {
661 0     0   0 $self->puke( "-$op => undef not supported" );
662             },
663 146         1427 });
664             }
665              
666             sub _where_op_NEST {
667 26     26   52 my ($self, $op, $v) = @_;
668              
669             $self->_SWITCH_refkind($v, {
670              
671             SCALAR => sub { # permissively interpreted as SQL
672 0     0   0 $self->belch( "literal SQL should be -nest => \\'scalar' "
673             . "instead of -nest => 'scalar' " );
674 0         0 return ($v);
675             },
676              
677             UNDEF => sub {
678 0     0   0 $self->puke( "-$op => undef not supported" );
679             },
680              
681             FALLBACK => sub {
682 26     26   54 $self->_recurse_where ($v);
683             },
684              
685 26         177 });
686             }
687              
688              
689             sub _where_op_BOOL {
690 24     24   40 my ($self, $op, $v) = @_;
691              
692             my ($s, @b) = $self->_SWITCH_refkind($v, {
693             SCALAR => sub { # interpreted as SQL column
694 14     14   28 $self->_convert($self->_quote($v));
695             },
696              
697             UNDEF => sub {
698 0     0   0 $self->puke( "-$op => undef not supported" );
699             },
700              
701             FALLBACK => sub {
702 10     10   19 $self->_recurse_where ($v);
703             },
704 24         155 });
705              
706 24 100       140 $s = "(NOT $s)" if $op =~ /^not/i;
707 24         73 ($s, @b);
708             }
709              
710              
711             sub _where_op_IDENT {
712 8     8   13 my $self = shift;
713 8         18 my ($op, $rhs) = splice @_, -2;
714 8 100 66     25 if (! defined $rhs or length ref $rhs) {
715 2         6 $self->puke( "-$op requires a single plain scalar argument (a quotable identifier)" );
716             }
717              
718             # in case we are called as a top level special op (no '=')
719 6         7 my $lhs = shift;
720              
721 6         18 $_ = $self->_convert($self->_quote($_)) for ($lhs, $rhs);
722              
723 6 100       22 return $lhs
724             ? "$lhs = $rhs"
725             : $rhs
726             ;
727             }
728              
729             sub _where_op_VALUE {
730 12     12   16 my $self = shift;
731 12         25 my ($op, $rhs) = splice @_, -2;
732              
733             # in case we are called as a top level special op (no '=')
734 12         18 my $lhs = shift;
735              
736             # special-case NULL
737 12 100       20 if (! defined $rhs) {
738 4 50       14 return defined $lhs
739             ? $self->_convert($self->_quote($lhs)) . ' IS NULL'
740             : undef
741             ;
742             }
743              
744             my @bind =
745             $self->_bindtype (
746 8 100       52 ( defined $lhs ? $lhs : $self->{_nested_func_lhs} ),
747             $rhs,
748             )
749             ;
750              
751 8 100       20 return $lhs
752             ? (
753             $self->_convert($self->_quote($lhs)) . ' = ' . $self->_convert('?'),
754             @bind
755             )
756             : (
757             $self->_convert('?'),
758             @bind,
759             )
760             ;
761             }
762              
763             sub _where_hashpair_ARRAYREF {
764 46     46   93 my ($self, $k, $v) = @_;
765              
766 46 100       93 if( @$v ) {
767 45         86 my @v = @$v; # need copy because of shift below
768 45         135 $self->_debug("ARRAY($k) means distribute over elements");
769              
770             # put apart first element if it is an operator (-and, -or)
771 45 100 66     247 my $op = (
772             (defined $v[0] && $v[0] =~ /^ - (?: AND|OR ) $/ix)
773             ? shift @v
774             : ''
775             );
776 45         95 my @distributed = map { {$k => $_} } @v;
  104         238  
777              
778 45 100       98 if ($op) {
779 22         66 $self->_debug("OP($op) reinjected into the distributed array");
780 22         48 unshift @distributed, $op;
781             }
782              
783 45 100       108 my $logic = $op ? substr($op, 1) : '';
784              
785 45         137 return $self->_recurse_where(\@distributed, $logic);
786             }
787             else {
788 1         5 $self->_debug("empty ARRAY($k) means 0=1");
789 1         2 return ($self->{sqlfalse});
790             }
791             }
792              
793             sub _where_hashpair_HASHREF {
794 583     583   1044 my ($self, $k, $v, $logic) = @_;
795 583   100     1887 $logic ||= 'and';
796              
797             local $self->{_nested_func_lhs} = defined $self->{_nested_func_lhs}
798             ? $self->{_nested_func_lhs}
799 583 100       1641 : $k
800             ;
801              
802 583         798 my ($all_sql, @all_bind);
803              
804 583         1394 for my $orig_op (sort keys %$v) {
805 590         842 my $val = $v->{$orig_op};
806              
807             # put the operator in canonical form
808 590         804 my $op = $orig_op;
809              
810             # FIXME - we need to phase out dash-less ops
811 590         1324 $op =~ s/^-//; # remove possible initial dash
812 590         1953 $op =~ s/^\s+|\s+$//g;# remove leading/trailing space
813 590         1342 $op =~ s/\s+/ /g; # compress whitespace
814              
815 590         1391 $self->_assert_pass_injection_guard($op);
816              
817             # fixup is_not
818 588         952 $op =~ s/^is_not/IS NOT/i;
819              
820             # so that -not_foo works correctly
821 588         880 $op =~ s/^not_/NOT /i;
822              
823             # another retarded special case: foo => { $op => { -value => undef } }
824 588 100 100     1486 if (ref $val eq 'HASH' and keys %$val == 1 and exists $val->{-value} and ! defined $val->{-value} ) {
      100        
      100        
825 28         41 $val = undef;
826             }
827              
828 588         850 my ($sql, @bind);
829              
830             # CASE: col-value logic modifiers
831 588 100       2147 if ( $orig_op =~ /^ \- (and|or) $/xi ) {
    100          
832 1         4 ($sql, @bind) = $self->_where_hashpair_HASHREF($k, $val, $1);
833             }
834             # CASE: special operators like -in or -between
835 2617     2617   7327 elsif ( my $special_op = List::Util::first {$op =~ $_->{regex}} @{$self->{special_ops}} ) {
  587         1676  
836 137         243 my $handler = $special_op->{handler};
837 137 50       308 if (! $handler) {
    100          
    50          
838 0         0 $self->puke( "No handler supplied for special operator $orig_op" );
839             }
840             elsif (not ref $handler) {
841 134         362 ($sql, @bind) = $self->$handler ($k, $op, $val);
842             }
843             elsif (ref $handler eq 'CODE') {
844 3         9 ($sql, @bind) = $handler->($self, $k, $op, $val);
845             }
846             else {
847 0         0 $self->puke( "Illegal handler for special operator $orig_op - expecting a method name or a coderef" );
848             }
849             }
850             else {
851             $self->_SWITCH_refkind($val, {
852              
853             ARRAYREF => sub { # CASE: col => {op => \@vals}
854 149     149   326 ($sql, @bind) = $self->_where_field_op_ARRAYREF($k, $op, $val);
855             },
856              
857             ARRAYREFREF => sub { # CASE: col => {op => \[$sql, @bind]} (literal SQL with bind)
858 10     10   25 my ($sub_sql, @sub_bind) = @$$val;
859 10         27 $self->_assert_bindval_matches_bindtype(@sub_bind);
860 8         20 $sql = join ' ', $self->_convert($self->_quote($k)),
861             $self->_sqlcase($op),
862             $sub_sql;
863 8         23 @bind = @sub_bind;
864             },
865              
866             UNDEF => sub { # CASE: col => {op => undef} : sql "IS (NOT)? NULL"
867             my $is =
868             $op =~ /^not$/i ? 'is not' # legacy
869             : $op =~ $self->{equality_op} ? 'is'
870             : $op =~ $self->{like_op} ? $self->belch("Supplying an undefined argument to '@{[ uc $op]}' is deprecated") && 'is'
871             : $op =~ $self->{inequality_op} ? 'is not'
872 77 50 50 77   688 : $op =~ $self->{not_like_op} ? $self->belch("Supplying an undefined argument to '@{[ uc $op]}' is deprecated") && 'is not'
    100 50        
    100          
    100          
    100          
873             : $self->puke( "unexpected operator '$orig_op' with undef operand" );
874              
875 77         58226 $sql = $self->_quote($k) . $self->_sqlcase(" $is null");
876             },
877              
878             FALLBACK => sub { # CASE: col => {op/func => $stuff}
879 214     214   467 ($sql, @bind) = $self->_where_unary_op ($op, $val);
880              
881             $sql = join (' ',
882             $self->_convert($self->_quote($k)),
883 212 50       408 $self->{_nested_func_lhs} eq $k ? $sql : "($sql)", # top level vs nested
884             );
885             },
886 450         3829 });
887             }
888              
889 561 100 66     44804 ($all_sql) = (defined $all_sql and $all_sql) ? $self->_join_sql_clauses($logic, [$all_sql, $sql], []) : $sql;
890 561         1386 push @all_bind, @bind;
891             }
892 554         1770 return ($all_sql, @all_bind);
893             }
894              
895             sub _where_field_IS {
896 40     40   85 my ($self, $k, $op, $v) = @_;
897              
898             my ($s) = $self->_SWITCH_refkind($v, {
899             UNDEF => sub {
900             join ' ',
901             $self->_convert($self->_quote($k)),
902 40     40   77 map { $self->_sqlcase($_)} ($op, 'null')
  80         123  
903             },
904             FALLBACK => sub {
905 0     0   0 $self->puke( "$op can only take undef as argument" );
906             },
907 40         223 });
908              
909 40         214 $s;
910             }
911              
912             sub _where_field_op_ARRAYREF {
913 149     149   287 my ($self, $k, $op, $vals) = @_;
914              
915 149         250 my @vals = @$vals; #always work on a copy
916              
917 149 100       268 if(@vals) {
918             $self->_debug(sprintf '%s means multiple elements: [ %s ]',
919             $vals,
920 106 100       188 join (', ', map { defined $_ ? "'$_'" : 'NULL' } @vals ),
  152         802  
921             );
922              
923             # see if the first element is an -and/-or op
924 106         144 my $logic;
925 106 100 100     320 if (defined $vals[0] && $vals[0] =~ /^ - ( AND|OR ) $/ix) {
926 2         9 $logic = uc $1;
927 2         4 shift @vals;
928             }
929              
930             # a long standing API wart - an attempt to change this behavior during
931             # the 1.50 series failed *spectacularly*. Warn instead and leave the
932             # behavior as is
933 106 100 66     577 if (
      100        
      100        
      100        
934             @vals > 1
935             and
936             (!$logic or $logic eq 'OR')
937             and
938             ( $op =~ $self->{inequality_op} or $op =~ $self->{not_like_op} )
939             ) {
940 36         78 my $o = uc($op);
941 36         103 $self->belch(
942             "A multi-element arrayref as an argument to the inequality op '$o' "
943             . 'is technically equivalent to an always-true 1=1 (you probably wanted '
944             . "to say ...{ \$inequality_op => [ -and => \@values ] }... instead)"
945             );
946             }
947              
948             # distribute $op over each remaining member of @vals, append logic if exists
949 106         36715 return $self->_recurse_where([map { {$k => {$op, $_}} } @vals], $logic);
  150         527  
950              
951             }
952             else {
953             # try to DWIM on equality operators
954             return
955             $op =~ $self->{equality_op} ? $self->{sqlfalse}
956             : $op =~ $self->{like_op} ? $self->belch("Supplying an empty arrayref to '@{[ uc $op]}' is deprecated") && $self->{sqlfalse}
957             : $op =~ $self->{inequality_op} ? $self->{sqltrue}
958             : $op =~ $self->{not_like_op} ? $self->belch("Supplying an empty arrayref to '@{[ uc $op]}' is deprecated") && $self->{sqltrue}
959 43 100 33     451 : $self->puke( "operator '$op' applied on an empty array (field '$k')" );
    100 33        
    100          
    50          
960             }
961             }
962              
963              
964             sub _where_hashpair_SCALARREF {
965 32     32   60 my ($self, $k, $v) = @_;
966 32         107 $self->_debug("SCALAR($k) means literal SQL: $$v");
967 32         66 my $sql = $self->_quote($k) . " " . $$v;
968 32         98 return ($sql);
969             }
970              
971             # literal SQL with bind
972             sub _where_hashpair_ARRAYREFREF {
973 27     27   62 my ($self, $k, $v) = @_;
974 27         59 $self->_debug("REF($k) means literal SQL: @${$v}");
  27         104  
975 27         65 my ($sql, @bind) = @$$v;
976 27         76 $self->_assert_bindval_matches_bindtype(@bind);
977 25         65 $sql = $self->_quote($k) . " " . $sql;
978 25         79 return ($sql, @bind );
979             }
980              
981             # literal SQL without bind
982             sub _where_hashpair_SCALAR {
983 434     434   723 my ($self, $k, $v) = @_;
984 434         1456 $self->_debug("NOREF($k) means simple key=val: $k $self->{cmp} $v");
985             my $sql = join ' ', $self->_convert($self->_quote($k)),
986 434         830 $self->_sqlcase($self->{cmp}),
987             $self->_convert('?');
988 433         912 my @bind = $self->_bindtype($k, $v);
989 433         1226 return ( $sql, @bind);
990             }
991              
992              
993             sub _where_hashpair_UNDEF {
994 10     10   21 my ($self, $k, $v) = @_;
995 10         29 $self->_debug("UNDEF($k) means IS NULL");
996 10         20 my $sql = $self->_quote($k) . $self->_sqlcase(' is null');
997 10         27 return ($sql);
998             }
999              
1000             #======================================================================
1001             # WHERE: TOP-LEVEL OTHERS (SCALARREF, SCALAR, UNDEF)
1002             #======================================================================
1003              
1004              
1005             sub _where_SCALARREF {
1006 6     6   15 my ($self, $where) = @_;
1007              
1008             # literal sql
1009 6         17 $self->_debug("SCALAR(*top) means literal SQL: $$where");
1010 6         14 return ($$where);
1011             }
1012              
1013              
1014             sub _where_SCALAR {
1015 0     0   0 my ($self, $where) = @_;
1016              
1017             # literal sql
1018 0         0 $self->_debug("NOREF(*top) means literal SQL: $where");
1019 0         0 return ($where);
1020             }
1021              
1022              
1023             sub _where_UNDEF {
1024 46     46   64 my ($self) = @_;
1025 46         81 return ();
1026             }
1027              
1028              
1029             #======================================================================
1030             # WHERE: BUILTIN SPECIAL OPERATORS (-in, -between)
1031             #======================================================================
1032              
1033              
1034             sub _where_field_BETWEEN {
1035 45     45   94 my ($self, $k, $op, $vals) = @_;
1036              
1037 45         60 my ($label, $and, $placeholder);
1038 45         95 $label = $self->_convert($self->_quote($k));
1039 45         102 $and = ' ' . $self->_sqlcase('and') . ' ';
1040 45         80 $placeholder = $self->_convert('?');
1041 45         78 $op = $self->_sqlcase($op);
1042              
1043 45         88 my $invalid_args = "Operator '$op' requires either an arrayref with two defined values or expressions, or a single literal scalarref/arrayref-ref";
1044              
1045             my ($clause, @bind) = $self->_SWITCH_refkind($vals, {
1046             ARRAYREFREF => sub {
1047 5     5   19 my ($s, @b) = @$$vals;
1048 5         12 $self->_assert_bindval_matches_bindtype(@b);
1049 5         15 ($s, @b);
1050             },
1051             SCALARREF => sub {
1052 3     3   7 return $$vals;
1053             },
1054             ARRAYREF => sub {
1055 35 100   35   86 $self->puke( $invalid_args ) if @$vals != 2;
1056              
1057 28         47 my (@all_sql, @all_bind);
1058 28         49 foreach my $val (@$vals) {
1059             my ($sql, @bind) = $self->_SWITCH_refkind($val, {
1060             SCALAR => sub {
1061 39         72 return ($placeholder, $self->_bindtype($k, $val) );
1062             },
1063             SCALARREF => sub {
1064 6         12 return $$val;
1065             },
1066             ARRAYREFREF => sub {
1067 4         9 my ($sql, @bind) = @$$val;
1068 4         9 $self->_assert_bindval_matches_bindtype(@bind);
1069 4         10 return ($sql, @bind);
1070             },
1071             HASHREF => sub {
1072 2         5 my ($func, $arg, @rest) = %$val;
1073 2 50 33     12 $self->puke ("Only simple { -func => arg } functions accepted as sub-arguments to BETWEEN")
1074             if (@rest or $func !~ /^ \- (.+)/x);
1075 2         6 $self->_where_unary_op ($1 => $arg);
1076             },
1077             FALLBACK => sub {
1078 3         7 $self->puke( $invalid_args ),
1079             },
1080 54         419 });
1081 51         322 push @all_sql, $sql;
1082 51         104 push @all_bind, @bind;
1083             }
1084              
1085             return (
1086 25         118 (join $and, @all_sql),
1087             @all_bind
1088             );
1089             },
1090             FALLBACK => sub {
1091 2     2   14 $self->puke( $invalid_args ),
1092             },
1093 45         392 });
1094              
1095 33         272 my $sql = "( $label $op $clause )";
1096 33         93 return ($sql, @bind)
1097             }
1098              
1099              
1100             sub _where_field_IN {
1101 37     37   84 my ($self, $k, $op, $vals) = @_;
1102              
1103             # backwards compatibility: if scalar, force into an arrayref
1104 37 100 100     154 $vals = [$vals] if defined $vals && ! ref $vals;
1105              
1106 37         84 my ($label) = $self->_convert($self->_quote($k));
1107 37         74 my ($placeholder) = $self->_convert('?');
1108 37         69 $op = $self->_sqlcase($op);
1109              
1110             my ($sql, @bind) = $self->_SWITCH_refkind($vals, {
1111             ARRAYREF => sub { # list of choices
1112 25 100   25   68 if (@$vals) { # nonempty list
1113 22         28 my (@all_sql, @all_bind);
1114              
1115 22         45 for my $val (@$vals) {
1116             my ($sql, @bind) = $self->_SWITCH_refkind($val, {
1117             SCALAR => sub {
1118 57         112 return ($placeholder, $val);
1119             },
1120             SCALARREF => sub {
1121 1         3 return $$val;
1122             },
1123             ARRAYREFREF => sub {
1124 1         4 my ($sql, @bind) = @$$val;
1125 1         4 $self->_assert_bindval_matches_bindtype(@bind);
1126 1         3 return ($sql, @bind);
1127             },
1128             HASHREF => sub {
1129 1         4 my ($func, $arg, @rest) = %$val;
1130 1 50 33     12 $self->puke ("Only simple { -func => arg } functions accepted as sub-arguments to IN")
1131             if (@rest or $func !~ /^ \- (.+)/x);
1132 1         5 $self->_where_unary_op ($1 => $arg);
1133             },
1134             UNDEF => sub {
1135 4         9 $self->puke(
1136             'NULL-within-IN not implemented: The upcoming SQL::Abstract::Classic 2.0 will emit the logically correct SQL instead of raising this exception.'
1137             );
1138             },
1139 64         398 });
1140 60         294 push @all_sql, $sql;
1141 60         134 push @all_bind, @bind;
1142             }
1143              
1144             return (
1145 18         95 sprintf ('%s %s ( %s )',
1146             $label,
1147             $op,
1148             join (', ', @all_sql)
1149             ),
1150             $self->_bindtype($k, @all_bind),
1151             );
1152             }
1153             else { # empty list: some databases won't understand "IN ()", so DWIM
1154 3 100       9 my $sql = ($op =~ /\bnot\b/i) ? $self->{sqltrue} : $self->{sqlfalse};
1155 3         7 return ($sql);
1156             }
1157             },
1158              
1159             SCALARREF => sub { # literal SQL
1160 4     4   8 my $sql = $self->_open_outer_paren ($$vals);
1161 4         15 return ("$label $op ( $sql )");
1162             },
1163             ARRAYREFREF => sub { # literal SQL with bind
1164 7     7   18 my ($sql, @bind) = @$$vals;
1165 7         20 $self->_assert_bindval_matches_bindtype(@bind);
1166 5         12 $sql = $self->_open_outer_paren ($sql);
1167 5         26 return ("$label $op ( $sql )", @bind);
1168             },
1169              
1170             UNDEF => sub {
1171 1     1   5 $self->puke( "Argument passed to the '$op' operator can not be undefined" );
1172             },
1173              
1174             FALLBACK => sub {
1175 0     0   0 $self->puke( "special op $op requires an arrayref (or scalarref/arrayref-ref)" );
1176             },
1177 37         421 });
1178              
1179 30         385 return ($sql, @bind);
1180             }
1181              
1182             # Some databases (SQLite) treat col IN (1, 2) different from
1183             # col IN ( (1, 2) ). Use this to strip all outer parens while
1184             # adding them back in the corresponding method
1185             sub _open_outer_paren {
1186 9     9   23 my ($self, $sql) = @_;
1187              
1188 9         44 while ( my ($inner) = $sql =~ /^ \s* \( (.*) \) \s* $/xs ) {
1189              
1190             # there are closing parens inside, need the heavy duty machinery
1191             # to reevaluate the extraction starting from $sql (full reevaluation)
1192 7 100       28 if ( $inner =~ /\)/ ) {
1193 6         1588 require Text::Balanced;
1194              
1195 6         29080 my (undef, $remainder) = do {
1196             # idiotic design - writes to $@ but *DOES NOT* throw exceptions
1197 6         10 local $@;
1198 6         27 Text::Balanced::extract_bracketed( $sql, '()', qr/\s*/ );
1199             };
1200              
1201             # the entire expression needs to be a balanced bracketed thing
1202             # (after an extract no remainder sans trailing space)
1203 6 100 66     1124 last if defined $remainder and $remainder =~ /\S/;
1204             }
1205              
1206 6         34 $sql = $inner;
1207             }
1208              
1209 9         22 $sql;
1210             }
1211              
1212              
1213             #======================================================================
1214             # ORDER BY
1215             #======================================================================
1216              
1217             sub _order_by {
1218 52     52   3642 my ($self, $arg) = @_;
1219              
1220 52         68 my (@sql, @bind);
1221 52         103 for my $c ($self->_order_by_chunks ($arg) ) {
1222             $self->_SWITCH_refkind ($c, {
1223 38     38   223 SCALAR => sub { push @sql, $c },
1224 52     52   70 ARRAYREF => sub { push @sql, shift @$c; push @bind, @$c },
  52         158  
1225 90         351 });
1226             }
1227              
1228 50 100       393 my $sql = @sql
1229             ? sprintf ('%s %s',
1230             $self->_sqlcase(' order by'),
1231             join (', ', @sql)
1232             )
1233             : ''
1234             ;
1235              
1236 50 50       163 return wantarray ? ($sql, @bind) : $sql;
1237             }
1238              
1239             sub _order_by_chunks {
1240 177     177   266 my ($self, $arg) = @_;
1241              
1242             return $self->_SWITCH_refkind($arg, {
1243              
1244             ARRAYREF => sub {
1245 47     47   212 map { $self->_order_by_chunks ($_ ) } @$arg;
  87         152  
1246             },
1247              
1248             ARRAYREFREF => sub {
1249 10     10   18 my ($s, @b) = @$$arg;
1250 10         24 $self->_assert_bindval_matches_bindtype(@b);
1251 10         30 [ $s, @b ];
1252             },
1253              
1254 76     76   177 SCALAR => sub {$self->_quote($arg)},
1255              
1256 0     0   0 UNDEF => sub {return () },
1257              
1258 4     4   10 SCALARREF => sub {$$arg}, # literal SQL, no quoting
1259              
1260             HASHREF => sub {
1261             # get first pair in hash
1262 40     40   95 my ($key, $val, @rest) = %$arg;
1263              
1264 40 50       67 return () unless $key;
1265              
1266 40 100 66     200 if ( @rest or not $key =~ /^-(desc|asc)/i ) {
1267 2         6 $self->puke( "hash passed to _order_by must have exactly one key (-desc or -asc)" );
1268             }
1269              
1270 38         92 my $direction = $1;
1271              
1272 38         46 my @ret;
1273 38         60 for my $c ($self->_order_by_chunks ($val)) {
1274 50         68 my ($sql, @bind);
1275              
1276             $self->_SWITCH_refkind ($c, {
1277             SCALAR => sub {
1278 42         59 $sql = $c;
1279             },
1280             ARRAYREF => sub {
1281 8         16 ($sql, @bind) = @$c;
1282             },
1283 50         208 });
1284              
1285 50         180 $sql = $sql . ' ' . $self->_sqlcase($direction);
1286              
1287 50         125 push @ret, [ $sql, @bind];
1288             }
1289              
1290 38         431 return @ret;
1291             },
1292 177         1508 });
1293             }
1294              
1295              
1296             #======================================================================
1297             # DATASOURCE (FOR NOW, JUST PLAIN TABLE OR LIST OF TABLES)
1298             #======================================================================
1299              
1300             sub _table {
1301 187     187   244 my $self = shift;
1302 187         248 my $from = shift;
1303             $self->_SWITCH_refkind($from, {
1304 4     4   9 ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$from;},
  10         19  
1305 183     183   344 SCALAR => sub {$self->_quote($from)},
1306 0     0   0 SCALARREF => sub {$$from},
1307 187         1192 });
1308             }
1309              
1310              
1311             #======================================================================
1312             # UTILITY FUNCTIONS
1313             #======================================================================
1314              
1315             # highly optimized, as it's called way too often
1316             sub _quote {
1317             # my ($self, $label) = @_;
1318              
1319 1415 100   1415   2357 return '' unless defined $_[1];
1320 1411 100       2453 return ${$_[1]} if ref($_[1]) eq 'SCALAR';
  2         5  
1321              
1322 1409 100       2360 unless ($_[0]->{quote_char}) {
1323 948         1973 $_[0]->_assert_pass_injection_guard($_[1]);
1324 947         2626 return $_[1];
1325             }
1326              
1327 461         809 my $qref = ref $_[0]->{quote_char};
1328 461         657 my ($l, $r);
1329 461 50       767 if (!$qref) {
    0          
1330 461         823 ($l, $r) = ( $_[0]->{quote_char}, $_[0]->{quote_char} );
1331             }
1332             elsif ($qref eq 'ARRAY') {
1333 0         0 ($l, $r) = @{$_[0]->{quote_char}};
  0         0  
1334             }
1335             else {
1336 0         0 $_[0]->puke( "Unsupported quote_char format: $_[0]->{quote_char}" );
1337             }
1338 461   66     1280 my $esc = $_[0]->{escape_char} || $r;
1339              
1340             # parts containing * are naturally unquoted
1341             return join( $_[0]->{name_sep}||'', map
1342 464 50       853 { $_ eq '*' ? $_ : do { (my $n = $_) =~ s/(\Q$esc\E|\Q$r\E)/$esc$1/g; $l . $n . $r } }
  464         1572  
  464         2172  
1343 461 100 100     1913 ( $_[0]->{name_sep} ? split (/\Q$_[0]->{name_sep}\E/, $_[1] ) : $_[1] )
1344             );
1345             }
1346              
1347              
1348             # Conversion, if applicable
1349             sub _convert ($) {
1350             #my ($self, $arg) = @_;
1351 1541 100   1541   2536 if ($_[0]->{convert}) {
1352 38         58 return $_[0]->_sqlcase($_[0]->{convert}) .'(' . $_[1] . ')';
1353             }
1354 1503         3246 return $_[1];
1355             }
1356              
1357             # And bindtype
1358             sub _bindtype (@) {
1359             #my ($self, $col, @vals) = @_;
1360             # called often - tighten code
1361             return $_[0]->{bindtype} eq 'columns'
1362 981 100   981   4435 ? map {[$_[1], $_]} @_[2 .. $#_]
  100         582  
1363             : @_[2 .. $#_]
1364             ;
1365             }
1366              
1367             # Dies if any element of @bind is not in [colname => value] format
1368             # if bindtype is 'columns'.
1369             sub _assert_bindval_matches_bindtype {
1370             # my ($self, @bind) = @_;
1371 95     95   135 my $self = shift;
1372 95 100       244 if ($self->{bindtype} eq 'columns') {
1373 30         107 for (@_) {
1374 31 100 66     176 if (!defined $_ || ref($_) ne 'ARRAY' || @$_ != 2) {
      66        
1375 10         29 $self->puke( "bindtype 'columns' selected, you need to pass: [column_name => bind_value]" );
1376             }
1377             }
1378             }
1379             }
1380              
1381             sub _join_sql_clauses {
1382 1410     1410   2425 my ($self, $logic, $clauses_aref, $bind_aref) = @_;
1383              
1384 1410 100       2838 if (@$clauses_aref > 1) {
    50          
1385 358         628 my $join = " " . $self->_sqlcase($logic) . " ";
1386 358         917 my $sql = '( ' . join($join, @$clauses_aref) . ' )';
1387 358         1901 return ($sql, @$bind_aref);
1388             }
1389             elsif (@$clauses_aref) {
1390 1052         3339 return ($clauses_aref->[0], @$bind_aref); # no parentheses
1391             }
1392             else {
1393 0         0 return (); # if no SQL, ignore @$bind_aref
1394             }
1395             }
1396              
1397              
1398             # Fix SQL case, if so requested
1399             sub _sqlcase {
1400             # LDNOTE: if $self->{case} is true, then it contains 'lower', so we
1401             # don't touch the argument ... crooked logic, but let's not change it!
1402 2264 100   2264   6895 return $_[0]->{case} ? $_[1] : uc($_[1]);
1403             }
1404              
1405              
1406             #======================================================================
1407             # DISPATCHING FROM REFKIND
1408             #======================================================================
1409              
1410             sub _refkind {
1411 5288     5288   7176 my ($self, $data) = @_;
1412              
1413 5288 100       8872 return 'UNDEF' unless defined $data;
1414              
1415             # blessed objects are treated like scalars
1416 5042 100       10629 my $ref = (Scalar::Util::blessed $data) ? '' : ref $data;
1417              
1418 5042 100       9319 return 'SCALAR' unless $ref;
1419              
1420 3146         3663 my $n_steps = 1;
1421 3146         5536 while ($ref eq 'REF') {
1422 108         155 $data = $$data;
1423 108 100       254 $ref = (Scalar::Util::blessed $data) ? '' : ref $data;
1424 108 100       259 $n_steps++ if $ref;
1425             }
1426              
1427 3146   100     9010 return ($ref||'SCALAR') . ('REF' x $n_steps);
1428             }
1429              
1430             sub _try_refkind {
1431 5275     5275   6939 my ($self, $data) = @_;
1432 5275         7901 my @try = ($self->_refkind($data));
1433 5275 100 100     14042 push @try, 'SCALAR_or_UNDEF' if $try[0] eq 'SCALAR' || $try[0] eq 'UNDEF';
1434 5275         6681 push @try, 'FALLBACK';
1435 5275         9825 return \@try;
1436             }
1437              
1438             sub _METHOD_FOR_refkind {
1439 2639     2639   4055 my ($self, $meth_prefix, $data) = @_;
1440              
1441 2639         3033 my $method;
1442 2639         3033 for (@{$self->_try_refkind($data)}) {
  2639         4122  
1443 2639 50       9311 $method = $self->can($meth_prefix."_".$_)
1444             and last;
1445             }
1446              
1447 2639   33     6598 return $method || $self->puke( "cannot dispatch on '$meth_prefix' for ".$self->_refkind($data) );
1448             }
1449              
1450              
1451             sub _SWITCH_refkind {
1452 2636     2636   4902 my ($self, $data, $dispatch_table) = @_;
1453              
1454 2636         3067 my $coderef;
1455 2636         2975 for (@{$self->_try_refkind($data)}) {
  2636         4207  
1456 3390 100       6869 $coderef = $dispatch_table->{$_}
1457             and last;
1458             }
1459              
1460 2636 50       5067 $self->puke( "no dispatch entry for ".$self->_refkind($data) )
1461             unless $coderef;
1462              
1463 2636         3773 $coderef->();
1464             }
1465              
1466              
1467              
1468              
1469             #======================================================================
1470             # VALUES, GENERATE, AUTOLOAD
1471             #======================================================================
1472              
1473             # LDNOTE: original code from nwiger, didn't touch code in that section
1474             # I feel the AUTOLOAD stuff should not be the default, it should
1475             # only be activated on explicit demand by user.
1476              
1477             sub values {
1478 6     6 1 20349 my $self = shift;
1479 6   50     17 my $data = shift || return;
1480 6 50 0     18 $self->puke( "Argument to ", (ref($self) || $self), "->values must be a \\%hash" )
1481             unless ref $data eq 'HASH';
1482              
1483 6         8 my @all_bind;
1484 6         29 foreach my $k ( sort keys %$data ) {
1485 37         53 my $v = $data->{$k};
1486             $self->_SWITCH_refkind($v, {
1487             ARRAYREF => sub {
1488 1 50   1   3 if ($self->{array_datatypes}) { # array datatype
1489 0         0 push @all_bind, $self->_bindtype($k, $v);
1490             }
1491             else { # literal SQL with bind
1492 1         3 my ($sql, @bind) = @$v;
1493 1         3 $self->_assert_bindval_matches_bindtype(@bind);
1494 1         5 push @all_bind, @bind;
1495             }
1496             },
1497             ARRAYREFREF => sub { # literal SQL with bind
1498 1     1   2 my ($sql, @bind) = @${$v};
  1         3  
1499 1         3 $self->_assert_bindval_matches_bindtype(@bind);
1500 1         21 push @all_bind, @bind;
1501             },
1502       2     SCALARREF => sub { # literal SQL without bind
1503             },
1504             SCALAR_or_UNDEF => sub {
1505 33     33   51 push @all_bind, $self->_bindtype($k, $v);
1506             },
1507 37         207 });
1508             }
1509              
1510 6         33 return @all_bind;
1511             }
1512              
1513             sub generate {
1514 0     0 1 0 my $self = shift;
1515              
1516 0         0 my(@sql, @sqlq, @sqlv);
1517              
1518 0         0 for (@_) {
1519 0         0 my $ref = ref $_;
1520 0 0       0 if ($ref eq 'HASH') {
    0          
    0          
1521 0         0 for my $k (sort keys %$_) {
1522 0         0 my $v = $_->{$k};
1523 0         0 my $r = ref $v;
1524 0         0 my $label = $self->_quote($k);
1525 0 0       0 if ($r eq 'ARRAY') {
    0          
1526             # literal SQL with bind
1527 0         0 my ($sql, @bind) = @$v;
1528 0         0 $self->_assert_bindval_matches_bindtype(@bind);
1529 0         0 push @sqlq, "$label = $sql";
1530 0         0 push @sqlv, @bind;
1531             } elsif ($r eq 'SCALAR') {
1532             # literal SQL without bind
1533 0         0 push @sqlq, "$label = $$v";
1534             } else {
1535 0         0 push @sqlq, "$label = ?";
1536 0         0 push @sqlv, $self->_bindtype($k, $v);
1537             }
1538             }
1539 0         0 push @sql, $self->_sqlcase('set'), join ', ', @sqlq;
1540             } elsif ($ref eq 'ARRAY') {
1541             # unlike insert(), assume these are ONLY the column names, i.e. for SQL
1542 0         0 for my $v (@$_) {
1543 0         0 my $r = ref $v;
1544 0 0       0 if ($r eq 'ARRAY') { # literal SQL with bind
    0          
1545 0         0 my ($sql, @bind) = @$v;
1546 0         0 $self->_assert_bindval_matches_bindtype(@bind);
1547 0         0 push @sqlq, $sql;
1548 0         0 push @sqlv, @bind;
1549             } elsif ($r eq 'SCALAR') { # literal SQL without bind
1550             # embedded literal SQL
1551 0         0 push @sqlq, $$v;
1552             } else {
1553 0         0 push @sqlq, '?';
1554 0         0 push @sqlv, $v;
1555             }
1556             }
1557 0         0 push @sql, '(' . join(', ', @sqlq) . ')';
1558             } elsif ($ref eq 'SCALAR') {
1559             # literal SQL
1560 0         0 push @sql, $$_;
1561             } else {
1562             # strings get case twiddled
1563 0         0 push @sql, $self->_sqlcase($_);
1564             }
1565             }
1566              
1567 0         0 my $sql = join ' ', @sql;
1568              
1569             # this is pretty tricky
1570             # if ask for an array, return ($stmt, @bind)
1571             # otherwise, s/?/shift @sqlv/ to put it inline
1572 0 0       0 if (wantarray) {
1573 0         0 return ($sql, @sqlv);
1574             } else {
1575 0         0 1 while $sql =~ s/\?/my $d = shift(@sqlv);
  0         0  
1576 0 0       0 ref $d ? $d->[1] : $d/e;
1577 0         0 return $sql;
1578             }
1579             }
1580              
1581              
1582 599     599   1743062 sub DESTROY { 1 }
1583              
1584             sub AUTOLOAD {
1585             # This allows us to check for a local, then _form, attr
1586 0     0     my $self = shift;
1587 0           my($name) = $AUTOLOAD =~ /.*::(.+)/;
1588 0           return $self->generate($name, @_);
1589             }
1590              
1591             1;
1592              
1593              
1594              
1595             __END__