test84.cxx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. #include <string>
  5. #include <vector>
  6. #include <pqxx/cursor>
  7. #include <pqxx/transaction>
  8. #include "test_helpers.hxx"
  9. // "Adopted SQL Cursor" test program for libpqxx. Create SQL cursor, wrap it
  10. // in a cursor stream, then use it to fetch data and check for consistent
  11. // results. Compare results against an icursor_iterator so that is tested as
  12. // well.
  13. namespace
  14. {
  15. void test_084()
  16. {
  17. pqxx::connection conn;
  18. pqxx::transaction<pqxx::serializable> tx{conn};
  19. std::string const Table{"pg_tables"}, Key{"tablename"};
  20. // Count rows.
  21. pqxx::result R(tx.exec("SELECT count(*) FROM " + Table));
  22. PQXX_CHECK(
  23. R.at(0).at(0).as<long>() > 20,
  24. "Not enough rows in " + Table + ", cannot test.");
  25. // Create an SQL cursor and, for good measure, muddle up its state a bit.
  26. std::string const CurName{"MYCUR"},
  27. Query{"SELECT * FROM " + Table + " ORDER BY " + Key};
  28. constexpr int InitialSkip{2}, GetRows{3};
  29. tx.exec0("DECLARE " + tx.quote_name(CurName) + " CURSOR FOR " + Query);
  30. tx.exec0(
  31. "MOVE " + pqxx::to_string(InitialSkip * GetRows) +
  32. " "
  33. "IN " +
  34. tx.quote_name(CurName));
  35. // Wrap cursor in cursor stream. Apply some trickery to get its name inside
  36. // a result field for this purpose. This isn't easy because it's not
  37. // supposed to be easy; normally we'd only construct streams around existing
  38. // SQL cursors if they were being returned by functions.
  39. pqxx::icursorstream C{
  40. tx, tx.exec("SELECT '" + tx.esc(CurName) + "'")[0][0], GetRows};
  41. // Create parallel cursor to check results
  42. pqxx::icursorstream C2{tx, Query, "CHECKCUR", GetRows};
  43. pqxx::icursor_iterator i2{C2};
  44. // Remember, our adopted cursor is at position (InitialSkip*GetRows)
  45. pqxx::icursor_iterator i3(i2);
  46. PQXX_CHECK(
  47. (i3 == i2) and not(i3 != i2),
  48. "Equality on copy-constructed icursor_iterator is broken.");
  49. PQXX_CHECK(
  50. not(i3 > i2) and not(i3 < i2) and (i3 <= i2) and (i3 >= i2),
  51. "Comparison on identical icursor_iterators is broken.");
  52. i3 += InitialSkip;
  53. PQXX_CHECK(not(i3 <= i2), "icursor_iterator operator<=() is broken.");
  54. pqxx::icursor_iterator iend, i4;
  55. PQXX_CHECK(i3 != iend, "Early end to icursor_iterator iteration.");
  56. i4 = iend;
  57. PQXX_CHECK(i4 == iend, "Assigning empty icursor_iterator fails.");
  58. // Now start testing our new Cursor.
  59. C >> R;
  60. i2 = i3;
  61. pqxx::result R2(*i2++);
  62. PQXX_CHECK_EQUAL(
  63. std::size(R), static_cast<pqxx::result::size_type>(GetRows),
  64. "Got unexpected number of rows.");
  65. PQXX_CHECK_EQUAL(R, R2, "Unexpected result at [1]");
  66. C.get(R);
  67. R2 = *i2;
  68. PQXX_CHECK_EQUAL(R, R2, "Unexpected result at [2]");
  69. i2 += 1;
  70. C.ignore(GetRows);
  71. C.get(R);
  72. R2 = *++i2;
  73. PQXX_CHECK_EQUAL(R, R2, "Unexpected result at [3]");
  74. ++i2;
  75. R2 = *i2++;
  76. for (int i{1}; C.get(R) and i2 != iend; R2 = *i2++, ++i)
  77. PQXX_CHECK_EQUAL(
  78. R, R2, "Unexpected result in iteration at " + pqxx::to_string(i));
  79. PQXX_CHECK(i2 == iend, "Adopted cursor terminated early.");
  80. PQXX_CHECK(not(C >> R), "icursor_iterator terminated early.");
  81. }
  82. } // namespace
  83. PQXX_REGISTER_TEST(test_084);