#!/usr/bin/perl -w
use strict;
use Test::More tests => 185;
BEGIN
{
require 't/test-lib.pl';
use_ok('Rose::DB::Object::Std');
use_ok('Rose::DB::Object::MakeMethods::Std');
}
our($PG_HAS_CHKPASS, $HAVE_PG, $HAVE_MYSQL, $HAVE_INFORMIX, $HAVE_SQLITE);
#
# PostgreSQL
#
SKIP: foreach my $db_type (qw(pg pg_with_schema))
{
skip("PostgreSQL tests", 99) unless($HAVE_PG);
Rose::DB->default_type($db_type);
my $o = MyPgObject->new(name => 'John');
ok(ref $o && $o->isa('MyPgObject'), "new() 1 - $db_type");
$o->flag2('true');
$o->date_created('now');
$o->last_modified($o->date_created);
$o->save_col(7);
$o->other_id(1);
ok($o->save, "save() 1 - $db_type");
ok($o->load, "load() 1 - $db_type");
my $o2 = MyPgObject->new(id => $o->id);
ok(ref $o2 && $o2->isa('MyPgObject'), "new() 2 - $db_type");
is($o2->bits->to_Bin, '00101', "bits() (bitfield default value) - $db_type");
ok($o2->load, "load() 2 - $db_type");
ok(!$o2->not_found, "not_found() 1 - $db_type");
is($o2->name, $o->name, "load() verify 1 - $db_type");
is($o2->date_created, $o->date_created, "load() verify 2 - $db_type");
is($o2->last_modified, $o->last_modified, "load() verify 3 - $db_type");
is($o2->status, 'active', "load() verify 4 (default value) - $db_type");
is($o2->flag, 1, "load() verify 5 (default boolean value) - $db_type");
is($o2->flag2, 1, "load() verify 6 (boolean value) - $db_type");
is($o2->save_col, 7, "load() verify 7 (aliased column) - $db_type");
is($o2->start->ymd, '1980-12-24', "load() verify 8 (date value) - $db_type");
is($o2->bits->to_Bin, '00101', "load() verify 9 (bitfield value) - $db_type");
$o2->name('John 2');
$o2->start('5/24/2001');
sleep(1); # keep the last modified dates from being the same
$o2->last_modified('now');
ok($o2->save, "save() 2 - $db_type");
ok($o2->load, "load() 3 - $db_type");
is($o2->date_created, $o->date_created, "save() verify 1 - $db_type");
ok($o2->last_modified ne $o->last_modified, "save() verify 2 - $db_type");
is($o2->start->ymd, '2001-05-24', "save() verify 3 (date value) - $db_type");
my $o3 = MyPgObject->new();
my $db = $o3->db or die $o3->error;
ok(ref $db && $db->isa('Rose::DB'), "db() - $db_type");
is($db->dbh, $o3->dbh, "dbh() - $db_type");
my $o4 = MyPgObject->new(id => 999);
ok(!$o4->load(speculative => 1), "load() nonexistent - $db_type");
ok($o4->not_found, "not_found() 2 - $db_type");
ok($o->load, "load() 4 - $db_type");
SKIP:
{
if($PG_HAS_CHKPASS)
{
$o->{'password_encrypted'} = ':8R1Kf2nOS0bRE';
ok($o->password_is('xyzzy'), "chkpass() 1 - $db_type");
is($o->password, 'xyzzy', "chkpass() 2 - $db_type");
$o->password('foobar');
ok($o->password_is('foobar'), "chkpass() 3 - $db_type");
is($o->password, 'foobar', "chkpass() 4 - $db_type");
ok($o->save, "save() 3 - $db_type");
}
else
{
skip("chkpass tests", 5);
}
}
my $o5 = MyPgObject->new(id => $o->id);
ok($o5->load, "load() 5 - $db_type");
SKIP:
{
if($PG_HAS_CHKPASS)
{
ok($o5->password_is('foobar'), "chkpass() 5 - $db_type");
is($o5->password, 'foobar', "chkpass() 6 - $db_type");
}
else
{
skip("chkpass tests", 2);
}
}
$o5->nums([ 4, 5, 6 ]);
ok($o5->save, "save() 4 - $db_type");
ok($o->load, "load() 6 - $db_type");
is($o5->nums->[0], 4, "load() verify 10 (array value) - $db_type");
is($o5->nums->[1], 5, "load() verify 11 (array value) - $db_type");
is($o5->nums->[2], 6, "load() verify 12 (array value) - $db_type");
my @a = $o5->nums;
is($a[0], 4, "load() verify 13 (array value) - $db_type");
is($a[1], 5, "load() verify 14 (array value) - $db_type");
is($a[2], 6, "load() verify 15 (array value) - $db_type");
is(@a, 3, "load() verify 16 (array value) - $db_type");
my $other = $o->other;
is(ref $other, 'MyPgObjectOther', 'object_by_id 1');
is($other->name, 'John', 'object_by_id 2');
ok($o->delete, "delete() - $db_type");
eval { $o->meta->alias_column(nonesuch => 'foo') };
ok($@, 'alias_column() nonesuch');
my($new_id, $old_id);
$old_id = $o->id;
eval { $new_id = $o->meta->generate_primary_key_value($o->db) };
ok(defined $new_id && $new_id > $o->id, 'generate_primary_key_value()');
$old_id = $new_id;
eval { ($new_id) = $o->meta->generate_primary_key_values($o->db) };
ok(defined $new_id && $new_id > $o->id, 'generate_primary_key_values()');
}
#
# MySQL
#
SKIP: foreach my $db_type ('mysql')
{
skip("MySQL tests", 28) unless($HAVE_MYSQL);
Rose::DB->default_type($db_type);
my $o = MyMySQLObject->new(name => 'John');
ok(ref $o && $o->isa('MyMySQLObject'), "new() 1 - $db_type");
$o->flag2('true');
$o->date_created('now');
$o->last_modified($o->date_created);
$o->save_col(22);
ok($o->save, "save() 1 - $db_type");
ok($o->load, "load() 1 - $db_type");
my $o2 = MyMySQLObject->new(id => $o->id);
ok(ref $o2 && $o2->isa('MyMySQLObject'), "new() 2 - $db_type");
is($o2->bits->to_Bin, '00101', "bits() (bitfield default value) - $db_type");
ok($o2->load, "load() 2 - $db_type");
ok(!$o2->not_found, "not_found() 1 - $db_type");
is($o2->name, $o->name, "load() verify 1 - $db_type");
is($o2->date_created, $o->date_created, "load() verify 2 - $db_type");
is($o2->last_modified, $o->last_modified, "load() verify 3 - $db_type");
is($o2->status, 'active', "load() verify 4 (default value) - $db_type");
is($o2->flag, 1, "load() verify 5 (default boolean value) - $db_type");
is($o2->flag2, 1, "load() verify 6 (boolean value) - $db_type");
is($o2->save_col, 22, "load() verify 7 (aliased column) - $db_type");
is($o2->start->ymd, '1980-12-24', "load() verify 8 (date value) - $db_type");
is($o2->bits->to_Bin, '00101', "load() verify 9 (bitfield value) - $db_type");
$o2->name('John 2');
$o2->start('5/24/2001');
sleep(1); # keep the last modified dates from being the same
$o2->last_modified('now');
ok($o2->save, "save() 2 - $db_type");
ok($o2->load, "load() 3 - $db_type");
is($o2->date_created, $o->date_created, "save() verify 1 - $db_type");
ok($o2->last_modified ne $o->last_modified, "save() verify 2 - $db_type");
is($o2->start->ymd, '2001-05-24', "save() verify 3 (date value) - $db_type");
my $o3 = MyMySQLObject->new();
my $db = $o3->db or die $o3->error;
ok(ref $db && $db->isa('Rose::DB'), "db() - $db_type");
is($db->dbh, $o3->dbh, "dbh() - $db_type");
my $o4 = MyMySQLObject->new(id => 999);
ok(!$o4->load(speculative => 1), "load() nonexistent - $db_type");
ok($o4->not_found, "not_found() 2 - $db_type");
ok($o->delete, "delete() - $db_type");
eval { $o->meta->alias_column(nonesuch => 'foo') };
ok($@, 'alias_column() nonesuch');
}
#
# Informix
#
SKIP: foreach my $db_type ('informix')
{
skip("Informix tests", 28) unless($HAVE_INFORMIX);
Rose::DB->default_type($db_type);
my $o = MyInformixObject->new(name => 'John');
ok(ref $o && $o->isa('MyInformixObject'), "new() 1 - $db_type");
$o->flag2('true');
$o->date_created('now');
$o->last_modified($o->date_created);
$o->save_col(22);
ok($o->save, "save() 1 - $db_type");
ok($o->load, "load() 1 - $db_type");
my $o2 = MyInformixObject->new(id => $o->id);
ok(ref $o2 && $o2->isa('MyInformixObject'), "new() 2 - $db_type");
is($o2->bits->to_Bin, '00101', "bits() (bitfield default value) - $db_type");
ok($o2->load, "load() 2 - $db_type");
ok(!$o2->not_found, "not_found() 1 - $db_type");
is($o2->name, $o->name, "load() verify 1 - $db_type");
is($o2->date_created, $o->date_created, "load() verify 2 - $db_type");
is($o2->last_modified, $o->last_modified, "load() verify 3 - $db_type");
is($o2->status, 'active', "load() verify 4 (default value) - $db_type");
is($o2->flag, 1, "load() verify 5 (default boolean value) - $db_type");
is($o2->flag2, 1, "load() verify 6 (boolean value) - $db_type");
is($o2->save_col, 22, "load() verify 7 (aliased column) - $db_type");
is($o2->start->ymd, '1980-12-24', "load() verify 8 (date value) - $db_type");
is($o2->bits->to_Bin, '00101', "load() verify 9 (bitfield value) - $db_type");
$o2->name('John 2');
$o2->start('5/24/2001');
sleep(1); # keep the last modified dates from being the same
$o2->last_modified('now');
ok($o2->save, "save() 2 - $db_type");
ok($o2->load, "load() 3 - $db_type");
is($o2->date_created, $o->date_created, "save() verify 1 - $db_type");
ok($o2->last_modified ne $o->last_modified, "save() verify 2 - $db_type");
is($o2->start->ymd, '2001-05-24', "save() verify 3 (date value) - $db_type");
my $o3 = MyInformixObject->new();
my $db = $o3->db or die $o3->error;
ok(ref $db && $db->isa('Rose::DB'), "db() - $db_type");
is($db->dbh, $o3->dbh, "dbh() - $db_type");
my $o4 = MyInformixObject->new(id => 999);
ok(!$o4->load(speculative => 1), "load() nonexistent - $db_type");
ok($o4->not_found, "not_found() 2 - $db_type");
ok($o->delete, "delete() - $db_type");
eval { $o->meta->alias_column(nonesuch => 'foo') };
ok($@, 'alias_column() nonesuch');
}
#
# SQLite
#
SKIP: foreach my $db_type ('sqlite')
{
skip("Informix tests", 28) unless($HAVE_SQLITE);
Rose::DB->default_type($db_type);
my $o = MySQLiteObject->new(name => 'John');
ok(ref $o && $o->isa('MySQLiteObject'), "new() 1 - $db_type");
$o->flag2('true');
$o->date_created('now');
$o->last_modified($o->date_created);
$o->save_col(22);
ok($o->save, "save() 1 - $db_type");
ok($o->load, "load() 1 - $db_type");
my $o2 = MySQLiteObject->new(id => $o->id);
ok(ref $o2 && $o2->isa('MySQLiteObject'), "new() 2 - $db_type");
is($o2->bits->to_Bin, '00101', "bits() (bitfield default value) - $db_type");
ok($o2->load, "load() 2 - $db_type");
ok(!$o2->not_found, "not_found() 1 - $db_type");
is($o2->name, $o->name, "load() verify 1 - $db_type");
is($o2->date_created, $o->date_created, "load() verify 2 - $db_type");
is($o2->last_modified, $o->last_modified, "load() verify 3 - $db_type");
is($o2->status, 'active', "load() verify 4 (default value) - $db_type");
is($o2->flag, 1, "load() verify 5 (default boolean value) - $db_type");
is($o2->flag2, 1, "load() verify 6 (boolean value) - $db_type");
is($o2->save_col, 22, "load() verify 7 (aliased column) - $db_type");
is($o2->start->ymd, '1980-12-24', "load() verify 8 (date value) - $db_type");
is($o2->bits->to_Bin, '00101', "load() verify 9 (bitfield value) - $db_type");
$o2->name('John 2');
$o2->start('5/24/2001');
sleep(1); # keep the last modified dates from being the same
$o2->last_modified('now');
ok($o2->save, "save() 2 - $db_type");
ok($o2->load, "load() 3 - $db_type");
is($o2->date_created, $o->date_created, "save() verify 1 - $db_type");
ok($o2->last_modified ne $o->last_modified, "save() verify 2 - $db_type");
is($o2->start->ymd, '2001-05-24', "save() verify 3 (date value) - $db_type");
my $o3 = MySQLiteObject->new();
my $db = $o3->db or die $o3->error;
ok(ref $db && $db->isa('Rose::DB'), "db() - $db_type");
is($db->dbh, $o3->dbh, "dbh() - $db_type");
my $o4 = MySQLiteObject->new(id => 999);
ok(!$o4->load(speculative => 1), "load() nonexistent - $db_type");
ok($o4->not_found, "not_found() 2 - $db_type");
ok($o->delete, "delete() - $db_type");
eval { $o->meta->alias_column(nonesuch => 'foo') };
ok($@, 'alias_column() nonesuch');
}
BEGIN
{
#
# PostgreSQL
#
my $dbh;
eval
{
$dbh = Rose::DB->new('pg_admin')->retain_dbh()
or die Rose::DB->error;
};
if(!$@ && $dbh)
{
our $HAVE_PG = 1;
# Drop existing table and create schema, ignoring errors
{
local $dbh->{'RaiseError'} = 0;
local $dbh->{'PrintError'} = 0;
$dbh->do('DROP TABLE rose_db_object_test');
$dbh->do('DROP TABLE rose_db_object_other');
$dbh->do('DROP TABLE rose_db_object_private.rose_db_object_test');
$dbh->do('DROP TABLE rose_db_object_private.rose_db_object_other');
$dbh->do('DROP TABLE rose_db_object_chkpass_test');
$dbh->do('CREATE SCHEMA rose_db_object_private');
}
our $PG_HAS_CHKPASS = pg_has_chkpass();
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
id SERIAL NOT NULL PRIMARY KEY,
@{[ $PG_HAS_CHKPASS ? 'password CHKPASS,' : '' ]}
name VARCHAR(32) NOT NULL,
flag BOOLEAN NOT NULL,
flag2 BOOLEAN,
status VARCHAR(32) DEFAULT 'active',
bits BIT(5) NOT NULL DEFAULT B'00101',
start DATE,
save INT,
nums INT[],
other_id INT,
last_modified TIMESTAMP NOT NULL DEFAULT 'now',
date_created TIMESTAMP NOT NULL DEFAULT 'now'
)
EOF
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other
(
id SERIAL PRIMARY KEY,
name VARCHAR(32) NOT NULL
)
EOF
$dbh->do(<<"EOF");
INSERT INTO rose_db_object_other (id, name) VALUES (1, 'John')
EOF
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_private.rose_db_object_test
(
id SERIAL NOT NULL PRIMARY KEY,
@{[ $PG_HAS_CHKPASS ? 'password CHKPASS,' : '' ]}
name VARCHAR(32) NOT NULL,
flag BOOLEAN NOT NULL,
flag2 BOOLEAN,
status VARCHAR(32) DEFAULT 'active',
bits BIT(5) NOT NULL DEFAULT B'00101',
start DATE,
save INT,
nums INT[],
other_id INT,
last_modified TIMESTAMP NOT NULL DEFAULT 'now',
date_created TIMESTAMP NOT NULL DEFAULT 'now'
)
EOF
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_private.rose_db_object_other
(
id SERIAL PRIMARY KEY,
name VARCHAR(32) NOT NULL
)
EOF
$dbh->do(<<"EOF");
INSERT INTO rose_db_object_private.rose_db_object_other (id, name) VALUES (1, 'John')
EOF
$dbh->disconnect;
# Create test subclasses
package MyPgObjectOther;
our @ISA = qw(Rose::DB::Object::Std);
sub init_db { Rose::DB->new('pg') }
MyPgObjectOther->meta->table('rose_db_object_other');
MyPgObjectOther->meta->columns
(
id => { primary_key => 1 },
'name',
);
MyPgObjectOther->meta->initialize;
package MyPgObject;
our @ISA = qw(Rose::DB::Object::Std);
sub init_db { Rose::DB->new('pg') }
MyPgObject->meta->table('rose_db_object_test');
MyPgObject->meta->columns
(
'name',
id => { primary_key => 1 },
($PG_HAS_CHKPASS ? (password => { type => 'chkpass' }) : ()),
flag => { type => 'boolean', default => 1 },
flag2 => { type => 'boolean' },
status => { default => 'active' },
start => { type => 'date', default => '12/24/1980' },
save => { type => 'scalar' },
nums => { type => 'array' },
bits => { type => 'bitfield', bits => 5, default => 101 },
other_id => { type => 'int' },
last_modified => { type => 'timestamp' },
date_created => { type => 'timestamp' },
);
Rose::DB::Object::MakeMethods::Std->import
(
object_by_id =>
[
'other' => { class => 'MyPgObjectOther' },
],
);
eval { MyPgObject->meta->initialize };
Test::More::ok($@, 'meta->initialize() reserved method');
MyPgObject->meta->alias_column(save => 'save_col');
MyPgObject->meta->initialize(preserve_existing => 1);
}
#
# MySQL
#
my $db_version;
eval
{
my $db = Rose::DB->new('mysql_admin');
$dbh = $db->retain_dbh() or die Rose::DB->error;
$db_version = $db->database_version;
};
if(!$@ && $dbh)
{
our $HAVE_MYSQL = 1;
# Drop existing table and create schema, ignoring errors
{
local $dbh->{'RaiseError'} = 0;
local $dbh->{'PrintError'} = 0;
$dbh->do('DROP TABLE rose_db_object_test');
}
# MySQL 5.0.3 or later has a completely stupid "native" BIT type
my $bit_col =
($db_version >= 5_000_003) ?
q(bits BIT(5) NOT NULL DEFAULT B'00101') :
q(bits BIT(5) NOT NULL DEFAULT '00101');
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(32) NOT NULL,
flag TINYINT(1) NOT NULL,
flag2 TINYINT(1),
status VARCHAR(32) DEFAULT 'active',
$bit_col,
start DATE,
save INT,
last_modified TIMESTAMP,
date_created DATETIME
)
EOF
$dbh->disconnect;
# Create test subclass
package MyMySQLObject;
our @ISA = qw(Rose::DB::Object::Std);
sub init_db { Rose::DB->new('mysql') }
MyMySQLObject->meta->allow_inline_column_values(1);
MyMySQLObject->meta->table('rose_db_object_test');
MyMySQLObject->meta->columns
(
'name',
id => { primary_key => 1 },
flag => { type => 'boolean', default => 1 },
flag2 => { type => 'boolean' },
status => { default => 'active' },
start => { type => 'date', default => '12/24/1980' },
save => { type => 'scalar' },
bits => { type => 'bitfield', bits => 5, default => 101 },
last_modified => { type => 'timestamp' },
date_created => { type => 'datetime' },
);
eval { MyMySQLObject->meta->initialize };
Test::More::ok($@, 'meta->initialize() reserved method');
MyMySQLObject->meta->alias_column(save => 'save_col');
MyMySQLObject->meta->initialize(preserve_existing => 1);
}
#
# Informix
#
eval
{
$dbh = Rose::DB->new('informix_admin')->retain_dbh()
or die Rose::DB->error;
};
if(!$@ && $dbh)
{
our $HAVE_INFORMIX = 1;
# Drop existing table and create schema, ignoring errors
{
local $dbh->{'RaiseError'} = 0;
local $dbh->{'PrintError'} = 0;
$dbh->do('DROP TABLE rose_db_object_test');
}
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
id SERIAL NOT NULL PRIMARY KEY,
name VARCHAR(32) NOT NULL,
flag BOOLEAN NOT NULL,
flag2 BOOLEAN,
status VARCHAR(32) DEFAULT 'active',
bits VARCHAR(5) DEFAULT '00101' NOT NULL,
start DATE,
save INT,
last_modified DATETIME YEAR TO FRACTION(5),
date_created DATETIME YEAR TO FRACTION(5)
)
EOF
$dbh->disconnect;
# Create test subclass
package MyInformixObject;
our @ISA = qw(Rose::DB::Object::Std);
sub init_db { Rose::DB->new('informix') }
MyInformixObject->meta->table('rose_db_object_test');
MyInformixObject->meta->columns
(
'name',
id => { primary_key => 1 },
flag => { type => 'boolean', default => 1 },
flag2 => { type => 'boolean' },
status => { default => 'active' },
start => { type => 'date', default => '12/24/1980' },
save => { type => 'scalar' },
bits => { type => 'bitfield', bits => 5, default => 101 },
last_modified => { type => 'timestamp' },
date_created => { type => 'timestamp' },
);
eval { MyInformixObject->meta->initialize };
Test::More::ok($@, 'meta->initialize() reserved method');
MyInformixObject->meta->alias_column(save => 'save_col');
MyInformixObject->meta->initialize(preserve_existing => 1);
}
#
# SQLite
#
eval
{
$dbh = Rose::DB->new('sqlite_admin')->retain_dbh()
or die Rose::DB->error;
};
if(!$@ && $dbh)
{
our $HAVE_SQLITE = 1;
# Drop existing table and create schema, ignoring errors
{
local $dbh->{'RaiseError'} = 0;
local $dbh->{'PrintError'} = 0;
$dbh->do('DROP TABLE rose_db_object_test');
}
$dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(32) NOT NULL,
flag BOOLEAN NOT NULL,
flag2 BOOLEAN,
status VARCHAR(32) DEFAULT 'active',
bits VARCHAR(5) DEFAULT '00101' NOT NULL,
start DATE,
save INT,
last_modified TIMESTAMP,
date_created TIMESTAMP
)
EOF
$dbh->disconnect;
# Create test subclass
package MySQLiteObject;
our @ISA = qw(Rose::DB::Object::Std);
sub init_db { Rose::DB->new('sqlite') }
MySQLiteObject->meta->table('rose_db_object_test');
MySQLiteObject->meta->columns
(
'name',
id => { primary_key => 1 },
flag => { type => 'boolean', default => 1 },
flag2 => { type => 'boolean' },
status => { default => 'active' },
start => { type => 'date', default => '12/24/1980' },
save => { type => 'scalar' },
bits => { type => 'bitfield', bits => 5, default => 101 },
last_modified => { type => 'timestamp' },
date_created => { type => 'timestamp' },
);
eval { MySQLiteObject->meta->initialize };
Test::More::ok($@, 'meta->initialize() reserved method');
MySQLiteObject->meta->alias_column(save => 'save_col');
MySQLiteObject->meta->initialize(preserve_existing => 1);
}
}
END
{
# Delete test table
if($HAVE_PG)
{
# PostgreSQL
my $dbh = Rose::DB->new('pg_admin')->retain_dbh()
or die Rose::DB->error;
$dbh->do('DROP TABLE rose_db_object_test');
$dbh->do('DROP TABLE rose_db_object_other');
$dbh->do('DROP TABLE rose_db_object_private.rose_db_object_test');
$dbh->do('DROP TABLE rose_db_object_private.rose_db_object_other');
$dbh->do('DROP SCHEMA rose_db_object_private CASCADE');
$dbh->disconnect;
}
if($HAVE_MYSQL)
{
# MySQL
my $dbh = Rose::DB->new('mysql_admin')->retain_dbh()
or die Rose::DB->error;
$dbh->do('DROP TABLE rose_db_object_test');
$dbh->disconnect;
}
if($HAVE_INFORMIX)
{
# Informix
my $dbh = Rose::DB->new('informix_admin')->retain_dbh()
or die Rose::DB->error;
$dbh->do('DROP TABLE rose_db_object_test');
$dbh->disconnect;
}
if($HAVE_SQLITE)
{
# SQLite
my $dbh = Rose::DB->new('sqlite_admin')->retain_dbh()
or die Rose::DB->error;
$dbh->do('DROP TABLE rose_db_object_test');
$dbh->disconnect;
}
}