The PostgreSQL client API in modern C++

Overview

C++ client API to PostgreSQL {#mainpage}

Dmitigr Pgfe (PostGres FrontEnd, hereinafter referred to as Pgfe) - is a C++ client API to PostgreSQL servers. The development is focused on easines and robustness of use. At the same time, everything possible is being done to ensure that the performance is at its best. Pgfe is a part of the Dmitigr Cefeika project, but also available as a standalone library here.

Upcoming release 2.0

ATTENTION, API breaking changes starting from commit 62ceba3!

I'm currently working on Pgfe 2.0. The current stage is early alpha. Nonetheless, I recommend to switch to the new API despite the fact that it's still a subject to change while work on release 2.0 is in progress. (Although I don't think the changes will be significant.) Efforts will be made to make the API of Pgfe 2.0 as stable as possible.

Documentation

The Doxygen-generated documentation is located here. There is overview class diagram.

Hello, World

#include <dmitigr/pgfe.hpp>
#include <cstdio>

namespace pgfe = dmitigr::pgfe;

int main() try {
  // Making the connection.
  pgfe::Connection conn{pgfe::Connection_options{pgfe::Communication_mode::net}
    .net_hostname("localhost").database("pgfe_test")
    .username("pgfe_test").password("pgfe_test")};

  // Connecting.
  conn.connect();

  // Using Pgfe's helpers.
  using pgfe::a;  // for named arguments
  using pgfe::to; // for data conversions

  // Executing statement with positional parameters.
  conn.execute([](auto&& r)
  {
    std::printf("Number %i\n", to<int>(r.data()));
  }, "select generate_series($1::int, $2::int)", 1, 3);

  // Execute statement with named parameters.
  conn.execute([](auto&& r)
  {
    std::printf("Range [%i, %i]\n", to<int>(r["b"]), to<int>(r["e"]));
  },"select :begin b, :end e", a{"end", 1}, a{"begin", 0});

  // Prepare and execute the statement.
  auto* const ps = conn.prepare("select $1::int i");
  for (int i = 0; i < 3; ++i)
    ps->execute([](auto&& r){ std::printf("%i\n", to<int>(r["i"])); }, i);

  // Invoking the function.
  conn.invoke([](auto&& r)
  {
    std::printf("cos(%f) = %f\n", .5f, to<float>(r.data()));
  }, "cos", .5f);

  // Provoking the syntax error.
  conn.execute("provoke syntax error");
 } catch (const pgfe::Server_exception& e) {
  assert(e.error().condition() == pgfe::Server_errc::c42_syntax_error);
  std::printf("Error %s is handled as expected.\n", e.error().sqlstate());
 } catch (const std::exception& e) {
  std::printf("Oops: %s\n", e.what());
  return 1;
 }

Features

  • fast (negligible overhead compared to libpq);
  • can be used as header-only library;
  • work with database connections (in both blocking and non-blocking IO manner);
  • execute prepared statements (named parameters are supported);
  • conveniently call functions and procedures;
  • conveniently handle errors by either via exceptions or error conditions;
  • conveniently work with large objects;
  • enum entry for each predefined SQLSTATE;
  • easily convert the data from the client side representation to the server side representation and vice versa (conversions of multidimensional PostgreSQL arrays to/from any combinations of STL containers are supported out of the box!);
  • dynamically construct SQL queries;
  • separate SQL and C++ code (e.g., by placing SQL code into a text file);
  • simple and thread-safe connection pool.

Usage

Please, see Cefeika Usage section for hints how to link Pgfe.

Quick tutorial

Logically, Pgfe library consists of the following parts:

  • main (client/server communication);
  • data types conversions;
  • errors (exceptions and error conditions);
  • utilities.

The API is defined in the namespace dmitigr::pgfe. In this tutorial all the names are not explicitly qualified by this namespace.

Connecting to a server

By using class Connection_options it's easy to specify the required connection options:

// Example 1. Making connection options.
auto make_options()
{
  return Connection_options{Communication_mode::net}
    .net_hostname("localhost")
    .database("db")
    .username("user")
    .password("password");
}

By using class Connection it's easy to connect to the PostgreSQL server:

// Example 2. Making ready-to-use connection.
auto make_connection(const Connection_options& opts = {})
{
  Connection conn{opts};
  conn.connect(); // connect synchronously (in blocking manner)
  return conn; // return the ready-to-use instance
}

Executing SQL commands

Since v20alpha2 only extended query protocol is used under the hood to execute SQL commands. SQL commands can be executed and processed either synchronously or in non-blocking IO maner, i.e. without need of waiting a server response(-s), and thus, without thread blocking. In the latter case the methods of the class Connection with the suffix _nio shall be used.

With Pgfe it's easy to execute single commands:

// Example 3. Executing single commands.
void foo(Connection& conn)
{
  conn.execute("begin");
  conn.execute("create temp table num(val integer not null)");
  conn.execute([](auto&& row)
  {
    using dmitigr::pgfe::to;    // see "Data conversions" section for details
    auto val = to<int>(row[0]); // converts the value of num.val to int
    std::cout << val << "\n";   // prints the just inserted integers
  }, "insert into num select generate_series(1,3) returning val");
  conn.execute("rollback");
}

Extended query protocol used by Pgfe is based on prepared statements. In Pgfe prepared statements can be parameterized with either positional or named parameters. The class Sql_string provides functionality for constructing SQL statements, providing support for named parameters, as well as functionality for direct parameters replacement with any SQL statement to generate complex SQL expressions dynamically.

When using "extended query" protocol in its simplest form unnamed statements are prepared implicitly:

// Example 4. Preparing unnamed statements (`BEGIN`, `SELECT`, `ROLLBACK`) implicitly.
void foo(Connection& conn)
{
  conn.execute("begin");
  conn.execute([](auto&& row)
  {
    using dmitigr::pgfe::to;            // see "Data conversions" section for details
    auto val = to<std::string>(row[0]); // converts the retrieved value to std::string
    std::cout << val << "\n";           // prints "Hi!\n"
  }, "select 'Hi!'");
  conn.execute("rollback");
}

It's also easy to use named parameters:

// Example 5. Using named parameters in statements.
void foo(Connection& conn)
{
  // Please note, the sequence of the specified named parameters doesn't matter,
  // and that "end" parameter is specified before "begin" parameter.
  conn.execute([](auto&& row)
  {
    std::printf("Range [%i, %i]\n", to<int>(row["b"]), to<int>(row["e"]));
  },"select :begin b, :end e", a{"end", 1}, a{"begin", 0});
}

Of course, the statement (named or unnamed) can be prepared explicitly:

// Example 6. Preparing the unnamed statement parameterized by named parameters.
void foo(Connection& conn)
{
  conn.prepare("select generate_series(:inf::int, :sup::int) num")
    ->bind("inf", 1)
    .bind("sup", 3)
    .execute([](auto&& row)
    {
      // Printing the just generated integers without type conversion
      std::printf("%s\n", row["num"].bytes());
    });
}

Invoking functions and calling procedures

Pgfe provides the convenient API for functions invoking or procedures calling: methods Connection::invoke(), Connection::invoke_unexpanded() and Connection::call() accordingly.

To illustrate the API the following function definition is used:

create function person_info(id integer, name text, age integer)
returns text language sql as
$$
  select format('id=%s name=%s age=%s', id, name, age);
$$;

Calling "person_info" by using positional notation:

// Example 7. Using positional notation.
void foo(Connection& conn)
{
  conn.invoke("person_info", 1, "Dmitry", 36);
  // ...
}

Calling "person_info" by using named notation:

// Example 8. Using named notation.
void foo(Connection& conn)
{
  using dmitigr::pgfe::a;
  conn.invoke("person_info", a{"name", "Dmitry"}, a{"age", 36}, a{"id", 1});
  // ...
}

Calling "person_info" by using mixed notation:

// Example 9. Using mixed notation.
void foo(Connection& conn)
{
  using dmitigr::pgfe::a;
  conn.invoke("person_info", 1, a{"age", 36}, a{"name", "Dmitry"});
  // ...
}

Data conversions

Pgfe provides the support of conversions only for fundamental and standard C++ types out of the box. Conversions for special PostgreSQL types such as Date/Time Types aren't provided out of the box, since many implementations of these types are possible at the client side. Instead it's up to the user to decide what implementation to use. (If such conversions are needed at all.) For example, the template structure Conversions can be easily specialized to convert the data between PostgreSQL Date/Time Types and types from the Boost.Date_Time library.

The abstract class Data is designed to provide the interface for:

  • the values of prepared statements' parameters;
  • the data retrieved from a PostgreSQL server.

The template structure Conversions are used by:

  • method Prepared_statement::bind(std::size_t, T&&) to perfrom data conversions from objects or type T to objects of type Data;
  • function to() to perform data conversions from objects of type Data to objects of the specified type T.

Pgfe provides the partial specialization of the template structure Conversions to convert from/to PostgreSQL arrays (including multidimensional arrays!) representation to any combination of the STL containers out of the box! (At the moment, arrays conversions are only implemented for Data_format::text format.) In general, any PostgreSQL array can be represented as Container<Optional<T>>, where:

  • Container - is a template class of a container such as std::vector or std::list or std::deque;
  • Optional - is a template class of an optional value holder such as std::optional or boost::optional. The special value like std::nullopt represents the SQL NULL;
  • T - is the type of elements of the array. It can be Container<Optional<U>> to represent the multidimensional array.

In case when all the elements of the array are not NULL, it can be represented as the container with elements of type T rather than Optional<T>. But in case when the source array (which comes from the PostgreSQL server) contain at least one NULL element a runtime exception will be thrown. Summarizing:

  • the types Container<Optional<T>>, Container<Optional<Container<Optional<T>>>>, ... can be used to represent N-dimensional arrays of T which may contain NULL values;

  • the types Container<T>, Container<Container<T>>, ... can be used to represent N-dimensional arrays of T which may not contain NULL values.

User-defined data conversions could be implemented by either:

  • overloading the operators operator<< and operator>> for std::ostream and std::istream respectively;
  • specializing the template structure Conversions. (With this approach overheads of standard IO streams can be avoided.)

Response processing

Server responses can be retrieved:

  • implicitly in blocking IO manner by using methods such as Connection::perform(), Connection::prepare(), Connection::execute() etc. Some of these methods has overloads for passing the callback which is called by Pgfe every time the row is retrieved from the server;
  • explicitly in blocking IO manner by using methods such as Connection::wait_response() and Connection::wait_response_throw() etc after the using methods with the suffix "_nio";
  • explicitly in non-blocking IO maner by using the methods such as Connection::read_input(), Connection::handle_input(), Connection::socket_readiness() etc after the using methods with suffix "_nio".

To initiate retrieving the first response in non-blocking IO manner methods of the class Connection with the suffix _nio must be used. Otherwise, Pgfe will wait for the first response and if that response is error, an instance of type Server_exception will be thrown. This object provides access to the object of type Error, which contains all the error details.

Server responses are represented by the classes inherited from Response:

  • errors are represented by the class Error. Each server error is identifiable by a SQLSTATE condition. In Pgfe each such a condition is represented by the member of the enumeration Server_errc, integrated to the framework for reporting errors provided by the standard library in <system_error>. Therefore, working with SQLSTATEs is as simple and safe as with std::error_condition and enumerated types, for example:
// Example 10. Catching the syntax error.
void foo(Connection& conn)
{
  try {
    conn.perform("provoke syntax error");
  } catch (const Server_exception& e) {
    assert(e.error().condition() == Server_errc::c42_syntax_error);
  }
}
  • rows are represented by the class Row, for example:
// Example 11. Processing the rows.
void foo(Connection& conn)
{
  conn.execute([](auto&& row)
  {
    using dmitigr::pgfe::to;
    auto name = to<std::string>(row["name"]);
    std::printf("%s\n", name.data());
  }, "select name from usr where id = $1", 3); // where id = 3
}
  • prepared statements are represented by the class Prepared_statement, for example:
// Example 12. Working with named prepared statement.
void foo(Connection& conn)
{
  // Prepare the named statement
  auto* int_gen = conn.prepare("select generate_series($1::int, $2::int)", "int_gen");

  // Defining the row processor
  auto process = [](auto&& row)
  {
    using dmitigr::pgfe::to;
    auto n = to<int>(row[0]);
    std::printf("%i\n", n);
  };

  // Execute for the first time
  int_gen->bind(1).bind(2).execute(process);
  // Execute for the second time
  int_gen->bind(10).bind(20).execute(process);
}
  • operation success indicators are represented by the class Completion, for example:
// Example 13. Using completion info.
void foo(Connection& conn)
{
  auto completion = conn.perform("begin");
  std::printf("%s\n", completion.operation_name()); // prints "BEGIN"
}

Signal handling

Server signals are represented by classes, inherited from Signal:

  • notices are represented by the class Notice;
  • notifications are represented by the class Notification.

Signals can be handled:

  • by using the signal handlers (see Connection::set_notice_handler(), Connection::set_notification_handler());

Notifications can also be handled in non-blocking IO maner, by using the method Connection::pop_notification().

Signal handlers, being set, called by Pgfe automatically when signals are retrieved. (Usually it happens upon waiting a response.) If no notification handler is set, notifications will be queued to the internal storage until popped up by method Connection::pop_notification(). Be aware, that if notification are not popped up from the internal storage it may cause memory exhaustion!

Dynamic SQL

The standard classes like std::string or std::ostringstream can be used to make SQL strings dynamically. However, in some cases it is more convenient to use the class Sql_string for this purpose. Consider the following statement:

select :expr::int, ':expr';

This SQL string has one named parameter expr and one string constant ':expr'. It's possible to replace the named parameters of the SQL string with another SQL string by using Sql_string::replace_parameter(), for example:

// Example 14. Extending the SQL statement.
void foo()
{
  Sql_string sql{"select :expr::int, ':expr'"};
  sql.replace_parameter("expr", "sin(:expr1::int), cos(:expr2::int)");
}

Now the original statement is modified and has two named parameters:

select sin(:expr1::int), cos(:expr2::int), ':expr'

Note, that the quoted string :expr is not affected by the replacement operation.

Working with SQL code separately of C++ code

This feature is based on the idea to store the SQL code in a separate place, such as a text file. Consider the following SQL input, which is consists of two SQL strings with an extra data specified by the dollar-quoted string constants in the related comments:

-- This is query 1
--
-- $id$plus-one$id$
select :n::int + 1, ';'; -- note, the semicolons in quotes are allowed!

/* This is query 2
 *
 * $id$minus-one$id$
 */
select :n::int - 1

These SQL strings can be easily accessed by using class Sql_vector:

// Example 15. Parsing file with SQL statements.

std::string read_file(const std::filesystem::path& path); // defined somewhere

void foo()
{
  const auto input = read_file("bunch.sql");
  Sql_vector bunch{input};
  auto* minus_one = bunch.find("id", "minus-one"); // select :n::int - 1
  auto*  plus_one = bunch.find("id",  "plus-one"); // select :n::int + 1, ';'
  // ...
}

Connection pool

Pgfe provides a simple connection pool implemented in class Connection_pool:

// Example 16. Using the connection pool.

inline std::unique_ptr<Connection_pool> pool;
Connection_options connection_options(); // defined somewhere.

int main()
{
  Connection_pool pool{2, connection_options()};
  pool.connect(); // opening up 2 connections
  {
    auto conn1 = pool.connection(); // 1st attempt to get the connection from pool
    assert(conn1);  // ok
    conn1.perform("select 1");
    auto conn2 = pool.connection(); // 2nd attempt to get the connection from pool
    assert(conn2);  // ok
    conn2.perform("select 2");
    auto conn3 = pool.connection(); // 3rd attempt to get the connection from pool
    assert(!conn3); // the pool is exhausted
  } // connections are returned back to the pool here
  auto conn = pool.connection();
  assert(conn); // ok
  pool.disconnect(); // done with the pool
}

Exceptions

Pgfe may throw:

  • an instance of the type std::logic_error when using assert() is not good enough (for example, when checking the assertion must be done regardless of value of NDEBUG upon build);
  • an instance of the types std::runtime_error or Client_exception when some kind of runtime error occured on the client side;
  • an instance of the type Server_exception when some error occured on the server side and IO blocking API is in use.

Thread safety

By default, if not explicitly documented, all functions and methods of Pgfe are not thread safe. Thus, in most cases, some of the synchronization mechanisms (like mutexes) must be used to work with the same object from several threads.

Dependencies

Pgfe is depends on the libpq library.

CMake options

The table below (one may need to use horizontal scrolling for full view) contains variables which can be passed to CMake for customization of the Pgfe library.

CMake variable Possible values Default on Unix Default on Windows
Defaults
DMITIGR_PGFE_CONNECTION_COMMUNICATION_MODE uds | net uds net
DMITIGR_PGFE_CONNECTION_UDS_DIRECTORY an absolute path /tmp unavailable
DMITIGR_PGFE_CONNECTION_UDS_REQUIRE_SERVER_PROCESS_USERNAME a string not set unavailable
DMITIGR_PGFE_CONNECTION_TCP_KEEPALIVES_ENABLED On | Off Off Off
DMITIGR_PGFE_CONNECTION_TCP_KEEPALIVES_IDLE non-negative number null (system default) null (system default)
DMITIGR_PGFE_CONNECTION_TCP_KEEPALIVES_INTERVAL non-negative number null (system default) null (system default)
DMITIGR_PGFE_CONNECTION_TCP_KEEPALIVES_COUNT non-negative number null (system default) null (system default)
DMITIGR_PGFE_CONNECTION_NET_ADDRESS IPv4 or IPv6 address 127.0.0.1 127.0.0.1
DMITIGR_PGFE_CONNECTION_NET_HOSTNAME a string localhost localhost
DMITIGR_PGFE_CONNECTION_PORT a number 5432 5432
DMITIGR_PGFE_CONNECTION_USERNAME a string postgres postgres
DMITIGR_PGFE_CONNECTION_DATABASE a string postgres postgres
DMITIGR_PGFE_CONNECTION_PASSWORD a string "" ""
DMITIGR_PGFE_CONNECTION_KERBEROS_SERVICE_NAME a string null (not used) null (not used)
DMITIGR_PGFE_CONNECTION_SSL_ENABLED On | Off Off Off
DMITIGR_PGFE_CONNECTION_SSL_SERVER_HOSTNAME_VERIFICATION_ENABLED On | Off Off Off
DMITIGR_PGFE_CONNECTION_SSL_COMPRESSION_ENABLED On | Off Off Off
DMITIGR_PGFE_CONNECTION_SSL_CERTIFICATE_FILE an absolute path null (libpq's default) null (libpq's default)
DMITIGR_PGFE_CONNECTION_SSL_PRIVATE_KEY_FILE an absolute path null (libpq's default) null (libpq's default)
DMITIGR_PGFE_CONNECTION_SSL_CERTIFICATE_AUTHORITY_FILE an absolute path null (libpq's default) null (libpq's default)
DMITIGR_PGFE_CONNECTION_SSL_CERTIFICATE_REVOCATION_LIST_FILE an absolute path null (libpq's default) null (libpq's default)

Copyright

Copyright (C) Dmitry Igrishin

Comments
  • Error including the library

    Error including the library

    My program cannot include the library due to the following error.

    OS: Ubuntu 18.04 Compiler: g++-9 (Ubuntu 9.2.1-17ubuntu1~18.04.1) 9.2.1 20191102

    CMake compilation configuration: set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON)

    In file included from /usr/local/include/dmitigr/pgfe.hpp:26, from /home/hou/repo/library/pgfe_example/main.cpp:1: /usr/local/include/dmitigr/pgfe/array_conversions.hpp: In member function ‘void dmitigr::pgfe::detail::Filler_of_deepest_container<T, Optional, Container, Allocator>::operator()(std::string&&, bool, int, Types&& ...)’: /usr/local/include/dmitigr/pgfe/array_conversions.hpp:353:82: error: too many initializers for ‘dmitigr::pgfe::detail::iClient_exception’ 353 | throw detail::iClient_exception{Client_errc::excessive_array_dimensionality}; | ^ In file included from /usr/local/include/dmitigr/pgfe.hpp:26, from /home/hou/repo/library/pgfe_example/main.cpp:1: /usr/local/include/dmitigr/pgfe/array_conversions.hpp: In lambda function: /usr/local/include/dmitigr/pgfe/array_conversions.hpp:771:78: error: too many initializers for ‘dmitigr::pgfe::detail::iClient_exception’ 771 | throw iClient_exception{Client_errc::improper_value_type_of_container}; |

    opened by Riemannstein 12
  • `to<double>()` issue

    `to()` issue

    one one our column is stored as double precision and when retriever with PGFE we get runtime exception that is "under-flowing"

    #0  0x00007f7b9fe19cae in __cxxabiv1::__cxa_throw ([email protected]=0x7f7b94024e70, 
        tinfo=0x691a40 <typeinfo for std::out_of_range@@GLIBCXX_3.4>, 
        dest=0x7f7b9fe2ef10 <std::out_of_range::~out_of_range()>)
        at ../../../../libstdc++-v3/libsupc++/eh_throw.cc:78
    #1  0x00007f7b9fe436ca in std::__throw_out_of_range ([email protected]=0x475993 "stod")
        at ../../../../../libstdc++-v3/src/c++11/functexcept.cc:82
    #2  0x0000000000423756 in __gnu_cxx::__stoa<double, double, char> (__idx=<synthetic pointer>, 
        __str=0x7f7b94024dd0 "3.16202013338398e-322", __name=0x475993 "stod", 
        __convf=<optimized out>)
        at /opt/lt/rel/x86_64-centos7-linux/pgfe/8d1d07e/include/dmitigr/net/conversions.hpp:33
    

    I am also a bit surprised that all numbers from PostgreSQL come in as a string when using c++ connector - is there perhaps a way to change this?

    opened by siemib 8
  • Error handling in the row processing function

    Error handling in the row processing function

    I wonder what the correct way of error handling inside the row processing handler is. For me it would seem quite logical to throw an exception like in the following example:

    db.execute([&data](auto&& row) {
            auto color = to<std::string>(row["color"]);
            if (!color_name_is_valid(color))
                throw std::runtime_error("my database contain an invalid color name!");
        }, "SELECT color FROM palette");
    

    But when I do this, it seems that the database connection is not cleaned up properly. When I execute the next database query I get an error saying that "another command is already in progress".

    So, is throwing exeptions supported? Or is there some other ways of error handling?

    enhancement 
    opened by sabelka 4
  • How to retrieve data from a database / Documentation

    How to retrieve data from a database / Documentation

    Let's say I have to save in a std::string the value of the field name of the record with and id equal to 3 in the table users, how can I do this with Pgfe? The documentation clearly states how to perform queries to the database, but it's not so clear when it comes to retrieving data. I'm opening this also because the documentation in general seems to be based upon version 1 of Pgfe.

    opened by Tachi107 3
  • Mac OS X building

    Mac OS X building

    Hi, Dmitry

    I tried to compile you library using the Clang compiler and I found an issue: Clang does not support the lstdc++fs, so I made some modification in your CMakeLists.txt. Also, I get a warning in the "exceptions.hpp" header file. The explicitly defaulted default constructor is implicitly deleted in the Sys_exception class because base class 'std::system_error' has no default constructor.

    I don't know if these little issues are a concern for you, so stay comfortable to denied this pull request.

    opened by jdiego 3
  • jsonb in binary mode

    jsonb in binary mode

    hello it's me again 👨

    when using jsonb type (oid 3802) the retrieved value has an additional first character '<U+0001>'. It does not happen in the in text mode.

    example query:

    SELECT '{"a":1, "b":2}'::jsonb as "my_little_json"
    
    conn->set_result_format(dmitigr::pgfe::Data_format::binary);
    

    I retrieve value as :

    const std::string &string = pgfe::to<std::string>(row[i]);
    
    opened by siemib 2
  • A couple of unit-tests are failing

    A couple of unit-tests are failing

    Running make test on v2.0alpha3 tag yields an error :

    The following tests FAILED: 3 - misc-unit-mulf_valid (Failed) 10 - pgfe-unit-connection (Failed) 13 - pgfe-unit-hello_world (Failed)

    Platform: Arch Linux Pq library version: 13.1-2

    Configuration command line was: cmake -DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/postgresql/ -DDMITIGR_CEFEIKA_BUILD_TESTS=TRUE

    Though I don't know whether I should have a live Postgres server running, I didn't see any option to set it.

    cleanup request 
    opened by garikello 2
  • compile error on execute without query parameters

    compile error on execute without query parameters

    I get a compiler error when I try to compile an database query without any bind argument, like the following:

    #include "dmitigr/pgfe.hpp"
    
    using namespace dmitigr::pgfe;
    
    void foo(Connection& conn)
    {
      conn.execute("begin");
    }
    

    This is the error I get:

    In file included from /home/test/lib/pgfe/lib/dmitigr/pgfe/connection.hpp:17,
                     from /home/test/lib/pgfe/lib/dmitigr/pgfe/pgfe.hpp:32,
                     from /home/test/lib/pgfe/lib/dmitigr/pgfe.hpp:30,
                     from /home/test/src/test.cpp:1:
    /home/test/lib/pgfe/lib/dmitigr/pgfe/prepared_statement.hpp: In instantiation of ‘dmitigr::pgfe::Prepared_statement& dmitigr::pgfe::Prepared_statement::bind_many__(std::index_sequence<I ...>, Types&& ...) [with long unsigned int ...I = {}; Types = {}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int>]’:
    /home/test/lib/pgfe/lib/dmitigr/pgfe/prepared_statement.hpp:441:23:   required from ‘dmitigr::pgfe::Prepared_statement& dmitigr::pgfe::Prepared_statement::bind_many(Types&& ...) [with Types = {}]’
    /home/test/lib/pgfe/lib/dmitigr/pgfe/connection.hpp:860:18:   required from ‘std::enable_if_t<dmitigr::pgfe::detail::Response_callback_traits<F>::is_valid, dmitigr::pgfe::Completion> dmitigr::pgfe::Connection::execute(F&&, const dmitigr::pgfe::Sql_string&, Types&& ...) [with F = dmitigr::pgfe::Connection::execute<{}>::<lambda(auto:27&&)>; Types = {}; std::enable_if_t<dmitigr::pgfe::detail::Response_callback_traits<F>::is_valid, dmitigr::pgfe::Completion> = dmitigr::pgfe::Completion]’
    /home/test/lib/pgfe/lib/dmitigr/pgfe/connection.hpp:868:19:   required from ‘dmitigr::pgfe::Completion dmitigr::pgfe::Connection::execute(const dmitigr::pgfe::Sql_string&, Types&& ...) [with Types = {}]’
    /home/test/src/test.cpp:8:23:   required from here
    /home/test/lib/pgfe/lib/dmitigr/pgfe/prepared_statement.hpp:676:54: error: invalid initialization of non-const reference of type ‘dmitigr::pgfe::Prepared_statement&’ from an rvalue of type ‘void’
      676 |     return (bind__(I, std::forward<Types>(args)), ...);
    

    However, when I add some bind argument, like conn.execute("begin", 1);, then it compiles file without any errors!

    opened by sabelka 2
  • Unable to use the library with CMake

    Unable to use the library with CMake

    Hi, I've trying to use pgfe as an header only library with CMake, but when building the makefiles with CMake I get these errors:

    Dmitigr Cefeika header-only mode is set.
    CMake Error at /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:165 (message):
      Could NOT find PostgreSQL (missing: PostgreSQL_TYPE_INCLUDE_DIR) (found
      version "13.0")
    Call Stack (most recent call first):
      /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:458 (_FPHSA_FAILURE_MESSAGE)
      /usr/share/cmake-3.18/Modules/FindPostgreSQL.cmake:247 (find_package_handle_standard_args)
      vendor/pgfe/lib/dmitigr/pgfe/CMakeLists.txt:358 (find_package)
    

    I'm trying to compile my project on Debian Testing, and I've installed on my system libpq-dev and postgresql-server-dev-all version 13

    opened by Tachi107 2
  • Conversion from uint8_t

    Conversion from uint8_t

    Hi, there's a problem with conversion from uint8_t on macOS Catalina, 10.15.4 (19E287)

    struct simple {
      uint8_t id;
    }
    

    Viven that your model has such a field, you won't be able to initialize it correctly because of stream's eof would be false.

    Idk, maybe the problem is on macOS(clang) only.

    opened by own2pwn 2
  • Add missing connection options

    Add missing connection options

    • [x] channel_binding;
    • [x] tcp_user_timeout;
    • [x] sslpassword;
    • [x] sslsni;
    • [x] ssl_min_protocol_version;
    • [x] ssl_max_protocol_version;
    • [x] target_session_attrs.
    v2.0 
    opened by dmitigr 1
