Skip to content

Commit 5449a00

Browse files
committed
String conversion to string_view. More binary types. (#926)
* Retire `binarystring`. This type has been deprecated since 7.2.0, more than 4 years ago. * String conversion to `string_view`. More binary types. Fixes: #694 Fixes: #827 Making much broader use of concepts. String conversions now accept any contiguous range of `std::byte` as binary data. Traits specialisations for integer and floating-point types are simpler now. And you can now just convert from string to `std::string_view` (or `char const *`), so long as you don't access it after the original string's lifetime ends. * Work around Visual Studio 2022 concepts problem. This compiler was having trouble with the syntax I used to specialise the generic `string_traits<T>` template to a _concept_ `T` (as opposed to run-of-the-mill specialisation to a _type_ `T`). So just for the floating-point string traits, I went back to the old setup where I had a separate implementation type template (`string_float_traits`) and derived the `string_traits` implementations for those types from instantiations of that template. * Forbid string conversion from `char const *`. It was stupid of me to allow this. I hope nobody ever used it.
1 parent 50c8d03 commit 5449a00

File tree

11 files changed

+291
-418
lines changed

11 files changed

+291
-418
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
8.0.0
22
- C++20 is now the oldest C++ version that libpqxx supports.
3+
- "String conversion" to `std::string_view` is now supported. (#694)
4+
- **Beware lifetime** when "converting" a string to `std::string_view`!
5+
- Conversion from string to `char const *` is no longer allowed.
6+
- Binary data can be any `std::contiguous_range` of `std::byte`. (#925)
37
- Retired `binarystring` and its headers. Use `blob` instead.
48
- Retired `connection_base` type alias. Use `connection`.
59
- Retired `pqxx::encrypt_password()`. Use the ones in `pqxx::connection`.

config/Makefile.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ am__can_run_installinfo = \
124124
esac
125125
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
126126
am__DIST_COMMON = $(srcdir)/Makefile.in compile config.guess \
127-
config.sub depcomp install-sh ltmain.sh missing mkinstalldirs
127+
config.sub install-sh ltmain.sh missing mkinstalldirs
128128
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
129129
ACLOCAL = @ACLOCAL@
130130
AMTAR = @AMTAR@

include/pqxx/doc/datatypes.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ You can "teach" libpqxx (in the scope of your own application) to convert
1212
additional types of values to and from PostgreSQL's string format.
1313

1414
This is massively useful, but it's not for the faint of heart. You'll need to
15-
specialise some templates. And, **the API for doing this can change with any
16-
major libpqxx release.**
15+
specialise several templates. And, **the API for doing this can change with
16+
any major libpqxx release.**
1717

1818
If that happens, your code may fail to compile with the newer libpqxx version,
1919
and you'll have to go through the `NEWS` file to find the API changes. Usually
@@ -107,13 +107,16 @@ namespace near the top of your translation unit, and pass the type as an
107107
argument.
108108

109109
The library also provides specialisations for `std::optional<T>`,
110-
`std::shared_ptr<T>`, and `std::unique_ptr<T>`. If you have conversions for
111-
`T`, you'll also automatically have conversions for those.
110+
`std::shared_ptr<T>`, and `std::unique_ptr<T>` (for any given `T`). If you
111+
have conversions for `T`, you'll also automatically have conversions for those.
112112

113113

114114
Specialise `type_name`
115115
----------------------
116116

117+
(This is a feature that should disappear once we have introspection in the C++
118+
language.)
119+
117120
When errors happen during conversion, libpqxx will compose error messages for
118121
the user. Sometimes these will include the name of the type that's being
119122
converted.
@@ -142,12 +145,16 @@ Specialise `nullness`
142145
---------------------
143146

144147
A struct template `pqxx::nullness` defines whether your type has a natural
145-
"null value" built in. If so, it also provides member functions for producing
146-
and recognising null values.
148+
"null value" built in. For example, a `std::optional` instantiation has a
149+
value that neatly maps to an SQL null: the un-initialised state.
150+
151+
If your type has a value like that, its `pqxx::nullness` specialisation also
152+
provides member functions for producing and recognising null values.
147153

148154
The simplest scenario is also the most common: most types don't have a null
149155
value built in. There is no "null `int`" in C++. In that kind of case, just
150-
derive your nullness traits from `pqxx::no_null` as a shorthand:
156+
derive your nullness traits from `pqxx::no_null` as a shorthand: This tells
157+
libpqxx that your type has no null value of its own.
151158

152159
```cxx
153160
// T is your type.
@@ -196,9 +203,9 @@ where `NULL <> NULL`). Or `T` may have multiple different null values. Or `T`
196203
may override the comparison operator to behave in some unusual way.
197204
198205
As a third case, your type may be one that _always_ represents a null value.
199-
This is the case for `std::nullptr_t` and `std::nullopt_t`. In that case, you
200-
set `nullness<TYPE>::always_null` to `true` (as well as `has_null` of course),
201-
and you won't need to define any actual conversions.
206+
This is the case for `std::nullptr_t` and `std::nullopt_t`. In a case like
207+
that, you set `nullness<TYPE>::always_null` to `true` (as well as `has_null`
208+
of course), and you won't need to define any actual conversions.
202209
203210
204211
Specialise `string_traits`

include/pqxx/field.hxx

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -344,44 +344,13 @@ template<> inline bool field::to<char const *>(char const *&obj) const
344344
}
345345

346346

347-
template<> inline bool field::to<std::string_view>(std::string_view &obj) const
348-
{
349-
bool const null{is_null()};
350-
if (not null)
351-
obj = view();
352-
return not null;
353-
}
354-
355-
356-
template<>
357-
inline bool field::to<std::string_view>(
358-
std::string_view &obj, std::string_view const &default_value) const
359-
{
360-
bool const null{is_null()};
361-
if (null)
362-
obj = default_value;
363-
else
364-
obj = view();
365-
return not null;
366-
}
367-
368-
369-
template<> inline std::string_view field::as<std::string_view>() const
370-
{
371-
if (is_null())
372-
internal::throw_null_conversion(type_name<std::string_view>);
373-
return view();
374-
}
375-
376-
377-
template<>
378-
inline std::string_view
379-
field::as<std::string_view>(std::string_view const &default_value) const
380-
{
381-
return is_null() ? default_value : view();
382-
}
383-
384-
347+
/// Specialization: `to(zview &)`.
348+
/** This conversion is not generally available, since the general conversion
349+
* would not know whether there was indeed a terminating zero at the end of
350+
* the string. (It could check, but it would have no way of knowing that a
351+
* zero occurring after the string in memory was actually part of the same
352+
* allocation.)
353+
*/
385354
template<> inline bool field::to<zview>(zview &obj) const
386355
{
387356
bool const null{is_null()};

0 commit comments

Comments
 (0)