[Bast-commits] r8528 - in SQL-Abstract/1.x/branches/test_refactor: . lib/SQL lib/SQL/Abstract t

ribasushi at dev.catalyst.perl.org ribasushi at dev.catalyst.perl.org
Thu Feb 4 10:33:41 GMT 2010


Author: ribasushi
Date: 2010-02-04 10:33:40 +0000 (Thu, 04 Feb 2010)
New Revision: 8528

Added:
   SQL-Abstract/1.x/branches/test_refactor/t/05in_between.t
Removed:
   SQL-Abstract/1.x/branches/test_refactor/t/05between.t
Modified:
   SQL-Abstract/1.x/branches/test_refactor/
   SQL-Abstract/1.x/branches/test_refactor/Changes
   SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract.pm
   SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract/Test.pm
   SQL-Abstract/1.x/branches/test_refactor/t/01generate.t
   SQL-Abstract/1.x/branches/test_refactor/t/10test.t
Log:
 r7727 at Thesaurus (orig r7716):  ribasushi | 2009-09-22 09:18:02 +0200
 Omnipotent 'between'
 r7728 at Thesaurus (orig r7717):  ribasushi | 2009-09-22 09:55:36 +0200
 IN testing support
 r7729 at Thesaurus (orig r7718):  ribasushi | 2009-09-22 10:10:34 +0200
 Allow scalarref in IN and open up non-grouping parenthesis around IN arguments (saves sqlite from brain damage)
 r7730 at Thesaurus (orig r7719):  ribasushi | 2009-09-22 10:35:26 +0200
 Documentation and changes
 r7731 at Thesaurus (orig r7720):  ribasushi | 2009-09-22 10:42:00 +0200
 Release 1.59
 r7733 at Thesaurus (orig r7722):  ribasushi | 2009-09-22 13:00:11 +0200
 fix a dumb dumb regex error, /me -- 
 r7734 at Thesaurus (orig r7723):  ribasushi | 2009-09-22 13:03:37 +0200
 Release 1.60
 r8476 at Thesaurus (orig r8463):  ribasushi | 2010-01-28 12:14:12 +0100
 optional functionality for INSERT
 implementation of INSERT ... RETURNING 



Property changes on: SQL-Abstract/1.x/branches/test_refactor
___________________________________________________________________
Name: svk:merge
   - b9bda2dc-4395-4011-945f-8c81d782bde1:/branches/matthewt:18
b9bda2dc-4395-4011-945f-8c81d782bde1:/trunk:23
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/branches/and_or:6008
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/branches/bool_operator:7524
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/branches/special_op_handling:6158
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/trunk:7661
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/trunk/SQL-Abstract:3093
   + b9bda2dc-4395-4011-945f-8c81d782bde1:/branches/matthewt:18
b9bda2dc-4395-4011-945f-8c81d782bde1:/trunk:23
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/branches/and_or:6008
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/branches/bool_operator:7524
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/branches/special_op_handling:6158
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/SQL-Abstract/1.x/trunk:8463
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/trunk/SQL-Abstract:3093

Modified: SQL-Abstract/1.x/branches/test_refactor/Changes
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/Changes	2010-02-04 10:28:33 UTC (rev 8527)
+++ SQL-Abstract/1.x/branches/test_refactor/Changes	2010-02-04 10:33:40 UTC (rev 8528)
@@ -1,7 +1,17 @@
 Revision history for SQL::Abstract
 
-    - Fixed a couple of untrapped undefined warnings
+revision 1.60  2009-09-22 11:03 (UTC)
+----------------------------
+    - fix a well masked error in the sql-test tokenizer
 
+revision 1.59  2009-09-22 08:39 (UTC)
+----------------------------
+    - fixed a couple of untrapped undefined warnings
+    - allow -in/-between to accept literal sql in all logical
+      variants - see POD for details
+    - unroll multiple parenthesis around IN arguments to accomodate
+      crappy databases
+
 revision 1.58  2009-09-04 15:20 (UTC)
 ----------------------------
     - expanded the scope of -bool and -not_bool operators

