1 #include <iostream>
2
3 #include <pqxx/subtransaction>
4 #include <pqxx/transaction>
5
6 #include "test_helpers.hxx"
7
8
9 // Test program for libpqxx. Attempt to perform nested transactions.
10 namespace
11 {
test_088()12 void test_088()
13 {
14 pqxx::connection conn;
15
16 pqxx::work tx0{conn};
17 pqxx::test::create_pqxxevents(tx0);
18
19 // Trivial test: create subtransactions, and commit/abort
20 std::cout << tx0.exec1("SELECT 'tx0 starts'")[0].c_str() << std::endl;
21
22 pqxx::subtransaction T0a(static_cast<pqxx::dbtransaction &>(tx0), "T0a");
23 T0a.commit();
24
25 pqxx::subtransaction T0b(static_cast<pqxx::dbtransaction &>(tx0), "T0b");
26 T0b.abort();
27 std::cout << tx0.exec1("SELECT 'tx0 ends'")[0].c_str() << std::endl;
28 tx0.commit();
29
30 // Basic functionality: perform query in subtransaction; abort, continue
31 pqxx::work tx1{conn, "tx1"};
32 std::cout << tx1.exec1("SELECT 'tx1 starts'")[0].c_str() << std::endl;
33 pqxx::subtransaction tx1a{tx1, "tx1a"};
34 std::cout << tx1a.exec1("SELECT ' a'")[0].c_str() << std::endl;
35 tx1a.commit();
36 pqxx::subtransaction tx1b{tx1, "tx1b"};
37 std::cout << tx1b.exec1("SELECT ' b'")[0].c_str() << std::endl;
38 tx1b.abort();
39 pqxx::subtransaction tx1c{tx1, "tx1c"};
40 std::cout << tx1c.exec1("SELECT ' c'")[0].c_str() << std::endl;
41 tx1c.commit();
42 std::cout << tx1.exec1("SELECT 'tx1 ends'")[0].c_str() << std::endl;
43 tx1.commit();
44
45 // Commit/rollback functionality
46 pqxx::work tx2{conn, "tx2"};
47 std::string const Table{"test088"};
48 tx2.exec0("CREATE TEMP TABLE " + Table + "(no INTEGER, text VARCHAR)");
49
50 tx2.exec0("INSERT INTO " + Table + " VALUES(1,'tx2')");
51
52 pqxx::subtransaction tx2a{tx2, "tx2a"};
53 tx2a.exec0("INSERT INTO " + Table + " VALUES(2,'tx2a')");
54 tx2a.commit();
55 pqxx::subtransaction tx2b{tx2, "tx2b"};
56 tx2b.exec0("INSERT INTO " + Table + " VALUES(3,'tx2b')");
57 tx2b.abort();
58 pqxx::subtransaction tx2c{tx2, "tx2c"};
59 tx2c.exec0("INSERT INTO " + Table + " VALUES(4,'tx2c')");
60 tx2c.commit();
61 auto const R{tx2.exec("SELECT * FROM " + Table + " ORDER BY no")};
62 for (auto const &i : R)
63 std::cout << '\t' << i[0].c_str() << '\t' << i[1].c_str() << std::endl;
64
65 PQXX_CHECK_EQUAL(std::size(R), 3, "Wrong number of results.");
66
67 int expected[3]{1, 2, 4};
68 for (pqxx::result::size_type n{0}; n < std::size(R); ++n)
69 PQXX_CHECK_EQUAL(
70 R[n][0].as<int>(), expected[n], "Hit unexpected row number.");
71
72 tx2.abort();
73
74 // Auto-abort should only roll back the subtransaction.
75 pqxx::work tx3{conn, "tx3"};
76 pqxx::subtransaction tx3a(tx3, "tx3a");
77 PQXX_CHECK_THROWS(
78 tx3a.exec("SELECT * FROM nonexistent_table WHERE nonattribute=0"),
79 pqxx::sql_error, "Bogus query did not fail.");
80
81 // Subtransaction can only be aborted now, because there was an error.
82 tx3a.abort();
83 // We're back in our top-level transaction. This did not abort.
84 tx3.exec1("SELECT count(*) FROM pqxxevents");
85 // Make sure we can commit exactly one more level of transaction.
86 tx3.commit();
87 }
88 } // namespace
89
90
91 PQXX_REGISTER_TEST(test_088);
92