added patch from Guillermo to cleanup in/between,
[scpubgit/Q-Branch.git] / lib / SQL / Abstract.pm
1
2 package SQL::Abstract;
3
4 =head1 NAME
5
6 SQL::Abstract - Generate SQL from Perl data structures
7
8 =head1 SYNOPSIS
9
10     use SQL::Abstract;
11
12     my $sql = SQL::Abstract->new;
13
14     my($stmt, @bind) = $sql->select($table, \@fields, \%where, \@order);
15
16     my($stmt, @bind) = $sql->insert($table, \%fieldvals || \@values);
17
18     my($stmt, @bind) = $sql->update($table, \%fieldvals, \%where);
19
20     my($stmt, @bind) = $sql->delete($table, \%where);
21
22     # Then, use these in your DBI statements
23     my $sth = $dbh->prepare($stmt);
24     $sth->execute(@bind);
25
26     # Just generate the WHERE clause
27     my($stmt, @bind) = $sql->where(\%where, \@order);
28
29     # Return values in the same order, for hashed queries
30     # See PERFORMANCE section for more details
31     my @bind = $sql->values(\%fieldvals);
32
33 =head1 DESCRIPTION
34
35 This module was inspired by the excellent L<DBIx::Abstract>.
36 However, in using that module I found that what I really wanted
37 to do was generate SQL, but still retain complete control over my
38 statement handles and use the DBI interface. So, I set out to
39 create an abstract SQL generation module.
40
41 While based on the concepts used by L<DBIx::Abstract>, there are
42 several important differences, especially when it comes to WHERE
43 clauses. I have modified the concepts used to make the SQL easier
44 to generate from Perl data structures and, IMO, more intuitive.
45 The underlying idea is for this module to do what you mean, based
46 on the data structures you provide it. The big advantage is that
47 you don't have to modify your code every time your data changes,
48 as this module figures it out.
49
50 To begin with, an SQL INSERT is as easy as just specifying a hash
51 of C<key=value> pairs:
52
53     my %data = (
54         name => 'Jimbo Bobson',
55         phone => '123-456-7890',
56         address => '42 Sister Lane',
57         city => 'St. Louis',
58         state => 'Louisiana',
59     );
60
61 The SQL can then be generated with this:
62
63     my($stmt, @bind) = $sql->insert('people', \%data);
64
65 Which would give you something like this:
66
67     $stmt = "INSERT INTO people
68                     (address, city, name, phone, state)
69                     VALUES (?, ?, ?, ?, ?)";
70     @bind = ('42 Sister Lane', 'St. Louis', 'Jimbo Bobson',
71              '123-456-7890', 'Louisiana');
72
73 These are then used directly in your DBI code:
74
75     my $sth = $dbh->prepare($stmt);
76     $sth->execute(@bind);
77
78 In addition, you can apply SQL functions to elements of your C<%data>
79 by specifying an arrayref for the given hash value. For example, if
80 you need to execute the Oracle C<to_date> function on a value, you
81 can say something like this:
82
83     my %data = (
84         name => 'Bill',
85         date_entered => ["to_date(?,'MM/DD/YYYY')", "03/02/2003"],
86     ); 
87
88 The first value in the array is the actual SQL. Any other values are
89 optional and would be included in the bind values array. This gives
90 you:
91
92     my($stmt, @bind) = $sql->insert('people', \%data);
93
94     $stmt = "INSERT INTO people (name, date_entered) 
95                 VALUES (?, to_date(?,'MM/DD/YYYY'))";
96     @bind = ('Bill', '03/02/2003');
97
98 An UPDATE is just as easy, all you change is the name of the function:
99
100     my($stmt, @bind) = $sql->update('people', \%data);
101
102 Notice that your C<%data> isn't touched; the module will generate
103 the appropriately quirky SQL for you automatically. Usually you'll
104 want to specify a WHERE clause for your UPDATE, though, which is
105 where handling C<%where> hashes comes in handy...
106
107 This module can generate pretty complicated WHERE statements
108 easily. For example, simple C<key=value> pairs are taken to mean
109 equality, and if you want to see if a field is within a set
110 of values, you can use an arrayref. Let's say we wanted to
111 SELECT some data based on this criteria:
112
113     my %where = (
114        requestor => 'inna',
115        worker => ['nwiger', 'rcwe', 'sfz'],
116        status => { '!=', 'completed' }
117     );
118
119     my($stmt, @bind) = $sql->select('tickets', '*', \%where);
120
121 The above would give you something like this:
122
123     $stmt = "SELECT * FROM tickets WHERE
124                 ( requestor = ? ) AND ( status != ? )
125                 AND ( worker = ? OR worker = ? OR worker = ? )";
126     @bind = ('inna', 'completed', 'nwiger', 'rcwe', 'sfz');
127
128 Which you could then use in DBI code like so:
129
130     my $sth = $dbh->prepare($stmt);
131     $sth->execute(@bind);
132
133 Easy, eh?
134
135 =head1 FUNCTIONS
136
137 The functions are simple. There's one for each major SQL operation,
138 and a constructor you use first. The arguments are specified in a
139 similar order to each function (table, then fields, then a where 
140 clause) to try and simplify things.
141
142 =cut
143
144 use Carp;
145 use strict;
146
147 our $VERSION  = '1.22';
148 our $REVISION = '$Id$';
149 our $AUTOLOAD;
150
151 # Fix SQL case, if so requested
152 sub _sqlcase {
153     my $self = shift;
154     return $self->{case} ? $_[0] : uc($_[0]);
155 }
156
157 # Anon copies of arrays/hashes
158 # Based on deep_copy example by merlyn
159 # http://www.stonehenge.com/merlyn/UnixReview/col30.html
160 sub _anoncopy {
161     my $orig = shift;
162     return (ref $orig eq 'HASH')  ? +{map { $_ => _anoncopy($orig->{$_}) } keys %$orig}
163          : (ref $orig eq 'ARRAY') ? [map _anoncopy($_), @$orig]
164          : $orig;
165 }
166
167 # Debug
168 sub _debug {
169     return unless $_[0]->{debug}; shift;  # a little faster
170     my $func = (caller(1))[3];
171     warn "[$func] ", @_, "\n";
172 }
173
174 sub belch (@) {
175     my($func) = (caller(1))[3];
176     carp "[$func] Warning: ", @_;
177 }
178
179 sub puke (@) {
180     my($func) = (caller(1))[3];
181     croak "[$func] Fatal: ", @_;
182 }
183
184 # Utility functions
185 sub _table  {
186     my $self = shift;
187     my $from = shift;
188     if (ref $from eq 'ARRAY') {
189         return $self->_recurse_from(@$from);
190     } elsif (ref $from eq 'HASH') {
191         return $self->_make_as($from);
192     } else {
193         return $self->_quote($from);
194     }
195 }
196
197 sub _recurse_from {
198     my ($self, $from, @join) = @_;
199     my @sqlf;
200     push(@sqlf, $self->_make_as($from));
201     foreach my $j (@join) {
202         push @sqlf, ', ' . $self->_quote($j) and next unless ref $j;
203         push @sqlf, ', ' . $$j and next if ref $j eq 'SCALAR';
204         my ($to, $on) = @$j;
205
206         # check whether a join type exists
207         my $join_clause = '';
208         my $to_jt = ref($to) eq 'ARRAY' ? $to->[0] : $to;
209         if (ref($to_jt) eq 'HASH' and exists($to_jt->{-join_type})) {
210             $join_clause = $self->_sqlcase(' '.($to_jt->{-join_type}).' JOIN ');
211         } else {
212             $join_clause = $self->_sqlcase(' JOIN ');
213         }
214         push(@sqlf, $join_clause);
215
216         if (ref $to eq 'ARRAY') {
217             push(@sqlf, '(', $self->_recurse_from(@$to), ')');
218         } else {
219             push(@sqlf, $self->_make_as($to));
220         }
221         push(@sqlf, $self->_sqlcase(' ON '), $self->_join_condition($on));
222     }
223     return join('', @sqlf);
224 }
225
226 sub _make_as {
227     my ($self, $from) = @_;
228     return $self->_quote($from) unless ref $from;
229     return $$from if ref $from eq 'SCALAR';
230     return join(' ', map { (ref $_ eq 'SCALAR' ? $$_ : $self->_quote($_)) }
231                          reverse each %{$self->_skip_options($from)});
232 }
233
234 sub _skip_options {
235     my ($self, $hash) = @_;
236     my $clean_hash = {};
237     $clean_hash->{$_} = $hash->{$_}
238         for grep {!/^-/} keys %$hash;
239     return $clean_hash;
240 }
241
242 sub _join_condition {
243     my ($self, $cond) = @_;
244     if (ref $cond eq 'HASH') {
245         my %j;
246         for (keys %$cond) {
247             my $x = '= '.$self->_quote($cond->{$_}); $j{$_} = \$x;
248         };
249         return $self->_recurse_where(\%j);
250     } elsif (ref $cond eq 'ARRAY') {
251         return join(' OR ', map { $self->_join_condition($_) } @$cond);
252     } else {
253         die "Can't handle this yet!";
254     }
255 }
256
257
258 sub _quote {
259     my $self  = shift;
260     my $label = shift;
261
262     return '' unless defined $label;
263
264     return $label
265       if $label eq '*';
266
267     return $$label if ref($label) eq 'SCALAR';
268
269     return $label unless $self->{quote_char};
270
271     if (ref $self->{quote_char} eq "ARRAY") {
272
273         return $self->{quote_char}->[0] . $label . $self->{quote_char}->[1]
274             if !defined $self->{name_sep};
275
276         my $sep = $self->{name_sep};
277         return join($self->{name_sep},
278             map { $_ eq '*'
279                     ? $_
280                     : $self->{quote_char}->[0] . $_ . $self->{quote_char}->[1] }
281               split( /\Q$sep\E/, $label ) );
282     }
283
284
285     return $self->{quote_char} . $label . $self->{quote_char}
286       if !defined $self->{name_sep};
287
288     return join $self->{name_sep},
289         map { $_ eq '*' ? $_ : $self->{quote_char} . $_ . $self->{quote_char} }
290         split /\Q$self->{name_sep}\E/, $label;
291 }
292
293 # Conversion, if applicable
294 sub _convert ($) {
295     my $self = shift;
296     return @_ unless $self->{convert};
297     my $conv = $self->_sqlcase($self->{convert});
298     my @ret = map { $conv.'('.$_.')' } @_;
299     return wantarray ? @ret : $ret[0];
300 }
301
302 # And bindtype
303 sub _bindtype (@) {
304     my $self = shift;
305     my($col,@val) = @_;
306     return $self->{bindtype} eq 'columns' ? [ @_ ] : @val;
307 }
308
309 # Modified -logic or -nest
310 sub _modlogic ($) {
311     my $self = shift;
312     my $sym = @_ ? lc(shift) : $self->{logic};
313     $sym =~ tr/_/ /;
314     $sym = $self->{logic} if $sym eq 'nest';
315     return $self->_sqlcase($sym);  # override join
316 }
317
318 =head2 new(option => 'value')
319
320 The C<new()> function takes a list of options and values, and returns
321 a new B<SQL::Abstract> object which can then be used to generate SQL
322 through the methods below. The options accepted are:
323
324 =over
325
326 =item case
327
328 If set to 'lower', then SQL will be generated in all lowercase. By
329 default SQL is generated in "textbook" case meaning something like:
330
331     SELECT a_field FROM a_table WHERE some_field LIKE '%someval%'
332
333 =item cmp
334
335 This determines what the default comparison operator is. By default
336 it is C<=>, meaning that a hash like this:
337
338     %where = (name => 'nwiger', email => 'nate@wiger.org');
339
340 Will generate SQL like this:
341
342     WHERE name = 'nwiger' AND email = 'nate@wiger.org'
343
344 However, you may want loose comparisons by default, so if you set
345 C<cmp> to C<like> you would get SQL such as:
346
347     WHERE name like 'nwiger' AND email like 'nate@wiger.org'
348
349 You can also override the comparsion on an individual basis - see
350 the huge section on L</"WHERE CLAUSES"> at the bottom.
351
352 =item logic
353
354 This determines the default logical operator for multiple WHERE
355 statements in arrays. By default it is "or", meaning that a WHERE
356 array of the form:
357
358     @where = (
359         event_date => {'>=', '2/13/99'}, 
360         event_date => {'<=', '4/24/03'}, 
361     );
362
363 Will generate SQL like this:
364
365     WHERE event_date >= '2/13/99' OR event_date <= '4/24/03'
366
367 This is probably not what you want given this query, though (look
368 at the dates). To change the "OR" to an "AND", simply specify:
369
370     my $sql = SQL::Abstract->new(logic => 'and');
371
372 Which will change the above C<WHERE> to:
373
374     WHERE event_date >= '2/13/99' AND event_date <= '4/24/03'
375
376 =item convert
377
378 This will automatically convert comparisons using the specified SQL
379 function for both column and value. This is mostly used with an argument
380 of C<upper> or C<lower>, so that the SQL will have the effect of
381 case-insensitive "searches". For example, this:
382
383     $sql = SQL::Abstract->new(convert => 'upper');
384     %where = (keywords => 'MaKe iT CAse inSeNSItive');
385
386 Will turn out the following SQL:
387
388     WHERE upper(keywords) like upper('MaKe iT CAse inSeNSItive')
389
390 The conversion can be C<upper()>, C<lower()>, or any other SQL function
391 that can be applied symmetrically to fields (actually B<SQL::Abstract> does
392 not validate this option; it will just pass through what you specify verbatim).
393
394 =item bindtype
395
396 This is a kludge because many databases suck. For example, you can't
397 just bind values using DBI's C<execute()> for Oracle C<CLOB> or C<BLOB> fields.
398 Instead, you have to use C<bind_param()>:
399
400     $sth->bind_param(1, 'reg data');
401     $sth->bind_param(2, $lots, {ora_type => ORA_CLOB});
402
403 The problem is, B<SQL::Abstract> will normally just return a C<@bind> array,
404 which loses track of which field each slot refers to. Fear not.
405
406 If you specify C<bindtype> in new, you can determine how C<@bind> is returned.
407 Currently, you can specify either C<normal> (default) or C<columns>. If you
408 specify C<columns>, you will get an array that looks like this:
409
410     my $sql = SQL::Abstract->new(bindtype => 'columns');
411     my($stmt, @bind) = $sql->insert(...);
412
413     @bind = (
414         [ 'column1', 'value1' ],
415         [ 'column2', 'value2' ],
416         [ 'column3', 'value3' ],
417     );
418
419 You can then iterate through this manually, using DBI's C<bind_param()>.
420     
421     $sth->prepare($stmt);
422     my $i = 1;
423     for (@bind) {
424         my($col, $data) = @$_;
425         if ($col eq 'details' || $col eq 'comments') {
426             $sth->bind_param($i, $data, {ora_type => ORA_CLOB});
427         } elsif ($col eq 'image') {
428             $sth->bind_param($i, $data, {ora_type => ORA_BLOB});
429         } else {
430             $sth->bind_param($i, $data);
431         }
432         $i++;
433     }
434     $sth->execute;      # execute without @bind now
435
436 Now, why would you still use B<SQL::Abstract> if you have to do this crap?
437 Basically, the advantage is still that you don't have to care which fields
438 are or are not included. You could wrap that above C<for> loop in a simple
439 sub called C<bind_fields()> or something and reuse it repeatedly. You still
440 get a layer of abstraction over manual SQL specification.
441
442 =item quote_char
443
444 This is the character that a table or column name will be quoted
445 with.  By default this is an empty string, but you could set it to 
446 the character C<`>, to generate SQL like this:
447
448   SELECT `a_field` FROM `a_table` WHERE `some_field` LIKE '%someval%'
449
450 This is useful if you have tables or columns that are reserved words
451 in your database's SQL dialect.
452
453 =item name_sep
454
455 This is the character that separates a table and column name.  It is
456 necessary to specify this when the C<quote_char> option is selected,
457 so that tables and column names can be individually quoted like this:
458
459   SELECT `table`.`one_field` FROM `table` WHERE `table`.`other_field` = 1
460
461 =back
462
463 =cut
464
465 sub new {
466     my $self = shift;
467     my $class = ref($self) || $self;
468     my %opt = (ref $_[0] eq 'HASH') ? %{$_[0]} : @_;
469
470     # choose our case by keeping an option around
471     delete $opt{case} if $opt{case} && $opt{case} ne 'lower';
472
473     # override logical operator
474     $opt{logic} = uc $opt{logic} if $opt{logic};
475
476     # how to return bind vars
477     $opt{bindtype} ||= delete($opt{bind_type}) || 'normal';
478
479     # default comparison is "=", but can be overridden
480     $opt{cmp} ||= '=';
481
482     # default quotation character around tables/columns
483     $opt{quote_char} ||= '';
484
485     return bless \%opt, $class;
486 }
487
488 =head2 insert($table, \@values || \%fieldvals)
489
490 This is the simplest function. You simply give it a table name
491 and either an arrayref of values or hashref of field/value pairs.
492 It returns an SQL INSERT statement and a list of bind values.
493
494 =cut
495
496 sub insert {
497     my $self  = shift;
498     my $table = $self->_table(shift);
499     my $data  = shift || return;
500
501     my $sql   = $self->_sqlcase('insert into') . " $table ";
502     my(@sqlf, @sqlv, @sqlq) = ();
503
504     my $ref = ref $data;
505     if ($ref eq 'HASH') {
506         for my $k (sort keys %$data) {
507             my $v = $data->{$k};
508             my $r = ref $v;
509             # named fields, so must save names in order
510             push @sqlf, $self->_quote($k);
511             if ($r eq 'ARRAY') {
512                 # SQL included for values
513                 my @val = @$v;
514                 push @sqlq, shift @val;
515                 push @sqlv, $self->_bindtype($k, @val);
516             } elsif ($r eq 'SCALAR') {
517                 # embedded literal SQL
518                 push @sqlq, $$v;
519             } else { 
520                 push @sqlq, '?';
521                 push @sqlv, $self->_bindtype($k, $v);
522             }
523         }
524         $sql .= '(' . join(', ', @sqlf) .') '. $self->_sqlcase('values') . ' ('. join(', ', @sqlq) .')';
525     } elsif ($ref eq 'ARRAY') {
526         # just generate values(?,?) part
527         # no names (arrayref) so can't generate bindtype
528         carp "Warning: ",__PACKAGE__,"->insert called with arrayref when bindtype set"
529             if $self->{bindtype} ne 'normal';
530         for my $v (@$data) {
531             my $r = ref $v;
532             if ($r eq 'ARRAY') {
533                 my @val = @$v;
534                 push @sqlq, shift @val;
535                 push @sqlv, @val;
536             } elsif ($r eq 'SCALAR') {
537                 # embedded literal SQL
538                 push @sqlq, $$v;
539             } else { 
540                 push @sqlq, '?';
541                 push @sqlv, $v;
542             }
543         }
544         $sql .= $self->_sqlcase('values') . ' ('. join(', ', @sqlq) .')';
545     } elsif ($ref eq 'SCALAR') {
546         # literal SQL
547         $sql .= $$data;
548     } else {
549         puke "Unsupported data type specified to \$sql->insert";
550     }
551
552     return wantarray ? ($sql, @sqlv) : $sql;
553 }
554
555 =head2 update($table, \%fieldvals, \%where)
556
557 This takes a table, hashref of field/value pairs, and an optional
558 hashref WHERE clause. It returns an SQL UPDATE function and a list
559 of bind values.
560
561 =cut
562
563 sub update {
564     my $self  = shift;
565     my $table = $self->_table(shift);
566     my $data  = shift || return;
567     my $where = shift;
568
569     my $sql   = $self->_sqlcase('update') . " $table " . $self->_sqlcase('set ');
570     my(@sqlf, @sqlv) = ();
571
572     puke "Unsupported data type specified to \$sql->update"
573         unless ref $data eq 'HASH';
574
575     for my $k (sort keys %$data) {
576         my $v = $data->{$k};
577         my $r = ref $v;
578         my $label = $self->_quote($k);
579         if ($r eq 'ARRAY') {
580             # SQL included for values
581             my @bind = @$v;
582             my $sql = shift @bind;
583             push @sqlf, "$label = $sql";
584             push @sqlv, $self->_bindtype($k, @bind);
585         } elsif ($r eq 'SCALAR') {
586             # embedded literal SQL
587             push @sqlf, "$label = $$v";
588         } else { 
589             push @sqlf, "$label = ?";
590             push @sqlv, $self->_bindtype($k, $v);
591         }
592     }
593
594     $sql .= join ', ', @sqlf;
595
596     if ($where) {
597         my($wsql, @wval) = $self->where($where);
598         $sql .= $wsql;
599         push @sqlv, @wval;
600     }
601
602     return wantarray ? ($sql, @sqlv) : $sql;
603 }
604
605 =head2 select($table, \@fields, \%where, \@order)
606
607 This takes a table, arrayref of fields (or '*'), optional hashref
608 WHERE clause, and optional arrayref order by, and returns the
609 corresponding SQL SELECT statement and list of bind values.
610
611 =cut
612
613 sub select {
614     my $self   = shift;
615     my $table  = $self->_table(shift);
616     my $fields = shift || '*';
617     my $where  = shift;
618     my $order  = shift;
619
620     my $f = (ref $fields eq 'ARRAY') ? join ', ', map { $self->_quote($_) } @$fields : $fields;
621     my $sql = join ' ', $self->_sqlcase('select'), $f, $self->_sqlcase('from'), $table;
622
623     my(@sqlf, @sqlv) = ();
624     my($wsql, @wval) = $self->where($where, $order);
625     $sql .= $wsql;
626     push @sqlv, @wval;
627
628     return wantarray ? ($sql, @sqlv) : $sql; 
629 }
630
631 =head2 delete($table, \%where)
632
633 This takes a table name and optional hashref WHERE clause.
634 It returns an SQL DELETE statement and list of bind values.
635
636 =cut
637
638 sub delete {
639     my $self  = shift;
640     my $table = $self->_table(shift);
641     my $where = shift;
642
643     my $sql = $self->_sqlcase('delete from') . " $table";
644     my(@sqlf, @sqlv) = ();
645
646     if ($where) {
647         my($wsql, @wval) = $self->where($where);
648         $sql .= $wsql;
649         push @sqlv, @wval;
650     }
651
652     return wantarray ? ($sql, @sqlv) : $sql; 
653 }
654
655 =head2 where(\%where, \@order)
656
657 This is used to generate just the WHERE clause. For example,
658 if you have an arbitrary data structure and know what the
659 rest of your SQL is going to look like, but want an easy way
660 to produce a WHERE clause, use this. It returns an SQL WHERE
661 clause and list of bind values.
662
663 =cut
664
665 # Finally, a separate routine just to handle WHERE clauses
666 sub where {
667     my $self  = shift;
668     my $where = shift;
669     my $order = shift;
670
671     # Need a separate routine to properly wrap w/ "where"
672     my $sql = '';
673     my @ret = $self->_recurse_where($where);
674     if (@ret) {
675         my $wh = shift @ret;
676         $sql .= $self->_sqlcase(' where ') . $wh if $wh;
677     }
678
679     # order by?
680     if ($order) {
681         $sql .= $self->_order_by($order);
682     }
683
684     return wantarray ? ($sql, @ret) : $sql; 
685 }
686
687
688 sub _recurse_where {
689     local $^W = 0;  # really, you've gotta be fucking kidding me
690     my $self  = shift;
691     my $where = _anoncopy(shift);   # prevent destroying original
692     my $ref   = ref $where || '';
693     my $join  = shift || $self->{logic} ||
694                     ($ref eq 'ARRAY' ? $self->_sqlcase('or') : $self->_sqlcase('and'));
695
696     # For assembling SQL fields and values
697     my(@sqlf, @sqlv) = ();
698
699     # If an arrayref, then we join each element
700     if ($ref eq 'ARRAY') {
701         # need to use while() so can shift() for arrays
702         my $subjoin;
703         while (my $el = shift @$where) {
704
705             # skip empty elements, otherwise get invalid trailing AND stuff
706             if (my $ref2 = ref $el) {
707                 if ($ref2 eq 'ARRAY') {
708                     next unless @$el;
709                 } elsif ($ref2 eq 'HASH') {
710                     next unless %$el;
711                     $subjoin ||= $self->_sqlcase('and');
712                 } elsif ($ref2 eq 'SCALAR') {
713                     # literal SQL
714                     push @sqlf, $$el;
715                     next;
716                 }
717                 $self->_debug("$ref2(*top) means join with $subjoin");
718             } else {
719                 # top-level arrayref with scalars, recurse in pairs
720                 $self->_debug("NOREF(*top) means join with $subjoin");
721                 $el = {$el => shift(@$where)};
722             }
723             my @ret = $self->_recurse_where($el, $subjoin);
724             push @sqlf, shift @ret;
725             push @sqlv, @ret;
726         }
727     }
728     elsif ($ref eq 'HASH') {
729         # Note: during recursion, the last element will always be a hashref,
730         # since it needs to point a column => value. So this be the end.
731         for my $k (sort keys %$where) {
732             my $v = $where->{$k};
733             my $label = $self->_quote($k);
734
735             if ($k =~ /^-(\D+)/) {
736                 # special nesting, like -and, -or, -nest, so shift over
737                 my $subjoin = $self->_modlogic($1);
738                 $self->_debug("OP(-$1) means special logic ($subjoin), recursing...");
739                 my @ret = $self->_recurse_where($v, $subjoin);
740                 push @sqlf, shift @ret;
741                 push @sqlv, @ret;
742             } elsif (! defined($v)) {
743                 # undef = null
744                 $self->_debug("UNDEF($k) means IS NULL");
745                 push @sqlf, $label . $self->_sqlcase(' is null');
746             } elsif (ref $v eq 'ARRAY') {
747                 my @v = @$v;
748                 
749                 # multiple elements: multiple options
750                 $self->_debug("ARRAY($k) means multiple elements: [ @v ]");
751
752                 # special nesting, like -and, -or, -nest, so shift over
753                 my $subjoin = $self->_sqlcase('or');
754                 if ($v[0] =~ /^-(\D+)/) {
755                     $subjoin = $self->_modlogic($1);    # override subjoin
756                     $self->_debug("OP(-$1) means special logic ($subjoin), shifting...");
757                     shift @v;
758                 }
759
760                 # map into an array of hashrefs and recurse
761                 my @ret = $self->_recurse_where([map { {$k => $_} } @v], $subjoin);
762
763                 # push results into our structure
764                 push @sqlf, shift @ret;
765                 push @sqlv, @ret;
766             } elsif (ref $v eq 'HASH') {
767                 # modified operator { '!=', 'completed' }
768                 for my $f (sort keys %$v) {
769                     my $x = $v->{$f};
770
771                     # do the right thing for single -in values
772                     $x = [$x] if ($f =~ /^-?\s*(not[\s_]+)?in\s*$/i  &&  ref $x ne 'ARRAY');
773
774                     $self->_debug("HASH($k) means modified operator: { $f }");
775
776                     # check for the operator being "IN" or "BETWEEN" or whatever
777                     if (ref $x eq 'ARRAY') {
778                           if ($f =~ /^-?\s*(not[\s_]+)?(in|between)\s*$/i) {
779                               my $u = $self->_modlogic($1 . $2);
780                               $self->_debug("HASH($f => $x) uses special operator: [ $u ]");
781                               if ($u =~ /between/i) {
782                                   # SQL sucks
783                                   # Throw an exception if you try to use between with
784                                   # anything other than 2 values
785                                   $self->puke("You need two values to use between") unless @$x == 2;
786                                   push @sqlf, join ' ', $self->_convert($label), $u, $self->_convert('?'),
787                                                         $self->_sqlcase('and'), $self->_convert('?');
788                               } elsif (@$x) {
789                                   # DWIM for empty arrayrefs
790                                   push @sqlf, join ' ', $self->_convert($label), $u, '(',
791                                                   join(', ', map { $self->_convert('?') } @$x),
792                                               ')';
793                               } elsif(@$x == 0){
794                                   # Empty IN defaults to 0=1 and empty NOT IN to 1=1
795                                   push(@sqlf, ($u =~ /not/i ? "1=1" : "0=1"));
796                               }
797                               push @sqlv, $self->_bindtype($k, @$x);
798                           } else {
799                               # multiple elements: multiple options
800                               $self->_debug("ARRAY($x) means multiple elements: [ @$x ]");
801                               
802                               # map into an array of hashrefs and recurse
803                               my @ret = $self->_recurse_where([map { {$k => {$f, $_}} } @$x]);
804                               
805                               # push results into our structure
806                               push @sqlf, shift @ret;
807                               push @sqlv, @ret;
808                           }
809                     } elsif (! defined($x)) {
810                         # undef = NOT null
811                         my $not = ($f eq '!=' || $f eq 'not like') ? ' not' : '';
812                         push @sqlf, $label . $self->_sqlcase(" is$not null");
813                     } else {
814                         # regular ol' value
815                         $f =~ s/^-//;   # strip leading -like =>
816                         $f =~ s/_/ /;   # _ => " "
817                         push @sqlf, join ' ', $self->_convert($label), $self->_sqlcase($f), $self->_convert('?');
818                         push @sqlv, $self->_bindtype($k, $x);
819                     }
820                 }
821             } elsif (ref $v eq 'SCALAR') {
822                 # literal SQL
823                 $self->_debug("SCALAR($k) means literal SQL: $$v");
824                 push @sqlf, "$label $$v";
825             } else {
826                 # standard key => val
827                 $self->_debug("NOREF($k) means simple key=val: $k $self->{cmp} $v");
828                 push @sqlf, join ' ', $self->_convert($label), $self->_sqlcase($self->{cmp}), $self->_convert('?');
829                 push @sqlv, $self->_bindtype($k, $v);
830             }
831         }
832     }
833     elsif ($ref eq 'SCALAR') {
834         # literal sql
835         $self->_debug("SCALAR(*top) means literal SQL: $$where");
836         push @sqlf, $$where;
837     }
838     elsif (defined $where) {
839         # literal sql
840         $self->_debug("NOREF(*top) means literal SQL: $where");
841         push @sqlf, $where;
842     }
843
844     # assemble and return sql
845     my $wsql = @sqlf ? '( ' . join(" $join ", @sqlf) . ' )' : '';
846     return wantarray ? ($wsql, @sqlv) : $wsql; 
847 }
848
849 sub _order_by {
850     my $self = shift;
851     my $ref = ref $_[0];
852
853     my @vals = $ref eq 'ARRAY'  ? @{$_[0]} :
854                $ref eq 'SCALAR' ? $_[0]    :
855                $ref eq ''       ? $_[0]    :
856                puke "Unsupported data struct $ref for ORDER BY";
857
858     my $val = join ', ', map { $self->_quote($_) } @vals;
859     return $val ? $self->_sqlcase(' order by')." $val" : '';
860 }
861
862 =head2 values(\%data)
863
864 This just returns the values from the hash C<%data>, in the same
865 order that would be returned from any of the other above queries.
866 Using this allows you to markedly speed up your queries if you
867 are affecting lots of rows. See below under the L</"PERFORMANCE"> section.
868
869 =cut
870
871 sub values {
872     my $self = shift;
873     my $data = shift || return;
874     puke "Argument to ", __PACKAGE__, "->values must be a \\%hash"
875         unless ref $data eq 'HASH';
876     return map { $self->_bindtype($_, $data->{$_}) } sort keys %$data;
877 }
878
879 =head2 generate($any, 'number', $of, \@data, $struct, \%types)
880
881 Warning: This is an experimental method and subject to change.
882
883 This returns arbitrarily generated SQL. It's a really basic shortcut.
884 It will return two different things, depending on return context:
885
886     my($stmt, @bind) = $sql->generate('create table', \$table, \@fields);
887     my $stmt_and_val = $sql->generate('create table', \$table, \@fields);
888
889 These would return the following:
890
891     # First calling form
892     $stmt = "CREATE TABLE test (?, ?)";
893     @bind = (field1, field2);
894
895     # Second calling form
896     $stmt_and_val = "CREATE TABLE test (field1, field2)";
897
898 Depending on what you're trying to do, it's up to you to choose the correct
899 format. In this example, the second form is what you would want.
900
901 By the same token:
902
903     $sql->generate('alter session', { nls_date_format => 'MM/YY' });
904
905 Might give you:
906
907     ALTER SESSION SET nls_date_format = 'MM/YY'
908
909 You get the idea. Strings get their case twiddled, but everything
910 else remains verbatim.
911
912 =cut
913
914 sub generate {
915     my $self  = shift;
916
917     my(@sql, @sqlq, @sqlv);
918
919     for (@_) {
920         my $ref = ref $_;
921         if ($ref eq 'HASH') {
922             for my $k (sort keys %$_) {
923                 my $v = $_->{$k};
924                 my $r = ref $v;
925                 my $label = $self->_quote($k);
926                 if ($r eq 'ARRAY') {
927                     # SQL included for values
928                     my @bind = @$v;
929                     my $sql = shift @bind;
930                     push @sqlq, "$label = $sql";
931                     push @sqlv, $self->_bindtype($k, @bind);
932                 } elsif ($r eq 'SCALAR') {
933                     # embedded literal SQL
934                     push @sqlq, "$label = $$v";
935                 } else { 
936                     push @sqlq, "$label = ?";
937                     push @sqlv, $self->_bindtype($k, $v);
938                 }
939             }
940             push @sql, $self->_sqlcase('set'), join ', ', @sqlq;
941         } elsif ($ref eq 'ARRAY') {
942             # unlike insert(), assume these are ONLY the column names, i.e. for SQL
943             for my $v (@$_) {
944                 my $r = ref $v;
945                 if ($r eq 'ARRAY') {
946                     my @val = @$v;
947                     push @sqlq, shift @val;
948                     push @sqlv, @val;
949                 } elsif ($r eq 'SCALAR') {
950                     # embedded literal SQL
951                     push @sqlq, $$v;
952                 } else { 
953                     push @sqlq, '?';
954                     push @sqlv, $v;
955                 }
956             }
957             push @sql, '(' . join(', ', @sqlq) . ')';
958         } elsif ($ref eq 'SCALAR') {
959             # literal SQL
960             push @sql, $$_;
961         } else {
962             # strings get case twiddled
963             push @sql, $self->_sqlcase($_);
964         }
965     }
966
967     my $sql = join ' ', @sql;
968
969     # this is pretty tricky
970     # if ask for an array, return ($stmt, @bind)
971     # otherwise, s/?/shift @sqlv/ to put it inline
972     if (wantarray) {
973         return ($sql, @sqlv);
974     } else {
975         1 while $sql =~ s/\?/my $d = shift(@sqlv);
976                              ref $d ? $d->[1] : $d/e;
977         return $sql;
978     }
979 }
980
981 sub DESTROY { 1 }
982 sub AUTOLOAD {
983     # This allows us to check for a local, then _form, attr
984     my $self = shift;
985     my($name) = $AUTOLOAD =~ /.*::(.+)/;
986     return $self->generate($name, @_);
987 }
988
989 1;
990
991 __END__
992
993 =head1 WHERE CLAUSES
994
995 This module uses a variation on the idea from L<DBIx::Abstract>. It
996 is B<NOT>, repeat I<not> 100% compatible. B<The main logic of this
997 module is that things in arrays are OR'ed, and things in hashes
998 are AND'ed.>
999
1000 The easiest way to explain is to show lots of examples. After
1001 each C<%where> hash shown, it is assumed you used:
1002
1003     my($stmt, @bind) = $sql->where(\%where);
1004
1005 However, note that the C<%where> hash can be used directly in any
1006 of the other functions as well, as described above.
1007
1008 So, let's get started. To begin, a simple hash:
1009
1010     my %where  = (
1011         user   => 'nwiger',
1012         status => 'completed'
1013     );
1014
1015 Is converted to SQL C<key = val> statements:
1016
1017     $stmt = "WHERE user = ? AND status = ?";
1018     @bind = ('nwiger', 'completed');
1019
1020 One common thing I end up doing is having a list of values that
1021 a field can be in. To do this, simply specify a list inside of
1022 an arrayref:
1023
1024     my %where  = (
1025         user   => 'nwiger',
1026         status => ['assigned', 'in-progress', 'pending'];
1027     );
1028
1029 This simple code will create the following:
1030     
1031     $stmt = "WHERE user = ? AND ( status = ? OR status = ? OR status = ? )";
1032     @bind = ('nwiger', 'assigned', 'in-progress', 'pending');
1033
1034 If you want to specify a different type of operator for your comparison,
1035 you can use a hashref for a given column:
1036
1037     my %where  = (
1038         user   => 'nwiger',
1039         status => { '!=', 'completed' }
1040     );
1041
1042 Which would generate:
1043
1044     $stmt = "WHERE user = ? AND status != ?";
1045     @bind = ('nwiger', 'completed');
1046
1047 To test against multiple values, just enclose the values in an arrayref:
1048
1049     status => { '!=', ['assigned', 'in-progress', 'pending'] };
1050
1051 Which would give you:
1052
1053     "WHERE status != ? OR status != ? OR status != ?"
1054
1055 But, this is probably not what you want in this case (look at it). So
1056 the hashref can also contain multiple pairs, in which case it is expanded
1057 into an C<AND> of its elements:
1058
1059     my %where  = (
1060         user   => 'nwiger',
1061         status => { '!=', 'completed', -not_like => 'pending%' }
1062     );
1063
1064     # Or more dynamically, like from a form
1065     $where{user} = 'nwiger';
1066     $where{status}{'!='} = 'completed';
1067     $where{status}{'-not_like'} = 'pending%';
1068
1069     # Both generate this
1070     $stmt = "WHERE user = ? AND status != ? AND status NOT LIKE ?";
1071     @bind = ('nwiger', 'completed', 'pending%');
1072
1073 To get an OR instead, you can combine it with the arrayref idea:
1074
1075     my %where => (
1076          user => 'nwiger',
1077          priority => [ {'=', 2}, {'!=', 1} ]
1078     );
1079
1080 Which would generate:
1081
1082     $stmt = "WHERE user = ? AND priority = ? OR priority != ?";
1083     @bind = ('nwiger', '2', '1');
1084
1085 However, there is a subtle trap if you want to say something like
1086 this (notice the C<AND>):
1087
1088     WHERE priority != ? AND priority != ?
1089
1090 Because, in Perl you I<can't> do this:
1091
1092     priority => { '!=', 2, '!=', 1 }
1093
1094 As the second C<!=> key will obliterate the first. The solution
1095 is to use the special C<-modifier> form inside an arrayref:
1096
1097     priority => [ -and => {'!=', 2}, {'!=', 1} ]
1098
1099 Normally, these would be joined by C<OR>, but the modifier tells it
1100 to use C<AND> instead. (Hint: You can use this in conjunction with the
1101 C<logic> option to C<new()> in order to change the way your queries
1102 work by default.) B<Important:> Note that the C<-modifier> goes
1103 B<INSIDE> the arrayref, as an extra first element. This will
1104 B<NOT> do what you think it might:
1105
1106     priority => -and => [{'!=', 2}, {'!=', 1}]   # WRONG!
1107
1108 Here is a quick list of equivalencies, since there is some overlap:
1109
1110     # Same
1111     status => {'!=', 'completed', 'not like', 'pending%' }
1112     status => [ -and => {'!=', 'completed'}, {'not like', 'pending%'}]
1113
1114     # Same
1115     status => {'=', ['assigned', 'in-progress']}
1116     status => [ -or => {'=', 'assigned'}, {'=', 'in-progress'}]
1117     status => [ {'=', 'assigned'}, {'=', 'in-progress'} ]
1118
1119 In addition to C<-and> and C<-or>, there is also a special C<-nest>
1120 operator which adds an additional set of parens, to create a subquery.
1121 For example, to get something like this:
1122
1123     $stmt = WHERE user = ? AND ( workhrs > ? OR geo = ? )
1124     @bind = ('nwiger', '20', 'ASIA');
1125
1126 You would do:
1127
1128     my %where = (
1129          user => 'nwiger',
1130         -nest => [ workhrs => {'>', 20}, geo => 'ASIA' ],
1131     );
1132
1133 You can also use the hashref format to compare a list of fields using the
1134 C<IN> comparison operator, by specifying the list as an arrayref:
1135
1136     my %where  = (
1137         status   => 'completed',
1138         reportid => { -in => [567, 2335, 2] }
1139     );
1140
1141 Which would generate:
1142
1143     $stmt = "WHERE status = ? AND reportid IN (?,?,?)";
1144     @bind = ('completed', '567', '2335', '2');
1145
1146 You can use this same format to use other grouping functions, such
1147 as C<BETWEEN>, C<SOME>, and so forth. For example:
1148
1149     my %where  = (
1150         user   => 'nwiger',
1151         completion_date => {
1152            -not_between => ['2002-10-01', '2003-02-06']
1153         }
1154     );
1155
1156 Would give you:
1157
1158     WHERE user = ? AND completion_date NOT BETWEEN ( ? AND ? )
1159
1160 So far, we've seen how multiple conditions are joined with a top-level
1161 C<AND>.  We can change this by putting the different conditions we want in
1162 hashes and then putting those hashes in an array. For example:
1163
1164     my @where = (
1165         {
1166             user   => 'nwiger',
1167             status => { -like => ['pending%', 'dispatched'] },
1168         },
1169         {
1170             user   => 'robot',
1171             status => 'unassigned',
1172         }
1173     );
1174
1175 This data structure would create the following:
1176
1177     $stmt = "WHERE ( user = ? AND ( status LIKE ? OR status LIKE ? ) )
1178                 OR ( user = ? AND status = ? ) )";
1179     @bind = ('nwiger', 'pending', 'dispatched', 'robot', 'unassigned');
1180
1181 This can be combined with the C<-nest> operator to properly group
1182 SQL statements:
1183
1184     my @where = (
1185          -and => [
1186             user => 'nwiger',
1187             -nest => [
1188                 -and => [workhrs => {'>', 20}, geo => 'ASIA' ],
1189                 -and => [workhrs => {'<', 50}, geo => 'EURO' ]
1190             ],
1191         ],
1192     );
1193
1194 That would yield:
1195
1196     WHERE ( user = ? AND 
1197           ( ( workhrs > ? AND geo = ? )
1198          OR ( workhrs < ? AND geo = ? ) ) )
1199
1200 Finally, sometimes only literal SQL will do. If you want to include
1201 literal SQL verbatim, you can specify it as a scalar reference, namely:
1202
1203     my $inn = 'is Not Null';
1204     my %where = (
1205         priority => { '<', 2 },
1206         requestor => \$inn
1207     );
1208
1209 This would create:
1210
1211     $stmt = "WHERE priority < ? AND requestor is Not Null";
1212     @bind = ('2');
1213
1214 Note that in this example, you only get one bind parameter back, since
1215 the verbatim SQL is passed as part of the statement.
1216
1217 Of course, just to prove a point, the above can also be accomplished
1218 with this:
1219
1220     my %where = (
1221         priority  => { '<', 2 },
1222         requestor => { '!=', undef },
1223     );
1224
1225 TMTOWTDI.
1226
1227 These pages could go on for a while, since the nesting of the data
1228 structures this module can handle are pretty much unlimited (the
1229 module implements the C<WHERE> expansion as a recursive function
1230 internally). Your best bet is to "play around" with the module a
1231 little to see how the data structures behave, and choose the best
1232 format for your data based on that.
1233
1234 And of course, all the values above will probably be replaced with
1235 variables gotten from forms or the command line. After all, if you
1236 knew everything ahead of time, you wouldn't have to worry about
1237 dynamically-generating SQL and could just hardwire it into your
1238 script.
1239
1240 =head1 PERFORMANCE
1241
1242 Thanks to some benchmarking by Mark Stosberg, it turns out that
1243 this module is many orders of magnitude faster than using C<DBIx::Abstract>.
1244 I must admit this wasn't an intentional design issue, but it's a
1245 byproduct of the fact that you get to control your C<DBI> handles
1246 yourself.
1247
1248 To maximize performance, use a code snippet like the following:
1249
1250     # prepare a statement handle using the first row
1251     # and then reuse it for the rest of the rows
1252     my($sth, $stmt);
1253     for my $href (@array_of_hashrefs) {
1254         $stmt ||= $sql->insert('table', $href);
1255         $sth  ||= $dbh->prepare($stmt);
1256         $sth->execute($sql->values($href));
1257     }
1258
1259 The reason this works is because the keys in your C<$href> are sorted
1260 internally by B<SQL::Abstract>. Thus, as long as your data retains
1261 the same structure, you only have to generate the SQL the first time
1262 around. On subsequent queries, simply use the C<values> function provided
1263 by this module to return your values in the correct order.
1264
1265 =head1 FORMBUILDER
1266
1267 If you use my C<CGI::FormBuilder> module at all, you'll hopefully
1268 really like this part (I do, at least). Building up a complex query
1269 can be as simple as the following:
1270
1271     #!/usr/bin/perl
1272
1273     use CGI::FormBuilder;
1274     use SQL::Abstract;
1275
1276     my $form = CGI::FormBuilder->new(...);
1277     my $sql  = SQL::Abstract->new;
1278
1279     if ($form->submitted) {
1280         my $field = $form->field;
1281         my $id = delete $field->{id};
1282         my($stmt, @bind) = $sql->update('table', $field, {id => $id});
1283     }
1284
1285 Of course, you would still have to connect using C<DBI> to run the
1286 query, but the point is that if you make your form look like your
1287 table, the actual query script can be extremely simplistic.
1288
1289 If you're B<REALLY> lazy (I am), check out C<HTML::QuickTable> for
1290 a fast interface to returning and formatting data. I frequently 
1291 use these three modules together to write complex database query
1292 apps in under 50 lines.
1293
1294 =head1 NOTES
1295
1296 There is not (yet) any explicit support for SQL compound logic
1297 statements like "AND NOT". Instead, just do the de Morgan's
1298 law transformations yourself. For example, this:
1299
1300   "lname LIKE '%son%' AND NOT ( age < 10 OR age > 20 )"
1301
1302 Becomes:
1303
1304   "lname LIKE '%son%' AND ( age >= 10 AND age <= 20 )"
1305
1306 With the corresponding C<%where> hash:
1307
1308     %where = (
1309         lname => {like => '%son%'},
1310         age   => [-and => {'>=', 10}, {'<=', 20}],
1311     );
1312
1313 Again, remember that the C<-and> goes I<inside> the arrayref.
1314
1315 =head1 ACKNOWLEDGEMENTS
1316
1317 There are a number of individuals that have really helped out with
1318 this module. Unfortunately, most of them submitted bugs via CPAN
1319 so I have no idea who they are! But the people I do know are:
1320
1321     Matt Trout (DBIx::Class support)
1322     Mark Stosberg (benchmarking)
1323     Chas Owens (initial "IN" operator support)
1324     Philip Collins (per-field SQL functions)
1325     Eric Kolve (hashref "AND" support)
1326     Mike Fragassi (enhancements to "BETWEEN" and "LIKE")
1327     Dan Kubb (support for "quote_char" and "name_sep")
1328     Guillermo Roditi (patch to cleanup "IN" and "BETWEEN")
1329
1330 Thanks!
1331
1332 =head1 SEE ALSO
1333
1334 L<DBIx::Class>, L<DBIx::Abstract>, L<CGI::FormBuilder>, L<HTML::QuickTable>
1335
1336 =head1 AUTHOR
1337
1338 Copyright (c) 2001-2007 Nathan Wiger <nwiger@cpan.org>. All Rights Reserved.
1339
1340 This module is actively maintained by Matt Trout <mst@shadowcatsystems.co.uk>
1341
1342 For support, your best bet is to try the C<DBIx::Class> users mailing list.
1343 While not an official support venue, C<DBIx::Class> makes heavy use of
1344 C<SQL::Abstract>, and as such list members there are very familiar with
1345 how to create queries.
1346
1347 This module is free software; you may copy this under the terms of
1348 the GNU General Public License, or the Artistic License, copies of
1349 which should have accompanied your Perl kit.
1350
1351 =cut
1352