#!/usr/bin/perl -w

use strict;

use Test::More tests => 192;

BEGIN 
{
  require 't/test-lib.pl';
  use_ok('Rose::DB::Object');
}

our($PG_HAS_CHKPASS, $HAVE_PG, $HAVE_MYSQL_WITH_INNODB, $HAVE_INFORMIX);

#
# Postgres
#

SKIP: foreach my $db_type ('pg')
{
  skip("Postgres tests", 72)  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);

  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 $oo1 = MyPgOtherObject->new(k1 => 1, k2 => 2, k3 => 3, name => 'one');
  ok($oo1->save, 'other object save() 1');

  my $oo2 = MyPgOtherObject->new(k1 => 11, k2 => 12, k3 => 13, name => 'two');
  ok($oo2->save, 'other object save() 2');

  my $other2 = MyPgOtherObject2->new(id2 => 12, name => 'twelve');
  ok($other2->save, 'other 2 object save() 1');

  my $other3 = MyPgOtherObject3->new(id3 => 13, name => 'thirteen');
  ok($other3->save, 'other 3 object save() 1');

  my $other4 = MyPgOtherObject4->new(id4 => 14, name => 'fourteen');
  ok($other4->save, 'other 4 object save() 1');

  is($o->fother, undef, 'fother() 1');
  is($o->fother2, undef, 'fother2() 1');
  is($o->fother3, undef, 'fother3() 1');
  is($o->my_pg_other_object, undef, 'my_pg_other_object() 1');

  $o->fother_id2(12);
  $o->fother_id3(13);
  $o->fother_id4(14);
  $o->fkone(1);
  $o->fk2(2);
  $o->fk3(3);

  my $obj = $o->my_pg_other_object or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyPgOtherObject', 'my_pg_other_object() 2');
  is($obj->name, 'one', 'my_pg_other_object() 3');

  $obj = $o->fother or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyPgOtherObject2', 'fother() 2');
  is($obj->name, 'twelve', 'fother() 3');

  $obj = $o->fother2 or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyPgOtherObject3', 'fother2() 2');
  is($obj->name, 'thirteen', 'fother2() 3');

  $obj = $o->fother3 or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyPgOtherObject4', 'fother3() 2');
  is($obj->name, 'fourteen', 'fother3() 3');

  $o->my_pg_other_object(undef);
  $o->fkone(11);
  $o->fk2(12);
  $o->fk3(13);

  $obj = $o->my_pg_other_object or warn "# ", $o->error, "\n";

  is(ref $obj, 'MyPgOtherObject', 'my_pg_other_object() 4');
  is($obj->name, 'two', 'my_pg_other_object() 5');

  ok($o->delete, "delete() - $db_type");

  eval { $o->meta->alias_column(nonesuch => 'foo') };
  ok($@, 'alias_column() nonesuch');

  #
  # Test code generation
  #

  is(MyPgObject->meta->perl_foreign_keys_definition,
     <<'EOF', "perl_foreign_keys_definition 1 - $db_type");
__PACKAGE__->meta->foreign_keys(
    fother => {
        class => 'MyPgOtherObject2',
        key_columns => {
            fother_id2 => 'id2',
        },
    },

    fother2 => {
        class => 'MyPgOtherObject3',
        key_columns => {
            fother_id3 => 'id3',
        },
    },

    fother3 => {
        class => 'MyPgOtherObject4',
        key_columns => {
            fother_id4 => 'id4',
        },
    },

    my_pg_other_object => {
        class => 'MyPgOtherObject',
        key_columns => {
            fk1 => 'k1',
            fk2 => 'k2',
            fk3 => 'k3',
        },
    },
);
EOF

  is(MyPgObject->meta->perl_foreign_keys_definition(braces => 'bsd', indent => 2),
     <<'EOF', "perl_foreign_keys_definition 2 - $db_type");
__PACKAGE__->meta->foreign_keys
(
  fother => 
  {
    class => 'MyPgOtherObject2',
    key_columns => 
    {
      fother_id2 => 'id2',
    },
  },

  fother2 => 
  {
    class => 'MyPgOtherObject3',
    key_columns => 
    {
      fother_id3 => 'id3',
    },
  },

  fother3 => 
  {
    class => 'MyPgOtherObject4',
    key_columns => 
    {
      fother_id4 => 'id4',
    },
  },

  my_pg_other_object => 
  {
    class => 'MyPgOtherObject',
    key_columns => 
    {
      fk1 => 'k1',
      fk2 => 'k2',
      fk3 => 'k3',
    },
  },
);
EOF

  is(MyPgObject->meta->perl_class_definition,
     <<'EOF', "perl_class_definition 1 - $db_type");
package MyPgObject;

use strict;

use Rose::DB::Object
our @ISA = qw(Rose::DB::Object);

__PACKAGE__->meta->table('rose_db_object_test');

