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