From: Peter Rabbitson Date: Thu, 7 May 2009 17:07:19 +0000 (+0000) Subject: Temporary fix or the IN ( ( ... ) ) problem until we get proper SQLA AST (needs SQLA... X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ff1393c7524889fbd5dd7f9b69871ec419fcd745;p=dbsrgits%2FDBIx-Class-Historic.git Temporary fix or the IN ( ( ... ) ) problem until we get proper SQLA AST (needs SQLA released with commit 6158 to work) --- diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index c276f38..7987c40 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -38,10 +38,10 @@ package # Hide from PAUSE use base qw/SQL::Abstract::Limit/; -# This prevents the caching of $dbh in S::A::L, I believe sub new { my $self = shift->SUPER::new(@_); + # This prevents the caching of $dbh in S::A::L, I believe # If limit_dialect is a ref (like a $dbh), go ahead and replace # it with what it resolves to: $self->{limit_dialect} = $self->_find_syntax($self->{limit_dialect}) @@ -50,6 +50,60 @@ sub new { $self; } + + +# Some databases (sqlite) do not handle multiple parenthesis +# around in/between arguments. A tentative x IN ( ( 1, 2 ,3) ) +# is interpreted as x IN 1 or something similar. +# +# Since we currently do not have access to the SQLA AST, resort +# to barbaric mutilation of any SQL supplied in literal form + +sub _strip_outer_paren { + my ($self, $arg) = @_; + +use Data::Dumper; + + return $self->_SWITCH_refkind ($arg, { + ARRAYREFREF => sub { + $$arg->[0] = __strip_outer_paren ($$arg->[0]); + return $arg; + }, + SCALARREF => sub { + return \__strip_outer_paren( $$arg ); + }, + FALLBACK => sub { + return $arg + }, + }); +} + +sub __strip_outer_paren { + my $sql = shift; + + if ($sql and not ref $sql) { + while ($sql =~ /^ \s* \( (.*) \) \s* $/x ) { + $sql = $1; + } + } + + return $sql; +} + +sub _where_field_IN { + my ($self, $lhs, $op, $rhs) = @_; + $rhs = $self->_strip_outer_paren ($rhs); + return $self->SUPER::_where_field_IN ($lhs, $op, $rhs); +} + +sub _where_field_BETWEEN { + my ($self, $lhs, $op, $rhs) = @_; + $rhs = $self->_strip_outer_paren ($rhs); + return $self->SUPER::_where_field_BETWEEN ($lhs, $op, $rhs); +} + + + # DB2 is the only remaining DB using this. Even though we are not sure if # RowNumberOver is still needed here (should be part of SQLA) leave the # code in place diff --git a/t/count/in_subquery.t b/t/count/in_subquery.t new file mode 100644 index 0000000..1275c1e --- /dev/null +++ b/t/count/in_subquery.t @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Data::Dumper; + +use Test::More; + +plan ( tests => 1 ); + +use lib qw(t/lib); +use DBICTest; +use DBIC::SqlMakerTest; + +my $schema = DBICTest->init_schema(); + +{ + my $rs = $schema->resultset("CD")->search( + { 'artist.name' => 'Caterwauler McCrae' }, + { join => [qw/artist/]} + ); + my $squery = $rs->get_column('cdid')->as_query; + my $subsel_rs = $schema->resultset("CD")->search( { cdid => { IN => $squery } } ); + is($subsel_rs->count, $rs->count, 'Subselect on PK got the same row count'); +}