1 | #include "catch.hpp" |
2 | #include "test_helpers.hpp" |
3 | |
4 | using namespace duckdb; |
5 | using namespace std; |
6 | |
7 | TEST_CASE("Schema creation/deletion" , "[catalog]" ) { |
8 | unique_ptr<QueryResult> result; |
9 | DuckDB db(nullptr); |
10 | Connection con(db); |
11 | |
12 | // cannot drop MAIN schema |
13 | REQUIRE_FAIL(con.Query("DROP SCHEMA main CASCADE;" )); |
14 | |
15 | // create and drop an empty schema |
16 | REQUIRE_NO_FAIL(con.Query("CREATE SCHEMA test;" )); |
17 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA test;" )); |
18 | |
19 | // create the schema again |
20 | REQUIRE_NO_FAIL(con.Query("CREATE SCHEMA test;" )); |
21 | // duplicate schema |
22 | REQUIRE_FAIL(con.Query("CREATE SCHEMA test;" )); |
23 | // if not exists ignores error |
24 | REQUIRE_NO_FAIL(con.Query("CREATE SCHEMA IF NOT EXISTS test;" )); |
25 | |
26 | // create table inside schema that exists should succeed |
27 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test.hello(i INTEGER);" )); |
28 | // create table inside schema that does not exist should fail |
29 | REQUIRE_FAIL(con.Query("CREATE TABLE test2.hello(i INTEGER);" )); |
30 | |
31 | // use the table in queries |
32 | // insert into table |
33 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test.hello VALUES (2), (3), (4)" )); |
34 | // select from table without schema specified should fail |
35 | REQUIRE_FAIL(con.Query("SELECT * FROM hello" )); |
36 | |
37 | // with schema specified should succeed |
38 | result = con.Query("SELECT * FROM test.hello" ); |
39 | REQUIRE(CHECK_COLUMN(result, 0, {2, 3, 4})); |
40 | |
41 | // drop schema with dependencies should fail |
42 | REQUIRE_FAIL(con.Query("DROP SCHEMA test;" )); |
43 | // unless we use cascade to drop |
44 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA test CASCADE;" )); |
45 | // drop schema if exists should not fail if schema does not exist |
46 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA IF EXISTS test;" )); |
47 | // but drop schema without it should fail |
48 | REQUIRE_FAIL(con.Query("DROP SCHEMA test;" )); |
49 | } |
50 | |
51 | TEST_CASE("Schema creation/deletion with transactions" , "[catalog]" ) { |
52 | unique_ptr<QueryResult> result; |
53 | DuckDB db(nullptr); |
54 | Connection con(db); |
55 | |
56 | // create a schema with a table |
57 | REQUIRE_NO_FAIL(con.Query("CREATE SCHEMA test;" )); |
58 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test.hello(i INTEGER);" )); |
59 | |
60 | // in one transaction drop the table and then the schema (without cascade) |
61 | REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION;" )); |
62 | REQUIRE_NO_FAIL(con.Query("DROP TABLE test.hello;" )); |
63 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA test;" )); |
64 | REQUIRE_NO_FAIL(con.Query("COMMIT;" )); |
65 | |
66 | // now work with multiple connections |
67 | Connection con2(db); |
68 | |
69 | // create the same schema |
70 | REQUIRE_NO_FAIL(con.Query("CREATE SCHEMA test;" )); |
71 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test.hello(i INTEGER);" )); |
72 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test.hello VALUES (2), (3), (4)" )); |
73 | |
74 | // begin the transactions |
75 | REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION" )); |
76 | REQUIRE_NO_FAIL(con2.Query("BEGIN TRANSACTION" )); |
77 | |
78 | // con1 drops the schema and commits it |
79 | REQUIRE_NO_FAIL(con.Query("DROP TABLE test.hello;" )); |
80 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA test;" )); |
81 | REQUIRE_NO_FAIL(con.Query("COMMIT;" )); |
82 | |
83 | // con2 queries the schema (should still work) |
84 | result = con2.Query("SELECT * FROM test.hello" ); |
85 | REQUIRE(CHECK_COLUMN(result, 0, {2, 3, 4})); |
86 | |
87 | // now con2 finishes the transaction and tries again |
88 | REQUIRE_NO_FAIL(con2.Query("ROLLBACK;" )); |
89 | REQUIRE_FAIL(con2.Query("SELECT * FROM test.hello" )); |
90 | } |
91 | |
92 | TEST_CASE("Catalog conflicts" , "[catalog]" ) { |
93 | unique_ptr<QueryResult> result; |
94 | DuckDB db(nullptr); |
95 | Connection con(db), con2(db); |
96 | |
97 | REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION;" )); |
98 | REQUIRE_NO_FAIL(con2.Query("BEGIN TRANSACTION;" )); |
99 | |
100 | // create the same schema in both connections |
101 | REQUIRE_NO_FAIL(con.Query("CREATE SCHEMA test;" )); |
102 | // this should cause a conflict |
103 | REQUIRE_FAIL(con2.Query("CREATE SCHEMA test;" )); |
104 | |
105 | REQUIRE_NO_FAIL(con.Query("COMMIT" )); |
106 | REQUIRE_NO_FAIL(con2.Query("ROLLBACK" )); |
107 | |
108 | // now try the same with DROP SCHEMA |
109 | REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION;" )); |
110 | REQUIRE_NO_FAIL(con2.Query("BEGIN TRANSACTION;" )); |
111 | |
112 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA test;" )); |
113 | // this should cause a conflict |
114 | REQUIRE_FAIL(con2.Query("DROP SCHEMA test;" )); |
115 | |
116 | // rollback the drop |
117 | REQUIRE_NO_FAIL(con.Query("ROLLBACK" )); |
118 | REQUIRE_NO_FAIL(con2.Query("ROLLBACK" )); |
119 | |
120 | // now the schema should still exist, so we can drop it again |
121 | REQUIRE_NO_FAIL(con.Query("DROP SCHEMA test;" )); |
122 | } |
123 | |