Frequently Asked Questions
General questions
Is libpqxx really "official"?
Yes, that was what was decided in the distant past... for what "official" is worth in such a loose, distributed, nonprofit collaboration. The PostgreSQL core team accepted libpqxx as the replacement for the older libpq++ shortly after its creation in 2000. But unlike the older language bindings, libpqxx was never included in the PostgreSQL source tree.
Why not?
At the time, there was a procedure for adding a new language binding. The core team would decide to add the new library. They would then ask the authors to ensure that its build environment was uniform with the main PostgreSQL project. And finally, they would add the new library to the main project as a new directory in the source tree, and integrate it into the overall build. This was what they asked us to do with libpqxx as well.
(The incomparable J.H.M. "Ray" Dassen helped out tremendously with libpqxx's
autoconf
and automake
setup for this. It was total black magic to me back
then and it took me many years to catch up. Thank you, Ray, we still miss you!
❤️)
The PostgreSQL source tree was still being managed in CVS back then. CVS was a precursor to Subversion (svn), which in turn was a precursor to Git. Adding a directory to the repo was a big deal: Easy to do, yes, but CVS did not really support removing a directory. It was possible, but it was a bit of a hack. Not the kind of game you'd want to play with the central PostgreSQL repository. So it made sense to think twice before adding one.
Once the libpqxx build was ready for integration into the main postgres build, as we were discussing merging libpqxx into the source tree, someone on the core team noted that postgres had accumulated a lot of these libraries already, some no longer even maintained, and the repo was getting unwieldy. They had to turn that trend around. So this was where the team decided that new language drivers should live in their own repositories, outside the main PostgreSQL tree. Personal frustration aside, I think it was the right decision.
So there you have it. That is why libpqxx lives separate from postgres proper. For various reasons I hosted the project myself as well, and so for years I ran a lot of my own infrastructure on a custom server: revision control, membership control, bug tracking, spam filtering, network security, FTP server and http downloads, email, wiki, announcements, backups, deleting spam, and so on.
That all took a lot of work, and for a period, I did very little development on libpqxx. There weren't a lot of major features that needed libpqxx support, the code had ossified, supporting Windows was painful, and even the C++ language itself seemed stagnant. And of course I also had more to learn about working with a community. I lost access to my postgres-hosted mailing lists, and had trouble getting in touch with the maintainer. Things fell in disrepair.
The PostgreSQL core team noted that this state of affairs was not a good look for the official C++ API. I needed to step up. So over time, as free hosting sites got better, I moved the project to Github, streamlined the release procedure, and started updating the code to the newer C++ standards which were now being defined on an aggressive schedule. I culled workarounds for obsolete compilers, package-building setup for various operating systems went to the package maintainers where they belonged, the cumbersome release procedure went out the window, PostgreSQL massively improved its Windows support, lots of people helped out, the community came alive, and CMake widened our platform support. That is how things gradually came back to life.
I hope you like the result.
Can I become a project member?
There really is no such thing, sorry! Everyone's welcome to contribute, and since we develop libpqxx completely out in the open, everyone gets public credit.
So if you wish to collaborate on the project, that's easy. Just do it! Try posting your patches, bug reports, complaints or suggestions on the GitHub project. Build a name for yourself helping answer other users' questions in the issue tracker, and join in design discussions. The team is whoever helps.
What platforms does libpqxx run on?
For starters, just about anything that bears any resemblance to Unix (the various flavours of GNU/Linux and of BSD, Apple's macOS, Solaris, AIX, HP/UX, Irix etc.). The processor architecture doesn't matter much: libpqxx has been extensively tested on many different CPU architectures without any required changes or special support.
Then there's Microsoft Windows. Things are a bit less standardised here, but the platform has come a long way. The easiest way to develop in Windows is to build with CMake.
What PostgreSQL versions are supported?
As a general rule, all currently supported major PostgreSQL releases. At this entry's time of writing, both front-end and back-end need to be version 9.3 or better.
I want to use libpq++ and I have a question!
These two libraries are completely separate projects. You're looking at the
libpqxx
site, not the libpq++
one.
In fact libpqxx was written from scratch because the problems with libpq++ ran too deep to fix. Around the same time libpqxx was published, all postgres client interfaces were taken out of the main package and this included both the older libpq++ and the new libpqxx.
Isn't "Postgre" a strange name?
Yes. That's why it's not actually the name.
The correct short version of PostgreSQL is postgres, with the "s" at the end.
Feature Questions
Data is transferred in text form. Can I make it work directly in binary?
Many people ask for this feature because they are looking for increased performance. The underlying libpq library can transfer all data in binary form, but libpqxx is not going to support it any time soon.
There are good reasons for this:
-
The binary format may change between postgres versions. No guarantees.
-
Binary representations are undcoumented.
-
We have no good way to check that the server actually speaks the exact format we expect.
-
Binary data may not be as fast as it sounds. For example, it represents a simple integer as a relatively complex variable-length binary encoding.
-
It's not necessarily going to be more compact. For instance, an integer may take up more space in binary form than it does as text.
Nevertheless, there are special cases where binary transfers do make sense, and libpqxx does support these:
-
Large objects, a.k.a. "blobs." See the
argeobject
classes. Large objects are stored separately from regular data, and you access them using a file-like API. It's possible to retrieve or even rewrite just a part of a very large object, without having to transfer the whole thing to the client and back to the server. -
Prepared statements can take binary parameters. Some applications wrap
INSERT
statements in prepared statements to save the server from having to parse the entire statement, so for inserting data this may be close to what you're doing already. For efficient bulk insertion of data though, thestream_to
class is probably a better choice.
Apart from large objects, there is no way to retrieve regular data directly in
binary form. If you want to work with relatively large binary objects but do
not wish to use the blob
API, the best alternative is to keep them in regular
columns of BYTEA
type. Insert them using a prepared statement to avoid text
conversion on the way to the server, and retrieve them into binarystring
objects.
Can I let libpqxx write data from the database directly into my objects?
Some users would like to access SQL fields as if they were C++ struct/class members.
Libpqxx does not support exactly this, but there are alternatives. Streaming queries will let you map fields directly into local variables, but not into the members of an object:
for (auto [id, name]: tx.stream<int, std::string_view>(query))
{
process(id, name);
}
You can do the same thing with stream_from
, and stream_to
does it in the
opposite direction. These work with std::tuple<...>
. Each field in the
tuple corresponds to a field in the database.
There is also at least one Object-Relational Mapper (or ORM) based on libpqxx, built into FOST.
Can you expose this C-level libpq structure that libpqxx hides from me?
Generally, no. If you require support for specific high-level functionality, the better solution is usually to build it into the abstraction layer rather than to break the abstraction layer open like this.
Some of the things libpqxx does for you may become impossible if the library does not have full and unique control over the underlying C-level structures, or it might lead to subtle and complex bugs in your program.
Feel free, however, to prototype enhancements that meet your own needs, see what works best for you, and then submit a pull request or a feature request.
Can I have two or more simultaneous transactions?
Not within the same connection. Even if you use nested transactions (see the
subtransaction
class), a connection is always dealing with just one
transaction at a time. Of course you can create a new transaction on the
same connection once the previous one has completed.
If you want to have multiple concurrent transactions, let them work on different connections.
Questions about Building libpqxx and your own code
Will it work with my compiler?
It mainly depends on whether your compiler supports the right version of C++. For example, libpqxx 7.0 requires C++17 or better.
Can I build libpqxx and my own application with different compilers?
Sometimes. This is a drawback of how C++ works, or of the C-style linking process, depending on how you look at it. Generally you can't link code built with one C++ compiler to code built with another.
Even different versions of the same compiler may produce incompatible binaries. Modern versions of gcc adhere to a standard interface that should keep object files compatible between compilers versions, and some other compilers such as clang may be compatible with your gcc binaries and vice versa. However there are still minor changes in this ABI from time to time, so it's not perfect.
Do I need libpq when I use libpqxx?
Yes; libpqxx is built on top of libpq. You call libpqxx, and libpqxx in turn calls libpq. You won't need to use or know any libpq functions yourself though. Libpqxx hides it completely.
You may get link errors about missing symbols such as _PQconnectdb
,
_PQfinish
, _PQexec
and so on. Usually this means one or more of:
-
You need to link to libpq as well as to libpqxx.
-
You need to link to libpqxx first, and then to libpq.
-
If you have them, don't link "Release" artefacts with "Debug" ones.
How compatible are different libpqxx versions?
Releases are versioned like x.y.z
.
Generally speaking, if you've compiled your application against libpqxx
x.y.z, using a libpqxx
x.y.z+1` binary will probably work. I can't quite
guarantee it, but there's a good chance.
Also generally speaking, code written against libpqxx x.y.z
will generally
compile. link, and run against x.y+1.*
.
When upgrading from x.y.z
to x+1.*.*
though, all bets are off. This is
where we do major incompatible changes. Even then, there's a good chance that
your code will still compile and work — but expect to do some maintenance.
Why so few guarantees? It's just too easy to break ABI compatibility in a C++ library. A small sensible change can do it, and sometimes it might break compatibility on one compiler but not on another. Even a compiler upgrade might break binary compatibility.
Can I build a dynamic library?
You should get one if you use the configure
script's --enable-shared
option, or CMake's -DBUILD_SHARED_LIBS=1
option.
Are shared libraries a good idea? The answer depends on your OS.
On Windows, you'll probably want to build a DLL and ship it with your application. In that case, a shared library is a safe choice since nobody's going to upgrade the binary on their own. A shared library seems to be a conventional choice for Windows, so go ahead.
On other systems, shared libraries are usually packaged and installed globally,
independent from any individual application. That's great if you have a
library which promises binary compatibility between releases, but libpqxx
isn't one of those. So, prefer a static library unless you need to dlopen()
it at runtime.
Why can't the build procedure find libpq? It's in plain sight!
The build has several different ways of finding the libpq library and headers:
CMake
The CMake build uses the standard CMake machine for finding the PostgreSQL package, but there are ways of overriding it if that doesn't work.
If you have CMake 3.12 or better, you can set the PostgreSQL_ROOT
variable
when running cmake: "-DPostgreSQL_ROOT=../PostgreSQL-13
". This tells the
build where to look for both the libpq library and its headers.
Or, you can set individual variables for the various parts:
PostgreSQL_LIBRARY
, PostgreSQL_INCLUDE_DIR
, PostgreSQL_TYPE_INCLUDE_DIR
.
configure
The configure
script, by default, tries to find libpq by running
pkg-config
. Make sure that script is in your PATH
, and knows where to find
your PostgreSQL installation.
If that doesn't work, configure
will try the pg_config
script which comes
with postgres. If you have the script in your PATH
, you'll get the libpq
belonging to the same PostgreSQL install whose pg_config
script you used.
But, you can also set the paths explicitly. Pass --with-postgres-include
for
libpq's headers directory, and --with-postgres-lib
for its library directory.
Visual C++: Debug and Release
Visual C++ likes to build both libpq and libpqxx, as well as your program, in two flavours: debug and release.
When building your program in the Debug flavour, you must link to the Debug-flavoured builds of both libraries as well.
When building in the Release flavour, use only the Release-flavoured libraries.
Visual C++: min() and max()
This has been giving people no end of trouble. Visual C++, by default, defines
min()
and max()
as preprocessor macros… meaning that a lot of correct,
standard-conforming code will not compile properly. For instance a simple call
to std::max()
will break on Windows.
The libpqxx headers try to work around this silly problem, but it's easy to forget.
You can suppress the macros by defining the NOMINMAX
preprocessor macro.
However this may cause some of Visual C++'s own headers to fail to compile.
You may have to do a little dance of #define NOMINMAX
and #undef NOMINMAX
.
Troubleshooting Questions
I'm running into a bug. What can I do?
Have a look at the GitHub page. The "Issues" section is meant for bug reports, questions, and user problems.
Before you open an issue though, try searching for your problem — both in the issue tracker and on the Internet at large.
Does WinZip mess up the source tree?
Sometimes. This problem occurs on Windows systems only. If you use WinZip to extract the libpqxx source tarball, try disabling the "tar file smart CR/LF conversion" option.
I can't catch exceptions!
Some people report that their programs crash when an exception occurs. You're most likely to see this when logging into the database fails, because that's something you're likely to do very early on in your program.
Some common solution to try:
-
Have a
try/catch
block in your code, so that you can catch and report exceptions. Often it's just a simple problem such as needing a password to log into your database. -
If you're catching exceptions, are you catching them as "
const &
"? -
Some environments don't like throwing an exception in a shared library and then catching it in the main program, or in a different library.
-
Were libpqxx and your program built and linked using the same compiler, and the same compiler version?
-
If your compiler environment has separate "debug" and "release" modes, were libpqxx and your program, as well as your libpq, built in the same mode?
-
If you're compiling with gcc, make sure you use the
g++
command (not thegcc
command!) to compile both the library and your program. Similar withclang++
versusclang
. -
There may be a bug in the library's
throw
specifications. When using gcc or a compatible compiler, you may be able to detect this by recompiling both the library and your own code with the-fno-enforce-eh-specs
option. If the problem disappears when you do that, don't sit on it — report it!
Why does my program crash when a connection to the database breaks?
Sometimes connections to the database are lost even after they have been successfully established. This can happen for many reasons: a broken cable, a power outage in the wrong place, a crashed server, a change to your network configuration, or even a firewall dropping your connection because it hasn't been used for too long.
When that happens, your program (on Unix-like systems at least) may also
receive the SIGPIPE
signal. Your program's default response to receiving
this error is to abort. That can be useful for simple, short-lived programs
but many more complex applications can not afford to crash just because they
lose a network connection.
All you need to do deal with broken connections in libpqxx on Unix-like systems (and that includes GNU and BSD systems as well as macOS) is to make your program ignore this signal. Just include something like this in your program:
#include <signal.h>
int main()
{
signal(SIGPIPE, SIG_IGN);
// ...
If your code tries to use a connection that turns out to be broken, libpqxx
will throw a broken_connection
exception. Your code can then handle that
like it can any other exception.
Why does my program crash when it fails to connect to the database?
Usually this means there's an exception, and the exception isn't being caught properly.
See "I can't catch exceptions!" above.