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