From: Peter Rabbitson Date: Tue, 27 May 2014 17:17:26 +0000 (+0200) Subject: Retire DBIC::DebugObj, replace with $dbictest_schema->is_executed_sql_bind() X-Git-Tag: v0.082800~200 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=2cfc22ddff9cb35524031dfc9d429d294b5e3d6e;hp=680e2ac9adda36197b8b880c25fa344376f5914e;p=dbsrgits%2FDBIx-Class.git Retire DBIC::DebugObj, replace with $dbictest_schema->is_executed_sql_bind() This cuts down on a lot of the silliness with debugcb/debugobj, and makes for more precise tests as a whole. Went through great pains to not disturb any existing tests, fingercross this is indeed the case Read under -w for sanity --- diff --git a/Makefile.PL b/Makefile.PL index 492368e..108624a 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -84,7 +84,7 @@ my $runtime_requires = { 'namespace::clean' => '0.24', 'Path::Class' => '0.18', 'Scope::Guard' => '0.03', - 'SQL::Abstract' => '1.77', + 'SQL::Abstract' => '1.78', 'Try::Tiny' => '0.07', # Technically this is not a core dependency - it is only required diff --git a/t/18insert_default.t b/t/18insert_default.t index cd49cec..17657cc 100644 --- a/t/18insert_default.t +++ b/t/18insert_default.t @@ -2,11 +2,8 @@ use strict; use warnings; use Test::More; -use Test::Exception; use lib qw(t/lib); use DBICTest; -use DBIC::DebugObj; -use DBIC::SqlMakerTest; my $schema = DBICTest->init_schema(); $schema->storage->sql_maker->quote_char('"'); @@ -15,27 +12,12 @@ my $rs = $schema->resultset ('Artist'); my $last_obj = $rs->search ({}, { order_by => { -desc => 'artistid' }, rows => 1})->single; my $last_id = $last_obj ? $last_obj->artistid : 0; - -my ($sql, @bind); -my $orig_debugobj = $schema->storage->debugobj; -my $orig_debug = $schema->storage->debug; - -$schema->storage->debugobj (DBIC::DebugObj->new (\$sql, \@bind) ); -$schema->storage->debug (1); - my $obj; -lives_ok { $obj = $rs->create ({}) } 'Default insert successful'; - -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - -is_same_sql_bind ( - $sql, - \@bind, - 'INSERT INTO "artist" DEFAULT VALUES', - [], - 'Default-value insert correct SQL', -); +$schema->is_executed_sql_bind( sub { + $obj = $rs->create ({}) +}, [[ + 'INSERT INTO "artist" DEFAULT VALUES' +]], 'Default-value insert correct SQL' ); ok ($obj, 'Insert defaults ( $rs->create ({}) )' ); diff --git a/t/80unique.t b/t/80unique.t index ba5a181..b380225 100644 --- a/t/80unique.t +++ b/t/80unique.t @@ -6,8 +6,6 @@ use Test::Exception; use Test::Warn; use lib qw(t/lib); use DBICTest; -use DBIC::SqlMakerTest; -use DBIC::DebugObj; my $schema = DBICTest->init_schema(); @@ -228,23 +226,12 @@ is($row->baz, 3, 'baz is correct'); { my $artist = $schema->resultset('Artist')->find(1); - my ($sql, @bind); - my $old_debugobj = $schema->storage->debugobj; - my $old_debug = $schema->storage->debug; - $schema->storage->debugobj(DBIC::DebugObj->new(\$sql, \@bind)), - $schema->storage->debug(1); - - $artist->discard_changes; - - is_same_sql_bind ( - $sql, - \@bind, - 'SELECT me.artistid, me.name, me.rank, me.charfield FROM artist me WHERE me.artistid = ?', - [qw/'1'/], - ); - - $schema->storage->debug($old_debug); - $schema->storage->debugobj($old_debugobj); + $schema->is_executed_sql_bind( sub { $artist->discard_changes }, [ + [ + 'SELECT me.artistid, me.name, me.rank, me.charfield FROM artist me WHERE me.artistid = ?', + [ { dbic_colname => "me.artistid", sqlt_datatype => "integer" } => 1 ], + ] + ], 'Expected query on discard_changes'); } { diff --git a/t/85utf8.t b/t/85utf8.t index a07e42a..64b4994 100644 --- a/t/85utf8.t +++ b/t/85utf8.t @@ -5,7 +5,6 @@ use Test::More; use Test::Warn; use lib qw(t/lib); use DBICTest; -use DBIC::DebugObj; { package A::Comp; @@ -97,24 +96,22 @@ my $bytestream_title = my $utf8_title = "weird \x{466} stuff"; utf8::encode($bytestream_title); cmp_ok ($bytestream_title, 'ne', $utf8_title, 'unicode/raw differ (sanity check)'); -my $storage = $schema->storage; -my ($sql, @bind); -my $debugobj = DBIC::DebugObj->new (\$sql, \@bind); -my ($orig_debug, $orig_debugobj) = ($storage->debug, $storage->debugobj); -$storage->debugobj ($debugobj); -$storage->debug (1); - -my $cd = $schema->resultset('CD')->create( { artist => 1, title => $utf8_title, year => '2048' } ); - -$storage->debugobj ($orig_debugobj); -$storage->debug ($orig_debug); - -# bind values are always alphabetically ordered by column, thus [1] -# the single quotes are an artefact of the debug-system +my $cd; { local $TODO = "This has been broken since rev 1191, Mar 2006"; - is ($bind[1], "'$bytestream_title'", 'INSERT: raw bytes sent to the database'); -} + + $schema->is_executed_sql_bind( sub { + $cd = $schema->resultset('CD')->create( { artist => 1, title => $utf8_title, year => '2048' } ) + }, [[ + 'INSERT INTO cd ( artist, title, year) VALUES ( ?, ?, ? )', + [ { dbic_colname => "artist", sqlt_datatype => "integer" } + => 1 ], + [ { dbic_colname => "title", sqlt_datatype => "varchar", sqlt_size => 100 } + => $bytestream_title ], + [ { dbic_colname => "year", sqlt_datatype => "varchar", sqlt_size => 100 } + => 2048 ], + ]], 'INSERT: raw bytes sent to the database' ); +}; # this should be using the cursor directly, no inflation/processing of any sort my ($raw_db_title) = $schema->resultset('CD') @@ -149,16 +146,20 @@ ok(! utf8::is_utf8( $cd->{_column_data}{title} ), 'reloaded utf8-less title' ); $bytestream_title = $utf8_title = "something \x{219} else"; utf8::encode($bytestream_title); +$schema->is_executed_sql_bind( sub { + $cd->update ({ title => $utf8_title }); +}, [ + [ 'BEGIN' ], + [ + 'UPDATE cd SET title = ? WHERE cdid = ?', + [ { dbic_colname => "title", sqlt_datatype => "varchar", sqlt_size => 100 } + => $bytestream_title ], + [ { dbic_colname => "cdid", sqlt_datatype => "integer" } + => 6 ], + ], + [ 'COMMIT' ], +], 'UPDATE: raw bytes sent to the database'); -$storage->debugobj ($debugobj); -$storage->debug (1); - -$cd->update ({ title => $utf8_title }); - -$storage->debugobj ($orig_debugobj); -$storage->debug ($orig_debug); - -is ($bind[0], "'$bytestream_title'", 'UPDATE: raw bytes sent to the database'); ($raw_db_title) = $schema->resultset('CD') ->search ($cd->ident_condition) ->get_column('title') diff --git a/t/93autocast.t b/t/93autocast.t index 95d2b92..49c1f57 100644 --- a/t/93autocast.t +++ b/t/93autocast.t @@ -4,8 +4,6 @@ use warnings; use Test::More; use lib qw(t/lib); use DBICTest; -use DBIC::SqlMakerTest; -use DBIC::DebugObj; { # Fake storage driver for sqlite with autocast package DBICTest::SQLite::AutoCast; @@ -37,22 +35,18 @@ my $rs = $schema->resultset ('CD')->search ({ 'me.single_track' => \[ '= ?', [ single_track => 1 ] ], }, { join => 'tracks' }); -my ($sql, @bind); -my $debugobj = DBIC::DebugObj->new (\$sql, \@bind); -my $storage = $schema->storage; -my ($orig_debug, $orig_debugobj) = ($storage->debug, $storage->debugobj); -$storage->debugobj ($debugobj); -$storage->debug (1); - -# the quoting is a debugobj thing, not dbic-internals -my $bind = [ map { "'$_'" } qw/ - 5 1 2009 4 -/]; +my @bind = ( + [ { dbic_colname => "cdid", sqlt_datatype => "integer" } + => 5 ], + [ { dbic_colname => "single_track", sqlt_datatype => "integer" } + => 1 ], + [ { dbic_colname => "tracks.last_updated_on", sqlt_datatype => "datetime" } + => 2009 ], + [ { dbic_colname => "tracks.position", sqlt_datatype => "int" } + => 4 ], +); -$rs->all; -is_same_sql_bind ( - $sql, - \@bind, +$schema->is_executed_sql_bind( sub { $rs->all }, [[ ' SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me @@ -64,16 +58,12 @@ is_same_sql_bind ( AND tracks.last_updated_on < ? AND tracks.position = ? ', - $bind, - 'expected sql with casting off', -); + @bind, +]], 'expected sql with casting off' ); $schema->storage->auto_cast (1); -$rs->all; -is_same_sql_bind ( - $sql, - \@bind, +$schema->is_executed_sql_bind( sub { $rs->all }, [[ ' SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me @@ -85,11 +75,7 @@ is_same_sql_bind ( AND tracks.last_updated_on < CAST (? AS DateTime) AND tracks.position = ? ', - $bind, - 'expected sql with casting on', -); - -$storage->debugobj ($orig_debugobj); -$storage->debug ($orig_debug); + @bind, +]], 'expected sql with casting on' ); done_testing; diff --git a/t/count/count_rs.t b/t/count/count_rs.t index 83b6257..5883daf 100644 --- a/t/count/count_rs.t +++ b/t/count/count_rs.t @@ -6,7 +6,6 @@ use lib qw(t/lib); use Test::More; use DBICTest; use DBIC::SqlMakerTest; -use DBIC::DebugObj; use DBIx::Class::SQLMaker::LimitDialects; my ($ROWS, $OFFSET) = ( @@ -23,27 +22,25 @@ my $schema = DBICTest->init_schema(); { position => [1,2] }, { prefetch => [qw/disc lyrics/], rows => 3, offset => 8 }, ); - is ($rs->all, 2, 'Correct number of objects'); - - - my ($sql, @bind); - $schema->storage->debugobj(DBIC::DebugObj->new(\$sql, \@bind)); - $schema->storage->debug(1); + my @wherebind = ( + [ { sqlt_datatype => 'int', dbic_colname => 'position' } + => 1 ], + [ { sqlt_datatype => 'int', dbic_colname => 'position' } + => 2 ], + ); - is ($rs->count, 2, 'Correct count via count()'); + is ($rs->all, 2, 'Correct number of objects'); - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + is ($rs->count, 2, 'Correct count via count()'); + }, [[ 'SELECT COUNT( * ) FROM cd me JOIN track tracks ON tracks.cd = me.cdid JOIN cd disc ON disc.cdid = tracks.cd WHERE ( ( position = ? OR position = ? ) ) - ', - [ qw/'1' '2'/ ], - 'count softlimit applied', - ); + ', @wherebind + ]], 'count softlimit applied'); my $crs = $rs->count_rs; is ($crs->next, 2, 'Correct count via count_rs()'); @@ -60,14 +57,7 @@ my $schema = DBICTest->init_schema(); LIMIT ? OFFSET ? ) tracks )', - [ - [ { sqlt_datatype => 'int', dbic_colname => 'position' } - => 1 ], - [ { sqlt_datatype => 'int', dbic_colname => 'position' } - => 2 ], - [$ROWS => 3], - [$OFFSET => 8], - ], + [ @wherebind, [$ROWS => 3], [$OFFSET => 8] ], 'count_rs db-side limit applied', ); } @@ -79,17 +69,18 @@ my $schema = DBICTest->init_schema(); { 'tracks.position' => [1,2] }, { prefetch => [qw/tracks artist/], rows => 3, offset => 4 }, ); - is ($rs->all, 1, 'Correct number of objects'); - - my ($sql, @bind); - $schema->storage->debugobj(DBIC::DebugObj->new(\$sql, \@bind)); - $schema->storage->debug(1); + my @wherebind = ( + [ { sqlt_datatype => 'int', dbic_colname => 'tracks.position' } + => 1 ], + [ { sqlt_datatype => 'int', dbic_colname => 'tracks.position' } + => 2 ], + ); - is ($rs->count, 1, 'Correct count via count()'); + is ($rs->all, 1, 'Correct number of objects'); - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + is ($rs->count, 1, 'Correct count via count()'); + }, [ [ 'SELECT COUNT( * ) FROM ( SELECT cds.cdid @@ -100,10 +91,8 @@ my $schema = DBICTest->init_schema(); WHERE tracks.position = ? OR tracks.position = ? GROUP BY cds.cdid ) cds - ', - [ qw/'1' '2'/ ], - 'count softlimit applied', - ); + ', @wherebind + ]], 'count softlimit applied' ); my $crs = $rs->count_rs; is ($crs->next, 1, 'Correct count via count_rs()'); @@ -122,14 +111,7 @@ my $schema = DBICTest->init_schema(); LIMIT ? OFFSET ? ) cds )', - [ - [ { sqlt_datatype => 'int', dbic_colname => 'tracks.position' } - => 1 ], - [ { sqlt_datatype => 'int', dbic_colname => 'tracks.position' } - => 2 ], - [ $ROWS => 3], - [$OFFSET => 4], - ], + [ @wherebind, [$ROWS => 3], [$OFFSET => 4], ], 'count_rs db-side limit applied', ); } diff --git a/t/lib/DBIC/DebugObj.pm b/t/lib/DBIC/DebugObj.pm deleted file mode 100644 index c43bae9..0000000 --- a/t/lib/DBIC/DebugObj.pm +++ /dev/null @@ -1,50 +0,0 @@ -package DBIC::DebugObj; - -use strict; -use warnings; - -use Class::C3; - -use base qw/DBIx::Class::Storage::Statistics Exporter Class::Accessor::Fast/; - -__PACKAGE__->mk_accessors( qw/dbictest_sql_ref dbictest_bind_ref/ ); - - -=head2 new(PKG, SQL_REF, BIND_REF, ...) - -Creates a new instance that on subsequent queries will store -the generated SQL to the scalar pointed to by SQL_REF and bind -values to the array pointed to by BIND_REF. - -=cut - -sub new { - my $pkg = shift; - my $sql_ref = shift; - my $bind_ref = shift; - - my $self = $pkg->SUPER::new(@_); - - $self->debugfh(undef); - - $self->dbictest_sql_ref($sql_ref); - $self->dbictest_bind_ref($bind_ref || []); - - return $self; -} - -sub query_start { - my $self = shift; - - (${$self->dbictest_sql_ref}, @{$self->dbictest_bind_ref}) = @_; -} - -sub query_end { } - -sub txn_begin { } - -sub txn_commit { } - -sub txn_rollback { } - -1; diff --git a/t/lib/DBICTest/BaseSchema.pm b/t/lib/DBICTest/BaseSchema.pm index 0e1e5e2..ae8d74a 100644 --- a/t/lib/DBICTest/BaseSchema.pm +++ b/t/lib/DBICTest/BaseSchema.pm @@ -3,7 +3,6 @@ package #hide from pause use strict; use warnings; - use base qw(DBICTest::Base DBIx::Class::Schema); use Fcntl qw(:DEFAULT :seek :flock); @@ -12,6 +11,92 @@ use DBICTest::Util::LeakTracer qw(populate_weakregistry assert_empty_weakregistr use DBICTest::Util 'local_umask'; use namespace::clean; +{ + package # moar hide + DBICTest::SQLTracerObj; + use base 'DBIx::Class::Storage::Statistics'; + + sub query_start { push @{$_[0]{sqlbinds}}, [ ($_[1] =~ /^\s*(\S+)/)[0], [ $_[1], @{ $_[2]||[] } ] ] } + + # who the hell came up with this API >:( + for my $txn (qw(begin rollback commit)) { + no strict 'refs'; + *{"txn_$txn"} = sub { push @{$_[0]{sqlbinds}}, [ uc $txn => [ uc $txn ] ] }; + } + + sub svp_begin { push @{$_[0]{sqlbinds}}, [ SAVEPOINT => [ "SAVEPOINT $_[1]" ] ] } + sub svp_release { push @{$_[0]{sqlbinds}}, [ RELEASE_SAVEPOINT => [ "RELEASE $_[1]" ] ] } + sub svp_rollback { push @{$_[0]{sqlbinds}}, [ ROLLBACK_TO_SAVEPOINT => [ "ROLLBACK TO $_[1]" ] ] } + +} + +sub capture_executed_sql_bind { + my ($self, $cref) = @_; + + $self->throw_exception("Expecting a coderef to run") unless ref $cref eq 'CODE'; + + # hack around stupid, stupid API + no warnings 'redefine'; + local *DBIx::Class::Storage::DBI::_format_for_trace = sub { $_[1] }; + Class::C3->reinitialize if DBIx::Class::_ENV_::OLD_MRO; + + local $self->storage->{debugcb}; + local $self->storage->{debugobj} = my $tracer_obj = DBICTest::SQLTracerObj->new; + local $self->storage->{debug} = 1; + + + $cref->(); + + return $tracer_obj->{sqlbinds} || []; +} + +sub is_executed_sql_bind { + my ($self, $cref, $sqlbinds, $msg) = @_; + + local $Test::Builder::Level = $Test::Builder::Level + 1; + + $self->throw_exception("Expecting an arrayref of SQL/Bind pairs") unless ref $sqlbinds eq 'ARRAY'; + + my @expected = @$sqlbinds; + + my @got = map { $_->[1] } @{ $self->capture_executed_sql_bind($cref) }; + + + return Test::Builder->new->ok(1, $msg || "No queries executed while running $cref") + if !@got and !@expected; + + require SQL::Abstract::Test; + my $ret = 1; + while (@expected or @got) { + my $left = shift @got; + my $right = shift @expected; + + # allow the right side to "simplify" the entire shebang + if ($left and $right) { + $left = [ @$left ]; + for my $i (1..$#$right) { + if ( + ! ref $right->[$i] + and + ref $left->[$i] eq 'ARRAY' + and + @{$left->[$i]} == 2 + ) { + $left->[$i] = $left->[$i][1] + } + } + } + + $ret &= SQL::Abstract::Test::is_same_sql_bind( + \( $left || [] ), + \( $right || [] ), + $msg, + ); + } + + return $ret; +} + our $locker; END { # we need the $locker to be referenced here for delayed destruction diff --git a/t/lib/DBICTest/Stats.pm b/t/lib/DBICTest/Stats.pm deleted file mode 100644 index 5a4544f..0000000 --- a/t/lib/DBICTest/Stats.pm +++ /dev/null @@ -1,63 +0,0 @@ -package DBICTest::Stats; -use strict; -use warnings; - -use base qw/DBIx::Class::Storage::Statistics/; - -sub txn_begin { - my $self = shift; - - $self->{'TXN_BEGIN'}++; - return $self->{'TXN_BEGIN'}; -} - -sub txn_rollback { - my $self = shift; - - $self->{'TXN_ROLLBACK'}++; - return $self->{'TXN_ROLLBACK'}; -} - -sub txn_commit { - my $self = shift; - - $self->{'TXN_COMMIT'}++; - return $self->{'TXN_COMMIT'}; -} - -sub svp_begin { - my ($self, $name) = @_; - - $self->{'SVP_BEGIN'}++; - return $self->{'SVP_BEGIN'}; -} - -sub svp_release { - my ($self, $name) = @_; - - $self->{'SVP_RELEASE'}++; - return $self->{'SVP_RELEASE'}; -} - -sub svp_rollback { - my ($self, $name) = @_; - - $self->{'SVP_ROLLBACK'}++; - return $self->{'SVP_ROLLBACK'}; -} - -sub query_start { - my ($self, $string, @bind) = @_; - - $self->{'QUERY_START'}++; - return $self->{'QUERY_START'}; -} - -sub query_end { - my ($self, $string) = @_; - - $self->{'QUERY_END'}++; - return $self->{'QUERY_START'}; -} - -1; diff --git a/t/resultset/update_delete.t b/t/resultset/update_delete.t index 917e12f..ee32717 100644 --- a/t/resultset/update_delete.t +++ b/t/resultset/update_delete.t @@ -12,16 +12,9 @@ BEGIN { } use DBICTest; -use DBIC::DebugObj; -use DBIC::SqlMakerTest; my $schema = DBICTest->init_schema; -my ($sql, @bind); -my $debugobj = DBIC::DebugObj->new (\$sql, \@bind); -my $orig_debugobj = $schema->storage->debugobj; -my $orig_debug = $schema->storage->debug; - my $tkfks = $schema->resultset('FourKeys_to_TwoKeys'); my ($fa, $fb, $fc) = $tkfks->related_resultset ('fourkeys')->populate ([ @@ -64,23 +57,16 @@ my $fks = $schema->resultset ('FourKeys')->search ( ); is ($fks->count, 4, 'Joined FourKey count correct (2x2)'); - -$schema->storage->debugobj ($debugobj); -$schema->storage->debug (1); -$fks->update ({ read_count => \ 'read_count + 1' }); -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - -is_same_sql_bind ( - $sql, - \@bind, +$schema->is_executed_sql_bind( sub { + $fks->update ({ read_count => \ 'read_count + 1' }) +}, [[ 'UPDATE fourkeys SET read_count = read_count + 1 WHERE ( ( ( bar = ? OR bar = ? ) AND ( foo = ? OR foo = ? ) AND ( goodbye = ? OR goodbye = ? ) AND ( hello = ? OR hello = ? ) AND sensors != ? ) ) ', - [ ("'1'", "'2'") x 4, "'c'" ], - 'Correct update-SQL with multijoin with pruning', -); + (1, 2) x 4, + 'c', +]], 'Correct update-SQL with multijoin with pruning' ); is ($fa->discard_changes->read_count, 11, 'Update ran only once on discard-join resultset'); is ($fb->discard_changes->read_count, 21, 'Update ran only once on discard-join resultset'); @@ -88,40 +74,44 @@ is ($fc->discard_changes->read_count, 30, 'Update did not touch outlier'); # make the multi-join stick my $fks_multi = $fks->search({ 'fourkeys_to_twokeys.pilot_sequence' => { '!=' => 666 } }); - -$schema->storage->debugobj ($debugobj); -$schema->storage->debug (1); -$fks_multi->update ({ read_count => \ 'read_count + 1' }); -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - -is_same_sql_bind ( - $sql, - \@bind, - 'UPDATE fourkeys - SET read_count = read_count + 1 - WHERE ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? ) OR ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? )', - [ map { "'$_'" } ( (1) x 4, (2) x 4 ) ], - 'Correct update-SQL with multijoin without pruning', -); +$schema->is_executed_sql_bind( sub { + $fks_multi->update ({ read_count => \ 'read_count + 1' }) +}, [ + [ 'BEGIN' ], + [ + 'SELECT me.foo, me.bar, me.hello, me.goodbye + FROM fourkeys me + LEFT JOIN fourkeys_to_twokeys fourkeys_to_twokeys + ON fourkeys_to_twokeys.f_bar = me.bar AND fourkeys_to_twokeys.f_foo = me.foo AND fourkeys_to_twokeys.f_goodbye = me.goodbye AND fourkeys_to_twokeys.f_hello = me.hello + WHERE ( bar = ? OR bar = ? ) AND ( foo = ? OR foo = ? ) AND fourkeys_to_twokeys.pilot_sequence != ? AND ( goodbye = ? OR goodbye = ? ) AND ( hello = ? OR hello = ? ) AND sensors != ? + GROUP BY me.foo, me.bar, me.hello, me.goodbye + ', + (1, 2) x 2, + 666, + (1, 2) x 2, + 'c', + ], + [ + 'UPDATE fourkeys + SET read_count = read_count + 1 + WHERE ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? ) OR ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? ) + ', + ( (1) x 4, (2) x 4 ), + ], + [ 'COMMIT' ], +], 'Correct update-SQL with multijoin without pruning' ); is ($fa->discard_changes->read_count, 12, 'Update ran only once on joined resultset'); is ($fb->discard_changes->read_count, 22, 'Update ran only once on joined resultset'); is ($fc->discard_changes->read_count, 30, 'Update did not touch outlier'); # try the same sql with forced multicolumn in -$schema->storage->_use_multicolumn_in (1); -$schema->storage->debugobj ($debugobj); -$schema->storage->debug (1); -throws_ok { $fks_multi->update ({ read_count => \ 'read_count + 1' }) } # this can't actually execute, we just need the "as_query" - qr/\QDBI Exception:/ or do { $sql = ''; @bind = () }; -$schema->storage->_use_multicolumn_in (undef); -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - -is_same_sql_bind ( - $sql, - \@bind, +$schema->is_executed_sql_bind( sub { + local $schema->storage->{_use_multicolumn_in} = 1; + + # this can't actually execute on sqlite + eval { $fks_multi->update ({ read_count => \ 'read_count + 1' }) }; +}, [[ 'UPDATE fourkeys SET read_count = read_count + 1 WHERE ( @@ -137,39 +127,44 @@ is_same_sql_bind ( ) ) ', + ( 1, 2) x 2, + 666, + ( 1, 2) x 2, + 'c', +]], 'Correct update-SQL with multicolumn in support' ); + +$schema->is_executed_sql_bind( sub { + $fks->search({ 'twokeys.artist' => { '!=' => 666 } })->update({ read_count => \ 'read_count + 1' }); +}, [ + [ 'BEGIN' ], [ - ("'1'", "'2'") x 2, - "'666'", - ("'1'", "'2'") x 2, - "'c'", + 'SELECT me.foo, me.bar, me.hello, me.goodbye + FROM fourkeys me + LEFT JOIN fourkeys_to_twokeys fourkeys_to_twokeys + ON fourkeys_to_twokeys.f_bar = me.bar AND fourkeys_to_twokeys.f_foo = me.foo AND fourkeys_to_twokeys.f_goodbye = me.goodbye AND fourkeys_to_twokeys.f_hello = me.hello + LEFT JOIN twokeys twokeys + ON twokeys.artist = fourkeys_to_twokeys.t_artist AND twokeys.cd = fourkeys_to_twokeys.t_cd + WHERE ( bar = ? OR bar = ? ) AND ( foo = ? OR foo = ? ) AND ( goodbye = ? OR goodbye = ? ) AND ( hello = ? OR hello = ? ) AND sensors != ? AND twokeys.artist != ? + GROUP BY me.foo, me.bar, me.hello, me.goodbye + ', + (1, 2) x 4, + 'c', + 666, ], - 'Correct update-SQL with multicolumn in support', -); - -# make a *premultiplied* join stick -my $fks_premulti = $fks->search({ 'twokeys.artist' => { '!=' => 666 } }); - -$schema->storage->debugobj ($debugobj); -$schema->storage->debug (1); -$fks_premulti->update ({ read_count => \ 'read_count + 1' }); -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - -is_same_sql_bind ( - $sql, - \@bind, - 'UPDATE fourkeys - SET read_count = read_count + 1 - WHERE ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? ) OR ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? )', - [ map { "'$_'" } ( (1) x 4, (2) x 4 ) ], - 'Correct update-SQL with premultiplied restricting join without pruning', -); + [ + 'UPDATE fourkeys + SET read_count = read_count + 1 + WHERE ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? ) OR ( bar = ? AND foo = ? AND goodbye = ? AND hello = ? ) + ', + ( (1) x 4, (2) x 4 ), + ], + [ 'COMMIT' ], +], 'Correct update-SQL with premultiplied restricting join without pruning' ); is ($fa->discard_changes->read_count, 13, 'Update ran only once on joined resultset'); is ($fb->discard_changes->read_count, 23, 'Update ran only once on joined resultset'); is ($fc->discard_changes->read_count, 30, 'Update did not touch outlier'); - # # Make sure multicolumn in or the equivalent functions correctly # @@ -253,43 +248,34 @@ is ($tkfks->count, $tkfk_cnt -= 1, 'Only one row deleted'); # check with sql-equality, as sqlite will accept most bad sql just fine -$schema->storage->debugobj ($debugobj); -$schema->storage->debug (1); - { my $rs = $schema->resultset('CD')->search( { 'me.year' => { '!=' => 2010 } }, ); - $rs->search({}, { join => 'liner_notes' })->delete; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $rs->search({}, { join => 'liner_notes' })->delete; + }, [[ 'DELETE FROM cd WHERE ( year != ? )', - ["'2010'"], - 'Non-restricting multijoins properly thrown out' - ); + 2010, + ]], 'Non-restricting multijoins properly thrown out' ); - $rs->search({}, { prefetch => 'liner_notes' })->delete; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $rs->search({}, { prefetch => 'liner_notes' })->delete; + }, [[ 'DELETE FROM cd WHERE ( year != ? )', - ["'2010'"], - 'Non-restricting multiprefetch thrown out' - ); + 2010, + ]], 'Non-restricting multiprefetch thrown out' ); - $rs->search({}, { prefetch => 'artist' })->delete; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $rs->search({}, { prefetch => 'artist' })->delete; + }, [[ 'DELETE FROM cd WHERE ( cdid IN ( SELECT me.cdid FROM cd me JOIN artist artist ON artist.artistid = me.artist WHERE ( me.year != ? ) ) )', - ["'2010'"], - 'Restricting prefetch left in, selector thrown out' - ); + 2010, + ]], 'Restricting prefetch left in, selector thrown out'); - # switch artist and cd to fully qualified table names - # make sure nothing is stripped out +### switch artist and cd to fully qualified table names +### make sure nothing is stripped out my $cd_rsrc = $schema->source('CD'); $cd_rsrc->name('main.cd'); $cd_rsrc->relationship_info($_)->{attrs}{cascade_delete} = 0 @@ -300,85 +286,80 @@ $schema->storage->debug (1); $art_rsrc->relationship_info($_)->{attrs}{cascade_delete} = 0 for $art_rsrc->relationships; - $rs->delete; - is_same_sql_bind ( - $sql, - \@bind, - 'DELETE FROM main.cd WHERE ( year != ? )', - ["'2010'"], - 'delete with fully qualified table name' - ); + $schema->is_executed_sql_bind( sub { + $rs->delete + }, [[ + 'DELETE FROM main.cd WHERE year != ?', + 2010, + ]], 'delete with fully qualified table name' ); $rs->create({ title => 'foo', artist => 1, year => 2000 }); - $rs->delete_all; - is_same_sql_bind ( - $sql, - \@bind, - 'DELETE FROM main.cd WHERE ( cdid = ? )', - ["'1'"], - 'delete_all with fully qualified table name' - ); - - $rs->create({ cdid => 42, title => 'foo', artist => 2, year => 2000 }); - $rs->find(42)->delete; - is_same_sql_bind ( - $sql, - \@bind, - 'DELETE FROM main.cd WHERE ( cdid = ? )', - ["'42'"], - 'delete of object from table with fully qualified name' - ); + $schema->is_executed_sql_bind( sub { + $rs->delete_all + }, [ + [ 'BEGIN' ], + [ + 'SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM main.cd me WHERE me.year != ?', + 2010, + ], + [ + 'DELETE FROM main.cd WHERE ( cdid = ? )', + 1, + ], + [ 'COMMIT' ], + ], 'delete_all with fully qualified table name' ); $rs->create({ cdid => 42, title => 'foo', artist => 2, year => 2000 }); - $rs->find(42)->related_resultset('artist')->delete; - is_same_sql_bind ( - $sql, - \@bind, + my $cd42 = $rs->find(42); + + $schema->is_executed_sql_bind( sub { + $cd42->delete + }, [[ + 'DELETE FROM main.cd WHERE cdid = ?', + 42, + ]], 'delete of object from table with fully qualified name' ); + + $schema->is_executed_sql_bind( sub { + $cd42->related_resultset('artist')->delete + }, [[ 'DELETE FROM main.artist WHERE ( artistid IN ( SELECT me.artistid FROM main.artist me WHERE ( me.artistid = ? ) ) )', - ["'2'"], - 'delete of related object from scalarref fully qualified named table', - ); + 2, + ]], 'delete of related object from scalarref fully qualified named table' ); + + my $art3 = $schema->resultset('Artist')->find(3); - $schema->resultset('Artist')->find(3)->related_resultset('cds')->delete; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $art3->related_resultset('cds')->delete; + }, [[ 'DELETE FROM main.cd WHERE ( artist = ? )', - ["'3'"], - 'delete of related object from fully qualified named table', - ); + 3, + ]], 'delete of related object from fully qualified named table' ); - $schema->resultset('Artist')->find(3)->cds_unordered->delete; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $art3->cds_unordered->delete; + }, [[ 'DELETE FROM main.cd WHERE ( artist = ? )', - ["'3'"], - 'delete of related object from fully qualified named table via relaccessor', - ); + 3, + ]], 'delete of related object from fully qualified named table via relaccessor' ); - $rs->search({}, { prefetch => 'artist' })->delete; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $rs->search({}, { prefetch => 'artist' })->delete; + }, [[ 'DELETE FROM main.cd WHERE ( cdid IN ( SELECT me.cdid FROM main.cd me JOIN main.artist artist ON artist.artistid = me.artist WHERE ( me.year != ? ) ) )', - ["'2010'"], - 'delete with fully qualified table name and subquery correct' - ); + 2010, + ]], 'delete with fully qualified table name and subquery correct' ); # check that as_subselect_rs works ok # inner query is untouched, then a selector # and an IN condition - $schema->resultset('CD')->search({ - 'me.cdid' => 1, - 'artist.name' => 'partytimecity', - }, { - join => 'artist', - })->as_subselect_rs->delete; - - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + $schema->resultset('CD')->search({ + 'me.cdid' => 1, + 'artist.name' => 'partytimecity', + }, { + join => 'artist', + })->as_subselect_rs->delete; + }, [[ ' DELETE FROM main.cd WHERE ( @@ -393,12 +374,9 @@ $schema->storage->debug (1); ) ) ', - ["'partytimecity'", "'1'"], - 'Delete from as_subselect_rs works correctly' - ); + 'partytimecity', + 1, + ]], 'Delete from as_subselect_rs works correctly' ); } -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - done_testing; diff --git a/t/row/find_one_has_many.t b/t/row/find_one_has_many.t index 5e1e953..ea7767f 100644 --- a/t/row/find_one_has_many.t +++ b/t/row/find_one_has_many.t @@ -4,8 +4,6 @@ use warnings; use Test::More; use lib qw(t/lib); use DBICTest; -use DBIC::DebugObj; -use DBIC::SqlMakerTest; my $schema = DBICTest->init_schema(); @@ -15,20 +13,20 @@ $schema->resultset('CD')->delete; my $artist = $schema->resultset("Artist")->create({ artistid => 21, name => 'Michael Jackson', rank => 20 }); my $cd = $artist->create_related('cds', { year => 1975, title => 'Compilation from 1975' }); -my ($sql, @bind); -local $schema->storage->{debug} = 1; -local $schema->storage->{debugobj} = DBIC::DebugObj->new(\$sql, \@bind); - -my $find_cd = $artist->find_related('cds',{title => 'Compilation from 1975'}); - -s/^'//, s/'\z// for @bind; # why does DBIC::DebugObj not do this? - -is_same_sql_bind ( - $sql, - \@bind, - 'SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me WHERE ( ( me.artist = ? AND me.title = ? ) ) ORDER BY year ASC', - [21, 'Compilation from 1975'], - 'find_related only uses foreign key condition once', -); +$schema->is_executed_sql_bind(sub { + my $find_cd = $artist->find_related('cds',{title => 'Compilation from 1975'}); +}, [ + [ + ' SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track + FROM cd me + WHERE me.artist = ? AND me.title = ? + ORDER BY year ASC + ', + [ { dbic_colname => "me.artist", sqlt_datatype => "integer" } + => 21 ], + [ { dbic_colname => "me.title", sqlt_datatype => "varchar", sqlt_size => 100 } + => "Compilation from 1975" ], + ] +], 'find_related only uses foreign key condition once' ); done_testing; diff --git a/t/search/preserve_original_rs.t b/t/search/preserve_original_rs.t index cb9a306..04dc9a8 100644 --- a/t/search/preserve_original_rs.t +++ b/t/search/preserve_original_rs.t @@ -7,9 +7,8 @@ use Test::Exception; use lib qw(t/lib); use DBICTest; use DBIC::SqlMakerTest; -use DBIC::DebugObj; -use Storable qw/dclone/; +use Storable 'dclone'; my $schema = DBICTest->init_schema(); diff --git a/t/sqlmaker/mysql.t b/t/sqlmaker/mysql.t index b5ce8a5..5b3f330 100644 --- a/t/sqlmaker/mysql.t +++ b/t/sqlmaker/mysql.t @@ -7,7 +7,6 @@ use lib qw(t/lib); use DBICTest; use DBICTest::Schema; use DBIC::SqlMakerTest; -use DBIC::DebugObj; my $schema = DBICTest::Schema->connect (DBICTest->_database, { quote_char => '`' }); # cheat @@ -17,54 +16,39 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' ); # check that double-subqueries are properly wrapped { - my ($sql, @bind); - my $debugobj = DBIC::DebugObj->new (\$sql, \@bind); - my $orig_debugobj = $schema->storage->debugobj; - my $orig_debug = $schema->storage->debug; - - $schema->storage->debugobj ($debugobj); - $schema->storage->debug (1); - # the expected SQL may seem wastefully nonsensical - this is due to # CD's tablename being \'cd', which triggers the "this can be anything" # mode, and forces a subquery. This in turn forces *another* subquery # because mysql is being mysql # Also we know it will fail - never deployed. All we care about is the - # SQL to compare - eval { $schema->resultset ('CD')->update({ genreid => undef }) }; - is_same_sql_bind ( - $sql, - \@bind, + # SQL to compare, hence the eval + $schema->is_executed_sql_bind( sub { + eval { $schema->resultset ('CD')->update({ genreid => undef }) } + },[[ 'UPDATE cd SET `genreid` = ? WHERE `cdid` IN ( SELECT * FROM ( SELECT `me`.`cdid` FROM cd `me` ) `_forced_double_subquery` )', - [ 'NULL' ], - 'Correct update-SQL with double-wrapped subquery', - ); + [ { dbic_colname => "genreid", sqlt_datatype => "integer" } => undef ], + ]], 'Correct update-SQL with double-wrapped subquery' ); # same comment as above - eval { $schema->resultset ('CD')->delete }; - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + eval { $schema->resultset ('CD')->delete } + }, [[ 'DELETE FROM cd WHERE `cdid` IN ( SELECT * FROM ( SELECT `me`.`cdid` FROM cd `me` ) `_forced_double_subquery` )', - [], - 'Correct delete-SQL with double-wrapped subquery', - ); + ]], 'Correct delete-SQL with double-wrapped subquery' ); # and a couple of really contrived examples (we test them live in t/71mysql.t) my $rs = $schema->resultset('Artist')->search({ name => { -like => 'baby_%' } }); my ($count_sql, @count_bind) = @${$rs->count_rs->as_query}; - eval { - $schema->resultset('Artist')->search( - { artistid => { - -in => $rs->get_column('artistid') - ->as_query - } }, - )->update({ name => \[ "CONCAT( `name`, '_bell_out_of_', $count_sql )", @count_bind ] }); - }; - - is_same_sql_bind ( - $sql, - \@bind, + $schema->is_executed_sql_bind( sub { + eval { + $schema->resultset('Artist')->search( + { artistid => { + -in => $rs->get_column('artistid') + ->as_query + } }, + )->update({ name => \[ "CONCAT( `name`, '_bell_out_of_', $count_sql )", @count_bind ] }); + } + }, [[ q( UPDATE `artist` SET `name` = CONCAT(`name`, '_bell_out_of_', ( @@ -84,18 +68,18 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' ); WHERE `name` LIKE ? ) `_forced_double_subquery` ) ), - [ ("'baby_%'") x 2 ], - ); - - eval { - $schema->resultset('CD')->search_related('artist', - { 'artist.name' => { -like => 'baby_with_%' } } - )->delete - }; - - is_same_sql_bind ( - $sql, - \@bind, + ( [ { dbic_colname => "name", sqlt_datatype => "varchar", sqlt_size => 100 } + => 'baby_%' ] + ) x 2 + ]]); + + $schema->is_executed_sql_bind( sub { + eval { + $schema->resultset('CD')->search_related('artist', + { 'artist.name' => { -like => 'baby_with_%' } } + )->delete + } + }, [[ q( DELETE FROM `artist` WHERE `artistid` IN ( @@ -109,11 +93,9 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' ); ) `_forced_double_subquery` ) ), - [ "'baby_with_%'" ], - ); - - $schema->storage->debugobj ($orig_debugobj); - $schema->storage->debug ($orig_debug); + [ { dbic_colname => "artist.name", sqlt_datatype => "varchar", sqlt_size => 100 } + => 'baby_with_%' ], + ]] ); } # Test support for straight joins diff --git a/t/sqlmaker/quotes.t b/t/sqlmaker/quotes.t index 84f2a3f..d3a8c8f 100644 --- a/t/sqlmaker/quotes.t +++ b/t/sqlmaker/quotes.t @@ -6,27 +6,29 @@ use Test::More; use lib qw(t/lib); use DBICTest; use DBIC::SqlMakerTest; -use DBIC::DebugObj; -my $schema = DBICTest->init_schema(); +my $schema = DBICTest->init_schema( no_deploy => 1 ); $schema->connection( @{ $schema->storage->_dbi_connect_info }, { AutoCommit => 1, quote_char => [qw/[ ]/] } ); -my ($sql, @bind); -$schema->storage->debugobj(DBIC::DebugObj->new(\$sql, \@bind)); -$schema->storage->debug(1); +my $rs = $schema->resultset('CD')->search( + { 'me.year' => 2001, 'artist.name' => 'Caterwauler McCrae' }, + { join => 'artist' } +)->count_rs; + +my $expected_bind = [ + [ { dbic_colname => "artist.name", sqlt_datatype => "varchar", sqlt_size => 100 } + => 'Caterwauler McCrae' ], + [ { dbic_colname => "me.year", sqlt_datatype => "varchar", sqlt_size => 100 } + => 2001 ], +]; -my $rs = $schema->resultset('CD')->search( - { 'me.year' => 2001, 'artist.name' => 'Caterwauler McCrae' }, - { join => 'artist' }); -my $expected_bind = ["'Caterwauler McCrae'", "'2001'"]; -eval { $rs->count }; is_same_sql_bind( - $sql, \@bind, - "SELECT COUNT( * ) FROM cd [me] JOIN [artist] [artist] ON ( [artist].[artistid] = [me].[artist] ) WHERE ( [artist].[name] = ? AND [me].[year] = ? )", + $rs->as_query, + "(SELECT COUNT( * ) FROM cd [me] JOIN [artist] [artist] ON [artist].[artistid] = [me].[artist] WHERE ( [artist].[name] = ? AND [me].[year] = ? ))", $expected_bind, 'got correct SQL for count query with bracket quoting' ); @@ -34,27 +36,32 @@ is_same_sql_bind( $schema->storage->sql_maker->quote_char('`'); $schema->storage->sql_maker->name_sep('.'); -eval { $rs->count }; -is_same_sql_bind( - $sql, \@bind, - "SELECT COUNT( * ) FROM cd `me` JOIN `artist` `artist` ON ( `artist`.`artistid` = `me`.`artist` ) WHERE ( `artist`.`name` = ? AND `me`.`year` = ? )", +is_same_sql_bind ( + $rs->as_query, + "(SELECT COUNT( * ) FROM cd `me` JOIN `artist` `artist` ON ( `artist`.`artistid` = `me`.`artist` ) WHERE ( `artist`.`name` = ? AND `me`.`year` = ? ))", $expected_bind, - 'got correct SQL for count query with quoting' + 'got correct SQL for count query with mysql quoting' ); -my $order = 'year DESC'; -$rs = $schema->resultset('CD')->search({}, - { 'order_by' => $order }); -eval { $rs->first }; -like($sql, qr/ORDER BY `\Q${order}\E`/, 'quoted ORDER BY with DESC (should use a scalarref anyway)'); +# !!! talk to ribasushi *explicitly* before modfying these tests !!! +{ + is_same_sql_bind( + $schema->resultset('CD')->search({}, { order_by => 'year DESC', columns => 'cdid' })->as_query, + '(SELECT `me`.`cdid` FROM cd `me` ORDER BY `year DESC`)', + [], + 'quoted ORDER BY with DESC (should use a scalarref anyway)' + ); -$rs = $schema->resultset('CD')->search({}, - { 'order_by' => \$order }); -eval { $rs->first }; -like($sql, qr/ORDER BY \Q${order}\E/, 'did not quote ORDER BY with scalarref'); + is_same_sql_bind( + $schema->resultset('CD')->search({}, { order_by => \'year DESC', columns => 'cdid' })->as_query, + '(SELECT `me`.`cdid` FROM cd `me` ORDER BY year DESC)', + [], + 'did not quote ORDER BY with scalarref', + ); +} -is( - $schema->storage->sql_maker->update('group', { name => 'Bill', order => 12 }), +is_same_sql( + scalar $schema->storage->sql_maker->update('group', { order => 12, name => 'Bill' }), 'UPDATE `group` SET `name` = ?, `order` = ?', 'quoted table names for UPDATE' ); diff --git a/t/storage/debug.t b/t/storage/debug.t index 6d8e94c..514b43b 100644 --- a/t/storage/debug.t +++ b/t/storage/debug.t @@ -6,7 +6,6 @@ use Test::More; use Test::Exception; use lib qw(t/lib); use DBICTest; -use DBIC::DebugObj; use DBIC::SqlMakerTest; use Path::Class qw/file/; @@ -19,6 +18,7 @@ unlink $lfn or die $! if -e $lfn; # make sure we are testing the vanilla debugger and not ::PrettyPrint +require DBIx::Class::Storage::Statistics; $schema->storage->debugobj(DBIx::Class::Storage::Statistics->new); ok ( $schema->storage->debug(1), 'debug' ); @@ -61,25 +61,45 @@ dies_ok { open(STDERR, '>&STDERRCOPY'); -# test trace output correctness for bind params +# test debugcb and debugobj protocol { - my ($sql, @bind); - $schema->storage->debugobj(DBIC::DebugObj->new(\$sql, \@bind)); - - my @cds = $schema->resultset('CD')->search( { artist => 1, cdid => { -between => [ 1, 3 ] }, } ); - is_same_sql_bind( - $sql, \@bind, - "SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me WHERE ( artist = ? AND (cdid BETWEEN ? AND ?) )", - [qw/'1' '1' '3'/], - 'got correct SQL with all bind parameters (debugcb)' - ); - - @cds = $schema->resultset('CD')->search( { artist => 1, cdid => { -between => [ 1, 3 ] }, } ); - is_same_sql_bind( - $sql, \@bind, - "SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me WHERE ( artist = ? AND (cdid BETWEEN ? AND ?) )", ["'1'", "'1'", "'3'"], - 'got correct SQL with all bind parameters (debugobj)' - ); + my $rs = $schema->resultset('CD')->search( { + artist => 1, + cdid => { -between => [ 1, 3 ] }, + title => { '!=' => \[ '?', undef ] } + }); + + my $sql_trace = 'SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me WHERE ( ( artist = ? AND ( cdid BETWEEN ? AND ? ) AND title != ? ) )'; + my @bind_trace = qw( '1' '1' '3' NULL ); # quotes are in fact part of the trace + + + my @args; + $schema->storage->debugcb(sub { push @args, @_ } ); + + $rs->all; + + is_deeply( \@args, [ + "SELECT", + sprintf( "%s: %s\n", $sql_trace, join ', ', @bind_trace ), + ]); + + { + package DBICTest::DebugObj; + our @ISA = 'DBIx::Class::Storage::Statistics'; + + sub query_start { + my $self = shift; + ( $self->{_traced_sql}, @{$self->{_traced_bind}} ) = @_; + } + } + + my $do = $schema->storage->debugobj(DBICTest::DebugObj->new); + + $rs->all; + + is( $do->{_traced_sql}, $sql_trace ); + + is_deeply ( $do->{_traced_bind}, \@bind_trace ); } done_testing; diff --git a/t/storage/nobindvars.t b/t/storage/nobindvars.t index d2dd840..b229756 100644 --- a/t/storage/nobindvars.t +++ b/t/storage/nobindvars.t @@ -4,17 +4,14 @@ use warnings; use Test::More; use lib qw(t/lib); use DBICTest; -use DBIC::DebugObj; -use DBIC::SqlMakerTest; -use DBI::Const::GetInfoType; { # Fake storage driver for SQLite + no bind variables package DBICTest::SQLite::NoBindVars; - use Class::C3; - use base qw/ - DBIx::Class::Storage::DBI::NoBindVars - DBIx::Class::Storage::DBI::SQLite - /; + use base qw( + DBIx::Class::Storage::DBI::NoBindVars + DBIx::Class::Storage::DBI::SQLite + ); + use mro 'c3'; } my $schema = DBICTest->init_schema (storage_type => 'DBICTest::SQLite::NoBindVars', no_populate => 1); @@ -35,26 +32,13 @@ my $it = $schema->resultset('Artist')->search( {}, is( $it->count, 3, "LIMIT count ok" ); # ask for 3 rows out of 7 artists -my ($sql, @bind); -my $orig_debugobj = $schema->storage->debugobj; -my $orig_debug = $schema->storage->debug; -$schema->storage->debugobj (DBIC::DebugObj->new (\$sql, \@bind) ); -$schema->storage->debug (1); - -is( $it->next->name, "Artist 2", "iterator->next ok" ); -$it->next; -$it->next; -is( $it->next, undef, "next past end of resultset ok" ); - -$schema->storage->debugobj ($orig_debugobj); -$schema->storage->debug ($orig_debug); - -is_same_sql_bind ( - $sql, - \@bind, - 'SELECT me.artistid, me.name, me.rank, me.charfield FROM artist me ORDER BY artistid LIMIT 3 OFFSET 2', - [], - 'Correctly interpolated SQL' -); +$schema->is_executed_sql_bind( sub { + is( $it->next->name, "Artist 2", "iterator->next ok" ); + $it->next; + $it->next; + is( $it->next, undef, "next past end of resultset ok" ); +}, [ + [ 'SELECT me.artistid, me.name, me.rank, me.charfield FROM artist me ORDER BY artistid LIMIT 3 OFFSET 2' ], +], 'Correctly interpolated SQL' ); done_testing; diff --git a/t/storage/savepoints.t b/t/storage/savepoints.t index fab7036..0c56afc 100644 --- a/t/storage/savepoints.t +++ b/t/storage/savepoints.t @@ -3,17 +3,30 @@ use warnings; use Test::More; use Test::Exception; -use DBIx::Class::Optional::Dependencies (); + +use lib qw(t/lib); +use DBICTest; + +{ + package # moar hide + DBICTest::SVPTracerObj; + + use base 'DBIx::Class::Storage::Statistics'; + + sub query_start { 'do notning'} + sub callback { 'dummy '} + + for my $svpcall (map { "svp_$_" } qw(begin rollback release)) { + no strict 'refs'; + *$svpcall = sub { $_[0]{uc $svpcall}++ }; + } +} my $env2optdep = { DBICTEST_PG => 'test_rdbms_pg', DBICTEST_MYSQL => 'test_rdbms_mysql', }; -use lib qw(t/lib); -use DBICTest; -use DBICTest::Stats; - my $schema; for ('', keys %$env2optdep) { SKIP: { @@ -56,9 +69,8 @@ for ('', keys %$env2optdep) { SKIP: { note "Testing $prefix"; - my $stats = DBICTest::Stats->new; - $schema->storage->debugobj($stats); - $schema->storage->debug(1); + local $schema->storage->{debugobj} = my $stats = DBICTest::SVPTracerObj->new; + local $schema->storage->{debug} = 1; $schema->resultset('Artist')->create({ name => 'foo' });