2
0

test_result_slicing.cxx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include <pqxx/transaction>
  2. #include "../test_helpers.hxx"
  3. #include "pqxx/internal/ignore-deprecated-pre.hxx"
  4. namespace pqxx
  5. {
  6. template<> struct nullness<row::const_iterator> : no_null<row::const_iterator>
  7. {};
  8. template<>
  9. struct nullness<row::const_reverse_iterator>
  10. : no_null<const_reverse_row_iterator>
  11. {};
  12. template<> struct string_traits<row::const_iterator>
  13. {
  14. static constexpr zview text{"[row::const_iterator]"};
  15. static zview to_buf(char *, char *, row::const_iterator const &)
  16. {
  17. return text;
  18. }
  19. static char *into_buf(char *begin, char *end, row::const_iterator const &)
  20. {
  21. if ((end - begin) <= 30)
  22. throw conversion_overrun{"Not enough buffer for const row iterator."};
  23. std::memcpy(begin, text.c_str(), std::size(text) + 1);
  24. return begin + std::size(text);
  25. }
  26. static constexpr std::size_t
  27. size_buffer(row::const_iterator const &) noexcept
  28. {
  29. return std::size(text) + 1;
  30. }
  31. };
  32. template<> struct string_traits<row::const_reverse_iterator>
  33. {
  34. static constexpr zview text{"[row::const_reverse_iterator]"};
  35. static pqxx::zview
  36. to_buf(char *, char *, row::const_reverse_iterator const &)
  37. {
  38. return text;
  39. }
  40. static char *
  41. into_buf(char *begin, char *end, row::const_reverse_iterator const &)
  42. {
  43. if ((end - begin) <= 30)
  44. throw conversion_overrun{"Not enough buffer for const row iterator."};
  45. std::memcpy(begin, text.c_str(), std::size(text) + 1);
  46. return begin + std::size(text);
  47. }
  48. static constexpr std::size_t
  49. size_buffer(row::const_reverse_iterator const &) noexcept
  50. {
  51. return 100;
  52. }
  53. };
  54. } // namespace pqxx
  55. namespace
  56. {
  57. void test_result_slicing()
  58. {
  59. pqxx::connection conn;
  60. pqxx::work tx{conn};
  61. auto r{tx.exec("SELECT 1")};
  62. PQXX_CHECK(not std::empty(r[0]), "A plain row shows up as empty.");
  63. // Empty slice at beginning of row.
  64. pqxx::row s{r[0].slice(0, 0)};
  65. PQXX_CHECK(std::empty(s), "Empty slice does not show up as empty.");
  66. PQXX_CHECK_EQUAL(std::size(s), 0, "Slicing produces wrong row size.");
  67. PQXX_CHECK_EQUAL(
  68. std::begin(s), std::end(s), "Slice begin()/end() are broken.");
  69. PQXX_CHECK_EQUAL(
  70. std::rbegin(s), std::rend(s), "Slice rbegin()/rend() are broken.");
  71. PQXX_CHECK_THROWS(s.at(0), pqxx::range_error, "at() does not throw.");
  72. pqxx::row slice;
  73. PQXX_CHECK_THROWS(
  74. slice = r[0].slice(0, 2), pqxx::range_error, "No range check.");
  75. pqxx::ignore_unused(slice);
  76. PQXX_CHECK_THROWS(
  77. slice = r[0].slice(1, 0), pqxx::range_error, "Can reverse-slice.");
  78. pqxx::ignore_unused(slice);
  79. // Empty slice at end of row.
  80. s = r[0].slice(1, 1);
  81. PQXX_CHECK(std::empty(s), "empty() is broken.");
  82. PQXX_CHECK_EQUAL(std::size(s), 0, "size() is broken.");
  83. PQXX_CHECK_EQUAL(std::begin(s), std::end(s), "begin()/end() are broken.");
  84. PQXX_CHECK_EQUAL(
  85. std::rbegin(s), std::rend(s), "rbegin()/rend() are broken.");
  86. PQXX_CHECK_THROWS(s.at(0), pqxx::range_error, "at() is inconsistent.");
  87. // Slice that matches the entire row.
  88. s = r[0].slice(0, 1);
  89. PQXX_CHECK(not std::empty(s), "Nonempty slice shows up as empty.");
  90. PQXX_CHECK_EQUAL(std::size(s), 1, "size() breaks for non-empty slice.");
  91. PQXX_CHECK_EQUAL(std::begin(s) + 1, std::end(s), "Iteration is broken.");
  92. PQXX_CHECK_EQUAL(
  93. std::rbegin(s) + 1, std::rend(s), "Reverse iteration is broken.");
  94. PQXX_CHECK_EQUAL(s.at(0).as<int>(), 1, "Accessing a slice is broken.");
  95. PQXX_CHECK_EQUAL(s[0].as<int>(), 1, "operator[] is broken.");
  96. PQXX_CHECK_THROWS(s.at(1).as<int>(), pqxx::range_error, "at() is off.");
  97. // Meaningful slice at beginning of row.
  98. r = tx.exec("SELECT 1, 2, 3");
  99. s = r[0].slice(0, 1);
  100. PQXX_CHECK(not std::empty(s), "Slicing confuses empty().");
  101. PQXX_CHECK_THROWS(
  102. s.at(1).as<int>(), pqxx::range_error, "at() does not enforce slice.");
  103. // Meaningful slice that skips an initial column.
  104. s = r[0].slice(1, 2);
  105. PQXX_CHECK(
  106. not std::empty(s), "Slicing away leading columns confuses empty().");
  107. PQXX_CHECK_EQUAL(s[0].as<int>(), 2, "Slicing offset is broken.");
  108. PQXX_CHECK_EQUAL(
  109. std::begin(s)->as<int>(), 2, "Iteration uses wrong offset.");
  110. PQXX_CHECK_EQUAL(
  111. std::begin(s) + 1, std::end(s), "Iteration has wrong range.");
  112. PQXX_CHECK_EQUAL(
  113. std::rbegin(s) + 1, std::rend(s), "Reverse iteration has wrong range.");
  114. PQXX_CHECK_THROWS(
  115. s.at(1).as<int>(), pqxx::range_error, "Offset slicing is broken.");
  116. // Column names in a slice.
  117. r = tx.exec("SELECT 1 AS one, 2 AS two, 3 AS three");
  118. s = r[0].slice(1, 2);
  119. PQXX_CHECK_EQUAL(s["two"].as<int>(), 2, "Column addressing breaks.");
  120. PQXX_CHECK_THROWS(
  121. pqxx::ignore_unused(s.column_number("one")), pqxx::argument_error,
  122. "Can access column name before slice.");
  123. PQXX_CHECK_THROWS(
  124. pqxx::ignore_unused(s.column_number("three")), pqxx::argument_error,
  125. "Can access column name after slice.");
  126. PQXX_CHECK_EQUAL(
  127. s.column_number("Two"), 0, "Column name is case sensitive.");
  128. // Identical column names.
  129. r = tx.exec("SELECT 1 AS x, 2 AS x");
  130. s = r[0].slice(1, 2);
  131. PQXX_CHECK_EQUAL(s["x"].as<int>(), 2, "Identical column names break slice.");
  132. }
  133. PQXX_REGISTER_TEST(test_result_slicing);
  134. } // namespace
  135. #include "pqxx/internal/ignore-deprecated-post.hxx"