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