Result/row iterator rewrite

(Updated 2025-05-26)

The whole way you navigate a result object changes radically in libpqxx 8. It's still mostly compatible, but depending on how you access fields, you may need to adapt your code.

(Yes, I am profoundly sorry for this. The main pain point is in complying with the C++ standard. Read on.)

What's changed?

A great many things:

  • You now only use row and field in rare cases where you need to keep a result object alive in memory without owning a reference to it. These classes behave like reference-counted smart pointers to the actual data.
  • Instead, you get row_ref and field_ref. These behave like plain pointers, and to the result object — not to the underlying data. So you must ensure that the result stays valid, unchanged, and unmoved in memory.
  • Iterators, too, now behave more like pointers. Do not assign, destroy, or move a result while iterating it. (But you probably weren't doing that anyway, were you?)
  • A result iterator points at a row. In the old API you could use the array index operator on the iterator to get at a field in that row. This was nice in that it made the result feel more like a 2-dimensional C array. Unfortunately it always violated the C++ standard. In the new API, the index operator gets you not to a field but to another row: iter[n] == *(iter + n).
  • The result and row iterators now satisfy the random_access_iterator concept. Believe it or not, it was a bug report about this that started the whole undertaking.
  • Working with these classes is going to be less work for the computer, so probably faster.
  • The new field_ref class doesn't fully implement the API that field supports. Let's see what's actually needed in practice.
  • Gone are the deep, confusing inheritance hierarchies. A reverse iterator inherits from its forward counterpart, but that's it.

What do I need to change in my code?

Hopefully, not too much in practice. But potentially...

  1. First thing you're likely to run into is the change in getting to a field from an iterator pointing at a row: it[col] no longer works. But a result iterator still acts like a pointer to a row, so try (*it)[col], or use it->at(col).
  2. The lifetime rules are stricter. So run your code through all the verification tools you can, and have a good critical look at how you navigate libpqxx result objects. The major compilers have features called "analyzers": compile your project with these enabled, and run it. See whether the binary reports any runtime errors.
  3. Of course some features that you use may have become deprecated. Run your compiler with flags to warn about this, and to treat warnings as errors. The deprecation notices will generally give you some indication of what to do.
  4. If you were using deprecated features that are now gone, try doing the same thing with an older version of libpqxx.
  5. You may need to work around some field features that field_ref does not have. These are generally pretty simple. You can construct a field from the field_ref, or if the missing feature is simple enough, write your own code based on the old function. Or, ask me to implement the feature.