Releases(v2.1.2)
The official C++ client API for PostgreSQL.

libpqxx Welcome to libpqxx, the C++ API to the PostgreSQL database management system. Home page: http://pqxx.org/development/libpqxx/ Find libpqxx on

Jeroen Vermeulen 718 Jan 3, 2023
C++ client library for PostgreSQL

Welcome to taoPQ taoPQ is a lightweight C++ client library for accessing a PostgreSQL➚ database. It has no dependencies beyond libpq➚, the C applicati

The Art of C++ 232 Dec 22, 2022
Modern cryptography for PostgreSQL using libsodium.

pgsodium pgsodium is an encryption library extension for PostgreSQL using the libsodium library for high level cryptographic algorithms. pgsodium can

Michel Pelletier 386 Dec 23, 2022
YugabyteDB is a high-performance, cloud-native distributed SQL database that aims to support all PostgreSQL features

YugabyteDB is a high-performance, cloud-native distributed SQL database that aims to support all PostgreSQL features. It is best to fit for cloud-native OLTP (i.e. real-time, business-critical) applications that need absolute data correctness and require at least one of the following: scalability, high tolerance to failures, or globally-distributed deployments.

yugabyte 7.4k Jan 7, 2023
A PostgreSQL extension providing an async networking interface accessible via SQL using a background worker and curl.

