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