From 840a13a96182750a4024c17e6db1eee4de8f84b4 Mon Sep 17 00:00:00 2001 From: Jeroen Vermeulen Date: Fri, 5 Jul 2024 21:50:57 +0200 Subject: [PATCH] #841: Support parsing a field as an SQL array. (#854) It's annoying that there is already a `field::as_array()`, which returns an obsolete `array_parser` with its clunky API. I'm being aggressive in deprecating that one, so that eventually the _new_ function can assume its name without clashing. --- NEWS | 1 + include/pqxx/array.hxx | 12 +++++++----- include/pqxx/field.hxx | 17 +++++++++++++++++ test/unit/test_array.cxx | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index eab6d5ccc..9b22f5158 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ - Another fix to the readthedocs documentation build. (#845) - Work around CMake 3.30 renaming one of its functions. (#851) - Remove obscure deprecated `stream_to` constructor that never worked. (#853) + - Support reading a field as an SQL array using `as_sql_array()`. (#841) 7.9.1 - Fix bad conversion of array of empty strings to string. (#816) - Move `[[likely]]` feature check back to compile time, to speed up configure. diff --git a/include/pqxx/array.hxx b/include/pqxx/array.hxx index 855b16d93..9ade944e7 100644 --- a/include/pqxx/array.hxx +++ b/include/pqxx/array.hxx @@ -200,7 +200,11 @@ private: "Malformed array: does not end in the right number of '}'."}; } - explicit array(std::string_view data, pqxx::internal::encoding_group enc) + // Allow fields to construct arrays passing the encoding group. + // Couldn't make this work through a call gate, thanks to the templating. + friend class ::pqxx::field; + + array(std::string_view data, pqxx::internal::encoding_group enc) { using group = pqxx::internal::encoding_group; switch (enc) @@ -502,10 +506,8 @@ private: }; -/// Low-level array parser. -/** @warning This is not a great API. Something nicer is on the way. - * - * Use this to read an array field retrieved from the database. +/// Low-level parser for C++ arrays. @deprecated Use @ref pqxx::array instead. +/** Clunky old API for parsing SQL arrays. * * @warning This parser will only work reliably if your client encoding is * UTF-8, ASCII, or a "safe ASCII superset" (such as the EUC encodings) where diff --git a/include/pqxx/field.hxx b/include/pqxx/field.hxx index cdbc29e83..7187f6cf2 100644 --- a/include/pqxx/field.hxx +++ b/include/pqxx/field.hxx @@ -243,6 +243,19 @@ public: return as>(); } + /// Read SQL array contents as a @ref pqxx::array. + template + array as_sql_array() const + { + using array_type = array; + + // There's no such thing as a null SQL array. + if (is_null()) + internal::throw_null_conversion(type_name); + else + return array_type{this->view(), this->m_home.m_encoding}; + } + /// Parse the field as an SQL array. /** Call the parser to retrieve values (and structure) from the array. * @@ -250,6 +263,10 @@ public: * you keep the @ref row of `field` object alive, it will keep the @ref * result object alive as well. */ + [[deprecated( + "Avoid pqxx::array_parser. " + "Instead, use as_sql_array() to convert to pqxx::array." + )]] array_parser as_array() const & noexcept { return array_parser{c_str(), m_home.m_encoding}; diff --git a/test/unit/test_array.cxx b/test/unit/test_array.cxx index d8fc1b4eb..bce971d2f 100644 --- a/test/unit/test_array.cxx +++ b/test/unit/test_array.cxx @@ -693,6 +693,20 @@ void test_array_iterates_in_row_major_order() } +void test_as_sql_array() +{ + pqxx::connection conn; + pqxx::row r; + { + pqxx::work tx{conn}; + r = tx.exec1("SELECT ARRAY [5, 4, 3, 2]"); + // Connection closes, but we should still be able to parse the array. + } + auto const array{r[0].as_sql_array()}; + PQXX_CHECK_EQUAL(array[1], 4, "Got wrong value out of array."); +} + + PQXX_REGISTER_TEST(test_empty_arrays); PQXX_REGISTER_TEST(test_array_null_value); PQXX_REGISTER_TEST(test_array_double_quoted_string); @@ -714,4 +728,5 @@ PQXX_REGISTER_TEST(test_array_parses_multidim_arrays); PQXX_REGISTER_TEST(test_array_at_checks_bounds); PQXX_REGISTER_TEST(test_array_iterates_in_row_major_order); PQXX_REGISTER_TEST(test_array_generate_empty_strings); +PQXX_REGISTER_TEST(test_as_sql_array); } // namespace