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