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 --- example/url.cpp | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 example/url.cpp (limited to 'example/url.cpp') diff --git a/example/url.cpp b/example/url.cpp new file mode 100644 index 0000000..f5ed4f9 --- /dev/null +++ b/example/url.cpp @@ -0,0 +1,315 @@ +// +// 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) +// + +#include +#include +#include +#include + +using namespace boost; + +// tag::subtype[] +constexpr int pct_subtype = static_cast('U'); + +void tag_invoke(sqlite::set_result_tag, sqlite3_context * ctx, urls::pct_string_view value) +{ + using boost::sqlite::ext::sqlite3_api; + // we're using the sqlite API here directly, because we need to set a different subtype + sqlite3_result_text(ctx, value.data(), value.size(), nullptr); + sqlite3_result_subtype(ctx, pct_subtype); +} + + +void tag_invoke(sqlite::set_result_tag, sqlite3_context * ctx, const urls::segments_encoded_view & value) +{ + using boost::sqlite::ext::sqlite3_api; + // we're using the sqlite API here directly, because we need to set a different subtype + sqlite3_result_text(ctx, value.buffer().data(), value.buffer().size(), nullptr); + sqlite3_result_subtype(ctx, pct_subtype); +} +// end::subtype[] + +struct url_cursor final + : sqlite::vtab::cursor< + variant2::variant + > +{ + url_cursor(urls::url_view view) : view(view ) {} + + urls::url_view view; + bool done{false}; + + sqlite::result next() { done = true; return {};} + + sqlite::result row_id() {return static_cast(0);} + sqlite::result column(int i, bool /*nochange*/) + { + switch (i) + { + case 0: return view.scheme(); + case 1: return view.encoded_user(); + case 2: return view.encoded_password(); + case 3: return view.encoded_host(); + case 4: return view.port(); + case 5: return view.encoded_path(); + case 6: return view.encoded_query(); + case 7: return view.encoded_fragment(); + case 8: return view.buffer(); + default: + return variant2::monostate{}; + } + } + sqlite::result filter(int /*idx*/, const char * /*idxStr*/, span values) + { + if (values.size() > 0u) + view = urls::parse_uri(values[0].get_text()).value(); + return {}; + } + + bool eof() noexcept {return done || view.empty();} +}; + +struct url_wrapper final : sqlite::vtab::table +{ + urls::url value; + const char * declaration() override + { + return R"( + create table url( + scheme text, + user text, + password text, + host text, + port text, + path text, + query text, + fragment text, + url text hidden);)"; + } + + sqlite::result open() override + { + return url_cursor{value}; + } + + sqlite::result best_index(sqlite::vtab::index_info & info) override + { + for (const auto & constraint : info.constraints()) + { + if (constraint.iColumn == 8 && constraint.usable) + { + if (constraint.op != SQLITE_INDEX_CONSTRAINT_EQ) + return {SQLITE_MISUSE, + sqlite::error_info("query only support equality constraints")}; + info.usage_of(constraint).argvIndex = 1; + info.set_index(1); + } + } + + return {}; + } +}; + + +struct url_module final : sqlite::vtab::eponymous_module +{ + sqlite::result connect(sqlite::connection /*db*/, + int /*argc*/, const char * const */*argv*/) + { + return url_wrapper{}; + } +}; + +struct segements_cursor final : sqlite::vtab::cursor< + variant2::variant> +{ + segements_cursor(urls::segments_encoded_view view) : view(view) {} + urls::segments_encoded_view view; + urls::segments_encoded_view::const_iterator itr{view.begin()}; + + sqlite::result next() override { itr++; return {};} + + sqlite::result row_id() override {return std::distance(view.begin(), itr);} + sqlite::result column(int i, bool /*nochange*/) override + { + //nochange = true; + switch (i) + { + case 0: return std::distance(view.begin(), itr); + case 1: return *itr; + case 2: return view; + default: + return variant2::monostate{}; + } + } + sqlite::result filter(int /*idx*/, const char * /*idxStr*/, + span values) override + { + if (values.size() > 0u) + view = urls::segments_encoded_view(values[0].get_text()); + itr = view.begin(); + return {}; + } + bool eof() noexcept override {return itr == view.end();} +}; + +struct segment_wrapper final : sqlite::vtab::table +{ + urls::segments_encoded_view value; + const char * declaration() override + { + return R"( + create table segments( + idx integer, + segment text, + segments text hidden);)"; + } + + + + sqlite::result open() override + { + return segements_cursor{value}; + } + + sqlite::result best_index(sqlite::vtab::index_info & info) override + { + for (auto & constraint : info.constraints()) + { + if (constraint.iColumn == 2 + && constraint.usable) + { + if (constraint.op != SQLITE_INDEX_CONSTRAINT_EQ) + return {SQLITE_OK, sqlite::error_info("segments only support equality constraints")}; + info.usage_of(constraint).argvIndex = 1; + info.set_index(1); + } + } + + return {}; + } +}; + + +struct segments_module final : sqlite::vtab::eponymous_module +{ + sqlite::result connect(sqlite::connection /*conn*/, + int /*argc*/, const char * const */*argv*/) + { + return segment_wrapper{}; + } +}; + +// tag::query_cursor[] +struct query_cursor final : sqlite::vtab::cursor< + variant2::variant + > +{ + urls::params_encoded_view view; + urls::params_encoded_view::const_iterator itr{view.begin()}; + + sqlite::result next() override { itr++; return {};} + + sqlite::result row_id() override {return std::distance(view.begin(), itr);} + sqlite::result column(int i, bool /*nochange*/) override // <1> + { + //nochange = true; + switch (i) + { + case 0: return std::distance(view.begin(), itr); + case 1: return itr->key; + case 2: + if (!itr->has_value) + return variant2::monostate{}; + else + return itr->value; + case 3: return view.buffer(); + default: + return variant2::monostate{}; + } + } + sqlite::result filter(int /*idx*/, const char * /*idxStr*/, + span values) override + { + if (values.size() > 0u) // <2> + view = urls::params_encoded_view(values[0].get_text()); + itr = view.begin(); + + return {}; + } + bool eof() noexcept override {return itr == view.end();} +}; +// end::query_cursor[] + +// tag::query_boiler_plate[] +struct query_wrapper final : sqlite::vtab::table +{ + const char * declaration() override + { + return R"( + create table queries( + idx integer, + name text, + value text, + query_string text hidden);)"; // <1> + } + + sqlite::result open() override + { + return query_cursor{}; + } + + sqlite::result best_index(sqlite::vtab::index_info & info) override + { + for (auto & constraint : info.constraints()) + { + if (constraint.iColumn == 3 + && constraint.usable) + { + if (constraint.op != SQLITE_INDEX_CONSTRAINT_EQ) // <2> + return sqlite::error{SQLITE_OK, "query only support equality constraints"}; + + info.usage_of(constraint).argvIndex = 1; + info.set_index(1); + } + } + return {}; + } +}; + +struct query_module final : sqlite::vtab::eponymous_module +{ + sqlite::result connect(sqlite::connection /*conn*/, + int /*argc*/, const char * const */*argv*/) + { + return query_wrapper{}; + } +}; +// end::query_boiler_plate[] + +BOOST_SQLITE_EXTENSION(url, conn) +{ + sqlite::create_module(conn, "url", url_module{}); + sqlite::create_module(conn, "segments", segments_module()); + + // tag::query_boiler_plate[] + sqlite::create_module(conn, "query", query_module()); + // end::query_boiler_plate[] + sqlite::create_scalar_function( + conn, "pct_decode", + +[](boost::sqlite::context<> , boost::span s) + { + return urls::pct_string_view(s[0].get_text()).decode(); + }); + + sqlite::create_scalar_function( + conn, "pct_encode", + +[](boost::sqlite::context<> , boost::span s) + { + return urls::encode(s[0].get_text(), urls::pchars); + }); +} \ No newline at end of file -- cgit v1.2.3