From: Arthur Axel 'fREW' Schmidt Date: Sun, 27 Mar 2011 00:54:17 +0000 (-0500) Subject: fix mssql X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=90676d46cdf2159aa71c60e5caad33cfbe8e561e;p=dbsrgits%2FDBIx-Class.git fix mssql --- diff --git a/lib/DBIx/Class/SQLMaker.pm b/lib/DBIx/Class/SQLMaker.pm index 356965f..93aa7c9 100644 --- a/lib/DBIx/Class/SQLMaker.pm +++ b/lib/DBIx/Class/SQLMaker.pm @@ -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; diff --git a/lib/DBIx/Class/SQLMaker/DateOps.pm b/lib/DBIx/Class/SQLMaker/DateOps.pm index 3ea3e15..d2421d3 100644 --- a/lib/DBIx/Class/SQLMaker/DateOps.pm +++ b/lib/DBIx/Class/SQLMaker/DateOps.pm @@ -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; } diff --git a/lib/DBIx/Class/SQLMaker/MSSQL.pm b/lib/DBIx/Class/SQLMaker/MSSQL.pm index 96f0993..f3eda14 100644 --- a/lib/DBIx/Class/SQLMaker/MSSQL.pm +++ b/lib/DBIx/Class/SQLMaker/MSSQL.pm @@ -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, 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; diff --git a/lib/DBIx/Class/Storage/DBI/MSSQL.pm b/lib/DBIx/Class/Storage/DBI/MSSQL.pm index e0ff02f..95889c4 100644 --- a/lib/DBIx/Class/Storage/DBI/MSSQL.pm +++ b/lib/DBIx/Class/Storage/DBI/MSSQL.pm @@ -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; diff --git a/t/sqlmaker/op_dt.t b/t/sqlmaker/op_dt.t index 3c22901..93446cd 100644 --- a/t/sqlmaker/op_dt.t +++ b/t/sqlmaker/op_dt.t @@ -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)",