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