__PACKAGE__->meta->columns(
    bits          => { type => 'bitfield', bits => 5, default => '00101', not_null => 1 },
    date_created  => { type => 'timestamp' },
    fk1           => { type => 'integer', method_name => 'fkone' },
    fk2           => { type => 'integer' },
    fk3           => { type => 'integer' },
    flag          => { type => 'boolean', default => 'true', not_null => 1 },
    flag2         => { type => 'boolean' },
    fother_id2    => { type => 'integer' },
    fother_id3    => { type => 'integer' },
    fother_id4    => { type => 'integer' },
    id            => { type => 'integer', not_null => 1 },
    last_modified => { type => 'timestamp' },
    name          => { type => 'varchar', length => 32, not_null => 1 },
    nums          => { type => 'array' },
    password      => { type => 'chkpass' },
    save          => { type => 'integer', method_name => 'save_col' },
    start         => { type => 'date', default => '1980-12-24' },
    status        => { type => 'varchar', default => 'active', length => 32 },
);

__PACKAGE__->meta->primary_key_columns([ 'id' ]);

__PACKAGE__->meta->foreign_keys(
    fother => {
        class => 'MyPgOtherObject2',
        key_columns => {
            fother_id2 => 'id2',
        },
    },

    fother2 => {
        class => 'MyPgOtherObject3',
        key_columns => {
            fother_id3 => 'id3',
        },
    },

    fother3 => {
        class => 'MyPgOtherObject4',
        key_columns => {
            fother_id4 => 'id4',
        },
    },

    my_pg_other_object => {
        class => 'MyPgOtherObject',
        key_columns => {
            fk1 => 'k1',
            fk2 => 'k2',
            fk3 => 'k3',
        },
    },
);

__PACKAGE__->meta->initialize;

1;
EOF

  is(MyPgObject->meta->perl_class_definition(braces => 'bsd', indent => 2),
     <<'EOF', "perl_class_definition 2 - $db_type");
package MyPgObject;

use strict;

use Rose::DB::Object
our @ISA = qw(Rose::DB::Object);

__PACKAGE__->meta->table('rose_db_object_test');

__PACKAGE__->meta->columns
(
  bits          => { type => 'bitfield', bits => 5, default => '00101', not_null => 1 },
  date_created  => { type => 'timestamp' },
  fk1           => { type => 'integer', method_name => 'fkone' },
  fk2           => { type => 'integer' },
  fk3           => { type => 'integer' },
  flag          => { type => 'boolean', default => 'true', not_null => 1 },
  flag2         => { type => 'boolean' },
  fother_id2    => { type => 'integer' },
  fother_id3    => { type => 'integer' },
  fother_id4    => { type => 'integer' },
  id            => { type => 'integer', not_null => 1 },
  last_modified => { type => 'timestamp' },
  name          => { type => 'varchar', length => 32, not_null => 1 },
  nums          => { type => 'array' },
  password      => { type => 'chkpass' },
  save          => { type => 'integer', method_name => 'save_col' },
  start         => { type => 'date', default => '1980-12-24' },
  status        => { type => 'varchar', default => 'active', length => 32 },
);

__PACKAGE__->meta->primary_key_columns([ 'id' ]);

__PACKAGE__->meta->foreign_keys
(
  fother => 
  {
    class => 'MyPgOtherObject2',
    key_columns => 
    {
      fother_id2 => 'id2',
    },
  },

  fother2 => 
  {
    class => 'MyPgOtherObject3',
    key_columns => 
    {
      fother_id3 => 'id3',
    },
  },

  fother3 => 
  {
    class => 'MyPgOtherObject4',
    key_columns => 
    {
      fother_id4 => 'id4',
    },
  },

  my_pg_other_object => 
  {
    class => 'MyPgOtherObject',
    key_columns => 
    {
      fk1 => 'k1',
      fk2 => 'k2',
      fk3 => 'k3',
    },
  },
);

__PACKAGE__->meta->initialize;

1;
EOF
}

#
# MySQL
#

