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