1#include "catch.hpp"
2#include "test_helpers.hpp"
3
4using namespace duckdb;
5using namespace std;
6
7TEST_CASE("Test that index entries are properly removed after aborted append", "[transactions][.]") {
8 unique_ptr<QueryResult> result;
9 DuckDB db(nullptr);
10 Connection con(db), con2(db);
11 con.EnableQueryVerification();
12
13 REQUIRE_NO_FAIL(con.Query("CREATE TABLE integers(i INTEGER PRIMARY KEY);"));
14
15 REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION;"));
16 REQUIRE_NO_FAIL(con2.Query("BEGIN TRANSACTION;"));
17
18 REQUIRE_NO_FAIL(con.Query("INSERT INTO integers VALUES (1);"));
19 // insert the values [2..2048] into the table
20 for (int i = 2; i <= 2048; i++) {
21 REQUIRE_NO_FAIL(con2.Query("INSERT INTO integers VALUES (" + to_string(i) + ");"));
22 }
23 REQUIRE_NO_FAIL(con2.Query("INSERT INTO integers VALUES (" + to_string(1) + ");"));
24
25 // con commits first
26 REQUIRE_NO_FAIL(con.Query("COMMIT;"));
27 // con2 fails to commit because of the conflict
28 REQUIRE_FAIL(con2.Query("COMMIT;"));
29
30 result = con.Query("SELECT * FROM integers");
31 REQUIRE(CHECK_COLUMN(result, 0, {1}));
32
33 // now append the rows [2..2048 again]
34 REQUIRE_NO_FAIL(con2.Query("BEGIN TRANSACTION;"));
35 for (int i = 2; i <= 2048; i++) {
36 REQUIRE_NO_FAIL(con2.Query("INSERT INTO integers VALUES (" + to_string(i) + ");"));
37 }
38 // this time the commit should work
39 REQUIRE_NO_FAIL(con2.Query("COMMIT;"));
40
41 result = con.Query("SELECT COUNT(*), MIN(i), MAX(i) FROM integers ORDER BY 1");
42 REQUIRE(CHECK_COLUMN(result, 0, {2048}));
43 REQUIRE(CHECK_COLUMN(result, 1, {1}));
44 REQUIRE(CHECK_COLUMN(result, 2, {2048}));
45}
46
47TEST_CASE("Test abort of big append", "[transactions][.]") {
48 unique_ptr<QueryResult> result;
49 DuckDB db(nullptr);
50 Connection con(db), con2(db);
51 con.EnableQueryVerification();
52
53 REQUIRE_NO_FAIL(con.Query("CREATE TABLE integers(i INTEGER PRIMARY KEY);"));
54
55 REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION;"));
56 REQUIRE_NO_FAIL(con2.Query("BEGIN TRANSACTION;"));
57
58 // insert two blocks worth of values into the table in con2, plus the value [1]
59 // and the value [1] in con
60 REQUIRE_NO_FAIL(con.Query("INSERT INTO integers VALUES (1);"));
61 idx_t tpl_count = 2 * Storage::BLOCK_SIZE / sizeof(int);
62 auto prepared = con2.Prepare("INSERT INTO integers VALUES (?)");
63 for (int i = 2; i < (int32_t)tpl_count; i++) {
64 REQUIRE_NO_FAIL(prepared->Execute(i));
65 }
66 // finally insert the value "1"
67 REQUIRE_NO_FAIL(prepared->Execute(1));
68
69 // con commits first
70 REQUIRE_NO_FAIL(con.Query("COMMIT;"));
71 // con2 fails to commit because of the conflict
72 REQUIRE_FAIL(con2.Query("COMMIT;"));
73
74 result = con.Query("SELECT * FROM integers");
75 REQUIRE(CHECK_COLUMN(result, 0, {1}));
76
77 // now append some rows again
78 REQUIRE_NO_FAIL(con.Query("INSERT INTO integers VALUES (2);"));
79 REQUIRE_NO_FAIL(con.Query("INSERT INTO integers VALUES (3);"));
80 REQUIRE_NO_FAIL(con.Query("INSERT INTO integers VALUES (4);"));
81
82 result = con.Query("SELECT * FROM integers ORDER BY 1");
83 REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 4}));
84}
85