Skip to content

Commit

Permalink
Allow build to hide std::experimental::optional.
Browse files Browse the repository at this point in the history
Introduces a new macro, `PQXX_HIDE_EXP_OPTIONAL`, to hide support for
`std::experimental::optional` while building code for linking against
libpqxx.  This can paper over a difference in selected C++ language
versions between the build of libpqxx itself, and the build of the
software which uses it.

Fixes #93.
Fixes #95.
  • Loading branch information
jtv committed May 31, 2018
1 parent 547a917 commit 291db10
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 204 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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
Expand Down
208 changes: 9 additions & 199 deletions README-UPGRADE
Original file line number Diff line number Diff line change
@@ -1,201 +1,11 @@
NOTICES FOR USERS UPGRADING FROM EARLIER VERSIONS TO 5.0

This version has some relatively radical changes. They make the library easier
to read and manage, but they are likely to require changes in your code or to
your build configuration.

Older libpqxx versions used PGSTD as a macro for the standard namespace. This
was only needed for very old compilers, which might no longer be able to
compile current libpqxx versions anyway. The name is gone; use just "std"
instead. So, PGSTD::string becomes std::string etc.

The tuple header, and the tuple class, have been renamed to "row". This avoids
a name clash with std::tuple in code that has both "using std;" and
"using pqxx;".

The deprecated "noticer" types have been removed. Use errorhandler instead.

Support for many older compilers and libpq versions has been removed. You will
need at least libpq version 9.0, and the oldest gcc version that is known to
compile the current libpqxx is g++ 4.4.


NOTICES FOR USERS UPGRADING FROM 3.0 TO 3.1

The machinery to support conversion between the database's textual format and
the client's native types are now in a separate header, pqxx/strconv.
If your program fails to compile, try adding an include statement to include
this new header.

In binarystring objects, the results of the str() function are no longer cached
inside the object. This means that calling this function repeatedly will be a
lot slower (but keeping and caching the result yourself could be a lot faster)
than it was in previous versions. It also means that subsequent invocations
will return different string objects, not references to the same one.


NOTICES FOR USERS UPGRADING FROM 2.x TO 3.x

All items marked as deprecated in the 2.x API have been removed.

The Cursor and CachedResult classes are gone. A new class "stateless_cursor"
offers the functionality of Cursor combined with CachedResult's ease of use.
The only thing still missing is that stateless_cursor does not do any
client-side caching.

The sql_base class is still there, and sql_cursor offers low-level cursor access
for those who want to get close to the metal. The cursor stream API remains
unchanged.


NOTICES FOR USERS UPGRADING FROM 2.0 AND 2.1 VERSIONS TO 2.2.0 OR LATER

The default installation location has changed from /usr/local/pqxx to /usr/local
which should make it easier to run programs linked to libpqxx. If you upgrade,
be sure to remove your old /usr/local/pqxx is removed, or at least remove it
from your header and library paths when compiling your libpqxx programs.

The configure script no longer requires the --with-postgres options, nor does it
recognize them. Instead, it finds the PostgreSQL headers and libraries by
running Postgres' pg_config script. This should have been installed in the
binaries directory of your PostgreSQL installation; make sure it's in your
command path before running the libpqxx configure script.


IMPORTANT NOTICE FOR USERS UPGRADING TO 1.9.0 OR LATER FROM OLDER VERSIONS

Version 1.9.0 marks a radical change in the library, preparatory to the 2.0.0
release2003. These may require changes in your code; see the NEWS file for
quick overview of the changes. Most of these are also relevant for users
upgrading from 1.x to 2.x versions of the library.

Not all the changes will be of immediate importance to you; where possible,
typedefs have been provided to maintain backwards compatibility. In some cases
however, your existing code may fail to compile, or changes may be needed to
stay compatible with future versions of libpqxx.


1. The Great Renaming

Practically all classes have been renamed to fully lower-case names. This was
requested by several users, and should help stylistic integration with the C++
Standard Library.

Typedefs have been provided where necessary, so no immediate changes in your
code are needed on that score (although eventually of course the typedefs will
be phased out); however, don't be surprised if class names are spelled
differently in the documentation or in compiler messages than you're used to.


2. The Transformed Transaction Taxonomy (TTT)

The old Transaction hierarchy has been transformed to accomodate transaction
isolation levels as compile-time type properties. Also, there is now a separate
dbtransaction base class to indicate that a subclass opens a real transaction on
the backend. As you may have guessed, nontransaction is the only type of
transaction implementation that isn't derived from dbtransaction. The new root
of the inheritance tree is transaction_base.

Isolation levels are modeled as template arguments to the transaction types that
support them, i.e. those classes derived from dbtransaction. This makes it easy
to adapt if the set of isolation levels implemented by the underlying database
should ever change.

To limit the amount of inlined code, these newly templatized classes (i.e.
transaction and robusttransaction) are not derived directly from dbtransaction.
Instead, their implementations are mostly contained in basic_transaction and
basic_robusttransaction respectively. The template classes inherit their
implementations from these classes and only add the minimal changes required to
set their isolation levels. To express that a function requires a
robusttransaction of any isolation level, for instance, make its parameter
refer to a basic_robusttransaction.

