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