1 | #include "catch.hpp" |
2 | #include "test_helpers.hpp" |
3 | |
4 | using namespace duckdb; |
5 | using namespace std; |
6 | |
7 | TEST_CASE("Simple table creation transaction tests" , "[transactions]" ) { |
8 | unique_ptr<QueryResult> result; |
9 | DuckDB db(nullptr); |
10 | // create two connections |
11 | Connection con_one(db); |
12 | Connection con_two(db); |
13 | |
14 | // start transactions |
15 | result = con_one.Query("BEGIN TRANSACTION" ); |
16 | REQUIRE(result->success); |
17 | result = con_two.Query("BEGIN TRANSACTION" ); |
18 | REQUIRE(result->success); |
19 | |
20 | // create a table on connection one |
21 | result = con_one.Query("CREATE TABLE integers(i INTEGER)" ); |
22 | REQUIRE(result->success); |
23 | // connection one should be able to query the table |
24 | result = con_one.Query("SELECT * FROM integers" ); |
25 | REQUIRE(result->success); |
26 | // connection two should not be able to |
27 | result = con_two.Query("SELECT * FROM integers" ); |
28 | REQUIRE(!result->success); |
29 | // if we rollback, nobody should be able to query the table |
30 | result = con_one.Query("ROLLBACK" ); |
31 | REQUIRE(result->success); |
32 | |
33 | result = con_one.Query("SELECT * FROM integers" ); |
34 | REQUIRE(!result->success); |
35 | result = con_two.Query("SELECT * FROM integers" ); |
36 | REQUIRE(!result->success); |
37 | |
38 | // now if we commit the table |
39 | result = con_one.Query("BEGIN TRANSACTION" ); |
40 | REQUIRE(result->success); |
41 | result = con_one.Query("CREATE TABLE integers(i INTEGER)" ); |
42 | REQUIRE(result->success); |
43 | result = con_one.Query("COMMIT" ); |
44 | REQUIRE(result->success); |
45 | |
46 | // con two STILL should not see it because it was started before the |
47 | // transaction committed |
48 | result = con_two.Query("SELECT * FROM integers" ); |
49 | REQUIRE(!result->success); |
50 | |
51 | // but if we rollback and start a new transaction it should see it |
52 | result = con_two.Query("ROLLBACK" ); |
53 | REQUIRE(result->success); |
54 | result = con_two.Query("SELECT * FROM integers" ); |
55 | REQUIRE(result->success); |
56 | |
57 | // serialize conflict |
58 | |
59 | // start transactions |
60 | result = con_one.Query("BEGIN TRANSACTION" ); |
61 | REQUIRE(result->success); |
62 | result = con_two.Query("BEGIN TRANSACTION" ); |
63 | REQUIRE(result->success); |
64 | |
65 | // create a table on connection one |
66 | result = con_one.Query("CREATE TABLE integers2(i INTEGER)" ); |
67 | REQUIRE(result->success); |
68 | |
69 | // create a table on connection two with the same name |
70 | result = con_one.Query("CREATE TABLE integers2(i INTEGER)" ); |
71 | REQUIRE(!result->success); |
72 | } |
73 | |
74 | TEST_CASE("Stacked schema changes" , "[transactions]" ) { |
75 | unique_ptr<QueryResult> result; |
76 | DuckDB db(nullptr); |
77 | // create two connections |
78 | Connection con(db); |
79 | |
80 | con.Query("CREATE TABLE a(i INTEGER)" ); |
81 | con.Query("INSERT INTO a VALUES (44)" ); |
82 | result = con.Query("SELECT i FROM a" ); |
83 | REQUIRE(CHECK_COLUMN(result, 0, {44})); |
84 | |
85 | con.Query("BEGIN TRANSACTION" ); |
86 | con.Query("DROP TABLE a" ); |
87 | con.Query("CREATE TABLE a(i INTEGER)" ); |
88 | con.Query("INSERT INTO a VALUES (45)" ); |
89 | result = con.Query("SELECT i FROM a" ); |
90 | REQUIRE(CHECK_COLUMN(result, 0, {45})); |
91 | con.Query("ROLLBACK" ); |
92 | |
93 | result = con.Query("SELECT i FROM a" ); |
94 | REQUIRE(CHECK_COLUMN(result, 0, {44})); |
95 | |
96 | con.Query("BEGIN TRANSACTION" ); |
97 | con.Query("DROP TABLE a" ); |
98 | con.Query("CREATE TABLE a(i INTEGER)" ); |
99 | con.Query("INSERT INTO a VALUES (46)" ); |
100 | result = con.Query("SELECT i FROM a" ); |
101 | REQUIRE(CHECK_COLUMN(result, 0, {46})); |
102 | result = con.Query("COMMIT" ); |
103 | |
104 | result = con.Query("SELECT i FROM a" ); |
105 | REQUIRE(CHECK_COLUMN(result, 0, {46})); |
106 | } |
107 | |