SKIP: foreach my $db_type ('mysql')
{
  skip("MySQL tests", 54)  unless($HAVE_MYSQL_WITH_INNODB);

  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");

  my $oo1 = MyMySQLOtherObject->new(k1 => 1, k2 => 2, k3 => 3, name => 'one');
  ok($oo1->save, 'other object save() 1');

  my $oo2 = MyMySQLOtherObject->new(k1 => 11, k2 => 12, k3 => 13, name => 'two');
  ok($oo2->save, 'other object save() 2');

  my $other2 = MyMySQLOtherObject2->new(id2 => 12, name => 'twelve');
  ok($other2->save, 'other 2 object save() 1');

  my $other3 = MyMySQLOtherObject3->new(id3 => 13, name => 'thirteen');
  ok($other3->save, 'other 3 object save() 1');

  my $other4 = MyMySQLOtherObject4->new(id4 => 14, name => 'fourteen');
  ok($other4->save, 'other 4 object save() 1');

  is($o->fother, undef, 'fother() 1');
  is($o->fother2, undef, 'fother2() 1');
  is($o->fother3, undef, 'fother3() 1');
  is($o->my_my_sqlother_object, undef, 'my_my_sqlother_object() 1');

  $o->fother_id2(12);
  $o->fother_id3(13);
  $o->fother_id4(14);
  $o->fkone(1);
  $o->fk2(2);
  $o->fk3(3);

  my $obj = $o->my_my_sqlother_object or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyMySQLOtherObject', 'my_my_sqlother_object() 2');
  is($obj->name, 'one', 'my_my_sqlother_object() 3');

  $obj = $o->fother or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyMySQLOtherObject2', 'fother() 2');
  is($obj->name, 'twelve', 'fother() 3');

  $obj = $o->fother2 or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyMySQLOtherObject3', 'fother2() 2');
  is($obj->name, 'thirteen', 'fother2() 3');

  $obj = $o->fother3 or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyMySQLOtherObject4', 'fother3() 2');
  is($obj->name, 'fourteen', 'fother3() 3');

  $o->my_my_sqlother_object(undef);
  $o->fkone(11);
  $o->fk2(12);
  $o->fk3(13);

  $obj = $o->my_my_sqlother_object or warn "# ", $o->error, "\n";

  is(ref $obj, 'MyMySQLOtherObject', 'my_my_sqlother_object() 4');
  is($obj->name, 'two', 'my_my_sqlother_object() 5');


  ok($o->delete, "delete() - $db_type");
  
  eval { $o->meta->alias_column(nonesuch => 'foo') };
  ok($@, 'alias_column() nonesuch');

  #
  # Test code generation
  #

  is(MyMySQLObject->meta->perl_foreign_keys_definition,
     <<'EOF', "perl_foreign_keys_definition 1 - $db_type");
__PACKAGE__->meta->foreign_keys(
    fother => {
        class => 'MyMySQLOtherObject2',
        key_columns => {
            fother_id2 => 'id2',
        },
    },

    fother2 => {
        class => 'MyMySQLOtherObject3',
        key_columns => {
            fother_id3 => 'id3',
        },
    },

    fother3 => {
        class => 'MyMySQLOtherObject4',
        key_columns => {
            fother_id4 => 'id4',
        },
    },

    my_my_sqlother_object => {
        class => 'MyMySQLOtherObject',
        key_columns => {
            fk1 => 'k1',
            fk2 => 'k2',
            fk3 => 'k3',
        },
    },
);
EOF

  is(MyMySQLObject->meta->perl_foreign_keys_definition(braces => 'bsd', indent => 2),
     <<'EOF', "perl_foreign_keys_definition 2 - $db_type");
__PACKAGE__->meta->foreign_keys
(
  fother => 
  {
    class => 'MyMySQLOtherObject2',
    key_columns => 
    {
      fother_id2 => 'id2',
    },
  },

  fother2 => 
  {
    class => 'MyMySQLOtherObject3',
    key_columns => 
    {
      fother_id3 => 'id3',
    },
  },

  fother3 => 
  {
    class => 'MyMySQLOtherObject4',
    key_columns => 
    {
      fother_id4 => 'id4',
    },
  },

  my_my_sqlother_object => 
  {
    class => 'MyMySQLOtherObject',
    key_columns => 
    {
      fk1 => 'k1',
      fk2 => 'k2',
      fk3 => 'k3',
    },
  },
);
EOF

  is(MyMySQLObject->meta->perl_class_definition,
     <<'EOF', "perl_class_definition 1 - $db_type");
package MyMySQLObject;

use strict;

use Rose::DB::Object
our @ISA = qw(Rose::DB::Object);

__PACKAGE__->meta->table('rose_db_object_test');

__PACKAGE__->meta->columns(
    bits          => { type => 'bitfield', bits => 5, default => 101 },
    date_created  => { type => 'timestamp' },
    fk1           => { type => 'integer', method_name => 'fkone' },
    fk2           => { type => 'integer' },
    fk3           => { type => 'integer' },
    flag          => { type => 'boolean', default => 1 },
    flag2         => { type => 'boolean' },
    fother_id2    => { type => 'integer' },
    fother_id3    => { type => 'integer' },
    fother_id4    => { type => 'integer' },
    id            => { type => 'integer', not_null => 1 },
    last_modified => { type => 'timestamp', default => 'now' },
    name          => { type => 'varchar', default => '', length => 32, not_null => 1 },
    save          => { type => 'integer', method_name => 'save_col' },
    start         => { type => 'date', default => '1980-12-24' },
    status        => { type => 'varchar', default => 'active', length => 32 },
);

__PACKAGE__->meta->primary_key_columns([ 'id' ]);

__PACKAGE__->meta->foreign_keys(
    fother => {
        class => 'MyMySQLOtherObject2',
        key_columns => {
            fother_id2 => 'id2',
        },
    },

    fother2 => {
        class => 'MyMySQLOtherObject3',
        key_columns => {
            fother_id3 => 'id3',
        },
    },

    fother3 => {
        class => 'MyMySQLOtherObject4',
        key_columns => {
            fother_id4 => 'id4',
        },
    },

    my_my_sqlother_object => {
        class => 'MyMySQLOtherObject',
        key_columns => {
            fk1 => 'k1',
            fk2 => 'k2',
            fk3 => 'k3',
        },
    },
);

__PACKAGE__->meta->initialize;

1;
EOF

  is(MyMySQLObject->meta->perl_class_definition(braces => 'bsd', indent => 2),
     <<'EOF', "perl_class_definition 2 - $db_type");
package MyMySQLObject;

use strict;

use Rose::DB::Object
our @ISA = qw(Rose::DB::Object);

__PACKAGE__->meta->table('rose_db_object_test');

__PACKAGE__->meta->columns
(
  bits          => { type => 'bitfield', bits => 5, default => 101 },
  date_created  => { type => 'timestamp' },
  fk1           => { type => 'integer', method_name => 'fkone' },
  fk2           => { type => 'integer' },
  fk3           => { type => 'integer' },
  flag          => { type => 'boolean', default => 1 },
  flag2         => { type => 'boolean' },
  fother_id2    => { type => 'integer' },
  fother_id3    => { type => 'integer' },
  fother_id4    => { type => 'integer' },
  id            => { type => 'integer', not_null => 1 },
  last_modified => { type => 'timestamp', default => 'now' },
  name          => { type => 'varchar', default => '', length => 32, not_null => 1 },
  save          => { type => 'integer', method_name => 'save_col' },
  start         => { type => 'date', default => '1980-12-24' },
  status        => { type => 'varchar', default => 'active', length => 32 },
);

__PACKAGE__->meta->primary_key_columns([ 'id' ]);

__PACKAGE__->meta->foreign_keys
(
  fother => 
  {
    class => 'MyMySQLOtherObject2',
    key_columns => 
    {
      fother_id2 => 'id2',
    },
  },

  fother2 => 
  {
    class => 'MyMySQLOtherObject3',
    key_columns => 
    {
      fother_id3 => 'id3',
    },
  },

  fother3 => 
  {
    class => 'MyMySQLOtherObject4',
    key_columns => 
    {
      fother_id4 => 'id4',
    },
  },

  my_my_sqlother_object => 
  {
    class => 'MyMySQLOtherObject',
    key_columns => 
    {
      fk1 => 'k1',
      fk2 => 'k2',
      fk3 => 'k3',
    },
  },
);

__PACKAGE__->meta->initialize;

1;
EOF
}

