Result/row iterator rewrite
(Updated 2025-04-15)
I'm rewriting the result/row iterator classes so they're completely separate
from the row
and field
classes. No more deep, intricate inheritance trees!
The end result I hope will be more efficient, more standard-compliant iterators.
A lot of things will change. Most of these won't affect most code, but there are some incompatible changes.
Indexing operator
As it turns out, pqxx::result::const_iterator::operator[]
never properly
complied with the C++ standard! A call to my_iterator[n]
should return
*(my_iterator + n)
, not index column number n
on the current row.
Honestly, this was probably the most painful change for me — I had to change my code in a few places. But there was no choice: I want those iterators to be proper, standard, C++ iterators.
So, where your code writes my_result[row_num][col_num]
, you'll have to change
that to my *(my_result[row_num])[col_num]
. It's ugly, but... this is how it
was always meant to be.
Litetimes
Iterators will no longer increment the the refernce count for the result
object they're iterating. So you'll need to be a bit more careful with
lifetimes.
Now, when you iterate a result (or a row within a result), it's up to you to ensure that that result object does not get destroyed, or moved to a different location in memory.
Based on my experience prototyping the change, this one shouldn't affect many people. This has always been the normal way to work with iterators. I'm removing a feature that nobody asked for, and which in perfomance terms, not a lot of people will want to "pay" for.
Lightweight "row" and "field" classes
We already had pqxx::row
and pqxx::field
types. These classes are
reference-counted, meaning that you can get a row or field from a result
object, then destroy the result object, and still access data from the row or
field. That's not because the data is stored in the row or field object, but
because pqxx::result
is essentially a reference-counted pointer to the
underlying data received from the server, preventing it from getting destroyed
until all copies of the result object are destroyed.
But as with the iterators, most of the time, this isn't actually helpful. So
in 8.0 I'm adding more lightweight variants, pqxx::row_ref
and
pqxx::field_ref
which don't do this. You'll have to make sure that the
pqxx::result
is not destroyed, nor moved to a different location in meory,
until you're done with the rows and fields on that result.
The new iterators build on these new types, where the old ones were built on
the row
and field
types.
Some of the features in row
and field
do not exist in row_ref
and
field_ref
. This may change over time, but let's see which ones we can do
withou. All these classes have grown remarkably "fat" interfaces over the
years, and it's time to reset them and start over.