stream_to.hxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /** Definition of the pqxx::stream_to class.
  2. *
  3. * pqxx::stream_to enables optimized batch updates to a database table.
  4. *
  5. * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_to.hxx instead.
  6. *
  7. * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
  8. *
  9. * See COPYING for copyright license. If you did not receive a file called
  10. * COPYING with this source code, please notify the distributor of this mistake,
  11. * or contact the author.
  12. */
  13. #ifndef PQXX_H_STREAM_TO
  14. #define PQXX_H_STREAM_TO
  15. #include "pqxx/compiler-public.hxx"
  16. #include "pqxx/compiler-internal-pre.hxx"
  17. #include "pqxx/transaction_base.hxx"
  18. #include "pqxx/stream_base.hxx"
  19. #include "pqxx/stream_from.hxx"
  20. #include "pqxx/internal/type_utils.hxx"
  21. #include <string>
  22. namespace pqxx
  23. {
  24. /// Efficiently write data directly to a database table.
  25. /** If you wish to insert rows of data into a table, you can compose INSERT
  26. * statements and execute them. But it's slow and tedious, and you need to
  27. * worry about quoting and escaping the data.
  28. *
  29. * If you're just inserting a single row, it probably won't matter much. You
  30. * can use prepared or parameterised statements to take care of the escaping
  31. * for you. But if you're inserting large numbers of rows you will want
  32. * something better.
  33. *
  34. * Inserting rows one by one tends to take a lot of time, especially when you
  35. * are working with a remote database server over the network. Every single
  36. * row involves sending the data over the network, and waiting for a reply.
  37. * Do it "in bulk" using @c stream_to, and you may find that it goes many times
  38. * faster, sometimes even by orders of magnitude.
  39. *
  40. * Here's how it works: you create a @c stream_to stream to start writing to
  41. * your table. You will probably want to specify the columns. Then, you
  42. * feed your data into the stream one row at a time. And finally, you call the
  43. * stream's @c complete() to tell it to finalise the operation, wait for
  44. * completion, and check for errors.
  45. *
  46. * You insert data using the @c << ("shift-left") operator. Each row must be
  47. * something that can be iterated in order to get its constituent fields: a
  48. * @c std::tuple, a @c std::vector, or anything else with a @c begin and
  49. * @c end. It could be a class of your own. Of course the fields have to
  50. * match the columns you specified when creating the stream.
  51. *
  52. * There is also a matching stream_from for reading data in bulk.
  53. */
  54. class PQXX_LIBEXPORT stream_to : public stream_base
  55. {
  56. public:
  57. /// Create a stream, without specifying columns.
  58. /** Fields will be inserted in whatever order the columns have in the
  59. * database.
  60. *
  61. * You'll probably want to specify the columns, so that the mapping between
  62. * your data fields and the table is explicit in your code, and not hidden
  63. * in an "implicit contract" between your code and your schema.
  64. */
  65. stream_to(transaction_base &, const std::string &table_name);
  66. /// Create a stream, specifying column names as a container of strings.
  67. template<typename Columns> stream_to(
  68. transaction_base &,
  69. const std::string &table_name,
  70. const Columns& columns
  71. );
  72. /// Create a stream, specifying column names as a sequence of strings.
  73. template<typename Iter> stream_to(
  74. transaction_base &,
  75. const std::string &table_name,
  76. Iter columns_begin,
  77. Iter columns_end
  78. );
  79. ~stream_to() noexcept;
  80. /// Complete the operation, and check for errors.
  81. /** Always call this to close the stream in an orderly fashion, even after
  82. * an error. (In the case of an error, abort the transaction afterwards.)
  83. *
  84. * The only circumstance where it's safe to skip this is after an error, if
  85. * you're discarding the entire connection right away.
  86. */
  87. void complete() override;
  88. /// Insert a row of data.
  89. /** The data can be any type that can be iterated. Each iterated item
  90. * becomes a field in the row, in the same order as the columns you
  91. * specified when creating the stream.
  92. *
  93. * Each field will be converted into the database's format using
  94. * @c pqxx::to_string.
  95. */
  96. template<typename Tuple> stream_to & operator<<(const Tuple &);
  97. /// Stream a `stream_from` straight into a `stream_to`.
  98. /** This can be useful when copying between different databases. If the
  99. * source and the destination are on the same database, you'll get better
  100. * performance doing it all in a regular query.
  101. */
  102. stream_to &operator<<(stream_from &);
  103. private:
  104. /// Write a row of data, as a line of text.
  105. void write_raw_line(const std::string &);
  106. void set_up(transaction_base &, const std::string &table_name);
  107. void set_up(
  108. transaction_base &,
  109. const std::string &table_name,
  110. const std::string &columns
  111. );
  112. void close() override;
  113. };
  114. template<typename Columns> inline stream_to::stream_to(
  115. transaction_base &tb,
  116. const std::string &table_name,
  117. const Columns& columns
  118. ) : stream_to{
  119. tb,
  120. table_name,
  121. std::begin(columns),
  122. std::end(columns)
  123. }
  124. {}
  125. template<typename Iter> inline stream_to::stream_to(
  126. transaction_base &tb,
  127. const std::string &table_name,
  128. Iter columns_begin,
  129. Iter columns_end
  130. ) :
  131. namedclass{"stream_from", table_name},
  132. stream_base{tb}
  133. {
  134. set_up(
  135. tb,
  136. table_name,
  137. columnlist(columns_begin, columns_end)
  138. );
  139. }
  140. namespace internal
  141. {
  142. class PQXX_LIBEXPORT TypedCopyEscaper
  143. {
  144. static std::string escape(const std::string &);
  145. public:
  146. template<typename T> std::string operator()(const T* t) const
  147. {
  148. return string_traits<T>::is_null(*t) ? "\\N" : escape(to_string(*t));
  149. }
  150. };
  151. // Explicit specialization so we don't need a string_traits<> for nullptr_t
  152. template<> inline std::string TypedCopyEscaper::operator()<std::nullptr_t>(
  153. const std::nullptr_t*
  154. ) const
  155. { return "\\N"; }
  156. } // namespace pqxx::internal
  157. template<typename Tuple> stream_to & stream_to::operator<<(const Tuple &t)
  158. {
  159. write_raw_line(separated_list("\t", t, internal::TypedCopyEscaper()));
  160. return *this;
  161. }
  162. } // namespace pqxx
  163. #include "pqxx/compiler-internal-post.hxx"
  164. #endif