aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/libpqxx/src
diff options
context:
space:
mode:
authorgalaxycrab <UgnineSirdis@ydb.tech>2023-11-23 11:26:33 +0300
committergalaxycrab <UgnineSirdis@ydb.tech>2023-11-23 12:01:57 +0300
commit44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300 (patch)
treecb4d75cd1c6dbc3da0ed927337fd8d1b6ed9da84 /contrib/libs/libpqxx/src
parent0e69bf615395fdd48ecee032faaec81bc468b0b8 (diff)
downloadydb-44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300.tar.gz
YQ Connector:test INNER JOIN
Diffstat (limited to 'contrib/libs/libpqxx/src')
-rw-r--r--contrib/libs/libpqxx/src/array.cxx312
-rw-r--r--contrib/libs/libpqxx/src/binarystring.cxx150
-rw-r--r--contrib/libs/libpqxx/src/connection.cxx182
-rw-r--r--contrib/libs/libpqxx/src/connection_base.cxx1475
-rw-r--r--contrib/libs/libpqxx/src/cursor.cxx321
-rw-r--r--contrib/libs/libpqxx/src/dbtransaction.cxx99
-rw-r--r--contrib/libs/libpqxx/src/encodings.cxx826
-rw-r--r--contrib/libs/libpqxx/src/errorhandler.cxx44
-rw-r--r--contrib/libs/libpqxx/src/except.cxx124
-rw-r--r--contrib/libs/libpqxx/src/field.cxx77
-rw-r--r--contrib/libs/libpqxx/src/largeobject.cxx313
-rw-r--r--contrib/libs/libpqxx/src/nontransaction.cxx25
-rw-r--r--contrib/libs/libpqxx/src/notification.cxx36
-rw-r--r--contrib/libs/libpqxx/src/pipeline.cxx413
-rw-r--r--contrib/libs/libpqxx/src/prepared_statement.cxx69
-rw-r--r--contrib/libs/libpqxx/src/result.cxx454
-rw-r--r--contrib/libs/libpqxx/src/robusttransaction.cxx317
-rw-r--r--contrib/libs/libpqxx/src/row.cxx276
-rw-r--r--contrib/libs/libpqxx/src/sql_cursor.cxx309
-rw-r--r--contrib/libs/libpqxx/src/statement_parameters.cxx58
-rw-r--r--contrib/libs/libpqxx/src/strconv.cxx724
-rw-r--r--contrib/libs/libpqxx/src/stream_base.cxx43
-rw-r--r--contrib/libs/libpqxx/src/stream_from.cxx261
-rw-r--r--contrib/libs/libpqxx/src/stream_to.cxx142
-rw-r--r--contrib/libs/libpqxx/src/subtransaction.cxx74
-rw-r--r--contrib/libs/libpqxx/src/tablereader.cxx227
-rw-r--r--contrib/libs/libpqxx/src/tablestream.cxx38
-rw-r--r--contrib/libs/libpqxx/src/tablewriter.cxx160
-rw-r--r--contrib/libs/libpqxx/src/transaction.cxx72
-rw-r--r--contrib/libs/libpqxx/src/transaction_base.cxx577
-rw-r--r--contrib/libs/libpqxx/src/util.cxx121
-rw-r--r--contrib/libs/libpqxx/src/version.cxx18
32 files changed, 8337 insertions, 0 deletions
diff --git a/contrib/libs/libpqxx/src/array.cxx b/contrib/libs/libpqxx/src/array.cxx
new file mode 100644
index 0000000000..c16c7ae586
--- /dev/null
+++ b/contrib/libs/libpqxx/src/array.cxx
@@ -0,0 +1,312 @@
+/** Handling of SQL arrays.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <utility>
+
+#include "pqxx/array"
+#include "pqxx/except"
+
+
+namespace pqxx
+{
+/// Scan to next glyph in the buffer. Assumes there is one.
+std::string::size_type array_parser::scan_glyph(
+ std::string::size_type pos) const
+{
+ assert(pos < m_end);
+ return m_scan(m_input, m_end, pos);
+}
+
+
+/// Scan to next glyph in a substring. Assumes there is one.
+std::string::size_type array_parser::scan_glyph(
+ std::string::size_type pos,
+ std::string::size_type end) const
+{
+ assert(pos < end);
+ assert(end <= m_end);
+ return m_scan(m_input, end, pos);
+}
+
+
+/// Find the end of a single-quoted SQL string in an SQL array.
+/** Returns the offset of the first character after the closing quote.
+ */
+std::string::size_type array_parser::scan_single_quoted_string() const
+{
+ auto here = m_pos, next = scan_glyph(here);
+ assert(next < m_end);
+ assert(next - here == 1);
+ assert(m_input[here] == '\'');
+ for (
+ here = next, next = scan_glyph(here);
+ here < m_end;
+ here = next, next = scan_glyph(here)
+ )
+ {
+ if (next - here == 1) switch (m_input[here])
+ {
+ case '\'':
+ // SQL escapes single quotes by doubling them. Terrible idea, but it's
+ // what we have. Inspect the next character to find out whether this is
+ // the closing quote, or an escaped one inside the string.
+ here = next;
+ // (We can read beyond this quote because the array will always end in
+ // a closing brace.)
+ next = scan_glyph(here);
+
+ if ((here + 1 < next) or (m_input[here] != '\''))
+ {
+ // Our lookahead character is not an escaped quote. It's the first
+ // character outside our string. So, return it.
+ return here;
+ }
+
+ // We've just scanned an escaped quote. Keep going.
+ break;
+
+ case '\\':
+ // Backslash escape. Skip ahead by one more character.
+ here = next;
+ next = scan_glyph(here);
+ break;
+ }
+ }
+ throw argument_error{"Null byte in SQL string: " + std::string{m_input}};
+}
+
+
+/// Parse a single-quoted SQL string: un-quote it and un-escape it.
+std::string array_parser::parse_single_quoted_string(
+ std::string::size_type end) const
+{
+ // There have to be at least 2 characters: the opening and closing quotes.
+ assert(m_pos + 1 < end);
+ assert(m_input[m_pos] == '\'');
+ assert(m_input[end - 1] == '\'');
+
+ std::string output;
+ // Maximum output size is same as the input size, minus the opening and
+ // closing quotes. In the worst case, the real number could be half that.
+ // Usually it'll be a pretty close estimate.
+ output.reserve(end - m_pos - 2);
+ for (
+ auto here = m_pos + 1, next = scan_glyph(here, end);
+ here < end - 1;
+ here = next, next = scan_glyph(here, end)
+ )
+ {
+ if (
+ next - here == 1 and
+ (m_input[here] == '\'' or m_input[here] == '\\')
+ )
+ {
+ // Skip escape.
+ here = next;
+ next = scan_glyph(here, end);
+ }
+
+ output.append(m_input + here, m_input + next);
+ }
+
+ return output;
+}
+
+
+/// Find the end of a double-quoted SQL string in an SQL array.
+std::string::size_type array_parser::scan_double_quoted_string() const
+{
+ auto here = m_pos;
+ assert(here < m_end);
+ auto next = scan_glyph(here);
+ assert(next - here == 1);
+ assert(m_input[here] == '"');
+ for (
+ here = next, next = scan_glyph(here);
+ here < m_end;
+ here = next, next = scan_glyph(here)
+ )
+ {
+ if (next - here == 1) switch (m_input[here])
+ {
+ case '\\':
+ // Backslash escape. Skip ahead by one more character.
+ here = next;
+ next = scan_glyph(here);
+ break;
+
+ case '"':
+ // Closing quote. Return the position right after.
+ return next;
+ }
+ }
+ throw argument_error{"Null byte in SQL string: " + std::string{m_input}};
+}
+
+
+/// Parse a double-quoted SQL string: un-quote it and un-escape it.
+std::string array_parser::parse_double_quoted_string(
+ std::string::size_type end) const
+{
+ // There have to be at least 2 characters: the opening and closing quotes.
+ assert(m_pos + 1 < end);
+ assert(m_input[m_pos] == '"');
+ assert(m_input[end - 1] == '"');
+
+ std::string output;
+ // Maximum output size is same as the input size, minus the opening and
+ // closing quotes. In the worst case, the real number could be half that.
+ // Usually it'll be a pretty close estimate.
+ output.reserve(std::size_t(end - m_pos - 2));
+
+ for (
+ auto here = scan_glyph(m_pos, end), next = scan_glyph(here, end);
+ here < end - 1;
+ here = next, next = scan_glyph(here, end)
+ )
+ {
+ if ((next - here == 1) and (m_input[here] == '\\'))
+ {
+ // Skip escape.
+ here = next;
+ next = scan_glyph(here, end);
+ }
+
+ output.append(m_input + here, m_input + next);
+ }
+
+ return output;
+}
+
+
+/// Find the end of an unquoted string in an SQL array.
+/** Assumes UTF-8 or an ASCII-superset single-byte encoding.
+ */
+std::string::size_type array_parser::scan_unquoted_string() const
+{
+ auto here = m_pos, next = scan_glyph(here);
+ assert(here < m_end);
+ assert((next - here > 1) or (m_input[here] != '\''));
+ assert((next - here > 1) or (m_input[here] != '"'));
+
+ while (
+ (next - here) > 1 or
+ (
+ m_input[here] != ',' and
+ m_input[here] != ';' and
+ m_input[here] != '}'
+ )
+ )
+ {
+ here = next;
+ next = scan_glyph(here);
+ }
+ return here;
+}
+
+
+/// Parse an unquoted SQL string.
+/** Here, the special unquoted value NULL means a null value, not a string
+ * that happens to spell "NULL".
+ */
+std::string array_parser::parse_unquoted_string(
+ std::string::size_type end) const
+{
+ return std::string{m_input + m_pos, m_input + end};
+}
+
+
+array_parser::array_parser(
+ const char input[],
+ internal::encoding_group enc) :
+ m_input(input),
+ m_end(input == nullptr ? 0 : std::strlen(input)),
+ m_scan(internal::get_glyph_scanner(enc)),
+ m_pos(0)
+{
+}
+
+
+std::pair<array_parser::juncture, std::string>
+array_parser::get_next()
+{
+ juncture found;
+ std::string value;
+ std::string::size_type end;
+
+ if (m_input == nullptr or (m_pos >= m_end))
+ return std::make_pair(juncture::done, value);
+
+ if (scan_glyph(m_pos) - m_pos > 1)
+ {
+ // Non-ASCII unquoted string.
+ end = scan_unquoted_string();
+ value = parse_unquoted_string(end);
+ found = juncture::string_value;
+ }
+ else switch (m_input[m_pos])
+ {
+ case '\0':
+ // TODO: Maybe just raise an error?
+ found = juncture::done;
+ end = m_pos;
+ break;
+ case '{':
+ found = juncture::row_start;
+ end = scan_glyph(m_pos);
+ break;
+ case '}':
+ found = juncture::row_end;
+ end = scan_glyph(m_pos);
+ break;
+ case '\'':
+ found = juncture::string_value;
+ end = scan_single_quoted_string();
+ value = parse_single_quoted_string(end);
+ break;
+ case '"':
+ found = juncture::string_value;
+ end = scan_double_quoted_string();
+ value = parse_double_quoted_string(end);
+ break;
+ default:
+ end = scan_unquoted_string();
+ value = parse_unquoted_string(end);
+ if (value == "NULL")
+ {
+ // In this one situation, as a special case, NULL means a null field,
+ // not a string that happens to spell "NULL".
+ value.clear();
+ found = juncture::null_value;
+ }
+ else
+ {
+ // The normal case: we just parsed an unquoted string. The value is
+ // what we need.
+ found = juncture::string_value;
+ }
+ break;
+ }
+
+ // Skip a trailing field separator, if present.
+ if (end < m_end)
+ {
+ auto next = scan_glyph(end);
+ if (next - end == 1 and (m_input[end] == ',' or m_input[end] == ';'))
+ end = next;
+ }
+
+ m_pos = end;
+ return std::make_pair(found, value);
+}
+} // namespace pqxx
diff --git a/contrib/libs/libpqxx/src/binarystring.cxx b/contrib/libs/libpqxx/src/binarystring.cxx
new file mode 100644
index 0000000000..0091f48baf
--- /dev/null
+++ b/contrib/libs/libpqxx/src/binarystring.cxx
@@ -0,0 +1,150 @@
+/** Implementation of bytea (binary string) conversions.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <new>
+#include <stdexcept>
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/binarystring"
+#include "pqxx/field"
+
+
+using namespace pqxx::internal;
+
+namespace
+{
+using unsigned_char = unsigned char;
+using buffer = std::pair<unsigned char *, size_t>;
+
+
+buffer to_buffer(const void *data, size_t len)
+{
+ void *const output{malloc(len + 1)};
+ if (output == nullptr) throw std::bad_alloc{};
+ static_cast<char *>(output)[len] = '\0';
+ memcpy(static_cast<char *>(output), data, len);
+ return buffer{static_cast<unsigned char *>(output), len};
+}
+
+
+buffer to_buffer(const std::string &source)
+{
+ return to_buffer(source.c_str(), source.size());
+}
+
+
+
+buffer unescape(const unsigned char escaped[])
+{
+#ifdef _WIN32
+ /* On Windows only, the return value from PQunescapeBytea() must be freed
+ * using PQfreemem. Copy to a buffer allocated by libpqxx, so that the
+ * binarystring's buffer can be freed uniformly,
+ */
+ size_t unescaped_len = 0;
+ // TODO: Use make_unique once we require C++14. Sooo much easier.
+ std::unique_ptr<unsigned char, void(*)(unsigned char *)> A(
+ PQunescapeBytea(const_cast<unsigned char *>(escaped), &unescaped_len),
+ freepqmem_templated<unsigned char>);
+ void *data = A.get();
+ if (data == nullptr) throw std::bad_alloc{};
+ return to_buffer(data, unescaped_len);
+#else
+ /* On non-Windows platforms, it's okay to free libpq-allocated memory using
+ * free(). No extra copy needed.
+ */
+ buffer unescaped;
+ unescaped.first = PQunescapeBytea(
+ const_cast<unsigned char *>(escaped), &unescaped.second);
+ if (unescaped.first == nullptr) throw std::bad_alloc{};
+ return unescaped;
+#endif
+}
+
+} // namespace
+
+
+pqxx::binarystring::binarystring(const field &F) :
+ m_buf{make_smart_pointer()},
+ m_size{0}
+{
+ buffer unescaped{unescape(reinterpret_cast<const_pointer>(F.c_str()))};
+ m_buf = make_smart_pointer(unescaped.first);
+ m_size = unescaped.second;
+}
+
+
+pqxx::binarystring::binarystring(const std::string &s) :
+ m_buf{make_smart_pointer()},
+ m_size{s.size()}
+{
+ m_buf = make_smart_pointer(to_buffer(s).first);
+}
+
+
+pqxx::binarystring::binarystring(const void *binary_data, size_t len) :
+ m_buf{make_smart_pointer()},
+ m_size{len}
+{
+ m_buf = make_smart_pointer(to_buffer(binary_data, len).first);
+}
+
+
+bool pqxx::binarystring::operator==(const binarystring &rhs) const noexcept
+{
+ if (rhs.size() != size()) return false;
+ return std::memcmp(data(), rhs.data(), size()) == 0;
+}
+
+
+pqxx::binarystring &pqxx::binarystring::operator=(const binarystring &rhs)
+{
+ m_buf = rhs.m_buf;
+ m_size = rhs.m_size;
+ return *this;
+}
+
+
+pqxx::binarystring::const_reference pqxx::binarystring::at(size_type n) const
+{
+ if (n >= m_size)
+ {
+ if (m_size == 0)
+ throw std::out_of_range{"Accessing empty binarystring"};
+ throw std::out_of_range{
+ "binarystring index out of range: " +
+ to_string(n) + " (should be below " + to_string(m_size) + ")"};
+ }
+ return data()[n];
+}
+
+
+void pqxx::binarystring::swap(binarystring &rhs)
+{
+ m_buf.swap(rhs.m_buf);
+
+ // This part very obviously can't go wrong, so do it last
+ const auto s = m_size;
+ m_size = rhs.m_size;
+ rhs.m_size = s;
+}
+
+
+std::string pqxx::binarystring::str() const
+{
+ return std::string{get(), m_size};
+}
diff --git a/contrib/libs/libpqxx/src/connection.cxx b/contrib/libs/libpqxx/src/connection.cxx
new file mode 100644
index 0000000000..982b6d60f9
--- /dev/null
+++ b/contrib/libs/libpqxx/src/connection.cxx
@@ -0,0 +1,182 @@
+/** Implementation of the pqxx::connection and sibling classes.
+ *
+ * Different ways of setting up a backend connection.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <stdexcept>
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/connection"
+
+
+pqxx::connectionpolicy::connectionpolicy(const std::string &opts) :
+ m_options{opts}
+{
+}
+
+
+pqxx::connectionpolicy::~connectionpolicy() noexcept
+{
+}
+
+
+pqxx::connectionpolicy::handle
+pqxx::connectionpolicy::normalconnect(handle orig)
+{
+ if (orig) return orig;
+ orig = PQconnectdb(options().c_str());
+ if (orig == nullptr) throw std::bad_alloc{};
+ if (PQstatus(orig) != CONNECTION_OK)
+ {
+ const std::string msg{PQerrorMessage(orig)};
+ PQfinish(orig);
+ throw broken_connection{msg};
+ }
+ return orig;
+}
+
+
+pqxx::connectionpolicy::handle
+pqxx::connectionpolicy::do_startconnect(handle orig)
+{
+ return orig;
+}
+
+pqxx::connectionpolicy::handle
+pqxx::connectionpolicy::do_completeconnect(handle orig)
+{
+ return orig;
+}
+
+pqxx::connectionpolicy::handle
+pqxx::connectionpolicy::do_dropconnect(handle orig) noexcept
+{
+ return orig;
+}
+
+pqxx::connectionpolicy::handle
+pqxx::connectionpolicy::do_disconnect(handle orig) noexcept
+{
+ orig = do_dropconnect(orig);
+ if (orig) PQfinish(orig);
+ return nullptr;
+}
+
+
+bool pqxx::connectionpolicy::is_ready(handle h) const noexcept
+{
+ return h != nullptr;
+}
+
+
+pqxx::connectionpolicy::handle
+pqxx::connect_direct::do_startconnect(handle orig)
+{
+ if (orig) return orig;
+ orig = normalconnect(orig);
+ if (PQstatus(orig) != CONNECTION_OK)
+ {
+ const std::string msg{PQerrorMessage(orig)};
+ do_disconnect(orig);
+ throw broken_connection{msg};
+ }
+ return orig;
+}
+
+
+pqxx::connectionpolicy::handle
+pqxx::connect_lazy::do_completeconnect(handle orig)
+{
+ return normalconnect(orig);
+}
+
+
+pqxx::connect_async::connect_async(const std::string &opts) :
+ connectionpolicy{opts},
+ m_connecting{false}
+{
+}
+
+pqxx::connectionpolicy::handle
+pqxx::connect_async::do_startconnect(handle orig)
+{
+ if (orig != nullptr) return orig; // Already connecting or connected.
+ m_connecting = false;
+ orig = PQconnectStart(options().c_str());
+ if (orig == nullptr) throw std::bad_alloc{};
+ if (PQstatus(orig) == CONNECTION_BAD)
+ {
+ do_dropconnect(orig);
+ throw broken_connection{std::string{PQerrorMessage(orig)}};
+ }
+ m_connecting = true;
+ return orig;
+}
+
+
+pqxx::connectionpolicy::handle
+pqxx::connect_async::do_completeconnect(handle orig)
+{
+ const bool makenew = (orig == nullptr);
+ if (makenew) orig = do_startconnect(orig);
+ if (not m_connecting) return orig;
+
+ // Our "attempt to connect" state ends here, for better or for worse
+ m_connecting = false;
+
+ PostgresPollingStatusType pollstatus = PGRES_POLLING_WRITING;
+
+ do
+ {
+ switch (pollstatus)
+ {
+ case PGRES_POLLING_FAILED:
+ if (makenew) do_disconnect(orig);
+ throw broken_connection{std::string{PQerrorMessage(orig)}};
+
+ case PGRES_POLLING_READING:
+ internal::wait_read(orig);
+ break;
+
+ case PGRES_POLLING_WRITING:
+ internal::wait_write(orig);
+ break;
+
+ case PGRES_POLLING_OK:
+ break;
+
+ default:
+ // Meaningless, really, but deals with the obsolete PGRES_POLLING_ACTIVE
+ // without requiring it to be defined.
+ break;
+ }
+ pollstatus = PQconnectPoll(orig);
+ } while (pollstatus != PGRES_POLLING_OK);
+
+ return orig;
+}
+
+
+pqxx::connectionpolicy::handle
+pqxx::connect_async::do_dropconnect(handle orig) noexcept
+{
+ m_connecting = false;
+ return orig;
+}
+
+
+bool pqxx::connect_async::is_ready(handle h) const noexcept
+{
+ return h != nullptr and not m_connecting;
+}
diff --git a/contrib/libs/libpqxx/src/connection_base.cxx b/contrib/libs/libpqxx/src/connection_base.cxx
new file mode 100644
index 0000000000..345e3414ee
--- /dev/null
+++ b/contrib/libs/libpqxx/src/connection_base.cxx
@@ -0,0 +1,1475 @@
+/** Implementation of the pqxx::connection_base abstract base class.
+ *
+ * pqxx::connection_base encapsulates a frontend to backend connection.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <iterator>
+#include <memory>
+#include <stdexcept>
+
+#if defined(_WIN32)
+// Includes for WSAPoll().
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <mstcpip.h>
+#elif defined(HAVE_POLL)
+// Include for poll().
+#include <poll.h>
+#elif defined(HAVE_SYS_SELECT_H)
+// Include for select() on (recent) POSIX systems.
+#include <sys/select.h>
+#else
+// Includes for select() according to various older standards.
+#if defined(HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#endif
+#if defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/binarystring"
+#include "pqxx/connection"
+#include "pqxx/connection_base"
+#include "pqxx/nontransaction"
+#include "pqxx/pipeline"
+#include "pqxx/result"
+#include "pqxx/strconv"
+#include "pqxx/transaction"
+#include "pqxx/notification"
+
+#include "pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx"
+#include "pqxx/internal/gates/errorhandler-connection.hxx"
+#include "pqxx/internal/gates/result-creation.hxx"
+#include "pqxx/internal/gates/result-connection.hxx"
+
+using namespace pqxx;
+using namespace pqxx::internal;
+using namespace pqxx::prepare;
+
+
+extern "C"
+{
+// The PQnoticeProcessor that receives an error or warning from libpq and sends
+// it to the appropriate connection for processing.
+void pqxx_notice_processor(void *conn, const char *msg) noexcept
+{
+ reinterpret_cast<pqxx::connection_base *>(conn)->process_notice(msg);
+}
+
+
+// There's no way in libpq to disable a connection's notice processor. So,
+// set an inert one to get the same effect.
+void inert_notice_processor(void *, const char *) noexcept {}
+}
+
+
+std::string pqxx::encrypt_password(
+ const std::string &user, const std::string &password)
+{
+ std::unique_ptr<char, void (*)(char *)> p{
+ PQencryptPassword(password.c_str(), user.c_str()),
+ freepqmem_templated<char>};
+ return std::string{p.get()};
+}
+
+
+void pqxx::connection_base::init()
+{
+ m_conn = m_policy.do_startconnect(m_conn);
+#include "pqxx/internal/ignore-deprecated-pre.hxx"
+ if (m_policy.is_ready(m_conn)) activate();
+#include "pqxx/internal/ignore-deprecated-post.hxx"
+}
+
+
+pqxx::result pqxx::connection_base::make_result(
+ internal::pq::PGresult *rhs,
+ const std::string &query)
+{
+ return gate::result_creation::create(
+ rhs,
+ query,
+ internal::enc_group(encoding_id()));
+}
+
+
+int pqxx::connection_base::backendpid() const noexcept
+{
+ return m_conn ? PQbackendPID(m_conn) : 0;
+}
+
+
+namespace
+{
+PQXX_PURE int socket_of(const ::pqxx::internal::pq::PGconn *c) noexcept
+{
+ return c ? PQsocket(c) : -1;
+}
+}
+
+
+int pqxx::connection_base::sock() const noexcept
+{
+ return socket_of(m_conn);
+}
+
+
+void pqxx::connection_base::activate()
+{
+ if (not is_open())
+ {
+ if (m_inhibit_reactivation)
+ throw broken_connection{
+ "Could not reactivate connection; "
+ "reactivation is inhibited"};
+
+ // If any objects were open that didn't survive the closing of our
+ // connection, don't try to reactivate
+ if (m_reactivation_avoidance.get()) return;
+
+ try
+ {
+ m_conn = m_policy.do_startconnect(m_conn);
+ m_conn = m_policy.do_completeconnect(m_conn);
+ m_completed = true; // (But retracted if error is thrown below)
+
+ if (not is_open()) throw broken_connection{};
+
+ set_up_state();
+ }
+ catch (const broken_connection &e)
+ {
+ disconnect();
+ m_completed = false;
+ throw broken_connection{e.what()};
+ }
+ catch (const std::exception &)
+ {
+ m_completed = false;
+ throw;
+ }
+ }
+}
+
+
+void pqxx::connection_base::deactivate()
+{
+ if (m_conn == nullptr) return;
+
+ if (m_trans.get())
+ throw usage_error{
+ "Attempt to deactivate connection while " +
+ m_trans.get()->description() + " still open"};
+
+ if (m_reactivation_avoidance.get())
+ {
+ process_notice(
+ "Attempt to deactivate connection while it is in a state "
+ "that cannot be fully recovered later (ignoring)");
+ return;
+ }
+
+ m_completed = false;
+ m_conn = m_policy.do_disconnect(m_conn);
+}
+
+
+void pqxx::connection_base::simulate_failure()
+{
+ if (m_conn)
+ {
+ m_conn = m_policy.do_disconnect(m_conn);
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ inhibit_reactivation(true);
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ }
+}
+
+
+int pqxx::connection_base::protocol_version() const noexcept
+{
+ return m_conn ? PQprotocolVersion(m_conn) : 0;
+}
+
+
+int pqxx::connection_base::server_version() const noexcept
+{
+ return m_serverversion;
+}
+
+
+void pqxx::connection_base::set_variable(const std::string &Var,
+ const std::string &Value)
+{
+ if (m_trans.get())
+ {
+ // We're in a transaction. The variable should go in there.
+ m_trans.get()->set_variable(Var, Value);
+ }
+ else
+ {
+ // We're not in a transaction. Set a session variable.
+ if (is_open()) raw_set_var(Var, Value);
+ m_vars[Var] = Value;
+ }
+}
+
+
+std::string pqxx::connection_base::get_variable(const std::string &Var)
+{
+ return m_trans.get() ? m_trans.get()->get_variable(Var) : raw_get_var(Var);
+}
+
+
+std::string pqxx::connection_base::raw_get_var(const std::string &Var)
+{
+ // Is this variable in our local map of set variables?
+ const auto i = m_vars.find(Var);
+ if (i != m_vars.end()) return i->second;
+
+ return exec(("SHOW " + Var).c_str(), 0).at(0).at(0).as(std::string{});
+}
+
+
+void pqxx::connection_base::clearcaps() noexcept
+{
+ m_caps.reset();
+}
+
+
+/** Set up various parts of logical connection state that may need to be
+ * recovered because the physical connection to the database was lost and is
+ * being reset, or that may not have been initialized yet.
+ */
+void pqxx::connection_base::set_up_state()
+{
+ if (m_conn == nullptr)
+ throw internal_error{"set_up_state() on no connection"};
+
+ if (status() != CONNECTION_OK)
+ {
+ const auto msg = err_msg();
+ m_conn = m_policy.do_disconnect(m_conn);
+ throw failure{msg};
+ }
+
+ read_capabilities();
+
+ for (auto &p: m_prepared) p.second.registered = false;
+
+ // The default notice processor in libpq writes to stderr. Ours does
+ // nothing.
+ // If the caller registers an error handler, this gets replaced with an
+ // error handler that walks down the connection's chain of handlers. We
+ // don't do that by default because there's a danger: libpq may call the
+ // notice processor via a result object, even after the connection has been
+ // destroyed and the handlers list no longer exists.
+ clear_notice_processor();
+
+ internal_set_trace();
+
+ if (not m_receivers.empty() or not m_vars.empty())
+ {
+ std::stringstream restore_query;
+
+ // Pipeline all queries needed to restore receivers and variables, so we can
+ // send them over in one go.
+
+ // Reinstate all active receivers
+ if (not m_receivers.empty())
+ {
+ std::string Last;
+ for (auto &i: m_receivers)
+ {
+ // m_receivers can handle multiple receivers waiting on the same event;
+ // issue just one LISTEN for each event.
+ if (i.first != Last)
+ {
+ restore_query << "LISTEN " << quote_name(i.first) << "; ";
+ Last = i.first;
+ }
+ }
+ }
+
+ for (auto &i: m_vars)
+ restore_query << "SET " << i.first << "=" << i.second << "; ";
+
+ // Now do the whole batch at once
+ PQsendQuery(m_conn, restore_query.str().c_str());
+ result r;
+ do
+ r = make_result(PQgetResult(m_conn), "[RECONNECT]");
+ while (gate::result_connection(r));
+ }
+
+ m_completed = true;
+ if (not is_open()) throw broken_connection{};
+}
+
+
+void pqxx::connection_base::check_result(const result &R)
+{
+ if (not is_open()) throw broken_connection{};
+
+ // A shame we can't quite detect out-of-memory to turn this into a bad_alloc!
+ if (not gate::result_connection{R}) throw failure(err_msg());
+
+ gate::result_creation{R}.check_status();
+}
+
+
+void pqxx::connection_base::disconnect() noexcept
+{
+ // When we activate again, the server may be different!
+ clearcaps();
+
+ m_conn = m_policy.do_disconnect(m_conn);
+}
+
+
+bool pqxx::connection_base::is_open() const noexcept
+{
+ return m_conn and m_completed and (status() == CONNECTION_OK);
+}
+
+
+void pqxx::connection_base::process_notice_raw(const char msg[]) noexcept
+{
+ if ((msg == nullptr) or (*msg == '\0')) return;
+ const auto
+ rbegin = m_errorhandlers.crbegin(),
+ rend = m_errorhandlers.crend();
+ for (auto i = rbegin; (i != rend) and (**i)(msg); ++i) ;
+}
+
+
+void pqxx::connection_base::process_notice(const char msg[]) noexcept
+{
+ if (msg == nullptr) return;
+ const auto len = strlen(msg);
+ if (len == 0) return;
+ if (msg[len-1] == '\n')
+ {
+ process_notice_raw(msg);
+ }
+ else try
+ {
+ // Newline is missing. Try the C++ string version of this function.
+ process_notice(std::string{msg});
+ }
+ catch (const std::exception &)
+ {
+ // If we can't even do that, use plain old buffer copying instead
+ // (unavoidably, this will break up overly long messages!)
+ const char separator[] = "[...]\n";
+ char buf[1007];
+ size_t bytes = sizeof(buf)-sizeof(separator)-1;
+ size_t written;
+ strcpy(&buf[bytes], separator);
+ // Write all chunks but last. Each will fill the buffer exactly.
+ for (written = 0; (written+bytes) < len; written += bytes)
+ {
+ memcpy(buf, &msg[written], bytes);
+ process_notice_raw(buf);
+ }
+ // Write any remaining bytes (which won't fill an entire buffer)
+ bytes = len-written;
+ memcpy(buf, &msg[written], bytes);
+ // Add trailing nul byte, plus newline unless there already is one
+ strcpy(&buf[bytes], &"\n"[buf[bytes-1]=='\n']);
+ process_notice_raw(buf);
+ }
+}
+
+
+void pqxx::connection_base::process_notice(const std::string &msg) noexcept
+{
+ // Ensure that message passed to errorhandler ends in newline
+ if (msg[msg.size()-1] == '\n')
+ {
+ process_notice_raw(msg.c_str());
+ }
+ else try
+ {
+ const std::string nl = msg + "\n";
+ process_notice_raw(nl.c_str());
+ }
+ catch (const std::exception &)
+ {
+ // If nothing else works, try writing the message without the newline
+ process_notice_raw(msg.c_str());
+ // This is ugly.
+ process_notice_raw("\n");
+ }
+}
+
+
+void pqxx::connection_base::trace(FILE *Out) noexcept
+{
+ m_trace = Out;
+ if (m_conn) internal_set_trace();
+}
+
+
+void pqxx::connection_base::add_receiver(pqxx::notification_receiver *T)
+{
+ if (T == nullptr) throw argument_error{"Null receiver registered"};
+
+ // Add to receiver list and attempt to start listening.
+ const auto p = m_receivers.find(T->channel());
+ const receiver_list::value_type NewVal(T->channel(), T);
+
+ if (p == m_receivers.end())
+ {
+ // Not listening on this event yet, start doing so.
+ const std::string LQ("LISTEN " + quote_name(T->channel()));
+
+ if (is_open()) try
+ {
+ check_result(make_result(PQexec(m_conn, LQ.c_str()), LQ));
+ }
+ catch (const broken_connection &)
+ {
+ }
+ m_receivers.insert(NewVal);
+ }
+ else
+ {
+ m_receivers.insert(p, NewVal);
+ }
+}
+
+
+void pqxx::connection_base::remove_receiver(pqxx::notification_receiver *T)
+ noexcept
+{
+ if (T == nullptr) return;
+
+ try
+ {
+ const std::pair<const std::string, notification_receiver *> needle{
+ T->channel(), T};
+ auto R = m_receivers.equal_range(needle.first);
+ const auto i = find(R.first, R.second, needle);
+
+ if (i == R.second)
+ {
+ process_notice(
+ "Attempt to remove unknown receiver '" + needle.first + "'");
+ }
+ else
+ {
+ // Erase first; otherwise a notification for the same receiver may yet
+ // come in and wreak havoc. Thanks Dragan Milenkovic.
+ const bool gone = (m_conn and (R.second == ++R.first));
+ m_receivers.erase(i);
+ if (gone) exec(("UNLISTEN " + quote_name(needle.first)).c_str(), 0);
+ }
+ }
+ catch (const std::exception &e)
+ {
+ process_notice(e.what());
+ }
+}
+
+
+bool pqxx::connection_base::consume_input() noexcept
+{
+ return PQconsumeInput(m_conn) != 0;
+}
+
+
+bool pqxx::connection_base::is_busy() const noexcept
+{
+ return PQisBusy(m_conn) != 0;
+}
+
+
+namespace
+{
+/// Stateful libpq "cancel" operation.
+class cancel_wrapper
+{
+ PGcancel *m_cancel;
+ char m_errbuf[500];
+
+public:
+ explicit cancel_wrapper(PGconn *conn) :
+ m_cancel{nullptr},
+ m_errbuf{}
+ {
+ if (conn)
+ {
+ m_cancel = PQgetCancel(conn);
+ if (m_cancel == nullptr) throw std::bad_alloc{};
+ }
+ }
+ ~cancel_wrapper() { if (m_cancel) PQfreeCancel(m_cancel); }
+
+ void operator()()
+ {
+ if (not m_cancel) return;
+ if (PQcancel(m_cancel, m_errbuf, int{sizeof(m_errbuf)}) == 0)
+ throw sql_error{std::string{m_errbuf}};
+ }
+};
+}
+
+
+void pqxx::connection_base::cancel_query()
+{
+ cancel_wrapper cancel{m_conn};
+ cancel();
+}
+
+
+void pqxx::connection_base::set_verbosity(error_verbosity verbosity) noexcept
+{
+ PQsetErrorVerbosity(m_conn, static_cast<PGVerbosity>(verbosity));
+ m_verbosity = verbosity;
+}
+
+
+namespace
+{
+/// Unique pointer to PGnotify.
+using notify_ptr = std::unique_ptr<PGnotify, void (*)(PGnotify *)>;
+
+
+/// Get one notification from a connection, or null.
+notify_ptr get_notif(pqxx::internal::pq::PGconn *conn)
+{
+ return notify_ptr(PQnotifies(conn), freepqmem_templated<PGnotify>);
+}
+}
+
+
+int pqxx::connection_base::get_notifs()
+{
+ if (not is_open()) return 0;
+
+ if (not consume_input()) throw broken_connection{};
+
+ // Even if somehow we receive notifications during our transaction, don't
+ // deliver them.
+ if (m_trans.get()) return 0;
+
+ int notifs = 0;
+ for (auto N = get_notif(m_conn); N.get(); N = get_notif(m_conn))
+ {
+ notifs++;
+
+ const auto Hit = m_receivers.equal_range(std::string{N->relname});
+ for (auto i = Hit.first; i != Hit.second; ++i) try
+ {
+ (*i->second)(N->extra, N->be_pid);
+ }
+ catch (const std::exception &e)
+ {
+ try
+ {
+ process_notice(
+ "Exception in notification receiver '" +
+ i->first +
+ "': " +
+ e.what() +
+ "\n");
+ }
+ catch (const std::bad_alloc &)
+ {
+ // Out of memory. Try to get the message out in a more robust way.
+ process_notice(
+ "Exception in notification receiver, "
+ "and also ran out of memory\n");
+ }
+ catch (const std::exception &)
+ {
+ process_notice(
+ "Exception in notification receiver "
+ "(compounded by other error)\n");
+ }
+ }
+
+ N.reset();
+ }
+ return notifs;
+}
+
+
+const char *pqxx::connection_base::dbname()
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ if (m_conn == nullptr) activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ return PQdb(m_conn);
+}
+
+
+const char *pqxx::connection_base::username()
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ if (m_conn == nullptr) activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ return PQuser(m_conn);
+}
+
+
+const char *pqxx::connection_base::hostname()
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ if (m_conn == nullptr) activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ return PQhost(m_conn);
+}
+
+
+const char *pqxx::connection_base::port()
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ if (m_conn == nullptr) activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ return PQport(m_conn);
+}
+
+
+const char *pqxx::connection_base::err_msg() const noexcept
+{
+ return m_conn ? PQerrorMessage(m_conn) : "No connection to database";
+}
+
+
+void pqxx::connection_base::clear_notice_processor()
+{
+ PQsetNoticeProcessor(m_conn, inert_notice_processor, nullptr);
+}
+
+
+void pqxx::connection_base::set_notice_processor()
+{
+ PQsetNoticeProcessor(m_conn, pqxx_notice_processor, this);
+}
+
+
+void pqxx::connection_base::register_errorhandler(errorhandler *handler)
+{
+ // Set notice processor on demand, i.e. only when the caller actually
+ // registers an error handler.
+ // We do this just to make it less likely that users fall into the trap
+ // where a result object may hold a notice processor derived from its parent
+ // connection which has already been destroyed. Our notice processor goes
+ // through the connection's list of error handlers. If the connection object
+ // has already been destroyed though, that list no longer exists.
+ // By setting the notice processor on demand, we absolve users who never
+ // register an error handler from ahving to care about this nasty subtlety.
+ if (m_errorhandlers.empty()) set_notice_processor();
+ m_errorhandlers.push_back(handler);
+}
+
+
+void pqxx::connection_base::unregister_errorhandler(errorhandler *handler)
+ noexcept
+{
+ // The errorhandler itself will take care of nulling its pointer to this
+ // connection.
+ m_errorhandlers.remove(handler);
+ if (m_errorhandlers.empty()) clear_notice_processor();
+}
+
+
+std::vector<errorhandler *> pqxx::connection_base::get_errorhandlers() const
+{
+ return std::vector<errorhandler *>{
+ std::begin(m_errorhandlers), std::end(m_errorhandlers)};
+}
+
+
+pqxx::result pqxx::connection_base::exec(const char Query[], int Retries)
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+
+ auto R = make_result(PQexec(m_conn, Query), Query);
+
+ while ((Retries > 0) and not gate::result_connection{R} and not is_open())
+ {
+ Retries--;
+ reset();
+ if (is_open()) R = make_result(PQexec(m_conn, Query), Query);
+ }
+
+ check_result(R);
+
+ get_notifs();
+ return R;
+}
+
+
+void pqxx::connection_base::prepare(
+ const std::string &name,
+ const std::string &definition)
+{
+ auto i = m_prepared.find(name);
+ if (i != m_prepared.end())
+ {
+ if (definition != i->second.definition)
+ {
+ if (not name.empty())
+ throw argument_error{
+ "Inconsistent redefinition of prepared statement " + name};
+
+ i->second.registered = false;
+ i->second.definition = definition;
+ }
+ }
+ else
+ {
+ m_prepared.insert(make_pair(
+ name,
+ prepare::internal::prepared_def{definition}));
+ }
+}
+
+
+void pqxx::connection_base::prepare(const std::string &definition)
+{
+ this->prepare(std::string{}, definition);
+}
+
+
+void pqxx::connection_base::unprepare(const std::string &name)
+{
+ auto i = m_prepared.find(name);
+
+ // Quietly ignore duplicated or spurious unprepare()s
+ if (i == m_prepared.end()) return;
+
+ if (i->second.registered)
+ exec(("DEALLOCATE " + quote_name(name)).c_str(), 0);
+
+ m_prepared.erase(i);
+}
+
+
+pqxx::prepare::internal::prepared_def &
+pqxx::connection_base::find_prepared(const std::string &statement)
+{
+ auto s = m_prepared.find(statement);
+ if (s == m_prepared.end())
+ throw argument_error{"Unknown prepared statement '" + statement + "'"};
+ return s->second;
+}
+
+
+pqxx::prepare::internal::prepared_def &
+pqxx::connection_base::register_prepared(const std::string &name)
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ auto &s = find_prepared(name);
+
+ // "Register" (i.e., define) prepared statement with backend on demand
+ if (not s.registered)
+ {
+ auto r = make_result(
+ PQprepare(m_conn, name.c_str(), s.definition.c_str(), 0, nullptr),
+ "[PREPARE " + name + "]");
+ check_result(r);
+ s.registered = not name.empty();
+ return s;
+ }
+
+ return s;
+}
+
+
+void pqxx::connection_base::prepare_now(const std::string &name)
+{
+ register_prepared(name);
+}
+
+
+pqxx::result pqxx::connection_base::prepared_exec(
+ const std::string &statement,
+ const char *const params[],
+ const int paramlengths[],
+ const int binary[],
+ int nparams,
+ result_format format)
+{
+ register_prepared(statement);
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ auto r = make_result(
+ PQexecPrepared(
+ m_conn,
+ statement.c_str(),
+ nparams,
+ params,
+ paramlengths,
+ binary,
+ format == result_format::binary? 1 : 0),
+ statement);
+ check_result(r);
+ get_notifs();
+ return r;
+}
+
+
+pqxx::result pqxx::connection_base::exec_prepared(
+ const std::string &statement,
+ const internal::params &args,
+ result_format format)
+{
+ register_prepared(statement);
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ const auto pointers = args.get_pointers();
+ const auto pq_result = PQexecPrepared(
+ m_conn,
+ statement.c_str(),
+ int(args.nonnulls.size()),
+ pointers.data(),
+ args.lengths.data(),
+ args.binaries.data(),
+ format == result_format::binary? 1 : 0);
+ const auto r = make_result(pq_result, statement);
+ check_result(r);
+ get_notifs();
+ return r;
+}
+
+
+bool pqxx::connection_base::prepared_exists(const std::string &statement) const
+{
+ auto s = m_prepared.find(statement);
+ return s != PSMap::const_iterator(m_prepared.end());
+}
+
+
+void pqxx::connection_base::reset()
+{
+ if (m_inhibit_reactivation)
+ throw broken_connection{
+ "Could not reset connection: reactivation is inhibited"};
+ if (m_reactivation_avoidance.get()) return;
+
+ // TODO: Probably need to go through a full disconnect/reconnect!
+ // Forget about any previously ongoing connection attempts
+ m_conn = m_policy.do_dropconnect(m_conn);
+ m_completed = false;
+
+ if (m_conn)
+ {
+ // Reset existing connection
+ PQreset(m_conn);
+ set_up_state();
+ }
+ else
+ {
+ // No existing connection--start a new one
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ }
+}
+
+
+void pqxx::connection_base::close() noexcept
+{
+ m_completed = false;
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ inhibit_reactivation(false);
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ m_reactivation_avoidance.clear();
+ try
+ {
+ if (m_trans.get())
+ process_notice(
+ "Closing connection while " + m_trans.get()->description() +
+ " still open");
+
+ if (not m_receivers.empty())
+ {
+ process_notice("Closing connection with outstanding receivers.");
+ m_receivers.clear();
+ }
+
+ std::list<errorhandler *> old_handlers;
+ m_errorhandlers.swap(old_handlers);
+ const auto
+ rbegin = old_handlers.crbegin(),
+ rend = old_handlers.crend();
+ for (auto i = rbegin; i!=rend; ++i)
+ gate::errorhandler_connection_base{**i}.unregister();
+
+ m_conn = m_policy.do_disconnect(m_conn);
+ }
+ catch (...)
+ {
+ }
+}
+
+
+void pqxx::connection_base::raw_set_var(
+ const std::string &Var,
+ const std::string &Value)
+{
+ exec(("SET " + Var + "=" + Value).c_str(), 0);
+}
+
+
+void pqxx::connection_base::add_variables(
+ const std::map<std::string,std::string> &Vars)
+{
+ for (auto &i: Vars) m_vars[i.first] = i.second;
+}
+
+
+void pqxx::connection_base::internal_set_trace() noexcept
+{
+ if (m_conn)
+ {
+ if (m_trace) PQtrace(m_conn, m_trace);
+ else PQuntrace(m_conn);
+ }
+}
+
+
+int pqxx::connection_base::status() const noexcept
+{
+ return PQstatus(m_conn);
+}
+
+
+void pqxx::connection_base::register_transaction(transaction_base *T)
+{
+ m_trans.register_guest(T);
+}
+
+
+void pqxx::connection_base::unregister_transaction(transaction_base *T)
+ noexcept
+{
+ try
+ {
+ m_trans.unregister_guest(T);
+ }
+ catch (const std::exception &e)
+ {
+ process_notice(e.what());
+ }
+}
+
+
+bool pqxx::connection_base::read_copy_line(std::string &Line)
+{
+ if (not is_open())
+ throw internal_error{"read_copy_line() without connection"};
+
+ Line.erase();
+ bool Result;
+
+ char *Buf = nullptr;
+ const std::string query = "[END COPY]";
+ const auto line_len = PQgetCopyData(m_conn, &Buf, false);
+ switch (line_len)
+ {
+ case -2:
+ throw failure{"Reading of table data failed: " + std::string{err_msg()}};
+
+ case -1:
+ for (
+ auto R = make_result(PQgetResult(m_conn), query);
+ gate::result_connection(R);
+ R=make_result(PQgetResult(m_conn), query)
+ )
+ check_result(R);
+ Result = false;
+ break;
+
+ case 0:
+ throw internal_error{"table read inexplicably went asynchronous"};
+
+ default:
+ if (Buf)
+ {
+ std::unique_ptr<char, void (*)(char *)> PQA(
+ Buf, freepqmem_templated<char>);
+ Line.assign(Buf, unsigned(line_len));
+ }
+ Result = true;
+ }
+
+ return Result;
+}
+
+
+void pqxx::connection_base::write_copy_line(const std::string &Line)
+{
+ if (not is_open())
+ throw internal_error{"write_copy_line() without connection"};
+
+ const std::string L = Line + '\n';
+ const char *const LC = L.c_str();
+ const auto Len = L.size();
+
+ if (PQputCopyData(m_conn, LC, int(Len)) <= 0)
+ {
+ const std::string msg = (
+ std::string{"Error writing to table: "} + err_msg());
+// TODO: PQendcopy() is documented as obsolete!
+ PQendcopy(m_conn);
+ throw failure{msg};
+ }
+}
+
+
+void pqxx::connection_base::end_copy_write()
+{
+ int Res = PQputCopyEnd(m_conn, nullptr);
+ switch (Res)
+ {
+ case -1:
+ throw failure{"Write to table failed: " + std::string{err_msg()}};
+ case 0:
+ throw internal_error{"table write is inexplicably asynchronous"};
+ case 1:
+ // Normal termination. Retrieve result object.
+ break;
+
+ default:
+ throw internal_error{
+ "unexpected result " + to_string(Res) + " from PQputCopyEnd()"};
+ }
+
+ check_result(make_result(PQgetResult(m_conn), "[END COPY]"));
+}
+
+
+void pqxx::connection_base::start_exec(const std::string &Q)
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ if (PQsendQuery(m_conn, Q.c_str()) == 0) throw failure{err_msg()};
+}
+
+
+pqxx::internal::pq::PGresult *pqxx::connection_base::get_result()
+{
+ if (m_conn == nullptr) throw broken_connection{};
+ return PQgetResult(m_conn);
+}
+
+
+void pqxx::connection_base::add_reactivation_avoidance_count(int n)
+{
+ m_reactivation_avoidance.add(n);
+}
+
+
+std::string pqxx::connection_base::esc(const char str[], size_t maxlen)
+{
+ // We need a connection object... This is the one reason why this function is
+ // not const!
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ if (m_conn == nullptr) activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+
+ std::vector<char> buf(2 * maxlen + 1);
+ int err = 0;
+ // TODO: Can we make a callback-based string_view alternative to this?
+ // TODO: If we can, then quote() can wrap PQescapeLiteral()!
+ PQescapeStringConn(m_conn, buf.data(), str, maxlen, &err);
+ if (err) throw argument_error{err_msg()};
+ return std::string{buf.data()};
+}
+
+
+std::string pqxx::connection_base::esc(const char str[])
+{
+ return this->esc(str, strlen(str));
+}
+
+
+std::string pqxx::connection_base::esc(const std::string &str)
+{
+ return this->esc(str.c_str(), str.size());
+}
+
+
+std::string pqxx::connection_base::esc_raw(
+ const unsigned char str[],
+ size_t len)
+{
+ size_t bytes = 0;
+ // We need a connection object... This is the one reason why this function is
+ // not const!
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+
+ std::unique_ptr<unsigned char, void (*)(unsigned char *)> buf{
+ PQescapeByteaConn(m_conn, str, len, &bytes),
+ freepqmem_templated<unsigned char>};
+ if (buf.get() == nullptr) throw std::bad_alloc{};
+ return std::string{reinterpret_cast<char *>(buf.get())};
+}
+
+
+std::string pqxx::connection_base::unesc_raw(const char *text)
+{
+ size_t len;
+ unsigned char *bytes = const_cast<unsigned char *>(
+ reinterpret_cast<const unsigned char *>(text));
+ const std::unique_ptr<unsigned char, decltype(internal::freepqmem)*> ptr{
+ PQunescapeBytea(bytes, &len),
+ internal::freepqmem};
+ return std::string{ptr.get(), ptr.get() + len};
+}
+
+
+std::string pqxx::connection_base::quote_raw(
+ const unsigned char str[],
+ size_t len)
+{
+ return "'" + esc_raw(str, len) + "'::bytea";
+}
+
+
+std::string pqxx::connection_base::quote(const binarystring &b)
+{
+ return quote_raw(b.data(), b.size());
+}
+
+
+std::string pqxx::connection_base::quote_name(const std::string &identifier)
+{
+ // We need a connection object... This is the one reason why this function is
+ // not const!
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ std::unique_ptr<char, void (*)(char *)> buf{
+ PQescapeIdentifier(m_conn, identifier.c_str(), identifier.size()),
+ freepqmem_templated<char>};
+ if (buf.get() == nullptr) throw failure{err_msg()};
+ return std::string{buf.get()};
+}
+
+
+std::string pqxx::connection_base::esc_like(
+ const std::string &str,
+ char escape_char) const
+{
+ std::string out;
+ out.reserve(str.size());
+ internal::for_glyphs(
+ internal::enc_group(encoding_id()),
+ [&out, escape_char](const char *gbegin, const char *gend)
+ {
+ if ((gend - gbegin == 1) and (*gbegin == '_' or *gbegin == '%'))
+ out.push_back(escape_char);
+
+ for (; gbegin != gend; ++gbegin) out.push_back(*gbegin);
+ },
+ str.c_str(),
+ str.size());
+ return out;
+}
+
+
+pqxx::internal::reactivation_avoidance_exemption::
+ reactivation_avoidance_exemption(
+ connection_base &C) :
+ m_home{C},
+ m_count{gate::connection_reactivation_avoidance_exemption(C).get_counter()},
+ m_open{C.is_open()}
+{
+ gate::connection_reactivation_avoidance_exemption gate{C};
+ gate.clear_counter();
+}
+
+
+pqxx::internal::reactivation_avoidance_exemption::
+ ~reactivation_avoidance_exemption()
+{
+ // Don't leave the connection open if reactivation avoidance is in effect and
+ // the connection needed to be reactivated temporarily.
+ if (m_count and not m_open)
+ {
+#include "pqxx/internal/ignore-deprecated-pre.hxx"
+ m_home.deactivate();
+#include "pqxx/internal/ignore-deprecated-post.hxx"
+ }
+ gate::connection_reactivation_avoidance_exemption gate{m_home};
+ gate.add_counter(m_count);
+}
+
+
+namespace
+{
+#if defined(_WIN32) || defined(HAVE_POLL)
+// Convert a timeval to milliseconds, or -1 if no timeval is given.
+inline int tv_milliseconds(timeval *tv = nullptr)
+{
+ return tv ? int(tv->tv_sec * 1000 + tv->tv_usec/1000) : -1;
+}
+#endif
+
+
+/// Wait for an fd to become free for reading/writing. Optional timeout.
+void wait_fd(int fd, bool forwrite=false, timeval *tv=nullptr)
+{
+ if (fd < 0) throw pqxx::broken_connection{};
+
+// WSAPoll is available in winsock2.h only for versions of Windows >= 0x0600
+#if defined(_WIN32) && (_WIN32_WINNT >= 0x0600)
+ const short events = (forwrite ? POLLWRNORM : POLLRDNORM);
+ WSAPOLLFD fdarray{SOCKET(fd), events, 0};
+ WSAPoll(&fdarray, 1, tv_milliseconds(tv));
+#elif defined(HAVE_POLL)
+ const short events = short(
+ POLLERR|POLLHUP|POLLNVAL | (forwrite?POLLOUT:POLLIN));
+ pollfd pfd{fd, events, 0};
+ poll(&pfd, 1, tv_milliseconds(tv));
+#else
+ // No poll()? Our last option is select().
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ if (not forwrite) FD_SET(fd, &read_fds);
+
+ fd_set write_fds;
+ FD_ZERO(&write_fds);
+ if (forwrite) FD_SET(fd, &write_fds);
+
+ fd_set except_fds;
+ FD_ZERO(&except_fds);
+ FD_SET(fd, &except_fds);
+
+ select(fd+1, &read_fds, &write_fds, &except_fds, tv);
+#endif
+
+ // No need to report errors. The caller will try to use the file
+ // descriptor right after we return, so if the file descriptor is broken,
+ // the caller will notice soon enough.
+}
+} // namespace
+
+void pqxx::internal::wait_read(const internal::pq::PGconn *c)
+{
+ wait_fd(socket_of(c));
+}
+
+
+void pqxx::internal::wait_read(
+ const internal::pq::PGconn *c,
+ long seconds,
+ long microseconds)
+{
+ // These are really supposed to be time_t and suseconds_t. But not all
+ // platforms have that type; some use "long" instead, and some 64-bit
+ // systems use 32-bit integers here. So "int" seems to be the only really
+ // safe type to use.
+ timeval tv = { time_t(seconds), int(microseconds) };
+ wait_fd(socket_of(c), false, &tv);
+}
+
+
+void pqxx::internal::wait_write(const internal::pq::PGconn *c)
+{
+ wait_fd(socket_of(c), true);
+}
+
+
+void pqxx::connection_base::wait_read() const
+{
+ internal::wait_read(m_conn);
+}
+
+
+void pqxx::connection_base::wait_read(long seconds, long microseconds) const
+{
+ internal::wait_read(m_conn, seconds, microseconds);
+}
+
+
+void pqxx::connection_base::wait_write() const
+{
+ internal::wait_write(m_conn);
+}
+
+
+int pqxx::connection_base::await_notification()
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ int notifs = get_notifs();
+ if (notifs == 0)
+ {
+ wait_read();
+ notifs = get_notifs();
+ }
+ return notifs;
+}
+
+
+int pqxx::connection_base::await_notification(long seconds, long microseconds)
+{
+#include <pqxx/internal/ignore-deprecated-pre.hxx>
+ activate();
+#include <pqxx/internal/ignore-deprecated-post.hxx>
+ int notifs = get_notifs();
+ if (notifs == 0)
+ {
+ wait_read(seconds, microseconds);
+ notifs = get_notifs();
+ }
+ return notifs;
+}
+
+
+void pqxx::connection_base::read_capabilities()
+{
+ m_serverversion = PQserverVersion(m_conn);
+ if (m_serverversion <= 90000)
+ throw feature_not_supported{
+ "Unsupported server version; 9.0 is the minimum."};
+
+ switch (protocol_version()) {
+ case 0:
+ throw broken_connection{};
+ case 1:
+ case 2:
+ throw feature_not_supported{
+ "Unsupported frontend/backend protocol version; 3.0 is the minimum."};
+ default:
+ break;
+ }
+
+ // TODO: Check for capabilities here. Currently don't need any checks.
+}
+
+
+std::string pqxx::connection_base::adorn_name(const std::string &n)
+{
+ const std::string id = to_string(++m_unique_id);
+ return n.empty() ? ("x"+id) : (n+"_"+id);
+}
+
+
+std::string pqxx::connection_base::get_client_encoding() const
+{
+ return internal::name_encoding(encoding_id());
+}
+
+
+void pqxx::connection_base::set_client_encoding(const char encoding[])
+{
+ const auto retval = PQsetClientEncoding(m_conn, encoding);
+ switch (retval)
+ {
+ case 0:
+ // OK.
+ break;
+ case -1:
+ // TODO: Any helpful information we could give here?
+ throw failure{"Setting client encoding failed."};
+ default:
+ throw internal_error{
+ "Unexpected result from PQsetClientEncoding: " + to_string(retval)};
+ }
+}
+
+
+void pqxx::connection_base::set_client_encoding(const std::string &encoding)
+{
+ set_client_encoding(encoding.c_str());
+}
+
+
+int pqxx::connection_base::encoding_id() const
+{
+ const int enc = PQclientEncoding(m_conn);
+ if (enc == -1)
+ {
+ if (not is_open())
+ throw broken_connection{
+ "Could not obtain client encoding: not connected."};
+ throw failure{"Could not obtain client encoding."};
+ }
+ return enc;
+}
+
+
+pqxx::result pqxx::connection_base::parameterized_exec(
+ const std::string &query,
+ const char *const params[],
+ const int paramlengths[],
+ const int binaries[],
+ int nparams)
+{
+ auto r = make_result(
+ PQexecParams(
+ m_conn,
+ query.c_str(),
+ nparams,
+ nullptr,
+ params,
+ paramlengths,
+ binaries,
+ 0),
+ query);
+ check_result(r);
+ get_notifs();
+ return r;
+}
+
+
+pqxx::result pqxx::connection_base::exec_params(
+ const std::string &query,
+ const internal::params &args)
+{
+ const auto pointers = args.get_pointers();
+ const auto pq_result = PQexecParams(
+ m_conn,
+ query.c_str(),
+ int(args.nonnulls.size()),
+ nullptr,
+ pointers.data(),
+ args.lengths.data(),
+ args.binaries.data(),
+ 0);
+ const auto r = make_result(pq_result, query);
+ check_result(r);
+ get_notifs();
+ return r;
+}
diff --git a/contrib/libs/libpqxx/src/cursor.cxx b/contrib/libs/libpqxx/src/cursor.cxx
new file mode 100644
index 0000000000..8d2c7dfb25
--- /dev/null
+++ b/contrib/libs/libpqxx/src/cursor.cxx
@@ -0,0 +1,321 @@
+/** Implementation of libpqxx STL-style cursor classes.
+ *
+ * These classes wrap SQL cursors in STL-like interfaces.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <iterator>
+
+#include "pqxx/cursor"
+#include "pqxx/result"
+#include "pqxx/strconv"
+#include "pqxx/transaction"
+
+#include "pqxx/internal/gates/icursor_iterator-icursorstream.hxx"
+#include "pqxx/internal/gates/icursorstream-icursor_iterator.hxx"
+
+using namespace pqxx;
+using namespace pqxx::internal;
+
+
+pqxx::cursor_base::difference_type pqxx::cursor_base::all() noexcept
+{
+ // Implemented out-of-line so we don't fall afoul of Visual Studio defining
+ // min() and max() macros, which turn this expression into malformed code:
+ return std::numeric_limits<int>::max() - 1;
+}
+
+
+pqxx::cursor_base::difference_type cursor_base::backward_all() noexcept
+{
+ // Implemented out-of-line so we don't fall afoul of Visual Studio defining
+ // min() and max() macros, which turn this expression into malformed code:
+ return std::numeric_limits<int>::min() + 1;
+}
+
+
+pqxx::cursor_base::cursor_base(
+ connection_base &context,
+ const std::string &Name,
+ bool embellish_name) :
+ m_name{embellish_name ? context.adorn_name(Name) : Name}
+{
+}
+
+
+result::size_type pqxx::internal::obtain_stateless_cursor_size(sql_cursor &cur)
+{
+ if (cur.endpos() == -1) cur.move(cursor_base::all());
+ return result::size_type(cur.endpos() - 1);
+}
+
+
+result pqxx::internal::stateless_cursor_retrieve(
+ sql_cursor &cur,
+ result::difference_type size,
+ result::difference_type begin_pos,
+ result::difference_type end_pos)
+{
+ if (begin_pos < 0 or begin_pos > size)
+ throw range_error{"Starting position out of range"};
+
+ if (end_pos < -1) end_pos = -1;
+ else if (end_pos > size) end_pos = size;
+
+ if (begin_pos == end_pos) return cur.empty_result();
+
+ const int direction = ((begin_pos < end_pos) ? 1 : -1);
+ cur.move((begin_pos-direction) - (cur.pos()-1));
+ return cur.fetch(end_pos - begin_pos);
+}
+
+
+pqxx::icursorstream::icursorstream(
+ transaction_base &context,
+ const std::string &query,
+ const std::string &basename,
+ difference_type sstride) :
+ m_cur{context,
+ query,
+ basename,
+ cursor_base::forward_only,
+ cursor_base::read_only,
+ cursor_base::owned,
+ false},
+ m_stride{sstride},
+ m_realpos{0},
+ m_reqpos{0},
+ m_iterators{nullptr},
+ m_done{false}
+{
+ set_stride(sstride);
+}
+
+
+pqxx::icursorstream::icursorstream(
+ transaction_base &context,
+ const field &cname,
+ difference_type sstride,
+ cursor_base::ownershippolicy op) :
+ m_cur{context, cname.c_str(), op},
+ m_stride{sstride},
+ m_realpos{0},
+ m_reqpos{0},
+ m_iterators{nullptr},
+ m_done{false}
+{
+ set_stride(sstride);
+}
+
+
+void pqxx::icursorstream::set_stride(difference_type n)
+{
+ if (n < 1)
+ throw argument_error{"Attempt to set cursor stride to " + to_string(n)};
+ m_stride = n;
+}
+
+result pqxx::icursorstream::fetchblock()
+{
+ const result r{m_cur.fetch(m_stride)};
+ m_realpos += r.size();
+ if (r.empty()) m_done = true;
+ return r;
+}
+
+
+icursorstream &pqxx::icursorstream::ignore(std::streamsize n)
+{
+ auto offset = m_cur.move(difference_type(n));
+ m_realpos += offset;
+ if (offset < n) m_done = true;
+ return *this;
+}
+
+
+icursorstream::size_type pqxx::icursorstream::forward(size_type n)
+{
+ m_reqpos += difference_type(n) * m_stride;
+ return icursorstream::size_type(m_reqpos);
+}
+
+
+void pqxx::icursorstream::insert_iterator(icursor_iterator *i) noexcept
+{
+ gate::icursor_iterator_icursorstream{*i}.set_next(m_iterators);
+ if (m_iterators)
+ gate::icursor_iterator_icursorstream{*m_iterators}.set_prev(i);
+ m_iterators = i;
+}
+
+
+void pqxx::icursorstream::remove_iterator(icursor_iterator *i) const noexcept
+{
+ gate::icursor_iterator_icursorstream igate{*i};
+ if (i == m_iterators)
+ {
+ m_iterators = igate.get_next();
+ if (m_iterators)
+ gate::icursor_iterator_icursorstream{*m_iterators}.set_prev(nullptr);
+ }
+ else
+ {
+ auto prev = igate.get_prev(), next = igate.get_next();
+ gate::icursor_iterator_icursorstream{*prev}.set_next(next);
+ if (next) gate::icursor_iterator_icursorstream{*next}.set_prev(prev);
+ }
+ igate.set_prev(nullptr);
+ igate.set_next(nullptr);
+}
+
+
+void pqxx::icursorstream::service_iterators(difference_type topos)
+{
+ if (topos < m_realpos) return;
+
+ using todolist = std::multimap<difference_type,icursor_iterator*>;
+ todolist todo;
+ for (icursor_iterator *i = m_iterators, *next; i; i = next)
+ {
+ gate::icursor_iterator_icursorstream gate{*i};
+ const auto ipos = gate.pos();
+ if (ipos >= m_realpos and ipos <= topos)
+ todo.insert(todolist::value_type(ipos, i));
+ next = gate.get_next();
+ }
+ const auto todo_end = std::end(todo);
+ for (auto i = std::begin(todo); i != todo_end; )
+ {
+ const auto readpos = i->first;
+ if (readpos > m_realpos) ignore(readpos - m_realpos);
+ const result r = fetchblock();
+ for ( ; i != todo_end and i->first == readpos; ++i)
+ gate::icursor_iterator_icursorstream{*i->second}.fill(r);
+ }
+}
+
+
+pqxx::icursor_iterator::icursor_iterator() noexcept :
+ m_pos{0}
+{
+}
+
+
+pqxx::icursor_iterator::icursor_iterator(istream_type &s) noexcept :
+ m_stream{&s},
+ m_pos{difference_type(gate::icursorstream_icursor_iterator(s).forward(0))}
+{
+ gate::icursorstream_icursor_iterator{*m_stream}.insert_iterator(this);
+}
+
+
+pqxx::icursor_iterator::icursor_iterator(const icursor_iterator &rhs)
+ noexcept :
+ m_stream{rhs.m_stream},
+ m_here{rhs.m_here},
+ m_pos{rhs.m_pos}
+{
+ if (m_stream)
+ gate::icursorstream_icursor_iterator{*m_stream}.insert_iterator(this);
+}
+
+
+pqxx::icursor_iterator::~icursor_iterator() noexcept
+{
+ if (m_stream)
+ gate::icursorstream_icursor_iterator{*m_stream}.remove_iterator(this);
+}
+
+
+icursor_iterator pqxx::icursor_iterator::operator++(int)
+{
+ icursor_iterator old{*this};
+ m_pos = difference_type(
+ gate::icursorstream_icursor_iterator{*m_stream}.forward());
+ m_here.clear();
+ return old;
+}
+
+
+icursor_iterator &pqxx::icursor_iterator::operator++()
+{
+ m_pos = difference_type(
+ gate::icursorstream_icursor_iterator{*m_stream}.forward());
+ m_here.clear();
+ return *this;
+}
+
+
+icursor_iterator &pqxx::icursor_iterator::operator+=(difference_type n)
+{
+ if (n <= 0)
+ {
+ if (n == 0) return *this;
+ throw argument_error{"Advancing icursor_iterator by negative offset."};
+ }
+ m_pos = difference_type(
+ gate::icursorstream_icursor_iterator{*m_stream}.forward(
+ icursorstream::size_type(n)));
+ m_here.clear();
+ return *this;
+}
+
+
+icursor_iterator &
+pqxx::icursor_iterator::operator=(const icursor_iterator &rhs) noexcept
+{
+ if (rhs.m_stream == m_stream)
+ {
+ m_here = rhs.m_here;
+ m_pos = rhs.m_pos;
+ }
+ else
+ {
+ if (m_stream)
+ gate::icursorstream_icursor_iterator{*m_stream}.remove_iterator(this);
+ m_here = rhs.m_here;
+ m_pos = rhs.m_pos;
+ m_stream = rhs.m_stream;
+ if (m_stream)
+ gate::icursorstream_icursor_iterator{*m_stream}.insert_iterator(this);
+ }
+ return *this;
+}
+
+
+bool pqxx::icursor_iterator::operator==(const icursor_iterator &rhs) const
+{
+ if (m_stream == rhs.m_stream) return pos() == rhs.pos();
+ if (m_stream and rhs.m_stream) return false;
+ refresh();
+ rhs.refresh();
+ return m_here.empty() and rhs.m_here.empty();
+}
+
+
+bool pqxx::icursor_iterator::operator<(const icursor_iterator &rhs) const
+{
+ if (m_stream == rhs.m_stream) return pos() < rhs.pos();
+ refresh();
+ rhs.refresh();
+ return not m_here.empty();
+}
+
+
+void pqxx::icursor_iterator::refresh() const
+{
+ if (m_stream)
+ gate::icursorstream_icursor_iterator{*m_stream}.service_iterators(pos());
+}
+
+
+void pqxx::icursor_iterator::fill(const result &r)
+{
+ m_here = r;
+}
diff --git a/contrib/libs/libpqxx/src/dbtransaction.cxx b/contrib/libs/libpqxx/src/dbtransaction.cxx
new file mode 100644
index 0000000000..9d0938a181
--- /dev/null
+++ b/contrib/libs/libpqxx/src/dbtransaction.cxx
@@ -0,0 +1,99 @@
+/** Implementation of the pqxx::dbtransaction class.
+ *
+ * pqxx::dbtransaction represents a real backend transaction.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/dbtransaction"
+
+#include "pqxx/internal/gates/connection-dbtransaction.hxx"
+
+using namespace pqxx::internal;
+
+
+namespace
+{
+std::string generate_set_transaction(
+ pqxx::readwrite_policy rw,
+ const std::string &IsolationString=std::string{})
+{
+ std::string args;
+
+ if (not IsolationString.empty())
+ if (IsolationString != pqxx::isolation_traits<pqxx::read_committed>::name())
+ args += " ISOLATION LEVEL " + IsolationString;
+
+ if (rw != pqxx::read_write) args += " READ ONLY";
+
+ return args.empty() ? "BEGIN" : ("BEGIN; SET TRANSACTION" + args);
+}
+} // namespace
+
+
+pqxx::dbtransaction::dbtransaction(
+ connection_base &C,
+ const std::string &IsolationString,
+ readwrite_policy rw) :
+ namedclass{"dbtransaction"},
+ transaction_base{C},
+ m_start_cmd{generate_set_transaction(rw, IsolationString)}
+{
+}
+
+
+pqxx::dbtransaction::dbtransaction(
+ connection_base &C,
+ bool direct,
+ readwrite_policy rw) :
+ namedclass{"dbtransaction"},
+ transaction_base(C, direct),
+ m_start_cmd{generate_set_transaction(rw)}
+{
+}
+
+
+pqxx::dbtransaction::~dbtransaction()
+{
+}
+
+
+void pqxx::dbtransaction::do_begin()
+{
+ const gate::connection_dbtransaction gate(conn());
+ const int avoidance_counter = gate.get_reactivation_avoidance_count();
+ direct_exec(m_start_cmd.c_str(), avoidance_counter ? 0 : 2);
+}
+
+
+pqxx::result pqxx::dbtransaction::do_exec(const char Query[])
+{
+ try
+ {
+ return direct_exec(Query);
+ }
+ catch (const std::exception &)
+ {
+ try { abort(); } catch (const std::exception &) {}
+ throw;
+ }
+}
+
+
+void pqxx::dbtransaction::do_abort()
+{
+ reactivation_avoidance_clear();
+ direct_exec("ROLLBACK");
+}
+
+
+std::string pqxx::dbtransaction::fullname(const std::string &ttype,
+ const std::string &isolation)
+{
+ return ttype + "<" + isolation + ">";
+}
diff --git a/contrib/libs/libpqxx/src/encodings.cxx b/contrib/libs/libpqxx/src/encodings.cxx
new file mode 100644
index 0000000000..7102c891c4
--- /dev/null
+++ b/contrib/libs/libpqxx/src/encodings.cxx
@@ -0,0 +1,826 @@
+/** Implementation of string encodings support
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/except.hxx"
+#include "pqxx/internal/encodings.hxx"
+
+#include <cstring>
+#include <iomanip>
+#include <map>
+#include <sstream>
+
+using namespace pqxx::internal;
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+
+// Internal helper functions
+namespace
+{
+/// Extract byte from buffer, return as unsigned char.
+unsigned char get_byte(const char buffer[], std::string::size_type offset)
+{
+ return static_cast<unsigned char>(buffer[offset]);
+}
+
+
+[[noreturn]] void throw_for_encoding_error(
+ const char* encoding_name,
+ const char buffer[],
+ std::string::size_type start,
+ std::string::size_type count
+)
+{
+ std::stringstream s;
+ s
+ << "Invalid byte sequence for encoding "
+ << encoding_name
+ << " at byte "
+ << start
+ << ": "
+ << std::hex
+ << std::setw(2)
+ << std::setfill('0')
+ ;
+ for (std::string::size_type i{0}; i < count; ++i)
+ {
+ s << "0x" << static_cast<unsigned int>(get_byte(buffer, start + i));
+ if (i + 1 < count) s << " ";
+ }
+ throw pqxx::argument_error{s.str()};
+}
+
+
+/// Does value lie between bottom and top, inclusive?
+constexpr bool between_inc(unsigned char value, unsigned bottom, unsigned top)
+{
+ return value >= bottom and value <= top;
+}
+
+
+/*
+EUC-JP and EUC-JIS-2004 represent slightly different code points but iterate
+the same:
+ * https://en.wikipedia.org/wiki/Extended_Unix_Code#EUC-JP
+ * http://x0213.org/codetable/index.en.html
+*/
+std::string::size_type next_seq_for_euc_jplike(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start,
+ const char encoding_name[])
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error(encoding_name, buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (byte1 == 0x8e)
+ {
+ if (not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error(encoding_name, buffer, start, 2);
+
+ return start + 2;
+ }
+
+ if (between_inc(byte1, 0xa1, 0xfe))
+ {
+ if (not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error(encoding_name, buffer, start, 2);
+
+ return start + 2;
+ }
+
+ if (byte1 == 0x8f and start + 3 <= buffer_len)
+ {
+ const auto byte3 = get_byte(buffer, start + 2);
+ if (
+ not between_inc(byte2, 0xa1, 0xfe) or
+ not between_inc(byte3, 0xa1, 0xfe)
+ )
+ throw_for_encoding_error(encoding_name, buffer, start, 3);
+
+ return start + 3;
+ }
+
+ throw_for_encoding_error(encoding_name, buffer, start, 1);
+}
+
+/*
+As far as I can tell, for the purposes of iterating the only difference between
+SJIS and SJIS-2004 is increased range in the first byte of two-byte sequences
+(0xEF increased to 0xFC). Officially, that is; apparently the version of SJIS
+used by Postgres has the same range as SJIS-2004. They both have increased
+range over the documented versions, not having the even/odd restriction for the
+first byte in 2-byte sequences.
+*/
+// https://en.wikipedia.org/wiki/Shift_JIS#Shift_JIS_byte_map
+// http://x0213.org/codetable/index.en.html
+std::string::size_type next_seq_for_sjislike(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start,
+ const char* encoding_name
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80 or between_inc(byte1, 0xa1, 0xdf)) return start + 1;
+
+ if (
+ not between_inc(byte1, 0x81, 0x9f) and
+ not between_inc(byte1, 0xe0, 0xfc)
+ )
+ throw_for_encoding_error(encoding_name, buffer, start, 1);
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error(
+ encoding_name,
+ buffer,
+ start,
+ buffer_len - start);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (byte2 == 0x7f) throw_for_encoding_error(encoding_name, buffer, start, 2);
+
+ if (between_inc(byte2, 0x40, 0x9e) or between_inc(byte2, 0x9f, 0xfc))
+ return start + 2;
+
+ throw_for_encoding_error(encoding_name, buffer, start, 2);
+}
+} // namespace
+
+
+// Implement template specializations first
+namespace pqxx
+{
+namespace internal
+{
+template<encoding_group> struct glyph_scanner
+{
+ static std::string::size_type call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start);
+};
+
+template<>
+std::string::size_type glyph_scanner<encoding_group::MONOBYTE>::call(
+ const char /* buffer */[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+ else return start + 1;
+}
+
+// https://en.wikipedia.org/wiki/Big5#Organization
+template<> std::string::size_type glyph_scanner<encoding_group::BIG5>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (not between_inc(byte1, 0x81, 0xfe) or (start + 2 > buffer_len))
+ throw_for_encoding_error("BIG5", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (
+ not between_inc(byte2, 0x40, 0x7e) and
+ not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error("BIG5", buffer, start, 2);
+
+ return start + 2;
+}
+
+/*
+The PostgreSQL documentation claims that the EUC_* encodings are 1-3 bytes each,
+but other documents explain that the EUC sets can contain 1-(2,3,4) bytes
+depending on the specific extension:
+ EUC_CN : 1-2
+ EUC_JP : 1-3
+ EUC_JIS_2004: 1-2
+ EUC_KR : 1-2
+ EUC_TW : 1-4
+*/
+
+// https://en.wikipedia.org/wiki/GB_2312#EUC-CN
+template<> std::string::size_type glyph_scanner<encoding_group::EUC_CN>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (not between_inc(byte1, 0xa1, 0xf7) or start + 2 > buffer_len)
+ throw_for_encoding_error("EUC_CN", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error("EUC_CN", buffer, start, 2);
+
+ return start + 2;
+}
+
+template<> std::string::size_type glyph_scanner<encoding_group::EUC_JP>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ return next_seq_for_euc_jplike(buffer, buffer_len, start, "EUC_JP");
+}
+
+template<>
+std::string::size_type glyph_scanner<encoding_group::EUC_JIS_2004>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ return next_seq_for_euc_jplike(buffer, buffer_len, start, "EUC_JIS_2004");
+}
+
+// https://en.wikipedia.org/wiki/Extended_Unix_Code#EUC-KR
+template<> std::string::size_type glyph_scanner<encoding_group::EUC_KR>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (not between_inc(byte1, 0xa1, 0xfe) or start + 2 > buffer_len)
+ throw_for_encoding_error("EUC_KR", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error("EUC_KR", buffer, start, 1);
+
+ return start + 2;
+}
+
+// https://en.wikipedia.org/wiki/Extended_Unix_Code#EUC-TW
+template<> std::string::size_type glyph_scanner<encoding_group::EUC_TW>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("EUC_KR", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (between_inc(byte1, 0xa1, 0xfe))
+ {
+ if (not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error("EUC_KR", buffer, start, 2);
+
+ return start + 2;
+ }
+
+ if (byte1 != 0x8e or start + 4 > buffer_len)
+ throw_for_encoding_error("EUC_KR", buffer, start, 1);
+
+ if (
+ between_inc(byte2, 0xa1, 0xb0) and
+ between_inc(get_byte(buffer, start + 2), 0xa1, 0xfe) and
+ between_inc(get_byte(buffer, start + 3), 0xa1, 0xfe)
+ )
+ return start + 4;
+
+ throw_for_encoding_error("EUC_KR", buffer, start, 4);
+}
+
+// https://en.wikipedia.org/wiki/GB_18030#Mapping
+template<> std::string::size_type glyph_scanner<encoding_group::GB18030>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (between_inc(byte1, 0x80, 0xff)) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("GB18030", buffer, start, buffer_len - start);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (between_inc(byte2, 0x40, 0xfe))
+ {
+ if (byte2 == 0x7f)
+ throw_for_encoding_error("GB18030", buffer, start, 2);
+
+ return start + 2;
+ }
+
+ if (start + 4 > buffer_len)
+ throw_for_encoding_error("GB18030", buffer, start, buffer_len - start);
+
+ if (
+ between_inc(byte2, 0x30, 0x39) and
+ between_inc(get_byte(buffer, start + 2), 0x81, 0xfe) and
+ between_inc(get_byte(buffer, start + 3), 0x30, 0x39)
+ )
+ return start + 4;
+
+ throw_for_encoding_error("GB18030", buffer, start, 4);
+}
+
+// https://en.wikipedia.org/wiki/GBK_(character_encoding)#Encoding
+template<> std::string::size_type glyph_scanner<encoding_group::GBK>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("GBK", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (
+ (between_inc(byte1, 0xa1, 0xa9) and between_inc(byte2, 0xa1, 0xfe))
+ or
+ (between_inc(byte1, 0xb0, 0xf7) and between_inc(byte2, 0xa1, 0xfe))
+ or
+ (
+ between_inc(byte1, 0x81, 0xa0) and
+ between_inc(byte2, 0x40, 0xfe) and
+ byte2 != 0x7f
+ )
+ or
+ (
+ between_inc(byte1, 0xaa, 0xfe) and
+ between_inc(byte2, 0x40, 0xa0) and
+ byte2 != 0x7f
+ )
+ or
+ (
+ between_inc(byte1, 0xa8, 0xa9) and
+ between_inc(byte2, 0x40, 0xa0) and
+ byte2 != 0x7f
+ )
+ or
+ (between_inc(byte1, 0xaa, 0xaf) and between_inc(byte2, 0xa1, 0xfe))
+ or
+ (between_inc(byte1, 0xf8, 0xfe) and between_inc(byte2, 0xa1, 0xfe))
+ or
+ (
+ between_inc(byte1, 0xa1, 0xa7) and
+ between_inc(byte2, 0x40, 0xa0) and
+ byte2 != 0x7f
+ )
+ )
+ return start + 2;
+
+ throw_for_encoding_error("GBK", buffer, start, 2);
+}
+
+/*
+The PostgreSQL documentation claims that the JOHAB encoding is 1-3 bytes, but
+"CJKV Information Processing" describes it (actually just the Hangul portion)
+as "three five-bit segments" that reside inside 16 bits (2 bytes).
+
+CJKV Information Processing by Ken Lunde, pg. 269:
+
+ https://bit.ly/2BEOu5V
+*/
+template<> std::string::size_type glyph_scanner<encoding_group::JOHAB>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("JOHAB", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start);
+ if (
+ (
+ between_inc(byte1, 0x84, 0xd3) and
+ (between_inc(byte2, 0x41, 0x7e) or between_inc(byte2, 0x81, 0xfe))
+ )
+ or
+ (
+ (between_inc(byte1, 0xd8, 0xde) or between_inc(byte1, 0xe0, 0xf9)) and
+ (between_inc(byte2, 0x31, 0x7e) or between_inc(byte2, 0x91, 0xfe))
+ )
+ )
+ return start + 2;
+
+ throw_for_encoding_error("JOHAB", buffer, start, 2);
+}
+
+/*
+PostgreSQL's MULE_INTERNAL is the emacs rather than Xemacs implementation;
+see the server/mb/pg_wchar.h PostgreSQL header file.
+This is implemented according to the description in said header file, but I was
+unable to get it to successfully iterate a MULE-encoded test CSV generated using
+PostgreSQL 9.2.23. Use this at your own risk.
+*/
+template<>
+std::string::size_type glyph_scanner<encoding_group::MULE_INTERNAL>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("MULE_INTERNAL", buffer, start, 1);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (between_inc(byte1, 0x81, 0x8d) and byte2 >= 0xA0)
+ return start + 2;
+
+ if (start + 3 > buffer_len)
+ throw_for_encoding_error("MULE_INTERNAL", buffer, start, 2);
+
+ if (
+ (
+ (byte1 == 0x9A and between_inc(byte2, 0xa0, 0xdf)) or
+ (byte1 == 0x9B and between_inc(byte2, 0xe0, 0xef)) or
+ (between_inc(byte1, 0x90, 0x99) and byte2 >= 0xa0)
+ )
+ and
+ (
+ byte2 >= 0xA0
+ )
+ )
+ return start + 3;
+
+ if (start + 4 > buffer_len)
+ throw_for_encoding_error("MULE_INTERNAL", buffer, start, 3);
+
+ if (
+ (
+ (byte1 == 0x9C and between_inc(byte2, 0xf0, 0xf4)) or
+ (byte1 == 0x9D and between_inc(byte2, 0xf5, 0xfe))
+ )
+ and
+ get_byte(buffer, start + 2) >= 0xa0 and
+ get_byte(buffer, start + 4) >= 0xa0
+ )
+ return start + 4;
+
+ throw_for_encoding_error("MULE_INTERNAL", buffer, start, 4);
+}
+
+template<> std::string::size_type glyph_scanner<encoding_group::SJIS>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ return next_seq_for_sjislike(buffer, buffer_len, start, "SJIS");
+}
+
+template<>
+std::string::size_type glyph_scanner<encoding_group::SHIFT_JIS_2004>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ return next_seq_for_sjislike(buffer, buffer_len, start, "SHIFT_JIS_2004");
+}
+
+// https://en.wikipedia.org/wiki/Unified_Hangul_Code
+template<> std::string::size_type glyph_scanner<encoding_group::UHC>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("UHC", buffer, start, buffer_len - start);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (between_inc(byte1, 0x80, 0xc6))
+ {
+ if (
+ between_inc(byte2, 0x41, 0x5a) or
+ between_inc(byte2, 0x61, 0x7a) or
+ between_inc(byte2, 0x80, 0xfe)
+ )
+ return start + 2;
+
+ throw_for_encoding_error("UHC", buffer, start, 2);
+ }
+
+ if (between_inc(byte1, 0xa1, 0xfe))
+ {
+ if (not between_inc(byte2, 0xa1, 0xfe))
+ throw_for_encoding_error("UHC", buffer, start, 2);
+
+ return start + 2;
+ }
+
+ throw_for_encoding_error("UHC", buffer, start, 1);
+}
+
+// https://en.wikipedia.org/wiki/UTF-8#Description
+template<> std::string::size_type glyph_scanner<encoding_group::UTF8>::call(
+ const char buffer[],
+ std::string::size_type buffer_len,
+ std::string::size_type start
+)
+{
+ if (start >= buffer_len) return std::string::npos;
+
+ const auto byte1 = get_byte(buffer, start);
+ if (byte1 < 0x80) return start + 1;
+
+ if (start + 2 > buffer_len)
+ throw_for_encoding_error("UTF8", buffer, start, buffer_len - start);
+
+ const auto byte2 = get_byte(buffer, start + 1);
+ if (between_inc(byte1, 0xc0, 0xdf))
+ {
+ if (not between_inc(byte2, 0x80, 0xbf))
+ throw_for_encoding_error("UTF8", buffer, start, 2);
+
+ return start + 2;
+ }
+
+ if (start + 3 > buffer_len)
+ throw_for_encoding_error("UTF8", buffer, start, buffer_len - start);
+
+ const auto byte3 = get_byte(buffer, start + 2);
+ if (between_inc(byte1, 0xe0, 0xef))
+ {
+ if (between_inc(byte2, 0x80, 0xbf) and between_inc(byte3, 0x80, 0xbf))
+ return start + 3;
+
+ throw_for_encoding_error("UTF8", buffer, start, 3);
+ }
+
+ if (start + 4 > buffer_len)
+ throw_for_encoding_error("UTF8", buffer, start, buffer_len - start);
+
+ if (between_inc(byte1, 0xf0, 0xf7))
+ {
+ if (
+ between_inc(byte2, 0x80, 0xbf) and
+ between_inc(byte3, 0x80, 0xbf) and
+ between_inc(get_byte(buffer, start + 3), 0x80, 0xbf)
+ )
+ return start + 4;
+
+ throw_for_encoding_error("UTF8", buffer, start, 4);
+ }
+
+ throw_for_encoding_error("UTF8", buffer, start, 1);
+}
+
+
+const char *name_encoding(int encoding_id)
+{
+ return pg_encoding_to_char(encoding_id);
+}
+
+
+encoding_group enc_group(int libpq_enc_id)
+{
+ return enc_group(name_encoding(libpq_enc_id));
+}
+
+
+encoding_group enc_group(const std::string& encoding_name)
+{
+ static const std::map<std::string, encoding_group> encoding_map{
+ {"BIG5", encoding_group::BIG5},
+ {"EUC_CN", encoding_group::EUC_CN},
+ {"EUC_JP", encoding_group::EUC_JP},
+ {"EUC_JIS_2004", encoding_group::EUC_JIS_2004},
+ {"EUC_KR", encoding_group::EUC_KR},
+ {"EUC_TW", encoding_group::EUC_TW},
+ {"GB18030", encoding_group::GB18030},
+ {"GBK", encoding_group::GBK},
+ {"ISO_8859_5", encoding_group::MONOBYTE},
+ {"ISO_8859_6", encoding_group::MONOBYTE},
+ {"ISO_8859_7", encoding_group::MONOBYTE},
+ {"ISO_8859_8", encoding_group::MONOBYTE},
+ {"JOHAB", encoding_group::JOHAB},
+ {"KOI8R", encoding_group::MONOBYTE},
+ {"KOI8U", encoding_group::MONOBYTE},
+ {"LATIN1", encoding_group::MONOBYTE},
+ {"LATIN2", encoding_group::MONOBYTE},
+ {"LATIN3", encoding_group::MONOBYTE},
+ {"LATIN4", encoding_group::MONOBYTE},
+ {"LATIN5", encoding_group::MONOBYTE},
+ {"LATIN6", encoding_group::MONOBYTE},
+ {"LATIN7", encoding_group::MONOBYTE},
+ {"LATIN8", encoding_group::MONOBYTE},
+ {"LATIN9", encoding_group::MONOBYTE},
+ {"LATIN10", encoding_group::MONOBYTE},
+ {"MULE_INTERNAL", encoding_group::MULE_INTERNAL},
+ {"SJIS", encoding_group::SJIS},
+ {"SHIFT_JIS_2004", encoding_group::SHIFT_JIS_2004},
+ {"SQL_ASCII", encoding_group::MONOBYTE},
+ {"UHC", encoding_group::UHC},
+ {"UTF8", encoding_group::UTF8},
+ {"WIN866", encoding_group::MONOBYTE},
+ {"WIN874", encoding_group::MONOBYTE},
+ {"WIN1250", encoding_group::MONOBYTE},
+ {"WIN1251", encoding_group::MONOBYTE},
+ {"WIN1252", encoding_group::MONOBYTE},
+ {"WIN1253", encoding_group::MONOBYTE},
+ {"WIN1254", encoding_group::MONOBYTE},
+ {"WIN1255", encoding_group::MONOBYTE},
+ {"WIN1256", encoding_group::MONOBYTE},
+ {"WIN1257", encoding_group::MONOBYTE},
+ {"WIN1258", encoding_group::MONOBYTE},
+ };
+
+ const auto found_encoding_group = encoding_map.find(encoding_name);
+ if (found_encoding_group == encoding_map.end())
+ throw std::invalid_argument{
+ "unrecognized encoding '" + encoding_name + "'"
+ };
+ return found_encoding_group->second;
+}
+
+
+/// Look up instantiation @c T<enc>::call at runtime.
+/** Here, "T" is a struct template with a static member function "call", whose
+ * type is "F".
+ *
+ * The return value is a pointer to the "call" member function for the
+ * instantiation of T for encoding group enc.
+ */
+template<template<encoding_group> class T, typename F>
+inline F *for_encoding(encoding_group enc)
+{
+
+#define CASE_GROUP(ENC) \
+ case encoding_group::ENC: return T<encoding_group::ENC>::call
+
+ switch (enc)
+ {
+ CASE_GROUP(MONOBYTE);
+ CASE_GROUP(BIG5);
+ CASE_GROUP(EUC_CN);
+ CASE_GROUP(EUC_JP);
+ CASE_GROUP(EUC_JIS_2004);
+ CASE_GROUP(EUC_KR);
+ CASE_GROUP(EUC_TW);
+ CASE_GROUP(GB18030);
+ CASE_GROUP(GBK);
+ CASE_GROUP(JOHAB);
+ CASE_GROUP(MULE_INTERNAL);
+ CASE_GROUP(SJIS);
+ CASE_GROUP(SHIFT_JIS_2004);
+ CASE_GROUP(UHC);
+ CASE_GROUP(UTF8);
+ }
+ throw pqxx::usage_error{
+ "Unsupported encoding group code " + to_string(int(enc)) + "."};
+
+#undef CASE_GROUP
+}
+
+
+glyph_scanner_func *get_glyph_scanner(encoding_group enc)
+{
+ return for_encoding<glyph_scanner, glyph_scanner_func>(enc);
+}
+
+
+template<encoding_group E> struct char_finder
+{
+ static std::string::size_type call(
+ const std::string &haystack,
+ char needle,
+ std::string::size_type start)
+ {
+ const auto buffer = haystack.c_str();
+ const auto size = haystack.size();
+ for (
+ auto here = start;
+ here + 1 <= size;
+ here = glyph_scanner<E>::call(buffer, size, here)
+ )
+ {
+ if (haystack[here] == needle) return here;
+ }
+ return std::string::npos;
+ }
+};
+
+
+template<encoding_group E> struct string_finder
+{
+ static std::string::size_type call(
+ const std::string &haystack,
+ const std::string &needle,
+ std::string::size_type start)
+ {
+ const auto buffer = haystack.c_str();
+ const auto size = haystack.size();
+ const auto needle_size = needle.size();
+ for (
+ auto here = start;
+ here + needle_size <= size;
+ here = glyph_scanner<E>::call(buffer, size, here)
+ )
+ {
+ if (std::memcmp(buffer + here, needle.c_str(), needle_size) == 0)
+ return here;
+ }
+ return std::string::npos;
+ }
+};
+
+
+std::string::size_type find_with_encoding(
+ encoding_group enc,
+ const std::string& haystack,
+ char needle,
+ std::string::size_type start
+)
+{
+ using finder_func =
+ std::string::size_type(
+ const std::string &haystack,
+ char needle,
+ std::string::size_type start);
+ const auto finder = for_encoding<char_finder, finder_func>(enc);
+ return finder(haystack, needle, start);
+}
+
+
+std::string::size_type find_with_encoding(
+ encoding_group enc,
+ const std::string& haystack,
+ const std::string& needle,
+ std::string::size_type start
+)
+{
+ using finder_func =
+ std::string::size_type(
+ const std::string &haystack,
+ const std::string &needle,
+ std::string::size_type start);
+ const auto finder = for_encoding<string_finder, finder_func>(enc);
+ return finder(haystack, needle, start);
+}
+
+#undef DISPATCH_ENCODING_OPERATION
+
+} // namespace pqxx::internal
+} // namespace pqxx
diff --git a/contrib/libs/libpqxx/src/errorhandler.cxx b/contrib/libs/libpqxx/src/errorhandler.cxx
new file mode 100644
index 0000000000..f561746f9e
--- /dev/null
+++ b/contrib/libs/libpqxx/src/errorhandler.cxx
@@ -0,0 +1,44 @@
+/** Implementation of pqxx::errorhandler and helpers.
+ *
+ * pqxx::errorhandler allows programs to receive errors and warnings.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/connection_base"
+#include "pqxx/errorhandler"
+
+#include "pqxx/internal/gates/connection-errorhandler.hxx"
+
+
+using namespace pqxx;
+using namespace pqxx::internal;
+
+
+pqxx::errorhandler::errorhandler(connection_base &conn) :
+ m_home{&conn}
+{
+ gate::connection_errorhandler{*m_home}.register_errorhandler(this);
+}
+
+
+pqxx::errorhandler::~errorhandler()
+{
+ unregister();
+}
+
+
+void pqxx::errorhandler::unregister() noexcept
+{
+ if (m_home != nullptr)
+ {
+ gate::connection_errorhandler connection_gate{*m_home};
+ m_home = nullptr;
+ connection_gate.unregister_errorhandler(this);
+ }
+}
diff --git a/contrib/libs/libpqxx/src/except.cxx b/contrib/libs/libpqxx/src/except.cxx
new file mode 100644
index 0000000000..9dcc8a8201
--- /dev/null
+++ b/contrib/libs/libpqxx/src/except.cxx
@@ -0,0 +1,124 @@
+/** Implementation of libpqxx exception classes.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/except"
+
+
+pqxx::pqxx_exception::~pqxx_exception() noexcept
+{
+}
+
+
+pqxx::failure::failure(const std::string &whatarg) :
+ std::runtime_error{whatarg}
+{
+}
+
+
+pqxx::broken_connection::broken_connection() :
+ failure{"Connection to database failed"}
+{
+}
+
+
+pqxx::broken_connection::broken_connection(const std::string &whatarg) :
+ failure{whatarg}
+{
+}
+
+
+pqxx::sql_error::sql_error(
+ const std::string &whatarg,
+ const std::string &Q,
+ const char sqlstate[]) :
+ failure{whatarg},
+ m_query{Q},
+ m_sqlstate{sqlstate ? sqlstate : ""}
+{
+}
+
+
+pqxx::sql_error::~sql_error() noexcept
+{
+}
+
+
+PQXX_PURE const std::string &pqxx::sql_error::query() const noexcept
+{
+ return m_query;
+}
+
+
+PQXX_PURE const std::string &pqxx::sql_error::sqlstate() const noexcept
+{
+ return m_sqlstate;
+}
+
+
+pqxx::in_doubt_error::in_doubt_error(const std::string &whatarg) :
+ failure{whatarg}
+{
+}
+
+
+pqxx::transaction_rollback::transaction_rollback(const std::string &whatarg) :
+ failure{whatarg}
+{
+}
+
+
+pqxx::serialization_failure::serialization_failure(
+ const std::string &whatarg) :
+ transaction_rollback{whatarg}
+{
+}
+
+
+pqxx::statement_completion_unknown::statement_completion_unknown(
+ const std::string &whatarg) :
+ transaction_rollback{whatarg}
+{
+}
+
+
+pqxx::deadlock_detected::deadlock_detected(const std::string &whatarg) :
+ transaction_rollback{whatarg}
+{
+}
+
+
+pqxx::internal_error::internal_error(const std::string &whatarg) :
+ logic_error{"libpqxx internal error: " + whatarg}
+{
+}
+
+
+pqxx::usage_error::usage_error(const std::string &whatarg) :
+ logic_error{whatarg}
+{
+}
+
+
+pqxx::argument_error::argument_error(const std::string &whatarg) :
+ invalid_argument{whatarg}
+{
+}
+
+
+pqxx::conversion_error::conversion_error(const std::string &whatarg) :
+ domain_error{whatarg}
+{
+}
+
+
+pqxx::range_error::range_error(const std::string &whatarg) :
+ out_of_range{whatarg}
+{
+}
diff --git a/contrib/libs/libpqxx/src/field.cxx b/contrib/libs/libpqxx/src/field.cxx
new file mode 100644
index 0000000000..10f0f69e2b
--- /dev/null
+++ b/contrib/libs/libpqxx/src/field.cxx
@@ -0,0 +1,77 @@
+/** Implementation of the pqxx::field class.
+ *
+ * pqxx::field refers to a field in a query result.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cstring>
+
+#include "pqxx/internal/libpq-forward.hxx"
+
+#include "pqxx/result"
+
+
+pqxx::field::field(const pqxx::row &R, pqxx::row::size_type C) noexcept :
+ m_col{static_cast<decltype(m_col)>(C)},
+ m_home{R.m_result},
+ m_row{pqxx::result_size_type(R.m_index)}
+{
+}
+
+
+bool pqxx::field::operator==(const field &rhs) const
+{
+ if (is_null() != rhs.is_null()) return false;
+ // TODO: Verify null handling decision
+ const size_type s = size();
+ if (s != rhs.size()) return false;
+ return std::memcmp(c_str(), rhs.c_str(), s) == 0;
+}
+
+
+const char *pqxx::field::name() const
+{
+ return home().column_name(col());
+}
+
+
+pqxx::oid pqxx::field::type() const
+{
+ return home().column_type(col());
+}
+
+
+pqxx::oid pqxx::field::table() const
+{
+ return home().column_table(col());
+}
+
+
+pqxx::row::size_type pqxx::field::table_column() const
+{
+ return home().table_column(col());
+}
+
+
+const char *pqxx::field::c_str() const
+{
+ return home().GetValue(idx(), col());
+}
+
+
+bool pqxx::field::is_null() const noexcept
+{
+ return home().get_is_null(idx(), col());
+}
+
+
+pqxx::field::size_type pqxx::field::size() const noexcept
+{
+ return home().get_length(idx(), col());
+}
diff --git a/contrib/libs/libpqxx/src/largeobject.cxx b/contrib/libs/libpqxx/src/largeobject.cxx
new file mode 100644
index 0000000000..8020a2fc04
--- /dev/null
+++ b/contrib/libs/libpqxx/src/largeobject.cxx
@@ -0,0 +1,313 @@
+/** Implementation of the Large Objects interface.
+ *
+ * Allows direct access to large objects, as well as though I/O streams.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <algorithm>
+#include <cerrno>
+#include <stdexcept>
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/largeobject"
+
+#include "pqxx/internal/gates/connection-largeobject.hxx"
+
+
+using namespace pqxx::internal;
+
+namespace
+{
+inline int StdModeToPQMode(std::ios::openmode mode)
+{
+ /// Mode bits, copied from libpq-fs.h so that we no longer need that header.
+ constexpr int
+ INV_WRITE = 0x00020000,
+ INV_READ = 0x00040000;
+
+ return
+ ((mode & std::ios::in) ? INV_READ : 0) |
+ ((mode & std::ios::out) ? INV_WRITE : 0);
+}
+
+
+inline int StdDirToPQDir(std::ios::seekdir dir) noexcept
+{
+ // TODO: Figure out whether seekdir values match C counterparts!
+#ifdef PQXX_SEEKDIRS_MATCH_C
+ return dir;
+#else
+ int pqdir;
+ switch (dir)
+ {
+ case std::ios::beg: pqdir=SEEK_SET; break;
+ case std::ios::cur: pqdir=SEEK_CUR; break;
+ case std::ios::end: pqdir=SEEK_END; break;
+
+ /* Added mostly to silence compiler warning, but also to help compiler detect
+ * cases where this function can be optimized away completely. This latter
+ * reason should go away as soon as PQXX_SEEKDIRS_MATCH_C works.
+ */
+ default: pqdir = dir; break;
+ }
+ return pqdir;
+#endif
+}
+
+
+} // namespace
+
+
+pqxx::largeobject::largeobject(dbtransaction &T) :
+ m_id{}
+{
+ // (Mode is ignored as of postgres 8.1.)
+ m_id = lo_creat(raw_connection(T), 0);
+ if (m_id == oid_none)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{"Could not create large object: " + reason(T.conn(), err)};
+ }
+}
+
+
+pqxx::largeobject::largeobject(dbtransaction &T, const std::string &File) :
+ m_id{}
+{
+ m_id = lo_import(raw_connection(T), File.c_str());
+ if (m_id == oid_none)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{
+ "Could not import file '" + File + "' to large object: " +
+ reason(T.conn(), err)};
+ }
+}
+
+
+pqxx::largeobject::largeobject(const largeobjectaccess &O) noexcept :
+ m_id{O.id()}
+{
+}
+
+
+void pqxx::largeobject::to_file(
+ dbtransaction &T,
+ const std::string &File) const
+{
+ if (lo_export(raw_connection(T), id(), File.c_str()) == -1)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{
+ "Could not export large object " + to_string(m_id) + " "
+ "to file '" + File + "': " + reason(T.conn(), err)};
+ }
+}
+
+
+void pqxx::largeobject::remove(dbtransaction &T) const
+{
+ if (lo_unlink(raw_connection(T), id()) == -1)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{
+ "Could not delete large object " + to_string(m_id) + ": " +
+ reason(T.conn(), err)};
+ }
+}
+
+
+pqxx::internal::pq::PGconn *pqxx::largeobject::raw_connection(
+ const dbtransaction &T)
+{
+ return gate::connection_largeobject{T.conn()}.raw_connection();
+}
+
+
+std::string pqxx::largeobject::reason(const connection_base &c, int err) const
+{
+ if (err == ENOMEM) return "Out of memory";
+ if (id() == oid_none) return "No object selected";
+ return gate::const_connection_largeobject{c}.error_message();
+}
+
+
+pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T, openmode mode) :
+ largeobject{T},
+ m_trans{T}
+{
+ open(mode);
+}
+
+
+pqxx::largeobjectaccess::largeobjectaccess(
+ dbtransaction &T,
+ oid O,
+ openmode mode) :
+ largeobject{O},
+ m_trans{T}
+{
+ open(mode);
+}
+
+
+pqxx::largeobjectaccess::largeobjectaccess(
+ dbtransaction &T,
+ largeobject O,
+ openmode mode) :
+ largeobject{O},
+ m_trans{T}
+{
+ open(mode);
+}
+
+
+pqxx::largeobjectaccess::largeobjectaccess(
+ dbtransaction &T,
+ const std::string &File,
+ openmode mode) :
+ largeobject{T, File},
+ m_trans{T}
+{
+ open(mode);
+}
+
+
+pqxx::largeobjectaccess::size_type
+pqxx::largeobjectaccess::seek(size_type dest, seekdir dir)
+{
+ const auto Result = cseek(dest, dir);
+ if (Result == -1)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{"Error seeking in large object: " + reason(err)};
+ }
+
+ return Result;
+}
+
+
+pqxx::largeobjectaccess::pos_type
+pqxx::largeobjectaccess::cseek(off_type dest, seekdir dir) noexcept
+{
+ return lo_lseek(raw_connection(), m_fd, int(dest), StdDirToPQDir(dir));
+}
+
+
+pqxx::largeobjectaccess::pos_type
+pqxx::largeobjectaccess::cwrite(const char Buf[], size_type Len) noexcept
+{
+ return
+ std::max(
+ lo_write(raw_connection(), m_fd,const_cast<char *>(Buf), size_t(Len)),
+ -1);
+}
+
+
+pqxx::largeobjectaccess::pos_type
+pqxx::largeobjectaccess::cread(char Buf[], size_type Bytes) noexcept
+{
+ return std::max(lo_read(raw_connection(), m_fd, Buf, size_t(Bytes)), -1);
+}
+
+
+pqxx::largeobjectaccess::pos_type
+pqxx::largeobjectaccess::ctell() const noexcept
+{
+ return lo_tell(raw_connection(), m_fd);
+}
+
+
+void pqxx::largeobjectaccess::write(const char Buf[], size_type Len)
+{
+ const auto Bytes = cwrite(Buf, Len);
+ if (Bytes < Len)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ if (Bytes < 0)
+ throw failure{
+ "Error writing to large object #" + to_string(id()) + ": " +
+ reason(err)};
+ if (Bytes == 0)
+ throw failure{
+ "Could not write to large object #" + to_string(id()) + ": " +
+ reason(err)};
+
+ throw failure{
+ "Wanted to write " + to_string(Len) + " bytes to large object #" +
+ to_string(id()) + "; " "could only write " + to_string(Bytes)};
+ }
+}
+
+
+pqxx::largeobjectaccess::size_type
+pqxx::largeobjectaccess::read(char Buf[], size_type Len)
+{
+ const auto Bytes = cread(Buf, Len);
+ if (Bytes < 0)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{
+ "Error reading from large object #" + to_string(id()) + ": " +
+ reason(err)};
+ }
+ return Bytes;
+}
+
+
+void pqxx::largeobjectaccess::open(openmode mode)
+{
+ m_fd = lo_open(raw_connection(), id(), StdModeToPQMode(mode));
+ if (m_fd < 0)
+ {
+ const int err = errno;
+ if (err == ENOMEM) throw std::bad_alloc{};
+ throw failure{
+ "Could not open large object " + to_string(id()) + ": " +
+ reason(err)};
+ }
+}
+
+
+void pqxx::largeobjectaccess::close() noexcept
+{
+ if (m_fd >= 0) lo_close(raw_connection(), m_fd);
+}
+
+
+pqxx::largeobjectaccess::size_type pqxx::largeobjectaccess::tell() const
+{
+ const size_type res = ctell();
+ if (res == -1) throw failure{reason(errno)};
+ return res;
+}
+
+
+std::string pqxx::largeobjectaccess::reason(int err) const
+{
+ if (m_fd == -1) return "No object opened.";
+ return largeobject::reason(m_trans.conn(), err);
+}
+
+
+void pqxx::largeobjectaccess::process_notice(const std::string &s) noexcept
+{
+ m_trans.process_notice(s);
+}
diff --git a/contrib/libs/libpqxx/src/nontransaction.cxx b/contrib/libs/libpqxx/src/nontransaction.cxx
new file mode 100644
index 0000000000..09e13a94d0
--- /dev/null
+++ b/contrib/libs/libpqxx/src/nontransaction.cxx
@@ -0,0 +1,25 @@
+/** Implementation of the pqxx::nontransaction class.
+ *
+ * pqxx::nontransaction provides nontransactional database access.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/nontransaction"
+
+
+pqxx::nontransaction::~nontransaction()
+{
+ End();
+}
+
+
+pqxx::result pqxx::nontransaction::do_exec(const char Query[])
+{
+ return direct_exec(Query, 0);
+}
diff --git a/contrib/libs/libpqxx/src/notification.cxx b/contrib/libs/libpqxx/src/notification.cxx
new file mode 100644
index 0000000000..391a71c1a4
--- /dev/null
+++ b/contrib/libs/libpqxx/src/notification.cxx
@@ -0,0 +1,36 @@
+/** Implementation of the pqxx::notification_receiever class.
+ *
+ * pqxx::notification_receiver processes notifications.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <string>
+
+#include "pqxx/internal/gates/connection-notification_receiver.hxx"
+
+#include "pqxx/notification"
+
+
+using namespace pqxx::internal;
+
+
+pqxx::notification_receiver::notification_receiver(
+ connection_base &c,
+ const std::string &channel_name) :
+ m_conn{c},
+ m_channel{channel_name}
+{
+ gate::connection_notification_receiver{c}.add_receiver(this);
+}
+
+
+pqxx::notification_receiver::~notification_receiver()
+{
+ gate::connection_notification_receiver{this->conn()}.remove_receiver(this);
+}
diff --git a/contrib/libs/libpqxx/src/pipeline.cxx b/contrib/libs/libpqxx/src/pipeline.cxx
new file mode 100644
index 0000000000..15b646ea3b
--- /dev/null
+++ b/contrib/libs/libpqxx/src/pipeline.cxx
@@ -0,0 +1,413 @@
+/** Implementation of the pqxx::pipeline class.
+ *
+ * Throughput-optimized query interface.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <iterator>
+
+#include "pqxx/dbtransaction"
+#include "pqxx/pipeline"
+
+#include "pqxx/internal/gates/connection-pipeline.hxx"
+#include "pqxx/internal/gates/result-creation.hxx"
+
+
+using namespace pqxx;
+using namespace pqxx::internal;
+
+
+namespace
+{
+const std::string theSeparator{"; "};
+const std::string theDummyValue{"1"};
+const std::string theDummyQuery{"SELECT " + theDummyValue + theSeparator};
+}
+
+
+pqxx::pipeline::pipeline(transaction_base &t, const std::string &Name) :
+ namedclass{"pipeline", Name},
+ transactionfocus{t}
+{
+ m_issuedrange = make_pair(m_queries.end(), m_queries.end());
+ attach();
+}
+
+
+pqxx::pipeline::~pipeline() noexcept
+{
+ try { cancel(); } catch (const std::exception &) {}
+ detach();
+}
+
+
+void pqxx::pipeline::attach()
+{
+ if (not registered()) register_me();
+}
+
+
+void pqxx::pipeline::detach()
+{
+ if (registered()) unregister_me();
+}
+
+
+pipeline::query_id pqxx::pipeline::insert(const std::string &q)
+{
+ attach();
+ const query_id qid = generate_id();
+ const auto i = m_queries.insert(std::make_pair(qid,Query(q))).first;
+
+ if (m_issuedrange.second == m_queries.end())
+ {
+ m_issuedrange.second = i;
+ if (m_issuedrange.first == m_queries.end()) m_issuedrange.first = i;
+ }
+ m_num_waiting++;
+
+ if (m_num_waiting > m_retain)
+ {
+ if (have_pending()) receive_if_available();
+ if (not have_pending()) issue();
+ }
+
+ return qid;
+}
+
+
+void pqxx::pipeline::complete()
+{
+ if (have_pending()) receive(m_issuedrange.second);
+ if (m_num_waiting and (m_error == qid_limit()))
+ {
+ issue();
+ receive(m_queries.end());
+ }
+ detach();
+}
+
+
+void pqxx::pipeline::flush()
+{
+ if (not m_queries.empty())
+ {
+ if (have_pending()) receive(m_issuedrange.second);
+ m_issuedrange.first = m_issuedrange.second = m_queries.end();
+ m_num_waiting = 0;
+ m_dummy_pending = false;
+ m_queries.clear();
+ }
+ detach();
+}
+
+
+void pqxx::pipeline::cancel()
+{
+ while (have_pending())
+ {
+ gate::connection_pipeline(m_trans.conn()).cancel_query();
+ auto canceled_query = m_issuedrange.first;
+ ++m_issuedrange.first;
+ m_queries.erase(canceled_query);
+ }
+}
+
+
+bool pqxx::pipeline::is_finished(pipeline::query_id q) const
+{
+ if (m_queries.find(q) == m_queries.end())
+ throw std::logic_error{
+ "Requested status for unknown query '" + to_string(q) + "'."};
+ return
+ (QueryMap::const_iterator(m_issuedrange.first)==m_queries.end()) or
+ (q < m_issuedrange.first->first and q < m_error);
+}
+
+
+std::pair<pipeline::query_id, result> pqxx::pipeline::retrieve()
+{
+ if (m_queries.empty())
+ throw std::logic_error{"Attempt to retrieve result from empty pipeline."};
+ return retrieve(std::begin(m_queries));
+}
+
+
+int pqxx::pipeline::retain(int retain_max)
+{
+ if (retain_max < 0)
+ throw range_error{
+ "Attempt to make pipeline retain " +
+ to_string(retain_max) + " queries"};
+
+ const int oldvalue = m_retain;
+ m_retain = retain_max;
+
+ if (m_num_waiting >= m_retain) resume();
+
+ return oldvalue;
+}
+
+
+void pqxx::pipeline::resume()
+{
+ if (have_pending()) receive_if_available();
+ if (not have_pending() and m_num_waiting)
+ {
+ issue();
+ receive_if_available();
+ }
+}
+
+
+pipeline::query_id pqxx::pipeline::generate_id()
+{
+ if (m_q_id == qid_limit())
+ throw std::overflow_error{"Too many queries went through pipeline."};
+ ++m_q_id;
+ return m_q_id;
+}
+
+
+
+void pqxx::pipeline::issue()
+{
+ // TODO: Wrap in nested transaction if available, for extra "replayability"
+
+ // Retrieve that null result for the last query, if needed
+ obtain_result();
+
+ // Don't issue anything if we've encountered an error
+ if (m_error < qid_limit()) return;
+
+ // Start with oldest query (lowest id) not in previous issue range
+ auto oldest = m_issuedrange.second;
+
+ // Construct cumulative query string for entire batch
+ std::string cum = separated_list(
+ theSeparator, oldest, m_queries.end(),
+ [](QueryMap::const_iterator i){return i->second.get_query();});
+ const auto num_issued = QueryMap::size_type(std::distance(
+ oldest, m_queries.end()));
+ const bool prepend_dummy = (num_issued > 1);
+ if (prepend_dummy) cum = theDummyQuery + cum;
+
+ gate::connection_pipeline{m_trans.conn()}.start_exec(cum);
+
+ // Since we managed to send out these queries, update state to reflect this
+ m_dummy_pending = prepend_dummy;
+ m_issuedrange.first = oldest;
+ m_issuedrange.second = m_queries.end();
+ m_num_waiting -= int(num_issued);
+}
+
+
+void pqxx::pipeline::internal_error(const std::string &err)
+{
+ set_error_at(0);
+ throw pqxx::internal_error{err};
+}
+
+
+bool pqxx::pipeline::obtain_result(bool expect_none)
+{
+ gate::connection_pipeline gate{m_trans.conn()};
+ const auto r = gate.get_result();
+ if (r == nullptr)
+ {
+ if (have_pending() and not expect_none)
+ {
+ set_error_at(m_issuedrange.first->first);
+ m_issuedrange.second = m_issuedrange.first;
+ }
+ return false;
+ }
+
+ const result res = gate::result_creation::create(
+ r, std::begin(m_queries)->second.get_query(),
+ internal::enc_group(m_trans.conn().encoding_id()));
+
+ if (not have_pending())
+ {
+ set_error_at(std::begin(m_queries)->first);
+ throw std::logic_error{
+ "Got more results from pipeline than there were queries."};
+ }
+
+ // Must be the result for the oldest pending query
+ if (not m_issuedrange.first->second.get_result().empty())
+ internal_error("Multiple results for one query.");
+
+ m_issuedrange.first->second.set_result(res);
+ ++m_issuedrange.first;
+
+ return true;
+}
+
+
+void pqxx::pipeline::obtain_dummy()
+{
+ gate::connection_pipeline gate{m_trans.conn()};
+ const auto r = gate.get_result();
+ m_dummy_pending = false;
+
+ if (r == nullptr)
+ internal_error("Pipeline got no result from backend when it expected one.");
+
+ result R = gate::result_creation::create(
+ r,
+ "[DUMMY PIPELINE QUERY]",
+ internal::enc_group(m_trans.conn().encoding_id()));
+
+ bool OK = false;
+ try
+ {
+ gate::result_creation{R}.check_status();
+ OK = true;
+ }
+ catch (const sql_error &)
+ {
+ }
+ if (OK)
+ {
+ if (R.size() > 1)
+ internal_error("Unexpected result for dummy query in pipeline.");
+
+ if (std::string{R.at(0).at(0).c_str()} != theDummyValue)
+ internal_error("Dummy query in pipeline returned unexpected value.");
+ return;
+ }
+
+ /* Since none of the queries in the batch were actually executed, we can
+ * afford to replay them one by one until we find the exact query that
+ * caused the error. This gives us not only a more specific error message
+ * to report, but also tells us which query to report it for.
+ */
+ // First, give the whole batch the same syntax error message, in case all else
+ // is going to fail.
+ for (auto i = m_issuedrange.first; i != m_issuedrange.second; ++i)
+ i->second.set_result(R);
+
+ // Remember where the end of this batch was
+ const auto stop = m_issuedrange.second;
+
+ // Retrieve that null result for the last query, if needed
+ obtain_result(true);
+
+
+ // Reset internal state to forget botched batch attempt
+ m_num_waiting += int(std::distance(m_issuedrange.first, stop));
+ m_issuedrange.second = m_issuedrange.first;
+
+ // Issue queries in failed batch one at a time.
+ unregister_me();
+ try
+ {
+ do
+ {
+ m_num_waiting--;
+ const std::string &query = m_issuedrange.first->second.get_query();
+ const result res{m_trans.exec(query)};
+ m_issuedrange.first->second.set_result(res);
+ gate::result_creation{res}.check_status();
+ ++m_issuedrange.first;
+ }
+ while (m_issuedrange.first != stop);
+ }
+ catch (const std::exception &)
+ {
+ const query_id thud = m_issuedrange.first->first;
+ ++m_issuedrange.first;
+ m_issuedrange.second = m_issuedrange.first;
+ auto q = m_issuedrange.first;
+ set_error_at( (q == m_queries.end()) ? thud + 1 : q->first);
+ }
+}
+
+
+std::pair<pipeline::query_id, result>
+pqxx::pipeline::retrieve(pipeline::QueryMap::iterator q)
+{
+ if (q == m_queries.end())
+ throw std::logic_error{"Attempt to retrieve result for unknown query."};
+
+ if (q->first >= m_error)
+ throw std::runtime_error{
+ "Could not complete query in pipeline due to error in earlier query."};
+
+ // If query hasn't issued yet, do it now
+ if (m_issuedrange.second != m_queries.end() and
+ (q->first >= m_issuedrange.second->first))
+ {
+ if (have_pending()) receive(m_issuedrange.second);
+ if (m_error == qid_limit()) issue();
+ }
+
+ // If result not in yet, get it; else get at least whatever's convenient
+ if (have_pending())
+ {
+ if (q->first >= m_issuedrange.first->first)
+ {
+ auto suc = q;
+ ++suc;
+ receive(suc);
+ }
+ else
+ {
+ receive_if_available();
+ }
+ }
+
+ if (q->first >= m_error)
+ throw std::runtime_error{
+ "Could not complete query in pipeline due to error in earlier query."};
+
+ // Don't leave the backend idle if there are queries waiting to be issued
+ if (m_num_waiting and not have_pending() and (m_error==qid_limit())) issue();
+
+ const result R = q->second.get_result();
+ const auto P = std::make_pair(q->first, R);
+
+ m_queries.erase(q);
+
+ gate::result_creation{R}.check_status();
+ return P;
+}
+
+
+void pqxx::pipeline::get_further_available_results()
+{
+ gate::connection_pipeline gate{m_trans.conn()};
+ while (not gate.is_busy() and obtain_result())
+ if (not gate.consume_input()) throw broken_connection{};
+}
+
+
+void pqxx::pipeline::receive_if_available()
+{
+ gate::connection_pipeline gate{m_trans.conn()};
+ if (not gate.consume_input()) throw broken_connection{};
+ if (gate.is_busy()) return;
+
+ if (m_dummy_pending) obtain_dummy();
+ if (have_pending()) get_further_available_results();
+}
+
+
+void pqxx::pipeline::receive(pipeline::QueryMap::const_iterator stop)
+{
+ if (m_dummy_pending) obtain_dummy();
+
+ while (obtain_result() and
+ QueryMap::const_iterator{m_issuedrange.first} != stop) ;
+
+ // Also haul in any remaining "targets of opportunity"
+ if (QueryMap::const_iterator{m_issuedrange.first} == stop)
+ get_further_available_results();
+}
diff --git a/contrib/libs/libpqxx/src/prepared_statement.cxx b/contrib/libs/libpqxx/src/prepared_statement.cxx
new file mode 100644
index 0000000000..c2d7fe23f9
--- /dev/null
+++ b/contrib/libs/libpqxx/src/prepared_statement.cxx
@@ -0,0 +1,69 @@
+/** Helper classes for defining and executing prepared statements>
+ *
+ * See the connection_base hierarchy for more about prepared statements.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/connection_base"
+#include "pqxx/prepared_statement"
+#include "pqxx/result"
+#include "pqxx/transaction_base"
+
+#include "pqxx/internal/gates/connection-prepare-invocation.hxx"
+
+
+using namespace pqxx;
+using namespace pqxx::internal;
+
+
+pqxx::prepare::invocation::invocation(
+ transaction_base &home,
+ const std::string &statement) :
+ m_home{home},
+ m_statement{statement}
+{
+}
+
+pqxx::result pqxx::prepare::invocation::exec() const
+{
+ return internal_exec(result_format::text);
+}
+
+pqxx::result pqxx::prepare::invocation::exec_binary() const
+{
+ return internal_exec(result_format::binary);
+}
+
+pqxx::result pqxx::prepare::invocation::internal_exec(result_format format) const
+{
+ std::vector<const char *> ptrs;
+ std::vector<int> lens;
+ std::vector<int> binaries;
+ const int elts = marshall(ptrs, lens, binaries);
+
+ return gate::connection_prepare_invocation{m_home.conn()}.prepared_exec(
+ m_statement,
+ ptrs.data(),
+ lens.data(),
+ binaries.data(),
+ elts,
+ format);
+}
+
+bool pqxx::prepare::invocation::exists() const
+{
+ return gate::connection_prepare_invocation{m_home.conn()}.prepared_exists(
+ m_statement);
+}
+
+
+pqxx::prepare::internal::prepared_def::prepared_def(const std::string &def) :
+ definition{def}
+{
+}
diff --git a/contrib/libs/libpqxx/src/result.cxx b/contrib/libs/libpqxx/src/result.cxx
new file mode 100644
index 0000000000..fcb602d779
--- /dev/null
+++ b/contrib/libs/libpqxx/src/result.cxx
@@ -0,0 +1,454 @@
+/** Implementation of the pqxx::result class and support classes.
+ *
+ * pqxx::result represents the set of result rows from a database query
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/except"
+#include "pqxx/result"
+
+
+const std::string pqxx::result::s_empty_string;
+
+
+/// C++ wrapper for libpq's PQclear.
+void pqxx::internal::clear_result(const pq::PGresult *data)
+{
+ PQclear(const_cast<pq::PGresult *>(data));
+}
+
+
+pqxx::result::result(
+ pqxx::internal::pq::PGresult *rhs,
+ const std::string &Query,
+ internal::encoding_group enc) :
+ m_data{make_data_pointer(rhs)},
+ m_query{std::make_shared<std::string>(Query)},
+ m_encoding(enc)
+{
+}
+
+
+bool pqxx::result::operator==(const result &rhs) const noexcept
+{
+ if (&rhs == this) return true;
+ const auto s = size();
+ if (rhs.size() != s) return false;
+ for (size_type i=0; i<s; ++i)
+ if ((*this)[i] != rhs[i]) return false;
+ return true;
+}
+
+
+pqxx::result::const_reverse_iterator pqxx::result::rbegin() const
+{
+ return const_reverse_iterator{end()};
+}
+
+
+pqxx::result::const_reverse_iterator pqxx::result::crbegin() const
+{
+ return rbegin();
+}
+
+
+pqxx::result::const_reverse_iterator pqxx::result::rend() const
+{
+ return const_reverse_iterator{begin()};
+}
+
+
+pqxx::result::const_reverse_iterator pqxx::result::crend() const
+{
+ return rend();
+}
+
+
+pqxx::result::const_iterator pqxx::result::begin() const noexcept
+{
+ return const_iterator{this, 0};
+}
+
+
+pqxx::result::const_iterator pqxx::result::cbegin() const noexcept
+{
+ return begin();
+}
+
+
+pqxx::result::size_type pqxx::result::size() const noexcept
+{
+ return m_data.get() ? size_type(PQntuples(m_data.get())) : 0;
+}
+
+
+bool pqxx::result::empty() const noexcept
+{
+ return (m_data.get() == nullptr) or (PQntuples(m_data.get()) == 0);
+}
+
+
+pqxx::result::reference pqxx::result::front() const noexcept
+{
+ return row{*this, 0};
+}
+
+
+pqxx::result::reference pqxx::result::back() const noexcept
+{
+ return row{*this, size() - 1};
+}
+
+
+void pqxx::result::swap(result &rhs) noexcept
+{
+ m_data.swap(rhs.m_data);
+ m_query.swap(rhs.m_query);
+}
+
+
+const pqxx::row pqxx::result::operator[](result_size_type i) const noexcept
+{
+ return row{*this, i};
+}
+
+
+const pqxx::row pqxx::result::at(pqxx::result::size_type i) const
+{
+ if (i >= size()) throw range_error{"Row number out of range."};
+ return operator[](i);
+}
+
+
+namespace
+{
+/// C string comparison.
+inline bool equal(const char lhs[], const char rhs[])
+{
+ return strcmp(lhs, rhs) == 0;
+}
+} // namespace
+
+void pqxx::result::ThrowSQLError(
+ const std::string &Err,
+ const std::string &Query) const
+{
+ // Try to establish more precise error type, and throw corresponding
+ // type of exception.
+ const char *const code = PQresultErrorField(m_data.get(), PG_DIAG_SQLSTATE);
+ if (code) switch (code[0])
+ {
+ case '0':
+ switch (code[1])
+ {
+ case '8':
+ throw broken_connection{Err};
+ case 'A':
+ throw feature_not_supported{Err, Query, code};
+ }
+ break;
+ case '2':
+ switch (code[1])
+ {
+ case '2':
+ throw data_exception{Err, Query, code};
+ case '3':
+ if (equal(code,"23001")) throw restrict_violation{Err, Query, code};
+ if (equal(code,"23502")) throw not_null_violation{Err, Query, code};
+ if (equal(code,"23503"))
+ throw foreign_key_violation{Err, Query, code};
+ if (equal(code,"23505")) throw unique_violation{Err, Query, code};
+ if (equal(code,"23514")) throw check_violation{Err, Query, code};
+ throw integrity_constraint_violation{Err, Query, code};
+ case '4':
+ throw invalid_cursor_state{Err, Query, code};
+ case '6':
+ throw invalid_sql_statement_name{Err, Query, code};
+ }
+ break;
+ case '3':
+ switch (code[1])
+ {
+ case '4':
+ throw invalid_cursor_name{Err, Query, code};
+ }
+ break;
+ case '4':
+ switch (code[1])
+ {
+ case '0':
+ if (equal(code, "40000")) throw transaction_rollback{Err};
+ if (equal(code, "40001")) throw serialization_failure{Err};
+ if (equal(code, "40003")) throw statement_completion_unknown{Err};
+ if (equal(code, "40P01")) throw deadlock_detected{Err};
+ break;
+ case '2':
+ if (equal(code,"42501")) throw insufficient_privilege{Err, Query};
+ if (equal(code,"42601"))
+ throw syntax_error{Err, Query, code, errorposition()};
+ if (equal(code,"42703")) throw undefined_column{Err, Query, code};
+ if (equal(code,"42883")) throw undefined_function{Err, Query, code};
+ if (equal(code,"42P01")) throw undefined_table{Err, Query, code};
+ }
+ break;
+ case '5':
+ switch (code[1])
+ {
+ case '3':
+ if (equal(code,"53100")) throw disk_full{Err, Query, code};
+ if (equal(code,"53200")) throw out_of_memory{Err, Query, code};
+ if (equal(code,"53300")) throw too_many_connections{Err};
+ throw insufficient_resources{Err, Query, code};
+ }
+ break;
+
+ case 'P':
+ if (equal(code, "P0001")) throw plpgsql_raise{Err, Query, code};
+ if (equal(code, "P0002"))
+ throw plpgsql_no_data_found{Err, Query, code};
+ if (equal(code, "P0003"))
+ throw plpgsql_too_many_rows{Err, Query, code};
+ throw plpgsql_error{Err, Query, code};
+ }
+ // Fallback: No error code.
+ throw sql_error{Err, Query, code};
+}
+
+void pqxx::result::check_status() const
+{
+ const std::string Err = StatusError();
+ if (not Err.empty()) ThrowSQLError(Err, query());
+}
+
+
+std::string pqxx::result::StatusError() const
+{
+ if (m_data.get() == nullptr) throw failure{"No result set given."};
+
+ std::string Err;
+
+ switch (PQresultStatus(m_data.get()))
+ {
+ case PGRES_EMPTY_QUERY: // The string sent to the backend was empty.
+ case PGRES_COMMAND_OK: // Successful completion of a command returning no data
+ case PGRES_TUPLES_OK: // The query successfully executed
+ break;
+
+ case PGRES_COPY_OUT: // Copy Out (from server) data transfer started
+ case PGRES_COPY_IN: // Copy In (to server) data transfer started
+ break;
+
+ case PGRES_BAD_RESPONSE: // The server's response was not understood
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ Err = PQresultErrorMessage(m_data.get());
+ break;
+
+ default:
+ throw internal_error{
+ "pqxx::result: Unrecognized response code " +
+ to_string(int(PQresultStatus(m_data.get())))};
+ }
+ return Err;
+}
+
+
+const char *pqxx::result::cmd_status() const noexcept
+{
+ return PQcmdStatus(const_cast<internal::pq::PGresult *>(m_data.get()));
+}
+
+
+const std::string &pqxx::result::query() const noexcept
+{
+ return m_query ? *m_query : s_empty_string;
+}
+
+
+pqxx::oid pqxx::result::inserted_oid() const
+{
+ if (m_data.get() == nullptr)
+ throw usage_error{
+ "Attempt to read oid of inserted row without an INSERT result"};
+ return PQoidValue(const_cast<internal::pq::PGresult *>(m_data.get()));
+}
+
+
+pqxx::result::size_type pqxx::result::affected_rows() const
+{
+ const char *const RowsStr = PQcmdTuples(
+ const_cast<internal::pq::PGresult *>(m_data.get()));
+ return RowsStr[0] ? size_type(atoi(RowsStr)) : 0;
+}
+
+
+const char *pqxx::result::GetValue(
+ pqxx::result::size_type Row,
+ pqxx::row::size_type Col) const
+{
+ return PQgetvalue(m_data.get(), int(Row), int(Col));
+}
+
+
+bool pqxx::result::get_is_null(
+ pqxx::result::size_type Row,
+ pqxx::row::size_type Col) const
+{
+ return PQgetisnull(m_data.get(), int(Row), int(Col)) != 0;
+}
+
+pqxx::field::size_type pqxx::result::get_length(
+ pqxx::result::size_type Row,
+ pqxx::row::size_type Col) const noexcept
+{
+ return field::size_type(PQgetlength(m_data.get(), int(Row), int(Col)));
+}
+
+
+pqxx::oid pqxx::result::column_type(row::size_type ColNum) const
+{
+ const oid T = PQftype(m_data.get(), int(ColNum));
+ if (T == oid_none)
+ throw argument_error{
+ "Attempt to retrieve type of nonexistent column " +
+ to_string(ColNum) + " of query result."};
+ return T;
+}
+
+
+pqxx::oid pqxx::result::column_table(row::size_type ColNum) const
+{
+ const oid T = PQftable(m_data.get(), int(ColNum));
+
+ /* If we get oid_none, it may be because the column is computed, or because we
+ * got an invalid row number.
+ */
+ if (T == oid_none and ColNum >= columns())
+ throw argument_error{
+ "Attempt to retrieve table ID for column " + to_string(ColNum) +
+ " out of " + to_string(columns())};
+
+ return T;
+}
+
+
+pqxx::row::size_type pqxx::result::table_column(row::size_type ColNum) const
+{
+ const auto n = row::size_type(PQftablecol(m_data.get(), int(ColNum)));
+ if (n != 0) return n-1;
+
+ // Failed. Now find out why, so we can throw a sensible exception.
+ const std::string col_num = to_string(ColNum);
+ if (ColNum > columns())
+ throw range_error{"Invalid column index in table_column(): " + col_num};
+
+ if (m_data.get() == nullptr)
+ throw usage_error{
+ "Can't query origin of column " + col_num + ": "
+ "result is not initialized."};
+
+ throw usage_error{
+ "Can't query origin of column " + col_num + ": "
+ "not derived from table column."};
+}
+
+int pqxx::result::errorposition() const
+{
+ int pos = -1;
+ if (m_data.get())
+ {
+ const char *p = PQresultErrorField(
+ const_cast<internal::pq::PGresult *>(m_data.get()),
+ PG_DIAG_STATEMENT_POSITION);
+ if (p) from_string(p, pos);
+ }
+ return pos;
+}
+
+
+const char *pqxx::result::column_name(pqxx::row::size_type Number) const
+{
+ const char *const N = PQfname(m_data.get(), int(Number));
+ if (N == nullptr)
+ {
+ if (m_data.get() == nullptr)
+ throw usage_error{"Queried column name on null result."};
+ throw range_error{
+ "Invalid column number: " + to_string(Number) +
+ " (maximum is " + to_string(columns() - 1) + ")."};
+ }
+ return N;
+}
+
+
+pqxx::row::size_type pqxx::result::columns() const noexcept
+{
+ auto ptr = const_cast<internal::pq::PGresult *>(m_data.get());
+ return ptr ? row::size_type(PQnfields(ptr)) : 0;
+}
+
+
+// const_result_iterator
+
+pqxx::const_result_iterator pqxx::const_result_iterator::operator++(int)
+{
+ const_result_iterator old{*this};
+ m_index++;
+ return old;
+}
+
+
+pqxx::const_result_iterator pqxx::const_result_iterator::operator--(int)
+{
+ const_result_iterator old{*this};
+ m_index--;
+ return old;
+}
+
+
+pqxx::result::const_iterator
+pqxx::result::const_reverse_iterator::base() const noexcept
+{
+ iterator_type tmp{*this};
+ return ++tmp;
+}
+
+
+pqxx::const_reverse_result_iterator
+pqxx::const_reverse_result_iterator::operator++(int)
+{
+ const_reverse_result_iterator tmp{*this};
+ iterator_type::operator--();
+ return tmp;
+}
+
+
+pqxx::const_reverse_result_iterator
+pqxx::const_reverse_result_iterator::operator--(int)
+{
+ const_reverse_result_iterator tmp{*this};
+ iterator_type::operator++();
+ return tmp;
+}
+
+
+template<>
+std::string pqxx::to_string(const field &Obj)
+{
+ return std::string{Obj.c_str(), Obj.size()};
+}
diff --git a/contrib/libs/libpqxx/src/robusttransaction.cxx b/contrib/libs/libpqxx/src/robusttransaction.cxx
new file mode 100644
index 0000000000..fbada337df
--- /dev/null
+++ b/contrib/libs/libpqxx/src/robusttransaction.cxx
@@ -0,0 +1,317 @@
+/** Implementation of the pqxx::robusttransaction class.
+ *
+ * pqxx::robusttransaction is a slower but safer transaction class.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <stdexcept>
+
+#include "pqxx/connection_base"
+#include "pqxx/result"
+#include "pqxx/robusttransaction"
+
+
+using namespace pqxx::internal;
+
+
+// TODO: Log username in more places.
+
+pqxx::internal::basic_robusttransaction::basic_robusttransaction(
+ connection_base &C,
+ const std::string &IsolationLevel,
+ const std::string &table_name) :
+ namedclass{"robusttransaction"},
+ dbtransaction(C, IsolationLevel),
+ m_log_table{table_name}
+{
+ if (table_name.empty()) m_log_table = "pqxx_robusttransaction_log";
+ m_sequence = m_log_table + "_seq";
+}
+
+
+pqxx::internal::basic_robusttransaction::~basic_robusttransaction()
+{
+}
+
+
+void pqxx::internal::basic_robusttransaction::do_begin()
+{
+ try
+ {
+ CreateTransactionRecord();
+ }
+ catch (const std::exception &)
+ {
+ // The problem here *may* be that the log table doesn't exist yet. Create
+ // one, start a new transaction, and try again.
+ try { dbtransaction::do_abort(); } catch (const std::exception &) {}
+ CreateLogTable();
+ dbtransaction::do_begin();
+ m_backendpid = conn().backendpid();
+ CreateTransactionRecord();
+ }
+
+ dbtransaction::do_begin();
+
+ // If this transaction commits, the transaction record should also be gone.
+ direct_exec(sql_delete().c_str());
+
+ if (conn().server_version() >= 80300)
+ direct_exec("SELECT txid_current()")[0][0].to(m_xid);
+}
+
+
+
+void pqxx::internal::basic_robusttransaction::do_commit()
+{
+ if (m_record_id == 0)
+ throw internal_error{"transaction '" + name() + "' has no ID."};
+
+ // Check constraints before sending the COMMIT to the database to reduce the
+ // work being done inside our in-doubt window.
+ try
+ {
+ direct_exec("SET CONSTRAINTS ALL IMMEDIATE");
+ }
+ catch (...)
+ {
+ do_abort();
+ throw;
+ }
+
+ // Here comes the critical part. If we lose our connection here, we'll be
+ // left clueless as to whether the backend got the message and is trying to
+ // commit the transaction (let alone whether it will succeed if so). That
+ // case requires some special handling that makes robusttransaction what it
+ // is.
+ try
+ {
+ direct_exec("COMMIT");
+
+ // If we make it here, great. Normal, successful commit.
+ m_record_id = 0;
+ return;
+ }
+ catch (const broken_connection &)
+ {
+ // Oops, lost connection at the crucial moment. Fall through to in-doubt
+ // handling below.
+ }
+ catch (...)
+ {
+ if (conn().is_open())
+ {
+ // Commit failed--probably due to a constraint violation or something
+ // similar. But we're still connected, so no worries from a consistency
+ // point of view.
+ do_abort();
+ throw;
+ }
+ // Otherwise, fall through to in-doubt handling.
+ }
+
+ // If we get here, we're in doubt. Talk to the backend, figure out what
+ // happened. If the transaction record still exists, the transaction failed.
+ // If not, it succeeded.
+
+ bool exists;
+ try
+ {
+ exists = CheckTransactionRecord();
+ }
+ catch (const std::exception &f)
+ {
+ // Couldn't check for transaction record. We're still in doubt as to
+ // whether the transaction was performed.
+ const std::string Msg =
+ "WARNING: Connection lost while committing transaction "
+ "'" + name() + "' (id " + to_string(m_record_id) + ", "
+ "transaction_id " + m_xid + "). "
+ "Please check for this record in the "
+ "'" + m_log_table + "' table. "
+ "If the record exists, the transaction was executed. "
+ "If not, then it wasn't.\n";
+
+ process_notice(Msg);
+ process_notice(
+ "Could not verify existence of transaction record because of the "
+ "following error:\n");
+ process_notice(std::string{f.what()} + "\n");
+
+ throw in_doubt_error{Msg};
+ }
+
+ // Transaction record is still there, so the transaction failed and all we
+ // have is a "normal" transaction failure.
+ if (exists)
+ {
+ do_abort();
+ throw broken_connection{"Connection lost while committing."};
+ }
+
+ // Otherwise, the transaction succeeded. Forget there was ever an error.
+}
+
+
+void pqxx::internal::basic_robusttransaction::do_abort()
+{
+ dbtransaction::do_abort();
+ DeleteTransactionRecord();
+}
+
+
+// Create transaction log table if it didn't already exist
+void pqxx::internal::basic_robusttransaction::CreateLogTable()
+{
+ // Create log table in case it doesn't already exist. This code must only be
+ // executed before the backend transaction has properly started.
+ std::string CrTab =
+ "CREATE TABLE " + quote_name(m_log_table) + " ("
+ "id INTEGER NOT NULL, "
+ "username VARCHAR(256), "
+ "transaction_id xid, "
+ "name VARCHAR(256), "
+ "date TIMESTAMP NOT NULL"
+ ")";
+
+ try
+ {
+ direct_exec(CrTab.c_str(), 1);
+ }
+ catch (const std::exception &e)
+ {
+ conn().process_notice(
+ "Could not create transaction log table: " + std::string{e.what()});
+ }
+
+ try
+ {
+ direct_exec(("CREATE SEQUENCE " + m_sequence).c_str());
+ }
+ catch (const std::exception &e)
+ {
+ conn().process_notice(
+ "Could not create transaction log sequence: " + std::string{e.what()});
+ }
+}
+
+
+void pqxx::internal::basic_robusttransaction::CreateTransactionRecord()
+{
+ // Clean up old transaction records.
+ direct_exec((
+ "DELETE FROM " + m_log_table + " "
+ "WHERE date < CURRENT_TIMESTAMP - '30 days'::interval").c_str());
+
+ // Allocate id.
+ const std::string sql_get_id{"SELECT nextval(" + quote(m_sequence) + ")"};
+ direct_exec(sql_get_id.c_str())[0][0].to(m_record_id);
+
+ direct_exec((
+ "INSERT INTO " + quote_name(m_log_table) +
+ " (id, username, name, date) "
+ "VALUES "
+ "(" +
+ to_string(m_record_id) + ", " +
+ quote(conn().username()) + ", " +
+ (name().empty() ? "NULL" : quote(name())) + ", "
+ "CURRENT_TIMESTAMP"
+ ")").c_str());
+}
+
+
+std::string pqxx::internal::basic_robusttransaction::sql_delete() const
+{
+ return
+ "DELETE FROM " + quote_name(m_log_table) + " "
+ "WHERE id = " + to_string(m_record_id);
+}
+
+
+void pqxx::internal::basic_robusttransaction::DeleteTransactionRecord()
+ noexcept
+{
+ if (m_record_id == 0) return;
+
+ try
+ {
+ const std::string Del = sql_delete();
+
+ reactivation_avoidance_exemption E(conn());
+ direct_exec(Del.c_str(), 20);
+
+ // Now that we've arrived here, we're about as sure as we can be that that
+ // record is quite dead.
+ m_record_id = 0;
+ }
+ catch (const std::exception &)
+ {
+ }
+
+ if (m_record_id != 0) try
+ {
+ process_notice(
+ "WARNING: "
+ "Failed to delete obsolete transaction record with id " +
+ to_string(m_record_id) + " ('" + name() + "'). "
+ "Please delete it manually. Thank you.\n");
+ }
+ catch (const std::exception &)
+ {
+ }
+}
+
+
+// Attempt to establish whether transaction record with given ID still exists
+bool pqxx::internal::basic_robusttransaction::CheckTransactionRecord()
+{
+ bool hold = true;
+ for (int c=20; hold and c; internal::sleep_seconds(5), --c)
+ {
+ if (conn().server_version() > 80300)
+ {
+ const std::string query{
+ "SELECT " + m_xid + " >= txid_snapshot_xmin(txid_current_snapshot())"};
+ direct_exec(query.c_str())[0][0].to(hold);
+ }
+ else
+ {
+ /* Wait for the old backend (with the lost connection) to die.
+ *
+ * Actually this is only possible if stats_command_string (or maybe
+ * stats_start_collector?) has been set in postgresql.conf and we're
+ * running as the postgres superuser.
+ *
+ * Starting with 7.4, we could also use pg_locks. The entry for a zombied
+ * transaction will have a "relation" field of null, a "transaction" field
+ * with the transaction ID, and "pid" set to our backend pid. If the
+ * relation exists but no such record is found, then the transaction is no
+ * longer running.
+ */
+ const result R{direct_exec((
+ "SELECT current_query "
+ "FROM pq_stat_activity "
+ "WHERE procpid = " + to_string(m_backendpid)).c_str())};
+ hold = not R.empty();
+ }
+ }
+
+ if (hold)
+ throw in_doubt_error{
+ "Old backend process stays alive too long to wait for."};
+
+ // Now look for our transaction record
+ const std::string Find =
+ "SELECT id FROM " + quote_name(m_log_table) + " "
+ "WHERE "
+ "id = " + to_string(m_record_id) + " AND "
+ "user = " + conn().username();
+
+ return not direct_exec(Find.c_str(), 20).empty();
+}
diff --git a/contrib/libs/libpqxx/src/row.cxx b/contrib/libs/libpqxx/src/row.cxx
new file mode 100644
index 0000000000..3ae9a19a81
--- /dev/null
+++ b/contrib/libs/libpqxx/src/row.cxx
@@ -0,0 +1,276 @@
+/** Implementation of the pqxx::result class and support classes.
+ *
+ * pqxx::result represents the set of result rows from a database query.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cstdlib>
+#include <cstring>
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/except"
+#include "pqxx/result"
+
+#include "pqxx/internal/gates/result-row.hxx"
+
+
+pqxx::row::row(result r, size_t i) noexcept :
+ m_result{r},
+ m_index{long(i)},
+ m_end{internal::gate::result_row(r) ? r.columns() : 0}
+{
+}
+
+
+pqxx::row::const_iterator pqxx::row::begin() const noexcept
+{
+ return const_iterator{*this, m_begin};
+}
+
+
+pqxx::row::const_iterator pqxx::row::cbegin() const noexcept
+{
+ return begin();
+}
+
+
+pqxx::row::const_iterator pqxx::row::end() const noexcept
+{
+ return const_iterator{*this, m_end};
+}
+
+
+pqxx::row::const_iterator pqxx::row::cend() const noexcept
+{
+ return end();
+}
+
+
+pqxx::row::reference pqxx::row::front() const noexcept
+{
+ return field{*this, m_begin};
+}
+
+
+pqxx::row::reference pqxx::row::back() const noexcept
+{
+ return field{*this, m_end - 1};
+}
+
+
+pqxx::row::const_reverse_iterator pqxx::row::rbegin() const
+{
+ return const_reverse_row_iterator{end()};
+}
+
+
+pqxx::row::const_reverse_iterator pqxx::row::crbegin() const
+{
+ return rbegin();
+}
+
+
+pqxx::row::const_reverse_iterator pqxx::row::rend() const
+{
+ return const_reverse_row_iterator{begin()};
+}
+
+
+pqxx::row::const_reverse_iterator pqxx::row::crend() const
+{
+ return rend();
+}
+
+
+bool pqxx::row::operator==(const row &rhs) const noexcept
+{
+ if (&rhs == this) return true;
+ const auto s = size();
+ if (rhs.size() != s) return false;
+ // TODO: Depends on how null is handled!
+ for (size_type i=0; i<s; ++i) if ((*this)[i] != rhs[i]) return false;
+ return true;
+}
+
+
+pqxx::row::reference pqxx::row::operator[](size_type i) const noexcept
+{
+ return field{*this, m_begin + i};
+}
+
+
+pqxx::row::reference pqxx::row::operator[](int i) const noexcept
+{
+ return operator[](size_type(i));
+}
+
+
+pqxx::row::reference pqxx::row::operator[](const char f[]) const
+{
+ return at(f);
+}
+
+
+pqxx::row::reference pqxx::row::operator[](const std::string &s) const
+{
+ return operator[](s.c_str());
+}
+
+
+pqxx::row::reference pqxx::row::at(int i) const
+{
+ return at(size_type(i));
+}
+
+
+pqxx::row::reference pqxx::row::at(const std::string &s) const
+{
+ return at(s.c_str());
+}
+
+
+void pqxx::row::swap(row &rhs) noexcept
+{
+ const auto i = m_index;
+ const auto b= m_begin;
+ const auto e = m_end;
+ m_result.swap(rhs.m_result);
+ m_index = rhs.m_index;
+ m_begin = rhs.m_begin;
+ m_end = rhs.m_end;
+ rhs.m_index = i;
+ rhs.m_begin = b;
+ rhs.m_end = e;
+}
+
+
+pqxx::field pqxx::row::at(const char f[]) const
+{
+ return field{*this, m_begin + column_number(f)};
+}
+
+
+pqxx::field pqxx::row::at(pqxx::row::size_type i) const
+{
+ if (i >= size())
+ throw range_error{"Invalid field number."};
+
+ return operator[](i);
+}
+
+
+pqxx::oid pqxx::row::column_type(size_type ColNum) const
+{
+ return m_result.column_type(m_begin + ColNum);
+}
+
+
+pqxx::oid pqxx::row::column_table(size_type ColNum) const
+{
+ return m_result.column_table(m_begin + ColNum);
+}
+
+
+pqxx::row::size_type pqxx::row::table_column(size_type ColNum) const
+{
+ return m_result.table_column(m_begin + ColNum);
+}
+
+
+pqxx::row::size_type pqxx::row::column_number(const char ColName[]) const
+{
+ const auto n = m_result.column_number(ColName);
+ if (n >= m_end)
+ return result{}.column_number(ColName);
+ if (n >= m_begin)
+ return n - m_begin;
+
+ const char *const AdaptedColName = m_result.column_name(n);
+ for (auto i = m_begin; i < m_end; ++i)
+ if (strcmp(AdaptedColName, m_result.column_name(i)) == 0)
+ return i - m_begin;
+
+ return result{}.column_number(ColName);
+}
+
+
+pqxx::row::size_type pqxx::result::column_number(const char ColName[]) const
+{
+ const int N = PQfnumber(
+ const_cast<internal::pq::PGresult *>(m_data.get()), ColName);
+ if (N == -1)
+ throw argument_error{
+ "Unknown column name: '" + std::string{ColName} + "'."};
+
+ return row::size_type(N);
+}
+
+
+pqxx::row pqxx::row::slice(size_type Begin, size_type End) const
+{
+ if (Begin > End or End > size())
+ throw range_error{"Invalid field range."};
+
+ row result{*this};
+ result.m_begin = m_begin + Begin;
+ result.m_end = m_begin + End;
+ return result;
+}
+
+
+bool pqxx::row::empty() const noexcept
+{
+ return m_begin == m_end;
+}
+
+
+pqxx::const_row_iterator pqxx::const_row_iterator::operator++(int)
+{
+ const_row_iterator old{*this};
+ m_col++;
+ return old;
+}
+
+
+pqxx::const_row_iterator pqxx::const_row_iterator::operator--(int)
+{
+ const_row_iterator old{*this};
+ m_col--;
+ return old;
+}
+
+
+pqxx::const_row_iterator
+pqxx::const_reverse_row_iterator::base() const noexcept
+{
+ iterator_type tmp{*this};
+ return ++tmp;
+}
+
+
+pqxx::const_reverse_row_iterator
+pqxx::const_reverse_row_iterator::operator++(int)
+{
+ const_reverse_row_iterator tmp{*this};
+ operator++();
+ return tmp;
+}
+
+
+pqxx::const_reverse_row_iterator
+pqxx::const_reverse_row_iterator::operator--(int)
+{
+ const_reverse_row_iterator tmp{*this};
+ operator--();
+ return tmp;
+}
diff --git a/contrib/libs/libpqxx/src/sql_cursor.cxx b/contrib/libs/libpqxx/src/sql_cursor.cxx
new file mode 100644
index 0000000000..2ebdb1304d
--- /dev/null
+++ b/contrib/libs/libpqxx/src/sql_cursor.cxx
@@ -0,0 +1,309 @@
+/** Implementation of libpqxx STL-style cursor classes.
+ *
+ * These classes wrap SQL cursors in STL-like interfaces.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <iterator>
+
+#include "pqxx/cursor"
+
+#include "pqxx/internal/encodings.hxx"
+#include "pqxx/internal/gates/connection-sql_cursor.hxx"
+#include "pqxx/internal/gates/transaction-sql_cursor.hxx"
+
+using namespace pqxx;
+using namespace pqxx::internal;
+
+
+namespace
+{
+/// Is this character a "useless trailing character" in a query?
+/** A character is "useless" at the end of a query if it is either whitespace or
+ * a semicolon.
+ */
+inline bool useless_trail(char c)
+{
+ return isspace(c) or c==';';
+}
+
+
+/// Find end of nonempty query, stripping off any trailing semicolon.
+/** When executing a normal query, a trailing semicolon is meaningless but
+ * won't hurt. That's why we can't rule out that some code may include one.
+ *
+ * But for cursor queries, a trailing semicolon is a problem. The query gets
+ * embedded in a larger statement, which a semicolon would break into two.
+ * We'll have to remove it if present.
+ *
+ * A trailing semicolon may not actually be at the end. It could be masked by
+ * subsequent whitespace. If there's also a comment though, that's the
+ * caller's own lookout. We can't guard against every possible mistake, and
+ * text processing is actually remarkably sensitive to mistakes in a
+ * multi-encoding world.
+ *
+ * If there is a trailing semicolon, this function returns its offset. If
+ * there are more than one, it returns the offset of the first one. If there
+ * is no trailing semicolon, it returns the length of the query string.
+ *
+ * The query must be nonempty.
+ */
+std::string::size_type find_query_end(
+ const std::string &query,
+ encoding_group enc)
+{
+ const auto text = query.c_str();
+ const auto size = query.size();
+ std::string::size_type end;
+ if (enc == encoding_group::MONOBYTE)
+ {
+ // This is an encoding where we can scan backwards from the end.
+ for (end = query.size(); end > 0 and useless_trail(text[end-1]); --end);
+ }
+ else
+ {
+ // Complex encoding. We only know how to iterate forwards, so start from
+ // the beginning.
+ end = 0;
+
+ pqxx::internal::for_glyphs(
+ enc,
+ [text, &end](const char *gbegin, const char *gend)
+ {
+ if (gend - gbegin > 1 or not useless_trail(*gbegin))
+ end = std::string::size_type(gend - text);
+ },
+ text, size);
+ }
+
+ return end;
+}
+} // namespace
+
+
+pqxx::internal::sql_cursor::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) :
+ cursor_base{t.conn(), cname},
+ m_home{t.conn()},
+ m_adopted{false},
+ m_at_end{-1},
+ m_pos{0}
+{
+ if (&t.conn() != &m_home) throw internal_error{"Cursor in wrong connection"};
+
+#include "pqxx/internal/ignore-deprecated-pre.hxx"
+ m_home.activate();
+#include "pqxx/internal/ignore-deprecated-post.hxx"
+
+ if (query.empty()) throw usage_error{"Cursor has empty query."};
+ const auto enc = enc_group(t.conn().encoding_id());
+ const auto qend = find_query_end(query, enc);
+ if (qend == 0) throw usage_error{"Cursor has effectively empty query."};
+
+ std::stringstream cq, qn;
+
+ cq << "DECLARE " << t.quote_name(name()) << " ";
+
+ if (format == result_format::binary) {
+ cq << "BINARY ";
+ }
+
+ if (ap == cursor_base::forward_only) cq << "NO ";
+ cq << "SCROLL ";
+
+ cq << "CURSOR ";
+
+ if (hold) cq << "WITH HOLD ";
+
+ cq << "FOR ";
+ cq.write(query.c_str(), std::streamsize(qend));
+ cq << ' ';
+
+ if (up != cursor_base::update) cq << "FOR READ ONLY ";
+ else cq << "FOR UPDATE ";
+
+ qn << "[DECLARE " << name() << ']';
+ t.exec(cq, qn.str());
+
+ // Now that we're here in the starting position, keep a copy of an empty
+ // result. That may come in handy later, because we may not be able to
+ // construct an empty result with all the right metadata due to the weird
+ // meaning of "FETCH 0."
+ init_empty_result(t);
+
+ // If we're creating a WITH HOLD cursor, noone is going to destroy it until
+ // after this transaction. That means the connection cannot be deactivated
+ // without losing the cursor.
+ if (hold)
+ gate::connection_sql_cursor{t.conn()}.add_reactivation_avoidance_count(1);
+
+ m_ownership = op;
+}
+
+
+pqxx::internal::sql_cursor::sql_cursor(
+ transaction_base &t,
+ const std::string &cname,
+ cursor_base::ownershippolicy op) :
+ cursor_base{t.conn(), cname, false},
+ m_home{t.conn()},
+ m_empty_result{},
+ m_adopted{true},
+ m_at_end{0},
+ m_pos{-1}
+{
+ // If we take responsibility for destroying the cursor, that's one less
+ // reason not to allow the connection to be deactivated and reactivated.
+ // TODO: Go over lifetime/reactivation rules again to be sure they work.
+ if (op==cursor_base::owned)
+ gate::connection_sql_cursor{t.conn()}.add_reactivation_avoidance_count(-1);
+ m_adopted = true;
+ m_ownership = op;
+}
+
+
+void pqxx::internal::sql_cursor::close() noexcept
+{
+ if (m_ownership==cursor_base::owned)
+ {
+ try
+ {
+ gate::connection_sql_cursor{m_home}.exec(
+ ("CLOSE " + m_home.quote_name(name())).c_str(),
+ 0);
+ }
+ catch (const std::exception &)
+ {
+ }
+
+ if (m_adopted)
+ gate::connection_sql_cursor{m_home}.add_reactivation_avoidance_count(-1);
+
+ m_ownership = cursor_base::loose;
+ }
+}
+
+
+void pqxx::internal::sql_cursor::init_empty_result(transaction_base &t)
+{
+ if (pos() != 0) throw internal_error{"init_empty_result() from bad pos()."};
+ m_empty_result = t.exec("FETCH 0 IN " + m_home.quote_name(name()));
+}
+
+
+/// Compute actual displacement based on requested and reported displacements.
+internal::sql_cursor::difference_type
+pqxx::internal::sql_cursor::adjust(difference_type hoped,
+ difference_type actual)
+{
+ if (actual < 0) throw internal_error{"Negative rows in cursor movement."};
+ if (hoped == 0) return 0;
+ const int direction = ((hoped < 0) ? -1 : 1);
+ bool hit_end = false;
+ if (actual != labs(hoped))
+ {
+ if (actual > labs(hoped))
+ throw internal_error{"Cursor displacement larger than requested."};
+
+ // If we see fewer rows than requested, then we've hit an end (on either
+ // side) of the result set. Wether we make an extra step to a one-past-end
+ // position or whether we're already there depends on where we were
+ // previously: if our last move was in the same direction and also fell
+ // short, we're already at a one-past-end row.
+ if (m_at_end != direction) ++actual;
+
+ // If we hit the beginning, make sure our position calculation ends up
+ // at zero (even if we didn't previously know where we were!), and if we
+ // hit the other end, register the fact that we now know where the end
+ // of the result set is.
+ if (direction > 0) hit_end = true;
+ else if (m_pos == -1) m_pos = actual;
+ else if (m_pos != actual)
+ throw internal_error{
+ "Moved back to beginning, but wrong position: "
+ "hoped=" + to_string(hoped) + ", "
+ "actual=" + to_string(actual) + ", "
+ "m_pos=" + to_string(m_pos) + ", "
+ "direction=" + to_string(direction) + "."};
+
+ m_at_end = direction;
+ }
+ else
+ {
+ m_at_end = 0;
+ }
+
+ if (m_pos >= 0) m_pos += direction*actual;
+ if (hit_end)
+ {
+ if (m_endpos >= 0 and m_pos != m_endpos)
+ throw internal_error{"Inconsistent cursor end positions."};
+ m_endpos = m_pos;
+ }
+ return direction*actual;
+}
+
+
+result pqxx::internal::sql_cursor::fetch(
+ difference_type rows,
+ difference_type &displacement)
+{
+ if (rows == 0)
+ {
+ displacement = 0;
+ return m_empty_result;
+ }
+ const std::string query =
+ "FETCH " + stridestring(rows) + " IN " + m_home.quote_name(name());
+ const result r{gate::connection_sql_cursor{m_home}.exec(query.c_str(), 0)};
+ displacement = adjust(rows, difference_type(r.size()));
+ return r;
+}
+
+
+cursor_base::difference_type pqxx::internal::sql_cursor::move(
+ difference_type rows,
+ difference_type &displacement)
+{
+ if (rows == 0)
+ {
+ displacement = 0;
+ return 0;
+ }
+
+ const std::string query =
+ "MOVE " + stridestring(rows) + " IN " + m_home.quote_name(name());
+ const result r(gate::connection_sql_cursor{m_home}.exec(query.c_str(), 0));
+ difference_type d = difference_type(r.affected_rows());
+ displacement = adjust(rows, d);
+ return d;
+}
+
+
+std::string pqxx::internal::sql_cursor::stridestring(difference_type n)
+{
+ /* Some special-casing for ALL and BACKWARD ALL here. We used to use numeric
+ * "infinities" for difference_type for this (the highest and lowest possible
+ * values for "long"), but for PostgreSQL 8.0 at least, the backend appears to
+ * expect a 32-bit number and fails to parse large 64-bit numbers.
+ * We could change the alias to match this behaviour, but that would break
+ * if/when Postgres is changed to accept 64-bit displacements.
+ */
+ static const std::string All{"ALL"}, BackAll{"BACKWARD ALL"};
+ if (n >= cursor_base::all()) return All;
+ else if (n <= cursor_base::backward_all()) return BackAll;
+ return to_string(n);
+}
diff --git a/contrib/libs/libpqxx/src/statement_parameters.cxx b/contrib/libs/libpqxx/src/statement_parameters.cxx
new file mode 100644
index 0000000000..3500cb04a9
--- /dev/null
+++ b/contrib/libs/libpqxx/src/statement_parameters.cxx
@@ -0,0 +1,58 @@
+/** Common implementation for statement parameter lists.
+ *
+ * See the connection_base hierarchy for more about prepared statements
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/util"
+
+#include "pqxx/internal/statement_parameters.hxx"
+
+
+void pqxx::internal::statement_parameters::add_checked_param(
+ const std::string &value,
+ bool nonnull,
+ bool binary)
+{
+ m_nonnull.push_back(nonnull);
+ if (nonnull) m_values.push_back(value);
+ m_binary.push_back(binary);
+}
+
+
+int pqxx::internal::statement_parameters::marshall(
+ std::vector<const char *> &values,
+ std::vector<int> &lengths,
+ std::vector<int> &binaries) const
+{
+ const auto elements = m_nonnull.size();
+ const auto array_size = elements + 1;
+ values.clear();
+ values.resize(array_size, nullptr);
+ lengths.clear();
+ lengths.resize(array_size, 0);
+ // "Unpack" from m_values, which skips arguments that are null, to the
+ // outputs which represent all parameters including nulls.
+ size_t arg = 0;
+ for (size_t param = 0; param < elements; ++param)
+ if (m_nonnull[param])
+ {
+ values[param] = m_values[arg].c_str();
+ lengths[param] = int(m_values[arg].size());
+ ++arg;
+ }
+
+ // The binaries array is simpler: it maps 1-on-1.
+ binaries.resize(array_size);
+ for (size_t param = 0; param < elements; ++param)
+ binaries[param] = int(m_binary[param]);
+ binaries.back() = 0;
+
+ return int(elements);
+}
diff --git a/contrib/libs/libpqxx/src/strconv.cxx b/contrib/libs/libpqxx/src/strconv.cxx
new file mode 100644
index 0000000000..9e67d55bb3
--- /dev/null
+++ b/contrib/libs/libpqxx/src/strconv.cxx
@@ -0,0 +1,724 @@
+/** Implementation of string conversions.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+#include <limits>
+#include <locale>
+#include <system_error>
+
+#if __cplusplus < 201703
+// This is not C++17 or better. Don't use to_chars/from_chars; the code which
+// uses those also relies on other C++17 features.
+#if defined(PQXX_HAVE_CHARCONV_INT)
+#undef PQXX_HAVE_CHARCONV_INT
+#endif
+#if defined(PQXX_HAVE_CHARCONV_FLOAT)
+#undef PQXX_HAVE_CHARCONV_FLOAT
+#endif
+#endif
+
+#if defined(PQXX_HAVE_CHARCONV_INT) || defined(PQXX_HAVE_CHARCONV_FLOAT)
+#include <charconv>
+#endif
+
+#if __cplusplus >= 201703
+#include <string_view>
+#endif
+
+#include "pqxx/except"
+#include "pqxx/strconv"
+
+
+using namespace pqxx::internal;
+
+
+namespace
+{
+/// C string comparison.
+inline bool equal(const char lhs[], const char rhs[])
+{
+ return strcmp(lhs, rhs) == 0;
+}
+} // namespace
+
+
+namespace pqxx
+{
+namespace internal
+{
+void throw_null_conversion(const std::string &type)
+{
+ throw conversion_error{"Attempt to convert null to " + type + "."};
+}
+} // namespace pqxx::internal
+} // namespace pqxx
+
+
+#if defined(PQXX_HAVE_CHARCONV_INT) || defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace
+{
+template<typename T> void wrap_from_chars(std::string_view in, T &out)
+{
+ using traits = pqxx::string_traits<T>;
+ const char *end = in.data() + in.size();
+ const auto res = std::from_chars(in.data(), end, out);
+ if (res.ec == std::errc() and res.ptr == end) return;
+
+ std::string msg;
+ if (res.ec == std::errc())
+ {
+ msg = "Could not parse full string.";
+ }
+ else switch (res.ec)
+ {
+ case std::errc::result_out_of_range:
+ msg = "Value out of range.";
+ break;
+ case std::errc::invalid_argument:
+ msg = "Invalid argument.";
+ break;
+ default:
+ break;
+ }
+
+ const std::string base =
+ "Could not convert '" + std::string(in) + "' "
+ "to " + traits::name();
+ if (msg.empty()) throw pqxx::conversion_error{base + "."};
+ else throw pqxx::conversion_error{base + ": " + msg};
+}
+
+
+/// How big of a buffer do we want for representing a T?
+template<typename T> constexpr int size_buffer()
+{
+ using lim = std::numeric_limits<T>;
+ // Allocate room for how many digits? There's "max_digits10" for
+ // floating-point numbers, but only "digits10" for integer types.
+ constexpr auto digits = std::max({lim::digits10, lim::max_digits10});
+ // Leave a little bit of extra room for signs, decimal points, and the like.
+ return digits + 4;
+}
+
+
+/// Call @c std::to_chars. It differs for integer vs. floating-point types.
+template<typename TYPE, bool INTEGRAL> struct to_chars_caller;
+
+#if defined(PQXX_HAVE_CHARCONV_INT)
+/// For integer types, we pass "base 10" to @c std::to_chars.
+template<typename TYPE> struct to_chars_caller<TYPE, true>
+{
+ static std::to_chars_result call(char *begin, char *end, TYPE in)
+ { return std::to_chars(begin, end, in, 10); }
+};
+#endif
+
+#if defined(PQXX_HAVE_CHARCONV_FLOAT)
+/// For floating-point types, we pass "general format" to @c std::to_chars.
+template<typename TYPE>
+template<typename TYPE> struct to_chars_caller<TYPE, true>
+{
+ static std::to_chars_result call(char *begin, char *end, TYPE in)
+ { return std::to_chars(begin, end, in, std::chars_format::general); }
+};
+#endif
+} // namespace
+
+
+namespace pqxx
+{
+namespace internal
+{
+template<typename T> std::string builtin_traits<T>::to_string(T in)
+{
+ using traits = pqxx::string_traits<T>;
+ char buf[size_buffer<T>()];
+
+ // Annoying: we need to make slightly different calls to std::to_chars
+ // depending on whether this is an integral type or a floating-point type.
+ // Use to_chars_caller to hide the difference.
+ constexpr bool is_integer = std::numeric_limits<T>::is_integer;
+ const auto res = to_chars_caller<T, is_integer>::call(
+ buf, buf + sizeof(buf), in);
+ if (res.ec == std::errc()) return std::string(buf, res.ptr);
+
+ std::string msg;
+ switch (res.ec)
+ {
+ case std::errc::value_too_large:
+ msg = "Value too large.";
+ break;
+ default:
+ break;
+ }
+
+ const std::string base =
+ std::string{"Could not convert "} + traits::name() + " to string";
+ if (msg.empty()) throw pqxx::conversion_error{base + "."};
+ else throw pqxx::conversion_error{base + ": " + msg};
+}
+
+
+/// Translate @c from_string calls to @c wrap_from_chars calls.
+/** The only difference is the type of the string.
+ */
+template<typename TYPE>
+void builtin_traits<TYPE>::from_string(const char Str[], TYPE &Obj)
+ { wrap_from_chars(std::string_view{Str}, Obj); }
+} // namespace pqxx::internal
+} // namespace pqxx
+#endif // PQXX_HAVE_CHARCONV_INT || PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace
+{
+template<typename T> inline void set_to_Inf(T &t, int sign=1)
+{
+ T value = std::numeric_limits<T>::infinity();
+ if (sign < 0) value = -value;
+ t = value;
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_INT)
+namespace
+{
+[[noreturn]] void report_overflow()
+{
+ throw pqxx::conversion_error{
+ "Could not convert string to integer: value out of range."};
+}
+
+
+/** Helper to check for underflow before multiplying a number by 10.
+ *
+ * Needed just so the compiler doesn't get to complain about an "if (n < 0)"
+ * clause that's pointless for unsigned numbers.
+ */
+template<typename T, bool is_signed> struct underflow_check;
+
+/* Specialization for signed types: check.
+ */
+template<typename T> struct underflow_check<T, true>
+{
+ static void check_before_adding_digit(T n)
+ {
+ constexpr T ten{10};
+ if (n < 0 and (std::numeric_limits<T>::min() / ten) > n) report_overflow();
+ }
+};
+
+/* Specialization for unsigned types: no check needed becaue negative
+ * numbers don't exist.
+ */
+template<typename T> struct underflow_check<T, false>
+{
+ static void check_before_adding_digit(T) {}
+};
+
+
+/// Return 10*n, or throw exception if it overflows.
+template<typename T> T safe_multiply_by_ten(T n)
+{
+ using limits = std::numeric_limits<T>;
+ constexpr T ten{10};
+ if (n > 0 and (limits::max() / n) < ten) report_overflow();
+ underflow_check<T, limits::is_signed>::check_before_adding_digit(n);
+ return T(n * ten);
+}
+
+
+/// Add a digit d to n, or throw exception if it overflows.
+template<typename T> T safe_add_digit(T n, T d)
+{
+ assert((n >= 0 and d >= 0) or (n <=0 and d <= 0));
+ if ((n > 0) and (n > (std::numeric_limits<T>::max() - d))) report_overflow();
+ if ((n < 0) and (n < (std::numeric_limits<T>::min() - d))) report_overflow();
+ return n + d;
+}
+
+
+/// For use in string parsing: add new numeric digit to intermediate value
+template<typename L, typename R>
+ inline L absorb_digit(L value, R digit)
+{
+ return L(safe_multiply_by_ten(value) + L(digit));
+}
+
+
+template<typename T> void from_string_signed(const char Str[], T &Obj)
+{
+ int i = 0;
+ T result = 0;
+
+ if (not isdigit(Str[i]))
+ {
+ if (Str[i] != '-')
+ throw pqxx::conversion_error{
+ "Could not convert string to integer: '" + std::string{Str} + "'."};
+
+ for (++i; isdigit(Str[i]); ++i)
+ result = absorb_digit(result, -digit_to_number(Str[i]));
+ }
+ else
+ {
+ for (; isdigit(Str[i]); ++i)
+ result = absorb_digit(result, digit_to_number(Str[i]));
+ }
+
+ if (Str[i])
+ throw pqxx::conversion_error{
+ "Unexpected text after integer: '" + std::string{Str} + "'."};
+
+ Obj = result;
+}
+
+template<typename T> void from_string_unsigned(const char Str[], T &Obj)
+{
+ int i = 0;
+ T result = 0;
+
+ if (not isdigit(Str[i]))
+ throw pqxx::conversion_error{
+ "Could not convert string to unsigned integer: '" +
+ std::string{Str} + "'."};
+
+ for (; isdigit(Str[i]); ++i)
+ result = absorb_digit(result, digit_to_number(Str[i]));
+
+ if (Str[i])
+ throw pqxx::conversion_error{
+ "Unexpected text after integer: '" + std::string{Str} + "'."};
+
+ Obj = result;
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_INT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace
+{
+bool valid_infinity_string(const char str[]) noexcept
+{
+ return
+ equal("infinity", str) or
+ equal("Infinity", str) or
+ equal("INFINITY", str) or
+ equal("inf", str);
+}
+
+
+/// Wrapper for std::stringstream with C locale.
+/** Some of our string conversions use the standard library. But, they must
+ * _not_ obey the system's locale settings, or a value like 1000.0 might end
+ * up looking like "1.000,0".
+ *
+ * Initialising the stream (including locale and tweaked precision) seems to
+ * be expensive though. So, create thread-local instances which we re-use.
+ * It's a lockless way of keeping global variables thread-safe, basically.
+ *
+ * The stream initialisation happens once per thread, in the constructor.
+ * And that's why we need to wrap this in a class. We can't just do it at the
+ * call site, or we'd still be doing it for every call.
+ */
+template<typename T> class dumb_stringstream : public std::stringstream
+{
+public:
+ // Do not initialise the base-class object using "stringstream{}" (with curly
+ // braces): that breaks on Visual C++. The classic "stringstream()" syntax
+ // (with parentheses) does work.
+ dumb_stringstream()
+ {
+ this->imbue(std::locale::classic());
+ this->precision(std::numeric_limits<T>::max_digits10);
+ }
+};
+
+
+/* These are hard. Sacrifice performance of specialized, nonflexible,
+ * non-localized code and lean on standard library. Some special-case code
+ * handles NaNs.
+ */
+template<typename T> inline void from_string_float(const char Str[], T &Obj)
+{
+ bool ok = false;
+ T result;
+
+ switch (Str[0])
+ {
+ case 'N':
+ case 'n':
+ // Accept "NaN," "nan," etc.
+ ok = (
+ (Str[1]=='A' or Str[1]=='a') and
+ (Str[2]=='N' or Str[2]=='n') and
+ (Str[3] == '\0'));
+ result = std::numeric_limits<T>::quiet_NaN();
+ break;
+
+ case 'I':
+ case 'i':
+ ok = valid_infinity_string(Str);
+ set_to_Inf(result);
+ break;
+
+ default:
+ if (Str[0] == '-' and valid_infinity_string(&Str[1]))
+ {
+ ok = true;
+ set_to_Inf(result, -1);
+ }
+ else
+ {
+ thread_local dumb_stringstream<T> S;
+ // Visual Studio 2017 seems to fail on repeated conversions if the
+ // clear() is done before the seekg(). Still don't know why! See #124
+ // and #125.
+ S.seekg(0);
+ S.clear();
+ S.str(Str);
+ ok = static_cast<bool>(S >> result);
+ }
+ break;
+ }
+
+ if (not ok)
+ throw pqxx::conversion_error{
+ "Could not convert string to numeric value: '" +
+ std::string{Str} + "'."};
+
+ Obj = result;
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_INT)
+namespace
+{
+template<typename T> inline std::string to_string_unsigned(T Obj)
+{
+ if (not Obj) return "0";
+
+ // Every byte of width on T adds somewhere between 3 and 4 digits to the
+ // maximum length of our decimal string.
+ char buf[4*sizeof(T)+1];
+
+ char *p = &buf[sizeof(buf)];
+ *--p = '\0';
+ while (Obj > 0)
+ {
+ *--p = number_to_digit(int(Obj%10));
+ Obj = T(Obj / 10);
+ }
+ return p;
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_INT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_INT) || !defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace
+{
+template<typename T> inline std::string to_string_fallback(T Obj)
+{
+ thread_local dumb_stringstream<T> S;
+ S.str("");
+ S << Obj;
+ return S.str();
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_INT || !PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace
+{
+template<typename T> inline std::string to_string_float(T Obj)
+{
+ if (std::isnan(Obj)) return "nan";
+ if (std::isinf(Obj)) return Obj > 0 ? "infinity" : "-infinity";
+ return to_string_fallback(Obj);
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_INT)
+namespace
+{
+template<typename T> inline std::string to_string_signed(T Obj)
+{
+ if (Obj < 0)
+ {
+ // Remember--the smallest negative number for a given two's-complement type
+ // cannot be negated.
+ const bool negatable = (Obj != std::numeric_limits<T>::min());
+ if (negatable)
+ return '-' + to_string_unsigned(-Obj);
+ else
+ return to_string_fallback(Obj);
+ }
+
+ return to_string_unsigned(Obj);
+}
+} // namespace
+#endif // !PQXX_HAVE_CHARCONV_INT
+
+
+#if defined(PQXX_HAVE_CHARCONV_INT)
+namespace pqxx
+{
+template void
+builtin_traits<short>::from_string(const char[], short &);
+template void
+builtin_traits<unsigned short>::from_string(const char[], unsigned short &);
+template void
+builtin_traits<int>::from_string(const char[], int &);
+template void
+builtin_traits<unsigned int>::from_string(const char[], unsigned int &);
+template void
+builtin_traits<long>::from_string(const char[], long &);
+template void
+builtin_traits<unsigned long>::from_string(const char[], unsigned long &);
+template void
+builtin_traits<long long>::from_string(const char[], long long &);
+template void
+builtin_traits<unsigned long long>::from_string(
+ const char[], unsigned long long &);
+} // namespace pqxx
+#endif // PQXX_HAVE_CHARCONV_INT
+
+
+#if defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace pqxx
+{
+template
+void string_traits<float>::from_string(const char Str[], float &Obj);
+template
+void string_traits<double>::from_string(const char Str[], double &Obj);
+template
+void string_traits<long double>::from_string(
+ const char Str[],
+ long double &Obj);
+} // namespace pqxx
+#endif // PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if defined(PQXX_HAVE_CHARCONV_INT)
+namespace pqxx
+{
+namespace internal
+{
+template
+std::string builtin_traits<short>::to_string(short Obj);
+template
+std::string builtin_traits<unsigned short>::to_string(unsigned short Obj);
+template
+std::string builtin_traits<int>::to_string(int Obj);
+template
+std::string builtin_traits<unsigned int>::to_string(unsigned int Obj);
+template
+std::string builtin_traits<long>::to_string(long Obj);
+template
+std::string builtin_traits<unsigned long>::to_string(unsigned long Obj);
+template
+std::string builtin_traits<long long>::to_string(long long Obj);
+template
+std::string builtin_traits<unsigned long long>::to_string(
+ unsigned long long Obj);
+} // namespace pqxx::internal
+} // namespace pqxx
+#endif // PQXX_HAVE_CHARCONV_INT
+
+
+#if defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace pqxx
+{
+namespace internal
+{
+template
+std::string builtin_traits<float>::to_string(float Obj);
+template
+std::string builtin_traits<double>::to_string(double Obj);
+template
+std::string builtin_traits<long double>::to_string(long double Obj);
+} // namespace pqxx::internal
+} // namespace pqxx
+#endif // PQXX_HAVE_CHARCONV_FLOAT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_INT)
+namespace pqxx
+{
+namespace internal
+{
+template<>
+void builtin_traits<short>::from_string(const char Str[], short &Obj)
+ { from_string_signed(Str, Obj); }
+template<>
+std::string builtin_traits<short>::to_string(short Obj)
+ { return to_string_signed(Obj); }
+template<>
+void builtin_traits<unsigned short>::from_string(
+ const char Str[],
+ unsigned short &Obj)
+ { from_string_unsigned(Str, Obj); }
+template<>
+std::string builtin_traits<unsigned short>::to_string(unsigned short Obj)
+ { return to_string_unsigned(Obj); }
+template<>
+void builtin_traits<int>::from_string(const char Str[], int &Obj)
+ { from_string_signed(Str, Obj); }
+template<>
+std::string builtin_traits<int>::to_string(int Obj)
+ { return to_string_signed(Obj); }
+template<>
+void builtin_traits<unsigned int>::from_string(
+ const char Str[],
+ unsigned int &Obj)
+ { from_string_unsigned(Str, Obj); }
+template<>
+std::string builtin_traits<unsigned int>::to_string(unsigned int Obj)
+ { return to_string_unsigned(Obj); }
+template<>
+void builtin_traits<long>::from_string(const char Str[], long &Obj)
+ { from_string_signed(Str, Obj); }
+template<>
+std::string builtin_traits<long>::to_string(long Obj)
+ { return to_string_signed(Obj); }
+template<>
+void builtin_traits<unsigned long>::from_string(
+ const char Str[],
+ unsigned long &Obj)
+ { from_string_unsigned(Str, Obj); }
+template<>
+std::string builtin_traits<unsigned long>::to_string(unsigned long Obj)
+ { return to_string_unsigned(Obj); }
+template<>
+void builtin_traits<long long>::from_string(const char Str[], long long &Obj)
+ { from_string_signed(Str, Obj); }
+template<>
+std::string builtin_traits<long long>::to_string(long long Obj)
+ { return to_string_signed(Obj); }
+template<>
+void builtin_traits<unsigned long long>::from_string(
+ const char Str[],
+ unsigned long long &Obj)
+ { from_string_unsigned(Str, Obj); }
+template<>
+std::string builtin_traits<unsigned long long>::to_string(
+ unsigned long long Obj)
+ { return to_string_unsigned(Obj); }
+} // namespace pqxx::internal
+} // namespace pqxx
+#endif // !PQXX_HAVE_CHARCONV_INT
+
+
+#if !defined(PQXX_HAVE_CHARCONV_FLOAT)
+namespace pqxx
+{
+namespace internal
+{
+template<>
+void builtin_traits<float>::from_string(const char Str[], float &Obj)
+ { from_string_float(Str, Obj); }
+template<>
+std::string builtin_traits<float>::to_string(float Obj)
+ { return to_string_float(Obj); }
+template<>
+void builtin_traits<double>::from_string(const char Str[], double &Obj)
+ { from_string_float(Str, Obj); }
+template<>
+std::string builtin_traits<double>::to_string(double Obj)
+ { return to_string_float(Obj); }
+template<>
+void builtin_traits<long double>::from_string(
+ const char Str[], long double &Obj)
+ { from_string_float(Str, Obj); }
+template<>
+std::string builtin_traits<long double>::to_string(long double Obj)
+ { return to_string_float(Obj); }
+} // namespace pqxx::internal
+} // namespace pqxx
+#endif // !PQXX_HAVE_CHARCONV_FLOAT
+
+
+namespace pqxx
+{
+namespace internal
+{
+template<> void builtin_traits<bool>::from_string(const char Str[], bool &Obj)
+{
+ bool OK, result=false;
+
+ switch (Str[0])
+ {
+ case 0:
+ result = false;
+ OK = true;
+ break;
+
+ case 'f':
+ case 'F':
+ result = false;
+ OK = not (
+ (Str[1] != '\0') and
+ (not equal(Str+1, "alse")) and
+ (not equal(Str+1, "ALSE")));
+ break;
+
+ case '0':
+ {
+ int I;
+ string_traits<int>::from_string(Str, I);
+ result = (I != 0);
+ OK = ((I == 0) or (I == 1));
+ }
+ break;
+
+ case '1':
+ result = true;
+ OK = (Str[1] == '\0');
+ break;
+
+ case 't':
+ case 'T':
+ result = true;
+ OK = not (
+ (Str[1] != '\0') and
+ (not equal(Str+1, "rue")) and
+ (not equal(Str+1, "RUE")));
+ break;
+
+ default:
+ OK = false;
+ }
+
+ if (not OK)
+ throw conversion_error{
+ "Failed conversion to bool: '" + std::string{Str} + "'."};
+
+ Obj = result;
+}
+
+
+template<> std::string builtin_traits<bool>::to_string(bool Obj)
+{
+ return Obj ? "true" : "false";
+}
+} // namespace pqxx::internal
+} // namespace pqxx
diff --git a/contrib/libs/libpqxx/src/stream_base.cxx b/contrib/libs/libpqxx/src/stream_base.cxx
new file mode 100644
index 0000000000..598c2260e4
--- /dev/null
+++ b/contrib/libs/libpqxx/src/stream_base.cxx
@@ -0,0 +1,43 @@
+/** Implementation of the pqxx::stream_base class.
+ *
+ * pqxx::stream_base provides optimized batch access to a database table.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/stream_base.hxx"
+#include "pqxx/transaction"
+
+
+pqxx::stream_base::stream_base(transaction_base &tb) :
+ internal::namedclass("stream_base"),
+ internal::transactionfocus{tb},
+ m_finished{false}
+{}
+
+
+pqxx::stream_base::operator bool() const noexcept
+{
+ return not m_finished;
+}
+
+
+bool pqxx::stream_base::operator!() const noexcept
+{
+ return not static_cast<bool>(*this);
+}
+
+
+void pqxx::stream_base::close()
+{
+ if (*this)
+ {
+ m_finished = true;
+ unregister_me();
+ }
+}
diff --git a/contrib/libs/libpqxx/src/stream_from.cxx b/contrib/libs/libpqxx/src/stream_from.cxx
new file mode 100644
index 0000000000..8dbe2df3f3
--- /dev/null
+++ b/contrib/libs/libpqxx/src/stream_from.cxx
@@ -0,0 +1,261 @@
+/** Implementation of the pqxx::stream_from class.
+ *
+ * pqxx::stream_from enables optimized batch reads from a database table.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/stream_from"
+
+#include "pqxx/internal/encodings.hxx"
+#include "pqxx/internal/gates/transaction-stream_from.hxx"
+
+
+namespace
+{
+ // bool is_octalchar(char o) noexcept
+ // {
+ // return (o>='0') and (o<='7');
+ // }
+
+ /// Find first tab character at or after start position in string
+ /** If not found, returns line.size() rather than string::npos.
+ */
+ std::string::size_type find_tab(
+ pqxx::internal::encoding_group enc,
+ const std::string &line,
+ std::string::size_type start
+ )
+ {
+ auto here = pqxx::internal::find_with_encoding(enc, line, '\t', start);
+ return (here == std::string::npos) ? line.size() : here;
+ }
+} // namespace
+
+
+pqxx::stream_from::stream_from(
+ transaction_base &tb,
+ const std::string &table_name
+) :
+ namedclass{"stream_from", table_name},
+ stream_base{tb},
+ m_retry_line{false}
+{
+ set_up(tb, table_name);
+}
+
+
+pqxx::stream_from::~stream_from() noexcept
+{
+ try
+ {
+ complete();
+ }
+ catch (const std::exception &e)
+ {
+ reg_pending_error(e.what());
+ }
+}
+
+
+void pqxx::stream_from::complete()
+{
+ close();
+}
+
+
+bool pqxx::stream_from::get_raw_line(std::string &line)
+{
+ internal::gate::transaction_stream_from gate{m_trans};
+ if (*this)
+ try
+ {
+ if (not gate.read_copy_line(line)) close();
+ }
+ catch (const std::exception &)
+ {
+ close();
+ throw;
+ }
+ return *this;
+}
+
+
+void pqxx::stream_from::set_up(
+ transaction_base &tb,
+ const std::string &table_name
+)
+{
+ set_up(tb, table_name, "");
+}
+
+
+void pqxx::stream_from::set_up(
+ transaction_base &tb,
+ const std::string &table_name,
+ const std::string &columns
+)
+{
+ // Get the encoding before starting the COPY, otherwise reading the the
+ // variable will interrupt it
+ m_copy_encoding = internal::enc_group(m_trans.conn().encoding_id());
+ internal::gate::transaction_stream_from{tb}.BeginCopyRead(
+ table_name,
+ columns
+ );
+ register_me();
+}
+
+
+void pqxx::stream_from::close()
+{
+ pqxx::stream_base::close();
+ try
+ {
+ // Flush any remaining lines
+ std::string s;
+ while (get_raw_line(s));
+ }
+ catch (const broken_connection &)
+ {
+ try
+ {
+ pqxx::stream_base::close();
+ }
+ catch (const std::exception &) {}
+ throw;
+ }
+ catch (const std::exception &e)
+ {
+ reg_pending_error(e.what());
+ }
+}
+
+
+bool pqxx::stream_from::extract_field(
+ const std::string &line,
+ std::string::size_type &i,
+ std::string &s
+) const
+{
+ using namespace pqxx::internal;
+
+ const auto next_seq = get_glyph_scanner(m_copy_encoding);
+ s.clear();
+ bool is_null{false};
+ auto stop = find_tab(m_copy_encoding, line, i);
+ while (i < stop)
+ {
+ auto glyph_end = next_seq(line.c_str(), line.size(), i);
+ auto seq_len = glyph_end - i;
+ if (seq_len == 1)
+ {
+ switch (line[i])
+ {
+ case '\n':
+ // End-of-row; shouldn't happen, but we may get old-style
+ // newline-terminated lines.
+ i = stop;
+ break;
+
+ case '\\':
+ {
+ // Escape sequence.
+ if (glyph_end >= line.size())
+ throw failure{"Row ends in backslash"};
+ char n = line[glyph_end++];
+
+ /*
+ * "Presently, COPY TO will never emit an octal or hex-digits
+ * backslash sequence [...]"
+ * - https://www.postgresql.org/docs/10/sql-copy.html
+ */
+ // if (is_octalchar(n))
+ // {
+ // if (here.end_byte+2 >= line.size())
+ // throw failure{"Row ends in middle of octal value"};
+ // char n1 = line[here.end_byte++];
+ // char n2 = line[here.end_byte++];
+ // if (not is_octalchar(n1) or not is_octalchar(n2))
+ // throw failure{
+ // "Invalid octal in encoded table stream"
+ // };
+ // s += (
+ // (digit_to_number(n)<<6) |
+ // (digit_to_number(n1)<<3) |
+ // digit_to_number(n2)
+ // );
+ // break;
+ // }
+ // else
+ switch (n)
+ {
+ case 'N':
+ // Null value
+ if (not s.empty())
+ throw failure{
+ "Null sequence found in nonempty field"
+ };
+ is_null = true;
+ break;
+
+ case 'b': // Backspace
+ s += '\b'; break;
+ case 'f': // Vertical tab
+ s += '\f'; break;
+ case 'n': // Form feed
+ s += '\n'; break;
+ case 'r': // Newline
+ s += '\r'; break;
+ case 't': // Tab
+ s += '\t'; break;
+ case 'v': // Carriage return
+ s += '\v'; break;
+
+ default:
+ // Self-escaped character
+ s += n;
+ break;
+ }
+ }
+ break;
+
+ default:
+ s += line[i];
+ break;
+ }
+ }
+ else
+ {
+ // Multi-byte sequence; never treated specially, so just append
+ s.insert(s.size(), line.c_str() + i, seq_len);
+ }
+
+ i = glyph_end;
+ }
+
+ // Skip field separator
+ i += 1;
+
+ return not is_null;
+}
+
+template<> void pqxx::stream_from::extract_value<std::nullptr_t>(
+ const std::string &line,
+ std::nullptr_t&,
+ std::string::size_type &here,
+ std::string &workspace
+) const
+{
+ if (extract_field(line, here, workspace))
+ throw pqxx::conversion_error{
+ "Attempt to convert non-null '"
+ + workspace
+ + "' to null"
+ };
+}
diff --git a/contrib/libs/libpqxx/src/stream_to.cxx b/contrib/libs/libpqxx/src/stream_to.cxx
new file mode 100644
index 0000000000..18e52b1e6a
--- /dev/null
+++ b/contrib/libs/libpqxx/src/stream_to.cxx
@@ -0,0 +1,142 @@
+/** Implementation of the pqxx::stream_to class.
+ *
+ * pqxx::stream_to enables optimized batch updates to a database table.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/stream_to.hxx"
+
+#include "pqxx/internal/gates/transaction-stream_to.hxx"
+
+
+pqxx::stream_to::stream_to(
+ transaction_base &tb,
+ const std::string &table_name
+) :
+ namedclass{"stream_to", table_name},
+ stream_base{tb}
+{
+ set_up(tb, table_name);
+}
+
+
+pqxx::stream_to::~stream_to() noexcept
+{
+ try
+ {
+ complete();
+ }
+ catch (const std::exception &e)
+ {
+ reg_pending_error(e.what());
+ }
+}
+
+
+void pqxx::stream_to::complete()
+{
+ close();
+}
+
+
+void pqxx::stream_to::write_raw_line(const std::string &line)
+{
+ internal::gate::transaction_stream_to{m_trans}.write_copy_line(line);
+}
+
+
+pqxx::stream_to & pqxx::stream_to::operator<<(stream_from &tr)
+{
+ std::string line;
+ while (tr)
+ {
+ tr.get_raw_line(line);
+ write_raw_line(line);
+ }
+ return *this;
+}
+
+
+void pqxx::stream_to::set_up(
+ transaction_base &tb,
+ const std::string &table_name
+)
+{
+ set_up(tb, table_name, "");
+}
+
+
+void pqxx::stream_to::set_up(
+ transaction_base &tb,
+ const std::string &table_name,
+ const std::string &columns
+)
+{
+ internal::gate::transaction_stream_to{tb}.BeginCopyWrite(
+ table_name,
+ columns
+ );
+ register_me();
+}
+
+
+void pqxx::stream_to::close()
+{
+ if (*this)
+ {
+ stream_base::close();
+ try
+ {
+ internal::gate::transaction_stream_to{m_trans}.end_copy_write();
+ }
+ catch (const std::exception &)
+ {
+ try
+ {
+ stream_base::close();
+ }
+ catch (const std::exception &) {}
+ throw;
+ }
+ }
+}
+
+
+std::string pqxx::internal::TypedCopyEscaper::escape(const std::string &s)
+{
+ if (s.empty())
+ return s;
+
+ std::string escaped;
+ escaped.reserve(s.size()+1);
+
+ for (auto c : s)
+ switch (c)
+ {
+ case '\b': escaped += "\\b"; break; // Backspace
+ case '\f': escaped += "\\f"; break; // Vertical tab
+ case '\n': escaped += "\\n"; break; // Form feed
+ case '\r': escaped += "\\r"; break; // Newline
+ case '\t': escaped += "\\t"; break; // Tab
+ case '\v': escaped += "\\v"; break; // Carriage return
+ case '\\': escaped += "\\\\"; break; // Backslash
+ default:
+ if (c < ' ' or c > '~')
+ {
+ escaped += "\\";
+ for (auto i = 2; i >= 0; --i)
+ escaped += number_to_digit((c >> (3*i)) & 0x07);
+ }
+ else
+ escaped += c;
+ break;
+ }
+
+ return escaped;
+}
diff --git a/contrib/libs/libpqxx/src/subtransaction.cxx b/contrib/libs/libpqxx/src/subtransaction.cxx
new file mode 100644
index 0000000000..539c3c7847
--- /dev/null
+++ b/contrib/libs/libpqxx/src/subtransaction.cxx
@@ -0,0 +1,74 @@
+/** Implementation of the pqxx::subtransaction class.
+ *
+ * pqxx::transaction is a nested transaction, i.e. one within a transaction
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <stdexcept>
+
+#include "pqxx/connection_base"
+#include "pqxx/subtransaction"
+
+#include "pqxx/internal/gates/transaction-subtransaction.hxx"
+
+using namespace pqxx::internal;
+
+
+pqxx::subtransaction::subtransaction(
+ dbtransaction &T,
+ const std::string &Name) :
+ namedclass{"subtransaction", T.conn().adorn_name(Name)},
+ transactionfocus{T},
+ dbtransaction(T.conn(), false),
+ m_parent{T}
+{
+}
+
+
+namespace
+{
+using dbtransaction_ref = pqxx::dbtransaction &;
+}
+
+
+pqxx::subtransaction::subtransaction(
+ subtransaction &T,
+ const std::string &Name) :
+ subtransaction(dbtransaction_ref(T), Name)
+{
+}
+
+
+void pqxx::subtransaction::do_begin()
+{
+ try
+ {
+ direct_exec(("SAVEPOINT " + quote_name(name())).c_str());
+ }
+ catch (const sql_error &)
+ {
+ throw;
+ }
+}
+
+
+void pqxx::subtransaction::do_commit()
+{
+ const int ra = m_reactivation_avoidance.get();
+ m_reactivation_avoidance.clear();
+ direct_exec(("RELEASE SAVEPOINT " + quote_name(name())).c_str());
+ gate::transaction_subtransaction{m_parent}.add_reactivation_avoidance_count(
+ ra);
+}
+
+
+void pqxx::subtransaction::do_abort()
+{
+ direct_exec(("ROLLBACK TO SAVEPOINT " + quote_name(name())).c_str());
+}
diff --git a/contrib/libs/libpqxx/src/tablereader.cxx b/contrib/libs/libpqxx/src/tablereader.cxx
new file mode 100644
index 0000000000..4e4f315c66
--- /dev/null
+++ b/contrib/libs/libpqxx/src/tablereader.cxx
@@ -0,0 +1,227 @@
+/** Implementation of the pqxx::tablereader class.
+ *
+ * pqxx::tablereader enables optimized batch reads from a database table.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/tablereader"
+#include "pqxx/transaction"
+
+#include "pqxx/internal/gates/transaction-tablereader.hxx"
+
+using namespace pqxx::internal;
+
+
+pqxx::tablereader::tablereader(
+ transaction_base &T,
+ const std::string &Name,
+ const std::string &Null) :
+ namedclass{"tablereader", Name},
+ tablestream(T, Null),
+ m_done{true}
+{
+ set_up(T, Name);
+}
+
+void pqxx::tablereader::set_up(
+ transaction_base &T,
+ const std::string &Name,
+ const std::string &Columns)
+{
+ gate::transaction_tablereader{T}.BeginCopyRead(Name, Columns);
+ register_me();
+ m_done = false;
+}
+
+pqxx::tablereader::~tablereader() noexcept
+{
+ try
+ {
+ reader_close();
+ }
+ catch (const std::exception &e)
+ {
+ reg_pending_error(e.what());
+ }
+}
+
+
+bool pqxx::tablereader::get_raw_line(std::string &Line)
+{
+ if (not m_done) try
+ {
+ m_done = not gate::transaction_tablereader{m_trans}.read_copy_line(Line);
+ }
+ catch (const std::exception &)
+ {
+ m_done = true;
+ throw;
+ }
+ return not m_done;
+}
+
+
+void pqxx::tablereader::complete()
+{
+ reader_close();
+}
+
+
+void pqxx::tablereader::reader_close()
+{
+ if (not is_finished())
+ {
+ base_close();
+
+ // If any lines remain to be read, consume them to not confuse PQendcopy()
+ if (not m_done)
+ {
+ try
+ {
+ std::string Dummy;
+ while (get_raw_line(Dummy)) ;
+ }
+ catch (const broken_connection &)
+ {
+ try { base_close(); } catch (const std::exception &) {}
+ throw;
+ }
+ catch (const std::exception &e)
+ {
+ reg_pending_error(e.what());
+ }
+ }
+ }
+}
+
+
+namespace
+{
+inline bool is_octalchar(char o) noexcept
+{
+ return (o>='0') and (o<='7');
+}
+
+/// Find first tab character at or after start position in string
+/** If not found, returns Line.size() rather than string::npos.
+ */
+std::string::size_type findtab(
+ const std::string &Line,
+ std::string::size_type start)
+{
+ // TODO: Fix for multibyte encodings?
+ const auto here = Line.find('\t', start);
+ return (here == std::string::npos) ? Line.size() : here;
+}
+} // namespace
+
+
+std::string pqxx::tablereader::extract_field(
+ const std::string &Line,
+ std::string::size_type &i) const
+{
+ // TODO: Pick better exception types
+ std::string R;
+ bool isnull=false;
+ auto stop = findtab(Line, i);
+ for (; i < stop; ++i)
+ {
+ const char c = Line[i];
+ switch (c)
+ {
+ case '\n': // End of row
+ // Shouldn't happen, but we may get old-style, newline-terminated lines
+ i = stop;
+ break;
+
+ case '\\': // Escape sequence
+ {
+ const char n = Line[++i];
+ if (i >= Line.size())
+ throw failure{"Row ends in backslash."};
+
+ switch (n)
+ {
+ case 'N': // Null value
+ if (not R.empty())
+ throw failure{"Null sequence found in nonempty field."};
+ R = NullStr();
+ isnull = true;
+ break;
+
+ case '0': // Octal sequence (3 digits)
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ if ((i+2) >= Line.size())
+ throw failure{"Row ends in middle of octal value."};
+ const char n1 = Line[++i];
+ const char n2 = Line[++i];
+ if (not is_octalchar(n1) or not is_octalchar(n2))
+ throw failure{"Invalid octal in encoded table stream."};
+ R += char(
+ (digit_to_number(n)<<6) |
+ (digit_to_number(n1)<<3) |
+ digit_to_number(n2));
+ }
+ break;
+
+ case 'b':
+ // TODO: Escape code?
+ R += char(8);
+ break; // Backspace
+ case 'v':
+ // TODO: Escape code?
+ R += char(11);
+ break; // Vertical tab
+ case 'f':
+ // TODO: Escape code?
+ R += char(12);
+ break; // Form feed
+ case 'n':
+ R += '\n';
+ break; // Newline
+ case 't':
+ R += '\t';
+ break; // Tab
+ case 'r':
+ R += '\r';
+ break; // Carriage return;
+
+ default: // Self-escaped character
+ R += n;
+ // This may be a self-escaped tab that we thought was a terminator...
+ if (i == stop)
+ {
+ if ((i+1) >= Line.size())
+ throw internal_error{"COPY line ends in backslash."};
+ stop = findtab(Line, i+1);
+ }
+ break;
+ }
+ }
+ break;
+
+ default:
+ R += c;
+ break;
+ }
+ }
+ ++i;
+
+ if (isnull and (R.size() != NullStr().size()))
+ throw failure{"Field contains data behind null sequence."};
+
+ return R;
+}
diff --git a/contrib/libs/libpqxx/src/tablestream.cxx b/contrib/libs/libpqxx/src/tablestream.cxx
new file mode 100644
index 0000000000..6ab0148e1e
--- /dev/null
+++ b/contrib/libs/libpqxx/src/tablestream.cxx
@@ -0,0 +1,38 @@
+/** Implementation of the pqxx::tablestream class.
+ *
+ * pqxx::tablestream provides optimized batch access to a database table.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/tablestream"
+#include "pqxx/transaction"
+
+
+pqxx::tablestream::tablestream(transaction_base &STrans,
+ const std::string &Null) :
+ internal::namedclass{"tablestream"},
+ internal::transactionfocus{STrans},
+ m_null{Null}
+{
+}
+
+
+pqxx::tablestream::~tablestream() noexcept
+{
+}
+
+
+void pqxx::tablestream::base_close()
+{
+ if (not is_finished())
+ {
+ m_finished = true;
+ unregister_me();
+ }
+}
diff --git a/contrib/libs/libpqxx/src/tablewriter.cxx b/contrib/libs/libpqxx/src/tablewriter.cxx
new file mode 100644
index 0000000000..3ca5dae253
--- /dev/null
+++ b/contrib/libs/libpqxx/src/tablewriter.cxx
@@ -0,0 +1,160 @@
+/** Implementation of the pqxx::tablewriter class.
+ *
+ * pqxx::tablewriter enables optimized batch updates to a database table.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/tablereader"
+#include "pqxx/tablewriter"
+#include "pqxx/transaction"
+
+#include "pqxx/internal/gates/transaction-tablewriter.hxx"
+
+using namespace pqxx::internal;
+
+
+pqxx::tablewriter::tablewriter(
+ transaction_base &T,
+ const std::string &WName,
+ const std::string &Null) :
+ namedclass{"tablewriter", WName},
+ tablestream(T, Null)
+{
+ set_up(T, WName);
+}
+
+
+pqxx::tablewriter::~tablewriter() noexcept
+{
+ try
+ {
+ writer_close();
+ }
+ catch (const std::exception &e)
+ {
+ reg_pending_error(e.what());
+ }
+}
+
+
+void pqxx::tablewriter::set_up(
+ transaction_base &T,
+ const std::string &WName,
+ const std::string &Columns)
+{
+ gate::transaction_tablewriter{T}.BeginCopyWrite(WName, Columns);
+ register_me();
+}
+
+
+pqxx::tablewriter &pqxx::tablewriter::operator<<(pqxx::tablereader &R)
+{
+ std::string Line;
+ // TODO: Can we do this in binary mode? (Might require protocol version check)
+ while (R.get_raw_line(Line)) write_raw_line(Line);
+ return *this;
+}
+
+
+void pqxx::tablewriter::write_raw_line(const std::string &Line)
+{
+ const std::string::size_type len = Line.size();
+ gate::transaction_tablewriter{m_trans}.write_copy_line(
+ ((len == 0) or (Line[len-1] != '\n')) ?
+ Line :
+ std::string{Line, 0, len-1});
+}
+
+
+void pqxx::tablewriter::complete()
+{
+ writer_close();
+}
+
+
+void pqxx::tablewriter::writer_close()
+{
+ if (not is_finished())
+ {
+ base_close();
+ try
+ {
+ gate::transaction_tablewriter{m_trans}.end_copy_write();
+ }
+ catch (const std::exception &)
+ {
+ try { base_close(); } catch (const std::exception &) {}
+ throw;
+ }
+ }
+}
+
+
+namespace
+{
+inline char escapechar(char i) noexcept
+{
+ char r = '\0';
+ switch (i)
+ {
+ case 8: r='b'; break; // backspace
+ case 11: r='v'; break; // vertical tab
+ case 12: r='f'; break; // form feed
+ case '\n': r='n'; break; // newline
+ case '\t': r='t'; break; // tab
+ case '\r': r='r'; break; // carriage return
+ case '\\': r='\\'; break; // backslash
+ }
+ return r;
+}
+
+inline bool unprintable(char i) noexcept
+{
+ return i < ' ' or i > '~';
+}
+
+inline char tooctdigit(char c, int n)
+{
+ using unsigned_char = unsigned char;
+ unsigned int i = unsigned_char(c);
+ return number_to_digit((i>>(3*n)) & 0x07);
+}
+} // namespace
+
+
+std::string pqxx::internal::escape(
+ const std::string &s,
+ const std::string &null)
+{
+ if (s == null) return "\\N";
+ if (s.empty()) return s;
+
+ std::string R;
+ R.reserve(s.size()+1);
+
+ for (const auto c: s)
+ {
+ const char e = escapechar(c);
+ if (e)
+ {
+ R += '\\';
+ R += e;
+ }
+ else if (unprintable(c))
+ {
+ R += "\\";
+ for (int n=2; n>=0; --n) R += tooctdigit(c, n);
+ }
+ else
+ {
+ R += c;
+ }
+ }
+ return R;
+}
diff --git a/contrib/libs/libpqxx/src/transaction.cxx b/contrib/libs/libpqxx/src/transaction.cxx
new file mode 100644
index 0000000000..ff0f469e6c
--- /dev/null
+++ b/contrib/libs/libpqxx/src/transaction.cxx
@@ -0,0 +1,72 @@
+/** Implementation of the pqxx::transaction class.
+ *
+ * pqxx::transaction represents a regular database transaction.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <stdexcept>
+
+#include "pqxx/connection_base"
+#include "pqxx/result"
+#include "pqxx/transaction"
+
+
+pqxx::internal::basic_transaction::basic_transaction(
+ connection_base &C,
+ const std::string &IsolationLevel,
+ readwrite_policy rw) :
+ namedclass{"transaction"},
+ dbtransaction(C, IsolationLevel, rw)
+{
+}
+
+
+void pqxx::internal::basic_transaction::do_commit()
+{
+ try
+ {
+ direct_exec("COMMIT");
+ }
+ catch (const statement_completion_unknown &e)
+ {
+ // Outcome of "commit" is unknown. This is a disaster: we don't know the
+ // resulting state of the database.
+ process_notice(e.what() + std::string{"\n"});
+ const std::string msg =
+ "WARNING: Commit of transaction '" + name() + "' is unknown. "
+ "There is no way to tell whether the transaction succeeded "
+ "or was aborted except to check manually.";
+ process_notice(msg + "\n");
+ throw in_doubt_error{msg};
+ }
+ catch (const std::exception &e)
+ {
+ if (not conn().is_open())
+ {
+ // We've lost the connection while committing. There is just no way of
+ // telling what happened on the other end. >8-O
+ process_notice(e.what() + std::string{"\n"});
+
+ const std::string Msg =
+ "WARNING: Connection lost while committing transaction "
+ "'" + name() + "'. "
+ "There is no way to tell whether the transaction succeeded "
+ "or was aborted except to check manually.";
+
+ process_notice(Msg + "\n");
+ throw in_doubt_error{Msg};
+ }
+ else
+ {
+ // Commit failed--probably due to a constraint violation or something
+ // similar.
+ throw;
+ }
+ }
+}
diff --git a/contrib/libs/libpqxx/src/transaction_base.cxx b/contrib/libs/libpqxx/src/transaction_base.cxx
new file mode 100644
index 0000000000..84a7ab7e1b
--- /dev/null
+++ b/contrib/libs/libpqxx/src/transaction_base.cxx
@@ -0,0 +1,577 @@
+/** Common code and definitions for the transaction classes.
+ *
+ * pqxx::transaction_base defines the interface for any abstract class that
+ * represents a database transaction.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cstring>
+#include <stdexcept>
+
+#include "pqxx/connection_base"
+#include "pqxx/result"
+#include "pqxx/transaction_base"
+
+#include "pqxx/internal/gates/connection-transaction.hxx"
+#include "pqxx/internal/gates/connection-parameterized_invocation.hxx"
+#include "pqxx/internal/gates/transaction-transactionfocus.hxx"
+
+#include "pqxx/internal/encodings.hxx"
+
+
+using namespace pqxx::internal;
+
+
+pqxx::internal::parameterized_invocation::parameterized_invocation(
+ connection_base &c,
+ const std::string &query) :
+ m_home{c},
+ m_query{query}
+{
+}
+
+
+pqxx::result pqxx::internal::parameterized_invocation::exec()
+{
+ std::vector<const char *> values;
+ std::vector<int> lengths;
+ std::vector<int> binaries;
+ const int elements = marshall(values, lengths, binaries);
+
+ return gate::connection_parameterized_invocation{m_home}.parameterized_exec(
+ m_query,
+ values.data(),
+ lengths.data(),
+ binaries.data(),
+ elements);
+}
+
+
+pqxx::transaction_base::transaction_base(connection_base &C, bool direct) :
+ namedclass{"transaction_base"},
+ m_conn{C}
+{
+ if (direct)
+ {
+ gate::connection_transaction gate{conn()};
+ gate.register_transaction(this);
+ m_registered = true;
+ }
+}
+
+
+pqxx::transaction_base::~transaction_base()
+{
+ try
+ {
+ reactivation_avoidance_clear();
+ if (not m_pending_error.empty())
+ process_notice("UNPROCESSED ERROR: " + m_pending_error + "\n");
+
+ if (m_registered)
+ {
+ m_conn.process_notice(description() + " was never closed properly!\n");
+ gate::connection_transaction gate{conn()};
+ gate.unregister_transaction(this);
+ }
+ }
+ catch (const std::exception &e)
+ {
+ try
+ {
+ process_notice(std::string{e.what()} + "\n");
+ }
+ catch (const std::exception &)
+ {
+ process_notice(e.what());
+ }
+ }
+}
+
+
+void pqxx::transaction_base::commit()
+{
+ CheckPendingError();
+
+ // Check previous status code. Caller should only call this function if
+ // we're in "implicit" state, but multiple commits are silently accepted.
+ switch (m_status)
+ {
+ case st_nascent: // Empty transaction. No skin off our nose.
+ return;
+
+ case st_active: // Just fine. This is what we expect.
+ break;
+
+ case st_aborted:
+ throw usage_error{"Attempt to commit previously aborted " + description()};
+
+ case st_committed:
+ // Transaction has been committed already. This is not exactly proper
+ // behaviour, but throwing an exception here would only give the impression
+ // that an abort is needed--which would only confuse things further at this
+ // stage.
+ // Therefore, multiple commits are accepted, though under protest.
+ m_conn.process_notice(description() + " committed more than once.\n");
+ return;
+
+ case st_in_doubt:
+ // Transaction may or may not have been committed. The only thing we can
+ // really do is keep telling the caller that the transaction is in doubt.
+ throw in_doubt_error{
+ description() + " committed again while in an indeterminate state."};
+
+ default:
+ throw internal_error{"pqxx::transaction: invalid status code."};
+ }
+
+ // Tricky one. If stream is nested in transaction but inside the same scope,
+ // the commit() will come before the stream is closed. Which means the
+ // commit is premature. Punish this swiftly and without fail to discourage
+ // the habit from forming.
+ if (m_focus.get())
+ throw failure{
+ "Attempt to commit " + description() + " with " +
+ m_focus.get()->description() + " still open."};
+
+ // Check that we're still connected (as far as we know--this is not an
+ // absolute thing!) before trying to commit. If the connection was broken
+ // already, the commit would fail anyway but this way at least we don't remain
+ // in-doubt as to whether the backend got the commit order at all.
+ if (not m_conn.is_open())
+ throw broken_connection{
+ "Broken connection to backend; cannot complete transaction."};
+
+ try
+ {
+ do_commit();
+ m_status = st_committed;
+ }
+ catch (const in_doubt_error &)
+ {
+ m_status = st_in_doubt;
+ throw;
+ }
+ catch (const std::exception &)
+ {
+ m_status = st_aborted;
+ throw;
+ }
+
+ gate::connection_transaction gate{conn()};
+ gate.add_variables(m_vars);
+
+ End();
+}
+
+
+void pqxx::transaction_base::abort()
+{
+ // Check previous status code. Quietly accept multiple aborts to
+ // simplify emergency bailout code.
+ switch (m_status)
+ {
+ case st_nascent: // Never began transaction. No need to issue rollback.
+ break;
+
+ case st_active:
+ try { do_abort(); } catch (const std::exception &) { }
+ break;
+
+ case st_aborted:
+ return;
+
+ case st_committed:
+ throw usage_error{"Attempt to abort previously committed " + description()};
+
+ case st_in_doubt:
+ // Aborting an in-doubt transaction is probably a reasonably sane response
+ // to an insane situation. Log it, but do not complain.
+ m_conn.process_notice(
+ "Warning: " + description() + " aborted after going into "
+ "indeterminate state; it may have been executed anyway.\n");
+ return;
+
+ default:
+ throw internal_error{"Invalid transaction status."};
+ }
+
+ m_status = st_aborted;
+ End();
+}
+
+
+std::string pqxx::transaction_base::esc_raw(const std::string &str) const
+{
+ const unsigned char *p = reinterpret_cast<const unsigned char *>(str.c_str());
+ return conn().esc_raw(p, str.size());
+}
+
+
+std::string pqxx::transaction_base::quote_raw(const std::string &str) const
+{
+ const unsigned char *p = reinterpret_cast<const unsigned char *>(str.c_str());
+ return conn().quote_raw(p, str.size());
+}
+
+
+void pqxx::transaction_base::activate()
+{
+ switch (m_status)
+ {
+ case st_nascent:
+ // Make sure transaction has begun before executing anything
+ Begin();
+ break;
+
+ case st_active:
+ break;
+
+ case st_committed:
+ case st_aborted:
+ case st_in_doubt:
+ throw usage_error{
+ "Attempt to activate " + description() + " "
+ "which is already closed."};
+
+ default:
+ throw internal_error{"pqxx::transaction: invalid status code."};
+ }
+}
+
+
+pqxx::result pqxx::transaction_base::exec(
+ const std::string &Query,
+ const std::string &Desc)
+{
+ CheckPendingError();
+
+ const std::string N = (Desc.empty() ? "" : "'" + Desc + "' ");
+
+ if (m_focus.get())
+ throw usage_error{
+ "Attempt to execute query " + N +
+ "on " + description() + " "
+ "with " + m_focus.get()->description() + " still open."};
+
+ try
+ {
+ activate();
+ }
+ catch (const usage_error &e)
+ {
+ throw usage_error{"Error executing query " + N + ". " + e.what()};
+ }
+
+ // TODO: Pass Desc to do_exec(), and from there on down
+ return do_exec(Query.c_str());
+}
+
+
+pqxx::result pqxx::transaction_base::exec_n(
+ size_t rows,
+ const std::string &Query,
+ const std::string &Desc)
+{
+ const result r = exec(Query, Desc);
+ if (r.size() != rows)
+ {
+ const std::string N = (Desc.empty() ? "" : "'" + Desc + "'");
+ throw unexpected_rows{
+ "Expected " + to_string(rows) + " row(s) of data "
+ "from query " + N + ", got " + to_string(r.size()) + "."};
+ }
+ return r;
+}
+
+
+void pqxx::transaction_base::check_rowcount_prepared(
+ const std::string &statement,
+ size_t expected_rows,
+ size_t actual_rows)
+{
+ if (actual_rows != expected_rows)
+ {
+ throw unexpected_rows{
+ "Expected " + to_string(expected_rows) + " row(s) of data "
+ "from prepared statement '" + statement + "', got " +
+ to_string(actual_rows) + "."};
+ }
+}
+
+
+void pqxx::transaction_base::check_rowcount_params(
+ size_t expected_rows,
+ size_t actual_rows)
+{
+ if (actual_rows != expected_rows)
+ {
+ throw unexpected_rows{
+ "Expected " + to_string(expected_rows) + " row(s) of data "
+ "from parameterised query, got " + to_string(actual_rows) + "."};
+ }
+}
+
+
+pqxx::internal::parameterized_invocation
+pqxx::transaction_base::parameterized(const std::string &query)
+{
+#include "pqxx/internal/ignore-deprecated-pre.hxx"
+ return internal::parameterized_invocation{conn(), query};
+#include "pqxx/internal/ignore-deprecated-post.hxx"
+}
+
+
+pqxx::prepare::invocation
+pqxx::transaction_base::prepared(const std::string &statement)
+{
+ try
+ {
+ activate();
+ }
+ catch (const usage_error &e)
+ {
+ throw usage_error{
+ "Error executing prepared statement " + statement + ". " + e.what()};
+ }
+#include "pqxx/internal/ignore-deprecated-pre.hxx"
+ return prepare::invocation{*this, statement};
+#include "pqxx/internal/ignore-deprecated-post.hxx"
+}
+
+
+pqxx::result pqxx::transaction_base::internal_exec_prepared(
+ const std::string &statement,
+ const internal::params &args,
+ result_format format)
+{
+ gate::connection_transaction gate{conn()};
+ return gate.exec_prepared(statement, args, format);
+}
+
+
+pqxx::result pqxx::transaction_base::internal_exec_params(
+ const std::string &query,
+ const internal::params &args)
+{
+ gate::connection_transaction gate{conn()};
+ return gate.exec_params(query, args);
+}
+
+
+void pqxx::transaction_base::set_variable(
+ const std::string &Var,
+ const std::string &Value)
+{
+ // Before committing to this new value, see what the backend thinks about it
+ gate::connection_transaction gate{conn()};
+ gate.raw_set_var(Var, Value);
+ m_vars[Var] = Value;
+}
+
+
+std::string pqxx::transaction_base::get_variable(const std::string &Var)
+{
+ const std::map<std::string,std::string>::const_iterator i = m_vars.find(Var);
+ if (i != m_vars.end()) return i->second;
+ return gate::connection_transaction{conn()}.raw_get_var(Var);
+}
+
+
+void pqxx::transaction_base::Begin()
+{
+ if (m_status != st_nascent)
+ throw internal_error{
+ "pqxx::transaction: Begin() called while not in nascent state."};
+
+ try
+ {
+ // Better handle any pending notifications before we begin
+ m_conn.get_notifs();
+
+ do_begin();
+ m_status = st_active;
+ }
+ catch (const std::exception &)
+ {
+ End();
+ throw;
+ }
+}
+
+
+void pqxx::transaction_base::End() noexcept
+{
+ try
+ {
+ try { CheckPendingError(); }
+ catch (const std::exception &e) { m_conn.process_notice(e.what()); }
+
+ gate::connection_transaction gate{conn()};
+ if (m_registered)
+ {
+ m_registered = false;
+ gate.unregister_transaction(this);
+ }
+
+ if (m_status != st_active) return;
+
+ if (m_focus.get())
+ m_conn.process_notice(
+ "Closing " + description() + " with " +
+ m_focus.get()->description() + " still open.\n");
+
+ try { abort(); }
+ catch (const std::exception &e) { m_conn.process_notice(e.what()); }
+
+ gate.take_reactivation_avoidance(m_reactivation_avoidance.get());
+ m_reactivation_avoidance.clear();
+ }
+ catch (const std::exception &e)
+ {
+ try { m_conn.process_notice(e.what()); } catch (const std::exception &) {}
+ }
+}
+
+
+void pqxx::transaction_base::register_focus(internal::transactionfocus *S)
+{
+ m_focus.register_guest(S);
+}
+
+
+void pqxx::transaction_base::unregister_focus(internal::transactionfocus *S)
+ noexcept
+{
+ try
+ {
+ m_focus.unregister_guest(S);
+ }
+ catch (const std::exception &e)
+ {
+ m_conn.process_notice(std::string{e.what()} + "\n");
+ }
+}
+
+
+pqxx::result pqxx::transaction_base::direct_exec(const char C[], int Retries)
+{
+ CheckPendingError();
+ return gate::connection_transaction{conn()}.exec(C, Retries);
+}
+
+
+void pqxx::transaction_base::register_pending_error(const std::string &Err)
+ noexcept
+{
+ if (m_pending_error.empty() and not Err.empty())
+ {
+ try
+ {
+ m_pending_error = Err;
+ }
+ catch (const std::exception &e)
+ {
+ try
+ {
+ process_notice("UNABLE TO PROCESS ERROR\n");
+ process_notice(e.what());
+ process_notice("ERROR WAS:");
+ process_notice(Err);
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+}
+
+
+void pqxx::transaction_base::CheckPendingError()
+{
+ if (not m_pending_error.empty())
+ {
+ const std::string Err{m_pending_error};
+ m_pending_error.clear();
+ throw failure{Err};
+ }
+}
+
+
+namespace
+{
+std::string MakeCopyString(
+ const std::string &Table,
+ const std::string &Columns)
+{
+ std::string Q = "COPY " + Table + " ";
+ if (not Columns.empty()) Q += "(" + Columns + ") ";
+ return Q;
+}
+} // namespace
+
+
+void pqxx::transaction_base::BeginCopyRead(
+ const std::string &Table,
+ const std::string &Columns)
+{
+ exec(MakeCopyString(Table, Columns) + "TO STDOUT");
+}
+
+
+void pqxx::transaction_base::BeginCopyWrite(
+ const std::string &Table,
+ const std::string &Columns)
+{
+ exec(MakeCopyString(Table, Columns) + "FROM STDIN");
+}
+
+
+bool pqxx::transaction_base::read_copy_line(std::string &line)
+{
+ return gate::connection_transaction{conn()}.read_copy_line(line);
+}
+
+
+void pqxx::transaction_base::write_copy_line(const std::string &line)
+{
+ gate::connection_transaction gate{conn()};
+ gate.write_copy_line(line);
+}
+
+
+void pqxx::transaction_base::end_copy_write()
+{
+ gate::connection_transaction gate{conn()};
+ gate.end_copy_write();
+}
+
+
+void pqxx::internal::transactionfocus::register_me()
+{
+ gate::transaction_transactionfocus gate{m_trans};
+ gate.register_focus(this);
+ m_registered = true;
+}
+
+
+void pqxx::internal::transactionfocus::unregister_me() noexcept
+{
+ gate::transaction_transactionfocus gate{m_trans};
+ gate.unregister_focus(this);
+ m_registered = false;
+}
+
+void
+pqxx::internal::transactionfocus::reg_pending_error(const std::string &err)
+ noexcept
+{
+ gate::transaction_transactionfocus gate{m_trans};
+ gate.register_pending_error(err);
+}
diff --git a/contrib/libs/libpqxx/src/util.cxx b/contrib/libs/libpqxx/src/util.cxx
new file mode 100644
index 0000000000..646ace9930
--- /dev/null
+++ b/contrib/libs/libpqxx/src/util.cxx
@@ -0,0 +1,121 @@
+/** Various utility functions.
+ *
+ * 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.
+ */
+#include "pqxx/compiler-internal.hxx"
+
+#include <cerrno>
+#include <chrono>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <new>
+#include <thread>
+
+extern "C"
+{
+#include "libpq-fe.h"
+}
+
+#include "pqxx/except"
+#include "pqxx/util"
+
+
+using namespace pqxx::internal;
+
+
+pqxx::thread_safety_model pqxx::describe_thread_safety() noexcept
+{
+ thread_safety_model model;
+
+ if (PQisthreadsafe())
+ {
+ model.safe_libpq = true;
+ }
+ else
+ {
+ model.safe_libpq = false;
+ model.description += "Using a libpq build that is not thread-safe.\n";
+ }
+
+ // Sadly I'm not aware of any way to avoid this just yet.
+ model.safe_kerberos = false;
+ model.description +=
+ "Kerberos is not thread-safe. If your application uses Kerberos, "
+ "protect all calls to Kerberos or libpqxx using a global lock.\n";
+
+ return model;
+}
+
+
+std::string pqxx::internal::namedclass::description() const
+{
+ try
+ {
+ std::string desc = classname();
+ if (not name().empty()) desc += " '" + name() + "'";
+ return desc;
+ }
+ catch (const std::exception &)
+ {
+ // Oops, string composition failed! Probably out of memory.
+ // Let's try something easier.
+ }
+ return name().empty() ? classname() : name();
+}
+
+
+void pqxx::internal::CheckUniqueRegistration(const namedclass *New,
+ const namedclass *Old)
+{
+ if (New == nullptr)
+ throw internal_error{"null pointer registered."};
+ if (Old)
+ {
+ if (Old == New)
+ throw usage_error{"Started twice: " + New->description()};
+ throw usage_error{
+ "Started " + New->description() + " while " + Old->description() +
+ " still active."};
+ }
+}
+
+
+void pqxx::internal::CheckUniqueUnregistration(const namedclass *New,
+ const namedclass *Old)
+{
+ if (New != Old)
+ {
+ if (New == nullptr)
+ throw usage_error{
+ "Expected to close " + Old->description() + ", "
+ "but got null pointer instead."};
+ if (Old == nullptr)
+ throw usage_error{"Closed while not open: " + New->description()};
+ throw usage_error{
+ "Closed " + New->description() + "; "
+ "expected to close " + Old->description()};
+ }
+}
+
+
+void pqxx::internal::freepqmem(const void *p) noexcept
+{
+ PQfreemem(const_cast<void *>(p));
+}
+
+
+void pqxx::internal::freemallocmem(const void *p) noexcept
+{
+ free(const_cast<void *>(p));
+}
+
+
+void pqxx::internal::sleep_seconds(int s)
+{
+ std::this_thread::sleep_for(std::chrono::seconds(s));
+}
diff --git a/contrib/libs/libpqxx/src/version.cxx b/contrib/libs/libpqxx/src/version.cxx
new file mode 100644
index 0000000000..1fba1ec6d4
--- /dev/null
+++ b/contrib/libs/libpqxx/src/version.cxx
@@ -0,0 +1,18 @@
+#include "pqxx/compiler-internal.hxx"
+
+#include "pqxx/version"
+
+namespace pqxx
+{
+namespace internal
+{
+// One, single definition of this function. If a call fails to link, then the
+// libpqxx binary was built against a different libpqxx version than the code
+// which is being linked against it.
+template<> PQXX_LIBEXPORT
+int check_library_version<PQXX_VERSION_MAJOR, PQXX_VERSION_MINOR>() noexcept
+{
+ return 0;
+}
+}
+}