Modified: SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract/Test.pm
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract/Test.pm	2010-02-04 10:28:33 UTC (rev 8527)
+++ SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract/Test.pm	2010-02-04 10:33:40 UTC (rev 8528)
@@ -49,6 +49,7 @@
   'UNION',
   'INTERSECT',
   'EXCEPT',
+  'RETURNING',
 );
 
 # These are binary operator keywords always a single LHS and RHS
@@ -57,15 +58,21 @@
 # * BETWEEN without paranthesis around the ANDed arguments (which
 #   makes it a non-binary op) is detected and accomodated in 
 #   _recurse_parse()
+my $stuff_around_mathops = qr/[\w\s\`\'\)]/;
 my @binary_op_keywords = (
-  (map { "\Q$_\E" } (qw/< > != = <= >=/)),
-  '(?: NOT \s+)? LIKE',
-  '(?: NOT \s+)? BETWEEN',
+  ( map
+    { " (?<=  $stuff_around_mathops) " . quotemeta $_ . "(?= $stuff_around_mathops )" }
+    (qw/< > != = <= >=/)
+  ),
+  ( map
+    { '\b (?: NOT \s+)?' . $_ . '\b' }
+    (qw/IN BETWEEN LIKE/)
+  ),
 );
 
 my $tokenizer_re_str = join("\n\t|\n",
   ( map { '\b' . $_ . '\b' } @expression_terminator_sql_keywords, 'AND', 'OR', 'NOT'),
-  ( map { q! (?<= [\w\s\`\'\)] ) ! . $_ . q! (?= [\w\s\`\'\(] ) ! } @binary_op_keywords ),
+  @binary_op_keywords,
 );
 
 my $tokenizer_re = qr/ \s* ( \( | \) | \? | $tokenizer_re_str ) \s* /xi;

Modified: SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract.pm
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract.pm	2010-02-04 10:28:33 UTC (rev 8527)
+++ SQL-Abstract/1.x/branches/test_refactor/lib/SQL/Abstract.pm	2010-02-04 10:33:40 UTC (rev 8528)
@@ -15,7 +15,7 @@
 # GLOBALS
 #======================================================================
 
-our $VERSION  = '1.58';
+our $VERSION  = '1.60';
 
 # This would confuse some packagers
 #$VERSION      = eval $VERSION; # numify for warning-free dev releases
@@ -109,13 +109,24 @@
 #======================================================================
 
 sub insert {
-  my $self  = shift;
-  my $table = $self->_table(shift);
-  my $data  = shift || return;
+  my $self    = shift;
+  my $table   = $self->_table(shift);
+  my $data    = shift || return;
+  my $options = shift;
 
   my $method       = $self->_METHOD_FOR_refkind("_insert", $data);
-  my ($sql, @bind) = $self->$method($data); 
+  my ($sql, @bind) = $self->$method($data);
   $sql = join " ", $self->_sqlcase('insert into'), $table, $sql;
+
+  if (my $fields = $options->{returning}) {
+    my $f = $self->_SWITCH_refkind($fields, {
+      ARRAYREF     => sub {join ', ', map { $self->_quote($_) } @$fields;},
+      SCALAR       => sub {$self->_quote($fields)},
+      SCALARREF    => sub {$$fields},
+    });
+    $sql .= join " ", $self->_sqlcase(' returning'), $f;
+  }
+
   return wantarray ? ($sql, @bind) : $sql;
 }
 
@@ -818,38 +829,51 @@
 sub _where_field_BETWEEN {
   my ($self, $k, $op, $vals) = @_;
 
-  (ref $vals eq 'ARRAY' && @$vals == 2) or 
-  (ref $vals eq 'REF' && (@$$vals == 1 || @$$vals == 2 || @$$vals == 3))
-    or puke "special op 'between' requires an arrayref of two values (or a scalarref or arrayrefref for literal SQL)";
-
-  my ($clause, @bind, $label, $and, $placeholder);
+  my ($label, $and, $placeholder);
   $label       = $self->_convert($self->_quote($k));
   $and         = ' ' . $self->_sqlcase('and') . ' ';
   $placeholder = $self->_convert('?');
   $op               = $self->_sqlcase($op);
 
-  if (ref $vals eq 'REF') {
-    ($clause, @bind) = @$$vals;
-  }
-  else {
-    my (@all_sql, @all_bind);
+  my ($clause, @bind) = $self->_SWITCH_refkind($vals, {
+    ARRAYREFREF => sub {
+      return @$$vals;
+    },
+    SCALARREF => sub {
+      return $$vals;
+    },
+    ARRAYREF => sub {
+      puke "special op 'between' accepts an arrayref with exactly two values"
+        if @$vals != 2;
 
-    foreach my $val (@$vals) {
-      my ($sql, @bind) = $self->_SWITCH_refkind($val, {
-         SCALAR => sub {
-           return ($placeholder, ($val));
-         },
-         SCALARREF => sub {
-           return ($self->_convert($$val), ());
-         },
-      });
-      push @all_sql, $sql;
-      push @all_bind, @bind;
-    }
+      my (@all_sql, @all_bind);
+      foreach my $val (@$vals) {
+        my ($sql, @bind) = $self->_SWITCH_refkind($val, {
+           SCALAR => sub {
+             return ($placeholder, ($val));
+           },
+           SCALARREF => sub {
+             return ($self->_convert($$val), ());
+           },
+           ARRAYREFREF => sub {
+             my ($sql, @bind) = @$$val;
+             return ($self->_convert($sql), @bind);
+           },
+        });
+        push @all_sql, $sql;
+        push @all_bind, @bind;
+      }
 
-    $clause = (join $and, @all_sql);
-    @bind = $self->_bindtype($k, @all_bind);
-  }
+      return (
+        (join $and, @all_sql),
+        $self->_bindtype($k, @all_bind),
+      );
+    },
+    FALLBACK => sub {
+      puke "special op 'between' accepts an arrayref with two values, or a single literal scalarref/arrayref-ref";
+    },
+  });
+
   my $sql = "( $label $op $clause )";
   return ($sql, @bind)
 }
@@ -880,23 +904,35 @@
       }
     },
 
+    SCALARREF => sub {  # literal SQL
+      my $sql = $self->_open_outer_paren ($$vals);
+      return ("$label $op ( $sql )");
+    },
     ARRAYREFREF => sub {  # literal SQL with bind
       my ($sql, @bind) = @$$vals;
       $self->_assert_bindval_matches_bindtype(@bind);
+      $sql = $self->_open_outer_paren ($sql);
       return ("$label $op ( $sql )", @bind);
     },
 
     FALLBACK => sub {
-      puke "special op 'in' requires an arrayref (or arrayref-ref)";
+      puke "special op 'in' requires an arrayref (or scalarref/arrayref-ref)";
     },
   });
 
   return ($sql, @bind);
 }
 
+# Some databases (SQLite) treat col IN (1, 2) different from
+# col IN ( (1, 2) ). Use this to strip all outer parens while
+# adding them back in the corresponding method
+sub _open_outer_paren {
+  my ($self, $sql) = @_;
+  $sql = $1 while $sql =~ /^ \s* \( (.*) \) \s* $/x;
+  return $sql;
+}
 
 
-
 #======================================================================
 # ORDER BY
 #======================================================================
@@ -1650,7 +1686,7 @@
 
 =back
 
-=head2 insert($table, \@values || \%fieldvals)
+=head2 insert($table, \@values || \%fieldvals, \%options)
 
 This is the simplest function. You simply give it a table name
 and either an arrayref of values or hashref of field/value pairs.
@@ -1659,6 +1695,23 @@
 L</"Inserting and Updating SQL"> for information on how to insert
 with those data types.
 
+The optional C<\%options> hash reference may contain additional
+options to generate the insert SQL. Currently supported options
+are:
+
+=over 4
+
+=item returning
+
+Takes either a scalar of raw SQL fields, or an array reference of
+field names, and adds on an SQL C<RETURNING> statement at the end.
+This allows you to return data generated by the insert statement
+(such as row IDs) without performing another C<SELECT> statement.
+Note, however, this is not part of the SQL standard and may not
+be supported by all database engines.
+
+=back
+
 =head2 update($table, \%fieldvals, \%where)
 
 This takes a table, hashref of field/value pairs, and an optional
@@ -1947,9 +2000,28 @@
 (by default : C<1=0>). Similarly, C<< -not_in => [] >> generates
 'sqltrue' (by default : C<1=1>).
 
+In addition to the array you can supply a chunk of literal sql or
+literal sql with bind:
 
+    my %where = {
+      customer => { -in => \[
+        'SELECT cust_id FROM cust WHERE balance > ?',
+        2000,
+      ],
+      status => { -in => \'SELECT status_codes FROM states' },
+    };
 
-Another pair of operators is C<-between> and C<-not_between>, 
+would generate:
+
+    $stmt = "WHERE (
+          customer IN ( SELECT cust_id FROM cust WHERE balance > ? )
+      AND status IN ( SELECT status_codes FROM states )
+    )";
+    @bind = ('2000');
+
+
+
+Another pair of operators is C<-between> and C<-not_between>,
 used with an arrayref of two values:
 
     my %where  = (
@@ -1963,6 +2035,30 @@
 
     WHERE user = ? AND completion_date NOT BETWEEN ( ? AND ? )
 
+Just like with C<-in> all plausible combinations of literal SQL
+are possible:
+
+    my %where = {
+      start0 => { -between => [ 1, 2 ] },
+      start1 => { -between => \["? AND ?", 1, 2] },
+      start2 => { -between => \"lower(x) AND upper(y)" },
+      start3 => { -between => [ 
+        \"lower(x)",
+        \["upper(?)", 'stuff' ],
+      ] },
+    };
+
+Would give you:
+
+    $stmt = "WHERE (
+          ( start0 BETWEEN ? AND ?                )
+      AND ( start1 BETWEEN ? AND ?                )
+      AND ( start2 BETWEEN lower(x) AND upper(y)  )
+      AND ( start3 BETWEEN lower(x) AND upper(?)  )
+    )";
+    @bind = (1, 2, 1, 2, 'stuff');
+
+
 These are the two builtin "special operators"; but the 
 list can be expanded : see section L</"SPECIAL OPERATORS"> below.
 
@@ -2117,7 +2213,7 @@
     );
 
 
-TMTOWTDI.
+TMTOWTDI
 
 Conditions on boolean columns can be expressed in the same way, passing
 a reference to an empty string, however using liternal SQL in this way
@@ -2568,6 +2664,7 @@
     Laurent Dami (internal refactoring, multiple -nest, extensible list of special operators, literal SQL)
     Norbert Buchmuller (support for literal SQL in hashpair, misc. fixes & tests)
     Peter Rabbitson (rewrite of SQLA::Test, misc. fixes & tests)
+    Oliver Charles (support for "RETURNING" after "INSERT")
 
 Thanks!
 

Modified: SQL-Abstract/1.x/branches/test_refactor/t/01generate.t
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/t/01generate.t	2010-02-04 10:28:33 UTC (rev 8527)
+++ SQL-Abstract/1.x/branches/test_refactor/t/01generate.t	2010-02-04 10:33:40 UTC (rev 8528)
@@ -544,6 +544,46 @@
               stmt_q => 'SELECT * FROM `test` WHERE ( `a` = ? OR `b` = ? ) OR ( `a` = ? AND `b` = ? )',
               bind   => [[a => 1], [b => 1], [ a => 2], [ b => 2]],
       },
+      #60
+      {
+              func   => 'insert',
+              args   => ['test', [qw/1 2 3 4 5/], { returning => 'id' }],
+              stmt   => 'INSERT INTO test VALUES (?, ?, ?, ?, ?) RETURNING id',
+              stmt_q => 'INSERT INTO `test` VALUES (?, ?, ?, ?, ?) RETURNING `id`',
+              bind   => [qw/1 2 3 4 5/],
+      },
+      #60
+      {
+              func   => 'insert',
+              args   => ['test', [qw/1 2 3 4 5/], { returning => 'id, foo, bar' }],
+              stmt   => 'INSERT INTO test VALUES (?, ?, ?, ?, ?) RETURNING id, foo, bar',
+              stmt_q => 'INSERT INTO `test` VALUES (?, ?, ?, ?, ?) RETURNING `id, foo, bar`',
+              bind   => [qw/1 2 3 4 5/],
+      },
+      #61
+      {
+              func   => 'insert',
+              args   => ['test', [qw/1 2 3 4 5/], { returning => [qw(id  foo  bar) ] }],
+              stmt   => 'INSERT INTO test VALUES (?, ?, ?, ?, ?) RETURNING id, foo, bar',
+              stmt_q => 'INSERT INTO `test` VALUES (?, ?, ?, ?, ?) RETURNING `id`, `foo`, `bar`',
+              bind   => [qw/1 2 3 4 5/],
+      },
+      #62
+      {
+              func   => 'insert',
+              args   => ['test', [qw/1 2 3 4 5/], { returning => \'id, foo, bar' }],
+              stmt   => 'INSERT INTO test VALUES (?, ?, ?, ?, ?) RETURNING id, foo, bar',
+              stmt_q => 'INSERT INTO `test` VALUES (?, ?, ?, ?, ?) RETURNING id, foo, bar',
+              bind   => [qw/1 2 3 4 5/],
+      },
+      #63
+      {
+              func   => 'insert',
+              args   => ['test', [qw/1 2 3 4 5/], { returning => \'id' }],
+              stmt   => 'INSERT INTO test VALUES (?, ?, ?, ?, ?) RETURNING id',
+              stmt_q => 'INSERT INTO `test` VALUES (?, ?, ?, ?, ?) RETURNING id',
+              bind   => [qw/1 2 3 4 5/],
+      },
 );
 
 

Deleted: SQL-Abstract/1.x/branches/test_refactor/t/05between.t
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/t/05between.t	2010-02-04 10:28:33 UTC (rev 8527)
+++ SQL-Abstract/1.x/branches/test_refactor/t/05between.t	2010-02-04 10:33:40 UTC (rev 8528)
@@ -1,101 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-use Test::More;
-use Test::Exception;
-use SQL::Abstract::Test import => ['is_same_sql_bind'];
-
-use Data::Dumper;
-use SQL::Abstract;
-
-=begin
-Test -between and -in 
-  * between
-    * [scalar, scalar]
-    * [scalarref, scalar]
-    * [scalar, scalarref]
-    * [scalarref, scalarref]
-    * \[]
-      * \["? AND ?", scalar, scalar]
-      * \["1 AND ?", scalar]
-      * \["? AND 2", scalar]
-      * \["1 AND 2"]
-=cut
-
-my @in_between_tests = (
-  {
-    where => { x => { -between => [1, 2] } },
-    stmt => 'WHERE (x BETWEEN ? AND ?)',
-    bind => [qw/1 2/],
-    test => '-between with two placeholders',
-  },
-  {
-    where => { x => { -between => [\"1", 2] } },
-    stmt => 'WHERE (x BETWEEN 1 AND ?)',
-    bind => [qw/2/],
-    test => '-between with one literal sql arg and one placeholder',
-  },
-  {
-    where => { x => { -between => [1, \"2"] } },
-    stmt => 'WHERE (x BETWEEN ? AND 2)',
-    bind => [qw/1/],
-    test => '-between with one placeholder and one literal sql arg',
-  },
-  {
-    where => { x => { -between => [\'current_date - 1', \'current_date - 0'] } },
-    stmt => 'WHERE (x BETWEEN current_date - 1 AND current_date - 0)',
-    bind => [],
-    test => '-between with two literal sql arguments',
-  },
-  {
-    where => { x => { -between => \['? AND ?', 1, 2] } },
-    stmt => 'WHERE (x BETWEEN ? AND ?)',
-    bind => [1,2],
-    test => '-between with literal sql with placeholders (\["? AND ?", scalar, scalar])',
-  },
-  {
-    where => { x => { -between => \["'something' AND ?", 2] } },
-    stmt => "WHERE (x BETWEEN 'something' AND ?)",
-    bind => [2],
-    test => '-between with literal sql with one literal arg and one placeholder (\["\'something\' AND ?", scalar])',
-  },
-  {
-    where => { x => { -between => \["? AND 'something'", 1] } },
-    stmt => "WHERE (x BETWEEN ? AND 'something')",
-    bind => [1],
-    test => '-between with literal sql with one placeholder and one literal arg (\["? AND \'something\'", scalar])',
-  },
-  {
-    where => { x => { -between => \["'this' AND 'that'"] } },
-    stmt => "WHERE (x BETWEEN 'this' AND 'that')",
-    bind => [],
-    test => '-between with literal sql with two literal args (\["\'this\' AND \'that\'"])',
-  },
-);
-
-plan tests => @in_between_tests*3;
-
-for my $case (@in_between_tests) {
-  TODO: {
-    local $TODO = $case->{todo} if $case->{todo};
-
-    local $Data::Dumper::Terse = 1;
-
-    my @w;
-    local $SIG{__WARN__} = sub { push @w, @_ };
-    my $sql = SQL::Abstract->new ($case->{args} || {});
-    lives_ok (sub { 
-      my ($stmt, @bind) = $sql->where($case->{where});
-      is_same_sql_bind(
-        $stmt,
-        \@bind,
-        $case->{stmt},
-        $case->{bind},
-      )
-        || diag "Search term:\n" . Dumper $case->{where};
-    });
-    is (@w, 0, $case->{test} || 'No warnings within in-between tests')
-      || diag join "\n", 'Emitted warnings:', @w;
-  }
-}

Copied: SQL-Abstract/1.x/branches/test_refactor/t/05in_between.t (from rev 6974, SQL-Abstract/1.x/branches/test_refactor/t/05between.t)
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/t/05in_between.t	                        (rev 0)
+++ SQL-Abstract/1.x/branches/test_refactor/t/05in_between.t	2010-02-04 10:33:40 UTC (rev 8528)
@@ -0,0 +1,163 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Test::More;
+use Test::Exception;
+use SQL::Abstract::Test import => ['is_same_sql_bind'];
+
+use Data::Dumper;
+use SQL::Abstract;
+
+my @in_between_tests = (
+  {
+    where => { x => { -between => [1, 2] } },
+    stmt => 'WHERE (x BETWEEN ? AND ?)',
+    bind => [qw/1 2/],
+    test => '-between with two placeholders',
+  },
+  {
+    where => { x => { -between => [\"1", 2] } },
+    stmt => 'WHERE (x BETWEEN 1 AND ?)',
+    bind => [qw/2/],
+    test => '-between with one literal sql arg and one placeholder',
+  },
+  {
+    where => { x => { -between => [1, \"2"] } },
+    stmt => 'WHERE (x BETWEEN ? AND 2)',
+    bind => [qw/1/],
+    test => '-between with one placeholder and one literal sql arg',
+  },
+  {
+    where => { x => { -between => [\'current_date - 1', \'current_date - 0'] } },
+    stmt => 'WHERE (x BETWEEN current_date - 1 AND current_date - 0)',
+    bind => [],
+    test => '-between with two literal sql arguments',
+  },
+  {
+    where => { x => { -between => [ \['current_date - ?', 1], \['current_date - ?', 0] ] } },
+    stmt => 'WHERE (x BETWEEN current_date - ? AND current_date - ?)',
+    bind => [1, 0],
+    test => '-between with two literal sql arguments with bind',
+  },
+  {
+    where => { x => { -between => \['? AND ?', 1, 2] } },
+    stmt => 'WHERE (x BETWEEN ? AND ?)',
+    bind => [1,2],
+    test => '-between with literal sql with placeholders (\["? AND ?", scalar, scalar])',
+  },
+  {
+    where => { x => { -between => \["'something' AND ?", 2] } },
+    stmt => "WHERE (x BETWEEN 'something' AND ?)",
+    bind => [2],
+    test => '-between with literal sql with one literal arg and one placeholder (\["\'something\' AND ?", scalar])',
+  },
+  {
+    where => { x => { -between => \["? AND 'something'", 1] } },
+    stmt => "WHERE (x BETWEEN ? AND 'something')",
+    bind => [1],
+    test => '-between with literal sql with one placeholder and one literal arg (\["? AND \'something\'", scalar])',
+  },
+  {
+    where => { x => { -between => \"'this' AND 'that'" } },
+    stmt => "WHERE (x BETWEEN 'this' AND 'that')",
+    bind => [],
+    test => '-between with literal sql with a literal (\"\'this\' AND \'that\'")',
+  },
+  {
+    where => {
+      start0 => { -between => [ 1, 2 ] },
+      start1 => { -between => \["? AND ?", 1, 2] },
+      start2 => { -between => \"lower(x) AND upper(y)" },
+      start3 => { -between => [
+        \"lower(x)",
+        \["upper(?)", 'stuff' ],
+      ] },
+    },
+    stmt => "WHERE (
+          ( start0 BETWEEN ? AND ?                )
+      AND ( start1 BETWEEN ? AND ?                )
+      AND ( start2 BETWEEN lower(x) AND upper(y)  )
+      AND ( start3 BETWEEN lower(x) AND upper(?)  )
+    )",
+    bind => [1, 2, 1, 2, 'stuff'],
+    test => '-between POD test',
+  },
+
+  {
+    parenthesis_significant => 1,
+    where => { x => { -in => [ 1 .. 3] } },
+    stmt => "WHERE ( x IN (?, ?, ?) )",
+    bind => [ 1 .. 3],
+    test => '-in with an array of scalars',
+  },
+  {
+    parenthesis_significant => 1,
+    where => { x => { -in => [] } },
+    stmt => "WHERE ( 0=1 )",
+    bind => [],
+    test => '-in with an empty array',
+  },
+  {
+    parenthesis_significant => 1,
+    where => { x => { -in => \'( 1,2,lower(y) )' } },
+    stmt => "WHERE ( x IN (1, 2, lower(y) ) )",
+    bind => [],
+    test => '-in with a literal scalarref',
+  },
+  {
+    parenthesis_significant => 1,
+    where => { x => { -in => \['( ( ?,?,lower(y) ) )', 1, 2] } },
+    stmt => "WHERE ( x IN (?, ?, lower(y) ) )",
+    bind => [1, 2],
+    test => '-in with a literal arrayrefref',
+  },
+  {
+    parenthesis_significant => 1,
+    where => {
+      customer => { -in => \[
+        'SELECT cust_id FROM cust WHERE balance > ?',
+        2000,
+      ]},
+      status => { -in => \'SELECT status_codes FROM states' },
+    },
+    stmt => "
+      WHERE ((
+            customer IN ( SELECT cust_id FROM cust WHERE balance > ? )
+        AND status IN ( SELECT status_codes FROM states )
+      ))
+    ",
+    bind => [2000],
+    test => '-in POD test',
+  },
+);
+
+plan tests => @in_between_tests*4;
+
+for my $case (@in_between_tests) {
+  TODO: {
+    local $TODO = $case->{todo} if $case->{todo};
+    local $SQL::Abstract::Test::parenthesis_significant = $case->{parenthesis_significant};
+
+    local $Data::Dumper::Terse = 1;
+
+    lives_ok (sub {
+
+      my @w;
+      local $SIG{__WARN__} = sub { push @w, @_ };
+      my $sql = SQL::Abstract->new ($case->{args} || {});
+      lives_ok (sub { 
+        my ($stmt, @bind) = $sql->where($case->{where});
+        is_same_sql_bind(
+          $stmt,
+          \@bind,
+          $case->{stmt},
+          $case->{bind},
+        )
+          || diag "Search term:\n" . Dumper $case->{where};
+      });
+      is (@w, 0, $case->{test} || 'No warnings within in-between tests')
+        || diag join "\n", 'Emitted warnings:', @w;
+    }, "$case->{test} doesn't die");
+  }
+}

Modified: SQL-Abstract/1.x/branches/test_refactor/t/10test.t
===================================================================
--- SQL-Abstract/1.x/branches/test_refactor/t/10test.t	2010-02-04 10:28:33 UTC (rev 8527)
+++ SQL-Abstract/1.x/branches/test_refactor/t/10test.t	2010-02-04 10:33:40 UTC (rev 8528)
@@ -268,7 +268,16 @@
       },
       {
         equal => 0,
+        parenthesis_significant => 1,
         statements => [
+          q/SELECT foo FROM bar WHERE a IN (1,2,3)/,
+          q/SELECT foo FROM bar WHERE a IN (1,3,2)/,
+          q/SELECT foo FROM bar WHERE a IN ((1,2,3))/,
+        ]
+      },
+      {
+        equal => 0,
+        statements => [
           # BETWEEN with/without parenthesis around itself/RHS is a sticky business
           # if I made a mistake here, simply rewrite the special BETWEEN handling in
           # _recurse_parse()




More information about the Bast-commits mailing list