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