Merge 'current' into 'mssql_tweaks'
Rafael Kitover [Mon, 10 Aug 2009 10:18:03 +0000 (10:18 +0000)]
r9157@hlagh (orig r7116):  ilmari | 2009-07-24 13:44:58 -0400
Doc improvements by Robert Buels

lib/DBIx/Class/Schema/Loader/Base.pm
lib/DBIx/Class/Schema/Loader/DBI.pm
lib/DBIx/Class/Schema/Loader/DBI/MSSQL.pm
lib/DBIx/Class/Schema/Loader/DBI/Sybase.pm
lib/DBIx/Class/Schema/Loader/DBI/Sybase/Common.pm [new file with mode: 0644]
t/13db2_common.t
t/15sybase_common.t
t/16mssql_common.t [new file with mode: 0644]
t/16mssql_odbc_common.t
t/17mssql_dot_in_table_name.t [new file with mode: 0644]
t/lib/dbixcsl_common_tests.pm

index f674dcd..18b9ed4 100644 (file)
@@ -672,7 +672,14 @@ sub _setup_src_meta {
     my $table_class = $self->classes->{$table};
     my $table_moniker = $self->monikers->{$table};
 
-    $self->_dbic_stmt($table_class,'table',$table);
+    my $table_name = $table;
+    my $name_sep   = $self->schema->storage->sql_maker->name_sep;
+
+    if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
+        $table_name = \ $self->_quote_table_name($table_name);
+    }
+
+    $self->_dbic_stmt($table_class,'table',$table_name);
 
     my $cols = $self->_table_columns($table);
     my $col_info;
@@ -681,17 +688,26 @@ sub _setup_src_meta {
         $self->_dbic_stmt($table_class,'add_columns',@$cols);
     }
     else {
-        my %col_info_lc = map { lc($_), $col_info->{$_} } keys %$col_info;
+        if ($self->_is_case_sensitive) {
+            for my $col (keys %$col_info) {
+                $col_info->{$col}{accessor} = lc $col
+                    if $col ne lc($col);
+            }
+        } else {
+            $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
+        }
+
         my $fks = $self->_table_fk_info($table);
+
         for my $fkdef (@$fks) {
             for my $col (@{ $fkdef->{local_columns} }) {
-                $col_info_lc{$col}->{is_foreign_key} = 1;
+                $col_info->{$col}{is_foreign_key} = 1;
             }
         }
         $self->_dbic_stmt(
             $table_class,
             'add_columns',
-            map { $_, ($col_info_lc{$_}||{}) } @$cols
+            map { $_, ($col_info->{$_}||{}) } @$cols
         );
     }
 
@@ -815,6 +831,22 @@ sub _ext_stmt {
     push(@{$self->{_ext_storage}->{$class}}, $stmt);
 }
 
+sub _quote_table_name {
+    my ($self, $table) = @_;
+
+    my $qt = $self->schema->storage->sql_maker->quote_char;
+
+    return $table unless $qt;
+
+    if (ref $qt) {
+        return $qt->[0] . $table . $qt->[1];
+    }
+
+    return $qt . $table . $qt;
+}
+
+sub _is_case_sensitive { 0 }
+
 =head2 monikers
 
 Returns a hashref of loaded table to moniker mappings.  There will
index 4890b10..0854358 100644 (file)
@@ -90,8 +90,14 @@ sub _tables_list {
     my $dbh = $self->schema->storage->dbh;
     my @tables = $dbh->tables(undef, $self->db_schema, $table, $type);
 
-    s/\Q$self->{_quoter}\E//g    for @tables;
-    s/^.*\Q$self->{_namesep}\E// for @tables;
+    my $qt = qr/\Q$self->{_quoter}\E/;
+
+    if ($self->{_quoter} && $tables[0] =~ /$qt/) {
+        s/.* $qt (?= .* $qt)//xg for @tables;
+    } else {
+        s/^.*\Q$self->{_namesep}\E// for @tables;
+    }
+    s/$qt//g for @tables;
 
     return @tables;
 }
