diff options
author | galaxycrab <UgnineSirdis@ydb.tech> | 2023-11-23 11:26:33 +0300 |
---|---|---|
committer | galaxycrab <UgnineSirdis@ydb.tech> | 2023-11-23 12:01:57 +0300 |
commit | 44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300 (patch) | |
tree | cb4d75cd1c6dbc3da0ed927337fd8d1b6ed9da84 /contrib/libs/libpqxx/include/pqxx/internal | |
parent | 0e69bf615395fdd48ecee032faaec81bc468b0b8 (diff) | |
download | ydb-44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300.tar.gz |
YQ Connector:test INNER JOIN
Diffstat (limited to 'contrib/libs/libpqxx/include/pqxx/internal')
32 files changed, 1493 insertions, 0 deletions
diff --git a/contrib/libs/libpqxx/include/pqxx/internal/callgate.hxx b/contrib/libs/libpqxx/include/pqxx/internal/callgate.hxx new file mode 100644 index 0000000000..02ac152636 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/callgate.hxx @@ -0,0 +1,79 @@ +#ifndef PQXX_H_CALLGATE +#define PQXX_H_CALLGATE + +/* +Here's what a typical gate class definition looks like: + +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE @gateclass@ : callgate<@host@> +{ + friend class @client@; + + @gateclass@(reference x) : super(x) {} + + // Methods here. Use home() to access the host-class object. +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx +*/ + +namespace pqxx +{ +namespace internal +{ +/// Base class for call gates. +/** + * A call gate defines a limited, private interface on the host class that + * specified client classes can access. + * + * The metaphor works as follows: the gate stands in front of a "home," which is + * really a class, and only lets specific friends in. + * + * To implement a call gate that gives client C access to host H, + * - derive a gate class from callgate<H>; + * - make the gate class a friend of H; + * - make C a friend of the gate class; and + * - implement "stuff C can do with H" as private members in the gate class. + * + * This special kind of "gated" friendship gives C private access to H, but only + * through an expressly limited interface. The gate class can access its host + * object as home(). + * + * Keep gate classes entirely stateless. They should be ultra-lightweight + * wrappers for their host classes, and be optimized away as much as possible by + * the compiler. Once you start adding state, you're on a slippery slope away + * from the pure, clean, limited interface pattern that gate classes are meant + * to implement. + * + * Ideally, all member functions of the gate class should be one-liners passing + * calls straight on to the host class. It can be useful however to break this + * rule temporarily during inter-class refactoring. + */ +template<typename HOME> class PQXX_PRIVATE callgate +{ +protected: + /// This class, to keep constructors easy. + using super = callgate<HOME>; + /// A reference to the host class. Helps keep constructors easy. + using reference = HOME &; + + callgate(reference x) : m_home(x) {} + + /// The home object. The gate class has full "private" access. + reference home() const noexcept { return m_home; } + +private: + reference m_home; +}; +} // namespace pqxx::internal +} // namespace pqxx + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/encoding_group.hxx b/contrib/libs/libpqxx/include/pqxx/internal/encoding_group.hxx new file mode 100644 index 0000000000..be31d083b4 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/encoding_group.hxx @@ -0,0 +1,46 @@ +/** Enum type for supporting encodings in libpqxx + * + * 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_ENCODING_GROUP +#define PQXX_H_ENCODING_GROUP + + +namespace pqxx +{ +namespace internal +{ + +// Types of encodings supported by PostgreSQL, see +// https://www.postgresql.org/docs/current/static/multibyte.html#CHARSET-TABLE +enum class encoding_group +{ + // Handles all single-byte fixed-width encodings + MONOBYTE, + + // Multibyte encodings + BIG5, + EUC_CN, + EUC_JP, + EUC_JIS_2004, + EUC_KR, + EUC_TW, + GB18030, + GBK, + JOHAB, + MULE_INTERNAL, + SJIS, + SHIFT_JIS_2004, + UHC, + UTF8 +}; + +} // namespace pqxx::internal +} // namespace pqxx + + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/encodings.hxx b/contrib/libs/libpqxx/include/pqxx/internal/encodings.hxx new file mode 100644 index 0000000000..01ca223d48 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/encodings.hxx @@ -0,0 +1,99 @@ +/** Internal string encodings support for libpqxx + * + * 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_ENCODINGS +#define PQXX_H_ENCODINGS + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/internal/encoding_group.hxx" + +#include <string> + + +namespace pqxx +{ +namespace internal +{ +const char *name_encoding(int encoding_id); + +/// Convert libpq encoding enum or encoding name to its libpqxx group. +encoding_group enc_group(int /* libpq encoding ID */); +encoding_group enc_group(const std::string&); + + +/// Function type: "find the end of the current glyph." +/** This type of function takes a text buffer, and a location in that buffer, + * and returns the location one byte past the end of the current glyph. + * + * The start offset marks the beginning of the current glyph. It must fall + * within the buffer. + * + * There are multiple different glyph scnaner implementations, for different + * kinds of encodings. + */ +using glyph_scanner_func = + std::string::size_type( + const char buffer[], + std::string::size_type buffer_len, + std::string::size_type start); + + +/// Look up the glyph scanner function for a given encoding group. +/** To identify the glyph boundaries in a buffer, call this to obtain the + * scanner function appropriate for the buffer's encoding. Then, repeatedly + * call the scanner function to find the glyphs. + */ +PQXX_LIBEXPORT glyph_scanner_func *get_glyph_scanner(encoding_group); + + +/// Find a single-byte "needle" character in a "haystack" text buffer. +std::string::size_type find_with_encoding( + encoding_group enc, + const std::string& haystack, + char needle, + std::string::size_type start = 0 +); + + +PQXX_LIBEXPORT std::string::size_type find_with_encoding( + encoding_group enc, + const std::string& haystack, + const std::string& needle, + std::string::size_type start = 0 +); + + +/// Iterate over the glyphs in a buffer. +/** Scans the glyphs in the buffer, and for each, passes its begin and its + * one-past-end pointers to @c callback. + */ +template<typename CALLABLE> PQXX_LIBEXPORT inline void for_glyphs( + encoding_group enc, + CALLABLE callback, + const char buffer[], + std::string::size_type buffer_len, + std::string::size_type start = 0 +) +{ + const auto scan = get_glyph_scanner(enc); + for ( + std::string::size_type here = start, next; + here < buffer_len; + here = next + ) + { + next = scan(buffer, buffer_len, here); + callback(buffer + here, buffer + next); + } +} +} // namespace pqxx::internal +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-dbtransaction.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-dbtransaction.hxx new file mode 100644 index 0000000000..8ef2e4744f --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-dbtransaction.hxx @@ -0,0 +1,22 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class dbtransaction; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_dbtransaction : callgate<connection_base> +{ + friend class pqxx::dbtransaction; + + connection_dbtransaction(reference x) : super(x) {} + + int get_reactivation_avoidance_count() const noexcept + { return home().m_reactivation_avoidance.get(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-errorhandler.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-errorhandler.hxx new file mode 100644 index 0000000000..9c62704dbe --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-errorhandler.hxx @@ -0,0 +1,25 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class connection_base; +class errorhandler; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_errorhandler : callgate<connection_base> +{ + friend class pqxx::errorhandler; + + connection_errorhandler(reference x) : super(x) {} + + void register_errorhandler(errorhandler *h) + { home().register_errorhandler(h); } + void unregister_errorhandler(errorhandler *h) + { home().unregister_errorhandler(h); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-largeobject.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-largeobject.hxx new file mode 100644 index 0000000000..e4f3b28fcc --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-largeobject.hxx @@ -0,0 +1,35 @@ +#include <string> + +#include <pqxx/internal/callgate.hxx> +#include <pqxx/internal/libpq-forward.hxx> + +namespace pqxx +{ +class largeobject; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_largeobject : callgate<connection_base> +{ + friend class pqxx::largeobject; + + connection_largeobject(reference x) : super(x) {} + + pq::PGconn *raw_connection() const { return home().raw_connection(); } +}; + + +class PQXX_PRIVATE const_connection_largeobject : + callgate<const connection_base> +{ + friend class pqxx::largeobject; + + const_connection_largeobject(reference x) : super(x) {} + + std::string error_message() const { return home().err_msg(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-notification_receiver.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-notification_receiver.hxx new file mode 100644 index 0000000000..d03f048f37 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-notification_receiver.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> + +#include <pqxx/connection_base> + + +namespace pqxx +{ +class notification_receiver; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_notification_receiver : callgate<connection_base> +{ + friend class pqxx::notification_receiver; + + connection_notification_receiver(reference x) : super(x) {} + + void add_receiver(notification_receiver *receiver) + { home().add_receiver(receiver); } + void remove_receiver(notification_receiver *receiver) noexcept + { home().remove_receiver(receiver); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-parameterized_invocation.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-parameterized_invocation.hxx new file mode 100644 index 0000000000..364c5b6dac --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-parameterized_invocation.hxx @@ -0,0 +1,37 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class connection_base; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_parameterized_invocation : + callgate<connection_base> +{ + friend class pqxx::internal::parameterized_invocation; + + connection_parameterized_invocation(reference x) : super(x) {} + + result parameterized_exec( + const std::string &query, + const char *const params[], + const int paramlengths[], + const int binaries[], + int nparams) + { +#include <pqxx/internal/ignore-deprecated-pre.hxx> + return home().parameterized_exec( + query, + params, + paramlengths, + binaries, + nparams); +#include <pqxx/internal/ignore-deprecated-post.hxx> + } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-pipeline.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-pipeline.hxx new file mode 100644 index 0000000000..d7d42ef981 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-pipeline.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> +#include "pqxx/internal/libpq-forward.hxx" + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_pipeline : callgate<connection_base> +{ + friend class pqxx::pipeline; + + connection_pipeline(reference x) : super(x) {} + + void start_exec(const std::string &query) { home().start_exec(query); } + pqxx::internal::pq::PGresult *get_result() { return home().get_result(); } + void cancel_query() { home().cancel_query(); } + + bool consume_input() noexcept { return home().consume_input(); } + bool is_busy() const noexcept { return home().is_busy(); } + + int encoding_id() { return home().encoding_id(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-prepare-invocation.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-prepare-invocation.hxx new file mode 100644 index 0000000000..c1c29583cc --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-prepare-invocation.hxx @@ -0,0 +1,45 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace prepare +{ +class invocation; +} // namespace pqxx::prepare + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_prepare_invocation : callgate<connection_base> +{ + friend class pqxx::prepare::invocation; + + connection_prepare_invocation(reference x) : super(x) {} + + /// @deprecated To be replaced by exec_prepared. + result prepared_exec( + const std::string &statement, + const char *const params[], + const int paramlengths[], + const int binary[], + int nparams, + result_format format) + { +#include <pqxx/internal/ignore-deprecated-pre.hxx> + return home().prepared_exec( + statement, + params, + paramlengths, + binary, + nparams, + format); +#include <pqxx/internal/ignore-deprecated-post.hxx> + } + + bool prepared_exists(const std::string &statement) const + { return home().prepared_exists(statement); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx new file mode 100644 index 0000000000..48ef89a46e --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx @@ -0,0 +1,24 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +class reactivation_avoidance_exemption; + +namespace gate +{ +class PQXX_PRIVATE connection_reactivation_avoidance_exemption : + callgate<connection_base> +{ + friend class pqxx::internal::reactivation_avoidance_exemption; + + connection_reactivation_avoidance_exemption(reference x) : super(x) {} + + int get_counter() const { return home().m_reactivation_avoidance.get(); } + void add_counter(int x) const { home().m_reactivation_avoidance.add(x); } + void clear_counter() { home().m_reactivation_avoidance.clear(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-sql_cursor.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-sql_cursor.hxx new file mode 100644 index 0000000000..bb2cfee177 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-sql_cursor.hxx @@ -0,0 +1,25 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +class sql_cursor; + +namespace gate +{ +class PQXX_PRIVATE connection_sql_cursor : callgate<connection_base> +{ + friend class pqxx::internal::sql_cursor; + + connection_sql_cursor(reference x) : super(x) {} + + result exec(const char query[], int retries) + { return home().exec(query, retries); } + + void add_reactivation_avoidance_count(int n) + { home().add_reactivation_avoidance_count(n); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-transaction.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-transaction.hxx new file mode 100644 index 0000000000..f2aaac07f7 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-transaction.hxx @@ -0,0 +1,77 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class connection_base; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_transaction : callgate<connection_base> +{ + friend class pqxx::transaction_base; + + connection_transaction(reference x) : super(x) {} + + result exec(const char query[], int retries) + { return home().exec(query, retries); } + void register_transaction(transaction_base *t) + { home().register_transaction(t); } + void unregister_transaction(transaction_base *t) noexcept + { home().unregister_transaction(t); } + + bool read_copy_line(std::string &line) + { return home().read_copy_line(line); } + void write_copy_line(const std::string &line) + { home().write_copy_line(line); } + void end_copy_write() { home().end_copy_write(); } + + std::string raw_get_var(const std::string &var) + { return home().raw_get_var(var); } + void raw_set_var(const std::string &var, const std::string &value) + { home().raw_set_var(var, value); } + void add_variables(const std::map<std::string, std::string> &vars) + { home().add_variables(vars); } + + /// @deprecated To be replaced by exec_prepared. + result prepared_exec( + const std::string &statement, + const char *const params[], + const int paramlengths[], + const int binaries[], + int nparams) + { +#include <pqxx/internal/ignore-deprecated-pre.hxx> + return home().prepared_exec( + statement, + params, + paramlengths, + binaries, + nparams, + result_format::text); +#include <pqxx/internal/ignore-deprecated-post.hxx> + } + + result exec_prepared( + const std::string &statement, + const internal::params &args, + result_format format) + { + return home().exec_prepared(statement, args, format); + } + + result exec_params(const std::string &query, const internal::params &args) + { + return home().exec_params(query, args); + } + + bool prepared_exists(const std::string &statement) const + { return home().prepared_exists(statement); } + + void take_reactivation_avoidance(int counter) + { home().m_reactivation_avoidance.add(counter); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/errorhandler-connection.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/errorhandler-connection.hxx new file mode 100644 index 0000000000..1b118e5610 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/errorhandler-connection.hxx @@ -0,0 +1,19 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE errorhandler_connection_base : callgate<errorhandler> +{ + friend class pqxx::connection_base; + + errorhandler_connection_base(reference x) : super(x) {} + + void unregister() noexcept { home().unregister(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/icursor_iterator-icursorstream.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursor_iterator-icursorstream.hxx new file mode 100644 index 0000000000..9c17cf2916 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursor_iterator-icursorstream.hxx @@ -0,0 +1,28 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE icursor_iterator_icursorstream : callgate<icursor_iterator> +{ + friend class pqxx::icursorstream; + + icursor_iterator_icursorstream(reference x) : super(x) {} + + icursor_iterator::difference_type pos() const noexcept + { return home().pos(); } + + icursor_iterator *get_prev() { return home().m_prev; } + void set_prev(icursor_iterator *i) { home().m_prev = i; } + + icursor_iterator *get_next() { return home().m_next; } + void set_next(icursor_iterator *i) { home().m_next = i; } + + void fill(const result &r) { home().fill(r); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/icursorstream-icursor_iterator.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursorstream-icursor_iterator.hxx new file mode 100644 index 0000000000..8f28336bb5 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursorstream-icursor_iterator.hxx @@ -0,0 +1,30 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE icursorstream_icursor_iterator : callgate<icursorstream> +{ + friend class pqxx::icursor_iterator; + + icursorstream_icursor_iterator(reference x) : super(x) {} + + void insert_iterator(icursor_iterator *i) noexcept + { home().insert_iterator(i); } + + void remove_iterator(icursor_iterator *i) const noexcept + { home().remove_iterator(i); } + + icursorstream::size_type forward() { return home().forward(); } + icursorstream::size_type forward(icursorstream::size_type n) + { return home().forward(n); } + + void service_iterators(icursorstream::difference_type p) + { home().service_iterators(p); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/result-connection.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-connection.hxx new file mode 100644 index 0000000000..76c8e7a1f1 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-connection.hxx @@ -0,0 +1,20 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE result_connection : callgate<const result> +{ + friend class pqxx::connection_base; + + result_connection(reference x) : super(x) {} + + operator bool() const { return bool(home()); } + bool operator!() const { return not home(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/result-creation.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-creation.hxx new file mode 100644 index 0000000000..6d5671c529 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-creation.hxx @@ -0,0 +1,28 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE result_creation : callgate<const result> +{ + friend class pqxx::connection_base; + friend class pqxx::pipeline; + + result_creation(reference x) : super(x) {} + + static result create( + internal::pq::PGresult *rhs, + const std::string &query, + encoding_group enc) + { + return result(rhs, query, enc); + } + + void check_status() const { return home().check_status(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/result-row.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-row.hxx new file mode 100644 index 0000000000..692d3b5f5b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-row.hxx @@ -0,0 +1,22 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +class row; + +namespace gate +{ +class PQXX_PRIVATE result_row : callgate<result> +{ + friend class pqxx::row; + + result_row(reference x) : super(x) {} + + operator bool() + { return bool(home()); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-sql_cursor.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-sql_cursor.hxx new file mode 100644 index 0000000000..878b171b95 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-sql_cursor.hxx @@ -0,0 +1,16 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_sql_cursor : callgate<transaction_base> +{ + friend class pqxx::internal::sql_cursor; + transaction_sql_cursor(reference x) : super(x) {} +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_from.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_from.hxx new file mode 100644 index 0000000000..6345543dda --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_from.hxx @@ -0,0 +1,23 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_stream_from : callgate<transaction_base> +{ + friend class pqxx::stream_from; + + transaction_stream_from(reference x) : super(x) {} + + void BeginCopyRead(const std::string &table, const std::string &columns) + { home().BeginCopyRead(table, columns); } + + bool read_copy_line(std::string &line) + { return home().read_copy_line(line); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_to.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_to.hxx new file mode 100644 index 0000000000..6ee9e9b7d6 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_to.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_stream_to : callgate<transaction_base> +{ + friend class pqxx::stream_to; + + transaction_stream_to(reference x) : super(x) {} + + void BeginCopyWrite( + const std::string &table, + const std::string &columns = std::string{}) + { home().BeginCopyWrite(table, columns); } + + void write_copy_line(const std::string &line) + { home().write_copy_line(line); } + + void end_copy_write() { home().end_copy_write(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-subtransaction.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-subtransaction.hxx new file mode 100644 index 0000000000..243f47a798 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-subtransaction.hxx @@ -0,0 +1,20 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_subtransaction : callgate<transaction_base> +{ + friend class pqxx::subtransaction; + + transaction_subtransaction(reference x) : super(x) {} + + void add_reactivation_avoidance_count(int n) + { home().m_reactivation_avoidance.add(n); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablereader.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablereader.hxx new file mode 100644 index 0000000000..6946d36391 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablereader.hxx @@ -0,0 +1,23 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_tablereader : callgate<transaction_base> +{ + friend class pqxx::tablereader; + + transaction_tablereader(reference x) : super(x) {} + + void BeginCopyRead(const std::string &table, const std::string &columns) + { home().BeginCopyRead(table, columns); } + + bool read_copy_line(std::string &line) + { return home().read_copy_line(line); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablewriter.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablewriter.hxx new file mode 100644 index 0000000000..3256090a2f --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablewriter.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_tablewriter : callgate<transaction_base> +{ + friend class pqxx::tablewriter; + + transaction_tablewriter(reference x) : super(x) {} + + void BeginCopyWrite( + const std::string &table, + const std::string &columns = std::string{}) + { home().BeginCopyWrite(table, columns); } + + void write_copy_line(const std::string &line) + { home().write_copy_line(line); } + + void end_copy_write() { home().end_copy_write(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-transactionfocus.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-transactionfocus.hxx new file mode 100644 index 0000000000..9ea117a2ea --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-transactionfocus.hxx @@ -0,0 +1,23 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_transactionfocus : callgate<transaction_base> +{ + friend class pqxx::internal::transactionfocus; + + transaction_transactionfocus(reference x) : super(x) {} + + void register_focus(transactionfocus *focus) { home().register_focus(focus); } + void unregister_focus(transactionfocus *focus) noexcept + { home().unregister_focus(focus); } + void register_pending_error(const std::string &error) + { home().register_pending_error(error); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-post.hxx b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-post.hxx new file mode 100644 index 0000000000..32a84b2751 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-post.hxx @@ -0,0 +1,6 @@ +/// End a code block started by "ignore-deprecated-pre.hxx". +#if defined(__GNUC__) + +#pragma GCC diagnostic pop + +#endif // __GNUC__ diff --git a/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-pre.hxx b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-pre.hxx new file mode 100644 index 0000000000..9ada1b7205 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-pre.hxx @@ -0,0 +1,19 @@ +/** Start a block of deprecated code which may call other deprecated code. + * + * Most compilers will emit warnings when deprecated code is invoked from + * non-deprecated code. But some compilers (notably gcc) will always emit the + * warning, even when the calling code is also deprecated. + * + * This header starts a block where those warnings are suppressed. It can be + * included inside a code block. + * + * Always match the #include with a closing #include of + * "ignore-deprecated-post.hxx". To avoid mistakes, keep the enclosed area as + * small as possible. + */ +#if defined(__GNUC__) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#endif // __GNUC__ diff --git a/contrib/libs/libpqxx/include/pqxx/internal/libpq-forward.hxx b/contrib/libs/libpqxx/include/pqxx/internal/libpq-forward.hxx new file mode 100644 index 0000000000..394f3068b2 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/libpq-forward.hxx @@ -0,0 +1,34 @@ +/** Minimal forward declarations of libpq types needed in libpqxx headers. + * + * DO NOT INCLUDE THIS FILE when building client programs. + * + * 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. + */ +extern "C" +{ +struct pg_conn; +struct pg_result; +struct pgNotify; +} + +namespace pqxx +{ +namespace internal +{ +/// Forward declarations of libpq types as needed in libpqxx headers +namespace pq +{ +using PGconn = pg_conn; +using PGresult = pg_result; +using PGnotify = pgNotify; +using PQnoticeProcessor = void (*)(void *, const char *); +} +} + +/// PostgreSQL database row identifier +using oid = unsigned int; +} // extern "C" diff --git a/contrib/libs/libpqxx/include/pqxx/internal/sql_cursor.hxx b/contrib/libs/libpqxx/include/pqxx/internal/sql_cursor.hxx new file mode 100644 index 0000000000..828f9d3e6e --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/sql_cursor.hxx @@ -0,0 +1,122 @@ +/** Internal wrapper for SQL cursors. Supports higher-level cursor classes. + * + * DO NOT INCLUDE THIS FILE DIRECTLY. Other headers include it for you. + * + * 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_SQL_CURSOR +#define PQXX_H_SQL_CURSOR + +namespace pqxx +{ +namespace internal +{ +/// Cursor with SQL positioning semantics. +/** Thin wrapper around an SQL cursor, with SQL's ideas of positioning. + * + * SQL cursors have pre-increment/pre-decrement semantics, with on either end of + * the result set a special position that does not repesent a row. This class + * models SQL cursors for the purpose of implementing more C++-like semantics on + * top. + * + * Positions of actual rows are numbered starting at 1. Position 0 exists but + * does not refer to a row. There is a similar non-row position at the end of + * the result set. + * + * Don't use this at home. You deserve better. Use the stateles_cursor + * instead. + */ +class PQXX_LIBEXPORT sql_cursor : public cursor_base +{ +public: + sql_cursor( + transaction_base &t, + const std::string &query, + const std::string &cname, + cursor_base::accesspolicy ap, + cursor_base::updatepolicy up, + cursor_base::ownershippolicy op, + bool hold, + result_format format = result_format::text); + + sql_cursor( + transaction_base &t, + const std::string &cname, + cursor_base::ownershippolicy op); + + ~sql_cursor() noexcept { close(); } + + result fetch(difference_type rows, difference_type &displacement); + result fetch(difference_type rows) + { difference_type d=0; return fetch(rows, d); } + difference_type move(difference_type rows, difference_type &displacement); + difference_type move(difference_type rows) + { difference_type d=0; return move(rows, d); } + + /// Current position, or -1 for unknown + /** + * The starting position, just before the first row, counts as position zero. + * + * Position may be unknown if (and only if) this cursor was adopted, and has + * never hit its starting position (position zero). + */ + difference_type pos() const noexcept { return m_pos; } + + /// End position, or -1 for unknown + /** + * Returns the final position, just after the last row in the result set. The + * starting position, just before the first row, counts as position zero. + * + * End position is unknown until it is encountered during use. + */ + difference_type endpos() const noexcept { return m_endpos; } + + /// Return zero-row result for this cursor + const result &empty_result() const noexcept { return m_empty_result; } + + void close() noexcept; + +private: + difference_type adjust(difference_type hoped, difference_type actual); + static std::string stridestring(difference_type); + /// Initialize cached empty result. Call only at beginning or end! + void init_empty_result(transaction_base &); + + /// Connection this cursor lives in + connection_base &m_home; + + /// Zero-row result from this cursor (or plain empty one if cursor is adopted) + result m_empty_result; + + result m_cached_current_row; + + /// Is this cursor adopted (as opposed to created by this cursor object)? + bool m_adopted; + + /// Will this cursor object destroy its SQL cursor when it dies? + cursor_base::ownershippolicy m_ownership; + + /// At starting position (-1), somewhere in the middle (0), or past end (1) + int m_at_end; + + /// Position, or -1 for unknown + difference_type m_pos; + + /// End position, or -1 for unknown + difference_type m_endpos = -1; +}; + + +PQXX_LIBEXPORT result_size_type obtain_stateless_cursor_size(sql_cursor &); +PQXX_LIBEXPORT result stateless_cursor_retrieve( + sql_cursor &, + result::difference_type size, + result::difference_type begin_pos, + result::difference_type end_pos); +} // namespace internal +} // namespace pqxx +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/statement_parameters.hxx b/contrib/libs/libpqxx/include/pqxx/internal/statement_parameters.hxx new file mode 100644 index 0000000000..8c80f6df48 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/statement_parameters.hxx @@ -0,0 +1,227 @@ +/** Common implementation for statement parameter lists. + * + * These are used for both prepared statements and parameterized statements. + * + * DO NOT INCLUDE THIS FILE DIRECTLY. Other headers include it for you. + * + * 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_STATEMENT_PARAMETER +#define PQXX_H_STATEMENT_PARAMETER + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <cstring> +#include <iterator> +#include <string> +#include <vector> + +#include "pqxx/binarystring" +#include "pqxx/strconv" +#include "pqxx/util" + +#include "pqxx/internal/type_utils.hxx" + + +namespace pqxx +{ +namespace internal +{ +/// Marker type: pass a dynamically-determined number of statement parameters. +/** Normally when invoking a prepared or parameterised statement, the number + * of parameters is known at compile time. For instance, + * @c t.exec_prepared("foo", 1, "x"); executes statement @c foo with two + * parameters, an @c int and a C string. + * + * But sometimes you may want to pass a number of parameters known only at run + * time. In those cases, a @c dynamic_params encodes a dynamically + * determined number of parameters. + */ +template<typename IT> class dynamic_params +{ +public: + /// Wrap a sequence of pointers or iterators. + dynamic_params(IT begin, IT end) : m_begin(begin), m_end(end) {} + + /// Wrap a container. + template<typename C> explicit dynamic_params(const C &container) : + m_begin(std::begin(container)), + m_end(std::end(container)) + {} + + IT begin() const { return m_begin; } + IT end() const { return m_end; } + +private: + const IT m_begin, m_end; +}; + + +class PQXX_LIBEXPORT statement_parameters +{ +protected: + statement_parameters() =default; + statement_parameters &operator=(const statement_parameters &) =delete; + + void add_param() { this->add_checked_param("", false, false); } + template<typename T> void add_param(const T &v, bool nonnull) + { + nonnull = (nonnull && not pqxx::string_traits<T>::is_null(v)); + this->add_checked_param( + (nonnull ? pqxx::to_string(v) : ""), + nonnull, + false); + } + void add_binary_param(const binarystring &b, bool nonnull) + { this->add_checked_param(b.str(), nonnull, true); } + + /// Marshall parameter values into C-compatible arrays for passing to libpq. + int marshall( + std::vector<const char *> &values, + std::vector<int> &lengths, + std::vector<int> &binaries) const; + +private: + void add_checked_param(const std::string &value, bool nonnull, bool binary); + + std::vector<std::string> m_values; + std::vector<bool> m_nonnull; + std::vector<bool> m_binary; +}; + + +/// Internal type: encode statement parameters. +/** Compiles arguments for prepared statements and parameterised queries into + * a format that can be passed into libpq. + * + * Objects of this type are meant to be short-lived. If you pass in a non-null + * pointer as a parameter, it may simply use that pointer as a parameter value. + */ +struct params +{ + /// Construct directly from a series of statement arguments. + /** The arrays all default to zero, null, and empty strings. + */ + template<typename ...Args> params(Args && ... args) + { + strings.reserve(sizeof...(args)); + lengths.reserve(sizeof...(args)); + nonnulls.reserve(sizeof...(args)); + binaries.reserve(sizeof...(args)); + + // Start recursively storing parameters. + add_fields(std::forward<Args>(args)...); + } + + /// Compose a vector of pointers to parameter string values. + std::vector<const char *> get_pointers() const + { + const std::size_t num_fields = lengths.size(); + std::size_t cur_string = 0, cur_bin_string = 0; + std::vector<const char *> pointers(num_fields); + for (std::size_t index = 0; index < num_fields; index++) + { + const char *value; + if (binaries[index]) + { + value = bin_strings[cur_bin_string].get(); + cur_bin_string++; + } + else if (nonnulls[index]) + { + value = strings[cur_string].c_str(); + cur_string++; + } + else + { + value = nullptr; + } + pointers[index] = value; + } + return pointers; + } + + /// String values, for string parameters. + std::vector<std::string> strings; + /// As used by libpq: lengths of non-null arguments, in bytes. + std::vector<int> lengths; + /// As used by libpq: boolean "is this parameter non-null?" + std::vector<int> nonnulls; + /// As used by libpq: boolean "is this parameter in binary format?" + std::vector<int> binaries; + /// Binary string values, for binary parameters. + std::vector<pqxx::binarystring> bin_strings; + +private: + /// Add a non-null string field. + void add_field(std::string str) + { + lengths.push_back(int(str.size())); + nonnulls.push_back(1); + binaries.push_back(0); + strings.emplace_back(std::move(str)); + } + + /// Compile one argument (specialised for null pointer, a null value). + void add_field(std::nullptr_t) + { + lengths.push_back(0); + nonnulls.push_back(0); + binaries.push_back(0); + } + + /// Compile one argument (specialised for binarystring). + void add_field(const binarystring &arg) + { + lengths.push_back(int(arg.size())); + nonnulls.push_back(1); + binaries.push_back(1); + bin_strings.push_back(arg); + } + + /// Compile one argument (default, generic implementation). + /** Uses string_traits to represent the argument as a std::string. + */ + template<typename Arg> void add_field(const Arg &arg) + { + if (string_traits<Arg>::is_null(arg)) add_field(nullptr); + else add_field(to_string(arg)); + } + + /// Compile a dynamic_params object into a dynamic number of parameters. + template<typename IT> void add_field(const dynamic_params<IT> ¶meters) + { + for (auto param: parameters) add_field(param); + } + + /// Compile argument list. + /** This recursively "peels off" the next remaining element, compiles its + * information into its final form, and calls itself for the rest of the + * list. + * + * @param arg Current argument to be compiled. + * @param args Optional remaining arguments, to be compiled recursively. + */ + template<typename Arg, typename ...More> + void add_fields(Arg &&arg, More && ... args) + { + add_field(std::forward<Arg>(arg)); + // Compile remaining arguments, if any. + add_fields(std::forward<More>(args)...); + } + + /// Terminating version of add_fields, at the end of the list. + /** Recursion in add_fields ends with this call. + */ + void add_fields() {} +}; +} // namespace pqxx::internal +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/type_utils.hxx b/contrib/libs/libpqxx/include/pqxx/internal/type_utils.hxx new file mode 100644 index 0000000000..7bf5528018 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/type_utils.hxx @@ -0,0 +1,211 @@ +/** Type/template metaprogramming utilities for use internally in libpqxx + * + * 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_TYPE_UTILS +#define PQXX_H_TYPE_UTILS + +#include <memory> +#include <type_traits> + +#if defined(PQXX_HAVE_OPTIONAL) +#include <optional> +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +#error #include <experimental/optional> +#endif + +#include "pqxx/strconv" + +namespace pqxx +{ +namespace internal +{ + +/// Replicate std::void_t<> (available in C++17). +template<typename... T> using void_t = void; + +/// Extract the content type held by an `optional`-like wrapper type. +/* Replace nested `std::remove_*`s with `std::remove_cvref` in C++20 */ +template<typename T> using inner_type = typename std::remove_cv< + typename std::remove_reference< + decltype(*std::declval<T>()) + >::type +>::type; + +/// Does the given type have an `operator *()`? +template<typename T, typename = void> struct is_derefable : std::false_type {}; +template<typename T> struct is_derefable<T, void_t< + // Disable for arrays so they don't erroneously decay to pointers. + inner_type<typename std::enable_if<not std::is_array<T>::value, T>::type> +>> : std::true_type {}; + +/// Should the given type be treated as an optional-value wrapper type? +template<typename T, typename = void> struct is_optional : std::false_type {}; +template<typename T> struct is_optional<T, typename std::enable_if<( + is_derefable<T>::value + // Check if an `explicit operator bool` exists for this type + && std::is_constructible<bool, T>::value +)>::type> : std::true_type {}; + +/// Can `nullopt_t` implicitly convert to type T? +template< + typename T, + typename = void +> struct takes_std_nullopt : std::false_type {}; +#if defined(PQXX_HAVE_OPTIONAL) +template<typename T> struct takes_std_nullopt< + T, + typename std::enable_if<std::is_assignable<T, std::nullopt_t>::value>::type +> : std::true_type {}; +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +template<typename T> struct takes_std_nullopt< + T, + typename std::enable_if< + std::is_assignable<T, std::experimental::nullopt_t>::value + >::type +> : std::true_type {}; +#endif + +/// Is type T a `std::tuple<>`? +template<typename T, typename = void> struct is_tuple : std::false_type {}; +template<typename T> struct is_tuple< + T, + typename std::enable_if<(std::tuple_size<T>::value >= 0)>::type +> : std::true_type {}; + +/// Is type T an iterable container? +template<typename T, typename = void> struct is_container : std::false_type {}; +template<typename T> struct is_container< + T, + void_t< + decltype(std::begin(std::declval<T>())), + decltype(std::end(std::declval<T>())), + // Some people might implement a `std::tuple<>` specialization that is + // iterable when all the contained types are the same ;) + typename std::enable_if<not is_tuple<T>::value>::type + > +> : std::true_type {}; + +/// Get an appropriate null value for the given type. +/** + * pointer types `nullptr` + * `std::optional<>`-like `std::nullopt` + * `std::experimental::optional<>`-like `std::experimental::nullopt` + * other types `pqxx::string_traits<>::null()` + * Users may add support for their own wrapper types following this pattern. + */ +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + ( + is_optional<T>::value + && not takes_std_nullopt<T>::value + && std::is_assignable<T, std::nullptr_t>::value + ), + std::nullptr_t + >::type +{ return nullptr; } +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + (not is_optional<T>::value && not takes_std_nullopt<T>::value), + decltype(pqxx::string_traits<T>::null()) + >::type +{ return pqxx::string_traits<T>::null(); } +#if defined(PQXX_HAVE_OPTIONAL) +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + takes_std_nullopt<T>::value, + std::nullopt_t + >::type +{ return std::nullopt; } +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + takes_std_nullopt<T>::value, + std::experimental::nullopt_t + >::type +{ return std::experimental::nullopt; } +#endif + +/// Construct an optional-like type from the stored type. +/** + * While these may seem redundant, they are necessary to support smart pointers + * as optional storage types in a generic manner. It is suggested NOT to + * provide a version for `inner_type<T>*` as that will almost certainly leak + * memory. + * Users may add support for their own wrapper types following this pattern. + */ +// Enabled if the wrapper type can be directly constructed from the wrapped type +// (e.g. `std::optional<>`); explicitly disabled for raw pointers in case the +// inner type is convertible to a pointer (e.g. `int`) +template<typename T, typename V> constexpr auto make_optional(V&& v) + -> typename std::enable_if< + not std::is_same<T, inner_type<T>*>::value, + decltype(T(std::forward<V>(v))) + >::type +{ return T(std::forward<V>(v)); } +// Enabled if T is a specialization of `std::unique_ptr<>`. +template<typename T, typename V> constexpr auto make_optional(V&& v) + -> typename std::enable_if< + std::is_same<T, std::unique_ptr<inner_type<T>>>::value, + std::unique_ptr<inner_type<T>> + >::type +{ + return std::unique_ptr<inner_type<T>>(new inner_type<T>(std::forward<V>(v))); +} +// Enabled if T is a specialization of `std::shared_ptr<>`. +template<typename T, typename V> constexpr auto make_optional(V&& v) + -> typename std::enable_if< + std::is_same<T, std::shared_ptr<inner_type<T>>>::value, + std::shared_ptr<inner_type<T>> + >::type +{ return std::make_shared<inner_type<T>>(std::forward<V>(v)); } + +} // namespace pqxx::internal +} // namespace pqxx + + +// TODO: Move? +namespace pqxx +{ + +/// Meta `pqxx::string_traits` for std::optional-like types. +template<typename T> struct string_traits< + T, + typename std::enable_if<internal::is_optional<T>::value>::type +> +{ +private: + using I = internal::inner_type<T>; +public: + static constexpr const char *name() noexcept + { return string_traits<I>::name(); } + static constexpr bool has_null() noexcept { return true; } + static bool is_null(const T& v) + { return (not v || string_traits<I>::is_null(*v)); } + static constexpr T null() { return internal::null_value<T>(); } + static void from_string(const char Str[], T &Obj) + { + if (not Str) Obj = null(); + else + { + I inner; + string_traits<I>::from_string(Str, inner); + // Utilize existing memory if possible (e.g. for pointer types). + if (Obj) *Obj = inner; + // Important to assign to set valid flag for smart optional types. + else Obj = internal::make_optional<T>(inner); + } + } + static std::string to_string(const T& Obj) + { + if (is_null(Obj)) internal::throw_null_conversion(name()); + return string_traits<I>::to_string(*Obj); + } +}; + +} // namespace pqxx +#endif |