Commit | Line | Data |
86a51471 |
1 | use strict; |
2 | use warnings; |
3 | |
4 | use Test::More; |
5 | use Test::Exception; |
632d1e0f |
6 | use Test::Warn; |
2aeb3c7f |
7 | use Time::HiRes 'time'; |
67b35a45 |
8 | use Config; |
9 | |
86a51471 |
10 | use lib qw(t/lib); |
11 | use DBICTest; |
12 | |
67b35a45 |
13 | # savepoints test |
14 | { |
15 | my $schema = DBICTest->init_schema(auto_savepoint => 1); |
86a51471 |
16 | |
67b35a45 |
17 | my $ars = $schema->resultset('Artist'); |
86a51471 |
18 | |
67b35a45 |
19 | # test two-phase commit and inner transaction rollback from nested transactions |
86a51471 |
20 | $schema->txn_do(sub { |
67b35a45 |
21 | $ars->create({ name => 'in_outer_transaction' }); |
86a51471 |
22 | $schema->txn_do(sub { |
67b35a45 |
23 | $ars->create({ name => 'in_inner_transaction' }); |
86a51471 |
24 | }); |
67b35a45 |
25 | ok($ars->search({ name => 'in_inner_transaction' })->first, |
26 | 'commit from inner transaction visible in outer transaction'); |
27 | throws_ok { |
28 | $schema->txn_do(sub { |
29 | $ars->create({ name => 'in_inner_transaction_rolling_back' }); |
30 | die 'rolling back inner transaction'; |
31 | }); |
32 | } qr/rolling back inner transaction/, 'inner transaction rollback executed'; |
33 | $ars->create({ name => 'in_outer_transaction2' }); |
34 | }); |
35 | |
36 | ok($ars->search({ name => 'in_outer_transaction' })->first, |
37 | 'commit from outer transaction'); |
38 | ok($ars->search({ name => 'in_outer_transaction2' })->first, |
39 | 'second commit from outer transaction'); |
40 | ok($ars->search({ name => 'in_inner_transaction' })->first, |
41 | 'commit from inner transaction'); |
42 | is $ars->search({ name => 'in_inner_transaction_rolling_back' })->first, |
43 | undef, |
44 | 'rollback from inner transaction'; |
45 | } |
632d1e0f |
46 | |
2aeb3c7f |
47 | # check that we work somewhat OK with braindead SQLite transaction handling |
48 | # |
49 | # As per https://metacpan.org/source/ADAMK/DBD-SQLite-1.37/lib/DBD/SQLite.pm#L921 |
50 | # SQLite does *not* try to synchronize |
ab0b0a09 |
51 | # |
52 | # However DBD::SQLite 1.38_02 seems to fix this, with an accompanying test: |
53 | # https://metacpan.org/source/ADAMK/DBD-SQLite-1.38_02/t/54_literal_txn.t |
54 | |
55 | my $lit_txn_todo = eval { DBD::SQLite->VERSION(1.38_02) } |
56 | ? undef |
57 | : "DBD::SQLite before 1.38_02 is retarded wrt detecting literal BEGIN/COMMIT statements" |
58 | ; |
2aeb3c7f |
59 | |
60 | for my $prefix_comment (qw/Begin_only Commit_only Begin_and_Commit/) { |
61 | note "Testing with comment prefixes on $prefix_comment"; |
62 | |
63 | # FIXME warning won't help us for the time being |
64 | # perhaps when (if ever) DBD::SQLite gets fixed, |
65 | # we can do something extra here |
66 | local $SIG{__WARN__} = sub { warn @_ if $_[0] !~ /Internal transaction state .+? does not seem to match/ } |
ab0b0a09 |
67 | if ( $lit_txn_todo && !$ENV{TEST_VERBOSE} ); |
2aeb3c7f |
68 | |
69 | my ($c_begin, $c_commit) = map { $prefix_comment =~ $_ ? 1 : 0 } (qr/Begin/, qr/Commit/); |
70 | |
71 | my $schema = DBICTest->init_schema( no_deploy => 1 ); |
72 | my $ars = $schema->resultset('Artist'); |
73 | |
74 | ok (! $schema->storage->connected, 'No connection yet'); |
75 | |
76 | $schema->storage->dbh->do(<<'DDL'); |
77 | CREATE TABLE artist ( |
78 | artistid INTEGER PRIMARY KEY NOT NULL, |
79 | name varchar(100), |
80 | rank integer DEFAULT 13, |
81 | charfield char(10) NULL |
82 | ); |
83 | DDL |
84 | |
85 | my $artist = $ars->create({ name => 'Artist_' . time() }); |
86 | is ($ars->count, 1, 'Inserted artist ' . $artist->name); |
87 | |
88 | ok ($schema->storage->connected, 'Connected'); |
89 | ok ($schema->storage->_dbh->{AutoCommit}, 'DBD not in txn yet'); |
90 | |
91 | $schema->storage->dbh->do(join "\n", |
92 | $c_begin ? '-- comment' : (), |
93 | 'BEGIN TRANSACTION' |
94 | ); |
95 | ok ($schema->storage->connected, 'Still connected'); |
96 | { |
ab0b0a09 |
97 | local $TODO = $lit_txn_todo if $c_begin; |
2aeb3c7f |
98 | ok (! $schema->storage->_dbh->{AutoCommit}, "DBD aware of txn begin with comments on $prefix_comment"); |
99 | } |
100 | |
101 | $schema->storage->dbh->do(join "\n", |
102 | $c_commit ? '-- comment' : (), |
103 | 'COMMIT' |
104 | ); |
105 | ok ($schema->storage->connected, 'Still connected'); |
106 | { |
ab0b0a09 |
107 | local $TODO = $lit_txn_todo if $c_commit and ! $c_begin; |
2aeb3c7f |
108 | ok ($schema->storage->_dbh->{AutoCommit}, "DBD aware txn ended with comments on $prefix_comment"); |
109 | } |
110 | |
111 | is ($ars->count, 1, 'Inserted artists still there'); |
112 | |
113 | { |
114 | # this never worked in the 1st place |
ab0b0a09 |
115 | local $TODO = $lit_txn_todo if ! $c_begin and $c_commit; |
2aeb3c7f |
116 | |
08615cfb |
117 | # odd argument passing, because such nested crefs leak on 5.8 |
2aeb3c7f |
118 | lives_ok { |
119 | $schema->storage->txn_do (sub { |
08615cfb |
120 | ok ($_[0]->find({ name => $_[1] }), "Artist still where we left it after cycle with comments on $prefix_comment"); |
121 | }, $ars, $artist->name ); |
2aeb3c7f |
122 | } "Succesfull transaction with comments on $prefix_comment"; |
123 | } |
124 | } |
125 | |
126 | |
67b35a45 |
127 | my $schema = DBICTest->init_schema(); |
86a51471 |
128 | |
632d1e0f |
129 | # make sure the side-effects of RT#67581 do not result in data loss |
130 | my $row; |
67b35a45 |
131 | warnings_exist { $row = $schema->resultset('Artist')->create ({ name => 'alpha rank', rank => 'abc' }) } |
445bc0cd |
132 | [qr/Non-integer value supplied for column 'rank' despite the integer datatype/], |
632d1e0f |
133 | 'proper warning on string insertion into an numeric column' |
134 | ; |
135 | $row->discard_changes; |
136 | is ($row->rank, 'abc', 'proper rank inserted into database'); |
137 | |
67b35a45 |
138 | # and make sure we do not lose actual bigints |
139 | { |
140 | package DBICTest::BigIntArtist; |
141 | use base 'DBICTest::Schema::Artist'; |
142 | __PACKAGE__->table('artist'); |
143 | __PACKAGE__->add_column(bigint => { data_type => 'bigint' }); |
144 | } |
145 | $schema->register_class(BigIntArtist => 'DBICTest::BigIntArtist'); |
146 | $schema->storage->dbh_do(sub { |
147 | $_[1]->do('ALTER TABLE artist ADD COLUMN bigint BIGINT'); |
148 | }); |
149 | |
150 | # test upper/lower boundaries for sqlite and some values inbetween |
151 | # range is -(2**63) .. 2**63 - 1 |
2e092442 |
152 | SKIP: { |
153 | skip 'This perl does not seem to have 64bit int support - DBI roundtrip of large int will fail with DBD::SQLite < 1.37', 1 |
154 | if ($Config{ivsize} < 8 and ! eval { DBD::SQLite->VERSION(1.37); 1 }); |
67b35a45 |
155 | |
2e092442 |
156 | for my $bi (qw/ |
157 | -9223372036854775808 |
158 | -9223372036854775807 |
159 | -8694837494948124658 |
160 | -6848440844435891639 |
161 | -5664812265578554454 |
162 | -5380388020020483213 |
163 | -2564279463598428141 |
164 | 2442753333597784273 |
165 | 4790993557925631491 |
166 | 6773854980030157393 |
167 | 7627910776496326154 |
168 | 8297530189347439311 |
169 | 9223372036854775806 |
170 | 9223372036854775807 |
171 | /) { |
172 | $row = $schema->resultset('BigIntArtist')->create({ bigint => $bi }); |
173 | is ($row->bigint, $bi, "value in object correct ($bi)"); |
67b35a45 |
174 | |
175 | $row->discard_changes; |
176 | is ($row->bigint, $bi, "value in database correct ($bi)"); |
177 | } |
178 | } |
179 | |
86a51471 |
180 | done_testing; |
181 | |
182 | # vim:sts=2 sw=2: |