#
# Informix
#

SKIP: foreach my $db_type ('informix')
{
  skip("Informix tests", 65)  unless($HAVE_INFORMIX);

  Rose::DB->default_type($db_type);

  my $o = MyInformixObject->new(name => 'John', id => 1);

  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(7);

  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, 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 = 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->load, "load() 4 - $db_type");

  my $o5 = MyInformixObject->new(id => $o->id);

  ok($o5->load, "load() 5 - $db_type");

  $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 $oo1 = MyInformixOtherObject->new(k1 => 1, k2 => 2, k3 => 3, name => 'one');
  ok($oo1->save, 'other object save() 1');

  my $oo2 = MyInformixOtherObject->new(k1 => 11, k2 => 12, k3 => 13, name => 'two');
  ok($oo2->save, 'other object save() 2');

  my $other2 = MyInformixOtherObject2->new(id2 => 12, name => 'twelve');
  ok($other2->save, 'other 2 object save() 1');

  my $other3 = MyInformixOtherObject3->new(id3 => 13, name => 'thirteen');
  ok($other3->save, 'other 3 object save() 1');

  my $other4 = MyInformixOtherObject4->new(id4 => 14, name => 'fourteen');
  ok($other4->save, 'other 4 object save() 1');

  is($o->fother, undef, 'fother() 1');
  is($o->fother2, undef, 'fother2() 1');
  is($o->fother3, undef, 'fother3() 1');
  is($o->my_informix_other_object, undef, 'my_informix_other_object() 1');

  $o->fother_id2(12);
  $o->fother_id3(13);
  $o->fother_id4(14);
  $o->fkone(1);
  $o->fk2(2);
  $o->fk3(3);

  my $obj = $o->my_informix_other_object or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyInformixOtherObject', 'my_informix_other_object() 2');
  is($obj->name, 'one', 'my_informix_other_object() 3');

  $obj = $o->fother or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyInformixOtherObject2', 'fother() 2');
  is($obj->name, 'twelve', 'fother() 3');

  $obj = $o->fother2 or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyInformixOtherObject3', 'fother2() 2');
  is($obj->name, 'thirteen', 'fother2() 3');

  $obj = $o->fother3 or warn "# ", $o->error, "\n";
  is(ref $obj, 'MyInformixOtherObject4', 'fother3() 2');
  is($obj->name, 'fourteen', 'fother3() 3');

  $o->my_informix_other_object(undef);
  $o->fkone(11);
  $o->fk2(12);
  $o->fk3(13);

  $obj = $o->my_informix_other_object or warn "# ", $o->error, "\n";

  is(ref $obj, 'MyInformixOtherObject', 'my_informix_other_object() 4');
  is($obj->name, 'two', 'my_informix_other_object() 5');

  ok($o->delete, "delete() - $db_type");

  eval { $o->meta->alias_column(nonesuch => 'foo') };
  ok($@, 'alias_column() nonesuch');

  #
  # Test code generation
  #

  is(MyInformixObject->meta->perl_foreign_keys_definition,
     <<'EOF', "perl_foreign_keys_definition 1 - $db_type");