pg_net is a PostgreSQL extension exposing a SQL interface for async networking with a focus on scalability and UX.

Supabase 49 Dec 14, 2022
A framework to monitor and improve the performance of PostgreSQL using Machine Learning methods.

pg_plan_inspector pg_plan_inspector is being developed as a framework to monitor and improve the performance of PostgreSQL using Machine Learning meth

suzuki hironobu 198 Dec 27, 2022
Prometheus exporter for PostgreSQL

pgexporter pgexporter is a Prometheus exporter for PostgreSQL. pgexporter will connect to one or more PostgreSQL instances and let you monitor their o

null 19 Dec 22, 2022
PostgreSQL extension for pgexporter

pgexporter_ext pgexporter_ext is an extension for PostgreSQL to provide additional Prometheus metrics for pgexporter. Features Disk space metrics See

null 4 Apr 13, 2022
A friendly and lightweight C++ database library for MySQL, PostgreSQL, SQLite and ODBC.

QTL QTL is a C ++ library for accessing SQL databases and currently supports MySQL, SQLite, PostgreSQL and ODBC. QTL is a lightweight library that con

null 173 Dec 12, 2022
Backup / restore solution for PostgreSQL

pgmoneta pgmoneta is a backup / restore solution for PostgreSQL. pgmoneta is named after the Roman Goddess of Memory. Features Full backup Restore Sym

