libpqxx
The C++ client library for PostgreSQL
Loading...
Searching...
No Matches
stream_query_impl.hxx
1/* Code for parts of pqxx::internal::stream_query.
2 *
3 * These definitions needs to be in a separate file in order to iron out
4 * circular dependencies between headers.
5 */
6#if !defined(PQXX_H_STREAM_QUERY_IMPL)
7# define PQXX_H_STREAM_QUERY_IMPL
8
9namespace pqxx::internal
10{
11template<typename... TYPE>
13 transaction_base &tx, std::string_view query) :
14 transaction_focus{tx, "stream_query"}, m_char_finder{get_finder(tx)}
15{
16 auto const r{tx.exec(internal::concat("COPY (", query, ") TO STDOUT"))};
17 r.expect_columns(sizeof...(TYPE));
18 r.expect_rows(0);
19 register_me();
20}
21
22
23template<typename... TYPE>
25 transaction_base &tx, std::string_view query, params const &parms) :
26 transaction_focus{tx, "stream_query"}, m_char_finder{get_finder(tx)}
27{
28 auto const r{tx.exec(internal::concat("COPY (", query, ") TO STDOUT"), parms)
29 .no_rows()};
30 if (r.columns() != sizeof...(TYPE))
31 throw usage_error{concat(
32 "Parsing query stream with wrong number of columns: "
33 "code expects ",
34 sizeof...(TYPE), " but query returns ", r.columns(), ".")};
35 register_me();
36}
37
38
39template<typename... TYPE>
40inline char_finder_func *
41stream_query<TYPE...>::get_finder(transaction_base const &tx)
42{
43 auto const group{enc_group(tx.conn().encoding_id())};
45}
46
47
48// C++20: Replace with generator? Could be faster (local vars vs. members).
50
53template<typename... TYPE> class stream_query_input_iterator
54{
55 using stream_t = stream_query<TYPE...>;
56
57public:
58 using value_type = std::tuple<TYPE...>;
59 using difference_type = long;
60
62 m_home(&home),
63 m_line{typename stream_query<TYPE...>::line_handle(
65 {
66 consume_line();
67 }
70
73 {
74 assert(not done());
75 consume_line();
76 return *this;
77 }
78
80
83 {
84 ++*this;
85 return {};
86 }
87
89 value_type operator*() const
90 {
91 return m_home->parse_line(zview{m_line.get(), m_line_size});
92 }
93
95 bool operator==(stream_query_end_iterator) const noexcept { return done(); }
98 {
99 return not done();
100 }
101
103 operator=(stream_query_input_iterator &&rhs) noexcept
104 {
105 if (&rhs != this)
106 {
107 m_line = std::move(rhs.m_line);
108 m_home = rhs.m_home;
109 m_line_size = rhs.m_line_size;
110 }
111 return *this;
112 }
113
114private:
115 stream_query_input_iterator() {}
116
118 bool done() const noexcept { return m_home->done(); }
119
121
124 void consume_line() &
125 {
126 auto [line, size]{m_home->read_line()};
127 m_line = std::move(line);
128 m_line_size = size;
129 if (m_line)
130 {
131 // We know how many fields to expect. Replace the newline at the end
132 // with the field separator, so the parsing loop only needs to scan for a
133 // tab, not a tab or a newline.
134 char *const ptr{m_line.get()};
135 assert(ptr[size] == '\n');
136 ptr[size] = '\t';
137 }
138 }
139
140 stream_t *m_home;
141
143 typename stream_t::line_handle m_line;
144
146 std::size_t m_line_size;
147};
148
149
150template<typename... TYPE>
151inline bool operator==(
152 stream_query_end_iterator, stream_query_input_iterator<TYPE...> const &i)
153{
154 return i.done();
155}
156
157
158template<typename... TYPE>
159inline bool operator!=(
160 stream_query_end_iterator, stream_query_input_iterator<TYPE...> const &i)
161{
162 return not i.done();
163}
164
165
166template<typename... TYPE> inline auto stream_query<TYPE...>::begin() &
167{
168 return stream_query_input_iterator<TYPE...>{*this};
169}
170
171
172template<typename... TYPE>
173inline std::pair<typename stream_query<TYPE...>::line_handle, std::size_t>
175{
176 assert(not done());
177
178 internal::gate::connection_stream_from gate{m_trans->conn()};
179 try
180 {
181 auto line{gate.read_copy_line()};
182 // Check for completion.
183 if (not line.first)
184 PQXX_UNLIKELY close();
185 return line;
186 }
187 catch (std::exception const &)
188 {
189 close();
190 throw;
191 }
192}
193} // namespace pqxx::internal
194#endif
Input iterator for stream_query.
Definition stream_query_impl.hxx:54
stream_query_input_iterator & operator++() &
Pre-increment. This is what you'd normally want to use.
Definition stream_query_impl.hxx:72
bool operator!=(stream_query_end_iterator) const noexcept
Comparison only works for comparing to end().
Definition stream_query_impl.hxx:97
bool operator==(stream_query_end_iterator) const noexcept
Are we at the end?
Definition stream_query_impl.hxx:95
value_type operator*() const
Dereference. There's no caching in here, so don't repeat calls.
Definition stream_query_impl.hxx:89
stream_query_input_iterator operator++(int)
Post-increment. Only here to satisfy input_iterator concept.
Definition stream_query_impl.hxx:82
Stream query results from the database. Used by transaction_base::stream.
Definition stream_query.hxx:80
bool done() const &noexcept
Has this stream reached the end of its data?
Definition stream_query.hxx:106
stream_query(transaction_base &tx, std::string_view query)
Execute query on tx, stream results.
Definition stream_query_impl.hxx:12
std::tuple< TYPE... > parse_line(zview line) &
Parse and convert the latest line of data we received.
Definition stream_query.hxx:118
auto begin() &
Begin iterator. Only for use by "range for.".
Definition stream_query_impl.hxx:166
std::pair< line_handle, std::size_t > read_line() &
Read a COPY line from the server.
Definition stream_query_impl.hxx:174
Base class for things that monopolise a transaction's attention.
Definition transaction_focus.hxx:29
Marker-type wrapper: zero-terminated std::string_view.
Definition zview.hxx:38
Error in usage of libpqxx library, similar to std::logic_error.
Definition except.hxx:249
void pqfreemem(void const *ptr) noexcept
Wrapper for PQfreemem(), with C++ linkage.
Definition util.cxx:205
Internal items for libpqxx' own use. Do not use these yourself.
Definition encodings.cxx:33
std::string concat(TYPE... item)
Efficiently combine a bunch of items into one big string.
Definition concat.hxx:31
PQXX_PURE constexpr char_finder_func * get_s_char_finder(encoding_group enc)
Look up a "sentry" character search function for an encoding group.
Definition encodings.hxx:849
pqxx::internal::encoding_group enc_group(std::string_view encoding_name)
Convert libpq encoding name to its libpqxx encoding group.
Definition encodings.cxx:35
std::size_t(std::string_view haystack, std::size_t start) char_finder_func
Function type: "find first occurrence of specific any of ASCII characters.".
Definition encoding_group.hxx:70
The end() iterator for a stream_query.
Definition stream_query.hxx:47