diff options
author | galaxycrab <UgnineSirdis@ydb.tech> | 2023-11-23 11:26:33 +0300 |
---|---|---|
committer | galaxycrab <UgnineSirdis@ydb.tech> | 2023-11-23 12:01:57 +0300 |
commit | 44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300 (patch) | |
tree | cb4d75cd1c6dbc3da0ed927337fd8d1b6ed9da84 /contrib/libs/libpqxx | |
parent | 0e69bf615395fdd48ecee032faaec81bc468b0b8 (diff) | |
download | ydb-44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300.tar.gz |
YQ Connector:test INNER JOIN
Diffstat (limited to 'contrib/libs/libpqxx')
146 files changed, 20309 insertions, 0 deletions
diff --git a/contrib/libs/libpqxx/AUTHORS b/contrib/libs/libpqxx/AUTHORS new file mode 100644 index 0000000000..6a922e950c --- /dev/null +++ b/contrib/libs/libpqxx/AUTHORS @@ -0,0 +1,4 @@ +Jeroen T. Vermeulen. Wrote the code. +Ray Dassen. Did most of the autoconf etc. stuff. + +Lots of others helped with various other contributions. diff --git a/contrib/libs/libpqxx/CMakeLists.darwin-arm64.txt b/contrib/libs/libpqxx/CMakeLists.darwin-arm64.txt new file mode 100644 index 0000000000..14c39564ee --- /dev/null +++ b/contrib/libs/libpqxx/CMakeLists.darwin-arm64.txt @@ -0,0 +1,59 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpqxx) +target_compile_options(contrib-libs-libpqxx PRIVATE + -DHAVE_CONFIG_H + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpqxx PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/include +) +target_include_directories(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq +) +target_link_libraries(contrib-libs-libpqxx PUBLIC + contrib-libs-cxxsupp + contrib-libs-libpq +) +target_sources(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/array.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/binarystring.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/dbtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/encodings.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/errorhandler.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/except.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/field.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/largeobject.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/nontransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/notification.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/pipeline.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/prepared_statement.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/result.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/robusttransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/row.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/sql_cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/statement_parameters.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/strconv.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_from.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_to.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/subtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablereader.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablestream.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablewriter.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/util.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/version.cxx +) diff --git a/contrib/libs/libpqxx/CMakeLists.darwin-x86_64.txt b/contrib/libs/libpqxx/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..14c39564ee --- /dev/null +++ b/contrib/libs/libpqxx/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,59 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpqxx) +target_compile_options(contrib-libs-libpqxx PRIVATE + -DHAVE_CONFIG_H + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpqxx PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/include +) +target_include_directories(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq +) +target_link_libraries(contrib-libs-libpqxx PUBLIC + contrib-libs-cxxsupp + contrib-libs-libpq +) +target_sources(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/array.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/binarystring.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/dbtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/encodings.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/errorhandler.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/except.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/field.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/largeobject.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/nontransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/notification.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/pipeline.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/prepared_statement.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/result.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/robusttransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/row.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/sql_cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/statement_parameters.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/strconv.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_from.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_to.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/subtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablereader.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablestream.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablewriter.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/util.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/version.cxx +) diff --git a/contrib/libs/libpqxx/CMakeLists.linux-aarch64.txt b/contrib/libs/libpqxx/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..2bed345738 --- /dev/null +++ b/contrib/libs/libpqxx/CMakeLists.linux-aarch64.txt @@ -0,0 +1,60 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpqxx) +target_compile_options(contrib-libs-libpqxx PRIVATE + -DHAVE_CONFIG_H + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpqxx PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/include +) +target_include_directories(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq +) +target_link_libraries(contrib-libs-libpqxx PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + contrib-libs-libpq +) +target_sources(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/array.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/binarystring.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/dbtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/encodings.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/errorhandler.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/except.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/field.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/largeobject.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/nontransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/notification.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/pipeline.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/prepared_statement.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/result.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/robusttransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/row.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/sql_cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/statement_parameters.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/strconv.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_from.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_to.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/subtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablereader.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablestream.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablewriter.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/util.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/version.cxx +) diff --git a/contrib/libs/libpqxx/CMakeLists.linux-x86_64.txt b/contrib/libs/libpqxx/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..2bed345738 --- /dev/null +++ b/contrib/libs/libpqxx/CMakeLists.linux-x86_64.txt @@ -0,0 +1,60 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpqxx) +target_compile_options(contrib-libs-libpqxx PRIVATE + -DHAVE_CONFIG_H + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpqxx PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/include +) +target_include_directories(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq +) +target_link_libraries(contrib-libs-libpqxx PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + contrib-libs-libpq +) +target_sources(contrib-libs-libpqxx PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/array.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/binarystring.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/connection_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/dbtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/encodings.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/errorhandler.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/except.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/field.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/largeobject.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/nontransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/notification.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/pipeline.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/prepared_statement.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/result.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/robusttransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/row.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/sql_cursor.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/statement_parameters.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/strconv.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_from.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/stream_to.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/subtransaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablereader.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablestream.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/tablewriter.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/transaction_base.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/util.cxx + ${CMAKE_SOURCE_DIR}/contrib/libs/libpqxx/src/version.cxx +) diff --git a/contrib/libs/libpqxx/CMakeLists.txt b/contrib/libs/libpqxx/CMakeLists.txt new file mode 100644 index 0000000000..1beba2829f --- /dev/null +++ b/contrib/libs/libpqxx/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + include(CMakeLists.darwin-arm64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/contrib/libs/libpqxx/COPYING b/contrib/libs/libpqxx/COPYING new file mode 100755 index 0000000000..006c39da8b --- /dev/null +++ b/contrib/libs/libpqxx/COPYING @@ -0,0 +1,27 @@ +Copyright (c) 2000-2019 Jeroen T. Vermeulen. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the author, nor the names of other contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/contrib/libs/libpqxx/INSTALL b/contrib/libs/libpqxx/INSTALL new file mode 100755 index 0000000000..bf0aebe736 --- /dev/null +++ b/contrib/libs/libpqxx/INSTALL @@ -0,0 +1,212 @@ +Basic Installation +================== + + +The native build system for libpqxx is based on `configure` and `make`, +but there is also a CMake build. + + +Native build +------------ + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README.md' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. Running `configure' takes awhile. While + running, it prints some messages telling which features it is + checking for. + 2. Type `make' to compile the package. (Add e.g. `-j8` to run up to 8 + simultanerous compiler processes to speed this up.) + 3. Optionally, type `make check' to run any self-tests that come with + the package. + 4. Type `make install' to install the programs and any data files and + documentation. + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + +CMake build +----------- + +With CMake you can generate a build setup in your choice of build +system. The one I'm most familiar with is `make`. + +Like the native build, the CMake build needs the libpq library and headers +installed. But in addition, it also needs the `pg_type.h` header installed. +On some systems this will be in one of the `postgresql-server-dev-*` packages. + +That extra header is just to allow CMake to detect that you have a PostgreSQL +development setup installed. The build shouldn't actually need the file +otherwise, so if you can't find the file, it may be enough to create an empty +file in the right place. + +The CMake build works like: + 1. Go into the directory where you would like to build the library and + its intermediate files. This may be the source directory. + 2. Enter `cmake <sourcedir>`, where `<sourcedir>` is the location of + the libpqxx source code. This generates the build configuration. + 3. Type `make' to compile the package. (Add e.g. `-j8` to run up to 8 + simultanerous compiler processes to speed this up.) + + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment, or by +adding them to the `configure` command line: + + ./configure CXX='clang++' CXXFLAGS=-O3 LIBS=-lposix + + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README.md' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/contrib/libs/libpqxx/NEWS b/contrib/libs/libpqxx/NEWS new file mode 100644 index 0000000000..7fa015859b --- /dev/null +++ b/contrib/libs/libpqxx/NEWS @@ -0,0 +1,750 @@ +6.4.5 + - Fixed "const" support in arguments to parameterised/prepared statements. +6.4.4 + - Use pkg-config if pg-config is not available. + - In CMake build, prefer CMake's config headers over any found in source tree. +6.4.3 + - Updated copyright strings. + - Added missing "stream" headers to autotools-based install. + - Added stream headers to pqxx/pqxx header. +6.4.2 + - Fix mistake for Windows in 6.4.1: use PQfreemem, not std::free. + - Easily enable runtime checks in configure: "--enable-audit". + - Enable optimisation in CircleCI build. +6.4.1 + - Fixed more memory leaks. +6.4.0 + - Half fix, half work around nasty notice processor life time bug. + - Fix selective running of tests: "test/unit/runner test_infinities". + - Added some missing `std::` qualifications. +6.3.3 + - Throw more appropriate error when unable to read client encoding. + - CMake build fixes. +6.3.2 + - Conversion errors no longer throw pqxx::failure; always conversion_error! + - Use C++17's built-in numeric string conversions, if available. + - Query numeric precision in a more sensible, standard way. + - Avoid "dead code" warning. + - Replace obsolete autoconf macros. + - Remove all "using namespace std". + - CMake build fixes. +6.3.1 + - Windows compile fix (CALLBACK is a macro there). + - Work around Visual Studio 2017 not supporting ISO 646. +6.3.0 + - New "table stream" classes by Joseph Durel: stream_from/stream_to. + - Support weird characters in more identifiers: cursors, notifcations, etc. + - Connection policies are deprecated. It'll all be one class in 7.0! + - Connection deactivation/reactivation is deprecated. + - Some items that were documented as deprecated are now also declared as such. + - Fix Windows bug where WSAPoll was never used. Thanks dpolunin. + - Fix Windows CMake build to link to socket libraries. Thanks dpolunin. + - Various other changes to the CMake build. + - Fix failure when doing multiple string conversions with Visual C++. + - Fix nested project builds in CMake. Thanks Andrew Brownsword. + - In Visual Studio, build for host architecture, not "x64". + - Fix string conversion link error in Visual Studio. Thanks Ivan Poiakov. + - Fix string conversion to bool for "1". Thanks Amaracs. + - Fix in escaping of strings in arrays. Thanks smirql. + - Faster copying of results of large queries. Thanks Vsevolod Strukchinsky. + - Starting to handle encodings properly! Thanks to Joseph Durel. + - No longer using std::iterator (deprecated in C++17). +6.2.5 + - Removed deprecated pqxx-config. + - Build fix on Visual C++ when not defining NOMINMAX. + - Reduce setup code for string conversions, hopefully improving speed. + - Allow nul bytes in tablereader. + - Support defining string conversions for enum types. + - Fixed const/pure attributes warning in gcc 8. + - Updated build documentation to mention CMake option. + - Fixed a floating-point string conversion failure with Visual Studio 2017. +6.2.4 + - Fix builds in paths containing non-ASCII characters. + - New macro: PQXX_HIDE_EXP_OPTIONAL (to work around a client build error). +6.2.3 + - Build fixes. +6.2.2 + - Variable number of arguments to prepared or parameterised statement (#75). + - Windows build fix (#76). +6.2.1 + - Compile fixes. +6.2.0 + - At last! A check against version mismatch between library and headers. + - Small compile fixes. +6.1.1 + - Small compile fixes. + - A particular error string would always come out empty. +6.1.0 + - Dependencies among headers have changed. You may need extra includes. + - Library headers now include "*.hxx" directly, not the user-level headers. + - Supports parsing of SQL arrays, when using "ASCII-like" encodings. +6.0.0 + - C++11 is now required. Your compiler must have shared_ptr, noexcept, etc. + - Removed configure.ac.in; we now use configure.ac directly. + - Removed pqxx::items. Use the new C++11 initialiser syntax. + - Removed maketemporary. We weren't using it. + - Can now be built outside the source tree. + - New, simpler, lambda-friendly transactor framework. + - New, simpler, prepared statements and parameterised statements. + - Result rows can be passed around independently. + - New exec0(): perform query, expect zero rows of data. + - New exec1(): perform query, expect (and return) a single row of data. + - New exec_n(): perform query, expect exactly n rows of data. + - No longer defines Visual Studio's NOMINMAX in headers. + - Much faster configure script. + - Most configuration items are gone. + - Retired all existing capability flags. + - Uses WSAPoll() on Windows. + - Documentation on readthedocs.org, thanks Tim Sheerman-Chase. +5.1.0 + - Releases after this will require C++11! + - Internal simplification to pqxx::result. + - A row object now keeps its result object alive. + - New exec() variants: "expect & return 1 row," "expect no rows," "expect n." + - ChangeLog is gone. It was a drag on maintenance. +5.0.1 + - Exposed sqlstate in sql_error exception class. +5.0 + - The PGSTD namespace alias is gone. Use the std namespace directly. + - pqxx::tuple is now pqxx::row, to avoid clashes with std::tuple. + - Deprecated escape_binary functions dropped. + - Deprecated notify_listener class dropped. + - Support for many old compilers dropped. + - Support for "long long" and "long double" types is always enabled. + - No longer uses obsolete std::tr1 namespace; use plain std instead. + - Now requires libpq 9.1 or better. + - Requires server version 9.1 or better. + - Support for REPEATABLE READ isolation level added. + - Makefile fixes for Visual Studio 2013. + - Supports C++11 and C++14. + - No longer has obsolete debian & RPM packaging built in. + - Fixed failure to abort uncommitted subtransactions on destruction. + - Fixed failure to detect some integer overflows during conversion. + - Build tooling uses /usr/bin/env python instead of /usr/bin/python. + - New configure options: --with-postgres-include and --with-postgres-lib. + - In g++ or compatible compilers, non-exported items are no longer accessible. + - Many build fixes for various platforms and compilers. +4.0 + - API change: noticers are gone! Use errorhandlers to capture error output. + - API change: tablereaders and tablewriters are gone; they weren't safe. + - API change: prepared statements are now weakly-typed, and much simpler. + - API change: fields and tuples are now stand-alone classes in ::pqxx. + - API change: thread-safety field have_strerror_r is now have_safe_strerror. + - API change: notify_listener has been replaced with notification_receiver. + - notification_receiver takes a payload parameter. + - Easier Visual C++ setup. + - Absolutely requires a libpq version with PQescapeStringConn. + - Absolutely requires libpq 8.0 or better. + - Changes for C++0x. + - Supports clang++. + - Visual C++ makefiles now support new-style unit tests. + - Sample headers for more recent Visual Studio versions. + - Fixes binary-data escaping problems with postgres 9.0. + - Fixes problems with binary-string handling and escaping. + - Fixes compatibility problems between 9.x libpq and 7.x backend. + - quote_name to escape SQL identifiers for use in queries. + - syntax_error reports error's approximate location in the query. + - On Windows, now uses ws2_32 instead of wsock32. + - Various Windows build fixes. + - Updated for gcc 4.6.0. + - configure script supports --enable-documentation/--disable-documentation. + - Streamlined test/release toolchain. +3.1 + - Shared libraries are now versioned by ABI: 3.1 instead of 3.1.0 etc. + - Threading behaviour is now documented, and can be queried. + - Version information available at compile time. + - Supports parameterized statements. + - Result tuples now support slicing. + - Configure with --with-tr1=boost to use BOOST shared_ptr. + - String conversion now has its own header file. + - Supports read-only transactions. + - Fixed breakage with Solaris "make". + - Uses shared_ptr if available. + - binarystring::str() is no longer cached; no longer returns reference. + - Fixed problems in Visual C++ Makefile for test suite. + - Fixed problems with RPM packaging. + - Fixed build problem on RedHat/CentOS 5. + - Lets you check whether a prepared statement has been defined. + - "Varargs" prepared statements. + - Unnamed prepared statements now supported. + - Results have iterator as well as const_iterator. + - Rewrite of robusttransaction logic; may actually do its job now. + - Connections support async query cancel from signal handler or thread. + - More documentation for performance features. +3.0 + - Website is now at http://pqxx.org/ (no redirects) + - Completely replaced cursor classes + - More helpful error messages on failed connections + - More detailed hierarchy of constraint-violation exception classes + - trigger is now called notify_listener, trigger header is now notify-listen + - New mixin base class pqxx_exception distinguishes libpqxx exception types + - Quoting is back! transaction_base::quote() & connection_base::quote() + - Several build & documentation problems with Visual C++ fixed + - Compile fixes for gcc 4.2, 4.3 + - Compile fixes for Sun Studio Express 5.9 + - Uses strlcpy() where available, instead of strncpy() + - Keeps better track of applicable text encodings + - Fixed bug with prepared statement parameters in separate C++ statements + - robusttransaction now works for multiple users + - Pipeline lets you cancel ongoing queries, e.g. because they run for too long + - Fixed broken escaping of binary values in tablewriter + - Floating-point types now represented with full precision + - Proper unit tests for new functionality + - New traits-based system for adding data types + - Floating-point infinities now supported + - Flushing/completing a pipeline now frees up the transaction for other use + - Completely reworked test suite, builds and runs much faster + - tablewriter supports writing of raw lines +2.6.9 + - Removed old 1.x API (that means all identifiers with capital letters!) + - Tested with all current libpq versions and oldest/newest supported backends + - No longer have old OnCommit()/OnAbort()/OnDoubt() callbacks in transactor! + - Fixes failure when closing cursors with upper-case letters in their names + - Fixes bug when adding triggers to connections that aren't open yet + - Fixes bug when removing triggers + - Fixes small memory leak when preparing statements + - Fixes many problems with older backends + - Fixes bug in result::swap(): protocol versions were not swapped + - Some errors went undetected when using certain libpq versions + - Fixes prepared statements on new libpq versions talking to old backends + - Can estimate server version if libpq does not know how to obtain it + - Greatly reduced memory usage while escaping strings + - With Visual C++, creates lib/ directory if not already present + - Useful error messages when preparing statements + - Allows prepared statements to be registered explicitly + - Support for "long long" types; enable with PQXX_ALLOW_LONG_LONG macro + - Compilation errors for older libpq versions fixed + - Some new small utility classes for disabling notice processing etc. + - Result sets remember the queries that yielded them + - New test script, pqxx-fulltest, tests against all current postgres versions + - Connections can simulate failure + - Adds password encryption function +2.6.8 + - Fixes bug: binary parameters to prepared statements truncated at nul bytes + - New, more specific exception types to distinguish errors from server + - Resolved serious problems with generated reference documentation + - Automatically detect Windows socket library with MinGW + - Windows "make" fixed to run from main directory, not win32 + - Fixes "mktemp" problems on some BSD-based platforms + - pqxx-config is deprecated; use pkg-config instead + - On GNU/Linux, uses poll() instead of select() to avoid file descriptor limit + - Will provide server and protocol version information where available + - New cursor class, absolute_cursor +2.6.7 + - New escape functions for binary data: transaction_base::esc_raw() + - Improved detection of socket libraries, especially for MinGW + - Works around bug in some versions of GNU grep 2.5.1 + - Fixes problem with configuration headers + - Fixes PQprepare() detection + - Fixes incomplete Visual C++ Makefile + - Fixes compile error in workaround for older libpq versions + - Removes "rpath" link option +2.6.6 + - New, encoding-safe string-escaping functions + - Upper-case letters now allowed in prepared-statement names + - Fixes crash in test005 + - More Visual C++ improvements + - Removed collaboration diagrams from reference docs + - New templating system for generating Windows Makefiles etc. +2.6.5 + - Visual C++ users: copy win32/common-sample to win32/common before editing it + - Should fix problems finding socket library on MinGW + - Even more work on Visual C++ problems + - Updated documentation for Visual C++ users + - Fixed bug in prepared statements (mostly visible on Visual C++) + - Nested transactions work harder to detect backend support +2.6.4 + - Massively improved compatibility with Windows and Visual C++ + - Fixed late initialization of "direct" connection state + - Fixed problem with initialization of connection capabilities + - Fixed configuration bug for libpq in nonstandard locations + - Sample configuration header for libpq found in PostgreSQL 8.1 +2.6.3 + - Radical rework of prepared statements; INCOMPATIBLE INTERFACE CHANGE! + - Dropped support for g++ 2.95 + - Emulate prepared statements support on old libpq or old backend + - Bug fix: missing tutorial (release script now tests for this) + - Automatically links in socket library on Windows or Solaris, if needed + - Bug fix: check for std namespace didn't work + - Fixes for Cygwin/MSYS/MinGW +2.6.2 + - Bug fix: connection state was not set up properly in some common cases + - Bug fix: headers were installed in "include" instead of "include/pqxx" + - Bug fix: sqlesc(string) broke with multibyte or multiple encodings + - namedclass is now used as a virtual base; affects all subclass constructors + - Initial implementation of subtransactions + - Detect more connection capabilities + - Standard library namespace can be set from configure script's command line + - Completely reworked connection hierarchy, with separate policy objects + - Clients can now define their own connection policies + - Paved the way for client-defined thread synchronization + - Now lives at http://thaiopensource.org/development/libpqxx/ +2.6.1 + - Hugely improved recognition of different strerror_r() versions + - Resolved link problems with gcc 4.0 and shared library +2.6.0 + - New macro PQXX_SHARED defines whether to use/build libpqxx as shared library + - Robusttransaction compatible with PostgreSQL 8.1 + - Infrastructure for querying connection/backend capabilities at runtime + - Greatly improved cursor support + - Connection reactivation can be inhibited explicitly + - Tries even harder to make sense of conflicting strerror_r() definitions + - Detects connection failures that libpq glosses over + - Reference documentation grouped into more coherent sections + - Assumes strerror() is threadsafe on systems that have no strerror_r() + - Now allows connection's socket number to be queried + - New internal_error class for libpqxx-internal errors + - With Visual C++, doesn't redefine NOMINMAX if it is defined already + - Several compatibility improvements for Visual C++ + - Fixes and workarounds for HP-UX and HP aCC compiler + - Phased old cursor interface out of test suite; tests ported to new interface + - Added documentation on thread safety + - New thread safety model + - Large objects have functions to tell current position + - Minor updates to tutorial (somebody pay me and I'll do more :) + - No longer needs libpq-fs.h header + - Meaningful error messages for ambiguous string conversions fixed +2.5.6 + - Support null parameters to prepared statements (use C-style char pointers) +2.5.5 + - Diagnoses connection failure during result transfer + - Fixes invalid -R link option in pqxx-config +2.5.4 + - Fix workaround code for older libpq versions without PQunescapeBytea() + - Work around grep bug in Fedora Core 4 that broke configure in UTF-8 locales + - In Visual C++, assume libpqxx is a DLL when linking to std library as DLL + - Missing documentation in distribution archive is back again + - Export fewer symbols from library binary with gcc 4.0 + - Releases now automatically tested against gcc 4.0 + - Meaningful link errors for additional ambiguous string conversions + - DLL symbol exports now automatically tested before each release +2.5.3 + - Greatly improved builds on MinGW with MSYS + - All known problems with MinGW fixed + - Fix bugs in stream classes that caused failures and crashes with STLport + - Detects and uses STLport automatically +2.5.2 + - Fix memory leaks + - Fix problems with NaN (not-a-number values) on some compilers +2.5.1 + - Fix configure script; broke when very recent libpqxx was already installed + - Fix cursor breakage when "long" is more than 32 bits + - Fix cases where new-style abort/doubt handlers are used + - Fix for division-by-zero error in Visual C++ (changed sample headers) + - Improved checking for strerror_r in configure script + - Fix for problem MinGW has with configure script + - Fix spurious failure of Oid check in configure script +2.5.0 + - Fix race condition in removing triggers + - Fix binary string conversion with older libpq + - Fix some error strings that may previously have come out wrong + - No longer includes any libpq headers while compiling client code + - Improved thread safety: avoid strerror() where possible + - Prepared statements + - Translate more error conditions to std::bad_alloc exception + - Clearer and more specific explanations for configuration failures + - Improved documentation + - Looks for standard library in global namespace as well as std + - Accepts standard C library in std namespace + - Release script automatically tests with a range of compilers, not just one + - Compatible with g++ 2.95 again; this time it's tested automatically +2.4.4 + - Fix problems building shared library in Visual C++ + - Fix autobuild in Debian, which was broken by mistake in BSD grep workaround + - Fix conversion of string to floating-point type NaN + - Remove stray CVS directories from distribution archive + - Workaround for Visual C++ problem when issuing messages from destructors + - Yet more workarounds for Visual C++ bugs + - Fix situation where connection state might not be restored after failure + - Fix configuration problem on SunOS + - Network speedup in connection setup with pending variables and/or triggers +2.4.3 + - Yet more workarounds for bugs in Visual C++ .NET 2003 + - Fixes for SunC++ 5.5 + - On Visual C++, now defines NOMINMAX, fixing large object support + - Workaround for BSD grep + - Improvements for builds from CVS + - Sample config headers for Sun ONE Studio 8 +2.4.2 + - Fix minor problems with Apple's version of g++ 3.3 + - Fix problem with MingW on Windows + - Workarounds and fixes for Visual C++.NET 2003 + - Renewed compatibility with g++ 2.95 + - More sample configuration headers + - Updated reference documentation + - Removed assert code +2.4.1 + - Several bugs in icursor_iterator fixed; incompatible interface changes + - Tightens throw specifications on begin(), end(), size(), capacity() + - Containers define reference and pointer types + - Implements swap() in all container types + - Implements == and != in all container types + - Stabilizes new (but still limited) cursor interface + - icursor_iterator thinks purely in stride granularity + - Introduces </<=/>/>= comparisons for icursor_iterators + - Allows "adopted SQL cursors" in new cursor interface + - Reference-counting in binarystrings, so they can be copied (and efficiently) + - Fixes reference-to-temporary problem with std::reverse_iterator in results + - Result/tuple reverse_iterators no longer require std::reverse_iterator + - Includes some sample config headers (in config/sample-headers) + - Replaces iffy autoconf checks (avoid failures with maintainer mode's -Werror) + - Fixes incompatibility with some implementations of Unix "cut" program (again) +2.4.0 + - Fixes incompatibility with some implementations of Unix "cut" program + - Fixes "ptrdiff_t redefinition" problem in some environments + - More container-like tuples, so fields can be iterated + - All size_type types are now unsigned + - More conservative robusttransaction--thanks Tom Lane + - Stream-like extraction operator for result field conversion + - Warnings about deprecated headers now suppressed while compiling library + - Iterator constructors and copy assignments now have empty throw specs +2.3.0 + - Generates MinGW Makefile automatically + - Documents MinGW build + - Workaround for missing prepared-statement support + - Potential bug fixed in closing of connections + - Fixed incompatibility between new cursor streams and older backends + - Removed pqxxbench +2.2.9 + - Bugfix in removing trigger + - Added "failed connection" to regression test + - Some changes to throw specifications + - Putting libpq in its own namespace is optional +2.2.8 + - Moved libpq into pqxx::internal::pq namespace + - New config system separates compiler-related items from libpq-related ones + - Auto-generates Visual C++ Makefile, should always remain up-to-date now +2.2.7 + - Bugfix: from_string() didn't handle LONG_MIN--thanks Yannick Boivin +2.2.6 + - Complete "pipeline" rewrite, for better exception safety + - New garbage collection scheme for "result;" constructors now exception-free +2.2.5 + - First new cursor classes! + - Fixed strange failure in tablewriter during large insertions + - Updated tutorial +2.2.4 + - New utility class template, items<> for easy container initialization + - New utility function template, separated_list() + - Error handling bugfix in tablewriter + - Fixed tablereader handling of lines ending in empty fields + - tablereader lines no longer end in newline with old libpq versions +2.2.3 + - Trigger names no longer need to be proper identifiers + - Compile fixes for g++ 3.4.0 and other modern compilers + - Tablestreams may specify column lists + - Deprecated Quote() in favour of sqlesc(); improved quoting + - Fixed generation of libpqxx.spec +2.2.2 + - Bugfix in fieldstream w.r.t. reading strings on some systems + - Renamed config.h to internalconfig.h to avoid confusion + - New connection functions allow client to sleep until notification arrives + - Notification functions return number of notifications received + - Even fewer client-visible macros exported by libconfig.h +2.2.1 + - New, 2.x-style string conversions without locale problem + - Documentation improvements + - Implemented result::swap() +2.2.0 + - Installs to /usr/local by default, NOT to /usr/local/pqxx like before! + - Uses Postgres-provided script to find Postgres (thanks Peter Eisentraut) + - Which means no more configure arguments required on Irix (thanks Arjen Baart) + - Fixes long-standing bug in result class! + - New pipeline class for throughput optimization + - New field stream class: read result field as C++ stream + - Separate namespace pqxx::internal for definitions not relevant to the user + - More Windows compilation fixes + - SUN Workshop 6 compile fixes and workarounds (thanks Jon Meinecke) + - Implemented reverse_iterator for result class + - Checks for functional std::reverse_iterator template + - Preliminary Makefile for MinGW compiler (thanks Pasquale Fersini) + - Changed the way unique<> works + - Checks for functional std::count_if() + - Bugs fixed & test programs added +2.1.3 + - Makefile fixes for Visual C++, thanks Paresh Patel + - Library ABI versioning implemented, thanks Roger Leigh + - Uses old SQL isolation level syntax for compatibility, thanks koun@sina.com + - tablestreams can explicitly complete() before destructor + - Bugfix in robusttransaction: forgot to set isolation level + - Fixed off-by-ones in tablewriter escape code + - tablestreams now use \n-style escape sequences + - tablestreams support octal numbers + - Freely definable "null" strings in tablestreams, as originally intended + - Improved Debian packaging, thanks Roger Leigh + - tablestreams use libpq's new-style COPY functions, if available + - Extended automation of build/release procedure + - tablewriter writes in nonblocking mode to help hide communication latency + - Can get backend variables as well as set them + - More configuration macro cleanups + - Workaround for missing clear() in standard string + - Merry Christmas! +2.1.2 + - Compile fix for gcc libstdc++ 2.9, thanks Jaroslaw Staniek + - Moved deprecated functions below current ones + - Cleanups for Debian packaging (thanks Roger Leigh, new Debian maintainer!) + - Updated authors listings + - Bumped ABI version number for the first time (now 2:0:1) +2.1.1 + - More workarounds for gcc 2.95 + - Automated tools keep test makefiles up to date +2.1.0 + - Asynchronous connections + - Fixed configure --includedir option (thanks Ray Dassen!) + - Compile fixes for SUN Workshop 6, and one for gcc on FreeBSD 4.8 +2.0.0 + - New stable release! + - Includes all changes since 1.5 release. + - Workarounds for Microsoft Visual C++ 7 problems. Thanks Costin Musteata! + - No longer need to define PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION + - Integrated Windows configuration into regular configuration + - Only uses #warning if preprocessor supports it + - Works on libpq versions without PQ[un]escapeBytea() +1.9.9 + - Minor documentation changes +1.9.8 + - Workaround for compile problem with postgres 7.3 + - Convenience typedef for transaction<>: "work" +1.9.7 + - binarystring rewritten and moved to its own file + - binarystring::size() does not include terminating null byte! + - Implemented escaping of binary strings + - Fix in workaround for missing numeric_limits on some compilers + - String conversion supported for unsigned char * + - More helpful link errors for unsupported string conversions + - Complete test coverage +1.9.6 + - Fixes in "field table" support + - Improved coexistence with client program's config.h, if any + - Prefixed autoconf macros used in headers with "PQXX_" +1.9.5 + - Header file contents moved to .hxx files for editor filetype recognition + - Fixes wrong timestamp for include/pqxx/result in 1.9.4 distribution +1.9.4 + - Fixes Visual C++ build problem when compiling as library +1.9.3 + - Quick release for various minor changes +1.9.2 + - Renamed most public member functions to all-lower-case names + - <pqxx/all> (previously <pqxx/all.h> is now called <pqxx/pqxx> +1.9.1 + - tablestream destructor crashed if table didn't exist (thanks Sean [Rogers?]) + - Renamed all header files to remove ".h" suffix + - Tables created by regression test now prefixed with "pqxx" for safety + - Large objects now considered stable + - Migrated tutorial from SGML to DocBook XML (thanks Wichert Akkerman) + - Added tests 57-59 + - Fixed compile error in largeobject + - Updated Windows makefiles +1.9.0 + - EVERYTHING HAS CHANGED. Read the list or run into trouble! + - CURSOR HAS INCOMPATIBLE CHANGES AND MAY BE REPLACED COMPLETELY + - CACHEDRESULT HAS INCOMPATIBLE CHANGES (won't compile without changes) + - REVISE YOUR TRANSACTORS; now templatized on transaction type + - Finally got license file in order + - Incompatible change in setting transactor quality of service + - Cursors require serializable isolation level (checked at link time) + - Renamed Connection_base to connection_base, Connection to connection, + LazyConnection to lazyconnection + - Renamed LargeObject to largeobject, LargeObjectAccess to largeobjectaccess + - Renamed Noticer to noticer + - Renamed Trigger to trigger + - Renamed Result to result, Tuple to tuple, Field to field + - Renamed Unique<> to unique<> + - Renamed CachedResult to cachedresult + - Transformed Transaction Taxonomy (TTT): + - Renamed Transaction_base to transaction_base + - Renamed Transaction to transaction + - Renamed Transactor to transactor<> (now a template) + - Implemented transaction isolation levels as compile-time static properties + - transaction and robusttransaction now templatized on their isolation levels + - cachedresult requires serializable isolation level (checked at link time) + - Now need to include pqxx/transactor.h yourself if you need transactors + - Large objects require real backend transaction at compile time + - New type oid and constant oid_none for row identifiers resp. null oid + - Added some forgotten PQXX_LIBEXPORTs + - Tweaked documentation in many places +1.8.1 + - By popular request: more convenient way to read field values + - Documented locale sensitivity of ToString(), FromString(), Field::to() +1.8.0 + - Compiles on gcc 2.95 again (heavy streambuf workarounds in largeobject.h) + - ConnectionItf renamed to Connection_base, TransactionItf to Transaction_base + - connectionitf.h is now connection_base.h, transactionitf.h connection_base.h +1.7.8 + - BinaryString class for unescaping bytea strings + - PQAlloc template keeps track of libpq-allocated objects + - Removed some consts in Unique<>, ConnectionItf, sorry! + - Can now set session variables on connections, transactions +1.7.7 + - ./configure also looks for postgres in /usr/local/pgsql + - test007 now uses SQL_ASCII as its test encoding + - integrated Greg Hookey's Debian packaging +1.7.6 + - added postgres library (libpq) to dynamic link path +1.7.5 + - added test052 - test055 + - added Result::Tuple::ColumnNumber() + - also test setting of client encodings + - removed superfluous versions of to_file() from large object classes +1.7.4 + - new exception class, sql_error, remembers query text + - moved exception classes to new file include/pqxx/except.h + - test cases report texts of any failed queries + - added tools/rmlo.cxx +1.7.3 + - default constructors for connection classes + - revamped seeking operations on large objects + - better error messages in large objects + - added test050, test051 +1.7.2 + - more workarounds for Sun CC 5.1, thanks Jeroen van Erp! + - preliminary support for "named" queries + - can now Quote() string constants + - included Doxyfile in distribution archive + - helps avoid Windows memory allocation problem in DLLs + - allows setting of client character set encoding +1.7.1 + - regenerated documentation +1.7.0 + - removed all deprecated features + - connection string documentation in README + - separate Connection, LazyConnection classes + - made test001 more concise + - added test049 +1.6.4 + - configure script now respects different std namespace +1.6.3 + - olostream, lostream now flush themselves before closing + - fixed compilation problems when using ToString<>() on a plain char * + - compilation fixes for Sun compiler (thanks Jeroen van Erp!) + - added .pc file for pkgconfig (thanks Ray Dassen!) +1.6.2 + - Debian packaging added to distribution archive + - new ilostream, olostream, lostream classes +1.6.1 + - large object's cunlink() replaced by remove() + - default constructor for LargeObject +1.6.0 + - new large objects interface + - added test048 +1.5.0 + - allow result fields to be written to streams + - removed confusing CachedResult::clear() + - minor documentation updates + - added test046, test047 + - added <pqxx/all.h> convenience header +1.4.5 + - fixed crash CachedResult that was less shallow than I thought + - fixed quoting problem with adopted SQL cursors +1.4.4 + - (forgot to save cursor.cxx with new constructor in 1.4.4, sorry) +1.4.3 + - all tests now have three-digit numbers + - Cursor can adopt SQL cursor returned by a function +1.4.2 + - bugfix in CachedResult when accessing empty Results + - minor documentation improvements +1.4.1 + - documents new homepage: http://pqxx.tk/ + - Connection constructor accepts null connect string + - Exec() now also takes queries as C++ strings +1.4.0 + - Connection::IsOpen() renamed to is_open() + - NoticeProcessor replaced by Noticer (with C++ linkage) +1.3.7: + - detects nasty rare problem case with Cursors in unknown positions +1.3.6: + - fixed detection of missing PQescapeString(). Thanks David Wright! +v1.3.5: + - documented Windows build procedure + - fixed problem with upper-case letters in cursor names. Thanks key88! +2003-01-19 16:00, v1.3.4: + - support long double type + - clarified some error messages +2003-01-08 18:45, v1.3.3: + - fix missing include in test13 +2003-01-07 02:30, v1.3.2: + - configure looks for postgres includes/library in more places, thanks Ray! +2003-01-02 23:00, v1.3.1: + - bugfix in Cursor positioning +2003-01-02 20:30, v1.3.0: + - absolute positioning for Cursor + - better documentation on cursors + - reduced, but improved test suite output +2002-12-23 17:30, v1.2.8: + - Cursor::Move() returns number of rows skipped + - new typedef Cursor::size_type +2002-12-14 23:30, v1.2.7: + - test suite now distinguishes expected errors from unexpected ones +2002-12-09 20:00, v1.2.6: + - fixed some Cursor test cases for change in postgres 7.3 + - added important warning to Cursor +2002-12-09 02:00, v1.2.5: + - added important warning to CachedResult +2002-12-08 14:14, v1.2.4: + - fixed compile error on some systems in include/pqxx/util.h +2002-12-04 12:00, v1.2.3: + - workaround for broken <sys/select.h> on some systems + - fixed Quote() bug +2002-12-03 01:30, v1.2.2: + - fixed serious CachedResult bug + - added test41 +2002-12-02 17:00, v1.2.1: + - hopefully fixed cursor bug with PostgreSQL 7.3 +2002-12-01 22:00, v1.2.0: + - new CachedResult class +2002-11-07 13:15, v1.1.4: + - workaround for missing InvalidOid definition +2002-10-23 16:00, v1.1.3: + - Cursor & TableStream hierarchy now work on any transaction type + - get no. of affected rows & oid of inserted row from Result + - increased test coverage +2002-10-21 01:30, v1.1.2: + - updated build procedure + - Debian packaging improvements +2002-09-25 03:00, v1.1.1: + - supports activating/deactivating of connections + - various Connection getters now activate deferred connection first +2002-09-23 01:00, v1.1.0: + - supports lazy connections (added 19 test cases just for these) + - greatly reduced performance overhead for RobustTransaction + - removed id field from RobustTransaction's transaction log tables +2002-09-14 20:00, v1.0.1: + - now lives on GBorg + - various packaging updates +2002-06-12 17:30, v0.5.1: + - no longer have to destroy one transaction before creating the next +2002-06-07 17:15, v0.5.0: + - "make install" now finally installs headers! + - distribution now includes SGML (DocBook) version of tutorial +2002-06-04 15:00, v0.4.4: + - may now have multiple triggers with same name on single connection +2002-06-02 23:00, v0.4.3: + - fixed TableReader problem with \t and \n +2002-06-01 21:00, v0.4.2: + - hopefully fixes compile problem with broken std::iterator + - configure no longer requires --with-postgres-include=/usr/include/postgresql +2002-05-29 22:00, v0.4.1: + - can now also handle bool, unsigned char, short field types +2002-05-27 22:30, v0.4.0: + - RENAMED Transactor::TRANSACTIONTYPE to argument_type for STL conformance + - RENAMED Result::Field::name() to Name() + - documentation improvements + - minor optimizations +2002-05-18 00:00, v0.3.1: + - removed broken postgres_fe.h dependency (hopefully permanent fix) +2002-05-12 22:45, v0.3.0: + - also looks for postgres_fe.h in postgres' internal/ directory (tmp fix) +2002-05-05 01:30, v0.2.3: + - extensive build instructions in README + - make check now controlled through PG environment variables +2002-05-04 19:30, v0.2.2: + - more STL conformance + - fixed regression test + - test6 now copies "orgevents" to "events" by default +2002-04-28 23:45 Version bumped to 0.2 +2002-04-28 23:45 Self-generated distribution archive +2002-04-27 14:20 Replaced automake symlinks with actual files +2002-04-07 02:30 Released with configure script +2002-03-29 01:15 Not yet released. Still integrating autogen stuff... diff --git a/contrib/libs/libpqxx/README-UPGRADE b/contrib/libs/libpqxx/README-UPGRADE new file mode 100644 index 0000000000..f0368d6875 --- /dev/null +++ b/contrib/libs/libpqxx/README-UPGRADE @@ -0,0 +1,11 @@ +NOTICES FOR USERS UPGRADING FROM EARLIER VERSIONS TO 6.x + +As of 6.0, libpqxx requires C++11 or better. Make sure that your libpqxx is +built against the same version of the C++ standard as your own application, or +there may be build problems. + +It may be possible to paper over some mismatches. If your application build +fails with errors about `std::experimental::optional`, try defining a macro +`PQXX_HIDE_EXP_OPTIONAL` in your application's build. This will suppress +support for `std::experimental::optional` even if libpqxx was built to assume +that the feature is present. diff --git a/contrib/libs/libpqxx/README.md b/contrib/libs/libpqxx/README.md new file mode 100644 index 0000000000..754bb02a40 --- /dev/null +++ b/contrib/libs/libpqxx/README.md @@ -0,0 +1,489 @@ +libpqxx +======= + +Welcome to libpqxx, the C++ API to the PostgreSQL database management system. + +Compiling this package requires PostgreSQL to be installed -- including the C +headers for client development. The library builds on top of PostgreSQL's +standard C API, libpq, though this fact is almost completely hidden from +programmes which use libpqxx. + +As of release 6.0, C++11 is the minimum supported C++ version. Make sure your +compiler supports this, and if necessary, that you have support for C++11 +configured. + +**Version 7.0 will require C++17.** However, it's probably not a problem if +your compiler does not implement C++17 fully. Initially the 7.x series will +only require some basic C++17 features such as `std::string_view`. More +advanced use may follow later. + +Also, **7.0 will make some breaking changes in rarely used APIs:** + * All `connection` classes will be folded into a single class. + * Custom `connection` classes will no longer be supported. + * Connection reactivation will be explicit: _you_ call `activate()` if needed. + * "String traits" (for string conversions) will have a slightly different API. + +Find libpqxx on Github: https://github.com/jtv/libpqxx + + +Building libpqxx +---------------- + +There are three very different ways of building libpqxx: + 1. Using CMake, on any system which supports it. + 2. On Unix-like systems, using a `configure` script. + 3. With Visual Studio on Windows, using supplied project files and headers. + +The CMake build should work on any system where CMake is supported. This is a +recently contributed alternative build, so if you run into problems, your help +could be crucial in fixing them. + +The "Unix-like" section applies to systems that look like Unix: GNU/Linux, +Apple OSX and the BSD family, AIX, HP-UX, Irix, Solaris, etc. Microsoft +Windows with a Unix-like environment such as Cygwin or MinGW installed should +also work in the same way. + +There is a separate section below for a Visual C++ build on Windows. It takes +a bit of work, and if the CMake build works well, we may drop support for the +Windows/Visual C++ build later. + + +### Using CMake + +On CMake the standard way of working is to have the source tree in one +directory, and build in another. (The `configure` script supports this as +well, but that build is enough work that I didn't bother documenting it.) +Let's say you have the libpqxx source tree in a location `$SOURCE`, and are +building in a different location `$BUILD`. + +CMake also lets you choose whether to run the ultimate build through `make`, +or some other tool. The default on Unix-like systems is `make`, but you may +have to look in the CMake documentation what works well on your system. + +For a default build, using those two directories, go into `$BUILD` and run: + +```shell + cmake $SOURCE +``` + +This sets up the build, in your current directory. + +Stay in the `$SOURCE` directory, and run: + +```shell + make +``` + +If you have multiple cores that you want to put to good use, use the `-j` +option to make it run multiple jobs in parallel. For instance, if you have 8 +CPU cores, you'll probably want to be compiling about 8 files simultaneously: + +```shell + make -j8 +``` + + +### On Unix-like systems + +For the Unix-like systems the procedure is the standard "configure, make, make +install" sequence. In order to run the test suite, you'll also need to set up a +database for the tests to play with. + +Run the "configure" script with the `--help` option to see build and +installation options. You need to get these right before you compile. Then: + +```shell + ./configure # (plus any options you find appropriate) + make +``` + +This will compile the library. You'll also want to run the test suite to make +sure that everything works. To prepare for that, you need to set up a +disposable test database that the test suite to play with. You'll want +password-less authentication so that you won't need to log in for every test. + +In this example, the test database is called pqxx-test and runs on a server at +IP address 192.168.1.99. Before running the test, make sure you can log into +your test database with psql, the command-line SQL shell that comes with +PostgreSQL: + +```shell + PGHOST=192.168.1.99 PGDATฺABASE=pqxx-test psql +``` + +Once you have that working, use the same login parameters to run the libpqxx +test suite: + +```shell + make PGHOST=192.168.1.99 PGDATABASE=pqxx-test check +``` + + +Assuming that the test suite runs successfully, you are now ready to install. +You'll typically need superuser privileges to run this command: + +```shell + make install +``` + +Now you should be able to link your own programs with libpqxx. + +If something went wrong along the way, or what you have isn't quite what you +wanted, it's time to move on to that fineprint that we hinted at earlier. + + +#### 1. Configure + +A word on the configure script. It needs to find the C header and the binary +for libpq, the C-level client library, so that the libpqxx build procedure can +make use of them. + +The configure script finds these files by running a script called pg\_config +that comes with PostgresQL. If you have postgres installed, pg\_config should +be somewhere on your system. It will "know" where the relevant files are. The +configure script just needs to run it. + +Make sure that the folder containing pg\_config is in your executable path +before you run the configure script, or it will fail with a message like: + +``` +configure: error: PostgreSQL configuration script pg_config was not found. +``` + +If you don't want to have pg\_config in your path for whatever reason, or you +have multiple PostgreSQL installations on your system (each with their own copy +of pg\_config) and wish to override the default version, add an option like +this to your "configure" command line: + +```shell + PG_CONFIG=/home/me/postgres/bin/pg_config +``` + +Here, "/home/me/postgres/bin/pg\_config" is just an example of where your +preferred copy of pg\_config might be. This would tell the configure script +that you wish to build a libpqxx based on the postgres version found in +/home/me/postgres. + +About installing: if you wish to install libpqxx in a custom location, such as +your home directory /home/me, you can specify this to the configure script +before you build libpqxx. You select the installation location using the +configure script's --prefix option, e.g.: + +```shell + ./configure --prefix=/home/me +``` + +A custom location can be useful to keep locally-build software separate from +packaged software. Conventional installation locations for custom software on +Unix-like systems are /usr/local and /opt. + +Custom installation locations can also be handy if you don't have administrator +rights on the machine you're working on! + +The configure scripts supports many other options to tweak how and where +libpqxx is to be built and installed; try the --help option to get an overview +if you're interested. + +If configuration just plain won't work for whatever reason: take a look in the +config/sample-headers/ directory. Here you will find configuration headers for +various compilers and libpq versions. Pick the config-internal-\*.h and +config-public-\*.h headers for the compiler and libpq version most closely +matching your own, and see if they work for you. You may also want to tweak +them manually. + + +#### 2. Make + +One problem some people have run into at this stage is that the header files +for PostgreSQL need the OpenSSL header files to be installed. If this happens +to you, make sure openssl is installed and its headers are in your compiler's +include path. + + +#### 3. Make Check + +"Make check" is where you compile and run the test suite that verifies the +library's functionality. + +The "make check" procedure needs a database to play with. It will create and +drop various tables in that database. Use a throwaway database for this or +risk losing data! + +(Actually the test only manipulates tables whose names start with "pqxx" so in +practice the risk will be small. But better safe than sorry: use a disposable +test database separate from your own data.) + +To direct the test suite to the right database, set some or all of the +following environment variables as needed for "make check": + +``` + PGDATABASE (name of database; defaults to your user name) + PGHOST (database server; defaults to local machine) + PGPORT (TCP port to connect to; default is 5432) + PGUSER (your PostgreSQL user ID; defaults to your login name) + PGPASSWORD (your PostgreSQL password, if needed) +``` + +Further environment variables that may be of use to you are documented in the +libpq documentation and in the manpage for Postgres' command-line client, psql. + +Setting environment variables works differently depending on your shell, but +try one of these: + +```shell + VARIABLE=value + export VARIABLE +``` + +or + +```shell + set VARIABLE=value +``` + +Try printing the variable afterwards to make sure. The command is normally + +```shell + echo $VARIABLE +``` + +If you set the variable successfully, it should print the value you assigned. +It will print nothing if you failed to set the variable. + +On Unix-like systems, postgres may be listening on a Unix domain socket instead +of a TCP port. The socket will appear as a file somewhere in the filesystem +with a name like .s.PGSQL.5432. To connect to this type of socket, set PGHOST +to the directory where you find this file, as an absolute path. For example, +it may be "/tmp" or "/var/run" or "/var/run/postgresql". The leading slash +tells libpq that this is not a network address but a local Unix socket. + + +#### 4. Make Install + +This is where you install the libpqxx library and header files to your system. + +Assuming this succeeds, you should now be able to build your own programs by +adding the location of the header files (e.g. /usr/local/pqxx/include) to your +compiler's include path when compiling your application. Similarly, add the +location of the library binary (e.g. /usr/local/pqxx/lib) to your library +search path when linking your application. See the documentation and the test +programs for more information on using libpqxx. + +If you link with the dynamic version of the library, you may find that your +program fails to run because the run-time loader cannot find the library. + +There are several ways around that. Pick the first option that works for you: +1. by linking to the static version of the library, or +2. adding a link to the dynamic libpqxx library somewhere in your system's + standard library locations, or +3. adding libpqxx's lib/ directory to your loader's search path before + running your program. + +On Unix-like systems including GNU/Linux, the loader's search path can be +extended by setting the LD\_LIBRARY\_PATH variable. + +Enjoy! + + +### On Microsoft Windows + +Project files for Visual C++ are provided in the win32 directory, along with +some other Windows-specific material. These are very old, so if you run into +problems, please let us know what we can do to fix them. One known problem is +that _folder names with spaces in them_ cause trouble. If you run into +trouble, try using the alternative build using CMake! + +As yet another alternative, if you are running a Unix-like environment such as +Cygwin, you may want to try if the Unix build procedure works for you. In +theory it should be possible to run the configure script and build with Visual +C++ or any other compiler, so long as you have a reasonably Unix-like shell +environment. + +If you do proceed with the Visual C++ files, you'll need to copy the most +appropriate compile-time configuration files from various subdirectories in +config/example-headers/ to include/pqxx. You'll want to tweak them manually +to define the exact features your system, compiler, and PostgreSQL versions +support. On a Unix-like system the configure script would do this for you. + +Before trying to compile with Visual C++, you'll at least need to copy the file +win32/common-sample to win32/common, and edit the latter to reflect the proper +paths to your PostgreSQL headers and the libpq library. See the win32 +subdirectory for more documentation. + + +#### Manual Configuration: config-\*-\*.h + +Normally, on any vaguely Unix-like system, the configuration headers (called +config-internal-\*.h for the library's internal use, config-public-\*.h for +both the library and client programs) are generated from config.h.in. All +these files, once generated, are situated in the include/pqxx/ directory. + +The configitems file lists all configuration items and where they go; but see +win32/INSTALL.txt for a detailed description of how these files work. + +Getting the compiler-related configuration right can take several stages of +trying to build, looking at error messages, looking for configuration items +that may be related, changing them, and building again. If nothing seems to +help, register an issue on Github. Be sure to read the FAQ though, because +there are some known problems. + + +#### Windows-Specific Build Problems + +One problem specific to Windows is that apparently it doesn't let you free +memory in a DLL that was allocated in the main program or in another DLL, or +vice versa. This can cause trouble when setting your own notice handlers to +process error or warning output. Recommended practice is to build libpqxx as +a static library, not a DLL. + + +Documentation +------------- + +The doc/ directory contains API reference documentation and a tutorial, both in +HTML format. These are also available online. + +For more detailed information, look at the header files themselves. These are +in the include/pqxx/ directory. The reference documentation is extracted from +the headers using a program called Doxygen. + +When learning about programming with libpqxx, you'll want to start off by +reading about the `connection_base` class and its children, as well as the +`transaction_base` class. + +For programming examples, take a look at the test programs in the test/ +directory. If you don't know how a certain function or class is used, try +searching the test programs for that name. + + +Programming with libpqxx +------------------------ + +Your first program will involve the libpqxx classes "connection" (see headers +`pqxx/connection_base.hxx` and `pqxx/connection.hxx`), and `work` (a +convenience alias for `transaction<>` which conforms to the interface defined +in `pqxx/transaction_base.hxx`). + +These `*.hxx` headers are not the ones you include in your program. Instead, +include the versions without filename suffix (e.g. `pqxx/connection_base`). +Those will include the actual .hxx files for you. This was done so that +includes are in standard C++ style (as in `<iostream>` etc.), but an editor +will still recognize them as files containing C++ code. + +Continuing the list of classes, you will most likely also need the result class +(`pqxx/result.hxx`). In a nutshell, you create a `connection` based on a +Postgres connection string (see below), create a `work` in the context of that +connection, and run one or more queries on the work which return `result` +objects. The results are containers of rows of data, each of which you can +treat as an array of strings: one for each field in the row. It's that simple. + +Here is a simple example program to get you going, with full error handling: + +```c++ +#include <iostream> +#include <pqxx/pqxx> + +int main() +{ + try + { + pqxx::connection C; + std::cout << "Connected to " << C.dbname() << std::endl; + pqxx::work W(C); + + pqxx::result R = W.exec("SELECT name FROM employee"); + + std::cout << "Found " << R.size() << "employees:" << std::endl; + for (auto row: R) + std::cout << row[0].c_str() << std::endl; + + std::cout << "Doubling all employees' salaries..." << std::endl; + W.exec("UPDATE employee SET salary = salary*2"); + + std::cout << "Making changes definite: "; + W.commit(); + std::cout << "OK." << std::endl; + } + catch (const std::exception &e) + { + std::cerr << e.what() << std::endl; + return 1; + } + return 0; +} +``` + + +Connection strings +------------------ + +Postgres connection strings state which database server you wish to connect to, +under which username, using which password, and so on. Their format is defined +in the documentation for libpq, the C client interface for PostgreSQL. +Alternatively, these values may be defined by setting certain environment +variables as documented in e.g. the manual for psql, the command line interface +to PostgreSQL. Again the definitions are the same for libpqxx-based programs. + +The connection strings and variables are not fully and definitively documented +here; this document will tell you just enough to get going. Check the +PostgreSQL documentation for authoritative information. + +The connection string consists of attribute=value pairs separated by spaces, +e.g. "user=john password=1x2y3z4". The valid attributes include: + +- `host` + Name of server to connect to, or the full file path (beginning with a + slash) to a Unix-domain socket on the local machine. Defaults to + "/tmp". Equivalent to (but overrides) environment variable PGHOST. + +- `hostaddr` + IP address of a server to connect to; mutually exclusive with "host". + +- `port` + Port number at the server host to connect to, or socket file name + extension for Unix-domain connections. Equivalent to (but overrides) + environment variable PGPORT. + +- `dbname` + Name of the database to connect to. A single server may host multiple + databases. Defaults to the same name as the current user's name. + Equivalent to (but overrides) environment variable PGDATABASE. + +- `user` + User name to connect under. This defaults to the name of the current + user, although PostgreSQL users are not necessarily the same thing as + system users. + +- `requiressl` + If set to 1, demands an encrypted SSL connection (and fails if no SSL + connection can be created). + +Settings in the connection strings override the environment variables, which in +turn override the default, on a variable-by-variable basis. You only need to +define those variables that require non-default values. + + +Linking with libpqxx +-------------------- + +To link your final program, make sure you link to both the C-level libpq library +and the actual C++ library, libpqxx. With most Unix-style compilers, you'd do +this using the options + +``` + -lpqxx -lpq +``` + +while linking. Both libraries must be in your link path, so the linker knows +where to find them. Any dynamic libraries you use must also be in a place +where the loader can find them when loading your program at runtime. + +Some users have reported problems using the above syntax, however, particularly +when multiple versions of libpqxx are partially or incorrectly installed on the +system. If you get massive link errors, try removing the "-lpqxx" argument from +the command line and replacing it with the name of the libpqxx library binary +instead. That's typically libpqxx.a, but you'll have to add the path to its +location as well, e.g. /usr/local/pqxx/lib/libpqxx.a. This will ensure that the +linker will use that exact version of the library rather than one found +elsewhere on the system, and eliminate worries about the exact right version of +the library being installed with your program.. diff --git a/contrib/libs/libpqxx/include/pqxx/array b/contrib/libs/libpqxx/include/pqxx/array new file mode 100644 index 0000000000..97311d1c18 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/array @@ -0,0 +1,4 @@ +/** Handling of SQL arrays. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/array.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/array.hxx b/contrib/libs/libpqxx/include/pqxx/array.hxx new file mode 100644 index 0000000000..dbb464c540 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/array.hxx @@ -0,0 +1,101 @@ +/** Handling of SQL arrays. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ARRAY +#define PQXX_H_ARRAY + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/internal/encoding_group.hxx" +#include "pqxx/internal/encodings.hxx" + +#include <stdexcept> +#include <string> +#include <utility> + + +namespace pqxx +{ +/// Low-level array parser. +/** Use this to read an array field retrieved from the database. + * + * This parser will only work reliably if your client encoding is UTF-8, ASCII, + * or a single-byte encoding which is a superset of ASCII (such as Latin-1). + * + * Also, the parser only supports array element types which use either a comma + * or a semicolon ("," or ";") as the separator between array elements. All + * built-in types use comma, except for one which uses semicolon, but some + * custom types may not work. + * + * The input is a C-style string containing the textual representation of an + * array, as returned by the database. The parser reads this representation + * on the fly. The string must remain in memory until parsing is done. + * + * Parse the array by making calls to @c get_next until it returns a + * @c juncture of "done". The @c juncture tells you what the parser found in + * that step: did the array "nest" to a deeper level, or "un-nest" back up? + */ +class PQXX_LIBEXPORT array_parser +{ +public: + /// What's the latest thing found in the array? + enum juncture + { + /// Starting a new row. + row_start, + /// Ending the current row. + row_end, + /// Found a NULL value. + null_value, + /// Found a string value. + string_value, + /// Parsing has completed. + done, + }; + +// XXX: Actually _pass_ encoding group! + /// Constructor. You don't need this; use @c field::as_array instead. + explicit array_parser( + const char input[], + internal::encoding_group=internal::encoding_group::MONOBYTE); + + /// Parse the next step in the array. + /** Returns what it found. If the juncture is @c string_value, the string + * will contain the value. Otherwise, it will be empty. + * + * Call this until the @c juncture it returns is @c done. + */ + std::pair<juncture, std::string> get_next(); + +private: + const char *const m_input; + const std::string::size_type m_end; + internal::glyph_scanner_func *const m_scan; + + /// Current parsing position in the input. + std::string::size_type m_pos; + + std::string::size_type scan_single_quoted_string() const; + std::string parse_single_quoted_string(std::string::size_type end) const; + std::string::size_type scan_double_quoted_string() const; + std::string parse_double_quoted_string(std::string::size_type end) const; + std::string::size_type scan_unquoted_string() const; + std::string parse_unquoted_string(std::string::size_type end) const; + + std::string::size_type scan_glyph(std::string::size_type pos) const; + std::string::size_type scan_glyph( + std::string::size_type pos, + std::string::size_type end) const; +}; +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/basic_connection.hxx b/contrib/libs/libpqxx/include/pqxx/basic_connection.hxx new file mode 100644 index 0000000000..6e7372195a --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/basic_connection.hxx @@ -0,0 +1,107 @@ +/** Definition of the pqxx::basic_connection class template. + * + * Instantiations of basic_connection bring connections and policies together. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/basic_connection instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_BASIC_CONNECTION +#define PQXX_H_BASIC_CONNECTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <cstddef> +#include <memory> +#include <string> + +#include "pqxx/connection_base.hxx" + + +namespace pqxx +{ + +/// Base-class template for all libpqxx connection types. +/** @deprecated In libpqxx 7, all built-in connection types will be implemented + * as a single class. You'll specify the connection policy as an optional + * constructor argument. + * + * Combines connection_base (the highly complex class implementing essentially + * all connection-related functionality) with a connection policy (a simpler + * helper class determining the rules that govern the process of setting up the + * underlying connection to the backend). + * + * The pattern used to combine these classes is the same as for + * basic_transaction. Through use of the template mechanism, the policy object + * is embedded in the basic_connection object so that it does not need to be + * allocated separately. This also avoids the need for virtual functions in + * this class. + */ +template<typename CONNECTPOLICY> class basic_connection_base : + public connection_base +{ +public: + basic_connection_base() : + connection_base(m_policy), + m_options(std::string{}), + m_policy(m_options) + { init(); } + + /// The parsing of options is the same as libpq's PQconnect. + /// See: https://www.postgresql.org/docs/10/static/libpq-connect.html + explicit basic_connection_base(const std::string &opt) : + connection_base(m_policy), + m_options(opt), + m_policy(m_options) + {init();} + + /// See: @c basic_connection(const std::string &opt) + explicit basic_connection_base(const char opt[]) : + basic_connection_base(opt ? std::string{opt} : std::string{}) {} + + explicit basic_connection_base(std::nullptr_t) : basic_connection_base() {} + + ~basic_connection_base() noexcept + { close(); } + + const std::string &options() const noexcept //[t01] + {return m_policy.options();} + +private: + /// Connect string. @warn Must be initialized before the connector! + std::string m_options; + /// Connection policy. @warn Must be initialized after the connect string! + CONNECTPOLICY m_policy; +}; + + +/// Concrete connection type template. +/** @deprecated In libpqxx 7, all built-in connection types will be implemented + * as a single class. You'll specify the connection policy as an optional + * constructor argument. + */ +template<typename CONNECTPOLICY> struct basic_connection : + basic_connection_base<CONNECTPOLICY> +{ + PQXX_DEPRECATED basic_connection() =default; + PQXX_DEPRECATED explicit basic_connection(const std::string &opt) : + basic_connection(opt) {} + PQXX_DEPRECATED explicit basic_connection(const char opt[]) : + basic_connection(opt) {} + + PQXX_DEPRECATED explicit basic_connection(std::nullptr_t) : + basic_connection() {} + + using basic_connection_base<CONNECTPOLICY>::options; +}; + +} // namespace + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/binarystring b/contrib/libs/libpqxx/include/pqxx/binarystring new file mode 100644 index 0000000000..4214f0257d --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/binarystring @@ -0,0 +1,4 @@ +/** BYTEA (binary string) conversions. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/binarystring.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/binarystring.hxx b/contrib/libs/libpqxx/include/pqxx/binarystring.hxx new file mode 100644 index 0000000000..4262938ef3 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/binarystring.hxx @@ -0,0 +1,157 @@ +/** Representation for raw, binary data. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/binarystring instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_BINARYSTRING +#define PQXX_H_BINARYSTRING + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <memory> +#include <string> + +#include "pqxx/result.hxx" + + +namespace pqxx +{ + +/// Binary data corresponding to PostgreSQL's "BYTEA" binary-string type. +/** @ingroup escaping-functions + * + * This class represents a binary string as stored in a field of type bytea. + * The raw value returned by a bytea field contains escape sequences for certain + * characters, which are filtered out by binarystring. + * + * Internally a binarystring is zero-terminated, but it may also contain zero + * bytes, just like any other byte value. So don't assume that it can be + * treated as a C-style string unless you've made sure of this yourself. + * + * The binarystring retains its value even if the result it was obtained from is + * destroyed, but it cannot be copied or assigned. + * + * \relatesalso transaction_base::esc_raw + * + * To convert the other way, i.e. from a raw series of bytes to a string + * suitable for inclusion as bytea values in your SQL, use the transaction's + * esc_raw() functions. + * + * @warning This class is implemented as a reference-counting smart pointer. + * Copying, swapping, and destroying binarystring objects that refer to the same + * underlying data block is <em>not thread-safe</em>. If you wish to pass + * binarystrings around between threads, make sure that each of these operations + * is protected against concurrency with similar operations on the same object, + * or other objects pointing to the same data block. + */ +class PQXX_LIBEXPORT binarystring +{ +public: + using char_type = unsigned char; + using value_type = std::char_traits<char_type>::char_type; + using size_type = size_t; + using difference_type = long; + using const_reference = const value_type &; + using const_pointer = const value_type *; + using const_iterator = const_pointer; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + binarystring(const binarystring &) =default; + + /// Read and unescape bytea field + /** The field will be zero-terminated, even if the original bytea field isn't. + * @param F the field to read; must be a bytea field + */ + explicit binarystring(const field &); //[t62] + + /// Copy binary data from std::string. + explicit binarystring(const std::string &); + + /// Copy binary data of given length straight out of memory. + binarystring(const void *, size_t); + + /// Size of converted string in bytes + size_type size() const noexcept { return m_size; } //[t62] + /// Size of converted string in bytes + size_type length() const noexcept { return size(); } //[t62] + bool empty() const noexcept { return size()==0; } //[t62] + + const_iterator begin() const noexcept { return data(); } //[t62] + const_iterator cbegin() const noexcept { return begin(); } + const_iterator end() const noexcept { return data()+m_size; } //[t62] + const_iterator cend() const noexcept { return end(); } + + const_reference front() const noexcept { return *begin(); } //[t62] + const_reference back() const noexcept //[t62] + { return *(data()+m_size-1); } + + const_reverse_iterator rbegin() const //[t62] + { return const_reverse_iterator{end()}; } + const_reverse_iterator crbegin() const { return rbegin(); } + const_reverse_iterator rend() const //[t62] + { return const_reverse_iterator{begin()}; } + const_reverse_iterator crend() const { return rend(); } + + /// Unescaped field contents + const value_type *data() const noexcept {return m_buf.get();} //[t62] + + const_reference operator[](size_type i) const noexcept //[t62] + { return data()[i]; } + + PQXX_PURE bool operator==(const binarystring &) const noexcept; //[t62] + bool operator!=(const binarystring &rhs) const noexcept //[t62] + { return not operator==(rhs); } + + binarystring &operator=(const binarystring &); + + /// Index contained string, checking for valid index + const_reference at(size_type) const; //[t62] + + /// Swap contents with other binarystring + void swap(binarystring &); //[t62] + + /// Raw character buffer (no terminating zero is added) + /** @warning No terminating zero is added! If the binary data did not end in + * a null character, you will not find one here. + */ + const char *get() const noexcept //[t62] + { return reinterpret_cast<const char *>(m_buf.get()); } + + /// Read as regular C++ string (may include null characters) + /** @warning libpqxx releases before 3.1 stored the string and returned a + * reference to it. This is no longer the case! It now creates and returns + * a new string object. Avoid repeated use of this function; retrieve your + * string once and keep it in a local variable. Also, do not expect to be + * able to compare the string's address to that of an earlier invocation. + */ + std::string str() const; //[t62] + +private: + using smart_pointer_type = std::shared_ptr<value_type>; + + /// Shorthand: construct a smart_pointer_type. + static smart_pointer_type make_smart_pointer(unsigned char *buf=nullptr) + { +#if !(defined(_MSC_VER) && defined(__clang__)) + return smart_pointer_type{ + buf, + internal::freemallocmem_templated<unsigned char>}; +#else + return smart_pointer_type{buf, internal::freemallocmem}; +#endif + } + + smart_pointer_type m_buf; + size_type m_size; +}; +} + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/compiler-internal-post.hxx b/contrib/libs/libpqxx/include/pqxx/compiler-internal-post.hxx new file mode 100644 index 0000000000..6af34b5d30 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/compiler-internal-post.hxx @@ -0,0 +1,21 @@ +/** Compiler deficiency workarounds for compiling libpqxx headers. + * + * To be included at the end of each libpqxx header, in order to restore the + * client program's settings. + * + * 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. + */ +// NO GUARDS HERE! This code should be executed every time! + +#ifdef _WIN32 + +#ifdef _MSC_VER +#pragma warning (pop) // Restore client program's warning state +#endif + +#endif + diff --git a/contrib/libs/libpqxx/include/pqxx/compiler-internal-pre.hxx b/contrib/libs/libpqxx/include/pqxx/compiler-internal-pre.hxx new file mode 100644 index 0000000000..ac3a7b89ab --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/compiler-internal-pre.hxx @@ -0,0 +1,35 @@ +/** Compiler deficiency workarounds for compiling libpqxx headers. + * + * To be called at the start of each libpqxx header, in order to push the + * client program's settings and apply libpqxx's settings. + * + * Must be balanced by an include of -header-post.hxx at the end + * of the header. + * + * 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. + */ +// NO GUARDS HERE! This code should be executed every time! + +#ifdef _WIN32 +#ifdef _MSC_VER + +// Save client program warning state, and set warning level 4. +// Setting the warning level explicitly ensures that libpqxx +// headers will work with this warning level as well. +#pragma warning (push,4) + +#pragma warning (disable: 4251) +#pragma warning (disable: 4273) +#pragma warning (disable: 4275) +#pragma warning (disable: 4355) +#pragma warning (disable: 4511) // Copy constructor could not be generated. +#pragma warning (disable: 4512) // Assignment operator could not be generated. +#pragma warning (disable: 4996) // Deprecation warning, e.g. about strncpy(). + +#endif // _MSC_VER +#endif // _WIN32 + diff --git a/contrib/libs/libpqxx/include/pqxx/compiler-internal.hxx b/contrib/libs/libpqxx/include/pqxx/compiler-internal.hxx new file mode 100644 index 0000000000..9743f47866 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/compiler-internal.hxx @@ -0,0 +1,42 @@ +/** Compiler deficiency workarounds for compiling libpqxx itself. + * + * DO NOT INCLUDE THIS FILE when building client programs. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_COMPILER_INTERNAL +#define PQXX_H_COMPILER_INTERNAL + + +// Workarounds & definitions needed to compile libpqxx into a library +#include "pqxx/config-internal-compiler.h" + +#ifdef _WIN32 + +#ifdef PQXX_SHARED +#undef PQXX_LIBEXPORT +#define PQXX_LIBEXPORT __declspec(dllexport) +#define PQXX_PRIVATE __declspec() +#endif // PQXX_SHARED + +#ifdef _MSC_VER +#pragma warning (disable: 4251 4275 4273) +#pragma warning (disable: 4355) +#pragma warning (disable: 4996) // Deprecation warning, e.g. about strncpy(). +#endif + +#elif defined(__GNUC__) && defined(PQXX_HAVE_GCC_VISIBILITY) // !_WIN32 + +#define PQXX_LIBEXPORT __attribute__ ((visibility("default"))) +#define PQXX_PRIVATE __attribute__ ((visibility("hidden"))) + +#endif // __GNUC__ && PQXX_HAVE_GCC_VISIBILITY + + +#include "pqxx/compiler-public.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/compiler-public.hxx b/contrib/libs/libpqxx/include/pqxx/compiler-public.hxx new file mode 100644 index 0000000000..352956c237 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/compiler-public.hxx @@ -0,0 +1,122 @@ +/** Compiler deficiency workarounds for libpqxx clients. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_COMPILER_PUBLIC +#define PQXX_H_COMPILER_PUBLIC + +// Workarounds & definitions that need to be included even in library's headers +#include "pqxx/config-public-compiler.h" + +// Some compilers, Visual Studio in particular, don't seem to support the +// standard's ISO-646 keywords out of the box. +#include <ciso646> + + +#if defined(__GNUC__) && defined(PQXX_HAVE_GCC_CONST) +/// Declare function without effects and without reading anything but its args. +#define PQXX_CONST __attribute__ ((const)) +#else +#define PQXX_CONST +#endif + +#if defined(PQXX_HAVE_DEPRECATED) +/// Mark an item as deprecated. +#define PQXX_DEPRECATED [[deprecated]] +#elif defined(__GNUC__) && defined(PQXX_HAVE_GCC_DEPRECATED) +#define PQXX_DEPRECATED __attribute__ ((deprecated)) +#else +#define PQXX_DEPRECATED +#endif + +#if defined(__GNUC__) && defined(PQXX_HAVE_GCC_PURE) +/// Declare function "pure": no side effects, only reads globals and its args. +#define PQXX_PURE __attribute__ ((pure)) +#else +#define PQXX_PURE +#endif + + +// Workarounds for Windows +#ifdef _WIN32 + +/* For now, export DLL symbols if _DLL is defined. This is done automatically + * by the compiler when linking to the dynamic version of the runtime library, + * according to "gzh" + */ +#if !defined(PQXX_LIBEXPORT) && defined(PQXX_SHARED) +#define PQXX_LIBEXPORT __declspec(dllimport) +#endif // !PQXX_LIBEXPORT && PQXX_SHARED + + +// Workarounds for Microsoft Visual C++ +#ifdef _MSC_VER + +// Suppress vtables on abstract classes. +#define PQXX_NOVTABLE __declspec(novtable) + +// Automatically link with the appropriate libpq (static or dynamic, debug or +// release). The default is to use the release DLL. Define PQXX_PQ_STATIC to +// link to a static version of libpq, and _DEBUG to link to a debug version. +// The two may be combined. +#if defined(PQXX_AUTOLINK) +#if defined(PQXX_PQ_STATIC) +#ifdef _DEBUG +#pragma comment(lib, "libpqd") +#else +#pragma comment(lib, "libpq") +#endif +#else +#ifdef _DEBUG +#pragma comment(lib, "libpqddll") +#else +#pragma comment(lib, "libpqdll") +#endif +#endif +#endif + +// If we're not compiling libpqxx itself, automatically link with the +// appropriate libpqxx library. To link with the libpqxx DLL, define +// PQXX_SHARED; the default is to link with the static library. A static link +// is the recommended practice. +// +// The preprocessor macro PQXX_INTERNAL is used to detect whether we +// are compiling the libpqxx library itself. When you compile the library +// yourself using your own project file, make sure to include this macro. +#if defined(PQXX_AUTOLINK) && !defined(PQXX_INTERNAL) + #ifdef PQXX_SHARED + #ifdef _DEBUG + #pragma comment(lib, "libpqxxD") + #else + #pragma comment(lib, "libpqxx") + #endif + #else // !PQXX_SHARED + #ifdef _DEBUG + #pragma comment(lib, "libpqxx_staticD") + #else + #pragma comment(lib, "libpqxx_static") + #endif + #endif +#endif + +#endif // _MSC_VER +#endif // _WIN32 + + +#ifndef PQXX_LIBEXPORT +#define PQXX_LIBEXPORT +#endif + +#ifndef PQXX_PRIVATE +#define PQXX_PRIVATE +#endif + +#ifndef PQXX_NOVTABLE +#define PQXX_NOVTABLE +#endif + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/config-internal-compiler.h b/contrib/libs/libpqxx/include/pqxx/config-internal-compiler.h new file mode 100644 index 0000000000..ddf45f0db7 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/config-internal-compiler.h @@ -0,0 +1,14 @@ +/* Automatically generated from config.h: internal/compiler config. */ + +#include <util/system/platform.h> + +#if defined(_linux_) || defined(_darwin_) + +# define HAVE_POLL 1 +# define HAVE_SYS_TIME_H 1 +# define HAVE_SYS_TYPES_H 1 +# define HAVE_UNISTD_H 1 +# define PQXX_HAVE_CHARCONV_INT 1 +# define PQXX_HAVE_GCC_VISIBILITY 1 + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/config-public-compiler.h b/contrib/libs/libpqxx/include/pqxx/config-public-compiler.h new file mode 100644 index 0000000000..5a6feb5739 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/config-public-compiler.h @@ -0,0 +1,11 @@ +/* Automatically generated from config.h: public/compiler config. */ + +#ifndef _MSC_VER +#define PQXX_HAVE_DEPRECATED 1 +#endif +#ifndef _MSC_VER +#define PQXX_HAVE_GCC_CONST 1 +#define PQXX_HAVE_GCC_DEPRECATED 1 +#define PQXX_HAVE_GCC_PURE 1 +#endif +#define PQXX_HAVE_OPTIONAL 1 diff --git a/contrib/libs/libpqxx/include/pqxx/connection b/contrib/libs/libpqxx/include/pqxx/connection new file mode 100644 index 0000000000..d08e357e93 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/connection @@ -0,0 +1,6 @@ +/** pqxx::connection and pqxx::lazyconnection classes. + * + * Different ways of setting up a backend connection. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/connection.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/connection.hxx b/contrib/libs/libpqxx/include/pqxx/connection.hxx new file mode 100644 index 0000000000..cb00743fec --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/connection.hxx @@ -0,0 +1,170 @@ +/** Definition of the pqxx::connection and pqxx::lazyconnection classes. + * + * Different ways of setting up a backend connection. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_CONNECTION +#define PQXX_H_CONNECTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/connectionpolicy.hxx" +#include "pqxx/basic_connection.hxx" + +namespace pqxx +{ + +/** + * @addtogroup connection Connection classes + * + * The connection classes are where the use of a database begins. You must + * connect to a database in order to access it. Your connection represents a + * session with the database. In the context of that connection you can create + * transactions, which in turn you can use to execute SQL. A connection can + * have only one regular transaction open at a time, but you can break your work + * down into any number of consecutive transactions and there is also some + * support for transaction nesting (using the subtransaction class). + * + * Many things come together in the connection classes. Handling of error and + * warning messages, for example, is defined by @e errorhandlers in the context + * of a connection. Prepared statements are also defined here. + * + * @warning In libpqxx 7, all built-in connection types will be implemented + * as a single class. You'll specify the connection policy as an optional + * constructor argument. + * + * Several types of connections are available, including plain connection and + * lazyconnection. These types are aliases combining a derivative of the + * connection_base class (where essentially all connection-related functionality + * is defined) with a policy class which governs how the connection is to be + * established. You pass details such as the database you wish to connect to, + * username and password, and so on as as PostgreSQL "connection string" and + * certain environment variables that you can learn more about from the core + * postgres documentation. + * + * See the connection_base documentation for a full list of features inherited + * by all connection classes. Connections can be deactivated and reactivated if + * needed (within reason, of course--you can't do this in the middle of a + * transaction), and where possible, disabled or broken connections are + * transparently re-enabled when you use them again. This is called + * "reactivation," and you may need to understand it because you'll want it + * disabled in certain situations. + * + * @warning Connection deactivation/reactivation will probably be removed in + * libpqxx 7. If your application relies on an ability to "put connections to + * sleep" and reactivate them later, you'll need to wrap them in some way to + * handle this. + * + * You can also set certain variables defined by the backend to influence its + * behaviour for the duration of your session, such as the applicable text + * encoding. You can query the connection's capabilities (because some features + * will depend on the versions of libpq and of the server backend that you're + * using) and parameters that you set in your connection string and/or + * environment variables. + * + * @{ + */ + +/// Connection policy; creates an immediate connection to a database. +/** This is the policy you typically need when you work with a database through + * libpqxx. It connects to the database immediately. Another option is to + * defer setting up the underlying connection to the database until it's + * actually needed; the connect_lazy policy implements such "lazy" * behaviour. + * + * The advantage of having an "immediate" connection (as this policy gives you) + * is that any errors in setting up the connection will occur during + * construction of the connection object, rather than at some later point + * further down your program. + */ +class PQXX_LIBEXPORT connect_direct : public connectionpolicy +{ +public: + /// The parsing of options is the same as in libpq's PQconnect. + /// See: https://www.postgresql.org/docs/10/static/libpq-connect.html + explicit connect_direct(const std::string &opts) : connectionpolicy{opts} {} + virtual handle do_startconnect(handle) override; +}; + +/// The "standard" connection type: connect to database right now +using connection = basic_connection_base<connect_direct>; + + +/// Lazy connection policy; causes connection to be deferred until first use. +/** This is connect_direct's lazy younger brother. It does not attempt to open + * a connection right away; the connection is only created when it is actually + * used. + */ +class PQXX_LIBEXPORT connect_lazy : public connectionpolicy +{ +public: + /// The parsing of options is the same as in libpq's PQconnect. + /// See: https://www.postgresql.org/docs/10/static/libpq-connect.html + explicit connect_lazy(const std::string &opts) : connectionpolicy{opts} {} + virtual handle do_completeconnect(handle) override; +}; + + +/// A "lazy" connection type: connect to database only when needed +using lazyconnection = basic_connection_base<connect_lazy>; + + +/// Asynchronous connection policy; connects "in the background" +/** Connection is initiated immediately, but completion is deferred until the + * connection is actually needed. + * + * This may help performance by allowing the client to do useful work while + * waiting for an answer from the server. + */ +class PQXX_LIBEXPORT connect_async : public connectionpolicy +{ +public: + /// The parsing of options is the same as in libpq's PQConnect + /// See: https://www.postgresql.org/docs/10/static/libpq-connect.html + explicit connect_async(const std::string &opts); + virtual handle do_startconnect(handle) override; + virtual handle do_completeconnect(handle) override; + virtual handle do_dropconnect(handle) noexcept override; + virtual bool is_ready(handle) const noexcept override; + +private: + /// Is a connection attempt in progress? + bool m_connecting; +}; + + +/// "Asynchronous" connection type: start connecting, but don't wait for it +using asyncconnection = basic_connection_base<connect_async>; + + +/// Nonfunctional, always-down connection policy for testing/debugging purposes +/** @warning You don't want to use this policy in normal code. + * Written for debugging and testing, this "connection policy" always fails to + * connect, and the internal connection pointer always remains null. + */ +class PQXX_LIBEXPORT connect_null : public connectionpolicy +{ +public: + explicit connect_null(const std::string &opts) : connectionpolicy{opts} {} +}; + + +/// A "dummy" connection type: don't connect to any database at all +using nullconnection = basic_connection_base<connect_null>; + +/** + * @} + */ + +} + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/connection_base b/contrib/libs/libpqxx/include/pqxx/connection_base new file mode 100644 index 0000000000..187b667cb3 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/connection_base @@ -0,0 +1,6 @@ +/** pqxx::connection_base abstract base class. + * + * pqxx::connection_base encapsulates a frontend-to-backend connection. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/connection_base.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/connection_base.hxx b/contrib/libs/libpqxx/include/pqxx/connection_base.hxx new file mode 100644 index 0000000000..8809639873 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/connection_base.hxx @@ -0,0 +1,940 @@ +/** Definition of the pqxx::connection_base abstract base class. + * + * pqxx::connection_base encapsulates a frontend to backend connection + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection_base instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_CONNECTION_BASE +#define PQXX_H_CONNECTION_BASE + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <bitset> +#include <list> +#include <map> +#include <memory> + +#include "pqxx/errorhandler.hxx" +#include "pqxx/except.hxx" +#include "pqxx/prepared_statement.hxx" +#include "pqxx/strconv.hxx" +#include "pqxx/util.hxx" +#include "pqxx/version.hxx" + + +/* Use of the libpqxx library starts here. + * + * Everything that can be done with a database through libpqxx must go through + * a connection object derived from connection_base. + */ + +/* Methods tested in eg. self-test program test1 are marked with "//[t01]" + */ + +namespace pqxx +{ +namespace internal +{ +class reactivation_avoidance_exemption; +class sql_cursor; + +class reactivation_avoidance_counter +{ +public: + reactivation_avoidance_counter() =default; + + void add(int n) noexcept { m_counter += n; } + void clear() noexcept { m_counter = 0; } + int get() const noexcept { return m_counter; } + +private: + int m_counter = 0; +}; + +} + + +/// Encrypt password for given user. +/** Use this when setting a new password for the user if password encryption is + * enabled. Inputs are the username the password is for, and the plaintext + * password. + * + * @return encrypted version of the password, suitable for encrypted PostgreSQL + * authentication. + * + * Thus the password for a user can be changed with: + * @code + * void setpw(transaction_base &t, const string &user, const string &pw) + * { + * t.exec("ALTER USER " + user + " " + * "PASSWORD '" + encrypt_password(user,pw) + "'"); + * } + * @endcode + */ +std::string PQXX_LIBEXPORT encrypt_password( //[t00] + const std::string &user, + const std::string &password); + + +namespace internal +{ +namespace gate +{ +class connection_dbtransaction; +class connection_errorhandler; +class connection_largeobject; +class connection_notification_receiver; +class connection_parameterized_invocation; +class connection_pipeline; +class connection_prepare_invocation; +class connection_reactivation_avoidance_exemption; +class connection_sql_cursor; +class connection_transaction; +class const_connection_largeobject; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal + + +/// connection_base abstract base class; represents a connection to a database. +/** This is the first class to look at when you wish to work with a database + * through libpqxx. Depending on the implementing concrete child class, a + * connection can be automatically opened when it is constructed, or when it is + * first used, or somewhere inbetween. The connection is automatically closed + * upon destruction (if it hasn't been closed already). + * + * To query or manipulate the database once connected, use one of the + * transaction classes (see pqxx/transaction_base.hxx) or preferably the + * transactor framework (see pqxx/transactor.hxx). + * + * If a network connection to the database server fails, the connection will be + * restored automatically (although any transaction going on at the time will + * have to be aborted). This also means that any information set in previous + * transactions that is not stored in the database, such as temp tables or + * connection-local variables defined with PostgreSQL's SET command, will be + * lost. Whenever you create such state, either keept it local to one + * transaction, where possible, or inhibit automatic reactivation of the + * connection using the inhibit_reactivation() method. + * + * When a connection breaks, you will typically get a broken_connection + * exception. This can happen at almost any point, and the details may depend + * on which connection class (all derived from this one) you use. + * + * As a general rule, always avoid raw queries if libpqxx offers a dedicated + * function for the same purpose. There may be hidden logic to hide certain + * complications from you, such as reinstating session variables when a + * broken or disabled connection is reactivated. + * + * @warning On Unix-like systems, including GNU and BSD systems, your program + * may receive the SIGPIPE signal when the connection to the backend breaks. By + * default this signal will abort your program. Use "signal(SIGPIPE, SIG_IGN)" + * if you want your program to continue running after a connection fails. + */ +class PQXX_LIBEXPORT connection_base +{ +public: + /// Explicitly close connection. + void disconnect() noexcept; //[t02] + + /// Is this connection open at the moment? + /** @warning This function is @b not needed in most code. Resist the + * temptation to check it after opening a connection; instead, rely on the + * broken_connection exception that will be thrown on connection failure. + */ + bool PQXX_PURE is_open() const noexcept; //[t01] + + /** + * @name Activation + * + * @warning Connection deactivation/reactivation will probably be removed in + * libpqxx 7. If your application relies on an ability to "put connections + * to sleep" and reactivate them later, you'll need to wrap them in some way + * to handle this. + * + * Connections can be temporarily deactivated, or they can break because of + * overly impatient firewalls dropping TCP connections. Where possible, + * libpqxx will try to re-activate these when resume using them, or you can + * wake them up explicitly. You probably won't need this feature, but you + * should be aware of it. + */ + //@{ + /// @deprecated Explicitly activate deferred or deactivated connection. + /** Use of this method is entirely optional. Whenever a connection is used + * while in a deferred or deactivated state, it will transparently try to + * bring itself into an activated state. This function is best viewed as an + * explicit hint to the connection that "if you're not in an active state, now + * would be a good time to get into one." Whether a connection is currently + * in an active state or not makes no real difference to its functionality. + * There is also no particular need to match calls to activate() with calls to + * deactivate(). A good time to call activate() might be just before you + * first open a transaction on a lazy connection. + */ + PQXX_DEPRECATED void activate(); //[t12] + + /// @deprecated Explicitly deactivate connection. + /** Like its counterpart activate(), this method is entirely optional. + * Calling this function really only makes sense if you won't be using this + * connection for a while and want to reduce the number of open connections on + * the database server. + * There is no particular need to match or pair calls to deactivate() with + * calls to activate(), but calling deactivate() during a transaction is an + * error. + */ + PQXX_DEPRECATED void deactivate(); //[t12] + + /// @deprecated Disallow (or permit) connection recovery + /** A connection whose underlying socket is not currently connected to the + * server will normally (re-)establish communication with the server whenever + * needed, or when the client program requests it (although for reasons of + * integrity, never inside a transaction; but retrying the whole transaction + * may implicitly cause the connection to be restored). In normal use this is + * quite a convenient thing to have and presents a simple, safe, predictable + * interface. + * + * There is at least one situation where this feature is not desirable, + * however. Although most session state (prepared statements, session + * variables) is automatically restored to its working state upon connection + * reactivation, temporary tables and so-called WITH HOLD cursors (which can + * live outside transactions) are not. + * + * Cursors that live outside transactions are automatically handled, and the + * library will quietly ignore requests to deactivate or reactivate + * connections while they exist; it does not want to give you the illusion of + * being back in your transaction when in reality you just dropped a cursor. + * With temporary tables this is not so easy: there is no easy way for the + * library to detect their creation or track their lifetimes. + * + * So if your program uses temporary tables, and any part of this use happens + * outside of any database transaction (or spans multiple transactions), some + * of the work you have done on these tables may unexpectedly be undone if the + * connection is broken or deactivated while any of these tables exists, and + * then reactivated or implicitly restored before you are finished with it. + * + * If this describes any part of your program, guard it against unexpected + * reconnections by inhibiting reconnection at the beginning. And if you want + * to continue doing work on the connection afterwards that no longer requires + * the temp tables, you can permit it again to get the benefits of connection + * reactivation for the remainder of the program. + * + * @param inhibit should reactivation be inhibited from here on? + * + * @warning Some connection types (the lazy and asynchronous types) defer + * completion of the socket-level connection until it is actually needed by + * the client program. Inhibiting reactivation before this connection is + * really established will prevent these connection types from doing their + * work. For those connection types, if you are sure that reactivation needs + * to be inhibited before any query goes across the connection, activate() the + * connection first. This will ensure that definite activation happens before + * you inhibit it. + */ + PQXX_DEPRECATED void inhibit_reactivation(bool inhibit) //[t86] + { m_inhibit_reactivation=inhibit; } + + /// Make the connection fail. @warning Do not use this except for testing! + /** Breaks the connection in some unspecified, horrible, dirty way to enable + * failure testing. + * + * Do not use this in normal programs. This is only meant for testing. + */ + void simulate_failure(); //[t94] + //@} + + /// Invoke notice processor function. The message should end in newline. + void process_notice(const char[]) noexcept; //[t14] + /// Invoke notice processor function. Newline at end is recommended. + void process_notice(const std::string &) noexcept; //[t14] + + /// Enable tracing to a given output stream, or nullptr to disable. + void trace(std::FILE *) noexcept; //[t03] + + /** + * @name Connection properties + * + * These are probably not of great interest, since most are derived from + * information supplied by the client program itself, but they are included + * for completeness. + */ + //@{ + /// Name of database we're connected to, if any. + /** @warning This activates the connection, which may fail with a + * broken_connection exception. + */ + const char *dbname(); //[t01] + + /// Database user ID we're connected under, if any. + /** @warning This activates the connection, which may fail with a + * broken_connection exception. + */ + const char *username(); //[t01] + + /// Address of server, or nullptr if none specified (i.e. default or local) + /** @warning This activates the connection, which may fail with a + * broken_connection exception. + */ + const char *hostname(); //[t01] + + /// Server port number we're connected to. + /** @warning This activates the connection, which may fail with a + * broken_connection exception. + */ + const char *port(); //[t01] + + /// Process ID for backend process. + /** Use with care: connections may be lost and automatically re-established + * without your knowledge, in which case this process ID may no longer be + * correct. You may, however, assume that this number remains constant and + * reliable within the span of a successful backend transaction. If the + * transaction fails, which may be due to a lost connection, then this number + * will have become invalid at some point within the transaction. + * + * @return Process identifier, or 0 if not currently connected. + */ + int PQXX_PURE backendpid() const noexcept; //[t01] + + /// Socket currently used for connection, or -1 for none. Use with care! + /** Query the current socket number. This is intended for event loops based + * on functions such as select() or poll(), where multiple file descriptors + * are watched. + * + * Please try to stay away from this function. It is really only meant for + * event loops that need to wait on more than one file descriptor. If all you + * need is to block until a notification arrives, for instance, use + * await_notification(). If you want to issue queries and retrieve results in + * nonblocking fashion, check out the pipeline class. + * + * @warning Don't store this value anywhere, and always be prepared for the + * possibility that, at any given time, there may not be a socket! The + * socket may change or even go away or be established during any invocation + * of libpqxx code on the connection, no matter how trivial. + */ + int PQXX_PURE sock() const noexcept; //[t87] + + /** + * @name Capabilities + * + * Some functionality may only be available in certain versions of the + * backend, or only when speaking certain versions of the communications + * protocol that connects us to the backend. + */ + //@{ + + /// Session capabilities. + /** No capabilities are defined at the moment: all capabilities that older + * versions checked for are now always supported. + */ + enum capability + { + /// Not a capability value; end-of-enumeration marker + cap_end, + }; + + + /// Does this connection seem to support the given capability? + /** Don't try to be smart by caching this information anywhere. Obtaining it + * is quite fast (especially after the first time) and what's more, a + * capability may "suddenly" appear or disappear if the connection is broken + * or deactivated, and then restored. This may happen silently any time no + * backend transaction is active; if it turns out that the server was upgraded + * or restored from an older backup, or the new connection goes to a different + * backend, then the restored session may have different capabilities than + * were available previously. + * + * Some guesswork is involved in establishing the presence of any capability; + * try not to rely on this function being exactly right. + * + * @warning Make sure your connection is active before calling this function, + * or the answer will always be "no." In particular, if you are using this + * function on a newly-created lazyconnection, activate the connection first. + */ + bool supports(capability c) const noexcept //[t88] + { return m_caps.test(c); } + + /// What version of the PostgreSQL protocol is this connection using? + /** The answer can be 0 (when there is no connection); 3 for protocol 3.0; or + * possibly higher values as newer protocol versions are taken into use. + * + * If the connection is broken and restored, the restored connection could + * possibly use a different server and protocol version. This would normally + * happen if the server is upgraded without shutting down the client program, + * for example. + */ + int PQXX_PURE protocol_version() const noexcept; //[t01] + + /// What version of the PostgreSQL server are we connected to? + /** The result is a bit complicated: each of the major, medium, and minor + * release numbers is written as a two-digit decimal number, and the three + * are then concatenated. Thus server version 9.4.2 will be returned as the + * decimal number 90402. If there is no connection to the server, this + * returns zero. + * + * @warning When writing version numbers in your code, don't add zero at the + * beginning! Numbers beginning with zero are interpreted as octal (base-8) + * in C++. Thus, 070402 is not the same as 70402, and 080000 is not a number + * at all because there is no digit "8" in octal notation. Use strictly + * decimal notation when it comes to these version numbers. + */ + int PQXX_PURE server_version() const noexcept; //[t01] + //@} + + /// @name Text encoding + /** + * Each connection is governed by a "client encoding," which dictates how + * strings and other text is represented in bytes. The database server will + * send text data to you in this encoding, and you should use it for the + * queries and data which you send to the server. + * + * Search the PostgreSQL documentation for "character set encodings" to find + * out more about the available encodings, how to extend them, and how to use + * them. Not all server-side encodings are compatible with all client-side + * encodings or vice versa. + * + * Encoding names are case-insensitive, so e.g. "UTF8" is equivalent to + * "utf8". + * + * You can change the client encoding, but this may not work when the + * connection is in a special state, such as when streaming a table. It's + * not clear what happens if you change the encoding during a transaction, + * and then abort the transaction. + */ + //@{ + /// Get client-side character encoding, by name. + std::string get_client_encoding() const; + + /// Set client-side character encoding, by name. + /** + * @param Encoding Name of the character set encoding to use. + */ + void set_client_encoding(const std::string &encoding); //[t07] + + /// Set client-side character encoding, by name. + /** + * @param Encoding Name of the character set encoding to use. + */ + void set_client_encoding(const char encoding[]); //[t07] + + /// Get the connection's encoding, as a PostgreSQL-defined code. + int PQXX_PRIVATE encoding_id() const; + + //@} + + /// Set session variable + /** Set a session variable for this connection, using the SET command. If the + * connection to the database is lost and recovered, the last-set value will + * be restored automatically. See the PostgreSQL documentation for a list of + * variables that can be set and their permissible values. + * If a transaction is currently in progress, aborting that transaction will + * normally discard the newly set value. However nontransaction (which + * doesn't start a real backend transaction) is an exception. + * + * @warning Do not mix the set_variable interface with manual setting of + * variables by executing the corresponding SQL commands, and do not get or + * set variables while a tablestream or pipeline is active on the same + * connection. + * @param Var Variable to set + * @param Value Value vor Var to assume: an identifier, a quoted string, or a + * number. + */ + void set_variable( //[t60] + const std::string &Var, + const std::string &Value); + + /// Read session variable + /** Will try to read the value locally, from the list of variables set with + * the set_variable function. If that fails, the database is queried. + * @warning Do not mix the set_variable interface with manual setting of + * variables by executing the corresponding SQL commands, and do not get or + * set variables while a tablestream or pipeline is active on the same + * connection. + */ + std::string get_variable(const std::string &); //[t60] + //@} + + + /** + * @name Notifications and Receivers + */ + //@{ + /// Check for pending notifications and take appropriate action. + /** + * All notifications found pending at call time are processed by finding + * any matching receivers and invoking those. If no receivers matched the + * notification string, none are invoked but the notification is considered + * processed. + * + * Exceptions thrown by client-registered receivers are reported using the + * connection's errorhandlers, but the exceptions themselves are not passed + * on outside this function. + * + * @return Number of notifications processed + */ + int get_notifs(); //[t04] + + + /// Wait for a notification to come in + /** The wait may also be terminated by other events, such as the connection + * to the backend failing. Any pending or received notifications are + * processed as part of the call. + * + * @return Number of notifications processed + */ + int await_notification(); //[t78] + + /// Wait for a notification to come in, or for given timeout to pass + /** The wait may also be terminated by other events, such as the connection + * to the backend failing. Any pending or received notifications are + * processed as part of the call. + + * @return Number of notifications processed + */ + int await_notification(long seconds, long microseconds); //[t79] + //@} + + + /** + * @name Prepared statements + * + * PostgreSQL supports prepared SQL statements, i.e. statements that can be + * registered under a client-provided name, optimized once by the backend, and + * executed any number of times under the given name. + * + * Prepared statement definitions are not sensitive to transaction boundaries; + * a statement defined inside a transaction will remain defined outside that + * transaction, even if the transaction itself is subsequently aborted. Once + * a statement has been prepared, only closing the connection or explicitly + * "unpreparing" it can make it go away. + * + * Use the @c pqxx::transaction_base::exec_prepared functions to execute a + * prepared statement. Use @c prepared().exists() to find out whether a + * statement has been prepared under a given name. See \ref prepared for a + * full discussion. + * + * Never try to prepare, execute, or unprepare a prepared statement manually + * using direct SQL queries. Always use the functions provided by libpqxx. + * + * @{ + */ + + /// Define a prepared statement. + /** + * The statement's definition can refer to a parameter using the parameter's + * positional number n in the definition. For example, the first parameter + * can be used as a variable "$1", the second as "$2" and so on. + * + * Here's an example of how to use prepared statements. Note the unusual + * syntax for passing parameters: every new argument is a parenthesized + * expression that is simply tacked onto the end of the statement! + * + * @code + * using namespace pqxx; + * void foo(connection_base &C) + * { + * C.prepare("findtable", "select * from pg_tables where name=$1"); + * work W{C}; + * result R = W.exec_prepared("findtable", "mytable"); + * if (R.empty()) throw runtime_error{"mytable not found!"}; + * } + * @endcode + * + * To save time, prepared statements aren't really registered with the backend + * until they are first used. If this is not what you want, e.g. because you + * have very specific realtime requirements, you can use the @c prepare_now() + * function to force immediate preparation. + * + * The statement may not be registered with the backend until it is actually + * used. So if, for example, the statement is syntactically incorrect, you + * may see a syntax_error here, or later when you try to call the statement, + * or during a @c prepare_now() call. + * + * @param name unique name for the new prepared statement. + * @param definition SQL statement to prepare. + */ + void prepare(const std::string &name, const std::string &definition); + + /// Define a nameless prepared statement. + /** + * This can be useful if you merely want to pass large binary parameters to a + * statement without otherwise wishing to prepare it. If you use this + * feature, always keep the definition and the use close together to avoid + * the nameless statement being redefined unexpectedly by code somewhere else. + */ + void prepare(const std::string &definition); + + /// Drop prepared statement. + void unprepare(const std::string &name); + + /// Request that prepared statement be registered with the server. + /** If the statement had already been fully prepared, this will do nothing. + * + * If the connection should break and be transparently restored, then the new + * connection will again defer registering the statement with the server. + * Since connections are never restored inside backend transactions, doing + * this once at the beginning of your transaction ensures that the statement + * will not be re-registered during that transaction. In most cases, however, + * it's probably better not to use this and let the connection decide when and + * whether to register prepared statements that you've defined. + */ + void prepare_now(const std::string &name); + + /** + * @} + */ + + /// @deprecated Pre-C++11 transactor function. + /** + * This has been superseded by the new transactor framework and + * @c pqxx::perform. + * + * Invokes the given transactor, making at most Attempts attempts to perform + * the encapsulated code. If the code throws any exception other than + * broken_connection, it will be aborted right away. + * + * @param T The transactor to be executed. + * @param Attempts Maximum number of attempts to be made to execute T. + */ + template<typename TRANSACTOR> + PQXX_DEPRECATED void perform(const TRANSACTOR &T, int Attempts); //[t04] + + /// @deprecated Pre-C++11 transactor function. Use @c pqxx::perform instead. + /** + * This has been superseded by the new transactor framework and + * @c pqxx::perform. + * + * @param T The transactor to be executed. + */ + template<typename TRANSACTOR> + PQXX_DEPRECATED void perform(const TRANSACTOR &T) + { +#include "pqxx/internal/ignore-deprecated-pre.hxx" + perform(T, 3); +#include "pqxx/internal/ignore-deprecated-post.hxx" + } + + /// Suffix unique number to name to make it unique within session context + /** Used internally to generate identifiers for SQL objects (such as cursors + * and nested transactions) based on a given human-readable base name. + */ + std::string adorn_name(const std::string &); //[90] + + /** + * @defgroup escaping-functions String-escaping functions + */ + //@{ + /// Escape string for use as SQL string literal on this connection + std::string esc(const char str[]); + + /// Escape string for use as SQL string literal on this connection + std::string esc(const char str[], size_t maxlen); + + /// Escape string for use as SQL string literal on this connection + std::string esc(const std::string &str); + + /// Escape binary string for use as SQL string literal on this connection + std::string esc_raw(const unsigned char str[], size_t len); + + /// Unescape binary data, e.g. from a table field or notification payload. + /** Takes a binary string as escaped by PostgreSQL, and returns a restored + * copy of the original binary data. + */ + std::string unesc_raw(const std::string &text) + { return unesc_raw(text.c_str()); } + + /// Unescape binary data, e.g. from a table field or notification payload. + /** Takes a binary string as escaped by PostgreSQL, and returns a restored + * copy of the original binary data. + */ + std::string unesc_raw(const char *text); + + /// Escape and quote a string of binary data. + std::string quote_raw(const unsigned char str[], size_t len); + + /// Escape and quote an SQL identifier for use in a query. + std::string quote_name(const std::string &identifier); + + /// Represent object as SQL string, including quoting & escaping. + /** Nulls are recognized and represented as SQL nulls. */ + template<typename T> + std::string quote(const T &t) + { + if (string_traits<T>::is_null(t)) return "NULL"; + return "'" + this->esc(to_string(t)) + "'"; + } + + std::string quote(const binarystring &); + + /// Escape string for literal LIKE match. + /** Use this when part of an SQL "LIKE" pattern should match only as a + * literal string, not as a pattern, even if it contains "%" or "_" + * characters that would normally act as wildcards. + * + * The string does not get string-escaped or quoted. You do that later. + * + * For instance, let's say you have a string @c name entered by the user, + * and you're searching a @c file column for items that match @c name + * followed by a dot and three letters. Even if @c name contains wildcard + * characters "%" or "_", you only want those to match literally, so "_" + * only matches "_" and "%" only matches a single "%". + * + * You do that by "like-escaping" @c name, appending the wildcard pattern + * @c ".___", and finally, escaping and quoting the result for inclusion in + * your query: + * + * tx.exec( + * "SELECT file FROM item WHERE file LIKE " + + * tx.quote(tx.esc_like(name) + ".___")); + * + * The SQL "LIKE" operator also lets you choose your own escape character. + * This is supported, but must be a single-byte character. + */ + std::string esc_like(const std::string &str, char escape_char='\\') const; + //@} + + /// Attempt to cancel the ongoing query, if any. + void cancel_query(); + + /// Error verbosity levels. + enum error_verbosity + { + // These values must match those in libpq's PGVerbosity enum. + terse=0, + normal=1, + verbose=2 + }; + + /// Set session verbosity. + /** Set the verbosity of error messages to "terse", "normal" (i.e. default) or + * "verbose." + * + * If "terse", returned messages include severity, primary text, and position + * only; this will normally fit on a single line. "normal" produces messages + * that include the above plus any detail, hint, or context fields (these + * might span multiple lines). "verbose" includes all available fields. + */ + void set_verbosity(error_verbosity verbosity) noexcept; + /// Retrieve current error verbosity + error_verbosity get_verbosity() const noexcept {return m_verbosity;} + + /// Return pointers to the active errorhandlers. + /** The entries are ordered from oldest to newest handler. + * + * You may use this to find errorhandlers that your application wants to + * delete when destroying the connection. Be aware, however, that libpqxx + * may also add errorhandlers of its own, and those will be included in the + * list. If this is a problem for you, derive your errorhandlers from a + * custom base class derived from pqxx::errorhandler. Then use dynamic_cast + * to find which of the error handlers are yours. + * + * The pointers point to the real errorhandlers. The container it returns + * however is a copy of the one internal to the connection, not a reference. + */ + std::vector<errorhandler *> get_errorhandlers() const; + +protected: + explicit connection_base(connectionpolicy &pol) : + m_policy{pol} + { + // Check library version. The check_library_version template is declared + // for any library version, but only actually defined for the version of + // the libpqxx binary against which the code is linked. + // + // If the library binary is a different version than the one declared in + // these headers, then this call will fail to link: there will be no + // definition for the function with these exact template parameter values. + // There will be a definition, but the version in the parameter values will + // be different. + // + // There is no particular reason to do this here in this constructor, except + // to ensure that every meaningful libpqxx client will execute it. The call + // must be in the execution path somewhere or the compiler won't try to link + // it. We can't use it to initialise a global or class-static variable, + // because a smart compiler might resolve it at compile time. + // + // On the other hand, we don't want to make a useless function call too + // often for performance reasons. A local static variable is initialised + // only on the definition's first execution. Compilers will be well + // optimised for this behaviour, so there's a minimal one-time cost. + static const auto version_ok = + internal::check_library_version<PQXX_VERSION_MAJOR, PQXX_VERSION_MINOR>(); + ignore_unused(version_ok); + + clearcaps(); + } + void init(); + + void close() noexcept; + void wait_read() const; + void wait_read(long seconds, long microseconds) const; + void wait_write() const; + +private: + + result make_result(internal::pq::PGresult *rhs, const std::string &query); + + void clearcaps() noexcept; + void PQXX_PRIVATE set_up_state(); + void PQXX_PRIVATE check_result(const result &); + + void PQXX_PRIVATE internal_set_trace() noexcept; + int PQXX_PRIVATE PQXX_PURE status() const noexcept; + + friend class internal::gate::const_connection_largeobject; + const char * PQXX_PURE err_msg() const noexcept; + + void PQXX_PRIVATE reset(); + std::string PQXX_PRIVATE raw_get_var(const std::string &); + void PQXX_PRIVATE process_notice_raw(const char msg[]) noexcept; + + void read_capabilities(); + + prepare::internal::prepared_def &find_prepared(const std::string &); + + prepare::internal::prepared_def ®ister_prepared(const std::string &); + + friend class internal::gate::connection_prepare_invocation; + /// @deprecated Use exec_prepared instead. + PQXX_DEPRECATED result prepared_exec( + const std::string &, + const char *const[], + const int[], + const int[], + int, + result_format format); + result exec_prepared(const std::string &statement, const internal::params &, result_format format = result_format::text); + bool prepared_exists(const std::string &) const; + + /// Connection handle. + internal::pq::PGconn *m_conn = nullptr; + + connectionpolicy &m_policy; + + /// Active transaction on connection, if any. + internal::unique<transaction_base> m_trans; + + /// Set libpq notice processor to call connection's error handlers chain. + void set_notice_processor(); + /// Clear libpq notice processor. + void clear_notice_processor(); + std::list<errorhandler *> m_errorhandlers; + + /// File to trace to, if any + std::FILE *m_trace = nullptr; + + using receiver_list = + std::multimap<std::string, pqxx::notification_receiver *>; + /// Notification receivers. + receiver_list m_receivers; + + /// Variables set in this session + std::map<std::string, std::string> m_vars; + + using PSMap = std::map<std::string, prepare::internal::prepared_def>; + /// Prepared statements existing in this section + PSMap m_prepared; + + /// Server version + int m_serverversion = 0; + + /// Stacking counter: known objects that can't be auto-reactivated + internal::reactivation_avoidance_counter m_reactivation_avoidance; + + /// Unique number to use as suffix for identifiers (see adorn_name()) + int m_unique_id = 0; + + /// Have we successfully established this connection? + bool m_completed = false; + + /// Is reactivation currently inhibited? + bool m_inhibit_reactivation = false; + + /// Set of session capabilities + std::bitset<cap_end> m_caps; + + /// Current verbosity level + error_verbosity m_verbosity = normal; + + friend class internal::gate::connection_errorhandler; + void PQXX_PRIVATE register_errorhandler(errorhandler *); + void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept; + + friend class internal::gate::connection_transaction; + result PQXX_PRIVATE exec(const char[], int Retries); + void PQXX_PRIVATE register_transaction(transaction_base *); + void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept; + bool PQXX_PRIVATE read_copy_line(std::string &); + void PQXX_PRIVATE write_copy_line(const std::string &); + void PQXX_PRIVATE end_copy_write(); + void PQXX_PRIVATE raw_set_var(const std::string &, const std::string &); + void PQXX_PRIVATE add_variables(const std::map<std::string, std::string> &); + + friend class internal::gate::connection_largeobject; + internal::pq::PGconn *raw_connection() const { return m_conn; } + + friend class internal::gate::connection_notification_receiver; + void add_receiver(notification_receiver *); + void remove_receiver(notification_receiver *) noexcept; + + friend class internal::gate::connection_pipeline; + void PQXX_PRIVATE start_exec(const std::string &); + bool PQXX_PRIVATE consume_input() noexcept; + bool PQXX_PRIVATE is_busy() const noexcept; + internal::pq::PGresult *get_result(); + + friend class internal::gate::connection_dbtransaction; + + friend class internal::gate::connection_sql_cursor; + void add_reactivation_avoidance_count(int); + + friend class internal::gate::connection_reactivation_avoidance_exemption; + + friend class internal::gate::connection_parameterized_invocation; + /// @deprecated Use exec_params instead. + PQXX_DEPRECATED result parameterized_exec( + const std::string &query, + const char *const params[], + const int paramlengths[], + const int binaries[], + int nparams); + + result exec_params( + const std::string &query, + const internal::params &args); + + connection_base(const connection_base &) =delete; + connection_base &operator=(const connection_base &) =delete; +}; + + +namespace internal +{ + +/// Scoped exemption to reactivation avoidance +class PQXX_LIBEXPORT reactivation_avoidance_exemption +{ +public: + explicit reactivation_avoidance_exemption(connection_base &C); + ~reactivation_avoidance_exemption(); + + void close_connection() noexcept { m_open = false; } + +private: + connection_base &m_home; + int m_count; + bool m_open; +}; + + +void wait_read(const internal::pq::PGconn *); +void wait_read(const internal::pq::PGconn *, long seconds, long microseconds); +void wait_write(const internal::pq::PGconn *); +} // namespace pqxx::internal + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/connectionpolicy.hxx b/contrib/libs/libpqxx/include/pqxx/connectionpolicy.hxx new file mode 100644 index 0000000000..3eebf9edbe --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/connectionpolicy.hxx @@ -0,0 +1,59 @@ +/** Definition of the connection policy classes. + * + * Interface for defining connection policies + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_CONNECTIONPOLICY +#define PQXX_H_CONNECTIONPOLICY + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <string> + +#include "pqxx/internal/libpq-forward.hxx" + + +namespace pqxx +{ + +/** + * @addtogroup connection Connection classes + */ +//@{ + +class PQXX_LIBEXPORT connectionpolicy +{ +public: + using handle = internal::pq::PGconn *; + + explicit connectionpolicy(const std::string &opts); + virtual ~connectionpolicy() noexcept; + + const std::string &options() const noexcept { return m_options; } + + virtual handle do_startconnect(handle orig); + virtual handle do_completeconnect(handle orig); + virtual handle do_dropconnect(handle orig) noexcept; + virtual handle do_disconnect(handle orig) noexcept; + virtual bool is_ready(handle) const noexcept; + +protected: + handle normalconnect(handle); + +private: + std::string m_options; +}; + +//@} +} // namespace + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/cursor b/contrib/libs/libpqxx/include/pqxx/cursor new file mode 100644 index 0000000000..02979afda5 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/cursor @@ -0,0 +1,6 @@ +/** Definition of the iterator/container-style cursor classes. + * + * C++-style wrappers for SQL cursors + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/cursor.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/cursor.hxx b/contrib/libs/libpqxx/include/pqxx/cursor.hxx new file mode 100644 index 0000000000..a1b53ab1cb --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/cursor.hxx @@ -0,0 +1,437 @@ +/** Definition of the iterator/container-style cursor classes. + * + * C++-style wrappers for SQL cursors + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/cursor instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_CURSOR +#define PQXX_H_CURSOR + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <limits> +#include <stdexcept> + +#include "pqxx/result.hxx" +#include "pqxx/transaction_base.hxx" + + +namespace pqxx +{ +/// Common definitions for cursor types +/** In C++ terms, fetches are always done in pre-increment or pre-decrement + * fashion--i.e. the result does not include the row the cursor is on at the + * beginning of the fetch, and the cursor ends up being positioned on the last + * row in the result. + * + * There are singular positions akin to @c end() at both the beginning and the + * end of the cursor's range of movement, although these fit in so naturally + * with the semantics that one rarely notices them. The cursor begins at the + * first of these, but any fetch in the forward direction will move the cursor + * off this position and onto the first row before returning anything. + */ +class PQXX_LIBEXPORT cursor_base +{ +public: + using size_type = result_size_type; + using difference_type = result_difference_type; + + /// Cursor access-pattern policy + /** Allowing a cursor to move forward only can result in better performance, + * so use this access policy whenever possible. + */ + enum accesspolicy + { + /// Cursor can move forward only + forward_only, + /// Cursor can move back and forth + random_access + }; + + /// Cursor update policy + /** + * @warning Not all PostgreSQL versions support updatable cursors. + */ + enum updatepolicy + { + /// Cursor can be used to read data but not to write + read_only, + /// Cursor can be used to update data as well as read it + update + }; + + /// Cursor destruction policy + /** The normal thing to do is to make a cursor object the owner of the SQL + * cursor it represents. There may be cases, however, where a cursor needs to + * persist beyond the end of the current transaction (and thus also beyond the + * lifetime of the cursor object that created it!), where it can be "adopted" + * into a new cursor object. See the basic_cursor documentation for an + * explanation of cursor adoption. + * + * If a cursor is created with "loose" ownership policy, the object + * representing the underlying SQL cursor will not take the latter with it + * when its own lifetime ends, nor will its originating transaction. + * + * @warning Use this feature with care and moderation. Only one cursor object + * should be responsible for any one underlying SQL cursor at any given time. + * + * @warning Don't "leak" cursors! As long as any "loose" cursor exists, + * any attempts to deactivate or reactivate the connection, implicitly or + * explicitly, are quietly ignored. + */ + enum ownershippolicy + { + /// Destroy SQL cursor when cursor object is closed at end of transaction + owned, + /// Leave SQL cursor in existence after close of object and transaction + loose + }; + + cursor_base() =delete; + cursor_base(const cursor_base &) =delete; + cursor_base &operator=(const cursor_base &) =delete; + + /** + * @name Special movement distances. + */ + //@{ + + /// Special value: read until end. + /** @return Maximum value for result::difference_type, so the cursor will + * attempt to read the largest possible result set. + */ + static difference_type all() noexcept; //[t81] + + /// Special value: read one row only. + /** @return Unsurprisingly, 1. + */ + static difference_type next() noexcept { return 1; } //[t81] + + /// Special value: read backwards, one row only. + /** @return Unsurprisingly, -1. + */ + static difference_type prior() noexcept { return -1; } //[t00] + + /// Special value: read backwards from current position back to origin. + /** @return Minimum value for result::difference_type. + */ + static difference_type backward_all() noexcept; //[t00] + + //@} + + /// Name of underlying SQL cursor + /** + * @returns Name of SQL cursor, which may differ from original given name. + * @warning Don't use this to access the SQL cursor directly without going + * through the provided wrapper classes! + */ + const std::string &name() const noexcept { return m_name; } //[t81] + +protected: + cursor_base( + connection_base &, + const std::string &Name, + bool embellish_name=true); + + const std::string m_name; +}; +} // namespace pqxx + + +#include <pqxx/internal/sql_cursor.hxx> + + +namespace pqxx +{ +/// "Stateless cursor" class: easy API for retrieving parts of result sets +/** This is a front-end for SQL cursors, but with a more C++-like API. + * + * Actually, stateless_cursor feels entirely different from SQL cursors. You + * don't keep track of positions, fetches, and moves; you just say which rows + * you want. See the retrieve() member function. + */ +template<cursor_base::updatepolicy up, cursor_base::ownershippolicy op> +class stateless_cursor +{ +public: + using size_type = result_size_type; + using difference_type = result_difference_type; + + /// Create cursor. + stateless_cursor( + transaction_base &trans, + const std::string &query, + const std::string &cname, + bool hold) : + m_cur{trans, query, cname, cursor_base::random_access, up, op, hold} + { + } + + /// Adopt existing scrolling SQL cursor. + stateless_cursor( + transaction_base &trans, + const std::string adopted_cursor) : + m_cur{trans, adopted_cursor, op} + { + // Put cursor in known position + m_cur.move(cursor_base::backward_all()); + } + + void close() noexcept { m_cur.close(); } + + /// Number of rows in cursor's result set + /** @note This function is not const; it may need to scroll to find the size + * of the result set. + */ + size_type size() { return internal::obtain_stateless_cursor_size(m_cur); } + + /// Retrieve rows from begin_pos (inclusive) to end_pos (exclusive) + /** Rows are numbered starting from 0 to size()-1. + * + * @param begin_pos First row to retrieve. May be one row beyond the end of + * the result set, to avoid errors for empty result sets. Otherwise, must be + * a valid row number in the result set. + * @param end_pos Row up to which to fetch. Rows are returned ordered from + * begin_pos to end_pos, i.e. in ascending order if begin_pos < end_pos but + * in descending order if begin_pos > end_pos. The end_pos may be arbitrarily + * inside or outside the result set; only existing rows are included in the + * result. + */ + result retrieve(difference_type begin_pos, difference_type end_pos) + { + return internal::stateless_cursor_retrieve( + m_cur, + result::difference_type(size()), + begin_pos, + end_pos); + } + + const std::string &name() const noexcept { return m_cur.name(); } + +private: + internal::sql_cursor m_cur; +}; + + +class icursor_iterator; + + +namespace internal +{ +namespace gate +{ +class icursor_iterator_icursorstream; +class icursorstream_icursor_iterator; +} // namespace internal::gate +} // namespace internal + + +/// Simple read-only cursor represented as a stream of results +/** SQL cursors can be tricky, especially in C++ since the two languages seem to + * have been designed on different planets. An SQL cursor has two singular + * positions akin to @c end() on either side of the underlying result set. + * + * These cultural differences are hidden from view somewhat by libpqxx, which + * tries to make SQL cursors behave more like familiar C++ entities such as + * iterators, sequences, streams, and containers. + * + * Data is fetched from the cursor as a sequence of result objects. Each of + * these will contain the number of rows defined as the stream's stride, except + * of course the last block of data which may contain fewer rows. + * + * This class can create or adopt cursors that live outside any backend + * transaction, which your backend version may not support. + */ +class PQXX_LIBEXPORT icursorstream +{ +public: + using size_type = cursor_base::size_type; + using difference_type = cursor_base::difference_type; + + /// Set up a read-only, forward-only cursor + /** Roughly equivalent to a C++ Standard Library istream, this cursor type + * supports only two operations: reading a block of rows while moving forward, + * and moving forward without reading any data. + * + * @param context Transaction context that this cursor will be active in + * @param query SQL query whose results this cursor shall iterate + * @param basename Suggested name for the SQL cursor; a unique code will be + * appended by the library to ensure its uniqueness + * @param sstride Number of rows to fetch per read operation; must be a + * positive number + */ + icursorstream( + transaction_base &context, + const std::string &query, + const std::string &basename, + difference_type sstride=1); //[t81] + + /// Adopt existing SQL cursor. Use with care. + /** Forms a cursor stream around an existing SQL cursor, as returned by e.g. a + * server-side function. The SQL cursor will be cleaned up by the stream's + * destructor as if it had been created by the stream; cleaning it up by hand + * or adopting the same cursor twice is an error. + * + * Passing the name of the cursor as a string is not allowed, both to avoid + * confusion with the other constructor and to discourage unnecessary use of + * adopted cursors. + * + * @warning It is technically possible to adopt a "WITH HOLD" cursor, i.e. a + * cursor that stays alive outside its creating transaction. However, any + * cursor stream (including the underlying SQL cursor, naturally) must be + * destroyed before its transaction context object is destroyed. Therefore + * the only way to use SQL's WITH HOLD feature is to adopt the cursor, but + * defer doing so until after entering the transaction context that will + * eventually destroy it. + * + * @param context Transaction context that this cursor will be active in. + * @param cname Result field containing the name of the SQL cursor to adopt. + * @param sstride Number of rows to fetch per read operation; must be a + * positive number. + * @param op Ownership policy. Determines whether the cursor underlying this + * stream will be destroyed when the stream is closed. + */ + icursorstream( + transaction_base &context, + const field &cname, + difference_type sstride=1, + cursor_base::ownershippolicy op=cursor_base::owned); //[t84] + + operator bool() const noexcept { return not m_done; } + + /// Read new value into given result object; same as operator >> + /** The result set may continue any number of rows from zero to the chosen + * stride, inclusive. An empty result will only be returned if there are no + * more rows to retrieve. + * @return Reference to this very stream, to facilitate "chained" invocations + * ("C.get(r1).get(r2);") + */ + icursorstream &get(result &res) { res = fetchblock(); return *this; } //[t81] + /// Read new value into given result object; same as get(result &) + /** The result set may continue any number of rows from zero to the chosen + * stride, inclusive. An empty result will only be returned if there are no + * more rows to retrieve. + * @return Reference to this very stream, to facilitate "chained" invocations + * ("C >> r1 >> r2;") + */ + icursorstream &operator>>(result &res) { return get(res); } //[t81] + + /// Move given number of rows forward (ignoring stride) without reading data + /** + * @return Reference to this very stream, to facilitate "chained" invocations + * ("C.ignore(2).get(r).ignore(4);") + */ + icursorstream &ignore(std::streamsize n=1); //[t81] + + /// Change stride, i.e. the number of rows to fetch per read operation + /** + * @param stride Must be a positive number + */ + void set_stride(difference_type stride); //[t81] + difference_type stride() const noexcept { return m_stride; } //[t81] + +private: + result fetchblock(); + + friend class internal::gate::icursorstream_icursor_iterator; + size_type forward(size_type n=1); + void insert_iterator(icursor_iterator *) noexcept; + void remove_iterator(icursor_iterator *) const noexcept; + + void service_iterators(difference_type); + + internal::sql_cursor m_cur; + + difference_type m_stride; + difference_type m_realpos, m_reqpos; + + mutable icursor_iterator *m_iterators; + + bool m_done; +}; + + +/// Approximate istream_iterator for icursorstream +/** Intended as an implementation of an input_iterator (as defined by the C++ + * Standard Library), this class supports only two basic operations: reading the + * current element, and moving forward. In addition to the minimal guarantees + * for istream_iterators, this class supports multiple successive reads of the + * same position (the current result set is cached in the iterator) even after + * copying and even after new data have been read from the stream. This appears + * to be a requirement for input_iterators. Comparisons are also supported in + * the general case. + * + * The iterator does not care about its own position, however. Moving an + * iterator forward moves the underlying stream forward and reads the data from + * the new stream position, regardless of the iterator's old position in the + * stream. + * + * The stream's stride defines the granularity for all iterator movement or + * access operations, i.e. "ici += 1" advances the stream by one stride's worth + * of rows, and "*ici++" reads one stride's worth of rows from the stream. + * + * @warning Do not read from the underlying stream or its cursor, move its read + * position, or change its stride, between the time the first icursor_iterator + * on it is created and the time its last icursor_iterator is destroyed. + * + * @warning Manipulating these iterators within the context of a single cursor + * stream is <em>not thread-safe</em>. Creating a new iterator, copying one, or + * destroying one affects the stream as a whole. + */ +class PQXX_LIBEXPORT icursor_iterator +{ +public: + using iterator_category = std::input_iterator_tag; + using value_type = result; + using pointer = const result *; + using reference = const result &; + using istream_type = icursorstream; + using size_type = istream_type::size_type; + using difference_type = istream_type::difference_type; + + icursor_iterator() noexcept; //[t84] + explicit icursor_iterator(istream_type &) noexcept; //[t84] + icursor_iterator(const icursor_iterator &) noexcept; //[t84] + ~icursor_iterator() noexcept; + + const result &operator*() const { refresh(); return m_here; } //[t84] + const result *operator->() const { refresh(); return &m_here; } //[t84] + icursor_iterator &operator++(); //[t84] + icursor_iterator operator++(int); //[t84] + icursor_iterator &operator+=(difference_type); //[t84] + icursor_iterator &operator=(const icursor_iterator &) noexcept; //[t84] + + bool operator==(const icursor_iterator &rhs) const; //[t84] + bool operator!=(const icursor_iterator &rhs) const noexcept //[t84] + { return not operator==(rhs); } + bool operator<(const icursor_iterator &rhs) const; //[t84] + bool operator>(const icursor_iterator &rhs) const //[t84] + { return rhs < *this; } + bool operator<=(const icursor_iterator &rhs) const //[t84] + { return not (*this > rhs); } + bool operator>=(const icursor_iterator &rhs) const //[t84] + { return not (*this < rhs); } + +private: + void refresh() const; + + friend class internal::gate::icursor_iterator_icursorstream; + difference_type pos() const noexcept { return m_pos; } + void fill(const result &); + + icursorstream *m_stream = nullptr; + result m_here; + difference_type m_pos; + icursor_iterator *m_prev = nullptr, *m_next = nullptr; +}; +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/dbtransaction b/contrib/libs/libpqxx/include/pqxx/dbtransaction new file mode 100644 index 0000000000..d3d6092ca9 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/dbtransaction @@ -0,0 +1,6 @@ +/** pqxx::dbtransaction abstract base class. + * + * pqxx::dbransaction defines a real transaction on the database. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/dbtransaction.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/dbtransaction.hxx b/contrib/libs/libpqxx/include/pqxx/dbtransaction.hxx new file mode 100644 index 0000000000..8ba7d70c6f --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/dbtransaction.hxx @@ -0,0 +1,109 @@ +/** Definition of the pqxx::dbtransaction abstract base class. + * + * pqxx::dbransaction defines a real transaction on the database. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/dbtransaction instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_DBTRANSACTION +#define PQXX_H_DBTRANSACTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/transaction_base.hxx" + +namespace pqxx +{ + +enum readwrite_policy +{ + read_only, + read_write +}; + + +/// Abstract base class responsible for bracketing a backend transaction. +/** + * @ingroup transaction + * + * Use a dbtransaction-derived object such as "work" (transaction<>) to enclose + * operations on a database in a single "unit of work." This ensures that the + * whole series of operations either succeeds as a whole or fails completely. + * In no case will it leave half-finished work behind in the database. + * + * Once processing on a transaction has succeeded and any changes should be + * allowed to become permanent in the database, call commit(). If something + * has gone wrong and the changes should be forgotten, call abort() instead. + * If you do neither, an implicit abort() is executed at destruction time. + * + * It is an error to abort a transaction that has already been committed, or to + * commit a transaction that has already been aborted. Aborting an already + * aborted transaction or committing an already committed one has been allowed + * to make errors easier to deal with. Repeated aborts or commits have no + * effect after the first one. + * + * Database transactions are not suitable for guarding long-running processes. + * If your transaction code becomes too long or too complex, please consider + * ways to break it up into smaller ones. There's no easy, general way to do + * this since application-specific considerations become important at this + * point. + * + * The actual operations for beginning and committing/aborting the backend + * transaction are implemented by a derived class. The implementing concrete + * class must also call Begin() and End() from its constructors and destructors, + * respectively, and implement do_exec(). + */ +class PQXX_LIBEXPORT PQXX_NOVTABLE dbtransaction : public transaction_base +{ +public: + virtual ~dbtransaction(); + +protected: + dbtransaction( + connection_base &, + const std::string &IsolationString, + readwrite_policy rw=read_write); + + explicit dbtransaction( + connection_base &, + bool direct=true, + readwrite_policy rw=read_write); + + + /// Start a transaction on the backend and set desired isolation level + void start_backend_transaction(); + + /// Sensible default implemented here: begin backend transaction + virtual void do_begin() override; //[t01] + /// Sensible default implemented here: perform query + virtual result do_exec(const char Query[]) override; + /// To be implemented by derived class: commit backend transaction + virtual void do_commit() override =0; + /// Sensible default implemented here: abort backend transaction + /** Default implementation does two things: + * <ol> + * <li>Clears the "connection reactivation avoidance counter"</li> + * <li>Executes a ROLLBACK statement</li> + * </ol> + */ + virtual void do_abort() override; //[t13] + + static std::string fullname(const std::string &ttype, + const std::string &isolation); + +private: + /// Precomputed SQL command to run at start of this transaction + std::string m_start_cmd; +}; + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/errorhandler b/contrib/libs/libpqxx/include/pqxx/errorhandler new file mode 100644 index 0000000000..fda3c0ae62 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/errorhandler @@ -0,0 +1,6 @@ +/** pqxx::errorhandler class. + * + * Callbacks for handling errors and warnings. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/errorhandler.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/errorhandler.hxx b/contrib/libs/libpqxx/include/pqxx/errorhandler.hxx new file mode 100644 index 0000000000..03ce923a3b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/errorhandler.hxx @@ -0,0 +1,96 @@ +/** Definition of the pqxx::errorhandler class. + * + * pqxx::errorhandler handlers errors and warnings in a database session. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection_base instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ERRORHANDLER +#define PQXX_H_ERRORHANDLER + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/types.hxx" + + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class errorhandler_connection_base; +} +} + +/** + * @addtogroup errorhandler + * @{ + */ + +/// Base class for error-handler callbacks. +/** To receive errors and warnings from a connection, subclass this with your + * own error-handler functor, and instantiate it for the connection. Destroying + * the handler un-registers it. + * + * A connection can have multiple error handlers at the same time. When the + * database connection emits an error or warning message, it passes the message + * to each error handler, starting with the most recently registered one and + * progressing towards the oldest one. However an error handler may also + * instruct the connection not to pass the message to further handlers by + * returning "false." + * + * @warning Strange things happen when a result object outlives its parent + * connection. If you register an error handler on a connection, then you must + * not access the result after destroying the connection. This applies even if + * you destroy the error handler first! + */ +class PQXX_LIBEXPORT errorhandler +{ +public: + explicit errorhandler(connection_base &); + virtual ~errorhandler(); + + /// Define in subclass: receive an error or warning message from the database. + /** + * @return Whether the same error message should also be passed to the + * remaining, older errorhandlers. + */ + virtual bool operator()(const char msg[]) noexcept =0; + +private: + connection_base *m_home; + + friend class internal::gate::errorhandler_connection_base; + void unregister() noexcept; + + errorhandler() =delete; + errorhandler(const errorhandler &) =delete; + errorhandler &operator=(const errorhandler &) =delete; +}; + + +/// An error handler that suppresses any previously registered error handlers. +class quiet_errorhandler : public errorhandler +{ +public: + quiet_errorhandler(connection_base &conn) : errorhandler{conn} {} + + virtual bool operator()(const char[]) noexcept override { return false; } +}; + +/** + * @} + */ + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/except b/contrib/libs/libpqxx/include/pqxx/except new file mode 100644 index 0000000000..e3cf0b0d5c --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/except @@ -0,0 +1,6 @@ +/** libpqxx exception classes. + * + * pqxx::sql_error, pqxx::broken_connection, pqxx::in_doubt_error, ... + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/except.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/except.hxx b/contrib/libs/libpqxx/include/pqxx/except.hxx new file mode 100644 index 0000000000..24d52d13e3 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/except.hxx @@ -0,0 +1,532 @@ +/** Definition of libpqxx exception classes. + * + * pqxx::sql_error, pqxx::broken_connection, pqxx::in_doubt_error, ... + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/except instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_EXCEPT +#define PQXX_H_EXCEPT + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <stdexcept> + +#include "pqxx/util.hxx" + + +namespace pqxx +{ + +/** + * @addtogroup exception Exception classes + * + * These exception classes follow, roughly, the two-level hierarchy defined by + * the PostgreSQL error codes (see Appendix A of the PostgreSQL documentation + * corresponding to your server version). The hierarchy given here is, as yet, + * not a complete mirror of the error codes. There are some other differences + * as well, e.g. the error code statement_completion_unknown has a separate + * status in libpqxx as in_doubt_error, and too_many_connections is classified + * as a broken_connection rather than a subtype of insufficient_resources. + * + * @see http://www.postgresql.org/docs/9.4/interactive/errcodes-appendix.html + * + * @{ + */ + +/// Mixin base class to identify libpqxx-specific exception types +/** + * If you wish to catch all exception types specific to libpqxx for some reason, + * catch this type. All of libpqxx's exception classes are derived from it + * through multiple-inheritance (they also fit into the standard library's + * exception hierarchy in more fitting places). + * + * This class is not derived from std::exception, since that could easily lead + * to exception classes with multiple std::exception base-class objects. As + * Bart Samwel points out, "catch" is subject to some nasty fineprint in such + * cases. + */ +class PQXX_LIBEXPORT PQXX_NOVTABLE pqxx_exception +{ +public: + /// Support run-time polymorphism, and keep this class abstract + virtual ~pqxx_exception() noexcept =0; + + /// Return std::exception base-class object + /** Use this to get at the exception's what() function, or to downcast to a + * more specific type using dynamic_cast. + * + * Casting directly from pqxx_exception to a specific exception type is not + * likely to work since pqxx_exception is not (and could not safely be) + * derived from std::exception. + * + * For example, to test dynamically whether an exception is an sql_error: + * + * @code + * try + * { + * // ... + * } + * catch (const pqxx::pqxx_exception &e) + * { + * std::cerr << e.base().what() << std::endl; + * const pqxx::sql_error *s=dynamic_cast<const pqxx::sql_error*>(&e.base()); + * if (s) std::cerr << "Query was: " << s->query() << std::endl; + * } + * @endcode + */ + PQXX_CONST virtual const std::exception &base() const noexcept =0; //[t00] +}; + + +/// Run-time failure encountered by libpqxx, similar to std::runtime_error +class PQXX_LIBEXPORT failure : + public pqxx_exception, public std::runtime_error +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit failure(const std::string &); +}; + + +/// Exception class for lost or failed backend connection. +/** + * @warning When this happens on Unix-like systems, you may also get a SIGPIPE + * signal. That signal aborts the program by default, so if you wish to be able + * to continue after a connection breaks, be sure to disarm this signal. + * + * If you're working on a Unix-like system, see the manual page for + * @c signal (2) on how to deal with SIGPIPE. The easiest way to make this + * signal harmless is to make your program ignore it: + * + * @code + * #include <signal.h> + * + * int main() + * { + * signal(SIGPIPE, SIG_IGN); + * // ... + * @endcode + */ +class PQXX_LIBEXPORT broken_connection : public failure +{ +public: + broken_connection(); + explicit broken_connection(const std::string &); +}; + + +/// Exception class for failed queries. +/** Carries, in addition to a regular error message, a copy of the failed query + * and (if available) the SQLSTATE value accompanying the error. + */ +class PQXX_LIBEXPORT sql_error : public failure +{ + /// Query string. Empty if unknown. + const std::string m_query; + /// SQLSTATE string describing the error type, if known; or empty string. + const std::string m_sqlstate; + +public: + explicit sql_error( + const std::string &msg="", + const std::string &Q="", + const char sqlstate[]=nullptr); + virtual ~sql_error() noexcept; + + /// The query whose execution triggered the exception + PQXX_PURE const std::string &query() const noexcept; //[t56] + + /// SQLSTATE error code if known, or empty string otherwise. + PQXX_PURE const std::string &sqlstate() const noexcept; +}; + + +/// "Help, I don't know whether transaction was committed successfully!" +/** Exception that might be thrown in rare cases where the connection to the + * database is lost while finishing a database transaction, and there's no way + * of telling whether it was actually executed by the backend. In this case + * the database is left in an indeterminate (but consistent) state, and only + * manual inspection will tell which is the case. + */ +class PQXX_LIBEXPORT in_doubt_error : public failure +{ +public: + explicit in_doubt_error(const std::string &); +}; + + +/// The backend saw itself forced to roll back the ongoing transaction. +class PQXX_LIBEXPORT transaction_rollback : public failure +{ +public: + explicit transaction_rollback(const std::string &); +}; + + +/// Transaction failed to serialize. Please retry it. +/** Can only happen at transaction isolation levels REPEATABLE READ and + * SERIALIZABLE. + * + * The current transaction cannot be committed without violating the guarantees + * made by its isolation level. This is the effect of a conflict with another + * ongoing transaction. The transaction may still succeed if you try to + * perform it again. + */ +class PQXX_LIBEXPORT serialization_failure : public transaction_rollback +{ +public: + explicit serialization_failure(const std::string &); +}; + + +/// We can't tell whether our last statement succeeded. +class PQXX_LIBEXPORT statement_completion_unknown : public transaction_rollback +{ +public: + explicit statement_completion_unknown(const std::string &); +}; + + +/// The ongoing transaction has deadlocked. Retrying it may help. +class PQXX_LIBEXPORT deadlock_detected : public transaction_rollback +{ +public: + explicit deadlock_detected(const std::string &); +}; + + +/// Internal error in libpqxx library +class PQXX_LIBEXPORT internal_error : + public pqxx_exception, public std::logic_error +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit internal_error(const std::string &); +}; + + +/// Error in usage of libpqxx library, similar to std::logic_error +class PQXX_LIBEXPORT usage_error : + public pqxx_exception, public std::logic_error +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit usage_error(const std::string &); +}; + + +/// Invalid argument passed to libpqxx, similar to std::invalid_argument +class PQXX_LIBEXPORT argument_error : + public pqxx_exception, public std::invalid_argument +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit argument_error(const std::string &); +}; + + +/// Value conversion failed, e.g. when converting "Hello" to int. +class PQXX_LIBEXPORT conversion_error : + public pqxx_exception, public std::domain_error +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit conversion_error(const std::string &); +}; + + +/// Something is out of range, similar to std::out_of_range +class PQXX_LIBEXPORT range_error : + public pqxx_exception, public std::out_of_range +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit range_error(const std::string &); +}; + + +/// Query returned an unexpected number of rows. +class PQXX_LIBEXPORT unexpected_rows : public range_error +{ + virtual const std::exception &base() const noexcept override + { return *this; } +public: + explicit unexpected_rows(const std::string &msg) : range_error{msg} {} +}; + + +/// Database feature not supported in current setup +class PQXX_LIBEXPORT feature_not_supported : public sql_error +{ +public: + explicit feature_not_supported( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +/// Error in data provided to SQL statement +class PQXX_LIBEXPORT data_exception : public sql_error +{ +public: + explicit data_exception( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT integrity_constraint_violation : public sql_error +{ +public: + explicit integrity_constraint_violation( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT restrict_violation : + public integrity_constraint_violation +{ +public: + explicit restrict_violation( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + integrity_constraint_violation{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT not_null_violation : + public integrity_constraint_violation +{ +public: + explicit not_null_violation( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + integrity_constraint_violation{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT foreign_key_violation : + public integrity_constraint_violation +{ +public: + explicit foreign_key_violation( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + integrity_constraint_violation{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT unique_violation : + public integrity_constraint_violation +{ +public: + explicit unique_violation( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + integrity_constraint_violation{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT check_violation : + public integrity_constraint_violation +{ +public: + explicit check_violation( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + integrity_constraint_violation{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT invalid_cursor_state : public sql_error +{ +public: + explicit invalid_cursor_state( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT invalid_sql_statement_name : public sql_error +{ +public: + explicit invalid_sql_statement_name( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT invalid_cursor_name : public sql_error +{ +public: + explicit invalid_cursor_name( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT syntax_error : public sql_error +{ +public: + /// Approximate position in string where error occurred, or -1 if unknown. + const int error_position; + + explicit syntax_error( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr, + int pos=-1) : + sql_error{err, Q, sqlstate}, error_position{pos} {} +}; + +class PQXX_LIBEXPORT undefined_column : public syntax_error +{ +public: + explicit undefined_column( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + syntax_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT undefined_function : public syntax_error +{ +public: + explicit undefined_function( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + syntax_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT undefined_table : public syntax_error +{ +public: + explicit undefined_table( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + syntax_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT insufficient_privilege : public sql_error +{ +public: + explicit insufficient_privilege( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +/// Resource shortage on the server +class PQXX_LIBEXPORT insufficient_resources : public sql_error +{ +public: + explicit insufficient_resources( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err,Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT disk_full : public insufficient_resources +{ +public: + explicit disk_full( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + insufficient_resources{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT out_of_memory : public insufficient_resources +{ +public: + explicit out_of_memory( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + insufficient_resources{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT too_many_connections : public broken_connection +{ +public: + explicit too_many_connections(const std::string &err) : + broken_connection{err} {} +}; + +/// PL/pgSQL error +/** Exceptions derived from this class are errors from PL/pgSQL procedures. + */ +class PQXX_LIBEXPORT plpgsql_error : public sql_error +{ +public: + explicit plpgsql_error( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + sql_error{err, Q, sqlstate} {} +}; + +/// Exception raised in PL/pgSQL procedure +class PQXX_LIBEXPORT plpgsql_raise : public plpgsql_error +{ +public: + explicit plpgsql_raise( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + plpgsql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT plpgsql_no_data_found : public plpgsql_error +{ +public: + explicit plpgsql_no_data_found( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + plpgsql_error{err, Q, sqlstate} {} +}; + +class PQXX_LIBEXPORT plpgsql_too_many_rows : public plpgsql_error +{ +public: + explicit plpgsql_too_many_rows( + const std::string &err, + const std::string &Q="", + const char sqlstate[]=nullptr) : + plpgsql_error{err, Q, sqlstate} {} +}; + +/** + * @} + */ + +} + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/field b/contrib/libs/libpqxx/include/pqxx/field new file mode 100644 index 0000000000..e799e6797b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/field @@ -0,0 +1,6 @@ +/** pqxx::field class. + * + * pqxx::field refers to a field in a query result. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/field.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/field.hxx b/contrib/libs/libpqxx/include/pqxx/field.hxx new file mode 100644 index 0000000000..5676d2a848 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/field.hxx @@ -0,0 +1,373 @@ +/** Definitions for the pqxx::field class. + * + * pqxx::field refers to a field in a query result. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_FIELD +#define PQXX_H_FIELD + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/internal/type_utils.hxx" + +#if defined(PQXX_HAVE_OPTIONAL) +#include <optional> + +/* Use std::experimental::optional as a fallback for std::optional, if + * present. + * + * This may break compilation for some software, if using a libpqxx that was + * configured for a different language version. To stop libpqxx headers from + * using or supporting std::experimental::optional, define a macro + * PQXX_HIDE_EXP_OPTIONAL when building your software. + */ +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +#error #include <experimental/optional> +#endif + +#include "pqxx/array.hxx" +#include "pqxx/result.hxx" +#include "pqxx/strconv.hxx" +#include "pqxx/types.hxx" + + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ +/// Reference to a field in a result set. +/** A field represents one entry in a row. It represents an actual value + * in the result set, and can be converted to various types. + */ +class PQXX_LIBEXPORT field +{ +public: + using size_type = field_size_type; + + /// Constructor. + /** Create field as reference to a field in a result set. + * @param R Row that this field is part of. + * @param C Column number of this field. + */ + field(const row &R, row_size_type C) noexcept; //[t01] + + /** + * @name Comparison + */ + //@{ + /// Byte-by-byte comparison of two fields (all nulls are considered equal) + /** @warning null handling is still open to discussion and change! + * + * Handling of null values differs from that in SQL where a comparison + * involving a null value yields null, so nulls are never considered equal + * to one another or even to themselves. + * + * Null handling also probably differs from the closest equivalent in C++, + * which is the NaN (Not-a-Number) value, a singularity comparable to + * SQL's null. This is because the builtin == operator demands that a == a. + * + * The usefulness of this operator is questionable. No interpretation + * whatsoever is imposed on the data; 0 and 0.0 are considered different, + * as are null vs. the empty string, or even different (but possibly + * equivalent and equally valid) encodings of the same Unicode character + * etc. + */ + bool operator==(const field &) const; //[t75] + + /// Byte-by-byte comparison (all nulls are considered equal) + /** @warning See operator==() for important information about this operator + */ + bool operator!=(const field &rhs) const //[t82] + {return not operator==(rhs);} + //@} + + /** + * @name Column information + */ + //@{ + /// Column name + const char *name() const; //[t11] + + /// Column type + oid type() const; //[t07] + + /// What table did this column come from? + oid table() const; //[t02] + + row_size_type num() const { return col(); } //[t82] + + /// What column number in its originating table did this column come from? + row_size_type table_column() const; //[t93] + //@} + + /** + * @name Content access + */ + //@{ + /// Read as plain C string + /** Since the field's data is stored internally in the form of a + * zero-terminated C string, this is the fastest way to read it. Use the + * to() or as() functions to convert the string to other types such as + * @c int, or to C++ strings. + */ + const char *c_str() const; //[t02] + + /// Is this field's value null? + bool is_null() const noexcept; //[t12] + + /// Return number of bytes taken up by the field's value. + /** + * Includes the terminating zero byte. + */ + size_type size() const noexcept; //[t11] + + /// Read value into Obj; or leave Obj untouched and return @c false if null + /** Note this can be used with optional types (except pointers other than + * C-strings) + */ + template<typename T> auto to(T &Obj) const //[t03] + -> typename std::enable_if<( + not std::is_pointer<T>::value + or std::is_same<T, const char*>::value + ), bool>::type + { + const char *const bytes = c_str(); + if (bytes[0] == '\0' and is_null()) return false; + from_string(bytes, Obj); + return true; + } + + /// Read value into Obj; or leave Obj untouched and return @c false if null + template<typename T> bool operator>>(T &Obj) const //[t07] + { return to(Obj); } + + /// Read value into Obj; or use Default & return @c false if null + /** Note this can be used with optional types (except pointers other than + * C-strings) + */ + template<typename T> auto to(T &Obj, const T &Default) const //[t12] + -> typename std::enable_if<( + not std::is_pointer<T>::value + or std::is_same<T, const char*>::value + ), bool>::type + { + const bool NotNull = to(Obj); + if (not NotNull) Obj = Default; + return NotNull; + } + + /// Return value as object of given type, or Default if null + /** Note that unless the function is instantiated with an explicit template + * argument, the Default value's type also determines the result type. + */ + template<typename T> T as(const T &Default) const //[t01] + { + T Obj; + to(Obj, Default); + return Obj; + } + + /// Return value as object of given type, or throw exception if null + /** Use as `as<std::optional<int>>()` or `as<my_untemplated_optional_t>()` as + * an alternative to `get<int>()`; this is disabled for use with raw pointers + * (other than C-strings) because storage for the value can't safely be + * allocated here + */ + template<typename T> T as() const //[t45] + { + T Obj; + if (not to(Obj)) Obj = string_traits<T>::null(); + return Obj; + } + + /// Return value wrapped in some optional type (empty for nulls) + /** Use as `get<int>()` as before to obtain previous behavior (i.e. only + * usable when `std::optional` or `std::experimental::optional` are + * available), or specify container type with `get<int, std::optional>()` + */ + template<typename T, template<typename> class O +#if defined(PQXX_HAVE_OPTIONAL) + = std::optional +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) + = std::experimental::optional +#endif + > constexpr O<T> get() const { return as<O<T>>(); } + + /// Parse the field as an SQL array. + /** Call the parser to retrieve values (and structure) from the array. + * + * Make sure the @c result object stays alive until parsing is finished. If + * you keep the @c row of @c field object alive, it will keep the @c result + * object alive as well. + */ + array_parser as_array() const + { return array_parser{c_str(), m_home.m_encoding}; } + //@} + + +protected: + const result &home() const noexcept { return m_home; } + size_t idx() const noexcept { return m_row; } + row_size_type col() const noexcept { return row_size_type(m_col); } + + /** + * You'd expect this to be a size_t, but due to the way reverse iterators + * are related to regular iterators, it must be allowed to underflow to -1. + */ + long m_col; + +private: + result m_home; + size_t m_row; +}; + + +/// Specialization: <tt>to(string &)</tt>. +template<> +inline bool field::to<std::string>(std::string &Obj) const +{ + const char *const bytes = c_str(); + if (bytes[0] == '\0' and is_null()) return false; + Obj = std::string{bytes, size()}; + return true; +} + +/// Specialization: <tt>to(const char *&)</tt>. +/** The buffer has the same lifetime as the data in this result (i.e. of this + * result object, or the last remaining one copied from it etc.), so take care + * not to use it after the last result object referring to this query result is + * destroyed. + */ +template<> +inline bool field::to<const char *>(const char *&Obj) const +{ + if (is_null()) return false; + Obj = c_str(); + return true; +} + + +template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR>> + class field_streambuf : + public std::basic_streambuf<CHAR, TRAITS> +{ +public: + using char_type = CHAR; + using traits_type = TRAITS; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + using openmode = std::ios::openmode; + using seekdir = std::ios::seekdir; + + explicit field_streambuf(const field &F) : //[t74] + m_field{F} + { + initialize(); + } + +protected: + virtual int sync() override { return traits_type::eof(); } + +protected: + virtual pos_type seekoff(off_type, seekdir, openmode) override + { return traits_type::eof(); } + virtual pos_type seekpos(pos_type, openmode) override + {return traits_type::eof();} + virtual int_type overflow(int_type) override + { return traits_type::eof(); } + virtual int_type underflow() override + { return traits_type::eof(); } + +private: + const field &m_field; + + int_type initialize() + { + char_type *G = + reinterpret_cast<char_type *>(const_cast<char *>(m_field.c_str())); + this->setg(G, G, G + m_field.size()); + return int_type(m_field.size()); + } +}; + + +/// Input stream that gets its data from a result field +/** Use this class exactly as you would any other istream to read data from a + * field. All formatting and streaming operations of @c std::istream are + * supported. What you'll typically want to use, however, is the fieldstream + * alias (which defines a basic_fieldstream for @c char). This is similar to + * how e.g. @c std::ifstream relates to @c std::basic_ifstream. + * + * This class has only been tested for the char type (and its default traits). + */ +template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR>> + class basic_fieldstream : + public std::basic_istream<CHAR, TRAITS> +{ + using super = std::basic_istream<CHAR, TRAITS>; + +public: + using char_type = CHAR; + using traits_type = TRAITS; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + + basic_fieldstream(const field &F) : super{nullptr}, m_buf{F} + { super::init(&m_buf); } + +private: + field_streambuf<CHAR, TRAITS> m_buf; +}; + +using fieldstream = basic_fieldstream<char>; + +/// Write a result field to any type of stream +/** This can be convenient when writing a field to an output stream. More + * importantly, it lets you write a field to e.g. a @c stringstream which you + * can then use to read, format and convert the field in ways that to() does not + * support. + * + * Example: parse a field into a variable of the nonstandard + * "<tt>long long</tt>" type. + * + * @code + * extern result R; + * long long L; + * stringstream S; + * + * // Write field's string into S + * S << R[0][0]; + * + * // Parse contents of S into L + * S >> L; + * @endcode + */ +template<typename CHAR> +inline std::basic_ostream<CHAR> &operator<<( + std::basic_ostream<CHAR> &S, const field &F) //[t46] +{ + S.write(F.c_str(), std::streamsize(F.size())); + return S; +} + + +/// Convert a field's string contents to another type. +template<typename T> +inline void from_string(const field &F, T &Obj) //[t46] + { from_string(F.c_str(), Obj, F.size()); } + +/// Convert a field to a string. +template<> PQXX_LIBEXPORT std::string to_string(const field &Obj); //[t74] + +} // namespace pqxx +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/callgate.hxx b/contrib/libs/libpqxx/include/pqxx/internal/callgate.hxx new file mode 100644 index 0000000000..02ac152636 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/callgate.hxx @@ -0,0 +1,79 @@ +#ifndef PQXX_H_CALLGATE +#define PQXX_H_CALLGATE + +/* +Here's what a typical gate class definition looks like: + +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE @gateclass@ : callgate<@host@> +{ + friend class @client@; + + @gateclass@(reference x) : super(x) {} + + // Methods here. Use home() to access the host-class object. +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx +*/ + +namespace pqxx +{ +namespace internal +{ +/// Base class for call gates. +/** + * A call gate defines a limited, private interface on the host class that + * specified client classes can access. + * + * The metaphor works as follows: the gate stands in front of a "home," which is + * really a class, and only lets specific friends in. + * + * To implement a call gate that gives client C access to host H, + * - derive a gate class from callgate<H>; + * - make the gate class a friend of H; + * - make C a friend of the gate class; and + * - implement "stuff C can do with H" as private members in the gate class. + * + * This special kind of "gated" friendship gives C private access to H, but only + * through an expressly limited interface. The gate class can access its host + * object as home(). + * + * Keep gate classes entirely stateless. They should be ultra-lightweight + * wrappers for their host classes, and be optimized away as much as possible by + * the compiler. Once you start adding state, you're on a slippery slope away + * from the pure, clean, limited interface pattern that gate classes are meant + * to implement. + * + * Ideally, all member functions of the gate class should be one-liners passing + * calls straight on to the host class. It can be useful however to break this + * rule temporarily during inter-class refactoring. + */ +template<typename HOME> class PQXX_PRIVATE callgate +{ +protected: + /// This class, to keep constructors easy. + using super = callgate<HOME>; + /// A reference to the host class. Helps keep constructors easy. + using reference = HOME &; + + callgate(reference x) : m_home(x) {} + + /// The home object. The gate class has full "private" access. + reference home() const noexcept { return m_home; } + +private: + reference m_home; +}; +} // namespace pqxx::internal +} // namespace pqxx + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/encoding_group.hxx b/contrib/libs/libpqxx/include/pqxx/internal/encoding_group.hxx new file mode 100644 index 0000000000..be31d083b4 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/encoding_group.hxx @@ -0,0 +1,46 @@ +/** Enum type for supporting encodings in libpqxx + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ENCODING_GROUP +#define PQXX_H_ENCODING_GROUP + + +namespace pqxx +{ +namespace internal +{ + +// Types of encodings supported by PostgreSQL, see +// https://www.postgresql.org/docs/current/static/multibyte.html#CHARSET-TABLE +enum class encoding_group +{ + // Handles all single-byte fixed-width encodings + MONOBYTE, + + // Multibyte encodings + BIG5, + EUC_CN, + EUC_JP, + EUC_JIS_2004, + EUC_KR, + EUC_TW, + GB18030, + GBK, + JOHAB, + MULE_INTERNAL, + SJIS, + SHIFT_JIS_2004, + UHC, + UTF8 +}; + +} // namespace pqxx::internal +} // namespace pqxx + + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/encodings.hxx b/contrib/libs/libpqxx/include/pqxx/internal/encodings.hxx new file mode 100644 index 0000000000..01ca223d48 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/encodings.hxx @@ -0,0 +1,99 @@ +/** Internal string encodings support for libpqxx + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ENCODINGS +#define PQXX_H_ENCODINGS + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/internal/encoding_group.hxx" + +#include <string> + + +namespace pqxx +{ +namespace internal +{ +const char *name_encoding(int encoding_id); + +/// Convert libpq encoding enum or encoding name to its libpqxx group. +encoding_group enc_group(int /* libpq encoding ID */); +encoding_group enc_group(const std::string&); + + +/// Function type: "find the end of the current glyph." +/** This type of function takes a text buffer, and a location in that buffer, + * and returns the location one byte past the end of the current glyph. + * + * The start offset marks the beginning of the current glyph. It must fall + * within the buffer. + * + * There are multiple different glyph scnaner implementations, for different + * kinds of encodings. + */ +using glyph_scanner_func = + std::string::size_type( + const char buffer[], + std::string::size_type buffer_len, + std::string::size_type start); + + +/// Look up the glyph scanner function for a given encoding group. +/** To identify the glyph boundaries in a buffer, call this to obtain the + * scanner function appropriate for the buffer's encoding. Then, repeatedly + * call the scanner function to find the glyphs. + */ +PQXX_LIBEXPORT glyph_scanner_func *get_glyph_scanner(encoding_group); + + +/// Find a single-byte "needle" character in a "haystack" text buffer. +std::string::size_type find_with_encoding( + encoding_group enc, + const std::string& haystack, + char needle, + std::string::size_type start = 0 +); + + +PQXX_LIBEXPORT std::string::size_type find_with_encoding( + encoding_group enc, + const std::string& haystack, + const std::string& needle, + std::string::size_type start = 0 +); + + +/// Iterate over the glyphs in a buffer. +/** Scans the glyphs in the buffer, and for each, passes its begin and its + * one-past-end pointers to @c callback. + */ +template<typename CALLABLE> PQXX_LIBEXPORT inline void for_glyphs( + encoding_group enc, + CALLABLE callback, + const char buffer[], + std::string::size_type buffer_len, + std::string::size_type start = 0 +) +{ + const auto scan = get_glyph_scanner(enc); + for ( + std::string::size_type here = start, next; + here < buffer_len; + here = next + ) + { + next = scan(buffer, buffer_len, here); + callback(buffer + here, buffer + next); + } +} +} // namespace pqxx::internal +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-dbtransaction.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-dbtransaction.hxx new file mode 100644 index 0000000000..8ef2e4744f --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-dbtransaction.hxx @@ -0,0 +1,22 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class dbtransaction; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_dbtransaction : callgate<connection_base> +{ + friend class pqxx::dbtransaction; + + connection_dbtransaction(reference x) : super(x) {} + + int get_reactivation_avoidance_count() const noexcept + { return home().m_reactivation_avoidance.get(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-errorhandler.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-errorhandler.hxx new file mode 100644 index 0000000000..9c62704dbe --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-errorhandler.hxx @@ -0,0 +1,25 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class connection_base; +class errorhandler; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_errorhandler : callgate<connection_base> +{ + friend class pqxx::errorhandler; + + connection_errorhandler(reference x) : super(x) {} + + void register_errorhandler(errorhandler *h) + { home().register_errorhandler(h); } + void unregister_errorhandler(errorhandler *h) + { home().unregister_errorhandler(h); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-largeobject.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-largeobject.hxx new file mode 100644 index 0000000000..e4f3b28fcc --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-largeobject.hxx @@ -0,0 +1,35 @@ +#include <string> + +#include <pqxx/internal/callgate.hxx> +#include <pqxx/internal/libpq-forward.hxx> + +namespace pqxx +{ +class largeobject; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_largeobject : callgate<connection_base> +{ + friend class pqxx::largeobject; + + connection_largeobject(reference x) : super(x) {} + + pq::PGconn *raw_connection() const { return home().raw_connection(); } +}; + + +class PQXX_PRIVATE const_connection_largeobject : + callgate<const connection_base> +{ + friend class pqxx::largeobject; + + const_connection_largeobject(reference x) : super(x) {} + + std::string error_message() const { return home().err_msg(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-notification_receiver.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-notification_receiver.hxx new file mode 100644 index 0000000000..d03f048f37 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-notification_receiver.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> + +#include <pqxx/connection_base> + + +namespace pqxx +{ +class notification_receiver; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_notification_receiver : callgate<connection_base> +{ + friend class pqxx::notification_receiver; + + connection_notification_receiver(reference x) : super(x) {} + + void add_receiver(notification_receiver *receiver) + { home().add_receiver(receiver); } + void remove_receiver(notification_receiver *receiver) noexcept + { home().remove_receiver(receiver); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-parameterized_invocation.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-parameterized_invocation.hxx new file mode 100644 index 0000000000..364c5b6dac --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-parameterized_invocation.hxx @@ -0,0 +1,37 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class connection_base; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_parameterized_invocation : + callgate<connection_base> +{ + friend class pqxx::internal::parameterized_invocation; + + connection_parameterized_invocation(reference x) : super(x) {} + + result parameterized_exec( + const std::string &query, + const char *const params[], + const int paramlengths[], + const int binaries[], + int nparams) + { +#include <pqxx/internal/ignore-deprecated-pre.hxx> + return home().parameterized_exec( + query, + params, + paramlengths, + binaries, + nparams); +#include <pqxx/internal/ignore-deprecated-post.hxx> + } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-pipeline.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-pipeline.hxx new file mode 100644 index 0000000000..d7d42ef981 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-pipeline.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> +#include "pqxx/internal/libpq-forward.hxx" + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_pipeline : callgate<connection_base> +{ + friend class pqxx::pipeline; + + connection_pipeline(reference x) : super(x) {} + + void start_exec(const std::string &query) { home().start_exec(query); } + pqxx::internal::pq::PGresult *get_result() { return home().get_result(); } + void cancel_query() { home().cancel_query(); } + + bool consume_input() noexcept { return home().consume_input(); } + bool is_busy() const noexcept { return home().is_busy(); } + + int encoding_id() { return home().encoding_id(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-prepare-invocation.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-prepare-invocation.hxx new file mode 100644 index 0000000000..c1c29583cc --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-prepare-invocation.hxx @@ -0,0 +1,45 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace prepare +{ +class invocation; +} // namespace pqxx::prepare + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_prepare_invocation : callgate<connection_base> +{ + friend class pqxx::prepare::invocation; + + connection_prepare_invocation(reference x) : super(x) {} + + /// @deprecated To be replaced by exec_prepared. + result prepared_exec( + const std::string &statement, + const char *const params[], + const int paramlengths[], + const int binary[], + int nparams, + result_format format) + { +#include <pqxx/internal/ignore-deprecated-pre.hxx> + return home().prepared_exec( + statement, + params, + paramlengths, + binary, + nparams, + format); +#include <pqxx/internal/ignore-deprecated-post.hxx> + } + + bool prepared_exists(const std::string &statement) const + { return home().prepared_exists(statement); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx new file mode 100644 index 0000000000..48ef89a46e --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-reactivation_avoidance_exemption.hxx @@ -0,0 +1,24 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +class reactivation_avoidance_exemption; + +namespace gate +{ +class PQXX_PRIVATE connection_reactivation_avoidance_exemption : + callgate<connection_base> +{ + friend class pqxx::internal::reactivation_avoidance_exemption; + + connection_reactivation_avoidance_exemption(reference x) : super(x) {} + + int get_counter() const { return home().m_reactivation_avoidance.get(); } + void add_counter(int x) const { home().m_reactivation_avoidance.add(x); } + void clear_counter() { home().m_reactivation_avoidance.clear(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-sql_cursor.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-sql_cursor.hxx new file mode 100644 index 0000000000..bb2cfee177 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-sql_cursor.hxx @@ -0,0 +1,25 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +class sql_cursor; + +namespace gate +{ +class PQXX_PRIVATE connection_sql_cursor : callgate<connection_base> +{ + friend class pqxx::internal::sql_cursor; + + connection_sql_cursor(reference x) : super(x) {} + + result exec(const char query[], int retries) + { return home().exec(query, retries); } + + void add_reactivation_avoidance_count(int n) + { home().add_reactivation_avoidance_count(n); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-transaction.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-transaction.hxx new file mode 100644 index 0000000000..f2aaac07f7 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/connection-transaction.hxx @@ -0,0 +1,77 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +class connection_base; + +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE connection_transaction : callgate<connection_base> +{ + friend class pqxx::transaction_base; + + connection_transaction(reference x) : super(x) {} + + result exec(const char query[], int retries) + { return home().exec(query, retries); } + void register_transaction(transaction_base *t) + { home().register_transaction(t); } + void unregister_transaction(transaction_base *t) noexcept + { home().unregister_transaction(t); } + + bool read_copy_line(std::string &line) + { return home().read_copy_line(line); } + void write_copy_line(const std::string &line) + { home().write_copy_line(line); } + void end_copy_write() { home().end_copy_write(); } + + std::string raw_get_var(const std::string &var) + { return home().raw_get_var(var); } + void raw_set_var(const std::string &var, const std::string &value) + { home().raw_set_var(var, value); } + void add_variables(const std::map<std::string, std::string> &vars) + { home().add_variables(vars); } + + /// @deprecated To be replaced by exec_prepared. + result prepared_exec( + const std::string &statement, + const char *const params[], + const int paramlengths[], + const int binaries[], + int nparams) + { +#include <pqxx/internal/ignore-deprecated-pre.hxx> + return home().prepared_exec( + statement, + params, + paramlengths, + binaries, + nparams, + result_format::text); +#include <pqxx/internal/ignore-deprecated-post.hxx> + } + + result exec_prepared( + const std::string &statement, + const internal::params &args, + result_format format) + { + return home().exec_prepared(statement, args, format); + } + + result exec_params(const std::string &query, const internal::params &args) + { + return home().exec_params(query, args); + } + + bool prepared_exists(const std::string &statement) const + { return home().prepared_exists(statement); } + + void take_reactivation_avoidance(int counter) + { home().m_reactivation_avoidance.add(counter); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/errorhandler-connection.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/errorhandler-connection.hxx new file mode 100644 index 0000000000..1b118e5610 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/errorhandler-connection.hxx @@ -0,0 +1,19 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE errorhandler_connection_base : callgate<errorhandler> +{ + friend class pqxx::connection_base; + + errorhandler_connection_base(reference x) : super(x) {} + + void unregister() noexcept { home().unregister(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/icursor_iterator-icursorstream.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursor_iterator-icursorstream.hxx new file mode 100644 index 0000000000..9c17cf2916 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursor_iterator-icursorstream.hxx @@ -0,0 +1,28 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE icursor_iterator_icursorstream : callgate<icursor_iterator> +{ + friend class pqxx::icursorstream; + + icursor_iterator_icursorstream(reference x) : super(x) {} + + icursor_iterator::difference_type pos() const noexcept + { return home().pos(); } + + icursor_iterator *get_prev() { return home().m_prev; } + void set_prev(icursor_iterator *i) { home().m_prev = i; } + + icursor_iterator *get_next() { return home().m_next; } + void set_next(icursor_iterator *i) { home().m_next = i; } + + void fill(const result &r) { home().fill(r); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/icursorstream-icursor_iterator.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursorstream-icursor_iterator.hxx new file mode 100644 index 0000000000..8f28336bb5 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/icursorstream-icursor_iterator.hxx @@ -0,0 +1,30 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE icursorstream_icursor_iterator : callgate<icursorstream> +{ + friend class pqxx::icursor_iterator; + + icursorstream_icursor_iterator(reference x) : super(x) {} + + void insert_iterator(icursor_iterator *i) noexcept + { home().insert_iterator(i); } + + void remove_iterator(icursor_iterator *i) const noexcept + { home().remove_iterator(i); } + + icursorstream::size_type forward() { return home().forward(); } + icursorstream::size_type forward(icursorstream::size_type n) + { return home().forward(n); } + + void service_iterators(icursorstream::difference_type p) + { home().service_iterators(p); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/result-connection.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-connection.hxx new file mode 100644 index 0000000000..76c8e7a1f1 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-connection.hxx @@ -0,0 +1,20 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE result_connection : callgate<const result> +{ + friend class pqxx::connection_base; + + result_connection(reference x) : super(x) {} + + operator bool() const { return bool(home()); } + bool operator!() const { return not home(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/result-creation.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-creation.hxx new file mode 100644 index 0000000000..6d5671c529 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-creation.hxx @@ -0,0 +1,28 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE result_creation : callgate<const result> +{ + friend class pqxx::connection_base; + friend class pqxx::pipeline; + + result_creation(reference x) : super(x) {} + + static result create( + internal::pq::PGresult *rhs, + const std::string &query, + encoding_group enc) + { + return result(rhs, query, enc); + } + + void check_status() const { return home().check_status(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/result-row.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-row.hxx new file mode 100644 index 0000000000..692d3b5f5b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/result-row.hxx @@ -0,0 +1,22 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +class row; + +namespace gate +{ +class PQXX_PRIVATE result_row : callgate<result> +{ + friend class pqxx::row; + + result_row(reference x) : super(x) {} + + operator bool() + { return bool(home()); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-sql_cursor.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-sql_cursor.hxx new file mode 100644 index 0000000000..878b171b95 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-sql_cursor.hxx @@ -0,0 +1,16 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_sql_cursor : callgate<transaction_base> +{ + friend class pqxx::internal::sql_cursor; + transaction_sql_cursor(reference x) : super(x) {} +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_from.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_from.hxx new file mode 100644 index 0000000000..6345543dda --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_from.hxx @@ -0,0 +1,23 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_stream_from : callgate<transaction_base> +{ + friend class pqxx::stream_from; + + transaction_stream_from(reference x) : super(x) {} + + void BeginCopyRead(const std::string &table, const std::string &columns) + { home().BeginCopyRead(table, columns); } + + bool read_copy_line(std::string &line) + { return home().read_copy_line(line); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_to.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_to.hxx new file mode 100644 index 0000000000..6ee9e9b7d6 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-stream_to.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_stream_to : callgate<transaction_base> +{ + friend class pqxx::stream_to; + + transaction_stream_to(reference x) : super(x) {} + + void BeginCopyWrite( + const std::string &table, + const std::string &columns = std::string{}) + { home().BeginCopyWrite(table, columns); } + + void write_copy_line(const std::string &line) + { home().write_copy_line(line); } + + void end_copy_write() { home().end_copy_write(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-subtransaction.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-subtransaction.hxx new file mode 100644 index 0000000000..243f47a798 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-subtransaction.hxx @@ -0,0 +1,20 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_subtransaction : callgate<transaction_base> +{ + friend class pqxx::subtransaction; + + transaction_subtransaction(reference x) : super(x) {} + + void add_reactivation_avoidance_count(int n) + { home().m_reactivation_avoidance.add(n); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablereader.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablereader.hxx new file mode 100644 index 0000000000..6946d36391 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablereader.hxx @@ -0,0 +1,23 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_tablereader : callgate<transaction_base> +{ + friend class pqxx::tablereader; + + transaction_tablereader(reference x) : super(x) {} + + void BeginCopyRead(const std::string &table, const std::string &columns) + { home().BeginCopyRead(table, columns); } + + bool read_copy_line(std::string &line) + { return home().read_copy_line(line); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablewriter.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablewriter.hxx new file mode 100644 index 0000000000..3256090a2f --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-tablewriter.hxx @@ -0,0 +1,27 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_tablewriter : callgate<transaction_base> +{ + friend class pqxx::tablewriter; + + transaction_tablewriter(reference x) : super(x) {} + + void BeginCopyWrite( + const std::string &table, + const std::string &columns = std::string{}) + { home().BeginCopyWrite(table, columns); } + + void write_copy_line(const std::string &line) + { home().write_copy_line(line); } + + void end_copy_write() { home().end_copy_write(); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-transactionfocus.hxx b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-transactionfocus.hxx new file mode 100644 index 0000000000..9ea117a2ea --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/gates/transaction-transactionfocus.hxx @@ -0,0 +1,23 @@ +#include <pqxx/internal/callgate.hxx> + +namespace pqxx +{ +namespace internal +{ +namespace gate +{ +class PQXX_PRIVATE transaction_transactionfocus : callgate<transaction_base> +{ + friend class pqxx::internal::transactionfocus; + + transaction_transactionfocus(reference x) : super(x) {} + + void register_focus(transactionfocus *focus) { home().register_focus(focus); } + void unregister_focus(transactionfocus *focus) noexcept + { home().unregister_focus(focus); } + void register_pending_error(const std::string &error) + { home().register_pending_error(error); } +}; +} // namespace pqxx::internal::gate +} // namespace pqxx::internal +} // namespace pqxx diff --git a/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-post.hxx b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-post.hxx new file mode 100644 index 0000000000..32a84b2751 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-post.hxx @@ -0,0 +1,6 @@ +/// End a code block started by "ignore-deprecated-pre.hxx". +#if defined(__GNUC__) + +#pragma GCC diagnostic pop + +#endif // __GNUC__ diff --git a/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-pre.hxx b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-pre.hxx new file mode 100644 index 0000000000..9ada1b7205 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/ignore-deprecated-pre.hxx @@ -0,0 +1,19 @@ +/** Start a block of deprecated code which may call other deprecated code. + * + * Most compilers will emit warnings when deprecated code is invoked from + * non-deprecated code. But some compilers (notably gcc) will always emit the + * warning, even when the calling code is also deprecated. + * + * This header starts a block where those warnings are suppressed. It can be + * included inside a code block. + * + * Always match the #include with a closing #include of + * "ignore-deprecated-post.hxx". To avoid mistakes, keep the enclosed area as + * small as possible. + */ +#if defined(__GNUC__) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#endif // __GNUC__ diff --git a/contrib/libs/libpqxx/include/pqxx/internal/libpq-forward.hxx b/contrib/libs/libpqxx/include/pqxx/internal/libpq-forward.hxx new file mode 100644 index 0000000000..394f3068b2 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/libpq-forward.hxx @@ -0,0 +1,34 @@ +/** Minimal forward declarations of libpq types needed in libpqxx headers. + * + * DO NOT INCLUDE THIS FILE when building client programs. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +extern "C" +{ +struct pg_conn; +struct pg_result; +struct pgNotify; +} + +namespace pqxx +{ +namespace internal +{ +/// Forward declarations of libpq types as needed in libpqxx headers +namespace pq +{ +using PGconn = pg_conn; +using PGresult = pg_result; +using PGnotify = pgNotify; +using PQnoticeProcessor = void (*)(void *, const char *); +} +} + +/// PostgreSQL database row identifier +using oid = unsigned int; +} // extern "C" diff --git a/contrib/libs/libpqxx/include/pqxx/internal/sql_cursor.hxx b/contrib/libs/libpqxx/include/pqxx/internal/sql_cursor.hxx new file mode 100644 index 0000000000..828f9d3e6e --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/sql_cursor.hxx @@ -0,0 +1,122 @@ +/** Internal wrapper for SQL cursors. Supports higher-level cursor classes. + * + * DO NOT INCLUDE THIS FILE DIRECTLY. Other headers include it for you. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this + * mistake, or contact the author. + */ +#ifndef PQXX_H_SQL_CURSOR +#define PQXX_H_SQL_CURSOR + +namespace pqxx +{ +namespace internal +{ +/// Cursor with SQL positioning semantics. +/** Thin wrapper around an SQL cursor, with SQL's ideas of positioning. + * + * SQL cursors have pre-increment/pre-decrement semantics, with on either end of + * the result set a special position that does not repesent a row. This class + * models SQL cursors for the purpose of implementing more C++-like semantics on + * top. + * + * Positions of actual rows are numbered starting at 1. Position 0 exists but + * does not refer to a row. There is a similar non-row position at the end of + * the result set. + * + * Don't use this at home. You deserve better. Use the stateles_cursor + * instead. + */ +class PQXX_LIBEXPORT sql_cursor : public cursor_base +{ +public: + sql_cursor( + transaction_base &t, + const std::string &query, + const std::string &cname, + cursor_base::accesspolicy ap, + cursor_base::updatepolicy up, + cursor_base::ownershippolicy op, + bool hold, + result_format format = result_format::text); + + sql_cursor( + transaction_base &t, + const std::string &cname, + cursor_base::ownershippolicy op); + + ~sql_cursor() noexcept { close(); } + + result fetch(difference_type rows, difference_type &displacement); + result fetch(difference_type rows) + { difference_type d=0; return fetch(rows, d); } + difference_type move(difference_type rows, difference_type &displacement); + difference_type move(difference_type rows) + { difference_type d=0; return move(rows, d); } + + /// Current position, or -1 for unknown + /** + * The starting position, just before the first row, counts as position zero. + * + * Position may be unknown if (and only if) this cursor was adopted, and has + * never hit its starting position (position zero). + */ + difference_type pos() const noexcept { return m_pos; } + + /// End position, or -1 for unknown + /** + * Returns the final position, just after the last row in the result set. The + * starting position, just before the first row, counts as position zero. + * + * End position is unknown until it is encountered during use. + */ + difference_type endpos() const noexcept { return m_endpos; } + + /// Return zero-row result for this cursor + const result &empty_result() const noexcept { return m_empty_result; } + + void close() noexcept; + +private: + difference_type adjust(difference_type hoped, difference_type actual); + static std::string stridestring(difference_type); + /// Initialize cached empty result. Call only at beginning or end! + void init_empty_result(transaction_base &); + + /// Connection this cursor lives in + connection_base &m_home; + + /// Zero-row result from this cursor (or plain empty one if cursor is adopted) + result m_empty_result; + + result m_cached_current_row; + + /// Is this cursor adopted (as opposed to created by this cursor object)? + bool m_adopted; + + /// Will this cursor object destroy its SQL cursor when it dies? + cursor_base::ownershippolicy m_ownership; + + /// At starting position (-1), somewhere in the middle (0), or past end (1) + int m_at_end; + + /// Position, or -1 for unknown + difference_type m_pos; + + /// End position, or -1 for unknown + difference_type m_endpos = -1; +}; + + +PQXX_LIBEXPORT result_size_type obtain_stateless_cursor_size(sql_cursor &); +PQXX_LIBEXPORT result stateless_cursor_retrieve( + sql_cursor &, + result::difference_type size, + result::difference_type begin_pos, + result::difference_type end_pos); +} // namespace internal +} // namespace pqxx +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/statement_parameters.hxx b/contrib/libs/libpqxx/include/pqxx/internal/statement_parameters.hxx new file mode 100644 index 0000000000..8c80f6df48 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/statement_parameters.hxx @@ -0,0 +1,227 @@ +/** Common implementation for statement parameter lists. + * + * These are used for both prepared statements and parameterized statements. + * + * DO NOT INCLUDE THIS FILE DIRECTLY. Other headers include it for you. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_STATEMENT_PARAMETER +#define PQXX_H_STATEMENT_PARAMETER + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <cstring> +#include <iterator> +#include <string> +#include <vector> + +#include "pqxx/binarystring" +#include "pqxx/strconv" +#include "pqxx/util" + +#include "pqxx/internal/type_utils.hxx" + + +namespace pqxx +{ +namespace internal +{ +/// Marker type: pass a dynamically-determined number of statement parameters. +/** Normally when invoking a prepared or parameterised statement, the number + * of parameters is known at compile time. For instance, + * @c t.exec_prepared("foo", 1, "x"); executes statement @c foo with two + * parameters, an @c int and a C string. + * + * But sometimes you may want to pass a number of parameters known only at run + * time. In those cases, a @c dynamic_params encodes a dynamically + * determined number of parameters. + */ +template<typename IT> class dynamic_params +{ +public: + /// Wrap a sequence of pointers or iterators. + dynamic_params(IT begin, IT end) : m_begin(begin), m_end(end) {} + + /// Wrap a container. + template<typename C> explicit dynamic_params(const C &container) : + m_begin(std::begin(container)), + m_end(std::end(container)) + {} + + IT begin() const { return m_begin; } + IT end() const { return m_end; } + +private: + const IT m_begin, m_end; +}; + + +class PQXX_LIBEXPORT statement_parameters +{ +protected: + statement_parameters() =default; + statement_parameters &operator=(const statement_parameters &) =delete; + + void add_param() { this->add_checked_param("", false, false); } + template<typename T> void add_param(const T &v, bool nonnull) + { + nonnull = (nonnull && not pqxx::string_traits<T>::is_null(v)); + this->add_checked_param( + (nonnull ? pqxx::to_string(v) : ""), + nonnull, + false); + } + void add_binary_param(const binarystring &b, bool nonnull) + { this->add_checked_param(b.str(), nonnull, true); } + + /// Marshall parameter values into C-compatible arrays for passing to libpq. + int marshall( + std::vector<const char *> &values, + std::vector<int> &lengths, + std::vector<int> &binaries) const; + +private: + void add_checked_param(const std::string &value, bool nonnull, bool binary); + + std::vector<std::string> m_values; + std::vector<bool> m_nonnull; + std::vector<bool> m_binary; +}; + + +/// Internal type: encode statement parameters. +/** Compiles arguments for prepared statements and parameterised queries into + * a format that can be passed into libpq. + * + * Objects of this type are meant to be short-lived. If you pass in a non-null + * pointer as a parameter, it may simply use that pointer as a parameter value. + */ +struct params +{ + /// Construct directly from a series of statement arguments. + /** The arrays all default to zero, null, and empty strings. + */ + template<typename ...Args> params(Args && ... args) + { + strings.reserve(sizeof...(args)); + lengths.reserve(sizeof...(args)); + nonnulls.reserve(sizeof...(args)); + binaries.reserve(sizeof...(args)); + + // Start recursively storing parameters. + add_fields(std::forward<Args>(args)...); + } + + /// Compose a vector of pointers to parameter string values. + std::vector<const char *> get_pointers() const + { + const std::size_t num_fields = lengths.size(); + std::size_t cur_string = 0, cur_bin_string = 0; + std::vector<const char *> pointers(num_fields); + for (std::size_t index = 0; index < num_fields; index++) + { + const char *value; + if (binaries[index]) + { + value = bin_strings[cur_bin_string].get(); + cur_bin_string++; + } + else if (nonnulls[index]) + { + value = strings[cur_string].c_str(); + cur_string++; + } + else + { + value = nullptr; + } + pointers[index] = value; + } + return pointers; + } + + /// String values, for string parameters. + std::vector<std::string> strings; + /// As used by libpq: lengths of non-null arguments, in bytes. + std::vector<int> lengths; + /// As used by libpq: boolean "is this parameter non-null?" + std::vector<int> nonnulls; + /// As used by libpq: boolean "is this parameter in binary format?" + std::vector<int> binaries; + /// Binary string values, for binary parameters. + std::vector<pqxx::binarystring> bin_strings; + +private: + /// Add a non-null string field. + void add_field(std::string str) + { + lengths.push_back(int(str.size())); + nonnulls.push_back(1); + binaries.push_back(0); + strings.emplace_back(std::move(str)); + } + + /// Compile one argument (specialised for null pointer, a null value). + void add_field(std::nullptr_t) + { + lengths.push_back(0); + nonnulls.push_back(0); + binaries.push_back(0); + } + + /// Compile one argument (specialised for binarystring). + void add_field(const binarystring &arg) + { + lengths.push_back(int(arg.size())); + nonnulls.push_back(1); + binaries.push_back(1); + bin_strings.push_back(arg); + } + + /// Compile one argument (default, generic implementation). + /** Uses string_traits to represent the argument as a std::string. + */ + template<typename Arg> void add_field(const Arg &arg) + { + if (string_traits<Arg>::is_null(arg)) add_field(nullptr); + else add_field(to_string(arg)); + } + + /// Compile a dynamic_params object into a dynamic number of parameters. + template<typename IT> void add_field(const dynamic_params<IT> ¶meters) + { + for (auto param: parameters) add_field(param); + } + + /// Compile argument list. + /** This recursively "peels off" the next remaining element, compiles its + * information into its final form, and calls itself for the rest of the + * list. + * + * @param arg Current argument to be compiled. + * @param args Optional remaining arguments, to be compiled recursively. + */ + template<typename Arg, typename ...More> + void add_fields(Arg &&arg, More && ... args) + { + add_field(std::forward<Arg>(arg)); + // Compile remaining arguments, if any. + add_fields(std::forward<More>(args)...); + } + + /// Terminating version of add_fields, at the end of the list. + /** Recursion in add_fields ends with this call. + */ + void add_fields() {} +}; +} // namespace pqxx::internal +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/internal/type_utils.hxx b/contrib/libs/libpqxx/include/pqxx/internal/type_utils.hxx new file mode 100644 index 0000000000..7bf5528018 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/internal/type_utils.hxx @@ -0,0 +1,211 @@ +/** Type/template metaprogramming utilities for use internally in libpqxx + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TYPE_UTILS +#define PQXX_H_TYPE_UTILS + +#include <memory> +#include <type_traits> + +#if defined(PQXX_HAVE_OPTIONAL) +#include <optional> +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +#error #include <experimental/optional> +#endif + +#include "pqxx/strconv" + +namespace pqxx +{ +namespace internal +{ + +/// Replicate std::void_t<> (available in C++17). +template<typename... T> using void_t = void; + +/// Extract the content type held by an `optional`-like wrapper type. +/* Replace nested `std::remove_*`s with `std::remove_cvref` in C++20 */ +template<typename T> using inner_type = typename std::remove_cv< + typename std::remove_reference< + decltype(*std::declval<T>()) + >::type +>::type; + +/// Does the given type have an `operator *()`? +template<typename T, typename = void> struct is_derefable : std::false_type {}; +template<typename T> struct is_derefable<T, void_t< + // Disable for arrays so they don't erroneously decay to pointers. + inner_type<typename std::enable_if<not std::is_array<T>::value, T>::type> +>> : std::true_type {}; + +/// Should the given type be treated as an optional-value wrapper type? +template<typename T, typename = void> struct is_optional : std::false_type {}; +template<typename T> struct is_optional<T, typename std::enable_if<( + is_derefable<T>::value + // Check if an `explicit operator bool` exists for this type + && std::is_constructible<bool, T>::value +)>::type> : std::true_type {}; + +/// Can `nullopt_t` implicitly convert to type T? +template< + typename T, + typename = void +> struct takes_std_nullopt : std::false_type {}; +#if defined(PQXX_HAVE_OPTIONAL) +template<typename T> struct takes_std_nullopt< + T, + typename std::enable_if<std::is_assignable<T, std::nullopt_t>::value>::type +> : std::true_type {}; +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +template<typename T> struct takes_std_nullopt< + T, + typename std::enable_if< + std::is_assignable<T, std::experimental::nullopt_t>::value + >::type +> : std::true_type {}; +#endif + +/// Is type T a `std::tuple<>`? +template<typename T, typename = void> struct is_tuple : std::false_type {}; +template<typename T> struct is_tuple< + T, + typename std::enable_if<(std::tuple_size<T>::value >= 0)>::type +> : std::true_type {}; + +/// Is type T an iterable container? +template<typename T, typename = void> struct is_container : std::false_type {}; +template<typename T> struct is_container< + T, + void_t< + decltype(std::begin(std::declval<T>())), + decltype(std::end(std::declval<T>())), + // Some people might implement a `std::tuple<>` specialization that is + // iterable when all the contained types are the same ;) + typename std::enable_if<not is_tuple<T>::value>::type + > +> : std::true_type {}; + +/// Get an appropriate null value for the given type. +/** + * pointer types `nullptr` + * `std::optional<>`-like `std::nullopt` + * `std::experimental::optional<>`-like `std::experimental::nullopt` + * other types `pqxx::string_traits<>::null()` + * Users may add support for their own wrapper types following this pattern. + */ +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + ( + is_optional<T>::value + && not takes_std_nullopt<T>::value + && std::is_assignable<T, std::nullptr_t>::value + ), + std::nullptr_t + >::type +{ return nullptr; } +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + (not is_optional<T>::value && not takes_std_nullopt<T>::value), + decltype(pqxx::string_traits<T>::null()) + >::type +{ return pqxx::string_traits<T>::null(); } +#if defined(PQXX_HAVE_OPTIONAL) +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + takes_std_nullopt<T>::value, + std::nullopt_t + >::type +{ return std::nullopt; } +#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL) +template<typename T> constexpr auto null_value() + -> typename std::enable_if< + takes_std_nullopt<T>::value, + std::experimental::nullopt_t + >::type +{ return std::experimental::nullopt; } +#endif + +/// Construct an optional-like type from the stored type. +/** + * While these may seem redundant, they are necessary to support smart pointers + * as optional storage types in a generic manner. It is suggested NOT to + * provide a version for `inner_type<T>*` as that will almost certainly leak + * memory. + * Users may add support for their own wrapper types following this pattern. + */ +// Enabled if the wrapper type can be directly constructed from the wrapped type +// (e.g. `std::optional<>`); explicitly disabled for raw pointers in case the +// inner type is convertible to a pointer (e.g. `int`) +template<typename T, typename V> constexpr auto make_optional(V&& v) + -> typename std::enable_if< + not std::is_same<T, inner_type<T>*>::value, + decltype(T(std::forward<V>(v))) + >::type +{ return T(std::forward<V>(v)); } +// Enabled if T is a specialization of `std::unique_ptr<>`. +template<typename T, typename V> constexpr auto make_optional(V&& v) + -> typename std::enable_if< + std::is_same<T, std::unique_ptr<inner_type<T>>>::value, + std::unique_ptr<inner_type<T>> + >::type +{ + return std::unique_ptr<inner_type<T>>(new inner_type<T>(std::forward<V>(v))); +} +// Enabled if T is a specialization of `std::shared_ptr<>`. +template<typename T, typename V> constexpr auto make_optional(V&& v) + -> typename std::enable_if< + std::is_same<T, std::shared_ptr<inner_type<T>>>::value, + std::shared_ptr<inner_type<T>> + >::type +{ return std::make_shared<inner_type<T>>(std::forward<V>(v)); } + +} // namespace pqxx::internal +} // namespace pqxx + + +// TODO: Move? +namespace pqxx +{ + +/// Meta `pqxx::string_traits` for std::optional-like types. +template<typename T> struct string_traits< + T, + typename std::enable_if<internal::is_optional<T>::value>::type +> +{ +private: + using I = internal::inner_type<T>; +public: + static constexpr const char *name() noexcept + { return string_traits<I>::name(); } + static constexpr bool has_null() noexcept { return true; } + static bool is_null(const T& v) + { return (not v || string_traits<I>::is_null(*v)); } + static constexpr T null() { return internal::null_value<T>(); } + static void from_string(const char Str[], T &Obj) + { + if (not Str) Obj = null(); + else + { + I inner; + string_traits<I>::from_string(Str, inner); + // Utilize existing memory if possible (e.g. for pointer types). + if (Obj) *Obj = inner; + // Important to assign to set valid flag for smart optional types. + else Obj = internal::make_optional<T>(inner); + } + } + static std::string to_string(const T& Obj) + { + if (is_null(Obj)) internal::throw_null_conversion(name()); + return string_traits<I>::to_string(*Obj); + } +}; + +} // namespace pqxx +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/isolation.hxx b/contrib/libs/libpqxx/include/pqxx/isolation.hxx new file mode 100644 index 0000000000..fbabb994ed --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/isolation.hxx @@ -0,0 +1,87 @@ +/** Definitions of transaction isolation levels. + * + * Policies and traits describing SQL transaction isolation levels + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/isolation instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ISOLATION +#define PQXX_H_ISOLATION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/util.hxx" + +namespace pqxx +{ + +/// Transaction isolation levels. +/** These are as defined in the SQL standard. But there are a few notes + * specific to PostgreSQL. + * + * First, postgres does not support "read uncommitted." The lowest level you + * can get is "read committed," which is better. PostgreSQL is built on the + * MVCC paradigm, which guarantees "read committed" isolation without any + * additional performance overhead, so there was no point in providing the + * lower level. + * + * Second, "repeatable read" also makes more isolation guarantees than the + * standard requires. According to the standard, this level prevents "dirty + * reads" and "nonrepeatable reads," but not "phantom reads." In postgres, + * it actually prevents all three. + * + * Third, "serializable" is only properly supported starting at postgres 9.1. + * If you request "serializable" isolation on an older backend, you will get + * the same isolation as in "repeatable read." It's better than the "repeatable + * read" defined in the SQL standard, but not a complete implementation of the + * standard's "serializable" isolation level. + * + * In general, a lower isolation level will allow more surprising interactions + * between ongoing transactions, but improve performance. A higher level + * gives you more protection from subtle concurrency bugs, but sometimes it + * may not be possible to complete your transaction without avoiding paradoxes + * in the data. In that case a transaction may fail, and the application will + * have to re-do the whole thing based on the latest state of the database. + * (If you want to retry your code in that situation, have a look at the + * transactor framework.) + * + * Study the levels and design your application with the right level in mind. + */ +enum isolation_level +{ + // read_uncommitted, + read_committed, + repeatable_read, + serializable +}; + +/// Traits class to describe an isolation level; primarly for libpqxx's own use +template<isolation_level LEVEL> struct isolation_traits +{ + static constexpr isolation_level level() noexcept { return LEVEL; } + static constexpr const char *name() noexcept; +}; + + +template<> +inline constexpr const char *isolation_traits<read_committed>::name() noexcept + { return "READ COMMITTED"; } + +template<> +inline constexpr const char *isolation_traits<repeatable_read>::name() noexcept + { return "REPEATABLE READ"; } + +template<> +inline constexpr const char *isolation_traits<serializable>::name() noexcept + { return "SERIALIZABLE"; } + +} + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/largeobject b/contrib/libs/libpqxx/include/pqxx/largeobject new file mode 100644 index 0000000000..b1dedd597a --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/largeobject @@ -0,0 +1,6 @@ +/** Large Objects interface. + * + * Supports direct access to large objects, as well as through I/O streams + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/largeobject.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/largeobject.hxx b/contrib/libs/libpqxx/include/pqxx/largeobject.hxx new file mode 100644 index 0000000000..f2f7c0e7fe --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/largeobject.hxx @@ -0,0 +1,672 @@ +/** Large Objects interface. + * + * Allows access to large objects directly, or through I/O streams. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_LARGEOBJECT +#define PQXX_H_LARGEOBJECT + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <streambuf> + +#include "pqxx/dbtransaction.hxx" + + +namespace pqxx +{ +/// Identity of a large object +/** This class encapsulates the identity of a large object. To access the + * contents of the object, create a largeobjectaccess, a largeobject_streambuf, + * or an ilostream, an olostream or a lostream around the largeobject. + * + * A largeobject must be accessed only from within a backend transaction, but + * the object's identity remains valid as long as the object exists. + */ +class PQXX_LIBEXPORT largeobject +{ +public: + using size_type = large_object_size_type; + + /// Refer to a nonexistent large object (similar to what a null pointer does) + largeobject() noexcept =default; //[t48] + + /// Create new large object + /** @param T Backend transaction in which the object is to be created + */ + explicit largeobject(dbtransaction &T); //[t48] + + /// Wrap object with given oid + /** Convert combination of a transaction and object identifier into a + * large object identity. Does not affect the database. + * @param O Object identifier for the given object + */ + explicit largeobject(oid O) noexcept : m_id{O} {} //[t48] + + /// Import large object from a local file + /** Creates a large object containing the data found in the given file. + * @param T Backend transaction in which the large object is to be created + * @param File A filename on the client program's filesystem + */ + largeobject(dbtransaction &T, const std::string &File); //[t53] + + /// Take identity of an opened large object + /** Copy identity of already opened large object. Note that this may be done + * as an implicit conversion. + * @param O Already opened large object to copy identity from + */ + largeobject(const largeobjectaccess &O) noexcept; //[t50] + + /// Object identifier + /** The number returned by this function identifies the large object in the + * database we're connected to (or oid_none is returned if we refer to the + * null object). + */ + oid id() const noexcept { return m_id; } //[t48] + + /** + * @name Identity comparisons + * + * These operators compare the object identifiers of large objects. This has + * nothing to do with the objects' actual contents; use them only for keeping + * track of containers of references to large objects and such. + */ + //@{ + /// Compare object identities + /** @warning Only valid between large objects in the same database. */ + bool operator==(const largeobject &other) const //[t51] + { return m_id == other.m_id; } + /// Compare object identities + /** @warning Only valid between large objects in the same database. */ + bool operator!=(const largeobject &other) const //[t51] + { return m_id != other.m_id; } + /// Compare object identities + /** @warning Only valid between large objects in the same database. */ + bool operator<=(const largeobject &other) const //[t51] + { return m_id <= other.m_id; } + /// Compare object identities + /** @warning Only valid between large objects in the same database. */ + bool operator>=(const largeobject &other) const //[t51] + { return m_id >= other.m_id; } + /// Compare object identities + /** @warning Only valid between large objects in the same database. */ + bool operator<(const largeobject &other) const //[t51] + { return m_id < other.m_id; } + /// Compare object identities + /** @warning Only valid between large objects in the same database. */ + bool operator>(const largeobject &other) const //[t51] + { return m_id > other.m_id; } + //@} + + /// Export large object's contents to a local file + /** Writes the data stored in the large object to the given file. + * @param T Transaction in which the object is to be accessed + * @param File A filename on the client's filesystem + */ + void to_file(dbtransaction &T, const std::string &File) const; //[t52] + + /// Delete large object from database + /** Unlike its low-level equivalent cunlink, this will throw an exception if + * deletion fails. + * @param T Transaction in which the object is to be deleted + */ + void remove(dbtransaction &T) const; //[t48] + +protected: + PQXX_PURE static internal::pq::PGconn *raw_connection( + const dbtransaction &T); + + PQXX_PRIVATE std::string reason(const connection_base &, int err) const; + +private: + oid m_id = oid_none; +}; + + +// TODO: New hierarchy with separate read / write / mixed-mode access + +/// Accessor for large object's contents. +class PQXX_LIBEXPORT largeobjectaccess : private largeobject +{ +public: + using largeobject::size_type; + using off_type = long; + using pos_type = size_type; + + /// Open mode: @c in, @c out (can be combined with the "or" operator) + /** According to the C++ standard, these should be in @c std::ios_base. We + * take them from @c std::ios instead, which should be safe because it + * inherits the same definition, to accommodate gcc 2.95 & 2.96. + */ + using openmode = std::ios::openmode; + + /// Seek direction: @c beg, @c cur, @c end + /** According to the C++ standard, these should be in @c std::ios_base. We + * take them from @c std::ios instead, which should be safe because it + * inherits the same definition, to accommodate gcc 2.95 & 2.96. + */ + using seekdir = std::ios::seekdir; + + /// Create new large object and open it + /** + * @param T Backend transaction in which the object is to be created + * @param mode Access mode, defaults to ios_base::in | ios_base::out + */ + explicit largeobjectaccess( //[t51] + dbtransaction &T, + openmode mode=std::ios::in|std::ios::out); + + /// Open large object with given oid + /** Convert combination of a transaction and object identifier into a + * large object identity. Does not affect the database. + * @param T Transaction in which the object is to be accessed + * @param O Object identifier for the given object + * @param mode Access mode, defaults to ios_base::in | ios_base::out + */ + largeobjectaccess( //[t52] + dbtransaction &T, + oid O, + openmode mode=std::ios::in|std::ios::out); + + /// Open given large object + /** Open a large object with the given identity for reading and/or writing + * @param T Transaction in which the object is to be accessed + * @param O Identity for the large object to be accessed + * @param mode Access mode, defaults to ios_base::in | ios_base::out + */ + largeobjectaccess( //[t50] + dbtransaction &T, + largeobject O, + openmode mode=std::ios::in|std::ios::out); + + /// Import large object from a local file and open it + /** Creates a large object containing the data found in the given file. + * @param T Backend transaction in which the large object is to be created + * @param File A filename on the client program's filesystem + * @param mode Access mode, defaults to ios_base::in | ios_base::out + */ + largeobjectaccess( //[t55] + dbtransaction &T, + const std::string &File, + openmode mode=std::ios::in|std::ios::out); + + ~largeobjectaccess() noexcept { close(); } + + /// Object identifier + /** The number returned by this function uniquely identifies the large object + * in the context of the database we're connected to. + */ + using largeobject::id; + + /// Export large object's contents to a local file + /** Writes the data stored in the large object to the given file. + * @param File A filename on the client's filesystem + */ + void to_file(const std::string &File) const //[t54] + { largeobject::to_file(m_trans, File); } + + using largeobject::to_file; + + /** + * @name High-level access to object contents + */ + //@{ + /// Write data to large object + /** If not all bytes could be written, an exception is thrown. + * @param Buf Data to write + * @param Len Number of bytes from Buf to write + */ + void write(const char Buf[], size_type Len); //[t51] + + /// Write string to large object + /** If not all bytes could be written, an exception is thrown. + * @param Buf Data to write; no terminating zero is written + */ + void write(const std::string &Buf) //[t50] + { write(Buf.c_str(), static_cast<size_type>(Buf.size())); } + + /// Read data from large object + /** Throws an exception if an error occurs while reading. + * @param Buf Location to store the read data in + * @param Len Number of bytes to try and read + * @return Number of bytes read, which may be less than the number requested + * if the end of the large object is reached + */ + size_type read(char Buf[], size_type Len); //[t50] + + /// Seek in large object's data stream + /** Throws an exception if an error occurs. + * @return The new position in the large object + */ + size_type seek(size_type dest, seekdir dir); //[t51] + + /// Report current position in large object's data stream + /** Throws an exception if an error occurs. + * @return The current position in the large object + */ + size_type tell() const; //[t50] + //@} + + /** + * @name Low-level access to object contents + * + * These functions provide a more "C-like" access interface, returning special + * values instead of throwing exceptions on error. These functions are + * generally best avoided in favour of the high-level access functions, which + * behave more like C++ functions should. + */ + //@{ + /// Seek in large object's data stream + /** Does not throw exception in case of error; inspect return value and + * @c errno instead. + * @param dest Offset to go to + * @param dir Origin to which dest is relative: ios_base::beg (from beginning + * of the object), ios_base::cur (from current access position), or + * ios_base;:end (from end of object) + * @return New position in large object, or -1 if an error occurred. + */ + pos_type cseek(off_type dest, seekdir dir) noexcept; //[t50] + + /// Write to large object's data stream + /** Does not throw exception in case of error; inspect return value and + * @c errno instead. + * @param Buf Data to write + * @param Len Number of bytes to write + * @return Number of bytes actually written, or -1 if an error occurred. + */ + off_type cwrite(const char Buf[], size_type Len) noexcept; //[t50] + + /// Read from large object's data stream + /** Does not throw exception in case of error; inspect return value and + * @c errno instead. + * @param Buf Area where incoming bytes should be stored + * @param Len Number of bytes to read + * @return Number of bytes actually read, or -1 if an error occurred. + */ + off_type cread(char Buf[], size_type Len) noexcept; //[t50] + + /// Report current position in large object's data stream + /** Does not throw exception in case of error; inspect return value and + * @c errno instead. + * @return Current position in large object, of -1 if an error occurred. + */ + pos_type ctell() const noexcept; //[t50] + //@} + + /** + * @name Error/warning output + */ + //@{ + /// Issue message to transaction's notice processor + void process_notice(const std::string &) noexcept; //[t50] + //@} + + using largeobject::remove; + + using largeobject::operator==; + using largeobject::operator!=; + using largeobject::operator<; + using largeobject::operator<=; + using largeobject::operator>; + using largeobject::operator>=; + +private: + PQXX_PRIVATE std::string reason(int err) const; + internal::pq::PGconn *raw_connection() const + { return largeobject::raw_connection(m_trans); } + + PQXX_PRIVATE void open(openmode mode); + void close() noexcept; + + dbtransaction &m_trans; + int m_fd = -1; + + largeobjectaccess() =delete; + largeobjectaccess(const largeobjectaccess &) =delete; + largeobjectaccess operator=(const largeobjectaccess &) =delete; +}; + + +/// Streambuf to use large objects in standard I/O streams +/** The standard streambuf classes provide uniform access to data storage such + * as files or string buffers, so they can be accessed using standard input or + * output streams. This streambuf implementation provides similar access to + * large objects, so they can be read and written using the same stream classes. + * + * @warning This class may not work properly in compiler environments that don't + * fully support Standard-compliant streambufs, such as g++ 2.95 or older. + */ +template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR>> + class largeobject_streambuf : + public std::basic_streambuf<CHAR, TRAITS> +{ + using size_type = long; +public: + using char_type = CHAR; + using traits_type = TRAITS; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + using openmode = largeobjectaccess::openmode; + using seekdir = largeobjectaccess::seekdir; + + largeobject_streambuf( //[t48] + dbtransaction &T, + largeobject O, + openmode mode=std::ios::in|std::ios::out, + size_type BufSize=512) : + m_bufsize{BufSize}, + m_obj{T, O, mode}, + m_g{nullptr}, + m_p{nullptr} + { initialize(mode); } + + largeobject_streambuf( //[t48] + dbtransaction &T, + oid O, + openmode mode=std::ios::in|std::ios::out, + size_type BufSize=512) : + m_bufsize{BufSize}, + m_obj{T, O, mode}, + m_g{nullptr}, + m_p{nullptr} + { initialize(mode); } + + virtual ~largeobject_streambuf() noexcept + { delete [] m_p; delete [] m_g; } + + + /// For use by large object stream classes + void process_notice(const std::string &s) { m_obj.process_notice(s); } + +protected: + virtual int sync() override + { + // setg() sets eback, gptr, egptr + this->setg(this->eback(), this->eback(), this->egptr()); + return overflow(EoF()); + } + + virtual pos_type seekoff( + off_type offset, + seekdir dir, + openmode) + override + { + return AdjustEOF(m_obj.cseek(largeobjectaccess::off_type(offset), dir)); + } + + virtual pos_type seekpos(pos_type pos, openmode) override + { + const largeobjectaccess::pos_type newpos = m_obj.cseek( + largeobjectaccess::off_type(pos), + std::ios::beg); + return AdjustEOF(newpos); + } + + virtual int_type overflow(int_type ch = EoF()) override + { + char *const pp = this->pptr(); + if (pp == nullptr) return EoF(); + char *const pb = this->pbase(); + int_type res = 0; + + if (pp > pb) res = int_type(AdjustEOF(m_obj.cwrite(pb, pp-pb))); + this->setp(m_p, m_p + m_bufsize); + + // Write that one more character, if it's there. + if (ch != EoF()) + { + *this->pptr() = char(ch); + this->pbump(1); + } + return res; + } + + virtual int_type underflow() override + { + if (this->gptr() == nullptr) return EoF(); + char *const eb = this->eback(); + const int_type res(static_cast<int_type>( + AdjustEOF(m_obj.cread(this->eback(), m_bufsize)))); + this->setg(eb, eb, eb + ((res==EoF()) ? 0 : res)); + return ((res == 0) or (res == EoF())) ? EoF() : *eb; + } + +private: + /// Shortcut for traits_type::eof(). + static int_type EoF() { return traits_type::eof(); } + + /// Helper: change error position of -1 to EOF (probably a no-op). + template<typename INTYPE> + static std::streampos AdjustEOF(INTYPE pos) + { return (pos==-1) ? std::streampos(EoF()) : std::streampos(pos); } + + void initialize(openmode mode) + { + if (mode & std::ios::in) + { + m_g = new char_type[unsigned(m_bufsize)]; + this->setg(m_g, m_g, m_g); + } + if (mode & std::ios::out) + { + m_p = new char_type[unsigned(m_bufsize)]; + this->setp(m_p, m_p + m_bufsize); + } + } + + const size_type m_bufsize; + largeobjectaccess m_obj; + + /// Get & put buffers. + char_type *m_g, *m_p; +}; + + +/// Input stream that gets its data from a large object. +/** Use this class exactly as you would any other istream to read data from a + * large object. All formatting and streaming operations of @c std::istream are + * supported. What you'll typically want to use, however, is the ilostream + * alias (which defines a basic_ilostream for @c char). This is similar to + * how e.g. @c std::ifstream relates to @c std::basic_ifstream. + * + * Currently only works for <tt><char, std::char_traits<char>></tt>. + */ +template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR>> + class basic_ilostream : + public std::basic_istream<CHAR, TRAITS> +{ + using super = std::basic_istream<CHAR, TRAITS>; + +public: + using char_type = CHAR; + using traits_type = TRAITS; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + + /// Create a basic_ilostream + /** + * @param T Transaction in which this stream is to exist + * @param O Large object to access + * @param BufSize Size of buffer to use internally (optional) + */ + basic_ilostream( //[t57] + dbtransaction &T, + largeobject O, + largeobject::size_type BufSize=512) : + super{nullptr}, + m_buf{T, O, std::ios::in, BufSize} + { super::init(&m_buf); } + + /// Create a basic_ilostream + /** + * @param T Transaction in which this stream is to exist + * @param O Identifier of a large object to access + * @param BufSize Size of buffer to use internally (optional) + */ + basic_ilostream( //[t48] + dbtransaction &T, + oid O, + largeobject::size_type BufSize=512) : + super{nullptr}, + m_buf{T, O, std::ios::in, BufSize} + { super::init(&m_buf); } + +private: + largeobject_streambuf<CHAR,TRAITS> m_buf; +}; + +using ilostream = basic_ilostream<char>; + + +/// Output stream that writes data back to a large object +/** Use this class exactly as you would any other ostream to write data to a + * large object. All formatting and streaming operations of @c std::ostream are + * supported. What you'll typically want to use, however, is the olostream + * alias (which defines a basic_olostream for @c char). This is similar to + * how e.g. @c std::ofstream is related to @c std::basic_ofstream. + * + * Currently only works for <tt><char, std::char_traits<char>></tt>. + */ +template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR>> + class basic_olostream : + public std::basic_ostream<CHAR, TRAITS> +{ + using super = std::basic_ostream<CHAR, TRAITS>; +public: + using char_type = CHAR; + using traits_type = TRAITS; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + + /// Create a basic_olostream + /** + * @param T transaction in which this stream is to exist + * @param O a large object to access + * @param BufSize size of buffer to use internally (optional) + */ + basic_olostream( //[t48] + dbtransaction &T, + largeobject O, + largeobject::size_type BufSize=512) : + super{nullptr}, + m_buf{T, O, std::ios::out, BufSize} + { super::init(&m_buf); } + + /// Create a basic_olostream + /** + * @param T transaction in which this stream is to exist + * @param O a large object to access + * @param BufSize size of buffer to use internally (optional) + */ + basic_olostream( //[t57] + dbtransaction &T, + oid O, + largeobject::size_type BufSize=512) : + super{nullptr}, + m_buf{T, O, std::ios::out, BufSize} + { super::init(&m_buf); } + + ~basic_olostream() + { + try + { + m_buf.pubsync(); m_buf.pubsync(); + } + catch (const std::exception &e) + { + m_buf.process_notice(e.what()); + } + } + +private: + largeobject_streambuf<CHAR,TRAITS> m_buf; +}; + +using olostream = basic_olostream<char>; + + +/// Stream that reads and writes a large object +/** Use this class exactly as you would a std::iostream to read data from, or + * write data to a large object. All formatting and streaming operations of + * @c std::iostream are supported. What you'll typically want to use, however, + * is the lostream alias (which defines a basic_lostream for @c char). This + * is similar to how e.g. @c std::fstream is related to @c std::basic_fstream. + * + * Currently only works for <tt><char, std::char_traits<char>></tt>. + */ +template<typename CHAR=char, typename TRAITS=std::char_traits<CHAR>> + class basic_lostream : + public std::basic_iostream<CHAR, TRAITS> +{ + using super = std::basic_iostream<CHAR, TRAITS>; + +public: + using char_type = CHAR; + using traits_type = TRAITS; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + + /// Create a basic_lostream + /** + * @param T Transaction in which this stream is to exist + * @param O Large object to access + * @param BufSize Size of buffer to use internally (optional) + */ + basic_lostream( //[t59] + dbtransaction &T, + largeobject O, + largeobject::size_type BufSize=512) : + super{nullptr}, + m_buf{T, O, std::ios::in | std::ios::out, BufSize} + { super::init(&m_buf); } + + /// Create a basic_lostream + /** + * @param T Transaction in which this stream is to exist + * @param O Large object to access + * @param BufSize Size of buffer to use internally (optional) + */ + basic_lostream( //[t59] + dbtransaction &T, + oid O, + largeobject::size_type BufSize=512) : + super{nullptr}, + m_buf{T, O, std::ios::in | std::ios::out, BufSize} + { super::init(&m_buf); } + + ~basic_lostream() + { + try + { + m_buf.pubsync(); m_buf.pubsync(); + } + catch (const std::exception &e) + { + m_buf.process_notice(e.what()); + } + } + +private: + largeobject_streambuf<CHAR,TRAITS> m_buf; +}; + +using lostream = basic_lostream<char>; + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/nontransaction b/contrib/libs/libpqxx/include/pqxx/nontransaction new file mode 100644 index 0000000000..e62ebdbc0b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/nontransaction @@ -0,0 +1,6 @@ +/** pqxx::nontransaction class. + * + * pqxx::nontransaction provides nontransactional database access. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/nontransaction.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/nontransaction.hxx b/contrib/libs/libpqxx/include/pqxx/nontransaction.hxx new file mode 100644 index 0000000000..40fb1331cf --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/nontransaction.hxx @@ -0,0 +1,80 @@ +/** Definition of the pqxx::nontransaction class. + * + * pqxx::nontransaction provides nontransactional database access + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/nontransaction instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_NONTRANSACTION +#define PQXX_H_NONTRANSACTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/connection_base.hxx" +#include "pqxx/result.hxx" +#include "pqxx/transaction_base.hxx" + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ + +/// Simple "transaction" class offering no transactional integrity. +/** + * @ingroup transaction + * + * nontransaction, like transaction or any other transaction_base-derived class, + * provides access to a database through a connection. Unlike its siblings, + * however, nontransaction does not maintain any kind of transactional + * integrity. This may be useful eg. for read-only access to the database that + * does not require a consistent, atomic view on its data; or for operations + * that are not allowed within a backend transaction, such as creating tables. + * + * For queries that update the database, however, a real transaction is likely + * to be faster unless the transaction consists of only a single record update. + * + * Also, you can keep a nontransaction open for as long as you like. Actual + * back-end transactions are limited in lifespan, and will sometimes fail just + * because they took too long to execute or were left idle for too long. This + * will not happen with a nontransaction (although the connection may still time + * out, e.g. when the network is unavailable for a very long time). + * + * Any query executed in a nontransaction is committed immediately, and neither + * commit() nor abort() has any effect. + * + * Database features that require a backend transaction, such as cursors or + * large objects, will not work in a nontransaction. + */ +class PQXX_LIBEXPORT nontransaction : public transaction_base +{ +public: + /// Constructor. + /** Create a "dummy" transaction. + * @param C Connection that this "transaction" will operate on. + * @param Name Optional name for the transaction, beginning with a letter + * and containing only letters and digits. + */ + explicit nontransaction( //[t14] + connection_base &C, + const std::string &Name=std::string{}) : + namedclass{"nontransaction", Name}, transaction_base{C} { Begin(); } + + virtual ~nontransaction(); //[t14] + +private: + virtual void do_begin() override {} //[t14] + virtual result do_exec(const char C[]) override; //[t14] + virtual void do_commit() override {} //[t14] + virtual void do_abort() override {} //[t14] +}; + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/notification b/contrib/libs/libpqxx/include/pqxx/notification new file mode 100644 index 0000000000..025b220baf --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/notification @@ -0,0 +1,6 @@ +/** pqxx::notification_receiver functor interface. + * + * pqxx::notification_receiver handles incoming notifications. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/notification.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/notification.hxx b/contrib/libs/libpqxx/include/pqxx/notification.hxx new file mode 100644 index 0000000000..77e818e009 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/notification.hxx @@ -0,0 +1,91 @@ +/** Definition of the pqxx::notification_receiver functor interface. + * + * pqxx::notification_receiver handles incoming notifications. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/notification instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_NOTIFICATION +#define PQXX_H_NOTIFICATION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <string> + +#include "pqxx/types.hxx" + + +namespace pqxx +{ +/// "Observer" base class for notifications. +/** @addtogroup notification Notifications and Receivers + * + * To listen on a notification issued using the NOTIFY command, derive your own + * class from notification_receiver and define its function-call operator to + * perform whatever action you wish to take when the given notification arrives. + * Then create an object of that class and pass it to your connection. DO NOT + * use raw SQL to listen for notifications, or your attempts to listen won't be + * resumed when a connection fails--and you'll have no way to notice. + * + * Notifications never arrive inside a transaction, not even in a + * nontransaction. Therefore, you are free to open a transaction of your own + * inside your receiver's function invocation operator. + * + * Notifications you are listening for may arrive anywhere within libpqxx code, + * but be aware that @b PostgreSQL @b defers @b notifications @b occurring + * @b inside @b transactions. (This was done for excellent reasons; just think + * about what happens if the transaction where you happen to handle an incoming + * notification is later rolled back for other reasons). So if you're keeping a + * transaction open, don't expect any of your receivers on the same connection + * to be notified. + * + * (For very similar reasons, outgoing notifications are also not sent until the + * transaction that sends them commits.) + * + * Multiple receivers on the same connection may listen on a notification of the + * same name. An incoming notification is processed by invoking all receivers + * (zero or more) of the same name. + */ +class PQXX_LIBEXPORT PQXX_NOVTABLE notification_receiver +{ +public: + /// Register the receiver with a connection. + /** + * @param c Connnection to operate on. + * @param channel Name of the notification to listen for. + */ + notification_receiver(connection_base &c, const std::string &channel); + notification_receiver(const notification_receiver &) =delete; + notification_receiver &operator=(const notification_receiver &) =delete; + virtual ~notification_receiver(); + + /// The channel that this receiver listens on. + const std::string &channel() const { return m_channel; } + + /// Overridable: action to invoke when notification arrives. + /** + * @param payload On PostgreSQL 9.0 or later, an optional string that may have + * been passed to the NOTIFY command. + * @param backend_pid Process ID of the database backend process that served + * our connection when the notification arrived. The actual process ID behind + * the connection may have changed by the time this method is called. + */ + virtual void operator()(const std::string &payload, int backend_pid) =0; + +protected: + connection_base &conn() const noexcept { return m_conn; } + +private: + connection_base &m_conn; + std::string m_channel; +}; +} + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/pipeline b/contrib/libs/libpqxx/include/pqxx/pipeline new file mode 100644 index 0000000000..6029f14622 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/pipeline @@ -0,0 +1,6 @@ +/** pqxx::pipeline class. + * + * Throughput-optimized query interface. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/pipeline.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/pipeline.hxx b/contrib/libs/libpqxx/include/pqxx/pipeline.hxx new file mode 100644 index 0000000000..25a5dea6a6 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/pipeline.hxx @@ -0,0 +1,210 @@ +/** Definition of the pqxx::pipeline class. + * + * Throughput-optimized query manager + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/pipeline instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_PIPELINE +#define PQXX_H_PIPELINE + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <limits> +#include <map> +#include <string> + +#include "pqxx/transaction_base.hxx" + + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ + +/// Processes several queries in FIFO manner, optimized for high throughput +/** Use a pipeline if you want to execute queries without always sitting still + * while they execute. Result retrieval is decoupled from execution request; + * queries "go in at the front" and results "come out the back." Actually + * results may be retrieved in any order, if you want. + * + * Feel free to pump as many queries into the pipeline as possible, even if they + * were generated after looking at a result from the same pipeline. To get the + * best possible throughput, try to make insertion of queries run as far ahead + * of results retrieval as possible; issue each query as early as possible and + * retrieve their results as late as possible, so the pipeline has as many + * ongoing queries as possible at any given time. In other words, keep it busy! + * + * One warning: if any of the queries you insert leads to a syntactic error, the + * error may be returned as if it were generated by an older query. Future + * versions may try to work around this if working in a nontransaction. + */ +class PQXX_LIBEXPORT pipeline : public internal::transactionfocus +{ +public: + using query_id = long; + + pipeline(const pipeline &) =delete; + pipeline &operator=(const pipeline &) =delete; + + explicit pipeline( //[t69] + transaction_base &, + const std::string &Name=std::string{}); + + ~pipeline() noexcept; + + /// Add query to the pipeline. + /** Queries are accumulated in the pipeline and sent to the backend in a + * concatenated format, separated by semicolons. The queries you insert must + * not use this construct themselves, or the pipeline will get hopelessly + * confused! + * @return Identifier for this query, unique only within this pipeline + */ + query_id insert(const std::string &); //[t69] + + /// Wait for all ongoing or pending operations to complete. + /** Detaches from the transaction when done. */ + void complete(); //[t71] + + /// Forget all ongoing or pending operations and retrieved results + /** Queries already sent to the backend may still be completed, depending + * on implementation and timing. + * + * Any error state (unless caused by an internal error) will also be cleared. + * This is mostly useful in a nontransaction, since a backend transaction is + * aborted automatically when an error occurs. + * + * Detaches from the transaction when done. + */ + void flush(); //[t70] + + /// Cancel ongoing query, if any. + /** May cancel any or all of the queries that have been inserted at this point + * whose results have not yet been retrieved. If the pipeline lives in a + * backend transaction, that transaction may be left in a nonfunctional state + * in which it can only be aborted. + * + * Therefore, either use this function in a nontransaction, or abort the + * transaction after calling it. + */ + void cancel(); + + /// Is result for given query available? + bool is_finished(query_id) const; //[t71] + + /// Retrieve result for given query. + /** If the query failed for whatever reason, this will throw an exception. + * The function will block if the query has not finished yet. + * @warning If results are retrieved out-of-order, i.e. in a different order + * than the one in which their queries were inserted, errors may "propagate" + * to subsequent queries. + */ + result retrieve(query_id qid) //[t71] + { return retrieve(m_queries.find(qid)).second; } + + /// Retrieve oldest unretrieved result (possibly wait for one) + /** @return The query's identifier and its result set */ + std::pair<query_id, result> retrieve(); //[t69] + + bool empty() const noexcept { return m_queries.empty(); } //[t69] + + /// Set maximum number of queries to retain before issuing them to the backend + /** The pipeline will perform better if multiple queries are issued at once, + * but retaining queries until the results are needed (as opposed to issuing + * them to the backend immediately) may negate any performance benefits the + * pipeline can offer. + * + * Recommended practice is to set this value no higher than the number of + * queries you intend to insert at a time. + * @param retain_max A nonnegative "retention capacity;" passing zero will + * cause queries to be issued immediately + * @return Old retention capacity + */ + int retain(int retain_max=2); //[t70] + + + /// Resume retained query emission (harmless when not needed) + void resume(); //[t70] + +private: + class PQXX_PRIVATE Query + { + public: + explicit Query(const std::string &q) : m_query{q}, m_res{} {} + + const result &get_result() const noexcept { return m_res; } + void set_result(const result &r) noexcept { m_res = r; } + const std::string &get_query() const noexcept { return m_query; } + + private: + std::string m_query; + result m_res; + }; + + using QueryMap = std::map<query_id,Query>; + + void attach(); + void detach(); + + /// Upper bound to query id's + static constexpr query_id qid_limit() noexcept + { + // Parenthesise this to work around an eternal Visual C++ problem: + // Without the extra parentheses, unless NOMINMAX is defined, the + // preprocessor will mistake this "max" for its annoying built-in macro + // of the same name. + return (std::numeric_limits<query_id>::max)(); + } + + /// Create new query_id + PQXX_PRIVATE query_id generate_id(); + + bool have_pending() const noexcept + { return m_issuedrange.second != m_issuedrange.first; } + + PQXX_PRIVATE void issue(); + + /// The given query failed; never issue anything beyond that + void set_error_at(query_id qid) noexcept + { if (qid < m_error) m_error = qid; } + + /// Throw pqxx::internal_error. + [[noreturn]] PQXX_PRIVATE void internal_error(const std::string &err); + + PQXX_PRIVATE bool obtain_result(bool expect_none=false); + + PQXX_PRIVATE void obtain_dummy(); + PQXX_PRIVATE void get_further_available_results(); + PQXX_PRIVATE void check_end_results(); + + /// Receive any results that happen to be available; it's not urgent + PQXX_PRIVATE void receive_if_available(); + + /// Receive results, up to stop if possible + PQXX_PRIVATE void receive(pipeline::QueryMap::const_iterator stop); + std::pair<pipeline::query_id, result> + retrieve(pipeline::QueryMap::iterator); + + QueryMap m_queries; + std::pair<QueryMap::iterator,QueryMap::iterator> m_issuedrange; + int m_retain = 0; + int m_num_waiting = 0; + query_id m_q_id = 0; + + /// Is there a "dummy query" pending? + bool m_dummy_pending = false; + + /// Point at which an error occurred; no results beyond it will be available + query_id m_error = qid_limit(); +}; + +} // namespace + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/pqxx b/contrib/libs/libpqxx/include/pqxx/pqxx new file mode 100644 index 0000000000..9cc33ad121 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/pqxx @@ -0,0 +1,19 @@ +/// Convenience header: include all libpqxx definitions. +#include "pqxx/array" +#include "pqxx/binarystring" +#include "pqxx/connection" +#include "pqxx/cursor" +#include "pqxx/errorhandler" +#include "pqxx/except" +#include "pqxx/largeobject" +#include "pqxx/nontransaction" +#include "pqxx/notification" +#include "pqxx/pipeline" +#include "pqxx/prepared_statement" +#include "pqxx/result" +#include "pqxx/robusttransaction" +#include "pqxx/stream_from" +#include "pqxx/stream_to" +#include "pqxx/subtransaction" +#include "pqxx/transaction" +#include "pqxx/transactor" diff --git a/contrib/libs/libpqxx/include/pqxx/prepared_statement b/contrib/libs/libpqxx/include/pqxx/prepared_statement new file mode 100644 index 0000000000..20c645f301 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/prepared_statement @@ -0,0 +1,6 @@ +/** Helper classes for defining and executing prepared statements. + * + * See the connection_base hierarchy for more about prepared statements + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/prepared_statement.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/prepared_statement.hxx b/contrib/libs/libpqxx/include/pqxx/prepared_statement.hxx new file mode 100644 index 0000000000..604d40665a --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/prepared_statement.hxx @@ -0,0 +1,177 @@ +/** 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. + */ +#ifndef PQXX_H_PREPARED_STATEMENT +#define PQXX_H_PREPARED_STATEMENT + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/types.hxx" +#include "pqxx/internal/statement_parameters.hxx" + + + +namespace pqxx +{ +/// Dedicated namespace for helper types related to prepared statements. +namespace prepare +{ +/// Pass a number of statement parameters only known at runtime. +/** When you call any of the @c exec_params functions, the number of arguments + * is normally known at compile time. This helper function supports the case + * where it is not. + * + * Use this function to pass a variable number of parameters, based on a + * sequence ranging from @c begin to @c end exclusively. + * + * The technique combines with the regular static parameters. You can use it + * to insert dynamic parameter lists in any place, or places, among the call's + * parameters. You can even insert multiple dynamic sequences. + * + * @param begin A pointer or iterator for iterating parameters. + * @param end A pointer or iterator for iterating parameters. + * @return An object representing the parameters. + */ +template<typename IT> inline pqxx::internal::dynamic_params<IT> +make_dynamic_params(IT begin, IT end) +{ + return pqxx::internal::dynamic_params<IT>(begin, end); +} + + +/// Pass a number of statement parameters only known at runtime. +/** When you call any of the @c exec_params functions, the number of arguments + * is normally known at compile time. This helper function supports the case + * where it is not. + * + * Use this function to pass a variable number of parameters, based on a + * container of parameter values. + * + * The technique combines with the regular static parameters. You can use it + * to insert dynamic parameter lists in any place, or places, among the call's + * parameters. You can even insert multiple dynamic containers. + * + * @param container A container of parameter values. + * @return An object representing the parameters. + */ +template<typename C> +inline pqxx::internal::dynamic_params<typename C::const_iterator> +make_dynamic_params(const C &container) +{ + return pqxx::internal::dynamic_params<typename C::const_iterator>(container); +} +} // namespace prepare +} // namespace pqxx + +namespace pqxx +{ +namespace prepare +{ +/// Helper class for passing parameters to, and executing, prepared statements +/** @deprecated As of 6.0, use @c transaction_base::exec_prepared and friends. + */ +class PQXX_LIBEXPORT invocation : internal::statement_parameters +{ +public: + PQXX_DEPRECATED invocation(transaction_base &, const std::string &statement); + invocation &operator=(const invocation &) =delete; + + /// Execute! + result exec() const; + + /// Execute and return result in binary format + result exec_binary() const; + + /// Has a statement of this name been defined? + bool exists() const; + + /// Pass null parameter. + invocation &operator()() { add_param(); return *this; } + + /// Pass parameter value. + /** + * @param v parameter value; will be represented as a string internally. + */ + template<typename T> invocation &operator()(const T &v) + { add_param(v, true); return *this; } + + /// Pass binary parameter value for a BYTEA field. + /** + * @param v binary string; will be passed on directly in binary form. + */ + invocation &operator()(const binarystring &v) + { add_binary_param(v, true); return *this; } + + /// Pass parameter value. + /** + * @param v parameter value (will be represented as a string internally). + * @param nonnull replaces value with null if set to false. + */ + template<typename T> invocation &operator()(const T &v, bool nonnull) + { add_param(v, nonnull); return *this; } + + /// Pass binary parameter value for a BYTEA field. + /** + * @param v binary string; will be passed on directly in binary form. + * @param nonnull determines whether to pass a real value, or nullptr. + */ + invocation &operator()(const binarystring &v, bool nonnull) + { add_binary_param(v, nonnull); return *this; } + + /// Pass C-style parameter string, or null if pointer is null. + /** + * This version is for passing C-style strings; it's a template, so any + * pointer type that @c to_string accepts will do. + * + * @param v parameter value (will be represented as a C++ string internally) + * @param nonnull replaces value with null if set to @c false + */ + template<typename T> invocation &operator()(T *v, bool nonnull=true) + { add_param(v, nonnull); return *this; } + + /// Pass C-style string parameter, or null if pointer is null. + /** This duplicates the pointer-to-template-argument-type version of the + * operator, but helps compilers with less advanced template implementations + * disambiguate calls where C-style strings are passed. + */ + invocation &operator()(const char *v, bool nonnull=true) + { add_param(v, nonnull); return *this; } + +private: + transaction_base &m_home; + const std::string m_statement; + + invocation &setparam(const std::string &, bool nonnull); + + result internal_exec(result_format format) const; +}; + + +namespace internal +{ +/// Internal representation of a prepared statement definition. +struct PQXX_LIBEXPORT prepared_def +{ + /// Text of prepared query. + std::string definition; + /// Has this prepared statement been prepared in the current session? + bool registered = false; + + prepared_def() =default; + explicit prepared_def(const std::string &); +}; + +} // namespace pqxx::prepare::internal +} // namespace pqxx::prepare +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/result b/contrib/libs/libpqxx/include/pqxx/result new file mode 100644 index 0000000000..d61e588681 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/result @@ -0,0 +1,11 @@ +/** pqxx::result class and support classes. + * + * pqxx::result represents the set of result rows from a database query. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/result.hxx" + +// Now include some types which depend on result, but which the user will +// expect to see defined after including this header. +#include "pqxx/result_iterator.hxx" +#include "pqxx/field.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/result.hxx b/contrib/libs/libpqxx/include/pqxx/result.hxx new file mode 100644 index 0000000000..b1f5ce3f4c --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/result.hxx @@ -0,0 +1,249 @@ +/** Definitions for the pqxx::result class and support classes. + * + * pqxx::result represents the set of result rows from a database query. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_RESULT +#define PQXX_H_RESULT + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include <ios> +#include <memory> +#include <stdexcept> + +#include "pqxx/except.hxx" +#include "pqxx/types.hxx" +#include "pqxx/util.hxx" + +#include "pqxx/internal/encodings.hxx" + + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ +namespace internal +{ +PQXX_LIBEXPORT void clear_result(const pq::PGresult *); + +namespace gate +{ +class result_connection; +class result_creation; +class result_row; +class result_sql_cursor; +} // namespace internal::gate +} // namespace internal + + +enum class result_format +{ + text = 0, + binary = 1 +}; + + +/// Result set containing data returned by a query or command. +/** This behaves as a container (as defined by the C++ standard library) and + * provides random access const iterators to iterate over its rows. A row + * can also be accessed by indexing a result R by the row's zero-based + * number: + * + * @code + * for (result::size_type i=0; i < R.size(); ++i) Process(R[i]); + * @endcode + * + * Result sets in libpqxx are lightweight, reference-counted wrapper objects + * which are relatively small and cheap to copy. Think of a result object as + * a "smart pointer" to an underlying result set. + * + * @warning The result set that a result object points to is not thread-safe. + * If you copy a result object, it still refers to the same underlying result + * set. So never copy, destroy, query, or otherwise access a result while + * another thread may be copying, destroying, querying, or otherwise accessing + * the same result set--even if it is doing so through a different result + * object! + */ +class PQXX_LIBEXPORT result +{ +public: + using size_type = result_size_type; + using difference_type = result_difference_type; + using reference = row; + using const_iterator = const_result_iterator; + using pointer = const_iterator; + using iterator = const_iterator; + using const_reverse_iterator = const_reverse_result_iterator; + using reverse_iterator = const_reverse_iterator; + + result() noexcept : //[t03] + m_data(make_data_pointer()), + m_query(), + m_encoding(internal::encoding_group::MONOBYTE) + {} + result(const result &rhs) noexcept =default; //[t01] + + result &operator=(const result &rhs) noexcept =default; //[t10] + + /** + * @name Comparisons + */ + //@{ + bool operator==(const result &) const noexcept; //[t70] + bool operator!=(const result &rhs) const noexcept //[t70] + { return not operator==(rhs); } + //@} + + const_reverse_iterator rbegin() const; //[t75] + const_reverse_iterator crbegin() const; + const_reverse_iterator rend() const; //[t75] + const_reverse_iterator crend() const; + + const_iterator begin() const noexcept; //[t01] + const_iterator cbegin() const noexcept; + inline const_iterator end() const noexcept; //[t01] + inline const_iterator cend() const noexcept; + + reference front() const noexcept; //[t74] + reference back() const noexcept; //[t75] + + PQXX_PURE size_type size() const noexcept; //[t02] + PQXX_PURE bool empty() const noexcept; //[t11] + size_type capacity() const noexcept { return size(); } //[t20] + + void swap(result &) noexcept; //[t77] + + const row operator[](size_type i) const noexcept; //[t02] + const row at(size_type) const; //[t10] + + void clear() noexcept { m_data.reset(); m_query = nullptr; } //[t20] + + /** + * @name Column information + */ + //@{ + /// Number of columns in result. + PQXX_PURE row_size_type columns() const noexcept; //[t11] + + /// Number of given column (throws exception if it doesn't exist). + row_size_type column_number(const char ColName[]) const; //[t11] + + /// Number of given column (throws exception if it doesn't exist). + row_size_type column_number(const std::string &Name) const //[t11] + {return column_number(Name.c_str());} + + /// Name of column with this number (throws exception if it doesn't exist) + const char *column_name(row_size_type Number) const; //[t11] + + /// Type of given column + oid column_type(row_size_type ColNum) const; //[t07] + /// Type of given column + oid column_type(int ColNum) const //[t07] + { return column_type(row_size_type(ColNum)); } + + /// Type of given column + oid column_type(const std::string &ColName) const //[t07] + { return column_type(column_number(ColName)); } + + /// Type of given column + oid column_type(const char ColName[]) const //[t07] + { return column_type(column_number(ColName)); } + + /// What table did this column come from? + oid column_table(row_size_type ColNum) const; //[t02] + + /// What table did this column come from? + oid column_table(int ColNum) const //[t02] + { return column_table(row_size_type(ColNum)); } + + /// What table did this column come from? + oid column_table(const std::string &ColName) const //[t02] + { return column_table(column_number(ColName)); } + + /// What column in its table did this column come from? + row_size_type table_column(row_size_type ColNum) const; //[t93] + + /// What column in its table did this column come from? + row_size_type table_column(int ColNum) const //[t93] + { return table_column(row_size_type(ColNum)); } + + /// What column in its table did this column come from? + row_size_type table_column(const std::string &ColName) const //[t93] + { return table_column(column_number(ColName)); } + //@} + + /// Query that produced this result, if available (empty string otherwise) + PQXX_PURE const std::string &query() const noexcept; //[t70] + + /// If command was @c INSERT of 1 row, return oid of inserted row + /** @return Identifier of inserted row if exactly one row was inserted, or + * oid_none otherwise. + */ + PQXX_PURE oid inserted_oid() const; //[t13] + + /// If command was @c INSERT, @c UPDATE, or @c DELETE: number of affected rows + /** @return Number of affected rows if last command was @c INSERT, @c UPDATE, + * or @c DELETE; zero for all other commands. + */ + PQXX_PURE size_type affected_rows() const; //[t07] + + +private: + using data_pointer = std::shared_ptr<const internal::pq::PGresult>; + + /// Underlying libpq result set. + data_pointer m_data; + + /// Factory for data_pointer. + static data_pointer make_data_pointer( + const internal::pq::PGresult *res=nullptr) + { return data_pointer{res, internal::clear_result}; } + + /// Query string. + std::shared_ptr<std::string> m_query; + + internal::encoding_group m_encoding; + + static const std::string s_empty_string; + + friend class pqxx::field; + PQXX_PURE const char *GetValue(size_type Row, row_size_type Col) const; + PQXX_PURE bool get_is_null(size_type Row, row_size_type Col) const; + PQXX_PURE field_size_type get_length( + size_type, + row_size_type) const noexcept; + + friend class pqxx::internal::gate::result_creation; + result( + internal::pq::PGresult *rhs, + const std::string &Query, + internal::encoding_group enc); + + PQXX_PRIVATE void check_status() const; + + friend class pqxx::internal::gate::result_connection; + friend class pqxx::internal::gate::result_row; + bool operator!() const noexcept { return not m_data.get(); } + operator bool() const noexcept { return m_data.get() != nullptr; } + + [[noreturn]] PQXX_PRIVATE void ThrowSQLError( + const std::string &Err, + const std::string &Query) const; + PQXX_PRIVATE PQXX_PURE int errorposition() const; + PQXX_PRIVATE std::string StatusError() const; + + friend class pqxx::internal::gate::result_sql_cursor; + PQXX_PURE const char *cmd_status() const noexcept; +}; +} // namespace pqxx +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/result_iterator.hxx b/contrib/libs/libpqxx/include/pqxx/result_iterator.hxx new file mode 100644 index 0000000000..b8e54d23ec --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/result_iterator.hxx @@ -0,0 +1,245 @@ +/** Definitions for the pqxx::result class and support classes. + * + * pqxx::result represents the set of result rows from a database query. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_RESULT_ITERATOR +#define PQXX_H_RESULT_ITERATOR + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/row.hxx" + + +/* Result iterator. + * + * Don't include this header from your own application; it is included for you + * by other libpqxx headers. + */ + +namespace pqxx +{ +/// Iterator for rows in a result. Use as result::const_iterator. +/** A result, once obtained, cannot be modified. Therefore there is no + * plain iterator type for result. However its const_iterator type can be + * used to inspect its rows without changing them. + */ +class PQXX_LIBEXPORT const_result_iterator : public row +{ +public: + using iterator_category = std::random_access_iterator_tag; + using value_type = const row; + using pointer = const row *; + using reference = row; + using size_type = result_size_type; + using difference_type = result_difference_type; + + const_result_iterator() noexcept : row{result(), 0} {} + const_result_iterator(const row &t) noexcept : row{t} {} + + /** + * @name Dereferencing operators + */ + //@{ + /** The iterator "points to" its own row, which is also itself. This + * allows a result to be addressed as a two-dimensional container without + * going through the intermediate step of dereferencing the iterator. I + * hope this works out to be similar to C pointer/array semantics in useful + * cases. + * + * IIRC Alex Stepanov, the inventor of the STL, once remarked that having + * this as standard behaviour for pointers would be useful in some + * algorithms. So even if this makes me look foolish, I would seem to be in + * distinguished company. + */ + pointer operator->() const { return this; } //[t12] + reference operator*() const { return row{*this}; } //[t12] + //@} + + /** + * @name Manipulations + */ + //@{ + const_result_iterator operator++(int); //[t12] + const_result_iterator &operator++() { ++m_index; return *this; } //[t01] + const_result_iterator operator--(int); //[t12] + const_result_iterator &operator--() { --m_index; return *this; } //[t12] + + const_result_iterator &operator+=(difference_type i) //[t12] + { m_index += i; return *this; } + const_result_iterator &operator-=(difference_type i) //[t12] + { m_index -= i; return *this; } + //@} + + /** + * @name Comparisons + */ + //@{ + bool operator==(const const_result_iterator &i) const //[t12] + {return m_index==i.m_index;} + bool operator!=(const const_result_iterator &i) const //[t12] + {return m_index!=i.m_index;} + bool operator<(const const_result_iterator &i) const //[t12] + {return m_index<i.m_index;} + bool operator<=(const const_result_iterator &i) const //[t12] + {return m_index<=i.m_index;} + bool operator>(const const_result_iterator &i) const //[t12] + {return m_index>i.m_index;} + bool operator>=(const const_result_iterator &i) const //[t12] + {return m_index>=i.m_index;} + //@} + + /** + * @name Arithmetic operators + */ + //@{ + inline const_result_iterator operator+(difference_type) const; //[t12] + friend const_result_iterator operator+( //[t12] + difference_type, + const_result_iterator); + inline const_result_iterator operator-(difference_type) const; //[t12] + inline difference_type operator-(const_result_iterator) const; //[t12] + //@} + +private: + friend class pqxx::result; + const_result_iterator(const pqxx::result *r, result_size_type i) noexcept : + row{*r, i} {} +}; + + +/// Reverse iterator for result. Use as result::const_reverse_iterator. +class PQXX_LIBEXPORT const_reverse_result_iterator : + private const_result_iterator +{ +public: + using super = const_result_iterator; + using iterator_type = const_result_iterator; + using iterator_type::iterator_category; + using iterator_type::difference_type; + using iterator_type::pointer; + using value_type = iterator_type::value_type; + using reference = iterator_type::reference; + + const_reverse_result_iterator( //[t75] + const const_reverse_result_iterator &rhs) : + const_result_iterator{rhs} {} + explicit const_reverse_result_iterator( //[t75] + const const_result_iterator &rhs) : + const_result_iterator{rhs} { super::operator--(); } + + PQXX_PURE const_result_iterator base() const noexcept; //[t75] + + /** + * @name Dereferencing operators + */ + //@{ + using const_result_iterator::operator->; //[t75] + using const_result_iterator::operator*; //[t75] + //@} + + /** + * @name Manipulations + */ + //@{ + const_reverse_result_iterator &operator=( //[t75] + const const_reverse_result_iterator &r) + { iterator_type::operator=(r); return *this; } + const_reverse_result_iterator &operator++() //[t75] + { iterator_type::operator--(); return *this; } + const_reverse_result_iterator operator++(int); //[t75] + const_reverse_result_iterator &operator--() //[t75] + { iterator_type::operator++(); return *this; } + const_reverse_result_iterator operator--(int); //[t75] + const_reverse_result_iterator &operator+=(difference_type i) //[t75] + { iterator_type::operator-=(i); return *this; } + const_reverse_result_iterator &operator-=(difference_type i) //[t75] + { iterator_type::operator+=(i); return *this; } + //@} + + /** + * @name Arithmetic operators + */ + //@{ + const_reverse_result_iterator operator+(difference_type i) const //[t75] + { return const_reverse_result_iterator(base() - i); } + const_reverse_result_iterator operator-(difference_type i) //[t75] + { return const_reverse_result_iterator(base() + i); } + difference_type operator-( //[t75] + const const_reverse_result_iterator &rhs) const + { return rhs.const_result_iterator::operator-(*this); } + //@} + + /** + * @name Comparisons + */ + //@{ + bool operator==( //[t75] + const const_reverse_result_iterator &rhs) const noexcept + { return iterator_type::operator==(rhs); } + bool operator!=( //[t75] + const const_reverse_result_iterator &rhs) const noexcept + { return not operator==(rhs); } + + bool operator<(const const_reverse_result_iterator &rhs) const //[t75] + { return iterator_type::operator>(rhs); } + bool operator<=(const const_reverse_result_iterator &rhs) const //[t75] + { return iterator_type::operator>=(rhs); } + bool operator>(const const_reverse_result_iterator &rhs) const //[t75] + { return iterator_type::operator<(rhs); } + bool operator>=(const const_reverse_result_iterator &rhs) const //[t75] + { return iterator_type::operator<=(rhs); } + //@} +}; + + +inline const_result_iterator +const_result_iterator::operator+(result::difference_type o) const +{ + return const_result_iterator{ + &m_result, size_type(result::difference_type(m_index) + o)}; +} + +inline const_result_iterator +operator+(result::difference_type o, const_result_iterator i) + { return i + o; } + +inline const_result_iterator +const_result_iterator::operator-(result::difference_type o) const +{ + return const_result_iterator{ + &m_result, + result_size_type(result::difference_type(m_index) - o)}; +} + +inline result::difference_type +const_result_iterator::operator-(const_result_iterator i) const + { return result::difference_type(num() - i.num()); } + +inline const_result_iterator result::end() const noexcept + { return const_result_iterator{this, size()}; } + + +inline const_result_iterator result::cend() const noexcept + { return end(); } + + +inline const_reverse_result_iterator +operator+( + result::difference_type n, + const const_reverse_result_iterator &i) + { return const_reverse_result_iterator{i.base() - n}; } + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/robusttransaction b/contrib/libs/libpqxx/include/pqxx/robusttransaction new file mode 100644 index 0000000000..4d8c99fc33 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/robusttransaction @@ -0,0 +1,6 @@ +/** pqxx::robusttransaction class. + * + * pqxx::robusttransaction is a slower but safer transaction class. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/robusttransaction.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/robusttransaction.hxx b/contrib/libs/libpqxx/include/pqxx/robusttransaction.hxx new file mode 100644 index 0000000000..c4c16323b1 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/robusttransaction.hxx @@ -0,0 +1,168 @@ +/** Definition of the pqxx::robusttransaction class. + * + * pqxx::robusttransaction is a slower but safer transaction class. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/robusttransaction instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ROBUSTTRANSACTION +#define PQXX_H_ROBUSTTRANSACTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/dbtransaction.hxx" + + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ + +namespace internal +{ +/// Helper base class for the @c robusttransaction class template. +class PQXX_LIBEXPORT PQXX_NOVTABLE basic_robusttransaction : + public dbtransaction +{ +public: + /// Isolation level is read_committed by default. + using isolation_tag = isolation_traits<read_committed>; + + virtual ~basic_robusttransaction() =0; //[t16] + +protected: + basic_robusttransaction( + connection_base &C, + const std::string &IsolationLevel, + const std::string &table_name=std::string{}); //[t16] + +private: + using IDType = unsigned long; + IDType m_record_id = 0; + std::string m_xid; + std::string m_log_table; + std::string m_sequence; + int m_backendpid = -1; + + virtual void do_begin() override; //[t18] + virtual void do_commit() override; //[t16] + virtual void do_abort() override; //[t18] + + PQXX_PRIVATE void CreateLogTable(); + PQXX_PRIVATE void CreateTransactionRecord(); + PQXX_PRIVATE std::string sql_delete() const; + PQXX_PRIVATE void DeleteTransactionRecord() noexcept; + PQXX_PRIVATE bool CheckTransactionRecord(); +}; +} // namespace internal + + +/** + * @ingroup transaction + * + * @{ + */ + +/// Slightly slower, better-fortified version of transaction +/** robusttransaction is similar to transaction, but spends more effort (and + * performance!) to deal with the hopefully rare case that the connection to + * the backend is lost just as the current transaction is being committed. In + * this case, there is no way to determine whether the backend managed to + * commit the transaction before noticing the loss of connection. + * + * In such cases, this class tries to reconnect to the database and figure out + * what happened. It will need to store and manage some information (pretty + * much a user-level transaction log) in the back-end for each and every + * transaction just on the off chance that this problem might occur. + * This service level was made optional since you may not want to pay this + * overhead where it is not necessary. Certainly the use of this class makes + * no sense for local connections, or for transactions that read the database + * but never modify it, or for noncritical database manipulations. + * + * Besides being slower, it's theoretically possible that robusttransaction + * actually fails more instead of less often than a normal transaction. This is + * due to the added work and complexity. What robusttransaction tries to + * achieve is to be more deterministic, not more successful per se. + * + * When a user first uses a robusttransaction in a database, the class will + * attempt to create a log table there to keep vital transaction-related state + * information in. This table, located in that same database, will be called + * pqxxlog_*user*, where *user* is the PostgreSQL username for that user. If + * the log table can not be created, the transaction fails immediately. + * + * If the user does not have permission to create the log table, the database + * administrator may create one for him beforehand, and give ownership (or at + * least full insert/update rights) to the user. The table must contain two + * non-unique fields (which will never be null): "name" (of text type, + * @c varchar(256) by default) and "date" (of @c timestamp type). Older + * versions of robusttransaction also added a unique "id" field; this field is + * now obsolete and the log table's implicit oids are used instead. The log + * tables' names may be made configurable in a future version of libpqxx. + * + * The transaction log table contains records describing unfinished + * transactions, i.e. ones that have been started but not, as far as the client + * knows, committed or aborted. This can mean any of the following: + * + * <ol> + * <li> The transaction is in progress. Since backend transactions can't run + * for extended periods of time, this can only be the case if the log record's + * timestamp (compared to the server's clock) is not very old, provided of + * course that the server's system clock hasn't just made a radical jump. + * <li> The client's connection to the server was lost, just when the client was + * committing the transaction, and the client so far has not been able to + * re-establish the connection to verify whether the transaction was actually + * completed or rolled back by the server. This is a serious (and luckily a + * rare) condition and requires manual inspection of the database to determine + * what happened. The robusttransaction will emit clear and specific warnings + * to this effect, and will identify the log record describing the transaction + * in question. + * <li> The transaction was completed (either by commit or by rollback), but the + * client's connection was durably lost just as it tried to clean up the log + * record. Again, robusttransaction will emit a clear and specific warning to + * tell you about this and request that the record be deleted as soon as + * possible. + * <li> The client has gone offline at any time while in one of the preceding + * states. This also requires manual intervention, but the client obviously is + * not able to issue a warning. + * </ol> + * + * It is safe to drop a log table when it is not in use (ie., it is empty or all + * records in it represent states 2-4 above). Each robusttransaction will + * attempt to recreate the table at its next time of use. + */ +template<isolation_level ISOLATIONLEVEL=read_committed> +class robusttransaction : public internal::basic_robusttransaction +{ +public: + using isolation_tag = isolation_traits<ISOLATIONLEVEL>; + + /// Constructor + /** Creates robusttransaction of given name + * @param C Connection that this robusttransaction should live inside. + * @param Name optional human-readable name for this transaction + */ + explicit robusttransaction( + connection_base &C, + const std::string &Name=std::string{}) : + namedclass{fullname("robusttransaction",isolation_tag::name()), Name}, + internal::basic_robusttransaction(C, isolation_tag::name()) + { Begin(); } + + virtual ~robusttransaction() noexcept + { End(); } +}; + +/** + * @} + */ + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/row.hxx b/contrib/libs/libpqxx/include/pqxx/row.hxx new file mode 100644 index 0000000000..2d8543795f --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/row.hxx @@ -0,0 +1,403 @@ +/** Definitions for the pqxx::result class and support classes. + * + * pqxx::result represents the set of result rows from a database query. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_ROW +#define PQXX_H_ROW + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/except.hxx" +#include "pqxx/field.hxx" +#include "pqxx/result.hxx" + + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ +/// Reference to one row in a result. +/** A row represents one row (also called a row) in a query result set. + * It also acts as a container mapping column numbers or names to field + * values (see below): + * + * @code + * cout << row["date"].c_str() << ": " << row["name"].c_str() << endl; + * @endcode + * + * The row itself acts like a (non-modifyable) container, complete with its + * own const_iterator and const_reverse_iterator. + */ +class PQXX_LIBEXPORT row +{ +public: + using size_type = row_size_type; + using difference_type = row_difference_type; + using const_iterator = const_row_iterator; + using iterator = const_iterator; + using reference = field; + using pointer = const_row_iterator; + using const_reverse_iterator = const_reverse_row_iterator; + using reverse_iterator = const_reverse_iterator; + + row() =default; + + /// @deprecated Do not use this constructor. It will become private. + row(result r, size_t i) noexcept; + + ~row() noexcept =default; // Yes Scott Meyers, you're absolutely right[1] + + /** + * @name Comparison + */ + //@{ + PQXX_PURE bool operator==(const row &) const noexcept; //[t75] + bool operator!=(const row &rhs) const noexcept //[t75] + { return not operator==(rhs); } + //@} + + const_iterator begin() const noexcept; //[t82] + const_iterator cbegin() const noexcept; + const_iterator end() const noexcept; //[t82] + const_iterator cend() const noexcept; + + /** + * @name Field access + */ + //@{ + reference front() const noexcept; //[t74] + reference back() const noexcept; //[t75] + + const_reverse_row_iterator rbegin() const; //[t82] + const_reverse_row_iterator crbegin() const; + const_reverse_row_iterator rend() const; //[t82] + const_reverse_row_iterator crend() const; + + reference operator[](size_type) const noexcept; //[t11] + reference operator[](int) const noexcept; //[t02] + /** Address field by name. + * @warning This is much slower than indexing by number, or iterating. + */ + reference operator[](const char[]) const; //[t11] + /** Address field by name. + * @warning This is much slower than indexing by number, or iterating. + */ + reference operator[](const std::string &) const; //[t11] + reference at(size_type) const; //[t11] + reference at(int) const; //[t11] + /** Address field by name. + * @warning This is much slower than indexing by number, or iterating. + */ + reference at(const char[]) const; //[t11] + /** Address field by name. + * @warning This is much slower than indexing by number, or iterating. + */ + reference at(const std::string &) const; //[t11] + //@} + + size_type size() const noexcept //[t11] + { return m_end-m_begin; } + + void swap(row &) noexcept; //[t11] + + /// Row number, assuming this is a real row and not end()/rend(). + size_t rownumber() const noexcept { return size_t(m_index); } //[t11] + + /** + * @name Column information + */ + //@{ + /// Number of given column (throws exception if it doesn't exist) + size_type column_number(const std::string &ColName) const //[t30] + { return column_number(ColName.c_str()); } + + /// Number of given column (throws exception if it doesn't exist) + size_type column_number(const char[]) const; //[t30] + + /// Type of given column + oid column_type(size_type) const; //[t07] + + /// Type of given column + oid column_type(int ColNum) const //[t07] + { return column_type(size_type(ColNum)); } + + /// Type of given column + oid column_type(const std::string &ColName) const //[t07] + { return column_type(column_number(ColName)); } + + /// Type of given column + oid column_type(const char ColName[]) const //[t07] + { return column_type(column_number(ColName)); } + + /// What table did this column come from? + oid column_table(size_type ColNum) const; //[t02] + + /// What table did this column come from? + oid column_table(int ColNum) const //[t02] + { return column_table(size_type(ColNum)); } + /// What table did this column come from? + oid column_table(const std::string &ColName) const //[t02] + { return column_table(column_number(ColName)); } + + /// What column number in its table did this result column come from? + /** A meaningful answer can be given only if the column in question comes + * directly from a column in a table. If the column is computed in any + * other way, a logic_error will be thrown. + * + * @param ColNum a zero-based column number in this result set + * @return a zero-based column number in originating table + */ + size_type table_column(size_type) const; //[t93] + + /// What column number in its table did this result column come from? + size_type table_column(int ColNum) const //[t93] + { return table_column(size_type(ColNum)); } + + /// What column number in its table did this result column come from? + size_type table_column(const std::string &ColName) const //[t93] + { return table_column(column_number(ColName)); } + //@} + + size_t num() const { return rownumber(); } //[t01] + + /** Produce a slice of this row, containing the given range of columns. + * + * The slice runs from the range's starting column to the range's end + * column, exclusive. It looks just like a normal result row, except + * slices can be empty. + * + * @warning Slicing is a relatively new feature, and not all software may be + * prepared to deal with empty slices. If there is any chance that your + * program might be creating empty slices and passing them to code that may + * not be designed with the possibility of empty rows in mind, be sure to + * test for that case. + */ + row slice(size_type Begin, size_type End) const; + + // Is this an empty slice? + PQXX_PURE bool empty() const noexcept; + +protected: + friend class field; + /// Result set of which this is one row. + result m_result; + /// Row number. + /** + * You'd expect this to be a size_t, but due to the way reverse iterators + * are related to regular iterators, it must be allowed to underflow to -1. + */ + long m_index = 0; + /// First column in slice. This row ignores lower-numbered columns. + size_type m_begin = 0; + /// End column in slice. This row only sees lower-numbered columns. + size_type m_end = 0; +}; + + +/// Iterator for fields in a row. Use as row::const_iterator. +class PQXX_LIBEXPORT const_row_iterator : public field +{ +public: + using iterator_category = std::random_access_iterator_tag; + using value_type = const field; + using pointer = const field *; + using size_type = row_size_type; + using difference_type = row_difference_type; + using reference = field; + + const_row_iterator(const row &T, row_size_type C) noexcept : //[t82] + field{T, C} {} + const_row_iterator(const field &F) noexcept : field{F} {} //[t82] + + /** + * @name Dereferencing operators + */ + //@{ + pointer operator->() const { return this; } //[t82] + reference operator*() const { return field{*this}; } //[t82] + //@} + + /** + * @name Manipulations + */ + //@{ + const_row_iterator operator++(int); //[t82] + const_row_iterator &operator++() { ++m_col; return *this; } //[t82] + const_row_iterator operator--(int); //[t82] + const_row_iterator &operator--() { --m_col; return *this; } //[t82] + + const_row_iterator &operator+=(difference_type i) //[t82] + { m_col = size_type(difference_type(m_col) + i); return *this; } + const_row_iterator &operator-=(difference_type i) //[t82] + { m_col = size_type(difference_type(m_col) - i); return *this; } + //@} + + /** + * @name Comparisons + */ + //@{ + bool operator==(const const_row_iterator &i) const //[t82] + {return col()==i.col();} + bool operator!=(const const_row_iterator &i) const //[t82] + {return col()!=i.col();} + bool operator<(const const_row_iterator &i) const //[t82] + {return col()<i.col();} + bool operator<=(const const_row_iterator &i) const //[t82] + {return col()<=i.col();} + bool operator>(const const_row_iterator &i) const //[t82] + {return col()>i.col();} + bool operator>=(const const_row_iterator &i) const //[t82] + {return col()>=i.col();} + //@} + + /** + * @name Arithmetic operators + */ + //@{ + inline const_row_iterator operator+(difference_type) const; //[t82] + + friend const_row_iterator operator+( //[t82] + difference_type, + const_row_iterator); + + inline const_row_iterator operator-(difference_type) const; //[t82] + inline difference_type operator-(const_row_iterator) const; //[t82] + //@} +}; + + +/// Reverse iterator for a row. Use as row::const_reverse_iterator. +class PQXX_LIBEXPORT const_reverse_row_iterator : private const_row_iterator +{ +public: + using super = const_row_iterator; + using iterator_type = const_row_iterator; + using iterator_type::iterator_category; + using iterator_type::difference_type; + using iterator_type::pointer; + using value_type = iterator_type::value_type; + using reference = iterator_type::reference; + + const_reverse_row_iterator(const const_reverse_row_iterator &r) : //[t82] + const_row_iterator{r} {} + explicit + const_reverse_row_iterator(const super &rhs) noexcept : //[t82] + const_row_iterator{rhs} { super::operator--(); } + + PQXX_PURE iterator_type base() const noexcept; //[t82] + + /** + * @name Dereferencing operators + */ + //@{ + using iterator_type::operator->; //[t82] + using iterator_type::operator*; //[t82] + //@} + + /** + * @name Manipulations + */ + //@{ + const_reverse_row_iterator & + operator=(const const_reverse_row_iterator &r) //[t82] + { iterator_type::operator=(r); return *this; } + const_reverse_row_iterator operator++() //[t82] + { iterator_type::operator--(); return *this; } + const_reverse_row_iterator operator++(int); //[t82] + const_reverse_row_iterator &operator--() //[t82] + { iterator_type::operator++(); return *this; } + const_reverse_row_iterator operator--(int); //[t82] + const_reverse_row_iterator &operator+=(difference_type i) //[t82] + { iterator_type::operator-=(i); return *this; } + const_reverse_row_iterator &operator-=(difference_type i) //[t82] + { iterator_type::operator+=(i); return *this; } + //@} + + /** + * @name Arithmetic operators + */ + //@{ + const_reverse_row_iterator operator+(difference_type i) const //[t82] + { return const_reverse_row_iterator{base()-i}; } + const_reverse_row_iterator operator-(difference_type i) //[t82] + { return const_reverse_row_iterator{base()+i}; } + difference_type + operator-(const const_reverse_row_iterator &rhs) const //[t82] + { return rhs.const_row_iterator::operator-(*this); } + //@} + + /** + * @name Comparisons + */ + //@{ + bool operator==(const const_reverse_row_iterator &rhs) const noexcept //[t82] + { return iterator_type::operator==(rhs); } + bool operator!=(const const_reverse_row_iterator &rhs) const noexcept //[t82] + { return !operator==(rhs); } + + bool operator<(const const_reverse_row_iterator &rhs) const //[t82] + { return iterator_type::operator>(rhs); } + bool operator<=(const const_reverse_row_iterator &rhs) const //[t82] + { return iterator_type::operator>=(rhs); } + bool operator>(const const_reverse_row_iterator &rhs) const //[t82] + { return iterator_type::operator<(rhs); } + bool operator>=(const const_reverse_row_iterator &rhs) const //[t82] + { return iterator_type::operator<=(rhs); } + //@} +}; + + +inline const_row_iterator +const_row_iterator::operator+(difference_type o) const +{ + return const_row_iterator{ + row(home(), idx()), + size_type(difference_type(col()) + o)}; +} + +inline const_row_iterator +operator+(const_row_iterator::difference_type o, const_row_iterator i) + { return i + o; } + +inline const_row_iterator +const_row_iterator::operator-(difference_type o) const +{ + return const_row_iterator{ + row(home(), idx()), + size_type(difference_type(col()) - o)}; +} + +inline const_row_iterator::difference_type +const_row_iterator::operator-(const_row_iterator i) const + { return difference_type(num() - i.num()); } + + +} // namespace pqxx + + +/* +[1] Scott Meyers, in one of his essential books, "Effective C++" and "More +Effective C++", points out that it is good style to have any class containing +a member of pointer type define a destructor--just to show that it knows what +it is doing with the pointer. This helps prevent nasty memory leak / double +deletion bugs typically resulting from programmers' omission to deal with such +issues in their destructors. + +The @c -Weffc++ option in gcc generates warnings for noncompliance with Scott's +style guidelines, and hence necessitates the definition of this destructor, +trivial as it may be. +*/ + + +#include "pqxx/compiler-internal-post.hxx" + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/strconv b/contrib/libs/libpqxx/include/pqxx/strconv new file mode 100644 index 0000000000..b70bf39bf4 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/strconv @@ -0,0 +1,4 @@ +/** String conversion definitions. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/strconv.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/strconv.hxx b/contrib/libs/libpqxx/include/pqxx/strconv.hxx new file mode 100644 index 0000000000..0cb120d876 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/strconv.hxx @@ -0,0 +1,341 @@ +/** String conversion definitions. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_STRINGCONV +#define PQXX_H_STRINGCONV + +#include "pqxx/compiler-public.hxx" + +#include <limits> +#include <sstream> +#include <stdexcept> + + +namespace pqxx +{ + +/** + * @defgroup stringconversion String conversion + * + * The PostgreSQL server accepts and represents data in string form. It has + * its own formats for various data types. The string conversions define how + * various C++ types translate to and from their respective PostgreSQL text + * representations. + * + * Each conversion is defined by a specialisation of the @c string_traits + * template. This template implements some basic functions to support the + * conversion, ideally in both directions. + * + * If you need to convert a type which is not supported out of the box, define + * your own @c string_traits specialisation for that type, similar to the ones + * defined here. Any conversion code which "sees" your specialisation will now + * support your conversion. In particular, you'll be able to read result + * fields into a variable of the new type. + * + * There is a macro to help you define conversions for individual enumeration + * types. The conversion will represent enumeration values as numeric strings. + */ +//@{ + +/// Traits class for use in string conversions +/** Specialize this template for a type that you wish to add to_string and + * from_string support for. + */ +template<typename T, typename = void> struct string_traits; + +namespace internal +{ +/// Throw exception for attempt to convert null to given type. +[[noreturn]] PQXX_LIBEXPORT void throw_null_conversion( + const std::string &type); + +/// Give a human-readable name for a type, at compile time. +/** Each instantiation contains a static member called @c value which is the + * type's name, as a string. + * + * This template should not be around for long. C++14's variable templates + * make it easier (eliminating the cumbersome struct) and C++20's introspection + * should obviate it completely. + */ +template<typename TYPE> struct type_name; +#define PQXX_DECLARE_TYPE_NAME(TYPE) \ + template<> struct type_name<TYPE> \ + { static constexpr const char *value = #TYPE; } + +PQXX_DECLARE_TYPE_NAME(bool); +PQXX_DECLARE_TYPE_NAME(short); +PQXX_DECLARE_TYPE_NAME(unsigned short); +PQXX_DECLARE_TYPE_NAME(int); +PQXX_DECLARE_TYPE_NAME(unsigned int); +PQXX_DECLARE_TYPE_NAME(long); +PQXX_DECLARE_TYPE_NAME(unsigned long); +PQXX_DECLARE_TYPE_NAME(long long); +PQXX_DECLARE_TYPE_NAME(unsigned long long); +PQXX_DECLARE_TYPE_NAME(float); +PQXX_DECLARE_TYPE_NAME(double); +PQXX_DECLARE_TYPE_NAME(long double); +PQXX_DECLARE_TYPE_NAME(char *); +PQXX_DECLARE_TYPE_NAME(const char *); +PQXX_DECLARE_TYPE_NAME(std::string); +PQXX_DECLARE_TYPE_NAME(const std::string); +PQXX_DECLARE_TYPE_NAME(std::stringstream); +#undef PQXX_DECLARE_TYPE_NAME + +template<size_t N> struct type_name<char[N]> +{ static constexpr const char *value = "char[]"; }; + + +/// Helper: string traits implementation for built-in types. +/** These types all look much alike, so they can share much of their traits + * classes (though templatised, of course). + * + * The actual `to_string` and `from_string` are implemented in the library, + * but the rest is defined inline. + */ +template<typename TYPE> struct PQXX_LIBEXPORT builtin_traits +{ + static constexpr const char *name() noexcept + { return internal::type_name<TYPE>::value; } + static constexpr bool has_null() noexcept { return false; } + static bool is_null(TYPE) { return false; } + [[noreturn]] static TYPE null() { throw_null_conversion(name()); } + static void from_string(const char Str[], TYPE &Obj); + static std::string to_string(TYPE Obj); +}; +} // namespace pqxx::internal + + +/// Helper: declare a string_traits specialisation for a builtin type. +#define PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(TYPE) \ + template<> struct PQXX_LIBEXPORT string_traits<TYPE> : \ + internal::builtin_traits<TYPE> {}; + +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(bool) + +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(short) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned short) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(int) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned int) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(long) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned long) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(long long) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned long long) + +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(float) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(double) +PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(long double) + +#undef PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION + + +/// Helper class for defining enum conversions. +/** The conversion will convert enum values to numeric strings, and vice versa. + * + * To define a string conversion for an enum type, derive a @c string_traits + * specialisation for the enum from this struct. + * + * There's usually an easier way though: the @c PQXX_DECLARE_ENUM_CONVERSION + * macro. Use @c enum_traits manually only if you need to customise your + * traits type in more detail, e.g. if your enum has a "null" value built in. + */ +template<typename ENUM> +struct enum_traits +{ + using underlying_type = typename std::underlying_type<ENUM>::type; + using underlying_traits = string_traits<underlying_type>; + + static constexpr bool has_null() noexcept { return false; } + [[noreturn]] static ENUM null() + { internal::throw_null_conversion("enum type"); } + + static void from_string(const char Str[], ENUM &Obj) + { + underlying_type tmp; + underlying_traits::from_string(Str, tmp); + Obj = ENUM(tmp); + } + + static std::string to_string(ENUM Obj) + { return underlying_traits::to_string(underlying_type(Obj)); } +}; + + +/// Macro: Define a string conversion for an enum type. +/** This specialises the @c pqxx::string_traits template, so use it in the + * @c ::pqxx namespace. + * + * For example: + * + * #include <iostream> + * #include <pqxx/strconv> + * enum X { xa, xb }; + * namespace pqxx { PQXX_DECLARE_ENUM_CONVERSION(x); } + * int main() { std::cout << to_string(xa) << std::endl; } + */ +#define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \ +template<> \ +struct string_traits<ENUM> : pqxx::enum_traits<ENUM> \ +{ \ + static constexpr const char *name() noexcept { return #ENUM; } \ + [[noreturn]] static ENUM null() \ + { internal::throw_null_conversion(name()); } \ +} + + +/// String traits for C-style string ("pointer to const char") +template<> struct PQXX_LIBEXPORT string_traits<const char *> +{ + static constexpr const char *name() noexcept { return "const char *"; } + static constexpr bool has_null() noexcept { return true; } + static bool is_null(const char *t) { return t == nullptr; } + static const char *null() { return nullptr; } + static void from_string(const char Str[], const char *&Obj) { Obj = Str; } + static std::string to_string(const char *Obj) { return Obj; } +}; + +/// String traits for non-const C-style string ("pointer to char") +template<> struct PQXX_LIBEXPORT string_traits<char *> +{ + static constexpr const char *name() noexcept { return "char *"; } + static constexpr bool has_null() noexcept { return true; } + static bool is_null(const char *t) { return t == nullptr; } + static const char *null() { return nullptr; } + + // Don't allow this conversion since it breaks const-safety. + // static void from_string(const char Str[], char *&Obj); + + static std::string to_string(char *Obj) { return Obj; } +}; + +/// String traits for C-style string constant ("array of char") +template<size_t N> struct PQXX_LIBEXPORT string_traits<char[N]> +{ + static constexpr const char *name() noexcept { return "char[]"; } + static constexpr bool has_null() noexcept { return true; } + static bool is_null(const char t[]) { return t == nullptr; } + static const char *null() { return nullptr; } + static std::string to_string(const char Obj[]) { return Obj; } +}; + +template<> struct PQXX_LIBEXPORT string_traits<std::string> +{ + static constexpr const char *name() noexcept { return "string"; } + static constexpr bool has_null() noexcept { return false; } + static bool is_null(const std::string &) { return false; } + [[noreturn]] static std::string null() + { internal::throw_null_conversion(name()); } + static void from_string(const char Str[], std::string &Obj) { Obj=Str; } + static std::string to_string(const std::string &Obj) { return Obj; } +}; + +template<> struct PQXX_LIBEXPORT string_traits<const std::string> +{ + static constexpr const char *name() noexcept { return "const string"; } + static constexpr bool has_null() noexcept { return false; } + static bool is_null(const std::string &) { return false; } + [[noreturn]] static const std::string null() + { internal::throw_null_conversion(name()); } + static const std::string to_string(const std::string &Obj) { return Obj; } +}; + +template<> struct PQXX_LIBEXPORT string_traits<std::stringstream> +{ + static constexpr const char *name() noexcept { return "stringstream"; } + static constexpr bool has_null() noexcept { return false; } + static bool is_null(const std::stringstream &) { return false; } + [[noreturn]] static std::stringstream null() + { internal::throw_null_conversion(name()); } + static void from_string(const char Str[], std::stringstream &Obj) + { Obj.clear(); Obj << Str; } + static std::string to_string(const std::stringstream &Obj) + { return Obj.str(); } +}; + + +// TODO: Implement date conversions. + +/// Attempt to convert postgres-generated string to given built-in type +/** If the form of the value found in the string does not match the expected + * type, e.g. if a decimal point is found when converting to an integer type, + * the conversion fails. Overflows (e.g. converting "9999999999" to a 16-bit + * C++ type) are also treated as errors. If in some cases this behaviour should + * be inappropriate, convert to something bigger such as @c long @c int first + * and then truncate the resulting value. + * + * Only the simplest possible conversions are supported. No fancy features + * such as hexadecimal or octal, spurious signs, or exponent notation will work. + * No whitespace is stripped away. Only the kinds of strings that come out of + * PostgreSQL and out of to_string() can be converted. + */ +template<typename T> + inline void from_string(const char Str[], T &Obj) +{ + if (Str == nullptr) throw std::runtime_error{"Attempt to read null string."}; + string_traits<T>::from_string(Str, Obj); +} + + +/// Conversion with known string length (for strings that may contain nuls) +/** This is only used for strings, where embedded nul bytes should not determine + * the end of the string. + * + * For all other types, this just uses the regular, nul-terminated version of + * from_string(). + */ +template<typename T> inline void from_string(const char Str[], T &Obj, size_t) +{ + return from_string(Str, Obj); +} + +template<> + inline void from_string<std::string>( //[t00] + const char Str[], + std::string &Obj, + size_t len) +{ + if (Str == nullptr) throw std::runtime_error{"Attempt to read null string."}; + Obj.assign(Str, len); +} + +template<typename T> + inline void from_string(const std::string &Str, T &Obj) //[t45] + { from_string(Str.c_str(), Obj); } + +template<typename T> + inline void from_string(const std::stringstream &Str, T &Obj) //[t00] + { from_string(Str.str(), Obj); } + +template<> inline void +from_string(const std::string &Str, std::string &Obj) //[t46] + { Obj = Str; } + + +namespace internal +{ +/// Compute numeric value of given textual digit (assuming that it is a digit) +constexpr int digit_to_number(char c) noexcept { return c-'0'; } +constexpr char number_to_digit(int i) noexcept + { return static_cast<char>(i+'0'); } +} // namespace pqxx::internal + + +/// Convert built-in type to a readable string that PostgreSQL will understand +/** No special formatting is done, and any locale settings are ignored. The + * resulting string will be human-readable and in a format suitable for use in + * SQL queries. + */ +template<typename T> inline std::string to_string(const T &Obj) + { return string_traits<T>::to_string(Obj); } + +//@} + +} // namespace pqxx + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/stream_base.hxx b/contrib/libs/libpqxx/include/pqxx/stream_base.hxx new file mode 100644 index 0000000000..d4af37fb07 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/stream_base.hxx @@ -0,0 +1,62 @@ +/** Definition of the pqxx::stream_base class. + * + * pqxx::stream_base provides optimized batch access to a database table. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_base instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_STREAM_BASE +#define PQXX_H_STREAM_BASE + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/transaction_base.hxx" +#include "pqxx/util.hxx" + +#include <string> + + +namespace pqxx +{ + +class PQXX_LIBEXPORT PQXX_NOVTABLE stream_base : + public internal::transactionfocus +{ +public: + explicit stream_base(transaction_base &); + // TODO: Can we get rid of the vtable? + virtual ~stream_base() noexcept =default; + virtual void complete() = 0; + operator bool() const noexcept; + bool operator!() const noexcept; +protected: + bool m_finished; + virtual void close(); + template<typename C> static std::string columnlist(const C &); + template<typename I> static std::string columnlist(I begin, I end); +private: + stream_base(); + stream_base(const stream_base&); + stream_base & operator=(const stream_base &); +}; + +template<typename C> std::string stream_base::columnlist(const C &c) +{ + return columnlist(std::begin(c), std::end(c)); +} + +template<typename I> std::string stream_base::columnlist(I begin, I end) +{ + return separated_list(",", begin, end); +} + +} // namespace pqxx + + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/stream_from b/contrib/libs/libpqxx/include/pqxx/stream_from new file mode 100644 index 0000000000..71dbb7dfe7 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/stream_from @@ -0,0 +1,6 @@ +/** pqxx::stream_from class. + * + * pqxx::stream_from enables optimized batch reads from a database table. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/stream_from.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/stream_from.hxx b/contrib/libs/libpqxx/include/pqxx/stream_from.hxx new file mode 100644 index 0000000000..bc6bcc7231 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/stream_from.hxx @@ -0,0 +1,210 @@ +/** Definition of the pqxx::stream_from class. + * + * pqxx::stream_from enables optimized batch reads from a database table. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_from instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_STREAM_FROM +#define PQXX_H_STREAM_FROM + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/transaction_base.hxx" +#include "pqxx/stream_base.hxx" +#include "pqxx/internal/type_utils.hxx" + +#include <string> + + +namespace pqxx +{ + +/// Efficiently pull data directly out of a table. +class PQXX_LIBEXPORT stream_from : public stream_base +{ +public: + stream_from( + transaction_base &, + const std::string &table_name + ); + template<typename Columns> stream_from( + transaction_base &, + const std::string &table_name, + const Columns& columns + ); + template<typename Iter> stream_from( + transaction_base &, + const std::string &table_name, + Iter columns_begin, + Iter columns_end + ); + + ~stream_from() noexcept; + + void complete() override; + + bool get_raw_line(std::string &); + template<typename Tuple> stream_from & operator>>(Tuple &); + +private: + internal::encoding_group m_copy_encoding; + std::string m_current_line; + bool m_retry_line; + + void set_up(transaction_base &, const std::string &table_name); + void set_up( + transaction_base &, + const std::string &table_name, + const std::string &columns + ); + + void close() override; + + bool extract_field( + const std::string &, + std::string::size_type &, + std::string & + ) const; + + template<typename Tuple, std::size_t I> auto tokenize_ith( + const std::string &, + Tuple &, + std::string::size_type, + std::string & + ) const -> typename std::enable_if<( + std::tuple_size<Tuple>::value > I + )>::type; + template<typename Tuple, std::size_t I> auto tokenize_ith( + const std::string &, + Tuple &, + std::string::size_type, + std::string & + ) const -> typename std::enable_if<( + std::tuple_size<Tuple>::value <= I + )>::type; + + template<typename T> void extract_value( + const std::string &line, + T& t, + std::string::size_type &here, + std::string &workspace + ) const; +}; + + +template<typename Columns> stream_from::stream_from( + transaction_base &tb, + const std::string &table_name, + const Columns& columns +) : stream_from{ + tb, + table_name, + std::begin(columns), + std::end(columns) +} {} + + +template<typename Iter> stream_from::stream_from( + transaction_base &tb, + const std::string &table_name, + Iter columns_begin, + Iter columns_end +) : + namedclass{"stream_from", table_name}, + stream_base{tb} +{ + set_up( + tb, + table_name, + columnlist(columns_begin, columns_end) + ); +} + + +template<typename Tuple> stream_from & stream_from::operator>>( + Tuple &t +) +{ + if (m_retry_line or get_raw_line(m_current_line)) + { + std::string workspace; + try + { + tokenize_ith<Tuple, 0>(m_current_line, t, 0, workspace); + m_retry_line = false; + } + catch (...) + { + m_retry_line = true; + throw; + } + } + return *this; +} + + +template<typename Tuple, std::size_t I> auto stream_from::tokenize_ith( + const std::string &line, + Tuple &t, + std::string::size_type here, + std::string &workspace +) const -> typename std::enable_if<( + std::tuple_size<Tuple>::value > I +)>::type +{ + if (here >= line.size()) + throw usage_error{"Too few fields to extract from stream_from line."}; + + extract_value(line, std::get<I>(t), here, workspace); + tokenize_ith<Tuple, I+1>(line, t, here, workspace); +} + + +template<typename Tuple, std::size_t I> auto stream_from::tokenize_ith( + const std::string &line, + Tuple & /* t */, + std::string::size_type here, + std::string & /* workspace */ +) const -> typename std::enable_if<( + std::tuple_size<Tuple>::value <= I +)>::type +{ + // Zero-column line may still have a trailing newline + if ( + here < line.size() and + not (here == line.size() - 1 and line[here] == '\n')) + throw usage_error{"Not all fields extracted from stream_from line"}; +} + + +template<typename T> void stream_from::extract_value( + const std::string &line, + T& t, + std::string::size_type &here, + std::string &workspace +) const +{ + if (extract_field(line, here, workspace)) + from_string<T>(workspace, t); + else + t = internal::null_value<T>(); +} + +template<> void stream_from::extract_value<std::nullptr_t>( + const std::string &line, + std::nullptr_t&, + std::string::size_type &here, + std::string &workspace +) const; + +} // namespace pqxx + + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/stream_to b/contrib/libs/libpqxx/include/pqxx/stream_to new file mode 100644 index 0000000000..a5100969d0 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/stream_to @@ -0,0 +1,6 @@ +/** pqxx::stream_to class. + * + * pqxx::stream_to enables optimized batch updates to a database table. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/stream_to.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/stream_to.hxx b/contrib/libs/libpqxx/include/pqxx/stream_to.hxx new file mode 100644 index 0000000000..cf23f980f5 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/stream_to.hxx @@ -0,0 +1,192 @@ +/** Definition of the pqxx::stream_to class. + * + * pqxx::stream_to enables optimized batch updates to a database table. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_to.hxx instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_STREAM_TO +#define PQXX_H_STREAM_TO + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/transaction_base.hxx" +#include "pqxx/stream_base.hxx" +#include "pqxx/stream_from.hxx" +#include "pqxx/internal/type_utils.hxx" + +#include <string> + + +namespace pqxx +{ + +/// Efficiently write data directly to a database table. +/** If you wish to insert rows of data into a table, you can compose INSERT + * statements and execute them. But it's slow and tedious, and you need to + * worry about quoting and escaping the data. + * + * If you're just inserting a single row, it probably won't matter much. You + * can use prepared or parameterised statements to take care of the escaping + * for you. But if you're inserting large numbers of rows you will want + * something better. + * + * Inserting rows one by one tends to take a lot of time, especially when you + * are working with a remote database server over the network. Every single + * row involves sending the data over the network, and waiting for a reply. + * Do it "in bulk" using @c stream_to, and you may find that it goes many times + * faster, sometimes even by orders of magnitude. + * + * Here's how it works: you create a @c stream_to stream to start writing to + * your table. You will probably want to specify the columns. Then, you + * feed your data into the stream one row at a time. And finally, you call the + * stream's @c complete() to tell it to finalise the operation, wait for + * completion, and check for errors. + * + * You insert data using the @c << ("shift-left") operator. Each row must be + * something that can be iterated in order to get its constituent fields: a + * @c std::tuple, a @c std::vector, or anything else with a @c begin and + * @c end. It could be a class of your own. Of course the fields have to + * match the columns you specified when creating the stream. + * + * There is also a matching stream_from for reading data in bulk. + */ +class PQXX_LIBEXPORT stream_to : public stream_base +{ +public: + /// Create a stream, without specifying columns. + /** Fields will be inserted in whatever order the columns have in the + * database. + * + * You'll probably want to specify the columns, so that the mapping between + * your data fields and the table is explicit in your code, and not hidden + * in an "implicit contract" between your code and your schema. + */ + stream_to(transaction_base &, const std::string &table_name); + + /// Create a stream, specifying column names as a container of strings. + template<typename Columns> stream_to( + transaction_base &, + const std::string &table_name, + const Columns& columns + ); + + /// Create a stream, specifying column names as a sequence of strings. + template<typename Iter> stream_to( + transaction_base &, + const std::string &table_name, + Iter columns_begin, + Iter columns_end + ); + + ~stream_to() noexcept; + + /// Complete the operation, and check for errors. + /** Always call this to close the stream in an orderly fashion, even after + * an error. (In the case of an error, abort the transaction afterwards.) + * + * The only circumstance where it's safe to skip this is after an error, if + * you're discarding the entire connection right away. + */ + void complete() override; + + /// Insert a row of data. + /** The data can be any type that can be iterated. Each iterated item + * becomes a field in the row, in the same order as the columns you + * specified when creating the stream. + * + * Each field will be converted into the database's format using + * @c pqxx::to_string. + */ + template<typename Tuple> stream_to & operator<<(const Tuple &); + + /// Stream a `stream_from` straight into a `stream_to`. + /** This can be useful when copying between different databases. If the + * source and the destination are on the same database, you'll get better + * performance doing it all in a regular query. + */ + stream_to &operator<<(stream_from &); + +private: + /// Write a row of data, as a line of text. + void write_raw_line(const std::string &); + + void set_up(transaction_base &, const std::string &table_name); + void set_up( + transaction_base &, + const std::string &table_name, + const std::string &columns + ); + + void close() override; +}; + + +template<typename Columns> inline stream_to::stream_to( + transaction_base &tb, + const std::string &table_name, + const Columns& columns +) : stream_to{ + tb, + table_name, + std::begin(columns), + std::end(columns) +} +{} + + +template<typename Iter> inline stream_to::stream_to( + transaction_base &tb, + const std::string &table_name, + Iter columns_begin, + Iter columns_end +) : + namedclass{"stream_from", table_name}, + stream_base{tb} +{ + set_up( + tb, + table_name, + columnlist(columns_begin, columns_end) + ); +} + + +namespace internal +{ + +class PQXX_LIBEXPORT TypedCopyEscaper +{ + static std::string escape(const std::string &); +public: + template<typename T> std::string operator()(const T* t) const + { + return string_traits<T>::is_null(*t) ? "\\N" : escape(to_string(*t)); + } +}; + +// Explicit specialization so we don't need a string_traits<> for nullptr_t +template<> inline std::string TypedCopyEscaper::operator()<std::nullptr_t>( + const std::nullptr_t* +) const +{ return "\\N"; } + +} // namespace pqxx::internal + + +template<typename Tuple> stream_to & stream_to::operator<<(const Tuple &t) +{ + write_raw_line(separated_list("\t", t, internal::TypedCopyEscaper())); + return *this; +} + +} // namespace pqxx + + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/subtransaction b/contrib/libs/libpqxx/include/pqxx/subtransaction new file mode 100644 index 0000000000..364ccab3fc --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/subtransaction @@ -0,0 +1,6 @@ +/** pqxx::subtransaction class. + * + * pqxx::subtransaction is a nested transaction, i.e. one inside a transaction. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/subtransaction.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/subtransaction.hxx b/contrib/libs/libpqxx/include/pqxx/subtransaction.hxx new file mode 100644 index 0000000000..2b353e63db --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/subtransaction.hxx @@ -0,0 +1,105 @@ +/** Definition of the pqxx::subtransaction class. + * + * pqxx::subtransaction is a nested transaction, i.e. one within a transaction. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/subtransaction instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_SUBTRANSACTION +#define PQXX_H_SUBTRANSACTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/dbtransaction.hxx" + + +/* Methods tested in eg. self-test program test1 are marked with "//[t01]" + */ + + +namespace pqxx +{ + +/** + * @ingroup transaction + */ +/// "Transaction" nested within another transaction +/** A subtransaction can be executed inside a backend transaction, or inside + * another subtransaction. This can be useful when, for example, statements in + * a transaction may harmlessly fail and you don't want them to abort the entire + * transaction. Here's an example of how a temporary table may be dropped + * before re-creating it, without failing if the table did not exist: + * + * @code + * void do_job(connection_base &C) + * { + * const string temptable = "fleetingtable"; + * + * // Since we're dealing with a temporary table here, disallow automatic + * // recovery of the connection in case it breaks. + * C.inhibit_reactivation(true); + * + * work W(C, "do_job"); + * do_firstpart(W); + * + * // Attempt to delete our temporary table if it already existed + * try + * { + * subtransaction S(W, "droptemp"); + * S.exec0("DROP TABLE " + temptable); + * S.commit(); + * } + * catch (const undefined_table &) + * { + * // Table did not exist. Which is what we were hoping to achieve anyway. + * // Carry on without regrets. + * } + * + * // S may have gone into a failed state and been destroyed, but the + * // upper-level transaction W is still fine. We can continue to use it. + * W.exec("CREATE TEMP TABLE " + temptable + "(bar integer, splat varchar)"); + * + * do_lastpart(W); + * } + * @endcode + * + * (This is just an example. If you really wanted to do drop a table without an + * error if it doesn't exist, you'd use DROP TABLE IF EXISTS.) + * + * There are no isolation levels inside a transaction. They are not needed + * because all actions within the same backend transaction are always performed + * sequentially anyway. + */ +class PQXX_LIBEXPORT subtransaction : + public internal::transactionfocus, + public dbtransaction +{ +public: + /// Nest a subtransaction nested in another transaction. + explicit subtransaction( //[t88] + dbtransaction &T, const std::string &Name=std::string{}); + + /// Nest a subtransaction in another subtransaction. + explicit subtransaction( + subtransaction &T, const std::string &Name=std::string{}); + + virtual ~subtransaction() noexcept + { End(); } + +private: + virtual void do_begin() override; //[t88] + virtual void do_commit() override; //[t88] + virtual void do_abort() override; //[t88] + + dbtransaction &m_parent; +}; +} + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/tablereader b/contrib/libs/libpqxx/include/pqxx/tablereader new file mode 100644 index 0000000000..daa5ec93e8 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/tablereader @@ -0,0 +1,6 @@ +/** pqxx::tablereader class. + * + * pqxx::tablereader enables optimized batch reads from a database table. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/tablereader.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/tablereader.hxx b/contrib/libs/libpqxx/include/pqxx/tablereader.hxx new file mode 100644 index 0000000000..f5300cbeb0 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/tablereader.hxx @@ -0,0 +1,118 @@ +/** Definition of the pqxx::tablereader class. + * + * pqxx::tablereader enables optimized batch reads from a database table. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/tablereader instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TABLEREADER +#define PQXX_H_TABLEREADER + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/result.hxx" +#include "pqxx/tablestream.hxx" + + +namespace pqxx +{ +/// @deprecated Use stream_from instead. +/** Efficiently pull data directly out of a table. + * @warning This class does not work reliably with multibyte encodings. Using + * it with some multi-byte encodings may pose a security risk. + */ +class PQXX_LIBEXPORT tablereader : public tablestream +{ +public: + PQXX_DEPRECATED tablereader( + transaction_base &, + const std::string &Name, + const std::string &Null=std::string{}); + template<typename ITER> + PQXX_DEPRECATED tablereader( + transaction_base &, + const std::string &Name, + ITER begincolumns, + ITER endcolumns); + template<typename ITER> + PQXX_DEPRECATED tablereader( + transaction_base &, + const std::string &Name, + ITER begincolumns, + ITER endcolumns, + const std::string &Null); + ~tablereader() noexcept; + template<typename TUPLE> tablereader &operator>>(TUPLE &); + operator bool() const noexcept { return not m_done; } + bool operator!() const noexcept { return m_done; } + bool get_raw_line(std::string &Line); + template<typename TUPLE> + void tokenize(std::string, TUPLE &) const; + virtual void complete() override; +private: + void set_up( + transaction_base &T, + const std::string &RName, + const std::string &Columns=std::string{}); + PQXX_PRIVATE void reader_close(); + std::string extract_field( + const std::string &, + std::string::size_type &) const; + bool m_done; +}; + + +template<typename ITER> inline +tablereader::tablereader( + transaction_base &T, + const std::string &Name, + ITER begincolumns, + ITER endcolumns) : + namedclass{Name, "tablereader"}, + tablestream{T, std::string{}}, + m_done{true} +{ + set_up(T, Name, columnlist(begincolumns, endcolumns)); +} + + +template<typename ITER> inline +tablereader::tablereader( + transaction_base &T, + const std::string &Name, + ITER begincolumns, + ITER endcolumns, + const std::string &Null) : + namedclass{Name, "tablereader"}, + tablestream{T, Null}, + m_done{true} +{ + set_up(T, Name, columnlist(begincolumns, endcolumns)); +} + + +template<typename TUPLE> +inline void tablereader::tokenize(std::string Line, TUPLE &T) const +{ + std::back_insert_iterator<TUPLE> ins = std::back_inserter(T); + std::string::size_type here = 0; + while (here < Line.size()) *ins++ = extract_field(Line, here); +} + + +template<typename TUPLE> +inline tablereader &pqxx::tablereader::operator>>(TUPLE &T) +{ + std::string Line; + if (get_raw_line(Line)) tokenize(Line, T); + return *this; +} +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/tablestream b/contrib/libs/libpqxx/include/pqxx/tablestream new file mode 100644 index 0000000000..57d700e800 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/tablestream @@ -0,0 +1,6 @@ +/** pqxx::tablestream class. + * + * pqxx::tablestream provides optimized batch access to a database table. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/tablestream.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/tablestream.hxx b/contrib/libs/libpqxx/include/pqxx/tablestream.hxx new file mode 100644 index 0000000000..1803604bec --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/tablestream.hxx @@ -0,0 +1,59 @@ +/** Definition of the pqxx::tablestream class. + * + * pqxx::tablestream provides optimized batch access to a database table. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/tablestream instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TABLESTREAM +#define PQXX_H_TABLESTREAM + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" +#include "pqxx/transaction_base.hxx" + + +namespace pqxx +{ +/// Base class for obsolete tablereader/tablewriter classes. +/** @deprecated Use stream_from and stream_to instead. + */ +class PQXX_LIBEXPORT PQXX_NOVTABLE tablestream : + public internal::transactionfocus +{ +public: + explicit tablestream( + transaction_base &Trans, + const std::string &Null=std::string{}); + virtual ~tablestream() noexcept =0; + virtual void complete() =0; +protected: + const std::string &NullStr() const { return m_null; } + bool is_finished() const noexcept { return m_finished; } + void base_close(); + template<typename ITER> + static std::string columnlist(ITER colbegin, ITER colend); +private: + std::string m_null; + bool m_finished = false; + + tablestream() =delete; + tablestream(const tablestream &) =delete; + tablestream &operator=(const tablestream &) =delete; +}; + + +template<typename ITER> inline +std::string tablestream::columnlist(ITER colbegin, ITER colend) +{ + return separated_list(",", colbegin, colend); +} +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/tablewriter b/contrib/libs/libpqxx/include/pqxx/tablewriter new file mode 100644 index 0000000000..80bdf59b2b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/tablewriter @@ -0,0 +1,6 @@ +/** pqxx::tablewriter class. + * + * pqxx::tablewriter enables optimized batch updates to a database table. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/tablewriter.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/tablewriter.hxx b/contrib/libs/libpqxx/include/pqxx/tablewriter.hxx new file mode 100644 index 0000000000..32e7a98b7c --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/tablewriter.hxx @@ -0,0 +1,209 @@ +/** Definition of the pqxx::tablewriter class. + * + * pqxx::tablewriter enables optimized batch updates to a database table. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/tablewriter.hxx instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TABLEWRITER +#define PQXX_H_TABLEWRITER + +#include <iterator> + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/tablestream.hxx" + + +namespace pqxx +{ +/// @deprecated Use stream_to instead. +/** Efficiently write data directly to a database table. + * @warning This class does not work reliably with multibyte encodings. Using + * it with some multi-byte encodings may pose a security risk. + */ +class PQXX_LIBEXPORT tablewriter : public tablestream +{ +public: + PQXX_DEPRECATED tablewriter( + transaction_base &, + const std::string &WName, + const std::string &Null=std::string{}); + template<typename ITER> + PQXX_DEPRECATED tablewriter( + transaction_base &, + const std::string &WName, + ITER begincolumns, + ITER endcolumns); + template<typename ITER> + PQXX_DEPRECATED tablewriter( + transaction_base &T, + const std::string &WName, + ITER begincolumns, + ITER endcolumns, + const std::string &Null); + ~tablewriter() noexcept; + template<typename IT> void insert(IT Begin, IT End); + template<typename TUPLE> void insert(const TUPLE &); + template<typename IT> void push_back(IT Begin, IT End); + template<typename TUPLE> void push_back(const TUPLE &); + template<typename SIZE> void reserve(SIZE) {} + template<typename TUPLE> tablewriter &operator<<(const TUPLE &); + tablewriter &operator<<(tablereader &); + template<typename IT> std::string generate(IT Begin, IT End) const; + template<typename TUPLE> std::string generate(const TUPLE &) const; + virtual void complete() override; + void write_raw_line(const std::string &); +private: + void set_up( + transaction_base &, + const std::string &WName, + const std::string &Columns = std::string{}); + PQXX_PRIVATE void writer_close(); +}; +} // namespace pqxx + + +namespace std +{ +template<> + class back_insert_iterator<pqxx::tablewriter> +{ +public: + using iterator_category = output_iterator_tag; + + explicit back_insert_iterator(pqxx::tablewriter &W) noexcept : + m_writer{&W} {} + + back_insert_iterator & + operator=(const back_insert_iterator &rhs) noexcept + { + m_writer = rhs.m_writer; + return *this; + } + + template<typename TUPLE> + back_insert_iterator &operator=(const TUPLE &T) + { + m_writer->insert(T); + return *this; + } + + back_insert_iterator &operator++() { return *this; } + back_insert_iterator &operator++(int) { return *this; } + back_insert_iterator &operator*() { return *this; } + +private: + pqxx::tablewriter *m_writer; +}; +} // namespace std + + +namespace pqxx +{ +template<typename ITER> inline tablewriter::tablewriter( + transaction_base &T, + const std::string &WName, + ITER begincolumns, + ITER endcolumns) : + namedclass{"tablewriter", WName}, + tablestream{T, std::string{}} +{ + set_up(T, WName, columnlist(begincolumns, endcolumns)); +} + + +template<typename ITER> inline tablewriter::tablewriter( + transaction_base &T, + const std::string &WName, + ITER begincolumns, + ITER endcolumns, + const std::string &Null) : + namedclass{"tablewriter", WName}, + tablestream{T, Null} +{ + set_up(T, WName, columnlist(begincolumns, endcolumns)); +} + + +namespace internal +{ +PQXX_LIBEXPORT std::string escape( + const std::string &s, + const std::string &null); + +inline std::string escape_any( + const std::string &s, + const std::string &null) +{ return escape(s, null); } + +inline std::string escape_any( + const char s[], + const std::string &null) +{ return s ? escape(std::string{s}, null) : "\\N"; } + +template<typename T> inline std::string escape_any( + const T &t, + const std::string &null) +{ return escape(to_string(t), null); } + + +template<typename IT> class Escaper +{ + const std::string &m_null; +public: + explicit Escaper(const std::string &null) : m_null{null} {} + std::string operator()(IT i) const { return escape_any(*i, m_null); } +}; +} + + +template<typename IT> +inline std::string tablewriter::generate(IT Begin, IT End) const +{ + return separated_list("\t", Begin, End, internal::Escaper<IT>{NullStr()}); +} +template<typename TUPLE> +inline std::string tablewriter::generate(const TUPLE &T) const +{ + return generate(std::begin(T), std::end(T)); +} + +template<typename IT> inline void tablewriter::insert(IT Begin, IT End) +{ + write_raw_line(generate(Begin, End)); +} + +template<typename TUPLE> inline void tablewriter::insert(const TUPLE &T) +{ + insert(std::begin(T), std::end(T)); +} + +template<typename IT> +inline void tablewriter::push_back(IT Begin, IT End) +{ + insert(Begin, End); +} + +template<typename TUPLE> +inline void tablewriter::push_back(const TUPLE &T) +{ + insert(std::begin(T), std::end(T)); +} + +template<typename TUPLE> +inline tablewriter &tablewriter::operator<<(const TUPLE &T) +{ + insert(T); + return *this; +} + +} // namespace pqxx +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/transaction b/contrib/libs/libpqxx/include/pqxx/transaction new file mode 100644 index 0000000000..755cd4179b --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/transaction @@ -0,0 +1,6 @@ +/** pqxx::transaction class. + * + * pqxx::transaction represents a standard database transaction. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/transaction.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/transaction.hxx b/contrib/libs/libpqxx/include/pqxx/transaction.hxx new file mode 100644 index 0000000000..6c0b1da0b2 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/transaction.hxx @@ -0,0 +1,116 @@ +/** Definition of the pqxx::transaction class. + * pqxx::transaction represents a standard database transaction. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TRANSACTION +#define PQXX_H_TRANSACTION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/dbtransaction.hxx" + + +/* Methods tested in eg. self-test program test1 are marked with "//[t01]" + */ + + +namespace pqxx +{ + +namespace internal +{ +/// Helper base class for the @c transaction class template. +class PQXX_LIBEXPORT basic_transaction : public dbtransaction +{ +protected: + basic_transaction( //[t01] + connection_base &C, + const std::string &IsolationLevel, + readwrite_policy); + +private: + virtual void do_commit() override; //[t01] +}; +} // namespace internal + + +/** + * @ingroup transaction + */ +//@{ + +/// Standard back-end transaction, templatized on isolation level +/** This is the type you'll normally want to use to represent a transaction on + * the database. + * + * While you may choose to create your own transaction object to interface to + * the database backend, it is recommended that you wrap your transaction code + * into a transactor code instead and let the transaction be created for you. + * @see pqxx/transactor.hxx + * + * If you should find that using a transactor makes your code less portable or + * too complex, go ahead, create your own transaction anyway. + * + * Usage example: double all wages + * + * @code + * extern connection C; + * work T(C); + * try + * { + * T.exec("UPDATE employees SET wage=wage*2"); + * T.commit(); // NOTE: do this inside try block + * } + * catch (const exception &e) + * { + * cerr << e.what() << endl; + * T.abort(); // Usually not needed; same happens when T's life ends. + * } + * @endcode + */ +template< + isolation_level ISOLATIONLEVEL=read_committed, + readwrite_policy READWRITE=read_write> +class transaction : public internal::basic_transaction +{ +public: + using isolation_tag = isolation_traits<ISOLATIONLEVEL>; + + /// Create a transaction. + /** + * @param C Connection for this transaction to operate on + * @param TName Optional name for transaction; must begin with a letter and + * may contain letters and digits only + */ + explicit transaction(connection_base &C, const std::string &TName): //[t01] + namedclass{fullname("transaction", isolation_tag::name()), TName}, + internal::basic_transaction(C, isolation_tag::name(), READWRITE) + { Begin(); } + + explicit transaction(connection_base &C) : //[t01] + transaction(C, "") {} + + virtual ~transaction() noexcept + { End(); } +}; + + +/// The default transaction type. +using work = transaction<>; + +/// Read-only transaction. +using read_transaction = transaction<read_committed, read_only>; + +//@} +} + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/transaction_base b/contrib/libs/libpqxx/include/pqxx/transaction_base new file mode 100644 index 0000000000..929c50d226 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/transaction_base @@ -0,0 +1,7 @@ +/** Base for the transaction classes. + * + * pqxx::transaction_base defines the interface for any abstract class that + * represents a database transaction. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/transaction_base.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/transaction_base.hxx b/contrib/libs/libpqxx/include/pqxx/transaction_base.hxx new file mode 100644 index 0000000000..06c2788d5a --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/transaction_base.hxx @@ -0,0 +1,664 @@ +/** Common code and definitions for the transaction classes. + * + * pqxx::transaction_base defines the interface for any abstract class that + * represents a database transaction. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TRANSACTION_BASE +#define PQXX_H_TRANSACTION_BASE + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +/* End-user programs need not include this file, unless they define their own + * transaction classes. This is not something the typical program should want + * to do. + * + * However, reading this file is worthwhile because it defines the public + * interface for the available transaction classes such as transaction and + * nontransaction. + */ + +#include "pqxx/connection_base.hxx" +#include "pqxx/internal/encoding_group.hxx" +#include "pqxx/isolation.hxx" +#include "pqxx/result.hxx" +#include "pqxx/row.hxx" + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ +namespace internal +{ +class sql_cursor; + +class PQXX_LIBEXPORT transactionfocus : public virtual namedclass +{ +public: + explicit transactionfocus(transaction_base &t) : + namedclass{"transactionfocus"}, + m_trans{t}, + m_registered{false} + { + } + + transactionfocus() =delete; + transactionfocus(const transactionfocus &) =delete; + transactionfocus &operator=(const transactionfocus &) =delete; + +protected: + void register_me(); + void unregister_me() noexcept; + void reg_pending_error(const std::string &) noexcept; + bool registered() const noexcept { return m_registered; } + + transaction_base &m_trans; + +private: + bool m_registered; +}; + + +/// Helper class to construct an invocation of a parameterised statement. +/** @deprecated Use @c exec_params and friends instead. + */ +class PQXX_LIBEXPORT parameterized_invocation : statement_parameters +{ +public: + PQXX_DEPRECATED parameterized_invocation( + connection_base &, const std::string &query); + + parameterized_invocation &operator()() { add_param(); return *this; } + parameterized_invocation &operator()(const binarystring &v) + { add_binary_param(v, true); return *this; } + template<typename T> parameterized_invocation &operator()(const T &v) + { add_param(v, true); return *this; } + parameterized_invocation &operator()(const binarystring &v, bool nonnull) + { add_binary_param(v, nonnull); return *this; } + template<typename T> + parameterized_invocation &operator()(const T &v, bool nonnull) + { add_param(v, nonnull); return *this; } + + result exec(); + +private: + /// Not allowed + parameterized_invocation &operator=(const parameterized_invocation &) + =delete; + + connection_base &m_home; + const std::string m_query; +}; +} // namespace internal + + +namespace internal +{ +namespace gate +{ +class transaction_subtransaction; +class transaction_tablereader; +class transaction_sql_cursor; +class transaction_stream_from; +class transaction_tablewriter; +class transaction_stream_to; +class transaction_transactionfocus; +} // namespace internal::gate +} // namespace internal + + +/** + * @defgroup transaction Transaction classes + * + * All database access goes through instances of these classes. + * However, not all implementations of this interface need to provide + * full transactional integrity. + * + * Several implementations of this interface are shipped with libpqxx, including + * the plain transaction class, the entirely unprotected nontransaction, and the + * more cautious robusttransaction. + */ + +/// Interface definition (and common code) for "transaction" classes. +/** + * @ingroup transaction + * + * Abstract base class for all transaction types. + */ +class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base : + public virtual internal::namedclass +{ +public: + /// If nothing else is known, our isolation level is at least read_committed + using isolation_tag = isolation_traits<read_committed>; + + transaction_base() =delete; + transaction_base(const transaction_base &) =delete; + transaction_base &operator=(const transaction_base &) =delete; + + virtual ~transaction_base() =0; //[t01] + + /// Commit the transaction + /** Unless this function is called explicitly, the transaction will not be + * committed (actually the nontransaction implementation breaks this rule, + * hence the name). + * + * Once this function returns, the whole transaction will typically be + * irrevocably completed in the database. There is also, however, a minute + * risk that the connection to the database may be lost at just the wrong + * moment. In that case, libpqxx may be unable to determine whether the + * transaction was completed or aborted and an in_doubt_error will be thrown + * to make this fact known to the caller. The robusttransaction + * implementation takes some special precautions to reduce this risk. + */ + void commit(); //[t01] + + /// Abort the transaction + /** No special effort is required to call this function; it will be called + * implicitly when the transaction is destructed. + */ + void abort(); //[t10] + + /** + * @ingroup escaping-functions + */ + //@{ + /// Escape string for use as SQL string literal in this transaction + std::string esc(const char str[]) const { return conn().esc(str); } + /// Escape string for use as SQL string literal in this transaction + std::string esc(const char str[], size_t maxlen) const + { return conn().esc(str, maxlen); } + /// Escape string for use as SQL string literal in this transaction + std::string esc(const std::string &str) const { return conn().esc(str); } + + /// Escape binary data for use as SQL string literal in this transaction + /** Raw, binary data is treated differently from regular strings. Binary + * strings are never interpreted as text, so they may safely include byte + * values or byte sequences that don't happen to represent valid characters in + * the character encoding being used. + * + * The binary string does not stop at the first zero byte, as is the case with + * textual strings. Instead, they may contain zero bytes anywhere. If it + * happens to contain bytes that look like quote characters, or other things + * that can disrupt their use in SQL queries, they will be replaced with + * special escape sequences. + */ + std::string esc_raw(const unsigned char data[], size_t len) const //[t62] + { return conn().esc_raw(data, len); } + /// Escape binary data for use as SQL string literal in this transaction + std::string esc_raw(const std::string &) const; //[t62] + + /// Unescape binary data, e.g. from a table field or notification payload. + /** Takes a binary string as escaped by PostgreSQL, and returns a restored + * copy of the original binary data. + */ + std::string unesc_raw(const std::string &text) const + { return conn().unesc_raw(text); } + + /// Unescape binary data, e.g. from a table field or notification payload. + /** Takes a binary string as escaped by PostgreSQL, and returns a restored + * copy of the original binary data. + */ + std::string unesc_raw(const char *text) const + { return conn().unesc_raw(text); } + + /// Represent object as SQL string, including quoting & escaping. + /** Nulls are recognized and represented as SQL nulls. */ + template<typename T> std::string quote(const T &t) const + { return conn().quote(t); } + + /// Binary-escape and quote a binarystring for use as an SQL constant. + std::string quote_raw(const unsigned char str[], size_t len) const + { return conn().quote_raw(str, len); } + + std::string quote_raw(const std::string &str) const; + + /// Escape an SQL identifier for use in a query. + std::string quote_name(const std::string &identifier) const + { return conn().quote_name(identifier); } + + /// Escape string for literal LIKE match. + std::string esc_like(const std::string &str, char escape_char='\\') const + { return conn().esc_like(str, escape_char); } + //@} + + /// Execute query + /** Perform a query in this transaction. + * + * This is one of the most important functions in libpqxx. + * + * Most libpqxx exceptions can be thrown from here, including sql_error, + * broken_connection, and many sql_error subtypes such as + * feature_not_supported or insufficient_privilege. But any exception thrown + * by the C++ standard library may also occur here. All exceptions will be + * derived from std::exception, however, and all libpqxx-specific exception + * types are derived from pqxx::pqxx_exception. + * + * @param Query Query or command to execute + * @param Desc Optional identifier for query, to help pinpoint SQL errors + * @return A result set describing the query's or command's result + */ + result exec( + const std::string &Query, + const std::string &Desc=std::string{}); //[t01] + + result exec( + const std::stringstream &Query, + const std::string &Desc=std::string{}) + { return exec(Query.str(), Desc); } + + /// Execute query, which should zero rows of data. + /** Works like exec, but fails if the result contains data. It still returns + * a result, however, which may contain useful metadata. + * + * @throw unexpected_rows If the query returned the wrong number of rows. + */ + result exec0( + const std::string &Query, + const std::string &Desc=std::string{}) + { return exec_n(0, Query, Desc); } + + /// Execute query returning a single row of data. + /** Works like exec, but requires the result to contain exactly one row. + * The row can be addressed directly, without the need to find the first row + * in a result set. + * + * @throw unexpected_rows If the query returned the wrong number of rows. + */ + row exec1(const std::string &Query, const std::string &Desc=std::string{}) + { return exec_n(1, Query, Desc).front(); } + + /// Execute query, expect given number of rows. + /** Works like exec, but checks that the number of rows is exactly what's + * expected. + * + * @throw unexpected_rows If the query returned the wrong number of rows. + */ + result exec_n( + size_t rows, + const std::string &Query, + const std::string &Desc=std::string{}); + + /** + * @name Parameterized statements + * + * You'll often need parameters in the queries you execute: "select the + * car with this licence plate." If the parameter is a string, you need to + * quote it and escape any special characters inside it, or it may become a + * target for an SQL injection attack. If it's an integer (for example), + * you need to convert it to a string, but in the database's format, without + * locale-specific niceties like "," separators between the thousands. + * + * Parameterised statements are an easier and safer way to do this. They're + * like prepared statements, but for a single use. You don't need to name + * them, and you don't need to prepare them first. + * + * Your query will include placeholders like @c $1 and $2 etc. in the places + * where you want the arguments to go. Then, you pass the argument values + * and the actual query is constructed for you. + * + * Pass the exact right number of parameters, and in the right order. The + * parameters in the query don't have to be neatly ordered from @c $1 to + * @c $2 to @c $3 - but you must pass the argument for @c $1 first, the one + * for @c $2 second, etc. + * + * @warning Beware of "nul" bytes. Any string you pass as a parameter will + * end at the first char with value zero. If you pass a @c std::string that + * contains a zero byte, the last byte in the value will be the one just + * before the zero. + */ + //@{ + /// Execute an SQL statement with parameters. + template<typename ...Args> + result exec_params(const std::string &query, Args &&...args) + { + return internal_exec_params( + query, internal::params(std::forward<Args>(args)...)); + } + + // Execute parameterised statement, expect a single-row result. + /** @throw unexpected_rows if the result does not consist of exactly one row. + */ + template<typename ...Args> + row exec_params1(const std::string &query, Args&&... args) + { + return exec_params_n(1, query, std::forward<Args>(args)...).front(); + } + + // Execute parameterised statement, expect a result with zero rows. + /** @throw unexpected_rows if the result contains rows. + */ + template<typename ...Args> + result exec_params0(const std::string &query, Args &&...args) + { + return exec_params_n(0, query, std::forward<Args>(args)...); + } + + // Execute parameterised statement, expect exactly a given number of rows. + /** @throw unexpected_rows if the result contains the wrong number of rows. + */ + template<typename ...Args> + result exec_params_n(size_t rows, const std::string &query, Args &&...args) + { + const auto r = exec_params(query, std::forward<Args>(args)...); + check_rowcount_params(rows, r.size()); + return r; + } + + /// Parameterize a statement. @deprecated Use @c exec_params instead. + /* Use this to build up a parameterized statement invocation, then invoke it + * using @c exec() + * + * Example: @c trans.parameterized("SELECT $1 + 1")(1).exec(); + * + * This is the old, pre-C++11 way of handling parameterised statements. As + * of libpqxx 6.0, it's made much easier using variadic templates. + */ + PQXX_DEPRECATED internal::parameterized_invocation + parameterized(const std::string &query); + //@} + + /** + * @name Prepared statements + * + * These are very similar to parameterised statements. The difference is + * that you prepare them in advance, giving them identifying names. You can + * then call them by these names, passing in the argument values appropriate + * for that call. + * + * You prepare a statement on the connection, using + * @c pqxx::connection_base::prepare(). But you then call the statement in a + * transaction, using the functions you see here. + * + * Never try to prepare, execute, or unprepare a prepared statement manually + * using direct SQL queries. Always use the functions provided by libpqxx. + * + * See \ref prepared for a full discussion. + * + * @warning Beware of "nul" bytes. Any string you pass as a parameter will + * end at the first char with value zero. If you pass a @c std::string that + * contains a zero byte, the last byte in the value will be the one just + * before the zero. If you need a zero byte, consider using + * pqxx::binarystring and/or SQL's @c bytea type. + */ + //@{ + + /// Execute a prepared statement, with optional arguments. + template<typename ...Args> + result exec_prepared(const std::string &statement, Args&&... args) + { + return internal_exec_prepared( + statement, internal::params(std::forward<Args>(args)...), result_format::text); + } + + /// Execute a prepared statement, with optional arguments. + template<typename ...Args> + result exec_prepared_binary(const std::string &statement, Args&&... args) + { + return internal_exec_prepared( + statement, internal::params(std::forward<Args>(args)...), result_format::binary); + } + + /// Execute a prepared statement, and expect a single-row result. + /** @throw pqxx::unexpected_rows if the result was not exactly 1 row. + */ + template<typename ...Args> + row exec_prepared1(const std::string &statement, Args&&... args) + { + return exec_prepared_n(1, statement, std::forward<Args>(args)...).front(); + } + + /// Execute a prepared statement, and expect a result with zero rows. + /** @throw pqxx::unexpected_rows if the result contained rows. + */ + template<typename ...Args> + result exec_prepared0(const std::string &statement, Args&&... args) + { + return exec_prepared_n(0, statement, std::forward<Args>(args)...); + } + + /// Execute a prepared statement, expect a result with given number of rows. + /** @throw pqxx::unexpected_rows if the result did not contain exactly the + * given number of rows. + */ + template<typename ...Args> + result exec_prepared_n( + size_t rows, + const std::string &statement, + Args&&... args) + { + const auto r = exec_prepared(statement, std::forward<Args>(args)...); + check_rowcount_prepared(statement, rows, r.size()); + return r; + } + + /// Execute prepared statement. @deprecated Use exec_prepared instead. + /** Just like param_declaration is a helper class that lets you tag parameter + * declarations onto the statement declaration, the invocation class returned + * here lets you tag parameter values onto the call: + * + * @code + * result run_mystatement(transaction_base &T) + * { + * return T.exec_prepared("mystatement", "param1", 2, nullptr, 4); + * } + * @endcode + * + * Here, parameter 1 (written as "<tt>$1</tt>" in the statement's body) is a + * string that receives the value "param1"; the second parameter is an integer + * with the value 2; the third receives a null, making its type irrelevant; + * and number 4 again is an integer. The ultimate invocation of exec() is + * essential; if you forget this, nothing happens. + * + * To see whether any prepared statement has been defined under a given name, + * use: + * + * @code + * T.prepared("mystatement").exists() + * @endcode + * + * @warning Do not try to execute a prepared statement manually through direct + * SQL statements. This is likely not to work, and even if it does, is likely + * to be slower than using the proper libpqxx functions. Also, libpqxx knows + * how to emulate prepared statements if some part of the infrastructure does + * not support them. + * + * @warning Actual definition of the prepared statement on the backend may be + * deferred until its first use, which means that any errors in the prepared + * statement may not show up until it is executed--and perhaps abort the + * ongoing transaction in the process. + * + * If you leave out the statement name, the call refers to the nameless + * statement instead. + */ + PQXX_DEPRECATED prepare::invocation + prepared(const std::string &statement=std::string{}); + + //@} + + /** + * @name Error/warning output + */ + //@{ + /// Have connection process warning message + void process_notice(const char Msg[]) const //[t14] + { m_conn.process_notice(Msg); } + /// Have connection process warning message + void process_notice(const std::string &Msg) const //[t14] + { m_conn.process_notice(Msg); } + //@} + + /// Connection this transaction is running in + connection_base &conn() const { return m_conn; } //[t04] + + /// Set session variable in this connection + /** The new value is typically forgotten if the transaction aborts. + * However nontransaction is an exception to this rule: in that case the set + * value will be kept regardless. Also, if the connection ever needs to be + * recovered, a value you set in a nontransaction will not be restored. + * @param Var The variable to set + * @param Val The new value to store in the variable + */ + void set_variable(const std::string &Var, const std::string &Val); //[t61] + + /// Get currently applicable value of variable + /** First consults an internal cache of variables that have been set (whether + * in the ongoing transaction or in the connection) using the set_variable + * functions. If it is not found there, the database is queried. + * + * @warning Do not mix the set_variable with raw "SET" queries, and do not + * try to set or get variables while a pipeline or table stream is active. + * + * @warning This function used to be declared as @c const but isn't anymore. + */ + std::string get_variable(const std::string &); //[t61] + +protected: + /// Create a transaction (to be called by implementation classes only) + /** The optional name, if nonempty, must begin with a letter and may contain + * letters and digits only. + * + * @param c The connection that this transaction is to act on. + * @param direct Running directly in connection context (i.e. not nested)? + */ + explicit transaction_base(connection_base &c, bool direct=true); + + /// Begin transaction (to be called by implementing class) + /** Will typically be called from implementing class' constructor. + */ + void Begin(); + + /// End transaction. To be called by implementing class' destructor + void End() noexcept; + + /// To be implemented by derived implementation class: start transaction + virtual void do_begin() =0; + /// To be implemented by derived implementation class: perform query + virtual result do_exec(const char Query[]) =0; + /// To be implemented by derived implementation class: commit transaction + virtual void do_commit() =0; + /// To be implemented by derived implementation class: abort transaction + virtual void do_abort() =0; + + // For use by implementing class: + + /// Execute query on connection directly + /** + * @param C Query or command to execute + * @param Retries Number of times to retry the query if it fails. Be + * extremely careful with this option; if you retry in the middle of a + * transaction, you may be setting up a new connection transparently and + * executing the latter part of the transaction without a backend transaction + * being active (and with the former part aborted). + */ + result direct_exec(const char C[], int Retries=0); + + /// Forget about any reactivation-blocking resources we tried to allocate + void reactivation_avoidance_clear() noexcept + {m_reactivation_avoidance.clear();} + +protected: + /// Resources allocated in this transaction that make reactivation impossible + /** This number may be negative! + */ + internal::reactivation_avoidance_counter m_reactivation_avoidance; + +private: + /* A transaction goes through the following stages in its lifecycle: + * <ul> + * <li> nascent: the transaction hasn't actually begun yet. If our connection + * fails at this stage, it may recover and the transaction can attempt to + * establish itself again. + * <li> active: the transaction has begun. Since no commit command has been + * issued, abortion is implicit if the connection fails now. + * <li> aborted: an abort has been issued; the transaction is terminated and + * its changes to the database rolled back. It will accept no further + * commands. + * <li> committed: the transaction has completed successfully, meaning that a + * commit has been issued. No further commands are accepted. + * <li> in_doubt: the connection was lost at the exact wrong time, and there + * is no way of telling whether the transaction was committed or aborted. + * </ul> + * + * Checking and maintaining state machine logic is the responsibility of the + * base class (ie., this one). + */ + enum Status + { + st_nascent, + st_active, + st_aborted, + st_committed, + st_in_doubt + }; + + /// Make sure transaction is opened on backend, if appropriate + PQXX_PRIVATE void activate(); + + PQXX_PRIVATE void CheckPendingError(); + + template<typename T> bool parm_is_null(T *p) const noexcept + { return p == nullptr; } + template<typename T> bool parm_is_null(T) const noexcept + { return false; } + + result internal_exec_prepared( + const std::string &statement, + const internal::params &args, + result_format format); + + result internal_exec_params( + const std::string &query, + const internal::params &args); + + /// Throw unexpected_rows if prepared statement returned wrong no. of rows. + void check_rowcount_prepared( + const std::string &statement, + size_t expected_rows, + size_t actual_rows); + + /// Throw unexpected_rows if wrong row count from parameterised statement. + void check_rowcount_params( + size_t expected_rows, size_t actual_rows); + + friend class pqxx::internal::gate::transaction_transactionfocus; + PQXX_PRIVATE void register_focus(internal::transactionfocus *); + PQXX_PRIVATE void unregister_focus(internal::transactionfocus *) noexcept; + PQXX_PRIVATE void register_pending_error(const std::string &) noexcept; + + friend class pqxx::internal::gate::transaction_tablereader; + friend class pqxx::internal::gate::transaction_stream_from; + PQXX_PRIVATE void BeginCopyRead(const std::string &, const std::string &); + bool read_copy_line(std::string &); + + friend class pqxx::internal::gate::transaction_tablewriter; + friend class pqxx::internal::gate::transaction_stream_to; + PQXX_PRIVATE void BeginCopyWrite( + const std::string &Table, + const std::string &Columns); + void write_copy_line(const std::string &); + void end_copy_write(); + + friend class pqxx::internal::gate::transaction_subtransaction; + + connection_base &m_conn; + + internal::unique<internal::transactionfocus> m_focus; + Status m_status = st_nascent; + bool m_registered = false; + std::map<std::string, std::string> m_vars; + std::string m_pending_error; +}; + +} // namespace pqxx + +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/transactor b/contrib/libs/libpqxx/include/pqxx/transactor new file mode 100644 index 0000000000..658551f9b6 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/transactor @@ -0,0 +1,6 @@ +/** pqxx::transactor class. + * + * pqxx::transactor is a framework-style wrapper for safe transactions. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/transactor.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/transactor.hxx b/contrib/libs/libpqxx/include/pqxx/transactor.hxx new file mode 100644 index 0000000000..5aba0193cb --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/transactor.hxx @@ -0,0 +1,274 @@ +/* Transactor framework, a wrapper for safely retryable transactions. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_TRANSACTOR +#define PQXX_H_TRANSACTOR + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +#include "pqxx/connection_base.hxx" +#include "pqxx/transaction.hxx" + + +// Methods tested in eg. test module test01 are marked with "//[t01]". + +namespace pqxx +{ +/** + * @defgroup transactor Transactor framework + * + * Sometimes a transaction can fail for completely transient reasons, such as a + * conflict with another transaction in SERIALIZABLE isolation. The right way + * to handle those failures is often just to re-run the transaction from + * scratch. + * + * For example, your REST API might be handling each HTTP request in its own + * database transaction, and if this kind of transient failure happens, you + * simply want to "replay" the whole request, in a fresh transaction. + * + * You won't necessarily want to execute the exact same SQL commands with the + * exact same data. Some of your SQL statements may depend on state that can + * vary between retries. So instead of dumbly replaying the SQL, you re-run + * the same application code that produced those SQL commands. + * + * The transactor framework makes it a little easier for you to do this safely, + * and avoid typical pitfalls. You encapsulate the work that you want to do + * into a callable that you pass to the @c perform function. + * + * Here's how it works. You write your transaction code as a lambda or + * function, which creates its own transaction object, does its work, and + * commits at the end. You pass that callback to @c pqxx::perform, which runs + * it for you. + * + * If there's a failure inside your callback, there will be an exception. Your + * transaction object goes out of scope and gets destroyed, so that it aborts + * implicitly. Seeing this, @c perform tries running your callback again. It + * stops doing that when the callback succeeds, or when it has failed too many + * times, or when there's an error that leaves the database in an unknown + * state, such as a lost connection just while we're waiting for the database + * to confirm a commit. It all depends on the type of exception. + * + * The callback takes no arguments. If you're using lambdas, the easy way to + * pass arguments is for the lambda to "capture" them from your variables. Or, + * if you're using functions, you may want to use @c std::bind. + * + * Once your callback succeeds, it can return a result, and @c perform will + * return that result back to you. + */ +//@{ + +/// Simple way to execute a transaction with automatic retry. +/** + * Executes your transaction code as a callback. Repeats it until it completes + * normally, or it throws an error other than the few libpqxx-generated + * exceptions that the framework understands, or after a given number of failed + * attempts, or if the transaction ends in an "in-doubt" state. + * + * (An in-doubt state is one where libpqxx cannot determine whether the server + * finally committed a transaction or not. This can happen if the network + * connection to the server is lost just while we're waiting for its reply to + * a "commit" statement. The server may have completed the commit, or not, but + * it can't tell you because there's no longer a connection. + * + * Using this still takes a bit of care. If your callback makes use of data + * from the database, you'll probably have to query that data within your + * callback. If the attempt to perform your callback fails, and the framework + * tries again, you'll be in a new transaction and the data in the database may + * have changed under your feet. + * + * Also be careful about changing variables or data structures from within + * your callback. The run may still fail, and perhaps get run again. The + * ideal way to do it (in most cases) is to return your result from your + * callback, and change your program's data state only after @c perform + * completes successfully. + * + * @param callback Transaction code that can be called with no arguments. + * @param attempts Maximum number of times to attempt performing callback. + * Must be greater than zero. + * @return Whatever your callback returns. + */ +template<typename TRANSACTION_CALLBACK> +inline auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3) + -> decltype(callback()) +{ + if (attempts <= 0) + throw std::invalid_argument{ + "Zero or negative number of attempts passed to pqxx::perform()."}; + + for (; attempts > 0; --attempts) + { + try + { + return callback(); + } + catch (const in_doubt_error &) + { + // Not sure whether transaction went through or not. The last thing in + // the world that we should do now is try again! + throw; + } + catch (const statement_completion_unknown &) + { + // Not sure whether our last statement succeeded. Don't risk running it + // again. + throw; + } + catch (const broken_connection &) + { + // Connection failed. Definitely worth retrying. + if (attempts <= 1) throw; + continue; + } + catch (const transaction_rollback &) + { + // Some error that may well be transient, such as serialization failure + // or deadlock. Worth retrying. + if (attempts <= 1) throw; + continue; + } + } + throw pqxx::internal_error{"No outcome reached on perform()."}; +} + +/// @deprecated Pre-C++11 wrapper for automatically retrying transactions. +/** + * Pass an object of your transactor-based class to connection_base::perform() + * to execute the transaction code embedded in it. + * + * connection_base::perform() is actually a template, specializing itself to any + * transactor type you pass to it. This means you will have to pass it a + * reference of your object's ultimate static type; runtime polymorphism is + * not allowed. Hence the absence of virtual methods in transactor. The + * exact methods to be called at runtime *must* be resolved at compile time. + * + * Your transactor-derived class must define a copy constructor. This will be + * used to create a "clean" copy of your transactor for every attempt that + * perform() makes to run it. + */ +template<typename TRANSACTION=transaction<read_committed>> class transactor +{ +public: + using argument_type = TRANSACTION; + PQXX_DEPRECATED explicit transactor( //[t04] + const std::string &TName="transactor") : + m_name{TName} { } + + /// Overridable transaction definition; insert your database code here + /** The operation will be retried if the connection to the backend is lost or + * the operation fails, but not if the connection is broken in such a way as + * to leave the library in doubt as to whether the operation succeeded. In + * that case, an in_doubt_error will be thrown. + * + * Recommended practice is to allow this operator to modify only the + * transactor itself, and the dedicated transaction object it is passed as an + * argument. This is what makes side effects, retrying etc. controllable in + * the transactor framework. + * @param T Dedicated transaction context created to perform this operation. + */ + void operator()(TRANSACTION &T); //[t04] + + // Overridable member functions, called by connection_base::perform() if an + // attempt to run transaction fails/succeeds, respectively, or if the + // connection is lost at just the wrong moment, goes into an indeterminate + // state. Use these to patch up runtime state to match events, if needed, or + // to report failure conditions. + + /// Optional overridable function to be called if transaction is aborted + /** This need not imply complete failure; the transactor will automatically + * retry the operation a number of times before giving up. on_abort() will be + * called for each of the failed attempts. + * + * One parameter is passed in by the framework: an error string describing why + * the transaction failed. This will also be logged to the connection's + * notice processor. + */ + void on_abort(const char[]) noexcept {} //[t13] + + /// Optional overridable function to be called after successful commit + /** If your on_commit() throws an exception, the actual back-end transaction + * will remain committed, so any changes in the database remain regardless of + * how this function terminates. + */ + void on_commit() {} //[t07] + + /// Overridable function to be called when "in doubt" about outcome + /** This may happen if the connection to the backend is lost while attempting + * to commit. In that case, the backend may have committed the transaction + * but is unable to confirm this to the frontend; or the transaction may have + * failed, causing it to be rolled back, but again without acknowledgement to + * the client program. The best way to deal with this situation is typically + * to wave red flags in the user's face and ask him to investigate. + * + * The robusttransaction class is intended to reduce the chances of this + * error occurring, at a certain cost in performance. + * @see robusttransaction + */ + void on_doubt() noexcept {} //[t13] + + /// The transactor's name. + std::string name() const { return m_name; } //[t13] + +private: + std::string m_name; +}; + + +template<typename TRANSACTOR> +inline void connection_base::perform( + const TRANSACTOR &T, + int Attempts) +{ + if (Attempts <= 0) return; + + bool Done = false; + + // Make attempts to perform T + do + { + --Attempts; + + // Work on a copy of T2 so we can restore the starting situation if need be + TRANSACTOR T2{T}; + try + { + typename TRANSACTOR::argument_type X{*this, T2.name()}; + T2(X); + X.commit(); + Done = true; + } + catch (const in_doubt_error &) + { + // Not sure whether transaction went through or not. The last thing in + // the world that we should do now is retry. + T2.on_doubt(); + throw; + } + catch (const std::exception &e) + { + // Could be any kind of error. + T2.on_abort(e.what()); + if (Attempts <= 0) throw; + continue; + } + catch (...) + { + // Don't try to forge ahead if we don't even know what happened + T2.on_abort("Unknown exception"); + throw; + } + + T2.on_commit(); + } while (not Done); +} +} // namespace pqxx +//@} +#include "pqxx/compiler-internal-post.hxx" +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/types.hxx b/contrib/libs/libpqxx/include/pqxx/types.hxx new file mode 100644 index 0000000000..49d1a0d1f0 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/types.hxx @@ -0,0 +1,57 @@ +/** + * Basic type aliases and forward declarations. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this + * mistake, or contact the author. + */ +#ifndef PQXX_H_TYPES +#define PQXX_H_TYPES + +#include <cstddef> + +namespace pqxx +{ +/// Number of rows in a result set. +using result_size_type = unsigned long; + +/// Difference between result sizes. +using result_difference_type = signed long; + +/// Number of fields in a row of database data. +using row_size_type = unsigned int; + +/// Difference between row sizes. +using row_difference_type = signed int; + +/// Number of bytes in a field of database data. +using field_size_type = std::size_t; + +/// Number of bytes in a large object. (Unusual: it's signed.) +using large_object_size_type = long; + + +// Forward declarations, to help break compilation dependencies. +// These won't necessarily include all classes in libpqxx. +class binarystring; +class connectionpolicy; +class connection_base; +class const_result_iterator; +class const_reverse_result_iterator; +class const_reverse_row_iterator; +class const_row_iterator; +class dbtransaction; +class field; +class largeobjectaccess; +class notification_receiver; +class range_error; +class result; +class row; +class tablereader; +class transaction_base; + +} // namespace pqxx + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/util b/contrib/libs/libpqxx/include/pqxx/util new file mode 100644 index 0000000000..6ec38ac111 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/util @@ -0,0 +1,5 @@ +/** Various utility definitions for libpqxx. + */ +// Actual definitions in .hxx file so editors and such recognize file type +#include "pqxx/util.hxx" + diff --git a/contrib/libs/libpqxx/include/pqxx/util.hxx b/contrib/libs/libpqxx/include/pqxx/util.hxx new file mode 100644 index 0000000000..86a9134c38 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/util.hxx @@ -0,0 +1,309 @@ +/** Various utility definitions for libpqxx. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/util instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_UTIL +#define PQXX_H_UTIL + +#include "pqxx/compiler-public.hxx" + +#include <cstdio> +#include <cctype> +#include <iterator> +#include <memory> +#include <stdexcept> +#include <string> +#include <type_traits> +#include <typeinfo> +#include <vector> + +#include "pqxx/strconv.hxx" + + +/// The home of all libpqxx classes, functions, templates, etc. +namespace pqxx {} + +#include <pqxx/internal/libpq-forward.hxx> + + +namespace pqxx +{ +/// Suppress compiler warning about an unused item. +template<typename T> inline void ignore_unused(T) {} + + +/// Descriptor of library's thread-safety model. +/** This describes what the library knows about various risks to thread-safety. + */ +struct PQXX_LIBEXPORT thread_safety_model +{ + /// @deprecated Is error reporting thread-safe? Now always true. + bool have_safe_strerror = true; + + /// Is the underlying libpq build thread-safe? + bool safe_libpq; + + /// @deprecated Query cancel is always thread-safe now. + bool safe_query_cancel = true; + + /// @deprecated Always thread-safe to copy a 'result' or 'binarystring' now. + bool safe_result_copy = true; + + /// Is Kerberos thread-safe? + /** @warning Is currently always @c false. + * + * If your application uses Kerberos, all accesses to libpqxx or Kerberos must + * be serialized. Confine their use to a single thread, or protect it with a + * global lock. + */ + bool safe_kerberos; + + /// A human-readable description of any thread-safety issues. + std::string description; +}; + + +/// Describe thread safety available in this build. +PQXX_LIBEXPORT thread_safety_model describe_thread_safety() noexcept; + + +/// The "null" oid. +constexpr oid oid_none = 0; + + +/** + * @defgroup utility Utility functions + */ +//@{ + +/// Represent sequence of values as a string, joined by a given separator. +/** + * Use this to turn e.g. the numbers 1, 2, and 3 into a string "1, 2, 3". + * + * @param sep separator string (to be placed between items) + * @param begin beginning of items sequence + * @param end end of items sequence + * @param access functor defining how to dereference sequence elements + */ +template<typename ITER, typename ACCESS> inline +std::string separated_list( //[t00] + const std::string &sep, + ITER begin, + ITER end, + ACCESS access) +{ + std::string result; + if (begin != end) + { + result = to_string(access(begin)); + for (++begin; begin != end; ++begin) + { + result += sep; + result += to_string(access(begin)); + } + } + return result; +} + + +/// Render sequence as a string, using given separator between items. +template<typename ITER> inline std::string +separated_list(const std::string &sep, ITER begin, ITER end) //[t00] + { return separated_list(sep, begin, end, [](ITER i){ return *i; }); } + + +/// Render items in a container as a string, using given separator. +template<typename CONTAINER> inline auto +separated_list(const std::string &sep, const CONTAINER &c) //[t10] + /* + Always std::string; necessary because SFINAE doesn't work with the + contents of function bodies, so the check for iterability has to be in + the signature. + */ + -> typename std::enable_if< + ( + not std::is_void<decltype(std::begin(c))>::value + and not std::is_void<decltype(std::end(c))>::value + ), + std::string + >::type +{ + return separated_list(sep, std::begin(c), std::end(c)); +} + + +/// Render items in a tuple as a string, using given separator. +template< + typename TUPLE, + std::size_t INDEX=0, + typename ACCESS, + typename std::enable_if< + (INDEX == std::tuple_size<TUPLE>::value-1), + int + >::type=0 +> +inline std::string +separated_list( + const std::string & /* sep */, + const TUPLE &t, + const ACCESS& access +) +{ + return to_string(access(&std::get<INDEX>(t))); +} + +template< + typename TUPLE, + std::size_t INDEX=0, + typename ACCESS, + typename std::enable_if< + (INDEX < std::tuple_size<TUPLE>::value-1), + int + >::type=0 +> +inline std::string +separated_list(const std::string &sep, const TUPLE &t, const ACCESS& access) +{ + return + to_string(access(&std::get<INDEX>(t))) + + sep + + separated_list<TUPLE, INDEX+1>(sep, t, access); +} + +template< + typename TUPLE, + std::size_t INDEX=0, + typename std::enable_if< + (INDEX <= std::tuple_size<TUPLE>::value), + int + >::type=0 +> +inline std::string +separated_list(const std::string &sep, const TUPLE &t) +{ + return separated_list(sep, t, [](const TUPLE &tup){return *tup;}); +} +//@} + + +/// Private namespace for libpqxx's internal use; do not access. +/** This namespace hides definitions internal to libpqxx. These are not + * supposed to be used by client programs, and they may change at any time + * without notice. + * + * Conversely, if you find something in this namespace tremendously useful, by + * all means do lodge a request for its publication. + * + * @warning Here be dragons! + */ +namespace internal +{ +PQXX_LIBEXPORT void freepqmem(const void *) noexcept; +template<typename P> inline void freepqmem_templated(P *p) noexcept +{ + freepqmem(p); +} + +PQXX_LIBEXPORT void freemallocmem(const void *) noexcept; +template<typename P> inline void freemallocmem_templated(P *p) noexcept +{ + freemallocmem(p); +} + + +/// Helper base class: object descriptions for error messages and such. +/** + * Classes derived from namedclass have a class name (such as "transaction"), + * an optional object name (such as "delete-old-logs"), and a description + * generated from the two names (such as "transaction delete-old-logs"). + * + * The class name is dynamic here, in order to support inheritance hierarchies + * where the exact class name may not be known statically. + * + * In inheritance hierarchies, make namedclass a virtual base class so that + * each class in the hierarchy can specify its own class name in its + * constructors. + */ +class PQXX_LIBEXPORT namedclass +{ +public: + explicit namedclass(const std::string &Classname) : + m_classname{Classname}, + m_name{} + { + } + + namedclass(const std::string &Classname, const std::string &Name) : + m_classname{Classname}, + m_name{Name} + { + } + + /// Object name, or the empty string if no name was given. + const std::string &name() const noexcept { return m_name; } //[t01] + + /// Class name. + const std::string &classname() const noexcept //[t73] + { return m_classname; } + + /// Combination of class name and object name; or just class name. + std::string description() const; + +private: + std::string m_classname, m_name; +}; + + +PQXX_PRIVATE void CheckUniqueRegistration( + const namedclass *New, const namedclass *Old); +PQXX_PRIVATE void CheckUniqueUnregistration( + const namedclass *New, const namedclass *Old); + + +/// Ensure proper opening/closing of GUEST objects related to a "host" object +/** Only a single GUEST may exist for a single host at any given time. GUEST + * must be derived from namedclass. + */ +template<typename GUEST> +class unique +{ +public: + unique() =default; + unique(const unique &) =delete; + unique &operator=(const unique &) =delete; + + GUEST *get() const noexcept { return m_guest; } + + void register_guest(GUEST *G) + { + CheckUniqueRegistration(G, m_guest); + m_guest = G; + } + + void unregister_guest(GUEST *G) + { + CheckUniqueUnregistration(G, m_guest); + m_guest = nullptr; + } + +private: + GUEST *m_guest = nullptr; +}; + + +/// Sleep for the given number of seconds +/** May return early, e.g. when interrupted by a signal. Completes instantly if + * a zero or negative sleep time is requested. + */ +PQXX_LIBEXPORT void sleep_seconds(int); + +} // namespace internal +} // namespace pqxx + +#endif diff --git a/contrib/libs/libpqxx/include/pqxx/version b/contrib/libs/libpqxx/include/pqxx/version new file mode 100644 index 0000000000..5f7ab6a14e --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/version @@ -0,0 +1,4 @@ +/** libpqxx version info. + */ +// Actual definitions in .hxx file so editors and such recognize file type. +#include "pqxx/version.hxx" diff --git a/contrib/libs/libpqxx/include/pqxx/version.hxx b/contrib/libs/libpqxx/include/pqxx/version.hxx new file mode 100644 index 0000000000..6fe982d433 --- /dev/null +++ b/contrib/libs/libpqxx/include/pqxx/version.hxx @@ -0,0 +1,57 @@ +/** Version info for libpqxx. + * + * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/version instead. + * + * Copyright (c) 2000-2019, Jeroen T. Vermeulen. + * + * See COPYING for copyright license. If you did not receive a file called + * COPYING with this source code, please notify the distributor of this mistake, + * or contact the author. + */ +#ifndef PQXX_H_VERSION + +#include "pqxx/compiler-public.hxx" +#include "pqxx/compiler-internal-pre.hxx" + +/// Full libpqxx version string. +#define PQXX_VERSION "6.4.4" +/// Library ABI version. +#define PQXX_ABI "6.4" + +/// Major version number. +#define PQXX_VERSION_MAJOR 6 +/// Minor version number. +#define PQXX_VERSION_MINOR 4 + +namespace pqxx +{ +namespace internal +{ +/// Library version check stub. +/** Helps detect version mismatches between libpqxx headers and the libpqxx + * library binary. + * + * Sometimes users run into trouble linking their code against libpqxx because + * they build their own libpqxx, but the system also has a different version + * installed. The declarations in the headers against which they compile their + * code will differ from the ones used to build the libpqxx version they're + * using, leading to confusing link errors. The solution is to generate a link + * error when the libpqxx binary is not the same version as the libpqxx headers + * used to compile the code. + * + * This is a template declaration, but its only actual definition is a + * sepcialisation for the current library version. The definition is in the + * libpqxx binary, so it's based on the version as found in the binary. The + * headers contain a call to the function, specialised on the libpqxx version + * as found in the headers. (The library build process will use its own local + * headers even if another version of the headers is installed on the system.) + * + * If the libpqxx binary was compiled for a different version than the user's + * code, linking will fail with an error: @c check_library_version will not + * exist for the given version number. + */ +template<int, int> PQXX_LIBEXPORT int check_library_version() noexcept; +} +} +#include "pqxx/compiler-internal-post.hxx" +#endif 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; +} +} +} diff --git a/contrib/libs/libpqxx/ya.make b/contrib/libs/libpqxx/ya.make new file mode 100644 index 0000000000..cd0e48d9a2 --- /dev/null +++ b/contrib/libs/libpqxx/ya.make @@ -0,0 +1,66 @@ +# Generated by devtools/yamaker from nixpkgs 22.05. + +LIBRARY() + +LICENSE(BSD-3-Clause) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +VERSION(6.4.5) + +ORIGINAL_SOURCE(https://github.com/jtv/libpqxx/archive/6.4.5.tar.gz) + +PEERDIR( + contrib/libs/libpq +) + +ADDINCL( + GLOBAL contrib/libs/libpqxx/include + contrib/libs/libpq + contrib/libs/libpq/src/interfaces/libpq +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +CFLAGS( + -DHAVE_CONFIG_H +) + +SRCS( + src/array.cxx + src/binarystring.cxx + src/connection.cxx + src/connection_base.cxx + src/cursor.cxx + src/dbtransaction.cxx + src/encodings.cxx + src/errorhandler.cxx + src/except.cxx + src/field.cxx + src/largeobject.cxx + src/nontransaction.cxx + src/notification.cxx + src/pipeline.cxx + src/prepared_statement.cxx + src/result.cxx + src/robusttransaction.cxx + src/row.cxx + src/sql_cursor.cxx + src/statement_parameters.cxx + src/strconv.cxx + src/stream_base.cxx + src/stream_from.cxx + src/stream_to.cxx + src/subtransaction.cxx + src/tablereader.cxx + src/tablestream.cxx + src/tablewriter.cxx + src/transaction.cxx + src/transaction_base.cxx + src/util.cxx + src/version.cxx +) + +END() |