@@ -117,10 +123,13 @@ sub _table_columns {
     my $dbh = $self->schema->storage->dbh;
 
     if($self->{db_schema}) {
-        $table = $self->{db_schema} . $self->{_namesep} . $table;
+        $table = $self->{db_schema} . $self->{_namesep} .
+            $self->_quote_table_name($table);
+    } else {
+        $table = $self->_quote_table_name($table);
     }
 
-    my $sth = $dbh->prepare($self->schema->storage->sql_maker->select($table, undef, \'1 = 0'));
+    my $sth = $dbh->prepare($self->schema->storage->sql_maker->select(\$table, undef, \'1 = 0'));
     $sth->execute;
     my $retval = \@{$sth->{NAME_lc}};
     $sth->finish;
index 74ba030..5151f21 100644 (file)
@@ -2,7 +2,10 @@ package DBIx::Class::Schema::Loader::DBI::MSSQL;
 
 use strict;
 use warnings;
-use base 'DBIx::Class::Schema::Loader::DBI';
+use base qw/
+    DBIx::Class::Schema::Loader::DBI
+    DBIx::Class::Schema::Loader::DBI::Sybase::Common
+/;
 use Carp::Clan qw/^DBIx::Class/;
 use Class::C3;
 
@@ -31,14 +34,10 @@ sub _setup {
     my $self = shift;
 
     $self->next::method(@_);
-    $self->{db_schema} ||= 'dbo';
+    $self->{db_schema} ||= $self->_build_db_schema;
+    $self->_set_quote_char_and_name_sep;
 }
 
-# DBD::Sybase doesn't implement get_info properly
-#sub _build_quoter  { [qw/[ ]/] }
-sub _build_quoter  { '"' }
-sub _build_namesep { '.' }
-
 sub _table_pk_info {
     my ($self, $table) = @_;
     my $dbh = $self->schema->storage->dbh;
@@ -130,6 +129,10 @@ L<DBIx::Class::Schema::Loader::DBI>
 
 Justin Hunter C<justin.d.hunter@gmail.com>
 
+=head1 CONTRIBUTORS
+
+Rafael Kitover <rkitover@cpan.org>
+
 =cut
 
 1;
index e45a946..7b3ec3d 100644 (file)
@@ -2,7 +2,10 @@ package DBIx::Class::Schema::Loader::DBI::Sybase;
 
 use strict;
 use warnings;
-use base 'DBIx::Class::Schema::Loader::DBI';
+use base qw/
+    DBIx::Class::Schema::Loader::DBI
+    DBIx::Class::Schema::Loader::DBI::Sybase::Common
+/;
 use Carp::Clan qw/^DBIx::Class/;
 use Class::C3;
 
@@ -27,11 +30,14 @@ See L<DBIx::Class::Schema::Loader::Base>.
 
 =cut
 
+sub _is_case_sensitive { 1 }
+
 sub _setup {
     my $self = shift;
 
     $self->next::method(@_);
-    $self->{db_schema} ||= 'dbo';
+    $self->{db_schema} ||= $self->_build_db_schema;
+    $self->_set_quote_char_and_name_sep;
 }
 
 sub _rebless {
@@ -67,7 +73,7 @@ sub _table_pk_info {
     my @keydata;
 
     while (my $row = $sth->fetchrow_hashref) {
-        push @keydata, lc $row->{column_name};
+        push @keydata, $row->{column_name};
     }
 
     return \@keydata;
@@ -76,19 +82,45 @@ sub _table_pk_info {
 sub _table_fk_info {
     my ($self, $table) = @_;
 
+    # check if FK_NAME is supported
+
+    my $dbh = $self->schema->storage->dbh;
+    local $dbh->{FetchHashKeyName} = 'NAME_lc';
+    # hide "Object does not exist in this database." when trying to fetch fkeys
+    local $dbh->{syb_err_handler} = sub { return $_[0] == 17461 ? 0 : 1 }; 
+    my $sth = $dbh->prepare(qq{sp_fkeys \@fktable_name = '$table'});
+    $sth->execute;
+    my $row = $sth->fetchrow_hashref;
+
+    return unless $row;
+
+    if (exists $row->{fk_name}) {
+        $sth->finish;
+        return $self->_table_fk_info_by_name($table);
+    }
+
+    $sth->finish;
+    return $self->_table_fk_info_builder($table);
+}
+
+sub _table_fk_info_by_name {
+    my ($self, $table) = @_;
     my ($local_cols, $remote_cols, $remote_table, @rels);
+
     my $dbh = $self->schema->storage->dbh;
+    local $dbh->{FetchHashKeyName} = 'NAME_lc';
     # hide "Object does not exist in this database." when trying to fetch fkeys
-    $dbh->{syb_err_handler} = sub { return 0 if $_[0] == 17461; }; 
-    my $sth = $dbh->prepare(qq{sp_fkeys \@FKTABLE_NAME = '$table'});
+    local $dbh->{syb_err_handler} = sub { return $_[0] == 17461 ? 0 : 1 }; 
+    my $sth = $dbh->prepare(qq{sp_fkeys \@fktable_name = '$table'});
     $sth->execute;
 
     while (my $row = $sth->fetchrow_hashref) {
-        next unless $row->{FK_NAME};
-        my $fk = $row->{FK_NAME};
-        push @{$local_cols->{$fk}}, lc $row->{FKCOLUMN_NAME};
-        push @{$remote_cols->{$fk}}, lc $row->{PKCOLUMN_NAME};
-        $remote_table->{$fk} = $row->{PKTABLE_NAME};
+        my $fk = $row->{fk_name};
+        next unless defined $fk;
+
+        push @{$local_cols->{$fk}}, $row->{fkcolumn_name};
+        push @{$remote_cols->{$fk}}, $row->{pkcolumn_name};
+        $remote_table->{$fk} = $row->{pktable_name};
     }
 
     foreach my $fk (keys %$remote_table) {
@@ -102,19 +134,91 @@ sub _table_fk_info {
     return \@rels;
 }
 
+sub _table_fk_info_builder {
+    my ($self, $table) = @_;
+
+    my $dbh = $self->schema->storage->dbh;
+    local $dbh->{FetchHashKeyName} = 'NAME_lc';
+    # hide "Object does not exist in this database." when trying to fetch fkeys
+    local $dbh->{syb_err_handler} = sub { return 0 if $_[0] == 17461; }; 
+    my $sth = $dbh->prepare(qq{sp_fkeys \@fktable_name = '$table'});
+    $sth->execute;
+
+    my @fk_info;
+    while (my $row = $sth->fetchrow_hashref) {
+        (my $ksq = $row->{key_seq}) =~ s/\s+//g;
+
+        my @keys = qw/pktable_name pkcolumn_name fktable_name fkcolumn_name/;
+        my %ds;
+        @ds{@keys}   = @{$row}{@keys};
+        $ds{key_seq} = $ksq;
+
+        push @{ $fk_info[$ksq] }, \%ds;
+    }
+
+    my $max_keys = $#fk_info;
+    my @rels;
+    for my $level (reverse 1 .. $max_keys) {
+        my @level_rels;
+        $level_rels[$level] = splice @fk_info, $level, 1;
+        my $count = @{ $level_rels[$level] };
+
+        for my $sub_level (reverse 1 .. $level-1) {
+            my $total = @{ $fk_info[$sub_level] };
+
+            $level_rels[$sub_level] = [
+                splice @{ $fk_info[$sub_level] }, $total-$count, $count
+            ];
+        }
+
+        while (1) {
+            my @rel = map shift @$_, @level_rels[1..$level];
+
+            last unless defined $rel[0];
+
+            my @local_columns  = map $_->{fkcolumn_name}, @rel;
+            my @remote_columns = map $_->{pkcolumn_name}, @rel;
+            my $remote_table   = $rel[0]->{pktable_name};
+
+            push @rels, {
+                local_columns => \@local_columns,
+                remote_columns => \@remote_columns,
+                remote_table => $remote_table
+            };
+        }
+    }
+
+    return \@rels;
+}
+
 sub _table_uniq_info {
     my ($self, $table) = @_;
 
+    local $SIG{__WARN__} = sub {};
+
     my $dbh = $self->schema->storage->dbh;
+    local $dbh->{FetchHashKeyName} = 'NAME_lc';
     my $sth = $dbh->prepare(qq{sp_helpconstraint \@objname='$table', \@nomsg='nomsg'});
-    $sth->execute;
+    eval { $sth->execute };
+    return if $@;
 
     my $constraints;
     while (my $row = $sth->fetchrow_hashref) {
-        my $type = $row->{constraint_type} || '';
-        if ($type =~ /^unique/i) {
-            my $name = lc $row->{constraint_name};
-            push @{$constraints->{$name}}, ( split /,/, lc $row->{constraint_keys} );
+        if (exists $row->{constraint_type}) {
+            my $type = $row->{constraint_type} || '';
+            if ($type =~ /^unique/i) {
+                my $name = $row->{constraint_name};
+                push @{$constraints->{$name}},
+                    ( split /,/, $row->{constraint_keys} );
+            }
+        } else {
+            my $def = $row->{definition} || next;
+            next unless $def =~ /^unique/i;
+            my $name = $row->{name};
+            my ($keys) = $def =~ /\((.*)\)/;
+            $keys =~ s/\s*//g;
+            my @keys = split /,/ => $keys;
+            push @{$constraints->{$name}}, @keys;
         }
     }
 
@@ -148,6 +252,10 @@ L<DBIx::Class::Schema::Loader::DBI>
 
 Justin Hunter C<justin.d.hunter@gmail.com>
 
+=head1 CONTRIBUTORS
+
+Rafael Kitover <rkitover@cpan.org>
+
 =cut
 
 1;
diff --git a/lib/DBIx/Class/Schema/Loader/DBI/Sybase/Common.pm b/lib/DBIx/Class/Schema/Loader/DBI/Sybase/Common.pm
new file mode 100644 (file)
index 0000000..c8c7a88
--- /dev/null
@@ -0,0 +1,79 @@
+package DBIx::Class::Schema::Loader::DBI::Sybase::Common;
+
+use strict;
+use warnings;
+use Carp::Clan qw/^DBIx::Class/;
+use Class::C3;
+
+our $VERSION = '0.04999_06';
+
+=head1 NAME
+
+DBIx::Class::Schema::Loader::DBI::Sybase::Common - Common functions for Sybase
+and MSSQL
+
+=head1 DESCRIPTION
+
+See L<DBIx::Class::Schema::Loader::Base>.
+
+=cut
+
+# DBD::Sybase doesn't implement get_info properly
+sub _build_quoter  { '"' }
+sub _build_namesep { '.' }
+
+sub _set_quote_char_and_name_sep {
+    my $self = shift;
+
+    $self->schema->storage->sql_maker->quote_char([qw/[ ]/])
+        unless $self->schema->storage->sql_maker->quote_char;
+
+    $self->schema->storage->sql_maker->name_sep('.')
+        unless $self->schema->storage->sql_maker->name_sep;
+}
+
+sub _build_db_schema {
+    my $self = shift;
+    my $dbh  = $self->schema->storage->dbh;
+
+    local $dbh->{FetchHashKeyName} = 'NAME_lc';
+    
+    my $test_table = "_loader_test_$$";
+
+    my $db_schema = 'dbo'; # default
+
+    eval {
+        $dbh->do("create table $test_table (id integer)");
+        my $sth = $dbh->prepare('sp_tables');
+        $sth->execute;
+        while (my $row = $sth->fetchrow_hashref) {
+            next unless $row->{table_name} eq $test_table;
+
+            $db_schema = $row->{table_owner};
+            last;
+        }
+        $sth->finish;
+        $dbh->do("drop table $test_table");
+    };
+    my $exception = $@;
+    eval { $dbh->do("drop table $test_table") };
+    carp "Could not determine db_schema, defaulting to $db_schema : $exception"
+        if $exception;
+
+    return $db_schema;
+}
+
+=head1 SEE ALSO
+
+L<DBIx::Class::Schema::Loader::DBI::Sybase>,
+L<DBIx::Class::Schema::Loader::DBI::MSSQL>,
+L<DBIx::Class::Schema::Loader::DBI>
+L<DBIx::Class::Schema::Loader>, L<DBIx::Class::Schema::Loader::Base>,
+
+=head1 AUTHOR
+
+Rafael Kitover <rkitover@cpan.org>
+
+=cut
+
+1;
index a4dd554..b27ef4f 100644 (file)
@@ -12,6 +12,7 @@ my $tester = dbixcsl_common_tests->new(
     dsn            => $dsn,
     user           => $user,
     password       => $password,
+    null           => '',
 );
 
 if( !$dsn || !$user ) {
index 4995752..bce97e1 100644 (file)
@@ -2,13 +2,14 @@ use strict;
 use lib qw(t/lib);
 use dbixcsl_common_tests;
 
+# you need maxConnect=256 in your DSN for this test to pass
+
 my $dsn      = $ENV{DBICTEST_SYBASE_DSN} || '';
 my $user     = $ENV{DBICTEST_SYBASE_USER} || '';
 my $password = $ENV{DBICTEST_SYBASE_PASS} || '';
 
 my $tester = dbixcsl_common_tests->new(
     vendor      => 'Sybase',
-    quote_char  => [qw/[ ]/],
     auto_inc_pk => 'INTEGER IDENTITY NOT NULL PRIMARY KEY',
     dsn         => $dsn,
     user        => $user,
diff --git a/t/16mssql_common.t b/t/16mssql_common.t
new file mode 100644 (file)
index 0000000..9cafbe5
--- /dev/null
@@ -0,0 +1,31 @@
+use strict;
+use warnings;
+
+# use this if you keep a copy of DBD::Sybase linked to FreeTDS somewhere else
+BEGIN {
+  if (my $lib_dirs = $ENV{DBICTEST_MSSQL_PERL5LIB}) {
+    unshift @INC, $_ for split /:/, $lib_dirs;
+  }
+}
+
+use lib qw(t/lib);
+use dbixcsl_common_tests;
+
+my $dsn      = $ENV{DBICTEST_MSSQL_DSN} || '';
+my $user     = $ENV{DBICTEST_MSSQL_USER} || '';
+my $password = $ENV{DBICTEST_MSSQL_PASS} || '';
+
+my $tester = dbixcsl_common_tests->new(
+    vendor      => 'Microsoft',
+    auto_inc_pk => 'INTEGER IDENTITY NOT NULL PRIMARY KEY',
+    dsn         => $dsn,
+    user        => $user,
+    password    => $password,
+);
+
+if( !$dsn || !$user ) {
+    $tester->skip_tests('You need to set the DBICTEST_MSSQL_DSN, _USER, and _PASS environment variables');
+}
+else {
+    $tester->run_tests();
+}
index 893bb8e..fdf1888 100644 (file)
@@ -8,7 +8,6 @@ my $password = $ENV{DBICTEST_MSSQL_ODBC_PASS} || '';
 
 my $tester = dbixcsl_common_tests->new(
     vendor      => 'Microsoft',
-    quote_char  => [qw/[ ]/],
     auto_inc_pk => 'INTEGER IDENTITY NOT NULL PRIMARY KEY',
     dsn         => $dsn,
     user        => $user,
diff --git a/t/17mssql_dot_in_table_name.t b/t/17mssql_dot_in_table_name.t
new file mode 100644 (file)
index 0000000..ab9f435
--- /dev/null
@@ -0,0 +1,86 @@
+use strict;
+use lib qw(t/lib);
+use Test::More;
+use DBI;
+
+my $DUMP_DIR;
+BEGIN { 
+    $DUMP_DIR = './t/_common_dump';
+}
+
+use lib $DUMP_DIR;
+use DBIx::Class::Schema::Loader 'make_schema_at', "dump_to_dir:$DUMP_DIR";
+use File::Path;
+
+my $dsn      = $ENV{DBICTEST_MSSQL_ODBC_DSN}  ||
+               $ENV{DBICTEST_MSSQL_DSN}  || '';
+
+my $user     = $ENV{DBICTEST_MSSQL_ODBC_USER} ||
+               $ENV{DBICTEST_MSSQL_USER} || '';
+
+my $password = $ENV{DBICTEST_MSSQL_ODBC_PASS} ||
+               $ENV{DBICTEST_MSSQL_PASS} || '';
+
+if( !$dsn || !$user ) {
+    plan skip_all =>
+'You need to set the DBICTEST_MSSQL_ODBC_DSN (or DBICTEST_MSSQL_DSN), _USER,' .
+' and _PASS environment variables';
+    exit;
+}
+
+plan tests => 3;
+
+my $dbh = DBI->connect($dsn, $user, $password, {
+    RaiseError => 1, PrintError => 0
+});
+
+eval { $dbh->do('DROP TABLE [loadertest.dot]') };
+$dbh->do(q{
+    CREATE TABLE [loadertest.dot] (
+        id INT IDENTITY NOT NULL PRIMARY KEY,
+        dat VARCHAR(8)
+    )
+});
+
+rmtree $DUMP_DIR;
+
+eval {
+    make_schema_at(
+        'TestSL::Schema', 
+        {
+            use_namespaces => 1,
+            constraint => qr/^loadertest\.dot\z/
+        },
+        [ $dsn, $user, $password, ]
+    );
+};
+
+ok !$@, 'table name with . parsed correctly';
+diag $@ if $@;
+
+#system qq{$^X -pi -e 's/"test\.dot"/\\\\"[loadertest.dot]"/' t/_common_dump/TestSL/Schema/Result/TestDot.pm};
+#diag do { local ($/, @ARGV) = (undef, "t/_common_dump/TestSL/Schema/Result/TestDot.pm"); <> };
+#do "t/_common_dump/TestSL/Schema/Result/TestDot.pm";
+
+eval 'use TestSL::Schema';
+ok !$@, 'loaded schema';
+diag $@ if $@;
+
+TODO: {
+    local $TODO = q{this is really a DBIC test to check if the table is usable,
+and it doesn't work in the released version yet};
+
+    eval {
+        my $rs = TestSL::Schema->resultset('LoadertestDot');
+        my $row = $rs->create({ dat => 'foo' });
+        $row->update({ dat => 'bar' });
+        $row = $rs->find($row->id);
+        $row->delete;
+    };
+    ok !$@, 'used table from DBIC succeessfully';
+    diag $@ if $@;
+}
+
+rmtree $DUMP_DIR;
+
+$dbh->do('DROP TABLE [loadertest.dot]');
index a8ab6b7..00ced93 100644 (file)
@@ -27,6 +27,9 @@ sub new {
 
     # Only MySQL uses this
     $self->{innodb} ||= '';
+
+    # DB2 doesn't support this
+    $self->{null} = 'NULL' unless defined $self->{null};
     
     $self->{verbose} = $ENV{TEST_VERBOSE} || 0;
 
@@ -391,7 +394,11 @@ sub test_schema {
         isa_ok( $rs_rel4->first, $class4);
 
         # find on multi-col pk
-        my $obj5 = $rsobj5->find({id1 => 1, id2 => 1});
+        my $obj5 = 
+           eval { $rsobj5->find({id1 => 1, iD2 => 1}) } ||
+           eval { $rsobj5->find({id1 => 1, id2 => 1}) };
+       die $@ if $@;
+
         is( $obj5->id2, 1, "Find on multi-col PK" );
 
         # mulit-col fk def
@@ -401,7 +408,10 @@ sub test_schema {
 
         ok($class6->column_info('loader_test2_id')->{is_foreign_key}, 'Foreign key detected');
         ok($class6->column_info('id')->{is_foreign_key}, 'Foreign key detected');
-        ok($class6->column_info('id2')->{is_foreign_key}, 'Foreign key detected');
+
+       my $id2_info = eval { $class6->column_info('id2') } ||
+                       $class6->column_info('Id2');
+        ok($id2_info->{is_foreign_key}, 'Foreign key detected');
 
         # fk that references a non-pk key (UNIQUE)
         my $obj8 = $rsobj8->find(1);
@@ -754,11 +764,11 @@ sub create {
                 id1 INTEGER NOT NULL,
                 iD2 INTEGER NOT NULL,
                 dat VARCHAR(8),
-                PRIMARY KEY (id1,id2)
+                PRIMARY KEY (id1,iD2)
             ) $self->{innodb}
         },
 
-        q{ INSERT INTO loader_test5 (id1,id2,dat) VALUES (1,1,'aaa') },
+        q{ INSERT INTO loader_test5 (id1,iD2,dat) VALUES (1,1,'aaa') },
 
         qq{
             CREATE TABLE loader_test6 (
@@ -771,7 +781,7 @@ sub create {
             ) $self->{innodb}
         },
 
-        (q{ INSERT INTO loader_test6 (id, id2,loader_test2_id,dat) } .
+        (q{ INSERT INTO loader_test6 (id, Id2,loader_test2_id,dat) } .
          q{ VALUES (1, 1,1,'aaa') }),
 
         qq{
@@ -953,7 +963,7 @@ sub create {
           CREATE TABLE loader_test32 (
             id INTEGER NOT NULL PRIMARY KEY,
             rel1 INTEGER NOT NULL,
-            rel2 INTEGER,
+            rel2 INTEGER $self->{null},
             FOREIGN KEY (rel1) REFERENCES loader_test31(id),
             FOREIGN KEY (rel2) REFERENCES loader_test31(id)
           ) $self->{innodb}
@@ -973,7 +983,7 @@ sub create {
           CREATE TABLE loader_test34 (
             id INTEGER NOT NULL PRIMARY KEY,
             rel1 INTEGER NOT NULL,
-            rel2 INTEGER,
+            rel2 INTEGER $self->{null},
             FOREIGN KEY (id,rel1) REFERENCES loader_test33(id1,id2),
             FOREIGN KEY (id,rel2) REFERENCES loader_test33(id1,id2)
           ) $self->{innodb}
@@ -986,7 +996,7 @@ sub create {
             CREATE TABLE loader_test10 (
                 id10 $self->{auto_inc_pk},
                 subject VARCHAR(8),
-                loader_test11 INTEGER
+                loader_test11 INTEGER $self->{null}
             ) $self->{innodb}
         },
         $make_auto_inc->(qw/loader_test10 id10/),
@@ -995,7 +1005,7 @@ sub create {
             CREATE TABLE loader_test11 (
                 id11 $self->{auto_inc_pk},
                 message VARCHAR(8) DEFAULT 'foo',
-                loader_test10 INTEGER,
+                loader_test10 INTEGER $self->{null},
                 FOREIGN KEY (loader_test10) REFERENCES loader_test10 (id10)
             ) $self->{innodb}
         },
@@ -1184,8 +1194,10 @@ sub drop_tables {
 
 sub DESTROY {
     my $self = shift;
-    $self->drop_tables if $self->{_created};
-    rmtree $DUMP_DIR;
+    unless ($ENV{SCHEMA_LOADER_TESTS_NOCLEANUP}) {
+       $self->drop_tables if $self->{_created};
+       rmtree $DUMP_DIR
+    }
 }
 
 1;