null 41 Dec 22, 2022
recovery postgresql table data by update/delete/rollback/dropcolumn command

recovery postgresql table data by update/delete/rollback/dropcolumn command

RadonDB 6 Aug 4, 2022
pgagroal is a high-performance protocol-native connection pool for PostgreSQL.

pgagroal is a high-performance protocol-native connection pool for PostgreSQL.

Agroal 555 Dec 27, 2022
xxhash functions for PostgreSQL

pg_xxhash PostgreSQL ❤️ xxhash Tested with xxhash 0.8.1 and PostgreSQL 14.1 on Linux and macOS. Think twice before even considering to use it in any s

Igor Hatarist 6 Oct 27, 2022
Distributed PostgreSQL as an extension

What is Citus? Citus is a PostgreSQL extension that transforms Postgres into a distributed database—so you can achieve high performance at any scale.

Citus Data 7.7k Dec 30, 2022
High-performance time-series aggregation for PostgreSQL

PipelineDB has joined Confluent, read the blog post here. PipelineDB will not have new releases beyond 1.0.0, although critical bugs will still be fix

PipelineDB 2.5k Dec 26, 2022
Reliable PostgreSQL Backup & Restore

pgBackRest Reliable PostgreSQL Backup & Restore Introduction pgBackRest aims to be a reliable, easy-to-use backup and restore solution that can seamle

pgBackRest 1.5k Dec 31, 2022
upstream module that allows nginx to communicate directly with PostgreSQL database.

About ngx_postgres is an upstream module that allows nginx to communicate directly with PostgreSQL database. Configuration directives postgres_server

RekGRpth 1 Apr 29, 2022
Open Source Oracle Compatible PostgreSQL.

IvorySQL is advanced, fully featured, open source Oracle compatible PostgreSQL with a firm commitment to always remain 100% compatible and a Drop-in r

null 420 Dec 28, 2022
Simple-MySQL-API is a free and easy API to manipulate MySQL with C99 and GCC compiler under GNU/Linux OS.

Simple-MySQL-API is a free and easy API to manipulate MySQL with C99 and GCC compiler under GNU/Linux OS.

Neptune 8 Aug 21, 2022