Release 1.72
[scpubgit/Q-Branch.git] / lib / SQL / Abstract.pm
CommitLineData
96449e8e 1package SQL::Abstract; # see doc at end of file
2
3# LDNOTE : this code is heavy refactoring from original SQLA.
4# Several design decisions will need discussion during
5# the test / diffusion / acceptance phase; those are marked with flag
6# 'LDNOTE' (note by laurent.dami AT free.fr)
7
8use Carp;
9use strict;
10use warnings;
312d830b 11use List::Util ();
12use Scalar::Util ();
96449e8e 13
14#======================================================================
15# GLOBALS
16#======================================================================
17
64b9e432 18our $VERSION = '1.72';
7479e27e 19
22f1a437 20# This would confuse some packagers
c520207b 21$VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
96449e8e 22
23our $AUTOLOAD;
24
25# special operators (-in, -between). May be extended/overridden by user.
26# See section WHERE: BUILTIN SPECIAL OPERATORS below for implementation
27my @BUILTIN_SPECIAL_OPS = (
b8db59b8 28 {regex => qr/^ (?: not \s )? between $/ix, handler => '_where_field_BETWEEN'},
29 {regex => qr/^ (?: not \s )? in $/ix, handler => '_where_field_IN'},
96449e8e 30);
31
97a920ef 32# unaryish operators - key maps to handler
59f23b3d 33my @BUILTIN_UNARY_OPS = (
a47b433a 34 # the digits are backcompat stuff
b8db59b8 35 { regex => qr/^ and (?: [_\s]? \d+ )? $/xi, handler => '_where_op_ANDOR' },
36 { regex => qr/^ or (?: [_\s]? \d+ )? $/xi, handler => '_where_op_ANDOR' },
37 { regex => qr/^ nest (?: [_\s]? \d+ )? $/xi, handler => '_where_op_NEST' },
38 { regex => qr/^ (?: not \s )? bool $/xi, handler => '_where_op_BOOL' },
59f23b3d 39);
97a920ef 40
96449e8e 41#======================================================================
42# DEBUGGING AND ERROR REPORTING
43#======================================================================
44
45sub _debug {
46 return unless $_[0]->{debug}; shift; # a little faster
47 my $func = (caller(1))[3];
48 warn "[$func] ", @_, "\n";
49}
50
51sub belch (@) {
52 my($func) = (caller(1))[3];
53 carp "[$func] Warning: ", @_;
54}
55
56sub puke (@) {
57 my($func) = (caller(1))[3];
58 croak "[$func] Fatal: ", @_;
59}
60
61
62#======================================================================
63# NEW
64#======================================================================
65
66sub new {
67 my $self = shift;
68 my $class = ref($self) || $self;
69 my %opt = (ref $_[0] eq 'HASH') ? %{$_[0]} : @_;
70
71 # choose our case by keeping an option around
72 delete $opt{case} if $opt{case} && $opt{case} ne 'lower';
73
74 # default logic for interpreting arrayrefs
ef559da3 75 $opt{logic} = $opt{logic} ? uc $opt{logic} : 'OR';
96449e8e 76
77 # how to return bind vars
78 # LDNOTE: changed nwiger code : why this 'delete' ??
79 # $opt{bindtype} ||= delete($opt{bind_type}) || 'normal';
80 $opt{bindtype} ||= 'normal';
81
82 # default comparison is "=", but can be overridden
83 $opt{cmp} ||= '=';
84
85 # try to recognize which are the 'equality' and 'unequality' ops
86 # (temporary quickfix, should go through a more seasoned API)
2281c758 87 $opt{equality_op} = qr/^(\Q$opt{cmp}\E|is|(is\s+)?like)$/i;
88 $opt{inequality_op} = qr/^(!=|<>|(is\s+)?not(\s+like)?)$/i;
96449e8e 89
90 # SQL booleans
91 $opt{sqltrue} ||= '1=1';
92 $opt{sqlfalse} ||= '0=1';
93
9d48860e 94 # special operators
96449e8e 95 $opt{special_ops} ||= [];
b6251592 96 # regexes are applied in order, thus push after user-defines
96449e8e 97 push @{$opt{special_ops}}, @BUILTIN_SPECIAL_OPS;
98
9d48860e 99 # unary operators
59f23b3d 100 $opt{unary_ops} ||= [];
101 push @{$opt{unary_ops}}, @BUILTIN_UNARY_OPS;
102
b6251592 103 # rudimentary saniy-check for user supplied bits treated as functions/operators
104 # If a purported function matches this regular expression, an exception is thrown.
105 # Literal SQL is *NOT* subject to this check, only functions (and column names
106 # when quoting is not in effect)
96449e8e 107
b6251592 108 # FIXME
109 # need to guard against ()'s in column names too, but this will break tons of
110 # hacks... ideas anyone?
111 $opt{injection_guard} ||= qr/
112 \;
113 |
114 ^ \s* go \s
115 /xmi;
96449e8e 116
b6251592 117 return bless \%opt, $class;
118}
96449e8e 119
170e6c33 120
121sub _assert_pass_injection_guard {
122 if ($_[1] =~ $_[0]->{injection_guard}) {
123 my $class = ref $_[0];
124 puke "Possible SQL injection attempt '$_[1]'. If this is indeed a part of the "
125 . "desired SQL use literal SQL ( \'...' or \[ '...' ] ) or supply your own "
126 . "{injection_guard} attribute to ${class}->new()"
127 }
128}
129
130
96449e8e 131#======================================================================
132# INSERT methods
133#======================================================================
134
135sub insert {
02288357 136 my $self = shift;
137 my $table = $self->_table(shift);
138 my $data = shift || return;
139 my $options = shift;
96449e8e 140
141 my $method = $self->_METHOD_FOR_refkind("_insert", $data);
02288357 142 my ($sql, @bind) = $self->$method($data);
96449e8e 143 $sql = join " ", $self->_sqlcase('insert into'), $table, $sql;
02288357 144
e82e648a 145 if ($options->{returning}) {
146 my ($s, @b) = $self->_insert_returning ($options);
147 $sql .= $s;
148 push @bind, @b;
02288357 149 }
150
96449e8e 151 return wantarray ? ($sql, @bind) : $sql;
152}
153
6b1fe79d 154sub _insert_returning {
e82e648a 155 my ($self, $options) = @_;
6b1fe79d 156
e82e648a 157 my $f = $options->{returning};
158
159 my $fieldlist = $self->_SWITCH_refkind($f, {
160 ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$f;},
161 SCALAR => sub {$self->_quote($f)},
162 SCALARREF => sub {$$f},
6b1fe79d 163 });
e82e648a 164 return $self->_sqlcase(' returning ') . $fieldlist;
6b1fe79d 165}
166
96449e8e 167sub _insert_HASHREF { # explicit list of fields and then values
168 my ($self, $data) = @_;
169
170 my @fields = sort keys %$data;
171
fe3ae272 172 my ($sql, @bind) = $self->_insert_values($data);
96449e8e 173
174 # assemble SQL
175 $_ = $self->_quote($_) foreach @fields;
176 $sql = "( ".join(", ", @fields).") ".$sql;
177
178 return ($sql, @bind);
179}
180
181sub _insert_ARRAYREF { # just generate values(?,?) part (no list of fields)
182 my ($self, $data) = @_;
183
184 # no names (arrayref) so can't generate bindtype
185 $self->{bindtype} ne 'columns'
186 or belch "can't do 'columns' bindtype when called with arrayref";
187
fe3ae272 188 # fold the list of values into a hash of column name - value pairs
189 # (where the column names are artificially generated, and their
190 # lexicographical ordering keep the ordering of the original list)
191 my $i = "a"; # incremented values will be in lexicographical order
192 my $data_in_hash = { map { ($i++ => $_) } @$data };
193
194 return $self->_insert_values($data_in_hash);
195}
196
197sub _insert_ARRAYREFREF { # literal SQL with bind
198 my ($self, $data) = @_;
199
200 my ($sql, @bind) = @${$data};
201 $self->_assert_bindval_matches_bindtype(@bind);
202
203 return ($sql, @bind);
204}
205
206
207sub _insert_SCALARREF { # literal SQL without bind
208 my ($self, $data) = @_;
209
210 return ($$data);
211}
212
213sub _insert_values {
214 my ($self, $data) = @_;
215
96449e8e 216 my (@values, @all_bind);
fe3ae272 217 foreach my $column (sort keys %$data) {
218 my $v = $data->{$column};
96449e8e 219
220 $self->_SWITCH_refkind($v, {
221
9d48860e 222 ARRAYREF => sub {
96449e8e 223 if ($self->{array_datatypes}) { # if array datatype are activated
224 push @values, '?';
fe3ae272 225 push @all_bind, $self->_bindtype($column, $v);
96449e8e 226 }
227 else { # else literal SQL with bind
228 my ($sql, @bind) = @$v;
fe3ae272 229 $self->_assert_bindval_matches_bindtype(@bind);
96449e8e 230 push @values, $sql;
231 push @all_bind, @bind;
232 }
233 },
234
235 ARRAYREFREF => sub { # literal SQL with bind
236 my ($sql, @bind) = @${$v};
fe3ae272 237 $self->_assert_bindval_matches_bindtype(@bind);
96449e8e 238 push @values, $sql;
239 push @all_bind, @bind;
240 },
241
9d48860e 242 # THINK : anything useful to do with a HASHREF ?
5db47f9f 243 HASHREF => sub { # (nothing, but old SQLA passed it through)
244 #TODO in SQLA >= 2.0 it will die instead
245 belch "HASH ref as bind value in insert is not supported";
246 push @values, '?';
fe3ae272 247 push @all_bind, $self->_bindtype($column, $v);
5db47f9f 248 },
96449e8e 249
250 SCALARREF => sub { # literal SQL without bind
251 push @values, $$v;
252 },
253
254 SCALAR_or_UNDEF => sub {
255 push @values, '?';
fe3ae272 256 push @all_bind, $self->_bindtype($column, $v);
96449e8e 257 },
258
259 });
260
261 }
262
263 my $sql = $self->_sqlcase('values')." ( ".join(", ", @values)." )";
264 return ($sql, @all_bind);
265}
266
267
96449e8e 268
269#======================================================================
270# UPDATE methods
271#======================================================================
272
273
274sub update {
275 my $self = shift;
276 my $table = $self->_table(shift);
277 my $data = shift || return;
278 my $where = shift;
279
280 # first build the 'SET' part of the sql statement
281 my (@set, @all_bind);
282 puke "Unsupported data type specified to \$sql->update"
283 unless ref $data eq 'HASH';
284
285 for my $k (sort keys %$data) {
286 my $v = $data->{$k};
287 my $r = ref $v;
288 my $label = $self->_quote($k);
289
290 $self->_SWITCH_refkind($v, {
9d48860e 291 ARRAYREF => sub {
96449e8e 292 if ($self->{array_datatypes}) { # array datatype
293 push @set, "$label = ?";
294 push @all_bind, $self->_bindtype($k, $v);
295 }
296 else { # literal SQL with bind
297 my ($sql, @bind) = @$v;
fe3ae272 298 $self->_assert_bindval_matches_bindtype(@bind);
96449e8e 299 push @set, "$label = $sql";
fe3ae272 300 push @all_bind, @bind;
96449e8e 301 }
302 },
303 ARRAYREFREF => sub { # literal SQL with bind
304 my ($sql, @bind) = @${$v};
fe3ae272 305 $self->_assert_bindval_matches_bindtype(@bind);
96449e8e 306 push @set, "$label = $sql";
fe3ae272 307 push @all_bind, @bind;
96449e8e 308 },
309 SCALARREF => sub { # literal SQL without bind
310 push @set, "$label = $$v";
0ec3aec7 311 },
312 HASHREF => sub {
313 my ($op, $arg, @rest) = %$v;
314
315 puke 'Operator calls in update must be in the form { -op => $arg }'
316 if (@rest or not $op =~ /^\-(.+)/);
317
318 local $self->{_nested_func_lhs} = $k;
319 my ($sql, @bind) = $self->_where_unary_op ($1, $arg);
320
321 push @set, "$label = $sql";
322 push @all_bind, @bind;
323 },
96449e8e 324 SCALAR_or_UNDEF => sub {
325 push @set, "$label = ?";
326 push @all_bind, $self->_bindtype($k, $v);
327 },
328 });
329 }
330
331 # generate sql
332 my $sql = $self->_sqlcase('update') . " $table " . $self->_sqlcase('set ')
333 . join ', ', @set;
334
335 if ($where) {
336 my($where_sql, @where_bind) = $self->where($where);
337 $sql .= $where_sql;
338 push @all_bind, @where_bind;
339 }
340
341 return wantarray ? ($sql, @all_bind) : $sql;
342}
343
344
345
346
347#======================================================================
348# SELECT
349#======================================================================
350
351
352sub select {
353 my $self = shift;
354 my $table = $self->_table(shift);
355 my $fields = shift || '*';
356 my $where = shift;
357 my $order = shift;
358
359 my($where_sql, @bind) = $self->where($where, $order);
360
361 my $f = (ref $fields eq 'ARRAY') ? join ', ', map { $self->_quote($_) } @$fields
362 : $fields;
9d48860e 363 my $sql = join(' ', $self->_sqlcase('select'), $f,
96449e8e 364 $self->_sqlcase('from'), $table)
365 . $where_sql;
366
9d48860e 367 return wantarray ? ($sql, @bind) : $sql;
96449e8e 368}
369
370#======================================================================
371# DELETE
372#======================================================================
373
374
375sub delete {
376 my $self = shift;
377 my $table = $self->_table(shift);
378 my $where = shift;
379
380
381 my($where_sql, @bind) = $self->where($where);
382 my $sql = $self->_sqlcase('delete from') . " $table" . $where_sql;
383
9d48860e 384 return wantarray ? ($sql, @bind) : $sql;
96449e8e 385}
386
387
388#======================================================================
389# WHERE: entry point
390#======================================================================
391
392
393
394# Finally, a separate routine just to handle WHERE clauses
395sub where {
396 my ($self, $where, $order) = @_;
397
398 # where ?
399 my ($sql, @bind) = $self->_recurse_where($where);
400 $sql = $sql ? $self->_sqlcase(' where ') . "( $sql )" : '';
401
402 # order by?
403 if ($order) {
404 $sql .= $self->_order_by($order);
405 }
406
9d48860e 407 return wantarray ? ($sql, @bind) : $sql;
96449e8e 408}
409
410
411sub _recurse_where {
412 my ($self, $where, $logic) = @_;
413
414 # dispatch on appropriate method according to refkind of $where
415 my $method = $self->_METHOD_FOR_refkind("_where", $where);
311b2151 416
9d48860e 417 my ($sql, @bind) = $self->$method($where, $logic);
311b2151 418
9d48860e 419 # DBIx::Class directly calls _recurse_where in scalar context, so
311b2151 420 # we must implement it, even if not in the official API
9d48860e 421 return wantarray ? ($sql, @bind) : $sql;
96449e8e 422}
423
424
425
426#======================================================================
427# WHERE: top-level ARRAYREF
428#======================================================================
429
430
431sub _where_ARRAYREF {
5e1d09d5 432 my ($self, $where, $logic) = @_;
96449e8e 433
5e1d09d5 434 $logic = uc($logic || $self->{logic});
96449e8e 435 $logic eq 'AND' or $logic eq 'OR' or puke "unknown logic: $logic";
436
437 my @clauses = @$where;
438
96449e8e 439 my (@sql_clauses, @all_bind);
96449e8e 440 # need to use while() so can shift() for pairs
9d48860e 441 while (my $el = shift @clauses) {
96449e8e 442
443 # switch according to kind of $el and get corresponding ($sql, @bind)
444 my ($sql, @bind) = $self->_SWITCH_refkind($el, {
445
446 # skip empty elements, otherwise get invalid trailing AND stuff
447 ARRAYREF => sub {$self->_recurse_where($el) if @$el},
448
c94a6c93 449 ARRAYREFREF => sub {
450 my ($s, @b) = @$$el;
451 $self->_assert_bindval_matches_bindtype(@b);
452 ($s, @b);
453 },
474e3335 454
96449e8e 455 HASHREF => sub {$self->_recurse_where($el, 'and') if %$el},
456 # LDNOTE : previous SQLA code for hashrefs was creating a dirty
457 # side-effect: the first hashref within an array would change
458 # the global logic to 'AND'. So [ {cond1, cond2}, [cond3, cond4] ]
9d48860e 459 # was interpreted as "(cond1 AND cond2) OR (cond3 AND cond4)",
96449e8e 460 # whereas it should be "(cond1 AND cond2) OR (cond3 OR cond4)".
461
462 SCALARREF => sub { ($$el); },
463
464 SCALAR => sub {# top-level arrayref with scalars, recurse in pairs
465 $self->_recurse_where({$el => shift(@clauses)})},
466
467 UNDEF => sub {puke "not supported : UNDEF in arrayref" },
468 });
469
4b7b6026 470 if ($sql) {
471 push @sql_clauses, $sql;
472 push @all_bind, @bind;
473 }
96449e8e 474 }
475
476 return $self->_join_sql_clauses($logic, \@sql_clauses, \@all_bind);
477}
478
474e3335 479#======================================================================
480# WHERE: top-level ARRAYREFREF
481#======================================================================
96449e8e 482
474e3335 483sub _where_ARRAYREFREF {
484 my ($self, $where) = @_;
c94a6c93 485 my ($sql, @bind) = @$$where;
486 $self->_assert_bindval_matches_bindtype(@bind);
474e3335 487 return ($sql, @bind);
488}
96449e8e 489
490#======================================================================
491# WHERE: top-level HASHREF
492#======================================================================
493
494sub _where_HASHREF {
495 my ($self, $where) = @_;
496 my (@sql_clauses, @all_bind);
497
2281c758 498 for my $k (sort keys %$where) {
96449e8e 499 my $v = $where->{$k};
500
2281c758 501 # ($k => $v) is either a special unary op or a regular hashpair
502 my ($sql, @bind) = do {
503 if ($k =~ /^-./) {
504 # put the operator in canonical form
505 my $op = $k;
b8db59b8 506 $op = substr $op, 1; # remove initial dash
2281c758 507 $op =~ s/^\s+|\s+$//g;# remove leading/trailing space
b8db59b8 508 $op =~ s/\s+/ /g; # compress whitespace
509
510 # so that -not_foo works correctly
511 $op =~ s/^not_/NOT /i;
2281c758 512
513 $self->_debug("Unary OP(-$op) within hashref, recursing...");
0ec3aec7 514 my ($s, @b) = $self->_where_unary_op ($op, $v);
515
516 # top level vs nested
517 # we assume that handled unary ops will take care of their ()s
518 $s = "($s)" unless (
519 List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}
520 or
521 defined($self->{_nested_func_lhs}) && ($self->{_nested_func_lhs} eq $k)
522 );
523 ($s, @b);
2281c758 524 }
525 else {
526 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $v);
527 $self->$method($k, $v);
528 }
529 };
96449e8e 530
531 push @sql_clauses, $sql;
532 push @all_bind, @bind;
533 }
534
535 return $self->_join_sql_clauses('and', \@sql_clauses, \@all_bind);
536}
537
0ec3aec7 538sub _where_unary_op {
2281c758 539 my ($self, $op, $rhs) = @_;
96449e8e 540
0ec3aec7 541 if (my $op_entry = List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}) {
542 my $handler = $op_entry->{handler};
543
544 if (not ref $handler) {
545 if ($op =~ s/ [_\s]? \d+ $//x ) {
546 belch 'Use of [and|or|nest]_N modifiers is deprecated and will be removed in SQLA v2.0. '
547 . "You probably wanted ...-and => [ -$op => COND1, -$op => COND2 ... ]";
548 }
549 return $self->$handler ($op, $rhs);
550 }
551 elsif (ref $handler eq 'CODE') {
552 return $handler->($self, $op, $rhs);
553 }
554 else {
555 puke "Illegal handler for operator $op - expecting a method name or a coderef";
556 }
557 }
558
559 $self->debug("Generic unary OP: $op - recursing as function");
560
170e6c33 561 $self->_assert_pass_injection_guard($op);
b6251592 562
2281c758 563 my ($sql, @bind) = $self->_SWITCH_refkind ($rhs, {
564 SCALAR => sub {
a7661cfc 565 puke "Illegal use of top-level '$op'"
566 unless $self->{_nested_func_lhs};
567
568 return (
569 $self->_convert('?'),
570 $self->_bindtype($self->{_nested_func_lhs}, $rhs)
571 );
2281c758 572 },
573 FALLBACK => sub {
574 $self->_recurse_where ($rhs)
575 },
576 });
96449e8e 577
953d164e 578 $sql = sprintf ('%s %s',
2281c758 579 $self->_sqlcase($op),
953d164e 580 $sql,
2281c758 581 );
96449e8e 582
2281c758 583 return ($sql, @bind);
97a920ef 584}
585
586sub _where_op_ANDOR {
2281c758 587 my ($self, $op, $v) = @_;
97a920ef 588
589 $self->_SWITCH_refkind($v, {
590 ARRAYREF => sub {
591 return $self->_where_ARRAYREF($v, $op);
592 },
593
594 HASHREF => sub {
59f23b3d 595 return ( $op =~ /^or/i )
97a920ef 596 ? $self->_where_ARRAYREF( [ map { $_ => $v->{$_} } ( sort keys %$v ) ], $op )
597 : $self->_where_HASHREF($v);
598 },
599
9d48860e 600 SCALARREF => sub {
48d9f5f8 601 puke "-$op => \\\$scalar makes little sense, use " .
602 ($op =~ /^or/i
603 ? '[ \$scalar, \%rest_of_conditions ] instead'
604 : '-and => [ \$scalar, \%rest_of_conditions ] instead'
605 );
97a920ef 606 },
607
608 ARRAYREFREF => sub {
48d9f5f8 609 puke "-$op => \\[...] makes little sense, use " .
610 ($op =~ /^or/i
611 ? '[ \[...], \%rest_of_conditions ] instead'
612 : '-and => [ \[...], \%rest_of_conditions ] instead'
613 );
97a920ef 614 },
615
616 SCALAR => sub { # permissively interpreted as SQL
48d9f5f8 617 puke "-$op => \$value makes little sense, use -bool => \$value instead";
97a920ef 618 },
619
620 UNDEF => sub {
621 puke "-$op => undef not supported";
622 },
623 });
624}
625
626sub _where_op_NEST {
9d48860e 627 my ($self, $op, $v) = @_;
97a920ef 628
96449e8e 629 $self->_SWITCH_refkind($v, {
630
96449e8e 631 SCALAR => sub { # permissively interpreted as SQL
01a01e57 632 belch "literal SQL should be -nest => \\'scalar' "
633 . "instead of -nest => 'scalar' ";
9d48860e 634 return ($v);
96449e8e 635 },
636
637 UNDEF => sub {
638 puke "-$op => undef not supported";
639 },
e9501094 640
641 FALLBACK => sub {
642 $self->_recurse_where ($v);
643 },
644
96449e8e 645 });
646}
647
648
97a920ef 649sub _where_op_BOOL {
9d48860e 650 my ($self, $op, $v) = @_;
97a920ef 651
b8db59b8 652 my ($s, @b) = $self->_SWITCH_refkind($v, {
653 SCALAR => sub { # interpreted as SQL column
654 $self->_convert($self->_quote($v));
655 },
ef03f1bc 656
b8db59b8 657 UNDEF => sub {
658 puke "-$op => undef not supported";
659 },
97a920ef 660
b8db59b8 661 FALLBACK => sub {
662 $self->_recurse_where ($v);
663 },
664 });
ef03f1bc 665
b8db59b8 666 $s = "(NOT $s)" if $op =~ /^not/i;
667 ($s, @b);
97a920ef 668}
669
670
96449e8e 671sub _where_hashpair_ARRAYREF {
672 my ($self, $k, $v) = @_;
673
674 if( @$v ) {
675 my @v = @$v; # need copy because of shift below
676 $self->_debug("ARRAY($k) means distribute over elements");
677
678 # put apart first element if it is an operator (-and, -or)
e3cecb45 679 my $op = (
680 (defined $v[0] && $v[0] =~ /^ - (?: AND|OR ) $/ix)
681 ? shift @v
682 : ''
04d940de 683 );
96449e8e 684 my @distributed = map { {$k => $_} } @v;
04d940de 685
686 if ($op) {
687 $self->_debug("OP($op) reinjected into the distributed array");
688 unshift @distributed, $op;
689 }
690
f67591bf 691 my $logic = $op ? substr($op, 1) : '';
96449e8e 692
f67591bf 693 return $self->_recurse_where(\@distributed, $logic);
9d48860e 694 }
96449e8e 695 else {
696 # LDNOTE : not sure of this one. What does "distribute over nothing" mean?
697 $self->_debug("empty ARRAY($k) means 0=1");
698 return ($self->{sqlfalse});
699 }
700}
701
702sub _where_hashpair_HASHREF {
eb49170d 703 my ($self, $k, $v, $logic) = @_;
704 $logic ||= 'and';
96449e8e 705
a7661cfc 706 local $self->{_nested_func_lhs} = $self->{_nested_func_lhs};
a7661cfc 707
eb49170d 708 my ($all_sql, @all_bind);
96449e8e 709
a47b433a 710 for my $orig_op (sort keys %$v) {
711 my $val = $v->{$orig_op};
96449e8e 712
713 # put the operator in canonical form
a47b433a 714 my $op = $orig_op;
b8db59b8 715
716 # FIXME - we need to phase out dash-less ops
717 $op =~ s/^-//; # remove possible initial dash
a47b433a 718 $op =~ s/^\s+|\s+$//g;# remove leading/trailing space
b8db59b8 719 $op =~ s/\s+/ /g; # compress whitespace
720
170e6c33 721 $self->_assert_pass_injection_guard($op);
b6251592 722
b8db59b8 723 # so that -not_foo works correctly
724 $op =~ s/^not_/NOT /i;
96449e8e 725
726 my ($sql, @bind);
727
2281c758 728 # CASE: col-value logic modifiers
729 if ( $orig_op =~ /^ \- (and|or) $/xi ) {
730 ($sql, @bind) = $self->_where_hashpair_HASHREF($k, $val, $1);
731 }
96449e8e 732 # CASE: special operators like -in or -between
312d830b 733 elsif ( my $special_op = List::Util::first {$op =~ $_->{regex}} @{$self->{special_ops}} ) {
3a2e1a5e 734 my $handler = $special_op->{handler};
735 if (! $handler) {
a47b433a 736 puke "No handler supplied for special operator $orig_op";
3a2e1a5e 737 }
738 elsif (not ref $handler) {
739 ($sql, @bind) = $self->$handler ($k, $op, $val);
740 }
741 elsif (ref $handler eq 'CODE') {
742 ($sql, @bind) = $handler->($self, $k, $op, $val);
743 }
744 else {
a47b433a 745 puke "Illegal handler for special operator $orig_op - expecting a method name or a coderef";
3a2e1a5e 746 }
96449e8e 747 }
96449e8e 748 else {
cf838930 749 $self->_SWITCH_refkind($val, {
750
751 ARRAYREF => sub { # CASE: col => {op => \@vals}
752 ($sql, @bind) = $self->_where_field_op_ARRAYREF($k, $op, $val);
753 },
754
fe3ae272 755 ARRAYREFREF => sub { # CASE: col => {op => \[$sql, @bind]} (literal SQL with bind)
b3be7bd0 756 my ($sub_sql, @sub_bind) = @$$val;
fe3ae272 757 $self->_assert_bindval_matches_bindtype(@sub_bind);
b3be7bd0 758 $sql = join ' ', $self->_convert($self->_quote($k)),
759 $self->_sqlcase($op),
760 $sub_sql;
fe3ae272 761 @bind = @sub_bind;
b3be7bd0 762 },
763
cf838930 764 UNDEF => sub { # CASE: col => {op => undef} : sql "IS (NOT)? NULL"
765 my $is = ($op =~ $self->{equality_op}) ? 'is' :
766 ($op =~ $self->{inequality_op}) ? 'is not' :
a47b433a 767 puke "unexpected operator '$orig_op' with undef operand";
cf838930 768 $sql = $self->_quote($k) . $self->_sqlcase(" $is null");
769 },
a47b433a 770
2281c758 771 FALLBACK => sub { # CASE: col => {op/func => $stuff}
07936978 772
953d164e 773 # retain for proper column type bind
774 $self->{_nested_func_lhs} ||= $k;
07936978 775
0ec3aec7 776 ($sql, @bind) = $self->_where_unary_op ($op, $val);
953d164e 777
778 $sql = join (' ',
779 $self->_convert($self->_quote($k)),
780 $self->{_nested_func_lhs} eq $k ? $sql : "($sql)", # top level vs nested
781 );
cf838930 782 },
783 });
96449e8e 784 }
785
eb49170d 786 ($all_sql) = (defined $all_sql and $all_sql) ? $self->_join_sql_clauses($logic, [$all_sql, $sql], []) : $sql;
96449e8e 787 push @all_bind, @bind;
788 }
eb49170d 789 return ($all_sql, @all_bind);
96449e8e 790}
791
792
793
794sub _where_field_op_ARRAYREF {
795 my ($self, $k, $op, $vals) = @_;
796
ce261791 797 my @vals = @$vals; #always work on a copy
798
799 if(@vals) {
bd6a65ca 800 $self->_debug(sprintf '%s means multiple elements: [ %s ]',
801 $vals,
802 join (', ', map { defined $_ ? "'$_'" : 'NULL' } @vals ),
803 );
96449e8e 804
4030915f 805 # see if the first element is an -and/-or op
806 my $logic;
bd6a65ca 807 if (defined $vals[0] && $vals[0] =~ /^ - ( AND|OR ) $/ix) {
4030915f 808 $logic = uc $1;
ce261791 809 shift @vals;
4030915f 810 }
811
ce261791 812 # distribute $op over each remaining member of @vals, append logic if exists
813 return $self->_recurse_where([map { {$k => {$op, $_}} } @vals], $logic);
4030915f 814
9d48860e 815 # LDNOTE : had planned to change the distribution logic when
816 # $op =~ $self->{inequality_op}, because of Morgan laws :
96449e8e 817 # with {field => {'!=' => [22, 33]}}, it would be ridiculous to generate
9d48860e 818 # WHERE field != 22 OR field != 33 : the user probably means
96449e8e 819 # WHERE field != 22 AND field != 33.
4030915f 820 # To do this, replace the above to roughly :
f2d5020d 821 # my $logic = ($op =~ $self->{inequality_op}) ? 'AND' : 'OR';
ce261791 822 # return $self->_recurse_where([map { {$k => {$op, $_}} } @vals], $logic);
96449e8e 823
9d48860e 824 }
96449e8e 825 else {
9d48860e 826 # try to DWIM on equality operators
96449e8e 827 # LDNOTE : not 100% sure this is the correct thing to do ...
828 return ($self->{sqlfalse}) if $op =~ $self->{equality_op};
829 return ($self->{sqltrue}) if $op =~ $self->{inequality_op};
830
831 # otherwise
832 puke "operator '$op' applied on an empty array (field '$k')";
833 }
834}
835
836
837sub _where_hashpair_SCALARREF {
838 my ($self, $k, $v) = @_;
839 $self->_debug("SCALAR($k) means literal SQL: $$v");
840 my $sql = $self->_quote($k) . " " . $$v;
841 return ($sql);
842}
843
fe3ae272 844# literal SQL with bind
96449e8e 845sub _where_hashpair_ARRAYREFREF {
846 my ($self, $k, $v) = @_;
847 $self->_debug("REF($k) means literal SQL: @${$v}");
c94a6c93 848 my ($sql, @bind) = @$$v;
fe3ae272 849 $self->_assert_bindval_matches_bindtype(@bind);
96449e8e 850 $sql = $self->_quote($k) . " " . $sql;
96449e8e 851 return ($sql, @bind );
852}
853
fe3ae272 854# literal SQL without bind
96449e8e 855sub _where_hashpair_SCALAR {
856 my ($self, $k, $v) = @_;
857 $self->_debug("NOREF($k) means simple key=val: $k $self->{cmp} $v");
9d48860e 858 my $sql = join ' ', $self->_convert($self->_quote($k)),
859 $self->_sqlcase($self->{cmp}),
96449e8e 860 $self->_convert('?');
861 my @bind = $self->_bindtype($k, $v);
862 return ( $sql, @bind);
863}
864
865
866sub _where_hashpair_UNDEF {
867 my ($self, $k, $v) = @_;
868 $self->_debug("UNDEF($k) means IS NULL");
869 my $sql = $self->_quote($k) . $self->_sqlcase(' is null');
870 return ($sql);
871}
872
873#======================================================================
874# WHERE: TOP-LEVEL OTHERS (SCALARREF, SCALAR, UNDEF)
875#======================================================================
876
877
878sub _where_SCALARREF {
879 my ($self, $where) = @_;
880
881 # literal sql
882 $self->_debug("SCALAR(*top) means literal SQL: $$where");
883 return ($$where);
884}
885
886
887sub _where_SCALAR {
888 my ($self, $where) = @_;
889
890 # literal sql
891 $self->_debug("NOREF(*top) means literal SQL: $where");
892 return ($where);
893}
894
895
896sub _where_UNDEF {
897 my ($self) = @_;
898 return ();
899}
900
901
902#======================================================================
903# WHERE: BUILTIN SPECIAL OPERATORS (-in, -between)
904#======================================================================
905
906
907sub _where_field_BETWEEN {
908 my ($self, $k, $op, $vals) = @_;
909
4d8b3dc4 910 my ($label, $and, $placeholder);
cf02fc47 911 $label = $self->_convert($self->_quote($k));
912 $and = ' ' . $self->_sqlcase('and') . ' ';
913 $placeholder = $self->_convert('?');
96449e8e 914 $op = $self->_sqlcase($op);
915
4d8b3dc4 916 my ($clause, @bind) = $self->_SWITCH_refkind($vals, {
917 ARRAYREFREF => sub {
c94a6c93 918 my ($s, @b) = @$$vals;
919 $self->_assert_bindval_matches_bindtype(@b);
920 ($s, @b);
4d8b3dc4 921 },
922 SCALARREF => sub {
923 return $$vals;
924 },
925 ARRAYREF => sub {
926 puke "special op 'between' accepts an arrayref with exactly two values"
927 if @$vals != 2;
928
929 my (@all_sql, @all_bind);
930 foreach my $val (@$vals) {
931 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
932 SCALAR => sub {
5e5cbf51 933 return ($placeholder, $self->_bindtype($k, $val) );
4d8b3dc4 934 },
935 SCALARREF => sub {
0336eddb 936 return $$val;
4d8b3dc4 937 },
938 ARRAYREFREF => sub {
939 my ($sql, @bind) = @$$val;
c94a6c93 940 $self->_assert_bindval_matches_bindtype(@bind);
0336eddb 941 return ($sql, @bind);
4d8b3dc4 942 },
0336eddb 943 HASHREF => sub {
944 my ($func, $arg, @rest) = %$val;
945 puke ("Only simple { -func => arg } functions accepted as sub-arguments to BETWEEN")
946 if (@rest or $func !~ /^ \- (.+)/x);
947 local $self->{_nested_func_lhs} = $k;
0ec3aec7 948 $self->_where_unary_op ($1 => $arg);
0336eddb 949 }
4d8b3dc4 950 });
951 push @all_sql, $sql;
952 push @all_bind, @bind;
953 }
954
955 return (
956 (join $and, @all_sql),
5e5cbf51 957 @all_bind
4d8b3dc4 958 );
959 },
960 FALLBACK => sub {
961 puke "special op 'between' accepts an arrayref with two values, or a single literal scalarref/arrayref-ref";
962 },
963 });
cf02fc47 964
cf02fc47 965 my $sql = "( $label $op $clause )";
96449e8e 966 return ($sql, @bind)
967}
968
969
970sub _where_field_IN {
971 my ($self, $k, $op, $vals) = @_;
972
973 # backwards compatibility : if scalar, force into an arrayref
974 $vals = [$vals] if defined $vals && ! ref $vals;
975
96449e8e 976 my ($label) = $self->_convert($self->_quote($k));
977 my ($placeholder) = $self->_convert('?');
96449e8e 978 $op = $self->_sqlcase($op);
979
8a0d798a 980 my ($sql, @bind) = $self->_SWITCH_refkind($vals, {
981 ARRAYREF => sub { # list of choices
982 if (@$vals) { # nonempty list
0336eddb 983 my (@all_sql, @all_bind);
984
985 for my $val (@$vals) {
986 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
987 SCALAR => sub {
988 return ($placeholder, $val);
989 },
990 SCALARREF => sub {
991 return $$val;
992 },
993 ARRAYREFREF => sub {
994 my ($sql, @bind) = @$$val;
995 $self->_assert_bindval_matches_bindtype(@bind);
996 return ($sql, @bind);
997 },
998 HASHREF => sub {
999 my ($func, $arg, @rest) = %$val;
1000 puke ("Only simple { -func => arg } functions accepted as sub-arguments to IN")
1001 if (@rest or $func !~ /^ \- (.+)/x);
1002 local $self->{_nested_func_lhs} = $k;
0ec3aec7 1003 $self->_where_unary_op ($1 => $arg);
279eb282 1004 },
1005 UNDEF => sub {
1006 return $self->_sqlcase('null');
1007 },
0336eddb 1008 });
1009 push @all_sql, $sql;
1010 push @all_bind, @bind;
1011 }
96449e8e 1012
88a89939 1013 return (
1014 sprintf ('%s %s ( %s )',
1015 $label,
1016 $op,
1017 join (', ', @all_sql)
1018 ),
1019 $self->_bindtype($k, @all_bind),
0336eddb 1020 );
8a0d798a 1021 }
1022 else { # empty list : some databases won't understand "IN ()", so DWIM
1023 my $sql = ($op =~ /\bnot\b/i) ? $self->{sqltrue} : $self->{sqlfalse};
1024 return ($sql);
1025 }
1026 },
1027
4a1f01a3 1028 SCALARREF => sub { # literal SQL
1029 my $sql = $self->_open_outer_paren ($$vals);
1030 return ("$label $op ( $sql )");
1031 },
8a0d798a 1032 ARRAYREFREF => sub { # literal SQL with bind
1033 my ($sql, @bind) = @$$vals;
fe3ae272 1034 $self->_assert_bindval_matches_bindtype(@bind);
4a1f01a3 1035 $sql = $self->_open_outer_paren ($sql);
8a0d798a 1036 return ("$label $op ( $sql )", @bind);
1037 },
1038
1039 FALLBACK => sub {
4a1f01a3 1040 puke "special op 'in' requires an arrayref (or scalarref/arrayref-ref)";
8a0d798a 1041 },
1042 });
1043
1044 return ($sql, @bind);
96449e8e 1045}
1046
4a1f01a3 1047# Some databases (SQLite) treat col IN (1, 2) different from
1048# col IN ( (1, 2) ). Use this to strip all outer parens while
1049# adding them back in the corresponding method
1050sub _open_outer_paren {
1051 my ($self, $sql) = @_;
171a709f 1052 $sql = $1 while $sql =~ /^ \s* \( (.*) \) \s* $/xs;
4a1f01a3 1053 return $sql;
1054}
1055
96449e8e 1056
96449e8e 1057#======================================================================
1058# ORDER BY
1059#======================================================================
1060
1061sub _order_by {
1062 my ($self, $arg) = @_;
1063
f267b646 1064 my (@sql, @bind);
1065 for my $c ($self->_order_by_chunks ($arg) ) {
1066 $self->_SWITCH_refkind ($c, {
1067 SCALAR => sub { push @sql, $c },
1068 ARRAYREF => sub { push @sql, shift @$c; push @bind, @$c },
1069 });
1070 }
1071
1072 my $sql = @sql
1073 ? sprintf ('%s %s',
1074 $self->_sqlcase(' order by'),
1075 join (', ', @sql)
1076 )
1077 : ''
1078 ;
1079
1080 return wantarray ? ($sql, @bind) : $sql;
1081}
1082
1083sub _order_by_chunks {
1084 my ($self, $arg) = @_;
1085
1086 return $self->_SWITCH_refkind($arg, {
96449e8e 1087
1088 ARRAYREF => sub {
f267b646 1089 map { $self->_order_by_chunks ($_ ) } @$arg;
96449e8e 1090 },
1091
c94a6c93 1092 ARRAYREFREF => sub {
1093 my ($s, @b) = @$$arg;
1094 $self->_assert_bindval_matches_bindtype(@b);
1095 [ $s, @b ];
1096 },
f267b646 1097
96449e8e 1098 SCALAR => sub {$self->_quote($arg)},
f267b646 1099
1100 UNDEF => sub {return () },
1101
96449e8e 1102 SCALARREF => sub {$$arg}, # literal SQL, no quoting
96449e8e 1103
f267b646 1104 HASHREF => sub {
1105 # get first pair in hash
c94a6c93 1106 my ($key, $val, @rest) = %$arg;
96449e8e 1107
f267b646 1108 return () unless $key;
96449e8e 1109
c94a6c93 1110 if ( @rest or not $key =~ /^-(desc|asc)/i ) {
f267b646 1111 puke "hash passed to _order_by must have exactly one key (-desc or -asc)";
1112 }
96449e8e 1113
f267b646 1114 my $direction = $1;
96449e8e 1115
e9bd3547 1116 my @ret;
f267b646 1117 for my $c ($self->_order_by_chunks ($val)) {
e9bd3547 1118 my ($sql, @bind);
96449e8e 1119
f267b646 1120 $self->_SWITCH_refkind ($c, {
1121 SCALAR => sub {
e9bd3547 1122 $sql = $c;
f267b646 1123 },
1124 ARRAYREF => sub {
e9bd3547 1125 ($sql, @bind) = @$c;
f267b646 1126 },
1127 });
96449e8e 1128
e9bd3547 1129 $sql = $sql . ' ' . $self->_sqlcase($direction);
96449e8e 1130
e9bd3547 1131 push @ret, [ $sql, @bind];
1132 }
96449e8e 1133
e9bd3547 1134 return @ret;
f267b646 1135 },
1136 });
96449e8e 1137}
1138
1139
96449e8e 1140#======================================================================
1141# DATASOURCE (FOR NOW, JUST PLAIN TABLE OR LIST OF TABLES)
1142#======================================================================
1143
1144sub _table {
1145 my $self = shift;
1146 my $from = shift;
1147 $self->_SWITCH_refkind($from, {
1148 ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$from;},
1149 SCALAR => sub {$self->_quote($from)},
1150 SCALARREF => sub {$$from},
1151 ARRAYREFREF => sub {join ', ', @$from;},
1152 });
1153}
1154
1155
1156#======================================================================
1157# UTILITY FUNCTIONS
1158#======================================================================
1159
955e77ca 1160# highly optimized, as it's called way too often
96449e8e 1161sub _quote {
955e77ca 1162 # my ($self, $label) = @_;
96449e8e 1163
955e77ca 1164 return '' unless defined $_[1];
955e77ca 1165 return ${$_[1]} if ref($_[1]) eq 'SCALAR';
96449e8e 1166
b6251592 1167 unless ($_[0]->{quote_char}) {
170e6c33 1168 $_[0]->_assert_pass_injection_guard($_[1]);
b6251592 1169 return $_[1];
1170 }
96449e8e 1171
07d7c35c 1172 my $qref = ref $_[0]->{quote_char};
955e77ca 1173 my ($l, $r);
07d7c35c 1174 if (!$qref) {
1175 ($l, $r) = ( $_[0]->{quote_char}, $_[0]->{quote_char} );
955e77ca 1176 }
07d7c35c 1177 elsif ($qref eq 'ARRAY') {
1178 ($l, $r) = @{$_[0]->{quote_char}};
955e77ca 1179 }
1180 else {
1181 puke "Unsupported quote_char format: $_[0]->{quote_char}";
1182 }
96449e8e 1183
07d7c35c 1184 # parts containing * are naturally unquoted
1185 return join( $_[0]->{name_sep}||'', map
955e77ca 1186 { $_ eq '*' ? $_ : $l . $_ . $r }
1187 ( $_[0]->{name_sep} ? split (/\Q$_[0]->{name_sep}\E/, $_[1] ) : $_[1] )
1188 );
96449e8e 1189}
1190
1191
1192# Conversion, if applicable
1193sub _convert ($) {
07d7c35c 1194 #my ($self, $arg) = @_;
96449e8e 1195
1196# LDNOTE : modified the previous implementation below because
1197# it was not consistent : the first "return" is always an array,
1198# the second "return" is context-dependent. Anyway, _convert
9d48860e 1199# seems always used with just a single argument, so make it a
96449e8e 1200# scalar function.
1201# return @_ unless $self->{convert};
1202# my $conv = $self->_sqlcase($self->{convert});
1203# my @ret = map { $conv.'('.$_.')' } @_;
1204# return wantarray ? @ret : $ret[0];
07d7c35c 1205 if ($_[0]->{convert}) {
1206 return $_[0]->_sqlcase($_[0]->{convert}) .'(' . $_[1] . ')';
96449e8e 1207 }
07d7c35c 1208 return $_[1];
96449e8e 1209}
1210
1211# And bindtype
1212sub _bindtype (@) {
07d7c35c 1213 #my ($self, $col, @vals) = @_;
96449e8e 1214
9d48860e 1215 #LDNOTE : changed original implementation below because it did not make
96449e8e 1216 # sense when bindtype eq 'columns' and @vals > 1.
1217# return $self->{bindtype} eq 'columns' ? [ $col, @vals ] : @vals;
1218
07d7c35c 1219 # called often - tighten code
1220 return $_[0]->{bindtype} eq 'columns'
1221 ? map {[$_[1], $_]} @_[2 .. $#_]
1222 : @_[2 .. $#_]
1223 ;
96449e8e 1224}
1225
fe3ae272 1226# Dies if any element of @bind is not in [colname => value] format
1227# if bindtype is 'columns'.
1228sub _assert_bindval_matches_bindtype {
c94a6c93 1229# my ($self, @bind) = @_;
1230 my $self = shift;
fe3ae272 1231 if ($self->{bindtype} eq 'columns') {
c94a6c93 1232 for (@_) {
1233 if (!defined $_ || ref($_) ne 'ARRAY' || @$_ != 2) {
3a06278c 1234 puke "bindtype 'columns' selected, you need to pass: [column_name => bind_value]"
fe3ae272 1235 }
1236 }
1237 }
1238}
1239
96449e8e 1240sub _join_sql_clauses {
1241 my ($self, $logic, $clauses_aref, $bind_aref) = @_;
1242
1243 if (@$clauses_aref > 1) {
1244 my $join = " " . $self->_sqlcase($logic) . " ";
1245 my $sql = '( ' . join($join, @$clauses_aref) . ' )';
1246 return ($sql, @$bind_aref);
1247 }
1248 elsif (@$clauses_aref) {
1249 return ($clauses_aref->[0], @$bind_aref); # no parentheses
1250 }
1251 else {
1252 return (); # if no SQL, ignore @$bind_aref
1253 }
1254}
1255
1256
1257# Fix SQL case, if so requested
1258sub _sqlcase {
96449e8e 1259 # LDNOTE: if $self->{case} is true, then it contains 'lower', so we
1260 # don't touch the argument ... crooked logic, but let's not change it!
07d7c35c 1261 return $_[0]->{case} ? $_[1] : uc($_[1]);
96449e8e 1262}
1263
1264
1265#======================================================================
1266# DISPATCHING FROM REFKIND
1267#======================================================================
1268
1269sub _refkind {
1270 my ($self, $data) = @_;
96449e8e 1271
955e77ca 1272 return 'UNDEF' unless defined $data;
1273
1274 # blessed objects are treated like scalars
1275 my $ref = (Scalar::Util::blessed $data) ? '' : ref $data;
1276
1277 return 'SCALAR' unless $ref;
1278
1279 my $n_steps = 1;
1280 while ($ref eq 'REF') {
96449e8e 1281 $data = $$data;
955e77ca 1282 $ref = (Scalar::Util::blessed $data) ? '' : ref $data;
1283 $n_steps++ if $ref;
96449e8e 1284 }
1285
848556bc 1286 return ($ref||'SCALAR') . ('REF' x $n_steps);
96449e8e 1287}
1288
1289sub _try_refkind {
1290 my ($self, $data) = @_;
1291 my @try = ($self->_refkind($data));
1292 push @try, 'SCALAR_or_UNDEF' if $try[0] eq 'SCALAR' || $try[0] eq 'UNDEF';
1293 push @try, 'FALLBACK';
955e77ca 1294 return \@try;
96449e8e 1295}
1296
1297sub _METHOD_FOR_refkind {
1298 my ($self, $meth_prefix, $data) = @_;
f39eaa60 1299
1300 my $method;
955e77ca 1301 for (@{$self->_try_refkind($data)}) {
f39eaa60 1302 $method = $self->can($meth_prefix."_".$_)
1303 and last;
1304 }
1305
1306 return $method || puke "cannot dispatch on '$meth_prefix' for ".$self->_refkind($data);
96449e8e 1307}
1308
1309
1310sub _SWITCH_refkind {
1311 my ($self, $data, $dispatch_table) = @_;
1312
f39eaa60 1313 my $coderef;
955e77ca 1314 for (@{$self->_try_refkind($data)}) {
f39eaa60 1315 $coderef = $dispatch_table->{$_}
1316 and last;
1317 }
1318
1319 puke "no dispatch entry for ".$self->_refkind($data)
1320 unless $coderef;
1321
96449e8e 1322 $coderef->();
1323}
1324
1325
1326
1327
1328#======================================================================
1329# VALUES, GENERATE, AUTOLOAD
1330#======================================================================
1331
1332# LDNOTE: original code from nwiger, didn't touch code in that section
1333# I feel the AUTOLOAD stuff should not be the default, it should
1334# only be activated on explicit demand by user.
1335
1336sub values {
1337 my $self = shift;
1338 my $data = shift || return;
1339 puke "Argument to ", __PACKAGE__, "->values must be a \\%hash"
1340 unless ref $data eq 'HASH';
bab725ce 1341
1342 my @all_bind;
1343 foreach my $k ( sort keys %$data ) {
1344 my $v = $data->{$k};
1345 $self->_SWITCH_refkind($v, {
9d48860e 1346 ARRAYREF => sub {
bab725ce 1347 if ($self->{array_datatypes}) { # array datatype
1348 push @all_bind, $self->_bindtype($k, $v);
1349 }
1350 else { # literal SQL with bind
1351 my ($sql, @bind) = @$v;
1352 $self->_assert_bindval_matches_bindtype(@bind);
1353 push @all_bind, @bind;
1354 }
1355 },
1356 ARRAYREFREF => sub { # literal SQL with bind
1357 my ($sql, @bind) = @${$v};
1358 $self->_assert_bindval_matches_bindtype(@bind);
1359 push @all_bind, @bind;
1360 },
1361 SCALARREF => sub { # literal SQL without bind
1362 },
1363 SCALAR_or_UNDEF => sub {
1364 push @all_bind, $self->_bindtype($k, $v);
1365 },
1366 });
1367 }
1368
1369 return @all_bind;
96449e8e 1370}
1371
1372sub generate {
1373 my $self = shift;
1374
1375 my(@sql, @sqlq, @sqlv);
1376
1377 for (@_) {
1378 my $ref = ref $_;
1379 if ($ref eq 'HASH') {
1380 for my $k (sort keys %$_) {
1381 my $v = $_->{$k};
1382 my $r = ref $v;
1383 my $label = $self->_quote($k);
1384 if ($r eq 'ARRAY') {
fe3ae272 1385 # literal SQL with bind
1386 my ($sql, @bind) = @$v;
1387 $self->_assert_bindval_matches_bindtype(@bind);
96449e8e 1388 push @sqlq, "$label = $sql";
fe3ae272 1389 push @sqlv, @bind;
96449e8e 1390 } elsif ($r eq 'SCALAR') {
fe3ae272 1391 # literal SQL without bind
96449e8e 1392 push @sqlq, "$label = $$v";
9d48860e 1393 } else {
96449e8e 1394 push @sqlq, "$label = ?";
1395 push @sqlv, $self->_bindtype($k, $v);
1396 }
1397 }
1398 push @sql, $self->_sqlcase('set'), join ', ', @sqlq;
1399 } elsif ($ref eq 'ARRAY') {
1400 # unlike insert(), assume these are ONLY the column names, i.e. for SQL
1401 for my $v (@$_) {
1402 my $r = ref $v;
fe3ae272 1403 if ($r eq 'ARRAY') { # literal SQL with bind
1404 my ($sql, @bind) = @$v;
1405 $self->_assert_bindval_matches_bindtype(@bind);
1406 push @sqlq, $sql;
1407 push @sqlv, @bind;
1408 } elsif ($r eq 'SCALAR') { # literal SQL without bind
96449e8e 1409 # embedded literal SQL
1410 push @sqlq, $$v;
9d48860e 1411 } else {
96449e8e 1412 push @sqlq, '?';
1413 push @sqlv, $v;
1414 }
1415 }
1416 push @sql, '(' . join(', ', @sqlq) . ')';
1417 } elsif ($ref eq 'SCALAR') {
1418 # literal SQL
1419 push @sql, $$_;
1420 } else {
1421 # strings get case twiddled
1422 push @sql, $self->_sqlcase($_);
1423 }
1424 }
1425
1426 my $sql = join ' ', @sql;
1427
1428 # this is pretty tricky
1429 # if ask for an array, return ($stmt, @bind)
1430 # otherwise, s/?/shift @sqlv/ to put it inline
1431 if (wantarray) {
1432 return ($sql, @sqlv);
1433 } else {
1434 1 while $sql =~ s/\?/my $d = shift(@sqlv);
1435 ref $d ? $d->[1] : $d/e;
1436 return $sql;
1437 }
1438}
1439
1440
1441sub DESTROY { 1 }
1442
1443sub AUTOLOAD {
1444 # This allows us to check for a local, then _form, attr
1445 my $self = shift;
1446 my($name) = $AUTOLOAD =~ /.*::(.+)/;
1447 return $self->generate($name, @_);
1448}
1449
14501;
1451
1452
1453
1454__END__
32eab2da 1455
1456=head1 NAME
1457
1458SQL::Abstract - Generate SQL from Perl data structures
1459
1460=head1 SYNOPSIS
1461
1462 use SQL::Abstract;
1463
1464 my $sql = SQL::Abstract->new;
1465
1466 my($stmt, @bind) = $sql->select($table, \@fields, \%where, \@order);
1467
1468 my($stmt, @bind) = $sql->insert($table, \%fieldvals || \@values);
1469
1470 my($stmt, @bind) = $sql->update($table, \%fieldvals, \%where);
1471
1472 my($stmt, @bind) = $sql->delete($table, \%where);
1473
1474 # Then, use these in your DBI statements
1475 my $sth = $dbh->prepare($stmt);
1476 $sth->execute(@bind);
1477
1478 # Just generate the WHERE clause
abe72f94 1479 my($stmt, @bind) = $sql->where(\%where, \@order);
32eab2da 1480
1481 # Return values in the same order, for hashed queries
1482 # See PERFORMANCE section for more details
1483 my @bind = $sql->values(\%fieldvals);
1484
1485=head1 DESCRIPTION
1486
1487This module was inspired by the excellent L<DBIx::Abstract>.
1488However, in using that module I found that what I really wanted
1489to do was generate SQL, but still retain complete control over my
1490statement handles and use the DBI interface. So, I set out to
1491create an abstract SQL generation module.
1492
1493While based on the concepts used by L<DBIx::Abstract>, there are
1494several important differences, especially when it comes to WHERE
1495clauses. I have modified the concepts used to make the SQL easier
1496to generate from Perl data structures and, IMO, more intuitive.
1497The underlying idea is for this module to do what you mean, based
1498on the data structures you provide it. The big advantage is that
1499you don't have to modify your code every time your data changes,
1500as this module figures it out.
1501
1502To begin with, an SQL INSERT is as easy as just specifying a hash
1503of C<key=value> pairs:
1504
1505 my %data = (
1506 name => 'Jimbo Bobson',
1507 phone => '123-456-7890',
1508 address => '42 Sister Lane',
1509 city => 'St. Louis',
1510 state => 'Louisiana',
1511 );
1512
1513The SQL can then be generated with this:
1514
1515 my($stmt, @bind) = $sql->insert('people', \%data);
1516
1517Which would give you something like this:
1518
1519 $stmt = "INSERT INTO people
1520 (address, city, name, phone, state)
1521 VALUES (?, ?, ?, ?, ?)";
1522 @bind = ('42 Sister Lane', 'St. Louis', 'Jimbo Bobson',
1523 '123-456-7890', 'Louisiana');
1524
1525These are then used directly in your DBI code:
1526
1527 my $sth = $dbh->prepare($stmt);
1528 $sth->execute(@bind);
1529
96449e8e 1530=head2 Inserting and Updating Arrays
1531
1532If your database has array types (like for example Postgres),
1533activate the special option C<< array_datatypes => 1 >>
9d48860e 1534when creating the C<SQL::Abstract> object.
96449e8e 1535Then you may use an arrayref to insert and update database array types:
1536
1537 my $sql = SQL::Abstract->new(array_datatypes => 1);
1538 my %data = (
1539 planets => [qw/Mercury Venus Earth Mars/]
1540 );
9d48860e 1541
96449e8e 1542 my($stmt, @bind) = $sql->insert('solar_system', \%data);
1543
1544This results in:
1545
1546 $stmt = "INSERT INTO solar_system (planets) VALUES (?)"
1547
1548 @bind = (['Mercury', 'Venus', 'Earth', 'Mars']);
1549
1550
1551=head2 Inserting and Updating SQL
1552
1553In order to apply SQL functions to elements of your C<%data> you may
1554specify a reference to an arrayref for the given hash value. For example,
1555if you need to execute the Oracle C<to_date> function on a value, you can
1556say something like this:
32eab2da 1557
1558 my %data = (
1559 name => 'Bill',
96449e8e 1560 date_entered => \["to_date(?,'MM/DD/YYYY')", "03/02/2003"],
9d48860e 1561 );
32eab2da 1562
1563The first value in the array is the actual SQL. Any other values are
1564optional and would be included in the bind values array. This gives
1565you:
1566
1567 my($stmt, @bind) = $sql->insert('people', \%data);
1568
9d48860e 1569 $stmt = "INSERT INTO people (name, date_entered)
32eab2da 1570 VALUES (?, to_date(?,'MM/DD/YYYY'))";
1571 @bind = ('Bill', '03/02/2003');
1572
1573An UPDATE is just as easy, all you change is the name of the function:
1574
1575 my($stmt, @bind) = $sql->update('people', \%data);
1576
1577Notice that your C<%data> isn't touched; the module will generate
1578the appropriately quirky SQL for you automatically. Usually you'll
1579want to specify a WHERE clause for your UPDATE, though, which is
1580where handling C<%where> hashes comes in handy...
1581
96449e8e 1582=head2 Complex where statements
1583
32eab2da 1584This module can generate pretty complicated WHERE statements
1585easily. For example, simple C<key=value> pairs are taken to mean
1586equality, and if you want to see if a field is within a set
1587of values, you can use an arrayref. Let's say we wanted to
1588SELECT some data based on this criteria:
1589
1590 my %where = (
1591 requestor => 'inna',
1592 worker => ['nwiger', 'rcwe', 'sfz'],
1593 status => { '!=', 'completed' }
1594 );
1595
1596 my($stmt, @bind) = $sql->select('tickets', '*', \%where);
1597
1598The above would give you something like this:
1599
1600 $stmt = "SELECT * FROM tickets WHERE
1601 ( requestor = ? ) AND ( status != ? )
1602 AND ( worker = ? OR worker = ? OR worker = ? )";
1603 @bind = ('inna', 'completed', 'nwiger', 'rcwe', 'sfz');
1604
1605Which you could then use in DBI code like so:
1606
1607 my $sth = $dbh->prepare($stmt);
1608 $sth->execute(@bind);
1609
1610Easy, eh?
1611
1612=head1 FUNCTIONS
1613
1614The functions are simple. There's one for each major SQL operation,
1615and a constructor you use first. The arguments are specified in a
9d48860e 1616similar order to each function (table, then fields, then a where
32eab2da 1617clause) to try and simplify things.
1618
83cab70b 1619
83cab70b 1620
32eab2da 1621
1622=head2 new(option => 'value')
1623
1624The C<new()> function takes a list of options and values, and returns
1625a new B<SQL::Abstract> object which can then be used to generate SQL
1626through the methods below. The options accepted are:
1627
1628=over
1629
1630=item case
1631
1632If set to 'lower', then SQL will be generated in all lowercase. By
1633default SQL is generated in "textbook" case meaning something like:
1634
1635 SELECT a_field FROM a_table WHERE some_field LIKE '%someval%'
1636
96449e8e 1637Any setting other than 'lower' is ignored.
1638
32eab2da 1639=item cmp
1640
1641This determines what the default comparison operator is. By default
1642it is C<=>, meaning that a hash like this:
1643
1644 %where = (name => 'nwiger', email => 'nate@wiger.org');
1645
1646Will generate SQL like this:
1647
1648 WHERE name = 'nwiger' AND email = 'nate@wiger.org'
1649
1650However, you may want loose comparisons by default, so if you set
1651C<cmp> to C<like> you would get SQL such as:
1652
1653 WHERE name like 'nwiger' AND email like 'nate@wiger.org'
1654
1655You can also override the comparsion on an individual basis - see
1656the huge section on L</"WHERE CLAUSES"> at the bottom.
1657
96449e8e 1658=item sqltrue, sqlfalse
1659
1660Expressions for inserting boolean values within SQL statements.
6e0c6552 1661By default these are C<1=1> and C<1=0>. They are used
1662by the special operators C<-in> and C<-not_in> for generating
1663correct SQL even when the argument is an empty array (see below).
96449e8e 1664
32eab2da 1665=item logic
1666
1667This determines the default logical operator for multiple WHERE
7cac25e6 1668statements in arrays or hashes. If absent, the default logic is "or"
1669for arrays, and "and" for hashes. This means that a WHERE
32eab2da 1670array of the form:
1671
1672 @where = (
9d48860e 1673 event_date => {'>=', '2/13/99'},
1674 event_date => {'<=', '4/24/03'},
32eab2da 1675 );
1676
7cac25e6 1677will generate SQL like this:
32eab2da 1678
1679 WHERE event_date >= '2/13/99' OR event_date <= '4/24/03'
1680
1681This is probably not what you want given this query, though (look
1682at the dates). To change the "OR" to an "AND", simply specify:
1683
1684 my $sql = SQL::Abstract->new(logic => 'and');
1685
1686Which will change the above C<WHERE> to:
1687
1688 WHERE event_date >= '2/13/99' AND event_date <= '4/24/03'
1689
96449e8e 1690The logic can also be changed locally by inserting
7cac25e6 1691a modifier in front of an arrayref :
96449e8e 1692
9d48860e 1693 @where = (-and => [event_date => {'>=', '2/13/99'},
7cac25e6 1694 event_date => {'<=', '4/24/03'} ]);
96449e8e 1695
1696See the L</"WHERE CLAUSES"> section for explanations.
1697
32eab2da 1698=item convert
1699
1700This will automatically convert comparisons using the specified SQL
1701function for both column and value. This is mostly used with an argument
1702of C<upper> or C<lower>, so that the SQL will have the effect of
1703case-insensitive "searches". For example, this:
1704
1705 $sql = SQL::Abstract->new(convert => 'upper');
1706 %where = (keywords => 'MaKe iT CAse inSeNSItive');
1707
1708Will turn out the following SQL:
1709
1710 WHERE upper(keywords) like upper('MaKe iT CAse inSeNSItive')
1711
1712The conversion can be C<upper()>, C<lower()>, or any other SQL function
1713that can be applied symmetrically to fields (actually B<SQL::Abstract> does
1714not validate this option; it will just pass through what you specify verbatim).
1715
1716=item bindtype
1717
1718This is a kludge because many databases suck. For example, you can't
1719just bind values using DBI's C<execute()> for Oracle C<CLOB> or C<BLOB> fields.
1720Instead, you have to use C<bind_param()>:
1721
1722 $sth->bind_param(1, 'reg data');
1723 $sth->bind_param(2, $lots, {ora_type => ORA_CLOB});
1724
1725The problem is, B<SQL::Abstract> will normally just return a C<@bind> array,
1726which loses track of which field each slot refers to. Fear not.
1727
1728If you specify C<bindtype> in new, you can determine how C<@bind> is returned.
1729Currently, you can specify either C<normal> (default) or C<columns>. If you
1730specify C<columns>, you will get an array that looks like this:
1731
1732 my $sql = SQL::Abstract->new(bindtype => 'columns');
1733 my($stmt, @bind) = $sql->insert(...);
1734
1735 @bind = (
1736 [ 'column1', 'value1' ],
1737 [ 'column2', 'value2' ],
1738 [ 'column3', 'value3' ],
1739 );
1740
1741You can then iterate through this manually, using DBI's C<bind_param()>.
e3f9dff4 1742
32eab2da 1743 $sth->prepare($stmt);
1744 my $i = 1;
1745 for (@bind) {
1746 my($col, $data) = @$_;
1747 if ($col eq 'details' || $col eq 'comments') {
1748 $sth->bind_param($i, $data, {ora_type => ORA_CLOB});
1749 } elsif ($col eq 'image') {
1750 $sth->bind_param($i, $data, {ora_type => ORA_BLOB});
1751 } else {
1752 $sth->bind_param($i, $data);
1753 }
1754 $i++;
1755 }
1756 $sth->execute; # execute without @bind now
1757
1758Now, why would you still use B<SQL::Abstract> if you have to do this crap?
1759Basically, the advantage is still that you don't have to care which fields
1760are or are not included. You could wrap that above C<for> loop in a simple
1761sub called C<bind_fields()> or something and reuse it repeatedly. You still
1762get a layer of abstraction over manual SQL specification.
1763
deb148a2 1764Note that if you set L</bindtype> to C<columns>, the C<\[$sql, @bind]>
1765construct (see L</Literal SQL with placeholders and bind values (subqueries)>)
1766will expect the bind values in this format.
1767
32eab2da 1768=item quote_char
1769
1770This is the character that a table or column name will be quoted
9d48860e 1771with. By default this is an empty string, but you could set it to
32eab2da 1772the character C<`>, to generate SQL like this:
1773
1774 SELECT `a_field` FROM `a_table` WHERE `some_field` LIKE '%someval%'
1775
96449e8e 1776Alternatively, you can supply an array ref of two items, the first being the left
1777hand quote character, and the second the right hand quote character. For
1778example, you could supply C<['[',']']> for SQL Server 2000 compliant quotes
1779that generates SQL like this:
1780
1781 SELECT [a_field] FROM [a_table] WHERE [some_field] LIKE '%someval%'
1782
9d48860e 1783Quoting is useful if you have tables or columns names that are reserved
96449e8e 1784words in your database's SQL dialect.
32eab2da 1785
1786=item name_sep
1787
1788This is the character that separates a table and column name. It is
1789necessary to specify this when the C<quote_char> option is selected,
1790so that tables and column names can be individually quoted like this:
1791
1792 SELECT `table`.`one_field` FROM `table` WHERE `table`.`other_field` = 1
1793
b6251592 1794=item injection_guard
1795
1796A regular expression C<qr/.../> that is applied to any C<-function> and unquoted
1797column name specified in a query structure. This is a safety mechanism to avoid
1798injection attacks when mishandling user input e.g.:
1799
1800 my %condition_as_column_value_pairs = get_values_from_user();
1801 $sqla->select( ... , \%condition_as_column_value_pairs );
1802
1803If the expression matches an exception is thrown. Note that literal SQL
1804supplied via C<\'...'> or C<\['...']> is B<not> checked in any way.
1805
1806Defaults to checking for C<;> and the C<GO> keyword (TransactSQL)
1807
96449e8e 1808=item array_datatypes
32eab2da 1809
9d48860e 1810When this option is true, arrayrefs in INSERT or UPDATE are
1811interpreted as array datatypes and are passed directly
96449e8e 1812to the DBI layer.
1813When this option is false, arrayrefs are interpreted
1814as literal SQL, just like refs to arrayrefs
1815(but this behavior is for backwards compatibility; when writing
1816new queries, use the "reference to arrayref" syntax
1817for literal SQL).
32eab2da 1818
32eab2da 1819
96449e8e 1820=item special_ops
32eab2da 1821
9d48860e 1822Takes a reference to a list of "special operators"
96449e8e 1823to extend the syntax understood by L<SQL::Abstract>.
1824See section L</"SPECIAL OPERATORS"> for details.
32eab2da 1825
59f23b3d 1826=item unary_ops
1827
9d48860e 1828Takes a reference to a list of "unary operators"
59f23b3d 1829to extend the syntax understood by L<SQL::Abstract>.
1830See section L</"UNARY OPERATORS"> for details.
1831
32eab2da 1832
32eab2da 1833
96449e8e 1834=back
32eab2da 1835
02288357 1836=head2 insert($table, \@values || \%fieldvals, \%options)
32eab2da 1837
1838This is the simplest function. You simply give it a table name
1839and either an arrayref of values or hashref of field/value pairs.
1840It returns an SQL INSERT statement and a list of bind values.
96449e8e 1841See the sections on L</"Inserting and Updating Arrays"> and
1842L</"Inserting and Updating SQL"> for information on how to insert
1843with those data types.
32eab2da 1844
02288357 1845The optional C<\%options> hash reference may contain additional
1846options to generate the insert SQL. Currently supported options
1847are:
1848
1849=over 4
1850
1851=item returning
1852
1853Takes either a scalar of raw SQL fields, or an array reference of
1854field names, and adds on an SQL C<RETURNING> statement at the end.
1855This allows you to return data generated by the insert statement
1856(such as row IDs) without performing another C<SELECT> statement.
1857Note, however, this is not part of the SQL standard and may not
1858be supported by all database engines.
1859
1860=back
1861
32eab2da 1862=head2 update($table, \%fieldvals, \%where)
1863
1864This takes a table, hashref of field/value pairs, and an optional
86298391 1865hashref L<WHERE clause|/WHERE CLAUSES>. It returns an SQL UPDATE function and a list
32eab2da 1866of bind values.
96449e8e 1867See the sections on L</"Inserting and Updating Arrays"> and
1868L</"Inserting and Updating SQL"> for information on how to insert
1869with those data types.
32eab2da 1870
96449e8e 1871=head2 select($source, $fields, $where, $order)
32eab2da 1872
9d48860e 1873This returns a SQL SELECT statement and associated list of bind values, as
96449e8e 1874specified by the arguments :
32eab2da 1875
96449e8e 1876=over
32eab2da 1877
96449e8e 1878=item $source
32eab2da 1879
9d48860e 1880Specification of the 'FROM' part of the statement.
96449e8e 1881The argument can be either a plain scalar (interpreted as a table
1882name, will be quoted), or an arrayref (interpreted as a list
1883of table names, joined by commas, quoted), or a scalarref
1884(literal table name, not quoted), or a ref to an arrayref
1885(list of literal table names, joined by commas, not quoted).
32eab2da 1886
96449e8e 1887=item $fields
32eab2da 1888
9d48860e 1889Specification of the list of fields to retrieve from
96449e8e 1890the source.
1891The argument can be either an arrayref (interpreted as a list
9d48860e 1892of field names, will be joined by commas and quoted), or a
96449e8e 1893plain scalar (literal SQL, not quoted).
1894Please observe that this API is not as flexible as for
e3f9dff4 1895the first argument C<$table>, for backwards compatibility reasons.
32eab2da 1896
96449e8e 1897=item $where
32eab2da 1898
96449e8e 1899Optional argument to specify the WHERE part of the query.
1900The argument is most often a hashref, but can also be
9d48860e 1901an arrayref or plain scalar --
96449e8e 1902see section L<WHERE clause|/"WHERE CLAUSES"> for details.
32eab2da 1903
96449e8e 1904=item $order
32eab2da 1905
96449e8e 1906Optional argument to specify the ORDER BY part of the query.
9d48860e 1907The argument can be a scalar, a hashref or an arrayref
96449e8e 1908-- see section L<ORDER BY clause|/"ORDER BY CLAUSES">
1909for details.
32eab2da 1910
96449e8e 1911=back
32eab2da 1912
32eab2da 1913
1914=head2 delete($table, \%where)
1915
86298391 1916This takes a table name and optional hashref L<WHERE clause|/WHERE CLAUSES>.
32eab2da 1917It returns an SQL DELETE statement and list of bind values.
1918
32eab2da 1919=head2 where(\%where, \@order)
1920
1921This is used to generate just the WHERE clause. For example,
1922if you have an arbitrary data structure and know what the
1923rest of your SQL is going to look like, but want an easy way
1924to produce a WHERE clause, use this. It returns an SQL WHERE
1925clause and list of bind values.
1926
32eab2da 1927
1928=head2 values(\%data)
1929
1930This just returns the values from the hash C<%data>, in the same
1931order that would be returned from any of the other above queries.
1932Using this allows you to markedly speed up your queries if you
1933are affecting lots of rows. See below under the L</"PERFORMANCE"> section.
1934
32eab2da 1935=head2 generate($any, 'number', $of, \@data, $struct, \%types)
1936
1937Warning: This is an experimental method and subject to change.
1938
1939This returns arbitrarily generated SQL. It's a really basic shortcut.
1940It will return two different things, depending on return context:
1941
1942 my($stmt, @bind) = $sql->generate('create table', \$table, \@fields);
1943 my $stmt_and_val = $sql->generate('create table', \$table, \@fields);
1944
1945These would return the following:
1946
1947 # First calling form
1948 $stmt = "CREATE TABLE test (?, ?)";
1949 @bind = (field1, field2);
1950
1951 # Second calling form
1952 $stmt_and_val = "CREATE TABLE test (field1, field2)";
1953
1954Depending on what you're trying to do, it's up to you to choose the correct
1955format. In this example, the second form is what you would want.
1956
1957By the same token:
1958
1959 $sql->generate('alter session', { nls_date_format => 'MM/YY' });
1960
1961Might give you:
1962
1963 ALTER SESSION SET nls_date_format = 'MM/YY'
1964
1965You get the idea. Strings get their case twiddled, but everything
1966else remains verbatim.
1967
32eab2da 1968
32eab2da 1969
32eab2da 1970
1971=head1 WHERE CLAUSES
1972
96449e8e 1973=head2 Introduction
1974
32eab2da 1975This module uses a variation on the idea from L<DBIx::Abstract>. It
1976is B<NOT>, repeat I<not> 100% compatible. B<The main logic of this
1977module is that things in arrays are OR'ed, and things in hashes
1978are AND'ed.>
1979
1980The easiest way to explain is to show lots of examples. After
1981each C<%where> hash shown, it is assumed you used:
1982
1983 my($stmt, @bind) = $sql->where(\%where);
1984
1985However, note that the C<%where> hash can be used directly in any
1986of the other functions as well, as described above.
1987
96449e8e 1988=head2 Key-value pairs
1989
32eab2da 1990So, let's get started. To begin, a simple hash:
1991
1992 my %where = (
1993 user => 'nwiger',
1994 status => 'completed'
1995 );
1996
1997Is converted to SQL C<key = val> statements:
1998
1999 $stmt = "WHERE user = ? AND status = ?";
2000 @bind = ('nwiger', 'completed');
2001
2002One common thing I end up doing is having a list of values that
2003a field can be in. To do this, simply specify a list inside of
2004an arrayref:
2005
2006 my %where = (
2007 user => 'nwiger',
2008 status => ['assigned', 'in-progress', 'pending'];
2009 );
2010
2011This simple code will create the following:
9d48860e 2012
32eab2da 2013 $stmt = "WHERE user = ? AND ( status = ? OR status = ? OR status = ? )";
2014 @bind = ('nwiger', 'assigned', 'in-progress', 'pending');
2015
9d48860e 2016A field associated to an empty arrayref will be considered a
7cac25e6 2017logical false and will generate 0=1.
8a68b5be 2018
b864ba9b 2019=head2 Tests for NULL values
2020
2021If the value part is C<undef> then this is converted to SQL <IS NULL>
2022
2023 my %where = (
2024 user => 'nwiger',
2025 status => undef,
2026 );
2027
2028becomes:
2029
2030 $stmt = "WHERE user = ? AND status IS NULL";
2031 @bind = ('nwiger');
2032
6e0c6552 2033=head2 Specific comparison operators
96449e8e 2034
32eab2da 2035If you want to specify a different type of operator for your comparison,
2036you can use a hashref for a given column:
2037
2038 my %where = (
2039 user => 'nwiger',
2040 status => { '!=', 'completed' }
2041 );
2042
2043Which would generate:
2044
2045 $stmt = "WHERE user = ? AND status != ?";
2046 @bind = ('nwiger', 'completed');
2047
2048To test against multiple values, just enclose the values in an arrayref:
2049
96449e8e 2050 status => { '=', ['assigned', 'in-progress', 'pending'] };
2051
f2d5020d 2052Which would give you:
96449e8e 2053
2054 "WHERE status = ? OR status = ? OR status = ?"
2055
2056
2057The hashref can also contain multiple pairs, in which case it is expanded
32eab2da 2058into an C<AND> of its elements:
2059
2060 my %where = (
2061 user => 'nwiger',
2062 status => { '!=', 'completed', -not_like => 'pending%' }
2063 );
2064
2065 # Or more dynamically, like from a form
2066 $where{user} = 'nwiger';
2067 $where{status}{'!='} = 'completed';
2068 $where{status}{'-not_like'} = 'pending%';
2069
2070 # Both generate this
2071 $stmt = "WHERE user = ? AND status != ? AND status NOT LIKE ?";
2072 @bind = ('nwiger', 'completed', 'pending%');
2073
96449e8e 2074
32eab2da 2075To get an OR instead, you can combine it with the arrayref idea:
2076
2077 my %where => (
2078 user => 'nwiger',
2079 priority => [ {'=', 2}, {'!=', 1} ]
2080 );
2081
2082Which would generate:
2083
2084 $stmt = "WHERE user = ? AND priority = ? OR priority != ?";
2085 @bind = ('nwiger', '2', '1');
2086
44b9e502 2087If you want to include literal SQL (with or without bind values), just use a
2088scalar reference or array reference as the value:
2089
2090 my %where = (
2091 date_entered => { '>' => \["to_date(?, 'MM/DD/YYYY')", "11/26/2008"] },
2092 date_expires => { '<' => \"now()" }
2093 );
2094
2095Which would generate:
2096
2097 $stmt = "WHERE date_entered > "to_date(?, 'MM/DD/YYYY') AND date_expires < now()";
2098 @bind = ('11/26/2008');
2099
96449e8e 2100
2101=head2 Logic and nesting operators
2102
2103In the example above,
2104there is a subtle trap if you want to say something like
32eab2da 2105this (notice the C<AND>):
2106
2107 WHERE priority != ? AND priority != ?
2108
2109Because, in Perl you I<can't> do this:
2110
2111 priority => { '!=', 2, '!=', 1 }
2112
2113As the second C<!=> key will obliterate the first. The solution
2114is to use the special C<-modifier> form inside an arrayref:
2115
9d48860e 2116 priority => [ -and => {'!=', 2},
96449e8e 2117 {'!=', 1} ]
2118
32eab2da 2119
2120Normally, these would be joined by C<OR>, but the modifier tells it
2121to use C<AND> instead. (Hint: You can use this in conjunction with the
2122C<logic> option to C<new()> in order to change the way your queries
2123work by default.) B<Important:> Note that the C<-modifier> goes
2124B<INSIDE> the arrayref, as an extra first element. This will
2125B<NOT> do what you think it might:
2126
2127 priority => -and => [{'!=', 2}, {'!=', 1}] # WRONG!
2128
2129Here is a quick list of equivalencies, since there is some overlap:
2130
2131 # Same
2132 status => {'!=', 'completed', 'not like', 'pending%' }
2133 status => [ -and => {'!=', 'completed'}, {'not like', 'pending%'}]
2134
2135 # Same
2136 status => {'=', ['assigned', 'in-progress']}
2137 status => [ -or => {'=', 'assigned'}, {'=', 'in-progress'}]
2138 status => [ {'=', 'assigned'}, {'=', 'in-progress'} ]
2139
e3f9dff4 2140
2141
96449e8e 2142=head2 Special operators : IN, BETWEEN, etc.
2143
32eab2da 2144You can also use the hashref format to compare a list of fields using the
2145C<IN> comparison operator, by specifying the list as an arrayref:
2146
2147 my %where = (
2148 status => 'completed',
2149 reportid => { -in => [567, 2335, 2] }
2150 );
2151
2152Which would generate:
2153
2154 $stmt = "WHERE status = ? AND reportid IN (?,?,?)";
2155 @bind = ('completed', '567', '2335', '2');
2156
9d48860e 2157The reverse operator C<-not_in> generates SQL C<NOT IN> and is used in
96449e8e 2158the same way.
2159
6e0c6552 2160If the argument to C<-in> is an empty array, 'sqlfalse' is generated
2161(by default : C<1=0>). Similarly, C<< -not_in => [] >> generates
2162'sqltrue' (by default : C<1=1>).
2163
e41c3bdd 2164In addition to the array you can supply a chunk of literal sql or
2165literal sql with bind:
6e0c6552 2166
e41c3bdd 2167 my %where = {
2168 customer => { -in => \[
2169 'SELECT cust_id FROM cust WHERE balance > ?',
2170 2000,
2171 ],
2172 status => { -in => \'SELECT status_codes FROM states' },
2173 };
6e0c6552 2174
e41c3bdd 2175would generate:
2176
2177 $stmt = "WHERE (
2178 customer IN ( SELECT cust_id FROM cust WHERE balance > ? )
2179 AND status IN ( SELECT status_codes FROM states )
2180 )";
2181 @bind = ('2000');
2182
2183
2184
2185Another pair of operators is C<-between> and C<-not_between>,
96449e8e 2186used with an arrayref of two values:
32eab2da 2187
2188 my %where = (
2189 user => 'nwiger',
2190 completion_date => {
2191 -not_between => ['2002-10-01', '2003-02-06']
2192 }
2193 );
2194
2195Would give you:
2196
2197 WHERE user = ? AND completion_date NOT BETWEEN ( ? AND ? )
2198
e41c3bdd 2199Just like with C<-in> all plausible combinations of literal SQL
2200are possible:
2201
2202 my %where = {
2203 start0 => { -between => [ 1, 2 ] },
2204 start1 => { -between => \["? AND ?", 1, 2] },
2205 start2 => { -between => \"lower(x) AND upper(y)" },
9d48860e 2206 start3 => { -between => [
e41c3bdd 2207 \"lower(x)",
2208 \["upper(?)", 'stuff' ],
2209 ] },
2210 };
2211
2212Would give you:
2213
2214 $stmt = "WHERE (
2215 ( start0 BETWEEN ? AND ? )
2216 AND ( start1 BETWEEN ? AND ? )
2217 AND ( start2 BETWEEN lower(x) AND upper(y) )
2218 AND ( start3 BETWEEN lower(x) AND upper(?) )
2219 )";
2220 @bind = (1, 2, 1, 2, 'stuff');
2221
2222
9d48860e 2223These are the two builtin "special operators"; but the
96449e8e 2224list can be expanded : see section L</"SPECIAL OPERATORS"> below.
2225
59f23b3d 2226=head2 Unary operators: bool
97a920ef 2227
2228If you wish to test against boolean columns or functions within your
2229database you can use the C<-bool> and C<-not_bool> operators. For
2230example to test the column C<is_user> being true and the column
827bb0eb 2231C<is_enabled> being false you would use:-
97a920ef 2232
2233 my %where = (
2234 -bool => 'is_user',
2235 -not_bool => 'is_enabled',
2236 );
2237
2238Would give you:
2239
277b5d3f 2240 WHERE is_user AND NOT is_enabled
97a920ef 2241
0b604e9d 2242If a more complex combination is required, testing more conditions,
2243then you should use the and/or operators:-
2244
2245 my %where = (
2246 -and => [
2247 -bool => 'one',
2248 -bool => 'two',
2249 -bool => 'three',
2250 -not_bool => 'four',
2251 ],
2252 );
2253
2254Would give you:
2255
2256 WHERE one AND two AND three AND NOT four
97a920ef 2257
2258
107b72f1 2259=head2 Nested conditions, -and/-or prefixes
96449e8e 2260
32eab2da 2261So far, we've seen how multiple conditions are joined with a top-level
2262C<AND>. We can change this by putting the different conditions we want in
2263hashes and then putting those hashes in an array. For example:
2264
2265 my @where = (
2266 {
2267 user => 'nwiger',
2268 status => { -like => ['pending%', 'dispatched'] },
2269 },
2270 {
2271 user => 'robot',
2272 status => 'unassigned',
2273 }
2274 );
2275
2276This data structure would create the following:
2277
2278 $stmt = "WHERE ( user = ? AND ( status LIKE ? OR status LIKE ? ) )
2279 OR ( user = ? AND status = ? ) )";
2280 @bind = ('nwiger', 'pending', 'dispatched', 'robot', 'unassigned');
2281
107b72f1 2282
48d9f5f8 2283Clauses in hashrefs or arrayrefs can be prefixed with an C<-and> or C<-or>
2284to change the logic inside :
32eab2da 2285
2286 my @where = (
2287 -and => [
2288 user => 'nwiger',
48d9f5f8 2289 [
2290 -and => [ workhrs => {'>', 20}, geo => 'ASIA' ],
2291 -or => { workhrs => {'<', 50}, geo => 'EURO' },
32eab2da 2292 ],
2293 ],
2294 );
2295
2296That would yield:
2297
48d9f5f8 2298 WHERE ( user = ? AND (
2299 ( workhrs > ? AND geo = ? )
2300 OR ( workhrs < ? OR geo = ? )
2301 ) )
107b72f1 2302
2303=head2 Algebraic inconsistency, for historical reasons
2304
7cac25e6 2305C<Important note>: when connecting several conditions, the C<-and->|C<-or>
2306operator goes C<outside> of the nested structure; whereas when connecting
2307several constraints on one column, the C<-and> operator goes
2308C<inside> the arrayref. Here is an example combining both features :
2309
2310 my @where = (
2311 -and => [a => 1, b => 2],
2312 -or => [c => 3, d => 4],
2313 e => [-and => {-like => 'foo%'}, {-like => '%bar'} ]
2314 )
2315
2316yielding
2317
9d48860e 2318 WHERE ( ( ( a = ? AND b = ? )
2319 OR ( c = ? OR d = ? )
7cac25e6 2320 OR ( e LIKE ? AND e LIKE ? ) ) )
2321
107b72f1 2322This difference in syntax is unfortunate but must be preserved for
2323historical reasons. So be careful : the two examples below would
2324seem algebraically equivalent, but they are not
2325
9d48860e 2326 {col => [-and => {-like => 'foo%'}, {-like => '%bar'}]}
107b72f1 2327 # yields : WHERE ( ( col LIKE ? AND col LIKE ? ) )
2328
9d48860e 2329 [-and => {col => {-like => 'foo%'}, {col => {-like => '%bar'}}]]
107b72f1 2330 # yields : WHERE ( ( col LIKE ? OR col LIKE ? ) )
2331
7cac25e6 2332
96449e8e 2333=head2 Literal SQL
2334
32eab2da 2335Finally, sometimes only literal SQL will do. If you want to include
2336literal SQL verbatim, you can specify it as a scalar reference, namely:
2337
2338 my $inn = 'is Not Null';
2339 my %where = (
2340 priority => { '<', 2 },
2341 requestor => \$inn
2342 );
2343
2344This would create:
2345
2346 $stmt = "WHERE priority < ? AND requestor is Not Null";
2347 @bind = ('2');
2348
2349Note that in this example, you only get one bind parameter back, since
2350the verbatim SQL is passed as part of the statement.
2351
2352Of course, just to prove a point, the above can also be accomplished
2353with this:
2354
2355 my %where = (
2356 priority => { '<', 2 },
2357 requestor => { '!=', undef },
2358 );
2359
96449e8e 2360
e41c3bdd 2361TMTOWTDI
32eab2da 2362
0b604e9d 2363Conditions on boolean columns can be expressed in the same way, passing
2364a reference to an empty string, however using liternal SQL in this way
2365is deprecated - the preferred method is to use the boolean operators -
2366see L</"Unary operators: bool"> :
96449e8e 2367
2368 my %where = (
2369 priority => { '<', 2 },
2370 is_ready => \"";
2371 );
2372
2373which yields
2374
2375 $stmt = "WHERE priority < ? AND is_ready";
2376 @bind = ('2');
2377
b864ba9b 2378Literal SQL is also the only way to compare 2 columns to one another:
2379
2380 my %where = (
2381 priority => { '<', 2 },
2382 requestor => \'= submittor'
2383 );
2384
2385which creates:
2386
2387 $stmt = "WHERE priority < ? AND requestor = submitter";
2388 @bind = ('2');
96449e8e 2389
2390=head2 Literal SQL with placeholders and bind values (subqueries)
2391
2392If the literal SQL to be inserted has placeholders and bind values,
2393use a reference to an arrayref (yes this is a double reference --
2394not so common, but perfectly legal Perl). For example, to find a date
2395in Postgres you can use something like this:
2396
2397 my %where = (
2398 date_column => \[q/= date '2008-09-30' - ?::integer/, 10/]
2399 )
2400
2401This would create:
2402
d2a8fe1a 2403 $stmt = "WHERE ( date_column = date '2008-09-30' - ?::integer )"
96449e8e 2404 @bind = ('10');
2405
deb148a2 2406Note that you must pass the bind values in the same format as they are returned
62552e7d 2407by L</where>. That means that if you set L</bindtype> to C<columns>, you must
26f2dca5 2408provide the bind values in the C<< [ column_meta => value ] >> format, where
2409C<column_meta> is an opaque scalar value; most commonly the column name, but
62552e7d 2410you can use any scalar value (including references and blessed references),
2411L<SQL::Abstract> will simply pass it through intact. So if C<bindtype> is set
2412to C<columns> the above example will look like:
deb148a2 2413
2414 my %where = (
2415 date_column => \[q/= date '2008-09-30' - ?::integer/, [ dummy => 10 ]/]
2416 )
96449e8e 2417
2418Literal SQL is especially useful for nesting parenthesized clauses in the
2419main SQL query. Here is a first example :
2420
2421 my ($sub_stmt, @sub_bind) = ("SELECT c1 FROM t1 WHERE c2 < ? AND c3 LIKE ?",
2422 100, "foo%");
2423 my %where = (
2424 foo => 1234,
2425 bar => \["IN ($sub_stmt)" => @sub_bind],
2426 );
2427
2428This yields :
2429
9d48860e 2430 $stmt = "WHERE (foo = ? AND bar IN (SELECT c1 FROM t1
96449e8e 2431 WHERE c2 < ? AND c3 LIKE ?))";
2432 @bind = (1234, 100, "foo%");
2433
9d48860e 2434Other subquery operators, like for example C<"E<gt> ALL"> or C<"NOT IN">,
96449e8e 2435are expressed in the same way. Of course the C<$sub_stmt> and
9d48860e 2436its associated bind values can be generated through a former call
96449e8e 2437to C<select()> :
2438
2439 my ($sub_stmt, @sub_bind)
9d48860e 2440 = $sql->select("t1", "c1", {c2 => {"<" => 100},
96449e8e 2441 c3 => {-like => "foo%"}});
2442 my %where = (
2443 foo => 1234,
2444 bar => \["> ALL ($sub_stmt)" => @sub_bind],
2445 );
2446
2447In the examples above, the subquery was used as an operator on a column;
9d48860e 2448but the same principle also applies for a clause within the main C<%where>
96449e8e 2449hash, like an EXISTS subquery :
2450
9d48860e 2451 my ($sub_stmt, @sub_bind)
96449e8e 2452 = $sql->select("t1", "*", {c1 => 1, c2 => \"> t0.c0"});
48d9f5f8 2453 my %where = ( -and => [
96449e8e 2454 foo => 1234,
48d9f5f8 2455 \["EXISTS ($sub_stmt)" => @sub_bind],
2456 ]);
96449e8e 2457
2458which yields
2459
9d48860e 2460 $stmt = "WHERE (foo = ? AND EXISTS (SELECT * FROM t1
96449e8e 2461 WHERE c1 = ? AND c2 > t0.c0))";
2462 @bind = (1234, 1);
2463
2464
9d48860e 2465Observe that the condition on C<c2> in the subquery refers to
2466column C<t0.c0> of the main query : this is I<not> a bind
2467value, so we have to express it through a scalar ref.
96449e8e 2468Writing C<< c2 => {">" => "t0.c0"} >> would have generated
2469C<< c2 > ? >> with bind value C<"t0.c0"> ... not exactly
2470what we wanted here.
2471
96449e8e 2472Finally, here is an example where a subquery is used
2473for expressing unary negation:
2474
9d48860e 2475 my ($sub_stmt, @sub_bind)
96449e8e 2476 = $sql->where({age => [{"<" => 10}, {">" => 20}]});
2477 $sub_stmt =~ s/^ where //i; # don't want "WHERE" in the subclause
2478 my %where = (
2479 lname => {like => '%son%'},
48d9f5f8 2480 \["NOT ($sub_stmt)" => @sub_bind],
96449e8e 2481 );
2482
2483This yields
2484
2485 $stmt = "lname LIKE ? AND NOT ( age < ? OR age > ? )"
2486 @bind = ('%son%', 10, 20)
2487
2488
2489
2490=head2 Conclusion
2491
32eab2da 2492These pages could go on for a while, since the nesting of the data
2493structures this module can handle are pretty much unlimited (the
2494module implements the C<WHERE> expansion as a recursive function
2495internally). Your best bet is to "play around" with the module a
2496little to see how the data structures behave, and choose the best
2497format for your data based on that.
2498
2499And of course, all the values above will probably be replaced with
2500variables gotten from forms or the command line. After all, if you
2501knew everything ahead of time, you wouldn't have to worry about
2502dynamically-generating SQL and could just hardwire it into your
2503script.
2504
96449e8e 2505
2506
2507
86298391 2508=head1 ORDER BY CLAUSES
2509
9d48860e 2510Some functions take an order by clause. This can either be a scalar (just a
86298391 2511column name,) a hash of C<< { -desc => 'col' } >> or C<< { -asc => 'col' } >>,
1cfa1db3 2512or an array of either of the two previous forms. Examples:
2513
952f9e2d 2514 Given | Will Generate
1cfa1db3 2515 ----------------------------------------------------------
952f9e2d 2516 |
2517 \'colA DESC' | ORDER BY colA DESC
2518 |
2519 'colA' | ORDER BY colA
2520 |
2521 [qw/colA colB/] | ORDER BY colA, colB
2522 |
2523 {-asc => 'colA'} | ORDER BY colA ASC
2524 |
2525 {-desc => 'colB'} | ORDER BY colB DESC
2526 |
2527 ['colA', {-asc => 'colB'}] | ORDER BY colA, colB ASC
2528 |
855e6047 2529 { -asc => [qw/colA colB/] } | ORDER BY colA ASC, colB ASC
952f9e2d 2530 |
2531 [ |
2532 { -asc => 'colA' }, | ORDER BY colA ASC, colB DESC,
2533 { -desc => [qw/colB/], | colC ASC, colD ASC
2534 { -asc => [qw/colC colD/],|
2535 ] |
2536 ===========================================================
86298391 2537
96449e8e 2538
2539
2540=head1 SPECIAL OPERATORS
2541
e3f9dff4 2542 my $sqlmaker = SQL::Abstract->new(special_ops => [
3a2e1a5e 2543 {
2544 regex => qr/.../,
e3f9dff4 2545 handler => sub {
2546 my ($self, $field, $op, $arg) = @_;
2547 ...
3a2e1a5e 2548 },
2549 },
2550 {
2551 regex => qr/.../,
2552 handler => 'method_name',
e3f9dff4 2553 },
2554 ]);
2555
9d48860e 2556A "special operator" is a SQL syntactic clause that can be
e3f9dff4 2557applied to a field, instead of a usual binary operator.
9d48860e 2558For example :
e3f9dff4 2559
2560 WHERE field IN (?, ?, ?)
2561 WHERE field BETWEEN ? AND ?
2562 WHERE MATCH(field) AGAINST (?, ?)
96449e8e 2563
e3f9dff4 2564Special operators IN and BETWEEN are fairly standard and therefore
3a2e1a5e 2565are builtin within C<SQL::Abstract> (as the overridable methods
2566C<_where_field_IN> and C<_where_field_BETWEEN>). For other operators,
2567like the MATCH .. AGAINST example above which is specific to MySQL,
2568you can write your own operator handlers - supply a C<special_ops>
2569argument to the C<new> method. That argument takes an arrayref of
2570operator definitions; each operator definition is a hashref with two
2571entries:
96449e8e 2572
e3f9dff4 2573=over
2574
2575=item regex
2576
2577the regular expression to match the operator
96449e8e 2578
e3f9dff4 2579=item handler
2580
3a2e1a5e 2581Either a coderef or a plain scalar method name. In both cases
2582the expected return is C<< ($sql, @bind) >>.
2583
2584When supplied with a method name, it is simply called on the
2585L<SQL::Abstract/> object as:
2586
2587 $self->$method_name ($field, $op, $arg)
2588
2589 Where:
2590
2591 $op is the part that matched the handler regex
2592 $field is the LHS of the operator
2593 $arg is the RHS
2594
2595When supplied with a coderef, it is called as:
2596
2597 $coderef->($self, $field, $op, $arg)
2598
e3f9dff4 2599
2600=back
2601
9d48860e 2602For example, here is an implementation
e3f9dff4 2603of the MATCH .. AGAINST syntax for MySQL
2604
2605 my $sqlmaker = SQL::Abstract->new(special_ops => [
9d48860e 2606
e3f9dff4 2607 # special op for MySql MATCH (field) AGAINST(word1, word2, ...)
9d48860e 2608 {regex => qr/^match$/i,
e3f9dff4 2609 handler => sub {
2610 my ($self, $field, $op, $arg) = @_;
2611 $arg = [$arg] if not ref $arg;
2612 my $label = $self->_quote($field);
2613 my ($placeholder) = $self->_convert('?');
2614 my $placeholders = join ", ", (($placeholder) x @$arg);
2615 my $sql = $self->_sqlcase('match') . " ($label) "
2616 . $self->_sqlcase('against') . " ($placeholders) ";
2617 my @bind = $self->_bindtype($field, @$arg);
2618 return ($sql, @bind);
2619 }
2620 },
9d48860e 2621
e3f9dff4 2622 ]);
96449e8e 2623
2624
59f23b3d 2625=head1 UNARY OPERATORS
2626
112b5232 2627 my $sqlmaker = SQL::Abstract->new(unary_ops => [
59f23b3d 2628 {
2629 regex => qr/.../,
2630 handler => sub {
2631 my ($self, $op, $arg) = @_;
2632 ...
2633 },
2634 },
2635 {
2636 regex => qr/.../,
2637 handler => 'method_name',
2638 },
2639 ]);
2640
9d48860e 2641A "unary operator" is a SQL syntactic clause that can be
59f23b3d 2642applied to a field - the operator goes before the field
2643
2644You can write your own operator handlers - supply a C<unary_ops>
2645argument to the C<new> method. That argument takes an arrayref of
2646operator definitions; each operator definition is a hashref with two
2647entries:
2648
2649=over
2650
2651=item regex
2652
2653the regular expression to match the operator
2654
2655=item handler
2656
2657Either a coderef or a plain scalar method name. In both cases
2658the expected return is C<< $sql >>.
2659
2660When supplied with a method name, it is simply called on the
2661L<SQL::Abstract/> object as:
2662
2663 $self->$method_name ($op, $arg)
2664
2665 Where:
2666
2667 $op is the part that matched the handler regex
2668 $arg is the RHS or argument of the operator
2669
2670When supplied with a coderef, it is called as:
2671
2672 $coderef->($self, $op, $arg)
2673
2674
2675=back
2676
2677
32eab2da 2678=head1 PERFORMANCE
2679
2680Thanks to some benchmarking by Mark Stosberg, it turns out that
2681this module is many orders of magnitude faster than using C<DBIx::Abstract>.
2682I must admit this wasn't an intentional design issue, but it's a
2683byproduct of the fact that you get to control your C<DBI> handles
2684yourself.
2685
2686To maximize performance, use a code snippet like the following:
2687
2688 # prepare a statement handle using the first row
2689 # and then reuse it for the rest of the rows
2690 my($sth, $stmt);
2691 for my $href (@array_of_hashrefs) {
2692 $stmt ||= $sql->insert('table', $href);
2693 $sth ||= $dbh->prepare($stmt);
2694 $sth->execute($sql->values($href));
2695 }
2696
2697The reason this works is because the keys in your C<$href> are sorted
2698internally by B<SQL::Abstract>. Thus, as long as your data retains
2699the same structure, you only have to generate the SQL the first time
2700around. On subsequent queries, simply use the C<values> function provided
2701by this module to return your values in the correct order.
2702
b864ba9b 2703However this depends on the values having the same type - if, for
2704example, the values of a where clause may either have values
2705(resulting in sql of the form C<column = ?> with a single bind
2706value), or alternatively the values might be C<undef> (resulting in
2707sql of the form C<column IS NULL> with no bind value) then the
2708caching technique suggested will not work.
96449e8e 2709
32eab2da 2710=head1 FORMBUILDER
2711
2712If you use my C<CGI::FormBuilder> module at all, you'll hopefully
2713really like this part (I do, at least). Building up a complex query
2714can be as simple as the following:
2715
2716 #!/usr/bin/perl
2717
2718 use CGI::FormBuilder;
2719 use SQL::Abstract;
2720
2721 my $form = CGI::FormBuilder->new(...);
2722 my $sql = SQL::Abstract->new;
2723
2724 if ($form->submitted) {
2725 my $field = $form->field;
2726 my $id = delete $field->{id};
2727 my($stmt, @bind) = $sql->update('table', $field, {id => $id});
2728 }
2729
2730Of course, you would still have to connect using C<DBI> to run the
2731query, but the point is that if you make your form look like your
2732table, the actual query script can be extremely simplistic.
2733
2734If you're B<REALLY> lazy (I am), check out C<HTML::QuickTable> for
9d48860e 2735a fast interface to returning and formatting data. I frequently
32eab2da 2736use these three modules together to write complex database query
2737apps in under 50 lines.
2738
d8cc1792 2739=head1 REPO
2740
2741=over
2742
2743=item * gitweb: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git>
2744
2745=item * git: L<git://git.shadowcat.co.uk/dbsrgits/DBIx-Class.git>
2746
2747=back
32eab2da 2748
96449e8e 2749=head1 CHANGES
2750
2751Version 1.50 was a major internal refactoring of C<SQL::Abstract>.
2752Great care has been taken to preserve the I<published> behavior
2753documented in previous versions in the 1.* family; however,
9d48860e 2754some features that were previously undocumented, or behaved
96449e8e 2755differently from the documentation, had to be changed in order
2756to clarify the semantics. Hence, client code that was relying
9d48860e 2757on some dark areas of C<SQL::Abstract> v1.*
96449e8e 2758B<might behave differently> in v1.50.
32eab2da 2759
d2a8fe1a 2760The main changes are :
2761
96449e8e 2762=over
32eab2da 2763
9d48860e 2764=item *
32eab2da 2765
96449e8e 2766support for literal SQL through the C<< \ [$sql, bind] >> syntax.
2767
2768=item *
2769
145fbfc8 2770support for the { operator => \"..." } construct (to embed literal SQL)
2771
2772=item *
2773
9c37b9c0 2774support for the { operator => \["...", @bind] } construct (to embed literal SQL with bind values)
2775
2776=item *
2777
96449e8e 2778optional support for L<array datatypes|/"Inserting and Updating Arrays">
2779
9d48860e 2780=item *
96449e8e 2781
2782defensive programming : check arguments
2783
2784=item *
2785
2786fixed bug with global logic, which was previously implemented
7cac25e6 2787through global variables yielding side-effects. Prior versions would
96449e8e 2788interpret C<< [ {cond1, cond2}, [cond3, cond4] ] >>
2789as C<< "(cond1 AND cond2) OR (cond3 AND cond4)" >>.
2790Now this is interpreted
2791as C<< "(cond1 AND cond2) OR (cond3 OR cond4)" >>.
2792
96449e8e 2793
2794=item *
2795
2796fixed semantics of _bindtype on array args
2797
9d48860e 2798=item *
96449e8e 2799
2800dropped the C<_anoncopy> of the %where tree. No longer necessary,
2801we just avoid shifting arrays within that tree.
2802
2803=item *
2804
2805dropped the C<_modlogic> function
2806
2807=back
32eab2da 2808
32eab2da 2809
32eab2da 2810
2811=head1 ACKNOWLEDGEMENTS
2812
2813There are a number of individuals that have really helped out with
2814this module. Unfortunately, most of them submitted bugs via CPAN
2815so I have no idea who they are! But the people I do know are:
2816
9d48860e 2817 Ash Berlin (order_by hash term support)
b643abe1 2818 Matt Trout (DBIx::Class support)
32eab2da 2819 Mark Stosberg (benchmarking)
2820 Chas Owens (initial "IN" operator support)
2821 Philip Collins (per-field SQL functions)
2822 Eric Kolve (hashref "AND" support)
2823 Mike Fragassi (enhancements to "BETWEEN" and "LIKE")
2824 Dan Kubb (support for "quote_char" and "name_sep")
f5aab26e 2825 Guillermo Roditi (patch to cleanup "IN" and "BETWEEN", fix and tests for _order_by)
48d9f5f8 2826 Laurent Dami (internal refactoring, extensible list of special operators, literal SQL)
dbdf7648 2827 Norbert Buchmuller (support for literal SQL in hashpair, misc. fixes & tests)
e96c510a 2828 Peter Rabbitson (rewrite of SQLA::Test, misc. fixes & tests)
02288357 2829 Oliver Charles (support for "RETURNING" after "INSERT")
32eab2da 2830
2831Thanks!
2832
32eab2da 2833=head1 SEE ALSO
2834
86298391 2835L<DBIx::Class>, L<DBIx::Abstract>, L<CGI::FormBuilder>, L<HTML::QuickTable>.
32eab2da 2836
32eab2da 2837=head1 AUTHOR
2838
b643abe1 2839Copyright (c) 2001-2007 Nathan Wiger <nwiger@cpan.org>. All Rights Reserved.
2840
2841This module is actively maintained by Matt Trout <mst@shadowcatsystems.co.uk>
32eab2da 2842
abe72f94 2843For support, your best bet is to try the C<DBIx::Class> users mailing list.
2844While not an official support venue, C<DBIx::Class> makes heavy use of
2845C<SQL::Abstract>, and as such list members there are very familiar with
2846how to create queries.
2847
0d067ded 2848=head1 LICENSE
2849
d988ab87 2850This module is free software; you may copy this under the same
2851terms as perl itself (either the GNU General Public License or
2852the Artistic License)
32eab2da 2853
2854=cut
2855