use DBICTest;
use DBIx::Class::_Util qw(sigwarn_silencer modver_gt_or_eq);
-# savepoints test
-{
- my $schema = DBICTest->init_schema(auto_savepoint => 1);
-
- my $ars = $schema->resultset('Artist');
-
- # test two-phase commit and inner transaction rollback from nested transactions
- $schema->txn_do(sub {
- $ars->create({ name => 'in_outer_transaction' });
- $schema->txn_do(sub {
- $ars->create({ name => 'in_inner_transaction' });
- });
- ok($ars->search({ name => 'in_inner_transaction' })->first,
- 'commit from inner transaction visible in outer transaction');
- throws_ok {
- $schema->txn_do(sub {
- $ars->create({ name => 'in_inner_transaction_rolling_back' });
- die 'rolling back inner transaction';
- });
- } qr/rolling back inner transaction/, 'inner transaction rollback executed';
- $ars->create({ name => 'in_outer_transaction2' });
- });
-
- ok($ars->search({ name => 'in_outer_transaction' })->first,
- 'commit from outer transaction');
- ok($ars->search({ name => 'in_outer_transaction2' })->first,
- 'second commit from outer transaction');
- ok($ars->search({ name => 'in_inner_transaction' })->first,
- 'commit from inner transaction');
- is $ars->search({ name => 'in_inner_transaction_rolling_back' })->first,
- undef,
- 'rollback from inner transaction';
-}
-
# check that we work somewhat OK with braindead SQLite transaction handling
#
# As per https://metacpan.org/source/ADAMK/DBD-SQLite-1.37/lib/DBD/SQLite.pm#L921
use warnings;
use Test::More;
+use Test::Exception;
use DBIx::Class::Optional::Dependencies ();
my $env2optdep = {
- DBICTEST_PG => 'rdbms_pg',
+ DBICTEST_PG => 'test_rdbms_pg',
DBICTEST_MYSQL => 'test_rdbms_mysql',
};
-plan skip_all => join (' ',
- 'Set $ENV{DBICTEST_PG_DSN} and/or $ENV{DBICTEST_MYSQL_DSN} _USER and _PASS to run these tests.',
-) unless grep { $ENV{"${_}_DSN"} } keys %$env2optdep;
-
use lib qw(t/lib);
use DBICTest;
use DBICTest::Stats;
my $schema;
-for my $prefix (keys %$env2optdep) { SKIP: {
- my ($dsn, $user, $pass) = map { $ENV{"${prefix}_$_"} } qw/DSN USER PASS/;
+for ('', keys %$env2optdep) { SKIP: {
- skip ("Skipping tests with $prefix: set \$ENV{${prefix}_DSN} _USER and _PASS", 1)
- unless $dsn;
+ my $prefix;
- skip ("Testing with ${prefix}_DSN needs " . DBIx::Class::Optional::Dependencies->req_missing_for( $env2optdep->{$prefix} ), 1)
- unless DBIx::Class::Optional::Dependencies->req_ok_for($env2optdep->{$prefix});
+ if ($prefix = $_) {
+ my ($dsn, $user, $pass) = map { $ENV{"${prefix}_$_"} } qw/DSN USER PASS/;
- $schema = DBICTest::Schema->connect ($dsn,$user,$pass,{ auto_savepoint => 1 });
+ skip ("Skipping tests with $prefix: set \$ENV{${prefix}_DSN} _USER and _PASS", 1)
+ unless $dsn;
- my $create_sql;
- $schema->storage->ensure_connected;
- if ($schema->storage->isa('DBIx::Class::Storage::DBI::Pg')) {
- $create_sql = "CREATE TABLE artist (artistid serial PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10))";
- $schema->storage->dbh->do('SET client_min_messages=WARNING');
- }
- elsif ($schema->storage->isa('DBIx::Class::Storage::DBI::mysql')) {
- $create_sql = "CREATE TABLE artist (artistid INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10)) ENGINE=InnoDB";
+ skip ("Testing with ${prefix}_DSN needs " . DBIx::Class::Optional::Dependencies->req_missing_for( $env2optdep->{$prefix} ), 1)
+ unless DBIx::Class::Optional::Dependencies->req_ok_for($env2optdep->{$prefix});
+
+ $schema = DBICTest::Schema->connect ($dsn,$user,$pass,{ auto_savepoint => 1 });
+
+ my $create_sql;
+ $schema->storage->ensure_connected;
+ if ($schema->storage->isa('DBIx::Class::Storage::DBI::Pg')) {
+ $create_sql = "CREATE TABLE artist (artistid serial PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10))";
+ $schema->storage->dbh->do('SET client_min_messages=WARNING');
+ }
+ elsif ($schema->storage->isa('DBIx::Class::Storage::DBI::mysql')) {
+ $create_sql = "CREATE TABLE artist (artistid INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10)) ENGINE=InnoDB";
+ }
+ else {
+ skip( 'Untested driver ' . $schema->storage, 1 );
+ }
+
+ $schema->storage->dbh_do (sub {
+ $_[1]->do('DROP TABLE IF EXISTS artist');
+ $_[1]->do($create_sql);
+ });
}
else {
- skip( 'Untested driver ' . $schema->storage, 1 );
+ $prefix = 'SQLite Internal DB';
+ $schema = DBICTest->init_schema( no_populate => 1, auto_savepoint => 1 );
}
note "Testing $prefix";
$schema->storage->debugobj($stats);
$schema->storage->debug(1);
- $schema->storage->dbh->do ('DROP TABLE IF EXISTS artist');
- $schema->storage->dbh->do ($create_sql);
-
$schema->resultset('Artist')->create({ name => 'foo' });
$schema->txn_begin;
$arty->update({ name => 'gphat' });
$arty->discard_changes;
cmp_ok($arty->name, 'eq', 'gphat', 'name changed');
+
# Active: 0 1 2
# Rollback doesn't DESTROY the savepoint, it just rolls back to the value
# at its conception
# Active: 0 1 2 3
$schema->svp_begin('testing3');
$arty->update({ name => 'coryg' });
+
# Active: 0 1 2 3 4
$schema->svp_begin('testing4');
$arty->update({ name => 'watson' });
# Release 3, which implicitly releases 4
# Active: 0 1 2
$schema->svp_release('testing3');
+
$arty->discard_changes;
cmp_ok($arty->name, 'eq', 'watson', 'release left data');
+
# This rolls back savepoint 2
# Active: 0 1 2
$schema->svp_rollback;
+
$arty->discard_changes;
cmp_ok($arty->name, 'eq', 'yourmom', 'rolled back to 2');
$schema->txn_commit;
+ is_deeply( $schema->storage->savepoints, [], 'All savepoints forgotten' );
+
# And now to see if txn_do will behave correctly
$schema->txn_do (sub {
my $artycp = $arty;
$arty->update;
});
+ is_deeply( $schema->storage->savepoints, [], 'All savepoints forgotten' );
+
$arty->discard_changes;
is($arty->name,'Miff','auto_savepoint worked');
cmp_ok($stats->{'SVP_ROLLBACK'},'==',5,'Correct number of savepoint rollbacks');
+### test originally written for SQLite exclusively (git blame -w -C -M)
+ # test two-phase commit and inner transaction rollback from nested transactions
+ my $ars = $schema->resultset('Artist');
+
+ $schema->txn_do(sub {
+ $ars->create({ name => 'in_outer_transaction' });
+ $schema->txn_do(sub {
+ $ars->create({ name => 'in_inner_transaction' });
+ });
+ ok($ars->search({ name => 'in_inner_transaction' })->first,
+ 'commit from inner transaction visible in outer transaction');
+ throws_ok {
+ $schema->txn_do(sub {
+ $ars->create({ name => 'in_inner_transaction_rolling_back' });
+ die 'rolling back inner transaction';
+ });
+ } qr/rolling back inner transaction/, 'inner transaction rollback executed';
+ $ars->create({ name => 'in_outer_transaction2' });
+ });
+
+ is_deeply( $schema->storage->savepoints, [], 'All savepoints forgotten' );
+
+ ok($ars->search({ name => 'in_outer_transaction' })->first,
+ 'commit from outer transaction');
+ ok($ars->search({ name => 'in_outer_transaction2' })->first,
+ 'second commit from outer transaction');
+ ok($ars->search({ name => 'in_inner_transaction' })->first,
+ 'commit from inner transaction');
+ is $ars->search({ name => 'in_inner_transaction_rolling_back' })->first,
+ undef,
+ 'rollback from inner transaction';
+
+### cleanupz
$schema->storage->dbh->do ("DROP TABLE artist");
}}