fix mssql
Arthur Axel 'fREW' Schmidt [Sun, 27 Mar 2011 00:54:17 +0000 (19:54 -0500)]
lib/DBIx/Class/SQLMaker.pm
lib/DBIx/Class/SQLMaker/DateOps.pm
lib/DBIx/Class/SQLMaker/MSSQL.pm
lib/DBIx/Class/Storage/DBI/MSSQL.pm
t/sqlmaker/op_dt.t

index 356965f..93aa7c9 100644 (file)
@@ -513,8 +513,8 @@ sub _where_op_FUNC {
   my $label       = $self->_convert($self->_quote($k));
   my $placeholder = $self->_convert('?');
 
-  croak '-func must be an array' unless ref $vals eq 'ARRAY';
-  croak 'first arg for -func must be a scalar' unless !ref $vals->[0];
+  $self->throw_exception('-func must be an array') unless ref $vals eq 'ARRAY';
+  $self->throw_exception('first arg for -func must be a scalar') unless !ref $vals->[0];
 
   my ($func,@rest_of_vals) = @$vals;
 
@@ -567,8 +567,8 @@ sub _where_op_OP {
   my $label       = $self->_convert($self->_quote($k));
   my $placeholder = $self->_convert('?');
 
-  croak 'argument to -op must be an arrayref' unless ref $vals eq 'ARRAY';
-  croak 'first arg for -op must be a scalar' unless !ref $vals->[0];
+  $self->throw_exception('argument to -op must be an arrayref') unless ref $vals eq 'ARRAY';
+  $self->throw_exception('first arg for -op must be a scalar') unless !ref $vals->[0];
 
   my ($op, @rest_of_vals) = @$vals;
 
index 3ea3e15..d2421d3 100644 (file)
@@ -4,13 +4,12 @@ use base qw/
   Class::Accessor::Grouped
 /;
 __PACKAGE__->mk_group_accessors (simple => qw/datetime_parser/);
-use Carp::Clan qw/^DBIx::Class|^SQL::Abstract|^Try::Tiny/;
 use Sub::Name 'subname';
 
 sub _where_op_CONVERT_DATETIME {
   my $self = shift;
   my ($op, $rhs) = splice @_, -2;
-  croak "-$op takes a DateTime only" unless ref $rhs  && $rhs->isa('DateTime');
+  $self->throw_exception("-$op takes a DateTime only") unless ref $rhs && $rhs->isa('DateTime');
 
   # in case we are called as a top level special op (no '=')
   my $lhs = shift;
@@ -66,8 +65,8 @@ sub _where_op_GET_DATETIME {
      $vals = $_[3];
   }
 
-  croak 'args to -dt_get must be an arrayref' unless ref $vals eq 'ARRAY';
-  croak 'first arg to -dt_get must be a scalar or ARRAY ref' unless !ref $vals->[0] || ref $vals->[0] eq 'ARRAY';
+  $self->throw_exception('args to -dt_get must be an arrayref') unless ref $vals eq 'ARRAY';
+  $self->throw_exception('first arg to -dt_get must be a scalar or ARRAY ref') unless !ref $vals->[0] || ref $vals->[0] eq 'ARRAY';
 
   my $part = $vals->[0];
   my $val  = $vals->[1];
@@ -136,14 +135,14 @@ sub _where_op_DATETIME_NOW {
      $vals = $_[3];
   }
 
-  croak "args to -$op must be an arrayref" unless ref $vals eq 'ARRAY';
+  $self->throw_exception("args to -$op must be an arrayref") unless ref $vals eq 'ARRAY';
   if (!exists $vals->[0]) {
      return $self->_datetime_now_sql()
   } elsif ($vals->[0] eq 'system') {
      require DateTime;
      return $self->_where_op_CONVERT_DATETIME('dt', DateTime->now);
   } else {
-     croak "first arg to -$op must be a 'system' or non-existant"
+     $self->throw_exception("first arg to -$op must be a 'system' or non-existant")
   }
 }
 
@@ -153,6 +152,30 @@ sub _reorder_add_datetime_vars {
    return ($amount, $date);
 }
 
+sub _dt_arg_transform {
+  my ($self, $k, $val) = @_;
+  my ($sql, @bind) = $self->_SWITCH_refkind($val, {
+     SCALAR => sub {
+       return ($self->_convert('?'), $self->_bindtype($k, $val) );
+     },
+     SCALARREF => sub {
+       return $$val;
+     },
+     ARRAYREFREF => sub {
+       my ($sql, @bind) = @$$val;
+       $self->_assert_bindval_matches_bindtype(@bind);
+       return ($sql, @bind);
+     },
+     HASHREF => sub {
+       my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
+       $self->$method('', $val);
+     }
+  });
+  return ($sql, @bind);
+}
+
+sub _where_op_ADD_DATETIME_transform_args { $_[0]->_dt_arg_transform($_[2], $_[3]) }
+
 sub _where_op_ADD_DATETIME {
   my ($self) = @_;
 
@@ -168,35 +191,19 @@ sub _where_op_ADD_DATETIME {
      $vals = $_[3];
   }
 
-  croak "args to -$op must be an arrayref" unless ref $vals eq 'ARRAY';
-  croak "first arg to -$op must be a scalar" unless !ref $vals->[0];
-  croak "-$op must have two more arguments" unless scalar @$vals == 3;
+  $self->throw_exception("args to -$op must be an arrayref") unless ref $vals eq 'ARRAY';
+  $self->throw_exception("first arg to -$op must be a scalar") unless !ref $vals->[0];
+  $self->throw_exception("-$op must have two more arguments") unless scalar @$vals == 3;
 
   my ($part, @rest) = @$vals;
 
-  my $placeholder = $self->_convert('?');
-
   my (@all_sql, @all_bind);
+  my $i = 0;
   foreach my $val ($self->_reorder_add_datetime_vars(@rest)) {
-    my ($sql, @bind) = $self->_SWITCH_refkind($val, {
-       SCALAR => sub {
-         return ($placeholder, $self->_bindtype($k, $val) );
-       },
-       SCALARREF => sub {
-         return $$val;
-       },
-       ARRAYREFREF => sub {
-         my ($sql, @bind) = @$$val;
-         $self->_assert_bindval_matches_bindtype(@bind);
-         return ($sql, @bind);
-       },
-       HASHREF => sub {
-         my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
-         $self->$method('', $val);
-       }
-    });
+    my ($sql, @bind) = $self->_where_op_ADD_DATETIME_transform_args($i, $k, $val);
     push @all_sql, $sql;
     push @all_bind, @bind;
+    $i++;
   }
 
   return $self->_datetime_add_sql($part, $all_sql[0], $all_sql[1]), @all_bind
@@ -223,9 +230,9 @@ sub _where_op_DIFF_DATETIME {
      $vals = $_[3];
   }
 
-  croak 'args to -dt_diff must be an arrayref' unless ref $vals eq 'ARRAY';
-  croak 'first arg to -dt_diff must be a scalar' unless !ref $vals->[0];
-  croak '-dt_diff must have two more arguments' unless scalar @$vals == 3;
+  $self->throw_exception('args to -dt_diff must be an arrayref') unless ref $vals eq 'ARRAY';
+  $self->throw_exception('first arg to -dt_diff must be a scalar') unless !ref $vals->[0];
+  $self->throw_exception('-dt_diff must have two more arguments') unless scalar @$vals == 3;
 
   my ($part, @val) = @$vals;
   my $placeholder = $self->_convert('?');
@@ -233,23 +240,7 @@ sub _where_op_DIFF_DATETIME {
   @val = $self->_reorder_diff_datetime_vars(@val);
   my (@all_sql, @all_bind);
   foreach my $val (@val) {
-    my ($sql, @bind) = $self->_SWITCH_refkind($val, {
-       SCALAR => sub {
-         return ($placeholder, $self->_bindtype($k, $val) );
-       },
-       SCALARREF => sub {
-         return $$val;
-       },
-       ARRAYREFREF => sub {
-         my ($sql, @bind) = @$$val;
-         $self->_assert_bindval_matches_bindtype(@bind);
-         return ($sql, @bind);
-       },
-       HASHREF => sub {
-         my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
-         $self->$method('', $val);
-       }
-    });
+    my ($sql, @bind) = $self->_dt_arg_transform($k, $val);
     push @all_sql, $sql;
     push @all_bind, @bind;
   }
index 96f0993..f3eda14 100644 (file)
@@ -56,8 +56,9 @@ sub _datetime_now_sql { 'NOW()' }
     die $self->_unsupported_date_adding($part, 'Microsoft SQL Server')
       unless exists $diff_part_map{$part};
 
-    my $placeholder = $self->_convert('?');
-    return "(DATEADD($diff_part_map{$part}, $amount, $date))"
+    return "(DATEADD($diff_part_map{$part}, " .
+      ($self->using_freetds && $amount eq '?' ? "CAST($amount AS INTEGER)" : $amount )
+      . ", $date))"
   }
 }
 
@@ -91,4 +92,14 @@ The function used to diff dates is C<DATEDIFF>, which supports
 
 =cut
 
+sub _where_op_ADD_DATETIME_transform_args {
+   my ($self, $i, $k, $val) = @_;
+
+   if ($i == 0 && !ref $val) {
+      return $self->_convert('?'), [\'integer' => $val ]
+   } else {
+      return $self->next::method($i, $k, $val)
+   }
+}
+
 1;
index e0ff02f..95889c4 100644 (file)
@@ -225,6 +225,12 @@ sub _ping {
   };
 }
 
+sub bind_attribute_by_data_type {
+  shift->is_datatype_numeric(shift)
+    ? do { require DBI; DBI::SQL_INTEGER() }
+    : {}
+}
+
 package # hide from PAUSE
   DBIx::Class::Storage::DBI::MSSQL::DateTime::Format;
 
index 3c22901..93446cd 100644 (file)
@@ -5,6 +5,7 @@ use Test::More;
 use Test::Exception;
 
 use lib qw(t/lib);
+use DBICTest::RunMode;
 use DBIC::SqlMakerTest;
 use DateTime;
 use DBIx::Class::SQLMaker::MSSQL;
@@ -619,11 +620,10 @@ my @tests = (
       hri    => [{ date => '2014-12-14 12:12:12' }],
     },
     mssql => {
-      select => "(DATEADD(year, ?, me.created_on))",
+      select => "(DATEADD(year, CAST(? AS INTEGER), me.created_on))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
       hri    => [{ date => '2014-12-14 12:12:12.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(me.created_on, INTERVAL ? YEAR)",
@@ -651,11 +651,10 @@ my @tests = (
       hri    => [{ date => '2012-03-14 12:12:12' }],
     },
     mssql => {
-      select => "(DATEADD(month, ?, me.created_on))",
+      select => "(DATEADD(month, CAST(? AS INTEGER), me.created_on))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
       hri    => [{ date => '2012-03-14 12:12:12.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(me.created_on, INTERVAL ? MONTH)",
@@ -683,11 +682,10 @@ my @tests = (
       hri    => [{ date => '2011-12-17 12:12:12' }],
     },
     mssql => {
-      select => "(DATEADD(dayofyear, ?, me.created_on))",
+      select => "(DATEADD(dayofyear, CAST(? AS INTEGER), me.created_on))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
       hri    => [{ date => '2011-12-17 12:12:12.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(me.created_on, INTERVAL ? DAY)",
@@ -715,11 +713,10 @@ my @tests = (
       hri    => [{ date => '2011-12-14 15:12:12' }],
     },
     mssql => {
-      select => "(DATEADD(hour, ?, me.created_on))",
+      select => "(DATEADD(hour, CAST(? AS INTEGER), me.created_on))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
       hri    => [{ date => '2011-12-14 15:12:12.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(me.created_on, INTERVAL ? HOUR)",
@@ -747,11 +744,10 @@ my @tests = (
       hri    => [{ date => '2011-12-14 12:15:12' }],
     },
     mssql => {
-      select => "(DATEADD(minute, ?, me.created_on))",
+      select => "(DATEADD(minute, CAST(? AS INTEGER), me.created_on))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
       hri    => [{ date => '2011-12-14 12:15:12.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(me.created_on, INTERVAL ? MINUTE)",
@@ -779,11 +775,10 @@ my @tests = (
       hri    => [{ date => '2011-12-14 12:12:15' }],
     },
     mssql => {
-      select => "(DATEADD(second, ?, me.created_on))",
+      select => "(DATEADD(second, CAST(? AS INTEGER), me.created_on))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3], [{dbic_colname => 'me.id', sqlt_datatype => 'integer'} => 2 ]],
       hri    => [{ date => '2011-12-14 12:12:15.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(me.created_on, INTERVAL ? SECOND)",
@@ -811,11 +806,10 @@ my @tests = (
       hri    => [{ date => '2011-12-15 12:12:15' }],
     },
     mssql => {
-      select => "(DATEADD(second, ?, (DATEADD(dayofyear, ?, me.created_on))))",
+      select => "(DATEADD(second, CAST(? AS INTEGER), (DATEADD(dayofyear, CAST(? AS INTEGER), me.created_on))))",
       where => "me.id = ?",
-      bind   => [[unknown_col, 3 ], [unknown_col, 1], [{dbic_colname => 'me.id', sqlt_datatype => 'integer' }, 2]],
+      bind   => [[{sqlt_datatype => 'integer'}, 3 ], [{sqlt_datatype => 'integer'}, 1], [{dbic_colname => 'me.id', sqlt_datatype => 'integer' }, 2]],
       hri    => [{ date => '2011-12-15 12:12:15.000' }],
-      skip   => 'need working bindtypes',
     },
     mysql => {
       select => "DATE_ADD(DATE_ADD(me.created_on, INTERVAL ? DAY), INTERVAL ? SECOND)",