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