From efcea3a80da7c4479d5fe168435ecc9fd06bdc72 Mon Sep 17 00:00:00 2001 From: John Turner Date: Sun, 14 Sep 2025 00:16:10 -0400 Subject: Squashed 'subprojects/boost-sqlite/' content from commit 3378e35 git-subtree-dir: subprojects/boost-sqlite git-subtree-split: 3378e353705271e569cf4ba15c467b840a39798c --- include/boost/sqlite/collation.hpp | 140 +++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 include/boost/sqlite/collation.hpp (limited to 'include/boost/sqlite/collation.hpp') diff --git a/include/boost/sqlite/collation.hpp b/include/boost/sqlite/collation.hpp new file mode 100644 index 0000000..a4624c4 --- /dev/null +++ b/include/boost/sqlite/collation.hpp @@ -0,0 +1,140 @@ +// +// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_SQLITE_COLLATION_HPP +#define BOOST_SQLITE_COLLATION_HPP + +#include +#include + +BOOST_SQLITE_BEGIN_NAMESPACE + +///@{ +/** Define a custom collation function + @ingroup reference + + @param conn A connection to the database in which to install the collation. + @param name The name of the collation. + @param func The function + + The function must be callable with two `string_view` and return an int, indicating the comparison results. + + @par Example + + @code{.cpp} + + // a case insensitive string omparison, e.g. from boost.urls + int ci_compare(string_view s0, string_view s1) noexcept; + + extern sqlite::connection conn; + + // Register the collation + sqlite::create_collation(conn, "iequal", &ci_compare); + + // use the collation to get by name, case insensitively + conn.query("select first_name, last_name from people where first_name = 'Klemens' collate iequal;"); + + // order by names case insensitively + conn.query("select * from people order by last_name collate iequal asc;"); + + @endcode + + */ + +template +void create_collation( + connection & conn, + cstring_ref name, + Func && func, + typename std::enable_if< + std::is_convertible< + decltype(func(string_view(), string_view())), + int>::value, + system::error_code>::type & ec) +{ + using func_type = typename std::decay::type; + unique_ptr f{new (memory_tag{}) func_type(std::forward(func))}; + if (f == nullptr) + { + BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_NOMEM); + return; + } + auto res = sqlite3_create_collation_v2( + conn.handle(), + name.c_str(), + SQLITE_UTF8, + f.get(), + +[](void * data, int len_l, const void * str_l, int len_r, const void * str_r) -> int + { + string_view l(static_cast(str_l), len_l); + string_view r(static_cast(str_r), len_r); + auto & impl = (*static_cast(data)); + static_assert(noexcept(impl(l, r)), + "Collation function must be noexcept"); + return impl(l, r); + }, + +[](void * p) { delete_(static_cast(p)); } + ); + + if (res != SQLITE_OK) + BOOST_SQLITE_ASSIGN_EC(ec, res); + else + f.release(); +} + + +template +auto create_collation( + connection & conn, + cstring_ref name, + Func && func) +#if !defined(BOOST_SQLITE_GENERATING_DOCS) + -> typename std::enable_if< + std::is_convertible< + decltype(func(string_view(), string_view())), + int>::value>::type +#endif +{ + system::error_code ec; + create_collation(conn, name, std::forward(func), ec); + if (ec) + detail::throw_error_code(ec, BOOST_CURRENT_LOCATION); +} + + +inline void delete_collation( + connection & conn, + cstring_ref name, + system::error_code & ec) +{ + auto res = sqlite3_create_collation_v2( + conn.handle(), + name.c_str(), + SQLITE_UTF8, + nullptr, nullptr, nullptr); + if (res != SQLITE_OK) + { + BOOST_SQLITE_ASSIGN_EC(ec, res); + } +} + + +inline auto delete_collation( + connection & conn, + cstring_ref name) +{ + system::error_code ec; + delete_collation(conn, name, ec); + if (ec) + detail::throw_error_code(ec, BOOST_CURRENT_LOCATION); +} + +/// @} + +BOOST_SQLITE_END_NAMESPACE + +#endif //BOOST_SQLITE_COLLATION_HPP -- cgit v1.2.3