__PACKAGE__->meta->foreign_keys(
    fother => {
        class => 'MyInformixOtherObject2',
        key_columns => {
            fother_id2 => 'id2',
        },
    },

    fother2 => {
        class => 'MyInformixOtherObject3',
        key_columns => {
            fother_id3 => 'id3',
        },
    },

    fother3 => {
        class => 'MyInformixOtherObject4',
        key_columns => {
            fother_id4 => 'id4',
        },
    },

    my_informix_other_object => {
        class => 'MyInformixOtherObject',
        key_columns => {
            fk1 => 'k1',
            fk2 => 'k2',
            fk3 => 'k3',
        },
    },
);
EOF

  is(MyInformixObject->meta->perl_foreign_keys_definition(braces => 'bsd', indent => 2),
     <<'EOF', "perl_foreign_keys_definition 2 - $db_type");
__PACKAGE__->meta->foreign_keys
(
  fother => 
  {
    class => 'MyInformixOtherObject2',
    key_columns => 
    {
      fother_id2 => 'id2',
    },
  },

  fother2 => 
  {
    class => 'MyInformixOtherObject3',
    key_columns => 
    {
      fother_id3 => 'id3',
    },
  },

  fother3 => 
  {
    class => 'MyInformixOtherObject4',
    key_columns => 
    {
      fother_id4 => 'id4',
    },
  },

  my_informix_other_object => 
  {
    class => 'MyInformixOtherObject',
    key_columns => 
    {
      fk1 => 'k1',
      fk2 => 'k2',
      fk3 => 'k3',
    },
  },
);
EOF

  is(MyInformixObject->meta->perl_class_definition,
     <<'EOF', "perl_class_definition 1 - $db_type");
package MyInformixObject;

use strict;

use Rose::DB::Object
our @ISA = qw(Rose::DB::Object);

__PACKAGE__->meta->table('rose_db_object_test');

__PACKAGE__->meta->columns(
    bits          => { type => 'bitfield', bits => 5, default => 101 },
    date_created  => { type => 'datetime year to fraction(5)' },
    fk1           => { type => 'integer', method_name => 'fkone' },
    fk2           => { type => 'integer' },
    fk3           => { type => 'integer' },
    flag          => { type => 'boolean', default => 't', not_null => 1 },
    flag2         => { type => 'boolean' },
    fother_id2    => { type => 'integer' },
    fother_id3    => { type => 'integer' },
    fother_id4    => { type => 'integer' },
    id            => { type => 'integer', not_null => 1 },
    last_modified => { type => 'datetime year to fraction(5)' },
    name          => { type => 'varchar', length => 32, not_null => 1 },
    nums          => { type => 'array' },
    save          => { type => 'integer', method_name => 'save_col' },
    start         => { type => 'date', default => '12/24/1980' },
    status        => { type => 'varchar', default => 'active', length => 32 },
);

__PACKAGE__->meta->primary_key_columns([ 'id' ]);

__PACKAGE__->meta->foreign_keys(
    fother => {
        class => 'MyInformixOtherObject2',
        key_columns => {
            fother_id2 => 'id2',
        },
    },

    fother2 => {
        class => 'MyInformixOtherObject3',
        key_columns => {
            fother_id3 => 'id3',
        },
    },

    fother3 => {
        class => 'MyInformixOtherObject4',
        key_columns => {
            fother_id4 => 'id4',
        },
    },

    my_informix_other_object => {
        class => 'MyInformixOtherObject',
        key_columns => {
            fk1 => 'k1',
            fk2 => 'k2',
            fk3 => 'k3',
        },
    },
);

__PACKAGE__->meta->initialize;

1;
EOF

  is(MyInformixObject->meta->perl_class_definition(braces => 'bsd', indent => 2),
     <<'EOF', "perl_class_definition 2 - $db_type");
package MyInformixObject;

use strict;

use Rose::DB::Object
our @ISA = qw(Rose::DB::Object);

__PACKAGE__->meta->table('rose_db_object_test');

__PACKAGE__->meta->columns
(
  bits          => { type => 'bitfield', bits => 5, default => 101 },
  date_created  => { type => 'datetime year to fraction(5)' },
  fk1           => { type => 'integer', method_name => 'fkone' },
  fk2           => { type => 'integer' },
  fk3           => { type => 'integer' },
  flag          => { type => 'boolean', default => 't', not_null => 1 },
  flag2         => { type => 'boolean' },
  fother_id2    => { type => 'integer' },
  fother_id3    => { type => 'integer' },
  fother_id4    => { type => 'integer' },
  id            => { type => 'integer', not_null => 1 },
  last_modified => { type => 'datetime year to fraction(5)' },
  name          => { type => 'varchar', length => 32, not_null => 1 },
  nums          => { type => 'array' },
  save          => { type => 'integer', method_name => 'save_col' },
  start         => { type => 'date', default => '12/24/1980' },
  status        => { type => 'varchar', default => 'active', length => 32 },
);

__PACKAGE__->meta->primary_key_columns([ 'id' ]);

