my $extra_count = $self->{extra}{count} || 0;
- plan tests => @connect_info * (178 + $extra_count + ($self->{data_type_tests}{test_count} || 0));
+ plan tests => @connect_info * (181 + $extra_count + ($self->{data_type_tests}{test_count} || 0));
foreach my $info_idx (0..$#connect_info) {
my $info = $connect_info[$info_idx];
my $file_count = grep /CREATE (?:TABLE|VIEW)/i, @{ $self->{extra}{create} || [] };
$file_count++; # schema
- $file_count++ if $self->{data_type_tests}{ddl};
+ $file_count++ for @{ $self->{data_type_tests}{table_names} || [] };
my $schema_class = $self->setup_schema($info, $file_count);
my ($monikers, $classes) = $self->monikers_and_classes($schema_class);
my %loader_opts = (
constraint =>
- qr/^(?:\S+\.)?(?:(?:$self->{vendor}|extra)_)?loader_test[0-9]+(?!.*_)/i,
+ qr/^(?:\S+\.)?(?:(?:$self->{vendor}|extra)_?)?loader_?test[0-9]+(?!.*_)/i,
relationships => 1,
additional_classes => 'TestAdditional',
additional_base_classes => 'TestAdditionalBase',
my $standard_sources = not defined $expected_count;
if ($standard_sources) {
- $expected_count = 36 + ($self->{data_type_tests}{test_count} ? 1 : 0);
+ $expected_count = 36;
+ $expected_count++ for @{ $self->{data_type_tests}{table_names} || [] };
$expected_count += grep /CREATE (?:TABLE|VIEW)/i,
@{ $self->{extra}{create} || [] };
$warn_count++ for grep /\b(?!loader_test9)\w+ has no primary key/i, @loader_warnings;
+ $warn_count++ for grep { my $w = $_; grep $w =~ $_, @{ $self->{warnings} || [] } } @loader_warnings;
+
if ($standard_sources) {
if($self->{skip_rels}) {
SKIP: {
'constant integer default',
);
+ is(
+ $class35->column_info('a_negative_int')->{default_value}, -42,
+ 'constant negative integer default',
+ );
+
cmp_ok(
$class35->column_info('a_double')->{default_value}, '==', 10.555,
'constant numeric default',
);
+ cmp_ok(
+ $class35->column_info('a_negative_double')->{default_value}, '==', -10.555,
+ 'constant negative numeric default',
+ );
+
my $function_default = $class35->column_info('a_function')->{default_value};
isa_ok( $function_default, 'SCALAR', 'default_value for function default' );
'might_have does not have is_deferrable');
# find on multi-col pk
- my $obj5 =
- eval { $rsobj5->find({id1 => 1, iD2 => 1}) } ||
- eval { $rsobj5->find({id1 => 1, id2 => 1}) };
- die $@ if $@;
-
- is( (eval { $obj5->id2 } || eval { $obj5->i_d2 }), 1, "Find on multi-col PK" );
+ if ($conn->_loader->preserve_case) {
+ my $obj5 = $rsobj5->find({id1 => 1, iD2 => 1});
+ is $obj5->i_d2, 1, 'Find on multi-col PK';
+ }
+ else {
+ my $obj5 = $rsobj5->find({id1 => 1, id2 => 1});
+ is $obj5->id2, 1, 'Find on multi-col PK';
+ }
# mulit-col fk def
my $obj6 = $rsobj6->find(1);
my $find_cb = sub {
return if -d;
- return if $_ eq 'LoaderTest30.pm';
+ return if /^(?:LoaderTest30|LoaderTest1|LoaderTest2X)\.pm\z/;
open my $fh, '<', $_ or die "Could not open $_ for reading: $!";
binmode $fh;
find $find_cb, $DUMP_DIR;
- my $before_digest = $digest->digest;
+# system "rm -f /tmp/before_rescan/* /tmp/after_rescan/*";
+# system "cp t/_common_dump/DBIXCSL_Test/Schema/*.pm /tmp/before_rescan";
+
+ my $before_digest = $digest->b64digest;
$conn->storage->disconnect; # needed for Firebird and Informix
my $dbh = $self->dbconnect(1);
};
is_deeply(\@new, [ qw/LoaderTest30/ ], "Rescan");
+# system "cp t/_common_dump/DBIXCSL_Test/Schema/*.pm /tmp/after_rescan";
+
$digest = Digest::MD5->new;
find $find_cb, $DUMP_DIR;
- my $after_digest = $digest->digest;
+ my $after_digest = $digest->b64digest;
is $before_digest, $after_digest,
'dumped files are not rewritten when there is no modification';
# run extra tests
$self->{extra}{run}->($conn, $monikers, $classes) if $self->{extra}{run};
+ $self->test_preserve_case($conn);
+
$self->drop_tables unless $ENV{SCHEMA_LOADER_TESTS_NOCLEANUP};
$conn->storage->disconnect;
}
}
+sub test_preserve_case {
+ my ($self, $conn) = @_;
+
+ my ($oqt, $cqt) = $self->get_oqt_cqt(always => 1); # open quote, close quote
+
+ my $dbh = $conn->storage->dbh;
+
+ {
+ # Silence annoying but harmless postgres "NOTICE: CREATE TABLE..."
+ local $SIG{__WARN__} = sub {
+ my $msg = shift;
+ warn $msg unless $msg =~ m{^NOTICE:\s+CREATE TABLE};
+ };
+
+ $dbh->do($_) for (
+qq|
+ CREATE TABLE ${oqt}LoaderTest40${cqt} (
+ ${oqt}Id${cqt} INTEGER NOT NULL PRIMARY KEY,
+ ${oqt}Foo3Bar${cqt} VARCHAR(100) NOT NULL
+ ) $self->{innodb}
+|,
+qq|
+ CREATE TABLE ${oqt}LoaderTest41${cqt} (
+ ${oqt}Id${cqt} INTEGER NOT NULL PRIMARY KEY,
+ ${oqt}LoaderTest40Id${cqt} INTEGER,
+ FOREIGN KEY (${oqt}LoaderTest40Id${cqt}) REFERENCES ${oqt}LoaderTest40${cqt} (${oqt}Id${cqt})
+ ) $self->{innodb}
+|,
+qq| INSERT INTO ${oqt}LoaderTest40${cqt} VALUES (1, 'foo') |,
+qq| INSERT INTO ${oqt}LoaderTest41${cqt} VALUES (1, 1) |,
+ );
+ }
+ $conn->storage->disconnect;
+
+ local $conn->_loader->{preserve_case} = 1;
+ $conn->_loader->_setup;
+
+ {
+ local $SIG{__WARN__} = sub {};
+ $conn->rescan;
+ }
+
+ if (not $self->{skip_rels}) {
+ is $conn->resultset('LoaderTest41')->find(1)->loader_test40->foo3_bar, 'foo',
+ 'rel and accessor for mixed-case column name in mixed case table';
+ }
+ else {
+ is $conn->resultset('LoaderTest40')->find(1)->foo3_bar, 'foo',
+ 'accessor for mixed-case column name in mixed case table';
+ }
+}
+
sub monikers_and_classes {
my ($self, $schema_class) = @_;
my ($monikers, $classes);
return $dbh;
}
+sub get_oqt_cqt {
+ my $self = shift;
+ my %opts = @_;
+
+ if ((not $opts{always}) && $self->{preserve_case_mode_is_exclusive}) {
+ return ('', '');
+ }
+
+ # XXX should get quote_char from the storage of an initialized loader.
+ my ($oqt, $cqt); # open quote, close quote
+ if (ref $self->{quote_char}) {
+ ($oqt, $cqt) = @{ $self->{quote_char} };
+ }
+ else {
+ $oqt = $cqt = $self->{quote_char} || '';
+ }
+
+ return ($oqt, $cqt);
+}
+
sub create {
my $self = shift;
id INTEGER NOT NULL PRIMARY KEY,
a_varchar VARCHAR(100) DEFAULT 'foo',
an_int INTEGER DEFAULT 42,
+ a_negative_int INTEGER DEFAULT -42,
a_double DOUBLE PRECISION DEFAULT 10.555,
+ a_negative_double DOUBLE PRECISION DEFAULT -10.555,
a_function $self->{default_function_def}
) $self->{innodb}
},
},
);
+ # some DBs require mixed case identifiers to be quoted
+ my ($oqt, $cqt) = $self->get_oqt_cqt;
+
@statements_reltests = (
qq{
CREATE TABLE loader_test3 (
q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(125,3,'ccc') },
q{ INSERT INTO loader_test4 (id,fkid,dat) VALUES(126,4,'ddd') },
- qq{
+ qq|
CREATE TABLE loader_test5 (
id1 INTEGER NOT NULL,
- iD2 INTEGER NOT NULL,
+ ${oqt}iD2${cqt} INTEGER NOT NULL,
dat VARCHAR(8),
from_id INTEGER $self->{null},
to_id INTEGER $self->{null},
- PRIMARY KEY (id1,iD2),
+ PRIMARY KEY (id1,${oqt}iD2${cqt}),
FOREIGN KEY (from_id) REFERENCES loader_test4 (id),
FOREIGN KEY (to_id) REFERENCES loader_test4 (id)
) $self->{innodb}
- },
+ |,
- q{ INSERT INTO loader_test5 (id1,iD2,dat) VALUES (1,1,'aaa') },
+ qq| INSERT INTO loader_test5 (id1,${oqt}iD2${cqt},dat) VALUES (1,1,'aaa') |,
- qq{
+ qq|
CREATE TABLE loader_test6 (
id INTEGER NOT NULL PRIMARY KEY,
- Id2 INTEGER,
+ ${oqt}Id2${cqt} INTEGER,
loader_test2_id INTEGER,
dat VARCHAR(8),
FOREIGN KEY (loader_test2_id) REFERENCES loader_test2 (id),
- FOREIGN KEY(id,Id2) REFERENCES loader_test5 (id1,iD2)
+ FOREIGN KEY(id,${oqt}Id2${cqt}) REFERENCES loader_test5 (id1,${oqt}iD2${cqt})
) $self->{innodb}
- },
+ |,
- (q{ INSERT INTO loader_test6 (id, Id2,loader_test2_id,dat) } .
+ (qq| INSERT INTO loader_test6 (id, ${oqt}Id2${cqt},loader_test2_id,dat) | .
q{ VALUES (1, 1,1,'aaa') }),
qq{
$dbh->do($_) foreach (@statements);
- $dbh->do($_) foreach (@{ $self->{data_type_tests}{ddl} || {} });
+ $dbh->do($_) foreach (@{ $self->{data_type_tests}{ddl} || [] });
unless($self->{skip_rels}) {
# hack for now, since DB2 doesn't like inline comments, and we need
my @tables_rescan = qw/ loader_test30 /;
+ my @tables_preserve_case_tests = qw/ LoaderTest41 LoaderTest40 /;
+
my $drop_fk_mysql =
q{ALTER TABLE loader_test10 DROP FOREIGN KEY loader_test11_fk};
unless($self->{skip_rels}) {
$dbh->do("DROP TABLE $_") for (@tables_reltests);
+ $dbh->do("DROP TABLE $_") for (@tables_reltests);
if($self->{vendor} =~ /mysql/i) {
$dbh->do($drop_fk_mysql);
}
$dbh->do($_) for map { $drop_auto_inc->(@$_) } @tables_auto_inc;
$dbh->do("DROP TABLE $_") for (@tables, @tables_rescan);
- foreach my $data_type_table (@{ $self->{data_type_tests}{table_names} || {} }) {
+ foreach my $data_type_table (@{ $self->{data_type_tests}{table_names} || [] }) {
$dbh->do("DROP TABLE $data_type_table");
}
+ my ($oqt, $cqt) = $self->get_oqt_cqt(always => 1);
+
+ $dbh->do("DROP TABLE ${oqt}${_}${cqt}") for @tables_preserve_case_tests;
+
$dbh->disconnect;
# fixup for Firebird
}
my %DATA_TYPE_MULTI_TABLE_OVERRIDES = (
- oracle => qr/\blong\b/,
+ oracle => qr/\blong\b/i,
+ mssql => qr/\b(?:timestamp|rowversion)\b/i,
+ informix => qr/\b(?:bigserial|serial8)\b/i,
);
sub setup_data_type_tests {
my $tests = $self->{data_type_tests} = {};
# split types into tables based on overrides
- my @types = keys %$types;
- my @split_off_types = grep /$DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})}/i, @types;
- my @first_table_types = grep !/$DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})}/i, @types;
+ my (@types, @split_off_types, @first_table_types);
+ {
+ my $split_off_re = $DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})} || qr/(?!)/;
+
+ @types = keys %$types;
+ @split_off_types = grep /$split_off_re/, @types;
+ @first_table_types = grep !/$split_off_re/, @types;
+ }
@types = +{ map +($_, $types->{$_}), @first_table_types },
map +{ $_, $types->{$_} }, @split_off_types;