aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/libpqxx/include/pqxx/stream_from.hxx
blob: bc6bcc723145bc8c0d63623471283d2f28b89700 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/** Definition of the pqxx::stream_from class.
 *
 * pqxx::stream_from enables optimized batch reads from a database table.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_from instead.
 *
 * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#ifndef PQXX_H_STREAM_FROM
#define PQXX_H_STREAM_FROM

#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"
#include "pqxx/transaction_base.hxx"
#include "pqxx/stream_base.hxx"
#include "pqxx/internal/type_utils.hxx"

#include <string>


namespace pqxx
{

/// Efficiently pull data directly out of a table.
class PQXX_LIBEXPORT stream_from : public stream_base
{
public:
  stream_from(
    transaction_base &,
    const std::string &table_name
  );
  template<typename Columns> stream_from(
    transaction_base &,
    const std::string &table_name,
    const Columns& columns
  );
  template<typename Iter> stream_from(
    transaction_base &,
    const std::string &table_name,
    Iter columns_begin,
    Iter columns_end
  );

  ~stream_from() noexcept;

  void complete() override;

  bool get_raw_line(std::string &);
  template<typename Tuple> stream_from & operator>>(Tuple &);

private:
  internal::encoding_group m_copy_encoding;
  std::string m_current_line;
  bool m_retry_line;

  void set_up(transaction_base &, const std::string &table_name);
  void set_up(
    transaction_base &,
    const std::string &table_name,
    const std::string &columns
  );

  void close() override;

  bool extract_field(
    const std::string &,
    std::string::size_type &,
    std::string &
  ) const;

  template<typename Tuple, std::size_t I> auto tokenize_ith(
    const std::string &,
    Tuple &,
    std::string::size_type,
    std::string &
  ) const -> typename std::enable_if<(
    std::tuple_size<Tuple>::value > I
  )>::type;
  template<typename Tuple, std::size_t I> auto tokenize_ith(
    const std::string &,
    Tuple &,
    std::string::size_type,
    std::string &
  ) const -> typename std::enable_if<(
    std::tuple_size<Tuple>::value <= I
  )>::type;

  template<typename T> void extract_value(
    const std::string &line,
    T& t,
    std::string::size_type &here,
    std::string &workspace
  ) const;
};


template<typename Columns> stream_from::stream_from(
  transaction_base &tb,
  const std::string &table_name,
  const Columns& columns
) : stream_from{
  tb,
  table_name,
  std::begin(columns),
  std::end(columns)
} {}


template<typename Iter> stream_from::stream_from(
  transaction_base &tb,
  const std::string &table_name,
  Iter columns_begin,
  Iter columns_end
) :
  namedclass{"stream_from", table_name},
  stream_base{tb}
{
  set_up(
    tb,
    table_name,
    columnlist(columns_begin, columns_end)
  );
}


template<typename Tuple> stream_from & stream_from::operator>>(
  Tuple &t
)
{
  if (m_retry_line or get_raw_line(m_current_line))
  {
    std::string workspace;
    try
    {
      tokenize_ith<Tuple, 0>(m_current_line, t, 0, workspace);
      m_retry_line = false;
    }
    catch (...)
    {
      m_retry_line = true;
      throw;
    }
  }
  return *this;
}


template<typename Tuple, std::size_t I> auto stream_from::tokenize_ith(
  const std::string &line,
  Tuple &t,
  std::string::size_type here,
  std::string &workspace
) const -> typename std::enable_if<(
  std::tuple_size<Tuple>::value > I
)>::type
{
  if (here >= line.size())
    throw usage_error{"Too few fields to extract from stream_from line."};

  extract_value(line, std::get<I>(t), here, workspace);
  tokenize_ith<Tuple, I+1>(line, t, here, workspace);
}


template<typename Tuple, std::size_t I> auto stream_from::tokenize_ith(
  const std::string &line,
  Tuple & /* t */,
  std::string::size_type here,
  std::string & /* workspace */
) const -> typename std::enable_if<(
  std::tuple_size<Tuple>::value <= I
)>::type
{
  // Zero-column line may still have a trailing newline
  if (
	here < line.size() and
        not (here == line.size() - 1 and line[here] == '\n'))
    throw usage_error{"Not all fields extracted from stream_from line"};
}


template<typename T> void stream_from::extract_value(
  const std::string &line,
  T& t,
  std::string::size_type &here,
  std::string &workspace
) const
{
  if (extract_field(line, here, workspace))
    from_string<T>(workspace, t);
  else
    t = internal::null_value<T>();
}

template<> void stream_from::extract_value<std::nullptr_t>(
  const std::string &line,
  std::nullptr_t&,
  std::string::size_type &here,
  std::string &workspace
) const;

} // namespace pqxx


#include "pqxx/compiler-internal-post.hxx"
#endif