__PACKAGE__->meta->foreign_keys
(
  fother => 
  {
    class => 'MyInformixOtherObject2',
    key_columns => 
    {
      fother_id2 => 'id2',
    },
  },

  fother2 => 
  {
    class => 'MyInformixOtherObject3',
    key_columns => 
    {
      fother_id3 => 'id3',
    },
  },

  fother3 => 
  {
    class => 'MyInformixOtherObject4',
    key_columns => 
    {
      fother_id4 => 'id4',
    },
  },

  my_informix_other_object => 
  {
    class => 'MyInformixOtherObject',
    key_columns => 
    {
      fk1 => 'k1',
      fk2 => 'k2',
      fk3 => 'k3',
    },
  },
);

__PACKAGE__->meta->initialize;

1;
EOF
}

BEGIN
{
  #
  # Postgres
  #

  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_other2');
      $dbh->do('DROP TABLE rose_db_object_other3');
      $dbh->do('DROP TABLE rose_db_object_other4');
      $dbh->do('DROP TABLE rose_db_object_chkpass_test');
    }

    eval
    {
      local $dbh->{'RaiseError'} = 1;
      local $dbh->{'PrintError'} = 0;
      $dbh->do('CREATE TABLE rose_db_object_chkpass_test (pass CHKPASS)');
      $dbh->do('DROP TABLE rose_db_object_chkpass_test');
    };
  
    our $PG_HAS_CHKPASS = 1  unless($@);

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other
(
  k1    INT NOT NULL,
  k2    INT NOT NULL,
  k3    INT NOT NULL,
  name  VARCHAR(32),

  PRIMARY KEY(k1, k2, k3)
)
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other2
(
  id2   SERIAL PRIMARY KEY,
  name  VARCHAR(32)
)
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other3
(
  id3   SERIAL PRIMARY KEY,
  name  VARCHAR(32)
)
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other4
(
  id4   SERIAL PRIMARY KEY,
  name  VARCHAR(32)
)
EOF
    # Create test foreign subclass 1

    package MyPgOtherObject;

    our @ISA = qw(Rose::DB::Object);

    sub init_db { Rose::DB->new('pg') }

    MyPgOtherObject->meta->table('rose_db_object_other');

    MyPgOtherObject->meta->auto_initialize;

    # Create test foreign subclasses 2-4

    package MyPgOtherObject2;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('pg') }
    MyPgOtherObject2->meta->table('rose_db_object_other2');
    MyPgOtherObject2->meta->auto_initialize;

    package MyPgOtherObject3;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('pg') }
    MyPgOtherObject3->meta->table('rose_db_object_other3');
    MyPgOtherObject3->meta->auto_initialize;

    package MyPgOtherObject4;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('pg') }
    MyPgOtherObject4->meta->table('rose_db_object_other4');
    MyPgOtherObject4->meta->auto_initialize;    
    
    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
  id             SERIAL PRIMARY KEY,
  @{[ $PG_HAS_CHKPASS ? 'password CHKPASS,' : '' ]}
  name           VARCHAR(32) NOT NULL,
  flag           BOOLEAN NOT NULL DEFAULT 't',
  flag2          BOOLEAN,
  status         VARCHAR(32) DEFAULT 'active',
  bits           BIT(5) NOT NULL DEFAULT B'00101',
  start          DATE DEFAULT '1980-12-24',
  save           INT,
  nums           INT[],
  fk1            INT,
  fk2            INT,
  fk3            INT,
  fother_id2     INT REFERENCES rose_db_object_other2 (id2),
  fother_id3     INT REFERENCES rose_db_object_other3 (id3),
  fother_id4     INT REFERENCES rose_db_object_other4 (id4),
  last_modified  TIMESTAMP,
  date_created   TIMESTAMP,
  
  FOREIGN KEY (fk1, fk2, fk3) REFERENCES rose_db_object_other (k1, k2, k3)
)
EOF

    $dbh->disconnect;

    # Create test subclass

    package MyPgObject;

    our @ISA = qw(Rose::DB::Object);

    sub init_db { Rose::DB->new('pg') }

    MyPgObject->meta->table('rose_db_object_test');

    MyPgObject->meta->column_name_to_method_name_mapper(sub
    {
      return ($_ eq 'fk1') ? 'fkone' : $_
    });

    MyPgObject->meta->auto_initialize;

    Test::More::ok(MyPgObject->can('fother'),  'fother() check - pg');
    Test::More::ok(MyPgObject->can('fother2'), 'fother2() check - pg');
    Test::More::ok(MyPgObject->can('fother3'), 'fother3() check - pg');

    package MyPgObjectEvalTest;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('pg') }

    eval 'package MyPgObjectEvalTest; ' . MyPgObject->meta->perl_foreign_keys_definition;
    Test::More::ok(!$@, 'perl_foreign_keys_definition eval - pg');
  }

  #
  # MySQL
  #

  eval
  {
    $dbh = Rose::DB->new('mysql_admin')->retain_dbh()
      or die Rose::DB->error;

    CLEAR:
    {
      local $dbh->{'RaiseError'} = 0;
      local $dbh->{'PrintError'} = 0;
      $dbh->do('DROP TABLE rose_db_object_test CASCADE');
      $dbh->do('DROP TABLE rose_db_object_other');
    }

    # Foreign key stuff requires InnoDB support
    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other
(
  k1    INT NOT NULL,
  k2    INT NOT NULL,
  k3    INT NOT NULL,
  name  VARCHAR(32),

  PRIMARY KEY(k1, k2, k3)
)
TYPE=InnoDB
EOF
  };

  if(!$@ && $dbh)
  {
    our $HAVE_MYSQL_WITH_INNODB = 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 CASCADE');
      $dbh->do('DROP TABLE rose_db_object_other');
      $dbh->do('DROP TABLE rose_db_object_other2');
      $dbh->do('DROP TABLE rose_db_object_other3');
      $dbh->do('DROP TABLE rose_db_object_other4');
    }

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other
(
  k1    INT UNSIGNED NOT NULL,
  k2    INT UNSIGNED NOT NULL,
  k3    INT UNSIGNED NOT NULL,
  name  VARCHAR(32),

  PRIMARY KEY(k1, k2, k3)
)
TYPE=InnoDB
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other2
(
  id2   INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name  VARCHAR(32)
)
TYPE=InnoDB
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other3
(
  id3   INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name  VARCHAR(32)
)
TYPE=InnoDB
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other4
(
  id4   INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name  VARCHAR(32)
)
TYPE=InnoDB
EOF

    # Create test foreign subclass 1

    package MyMySQLOtherObject;

    our @ISA = qw(Rose::DB::Object);

    sub init_db { Rose::DB->new('mysql') }

    MyMySQLOtherObject->meta->table('rose_db_object_other');

    MyMySQLOtherObject->meta->auto_initialize;

    # Create test foreign subclasses 2-4

    package MyMySQLOtherObject2;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('mysql') }
    MyMySQLOtherObject2->meta->table('rose_db_object_other2');
    MyMySQLOtherObject2->meta->auto_initialize;

    package MyMySQLOtherObject3;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('mysql') }
    MyMySQLOtherObject3->meta->table('rose_db_object_other3');
    MyMySQLOtherObject3->meta->auto_initialize;

    package MyMySQLOtherObject4;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('mysql') }
    MyMySQLOtherObject4->meta->table('rose_db_object_other4');
    MyMySQLOtherObject4->meta->auto_initialize;    

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
  id             INT AUTO_INCREMENT PRIMARY KEY,
  name           VARCHAR(32) NOT NULL,
  flag           BOOLEAN NOT NULL,
  flag2          BOOLEAN,
  status         VARCHAR(32) DEFAULT 'active',
  bits           BIT(5) NOT NULL DEFAULT '00101',
  start          DATE DEFAULT '1980-12-24',
  save           INT,
  fk1            INT UNSIGNED,
  fk2            INT UNSIGNED,
  fk3            INT UNSIGNED,
  fother_id2     INT UNSIGNED,
  fother_id3     INT UNSIGNED,
  fother_id4     INT UNSIGNED,
  last_modified  TIMESTAMP,
  date_created   TIMESTAMP,

  FOREIGN KEY (fother_id2) REFERENCES rose_db_object_other2 (id2),
  FOREIGN KEY (fother_id3) REFERENCES rose_db_object_other3 (id3),
  FOREIGN KEY (fother_id4) REFERENCES rose_db_object_other4 (id4),
  
  FOREIGN KEY (fk1, fk2, fk3) REFERENCES rose_db_object_other (k1, k2, k3)
)
TYPE=InnoDB
EOF

    $dbh->disconnect;

    # Create test subclass

    package MyMySQLObject;

    our @ISA = qw(Rose::DB::Object);

    sub init_db { Rose::DB->new('mysql') }

    MyMySQLObject->meta->table('rose_db_object_test');

    MyMySQLObject->meta->column_name_to_method_name_mapper(sub
    {
      return ($_ eq 'fk1') ? 'fkone' : $_
    });

    MyMySQLObject->meta->auto_init_columns;

    # Account for bugs in DBD::mysql's column_info implementation

    # BIT(5) column shows up as TINYINT(1)
    MyMySQLObject->meta->column(bits => { type => 'bitfield', bits => 5, default => 101 });
    
    # BOOLEAN column shows up as TINYINT(1)
    MyMySQLObject->meta->column(flag  => { type => 'boolean', default => 1 });
    MyMySQLObject->meta->column(flag2 => { type => 'boolean' });

    MyMySQLObject->meta->auto_initialize;

    Test::More::ok(MyMySQLObject->can('fother'),  'fother() check - mysql');
    Test::More::ok(MyMySQLObject->can('fother2'), 'fother2() check - mysql');
    Test::More::ok(MyMySQLObject->can('fother3'), 'fother3() check - mysql');

    package MyMySQLObjectEvalTest;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('mysql') }

    eval 'package MyMySQLObjectEvalTest; ' . MyMySQLObject->meta->perl_foreign_keys_definition;
    Test::More::ok(!$@, 'perl_foreign_keys_definition eval - mysql');
  }

  #
  # 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('DROP TABLE rose_db_object_other');
      $dbh->do('DROP TABLE rose_db_object_other2');
      $dbh->do('DROP TABLE rose_db_object_other3');
      $dbh->do('DROP TABLE rose_db_object_other4');
    }

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other
(
  k1    INT NOT NULL,
  k2    INT NOT NULL,
  k3    INT NOT NULL,
  name  VARCHAR(32),

  PRIMARY KEY(k1, k2, k3)
)
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other2
(
  id2   SERIAL PRIMARY KEY,
  name  VARCHAR(32)
)
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other3
(
  id3   SERIAL PRIMARY KEY,
  name  VARCHAR(32)
)
EOF

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_other4
(
  id4   SERIAL PRIMARY KEY,
  name  VARCHAR(32)
)
EOF

    # Create test foreign subclass 1

    package MyInformixOtherObject;

    our @ISA = qw(Rose::DB::Object);

    sub init_db { Rose::DB->new('informix') }

    MyInformixOtherObject->meta->table('rose_db_object_other');

    MyInformixOtherObject->meta->auto_initialize;

    # Create test foreign subclasses 2-4

    package MyInformixOtherObject2;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('informix') }
    MyInformixOtherObject2->meta->table('rose_db_object_other2');
    MyInformixOtherObject2->meta->auto_initialize;

    package MyInformixOtherObject3;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('informix') }
    MyInformixOtherObject3->meta->table('rose_db_object_other3');
    MyInformixOtherObject3->meta->auto_initialize;

    package MyInformixOtherObject4;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('informix') }
    MyInformixOtherObject4->meta->table('rose_db_object_other4');
    MyInformixOtherObject4->meta->auto_initialize;   

    $dbh->do(<<"EOF");