The database's default isolation level is "read committed," which means that a
transaction will read newly changed values as they become available from other
transactions as they commit. PostgreSQL also implements "serializable," which
completely isolates each transaction from seeing changes made by other
transactions while it is active. The drawback of the serializable level is that
the database may occasionally need to abort the transaction because its
"snapshot" view of the database has become impossible to maintain. Using
libpqxx transactors will isolate you from this concern.

The old Transaction name is now typedef'ed to mean transaction<read_committed>;
to get a serializable one, declare a transaction<serializable>. The same goes
for robusttransaction.

To use the default isolation level, just write transaction<> (or, naturally,
robusttransaction<>). This will use the default template parameter, which is
read_committed. For transaction<>, which you'll usually want to use, there is
also a convenience typedef called "work."

Isolation levels are defined in the new header file pqxx/isolation.h.


3. If you use Cursor or CachedResult...

These classes have contained a serious bug for some time now, which is related
to the transaction isolation levels described above. Even if you don't want to
upgrade right away, please try to avoid the "absolute positioning" feature of
Cursor, and avoid CachedResult altogether. Either will be safe if you only
read your result set once, in a strict forward-only manner, but please consider
upgrading libpqxx. Newer version ensure that your code will not build until you
fix the problem.

The problem is this: due to the database's default transaction isolation level
of "read committed," it is possible for another transaction to modify the
contents of your query's result set as you access them. The Cursor class in
recent versions of libpqxx knew how to keep track of their absolute position to
let you scroll directly to a given row, or to determine the size of the result
set. If another transaction modifies the rows you're interested in, however,
that may affect the number of rows in your result set and confuse your cursor
object's positioning logic. The CachedResult class was built on top of Cursor's
absolute positioning functionality, and so has the same problem.

TTT to the rescue. The new transaction hierarchy allows the constructors for
cursor and cachedresult to demand that they be passed a transaction with
isolation level "serializable." Failure to do so will yield a compile-time or
link-time error for the symbol error_permitted_isolation_level().

If you want to continue using cursors and cachedresults the way you were used
to, you'll need to replace the relevant transactions with ones declared as
serializable: transaction<serializable> or robusttransaction<serializable>.
This may require some restructuring or templatization of your program in some
cases, because the constructors for cursor and cachedresult must be able to see
the correct transaction isolation level at compile time, but I hope you'll agree
it was the only solution that was both safe and efficient.

The offending functionality will be spliced out of the cursor class; in fact,
the class may disappear altogether and be replaced by a set of iterator-based
interfaces; random-access iterators will only be available in serializable
transactions, and some optimizations will be possible for forward-only
iterators. The difference between updateable and read-only cursors may be
reflected as a distinction between regular iterators and const_iterators.


4. If you use Transactors

The old way of setting a transaction type as your transactor's "quality of
service," by overriding the nested typedef for "argument_type," has been
deprecated. It will still work as far as I can make out, but may at some point
in the future development of libpqxx fail to do what you expect. There will be
no compile-time warning of this, so please inspect your transactors manually.

The new way to set a transactor's quality of service is to pass the desired
transaction type as a template argument. The old Transactor name is defined to
mean "transactor<>", maintaining the old default of Transaction (which is now
really a transaction<read_committed>).

To replace this with, say, a nontransaction write:

class UnsafeTransactor : public transactor<nontransaction>

For a super-robust, highly reliable transactor, write:

class SafeTransactor : public transactor<robusttransactor<serializable> >

Note the space between the two closing angled-brackets: "> >" instead of merely
">>". This is due to an ambiguity in the C++ syntax. Without the whitespace,
the two consecutive larger-than signs would be parsed as a >> (shift-right)
operator.
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.
12 changes: 10 additions & 2 deletions include/pqxx/field.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@
#include <optional>
#endif

#if defined(PQXX_HAVE_EXP_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.
*/
#if defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL)
#include <experimental/optional>
#endif

Expand Down Expand Up @@ -165,7 +173,7 @@ public:
/// Return value as std::optional, or blank value if null.
template<typename T> std::optional<T> get() const
{ return get_opt<T, std::optional<T>>(); }
#elif defined(PQXX_HAVE_EXP_OPTIONAL)
#elif defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL)
/// Return value as std::experimental::optional, or blank value if null.
template<typename T> std::experimental::optional<T> get() const
{ return get_opt<T, std::experimental::optional<T>>(); }
Expand Down
4 changes: 2 additions & 2 deletions include/pqxx/internal/statement_parameters.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include <optional>
#endif

#if defined(PQXX_HAVE_EXP_OPTIONAL)
#if defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL)
#include <experimental/optional>
#endif

Expand Down Expand Up @@ -207,7 +207,7 @@ private:
}
#endif

#if defined(PQXX_HAVE_EXP_OPTIONAL)
#if defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL)
/// Compile one argument (specialised for std::experimental::optional<type>).
template<typename Arg> void add_field(
const std::experimental::optional<Arg> &arg)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/test_prepared_statement.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ void test_prepared_statements(transaction_base &T)
#if defined(PQXX_HAVE_OPTIONAL)
test_optional<std::optional<int>>(T);
#endif
#if defined(PQXX_HAVE_EXP_OPTIONAL)
#if defined(PQXX_HAVE_EXP_OPTIONAL) && !defined(PQXX_HIDE_EXP_OPTIONAL)
test_optional<std::experimental::optional<int>>(T);
#endif
}
Expand Down

0 comments on commit 291db10

Please sign in to comment.