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