You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This won't interest most users. But libpqxx has an extensive (and extensible) high-performance API for converting between C++ values and their SQL equivalents. And this gets simpler, faster, and safer in 8.x. I'd love to hear your opinions and suggestions. You can test it in PR #914.
If your application handles an object type that libpqxx doesn't support out of the box (such as a type you define yourself), writing it to the database and/or reading it from the database, you can integrate it by extending this API for your type. But in 7.x it's a real chore. You'd specialise the pqxx::string_traits template for your type, and define a bunch of functions and variables that define the conversion.
Here's some good news: in 8.x the API will be a bit easier! The into_buf() function is gone, and so are the converts_to_string and converts_from_string static member variables. I'll explain the changes in more detail below.
Convenient global functions
Each of the old conversions had some static member functions:
to_buf() returns an SQL string representation of your value, optionally using a buffer you provide.
into_buf() writes an SQL string representation of your value into a given buffer.
from_string() reads an SQL string representation and parses it into a value of your type.
In most cases, you will no longer need to mess with these. There are now global functions pqxx::to_buf(), pqxx::into_buf(), pqxx::from_string(), and pqxx::size_buffer(). They will call the traits functions for you as needed. If your type has an old 7.x-style conversion defined, these functions will "translate" for you. Some you can even call with the old 7.x API and it'll translate in the other direction.
By the way, the new conversions no longer use raw pointers. It's all spans and views. This makes it harder to make mistakes, and it helps keep static analysis tools happy.
Defining a conversion
This is the part that was such a chore in 7.x. It gets a bit easier.
To support string conversion for your type, you still define...
A specialisation of the pqxx::nullness template for your type. Typically you just derive from pqxx::no_null<...>.
A specialisation of the pqxx::string_traits template for your type.
And inside the string_traits, some static member functions:
from_string() (if you support conversion in that direction). It only changes in one small way.
size_buffer() to say how much buffer space the conversion to string might use, exactly as before.
to_buf(), which is where the exciting changes happen.
The rest is gone. Good riddance! And there are some further improvements to what's left.
The small change in from_string() is that it no longer requires a pqxx::zview argument (a zero-terminated version of std::string_view). Instead, you can just pass in a std::string_view. If your argument happens to be a zview, that'll still work since it's derived from string_view.
The other one is in to_buf(). When you cal this function, you pass a buffer. It may write the SQL text into this buffer at offset 0. Or it may write the text at a different offset in the buffer. (Yes, this really happens — it saved a bit of work in integer conversions.) Or it may just ignore the buffer and return a constant string, such as true and false. It may even use some of the buffer space as some temporary storage space for internal computations.
In 8.0, however, the conversion has one more possibility: it can also return a view of the original value that you passed in. So if you want to "convert" a char const * to an SQL string for instance, the conversion may just return a std::string_view on that same underlying text. It saves your CPU some copying work.
Of course that means that it's only safe to access the function's result for as long as both the buffer and the input value remain valid and unchanged in memory, and in the same location. Usually this won't matter because you'll either use the value and forget it immediately, or copy it somewhere for long-term storage.
The Future
The old 7.x API will mostly still work in 8.0, but your compiler may warn about use of deprecated functions.
However expect these legacy functions to be gone in 9.0. Or, if for whatever reason it takes more than a year or two to get a 9.0 release done, I may retire them before 9.0.
So don't wait for that to happen. Check your use of these functions. If you define any conversions, start updating them to the new API. (I've done it many times now, and it's pretty smooth.) Mainly, if you use to_buf(), check that you don't access its result beyond the lifetime of the input value.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This won't interest most users. But libpqxx has an extensive (and extensible) high-performance API for converting between C++ values and their SQL equivalents. And this gets simpler, faster, and safer in 8.x. I'd love to hear your opinions and suggestions. You can test it in PR #914.
If your application handles an object type that libpqxx doesn't support out of the box (such as a type you define yourself), writing it to the database and/or reading it from the database, you can integrate it by extending this API for your type. But in 7.x it's a real chore. You'd specialise the
pqxx::string_traitstemplate for your type, and define a bunch of functions and variables that define the conversion.Here's some good news: in 8.x the API will be a bit easier! The
into_buf()function is gone, and so are theconverts_to_stringandconverts_from_stringstatic member variables. I'll explain the changes in more detail below.Convenient global functions
Each of the old conversions had some static member functions:
to_buf()returns an SQL string representation of your value, optionally using a buffer you provide.into_buf()writes an SQL string representation of your value into a given buffer.from_string()reads an SQL string representation and parses it into a value of your type.In most cases, you will no longer need to mess with these. There are now global functions
pqxx::to_buf(),pqxx::into_buf(),pqxx::from_string(), andpqxx::size_buffer(). They will call the traits functions for you as needed. If your type has an old 7.x-style conversion defined, these functions will "translate" for you. Some you can even call with the old 7.x API and it'll translate in the other direction.By the way, the new conversions no longer use raw pointers. It's all spans and views. This makes it harder to make mistakes, and it helps keep static analysis tools happy.
Defining a conversion
This is the part that was such a chore in 7.x. It gets a bit easier.
To support string conversion for your type, you still define...
pqxx::nullnesstemplate for your type. Typically you just derive frompqxx::no_null<...>.pqxx::string_traitstemplate for your type.string_traits, some static member functions:from_string()(if you support conversion in that direction). It only changes in one small way.size_buffer()to say how much buffer space the conversion to string might use, exactly as before.to_buf(), which is where the exciting changes happen.The rest is gone. Good riddance! And there are some further improvements to what's left.
The small change in
from_string()is that it no longer requires apqxx::zviewargument (a zero-terminated version ofstd::string_view). Instead, you can just pass in astd::string_view. If your argument happens to be azview, that'll still work since it's derived fromstring_view.The other one is in
to_buf(). When you cal this function, you pass a buffer. It may write the SQL text into this buffer at offset 0. Or it may write the text at a different offset in the buffer. (Yes, this really happens — it saved a bit of work in integer conversions.) Or it may just ignore the buffer and return a constant string, such astrueandfalse. It may even use some of the buffer space as some temporary storage space for internal computations.In 8.0, however, the conversion has one more possibility: it can also return a view of the original value that you passed in. So if you want to "convert" a
char const *to an SQL string for instance, the conversion may just return astd::string_viewon that same underlying text. It saves your CPU some copying work.Of course that means that it's only safe to access the function's result for as long as both the buffer and the input value remain valid and unchanged in memory, and in the same location. Usually this won't matter because you'll either use the value and forget it immediately, or copy it somewhere for long-term storage.
The Future
The old 7.x API will mostly still work in 8.0, but your compiler may warn about use of deprecated functions.
However expect these legacy functions to be gone in 9.0. Or, if for whatever reason it takes more than a year or two to get a 9.0 release done, I may retire them before 9.0.
So don't wait for that to happen. Check your use of these functions. If you define any conversions, start updating them to the new API. (I've done it many times now, and it's pretty smooth.) Mainly, if you use
to_buf(), check that you don't access its result beyond the lifetime of the input value.What do you think?
Beta Was this translation helpful? Give feedback.
All reactions