CREATE TABLE rose_db_object_test
(
  id             INT NOT NULL PRIMARY KEY,
  name           VARCHAR(32) NOT NULL,
  flag           BOOLEAN DEFAULT 't' NOT NULL,
  flag2          BOOLEAN,
  status         VARCHAR(32) DEFAULT 'active',
  bits           VARCHAR(5) DEFAULT '00101' NOT NULL,
  start          DATE DEFAULT '12/24/1980',
  save           INT,
  nums           VARCHAR(255),
  fk1            INT,
  fk2            INT,
  fk3            INT,
  fother_id2     INT REFERENCES rose_db_object_other2 (id2),
  fother_id3     INT REFERENCES rose_db_object_other3 (id3),
  fother_id4     INT REFERENCES rose_db_object_other4 (id4),
  last_modified  DATETIME YEAR TO FRACTION(5),
  date_created   DATETIME YEAR TO FRACTION(5),
  
  FOREIGN KEY (fk1, fk2, fk3) REFERENCES rose_db_object_other (k1, k2, k3)
)
EOF

    $dbh->disconnect;

    # Create test subclass

    package MyInformixObject;

    our @ISA = qw(Rose::DB::Object);

    sub init_db { Rose::DB->new('informix') }

    MyInformixObject->meta->table('rose_db_object_test');


    MyInformixObject->meta->column_name_to_method_name_mapper(sub
    {
      return ($_ eq 'fk1') ? 'fkone' : $_
    });

    # No native support for bit types in Informix
    MyInformixObject->meta->column(bits => { type => 'bitfield', bits => 5, default => 101 });

    # No native support for array types in Informix
    MyInformixObject->meta->column(nums => { type => 'array' });

    MyInformixObject->meta->auto_initialize;

    Test::More::ok(MyInformixObject->can('fother'),  'fother() check - informix');
    Test::More::ok(MyInformixObject->can('fother2'), 'fother2() check - informix');
    Test::More::ok(MyInformixObject->can('fother3'), 'fother3() check - informix');

    package MyInformixObjectEvalTest;
    our @ISA = qw(Rose::DB::Object);
    sub init_db { Rose::DB->new('informix') }

    eval 'package MyInformixObjectEvalTest; ' . MyInformixObject->meta->perl_foreign_keys_definition;
    Test::More::ok(!$@, 'perl_foreign_keys_definition eval - informix');
  }
}

END
{
  # Delete test table

  if($HAVE_PG)
  {
    # Postgres
    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_other2');
    $dbh->do('DROP TABLE rose_db_object_other3');
    $dbh->do('DROP TABLE rose_db_object_other4');

    $dbh->disconnect;
  }
  
  if($HAVE_MYSQL_WITH_INNODB)
  {
    # MySQL
    my $dbh = Rose::DB->new('mysql_admin')->retain_dbh()
      or die Rose::DB->error;

    $dbh->do('DROP TABLE rose_db_object_test CASCADE');
    $dbh->do('DROP TABLE rose_db_object_other');
    $dbh->do('DROP TABLE rose_db_object_other2');
    $dbh->do('DROP TABLE rose_db_object_other3');
    $dbh->do('DROP TABLE rose_db_object_other4');

    $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->do('DROP TABLE rose_db_object_other');
    $dbh->do('DROP TABLE rose_db_object_other2');

    $dbh->disconnect;
  }
}
