test10.cxx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include <cstdio>
  2. #include <iostream>
  3. #include <vector>
  4. #include <pqxx/nontransaction>
  5. #include "test_helpers.hxx"
  6. using namespace pqxx;
  7. // Test program for libpqxx. Open connection to database, start a transaction,
  8. // abort it, and verify that it "never happened."
  9. namespace
  10. {
  11. // Let's take a boring year that is not going to be in the "pqxxevents" table
  12. constexpr int BoringYear{1977};
  13. std::string const Table("pqxxevents");
  14. // Count events, and boring events, in table
  15. std::pair<int, int> CountEvents(transaction_base &T)
  16. {
  17. std::string const events_query{"SELECT count(*) FROM " + Table};
  18. std::string const boring_query{
  19. events_query + " WHERE year=" + to_string(BoringYear)};
  20. return std::make_pair(
  21. T.query_value<int>(events_query), T.query_value<int>(boring_query));
  22. }
  23. // Try adding a record, then aborting it, and check whether the abort was
  24. // performed correctly.
  25. void Test(connection &C, bool ExplicitAbort)
  26. {
  27. std::pair<int, int> EventCounts;
  28. // First run our doomed transaction. This will refuse to run if an event
  29. // exists for our Boring Year.
  30. {
  31. // Begin a transaction acting on our current connection; we'll abort it
  32. // later though.
  33. work Doomed{C, "Doomed"};
  34. // Verify that our Boring Year was not yet in the events table
  35. EventCounts = CountEvents(Doomed);
  36. PQXX_CHECK_EQUAL(
  37. EventCounts.second, 0, "Can't run, boring year is already in table.");
  38. // Now let's try to introduce a row for our Boring Year
  39. Doomed.exec0(
  40. "INSERT INTO " + Table +
  41. "(year, event) "
  42. "VALUES (" +
  43. to_string(BoringYear) + ", 'yawn')");
  44. auto const Recount{CountEvents(Doomed)};
  45. PQXX_CHECK_EQUAL(
  46. Recount.second, 1, "Wrong # events for " + to_string(BoringYear));
  47. PQXX_CHECK_EQUAL(
  48. Recount.first, EventCounts.first + 1, "Number of events changed.");
  49. // Okay, we've added an entry but we don't really want to. Abort it
  50. // explicitly if requested, or simply let the Transaction object "expire."
  51. if (ExplicitAbort)
  52. Doomed.abort();
  53. // If now explicit abort requested, Doomed Transaction still ends here
  54. }
  55. // Now check that we're back in the original state. Note that this may go
  56. // wrong if somebody managed to change the table between our two
  57. // transactions.
  58. work Checkup(C, "Checkup");
  59. auto const NewEvents{CountEvents(Checkup)};
  60. PQXX_CHECK_EQUAL(
  61. NewEvents.first, EventCounts.first,
  62. "Number of events changed. This may be due to a bug in libpqxx, "
  63. "or the test table was modified by some other process.");
  64. PQXX_CHECK_EQUAL(
  65. NewEvents.second, 0,
  66. "Found unexpected events. This may be due to a bug in libpqxx, "
  67. "or the test table was modified by some other process.");
  68. }
  69. void test_abort()
  70. {
  71. connection conn;
  72. nontransaction t{conn};
  73. test::create_pqxxevents(t);
  74. connection &c(t.conn());
  75. t.commit();
  76. Test(c, true);
  77. Test(c, false);
  78. }
  79. PQXX_REGISTER_TEST(test_abort);
  80. } // namespace