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