diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/rgw/driver/dbstore/sqlite/statement.cc | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/rgw/driver/dbstore/sqlite/statement.cc')
-rw-r--r-- | src/rgw/driver/dbstore/sqlite/statement.cc | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/rgw/driver/dbstore/sqlite/statement.cc b/src/rgw/driver/dbstore/sqlite/statement.cc new file mode 100644 index 000000000..dcf7dba9c --- /dev/null +++ b/src/rgw/driver/dbstore/sqlite/statement.cc @@ -0,0 +1,196 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/dout.h" +#include "error.h" +#include "statement.h" + +#define dout_subsys ceph_subsys_rgw_dbstore + +namespace rgw::dbstore::sqlite { + +// owning pointer to arbitrary memory allocated and returned by sqlite3 +struct sqlite_deleter { + template <typename T> + void operator()(T* p) { ::sqlite3_free(p); } +}; +template <typename T> +using sqlite_ptr = std::unique_ptr<T, sqlite_deleter>; + + +stmt_ptr prepare_statement(const DoutPrefixProvider* dpp, + sqlite3* db, std::string_view sql) +{ + sqlite3_stmt* stmt = nullptr; + int result = ::sqlite3_prepare_v2(db, sql.data(), sql.size(), &stmt, nullptr); + auto ec = std::error_code{result, sqlite::error_category()}; + if (ec != sqlite::errc::ok) { + const char* errmsg = ::sqlite3_errmsg(db); + ldpp_dout(dpp, 1) << "preparation failed: " << errmsg + << " (" << ec << ")\nstatement: " << sql << dendl; + throw sqlite::error(errmsg, ec); + } + return stmt_ptr{stmt}; +} + +static int bind_index(const DoutPrefixProvider* dpp, + const stmt_binding& stmt, const char* name) +{ + const int index = ::sqlite3_bind_parameter_index(stmt.get(), name); + if (index <= 0) { + ldpp_dout(dpp, 1) << "binding failed on parameter name=" + << name << dendl; + sqlite3* db = ::sqlite3_db_handle(stmt.get()); + throw sqlite::error(db); + } + return index; +} + +void bind_text(const DoutPrefixProvider* dpp, const stmt_binding& stmt, + const char* name, std::string_view value) +{ + const int index = bind_index(dpp, stmt, name); + + int result = ::sqlite3_bind_text(stmt.get(), index, value.data(), + value.size(), SQLITE_STATIC); + auto ec = std::error_code{result, sqlite::error_category()}; + if (ec != sqlite::errc::ok) { + ldpp_dout(dpp, 1) << "binding failed on parameter name=" + << name << " value=" << value << dendl; + sqlite3* db = ::sqlite3_db_handle(stmt.get()); + throw sqlite::error(db, ec); + } +} + +void bind_int(const DoutPrefixProvider* dpp, const stmt_binding& stmt, + const char* name, int value) +{ + const int index = bind_index(dpp, stmt, name); + + int result = ::sqlite3_bind_int(stmt.get(), index, value); + auto ec = std::error_code{result, sqlite::error_category()}; + if (ec != sqlite::errc::ok) { + ldpp_dout(dpp, 1) << "binding failed on parameter name=" + << name << " value=" << value << dendl; + sqlite3* db = ::sqlite3_db_handle(stmt.get()); + throw sqlite::error(db, ec); + } +} + +void eval0(const DoutPrefixProvider* dpp, const stmt_execution& stmt) +{ + sqlite_ptr<char> sql; + if (dpp->get_cct()->_conf->subsys.should_gather<dout_subsys, 20>()) { + sql.reset(::sqlite3_expanded_sql(stmt.get())); + } + + const int result = ::sqlite3_step(stmt.get()); + auto ec = std::error_code{result, sqlite::error_category()}; + sqlite3* db = ::sqlite3_db_handle(stmt.get()); + + if (ec != sqlite::errc::done) { + const char* errmsg = ::sqlite3_errmsg(db); + ldpp_dout(dpp, 20) << "evaluation failed: " << errmsg + << " (" << ec << ")\nstatement: " << sql.get() << dendl; + throw sqlite::error(errmsg, ec); + } + ldpp_dout(dpp, 20) << "evaluation succeeded: " << sql.get() << dendl; +} + +void eval1(const DoutPrefixProvider* dpp, const stmt_execution& stmt) +{ + sqlite_ptr<char> sql; + if (dpp->get_cct()->_conf->subsys.should_gather<dout_subsys, 20>()) { + sql.reset(::sqlite3_expanded_sql(stmt.get())); + } + + const int result = ::sqlite3_step(stmt.get()); + auto ec = std::error_code{result, sqlite::error_category()}; + if (ec != sqlite::errc::row) { + sqlite3* db = ::sqlite3_db_handle(stmt.get()); + const char* errmsg = ::sqlite3_errmsg(db); + ldpp_dout(dpp, 1) << "evaluation failed: " << errmsg << " (" << ec + << ")\nstatement: " << sql.get() << dendl; + throw sqlite::error(errmsg, ec); + } + ldpp_dout(dpp, 20) << "evaluation succeeded: " << sql.get() << dendl; +} + +int column_int(const stmt_execution& stmt, int column) +{ + return ::sqlite3_column_int(stmt.get(), column); +} + +std::string column_text(const stmt_execution& stmt, int column) +{ + const unsigned char* text = ::sqlite3_column_text(stmt.get(), column); + // may be NULL + if (text) { + const std::size_t size = ::sqlite3_column_bytes(stmt.get(), column); + return {reinterpret_cast<const char*>(text), size}; + } else { + return {}; + } +} + +auto read_text_rows(const DoutPrefixProvider* dpp, + const stmt_execution& stmt, + std::span<std::string> entries) + -> std::span<std::string> +{ + sqlite_ptr<char> sql; + if (dpp->get_cct()->_conf->subsys.should_gather<dout_subsys, 20>()) { + sql.reset(::sqlite3_expanded_sql(stmt.get())); + } + + std::size_t count = 0; + while (count < entries.size()) { + const int result = ::sqlite3_step(stmt.get()); + auto ec = std::error_code{result, sqlite::error_category()}; + if (ec == sqlite::errc::done) { + break; + } + if (ec != sqlite::errc::row) { + sqlite3* db = ::sqlite3_db_handle(stmt.get()); + const char* errmsg = ::sqlite3_errmsg(db); + ldpp_dout(dpp, 1) << "evaluation failed: " << errmsg << " (" << ec + << ")\nstatement: " << sql.get() << dendl; + throw sqlite::error(errmsg, ec); + } + entries[count] = column_text(stmt, 0); + ++count; + } + ldpp_dout(dpp, 20) << "statement evaluation produced " << count + << " results: " << sql.get() << dendl; + + return entries.first(count); +} + +void execute(const DoutPrefixProvider* dpp, sqlite3* db, const char* query, + sqlite3_callback callback, void* arg) +{ + char* errmsg = nullptr; + const int result = ::sqlite3_exec(db, query, callback, arg, &errmsg); + auto ec = std::error_code{result, sqlite::error_category()}; + auto ptr = sqlite_ptr<char>{errmsg}; // free on destruction + if (ec != sqlite::errc::ok) { + ldpp_dout(dpp, 1) << "query execution failed: " << errmsg << " (" << ec + << ")\nquery: " << query << dendl; + throw sqlite::error(errmsg, ec); + } + ldpp_dout(dpp, 20) << "query execution succeeded: " << query << dendl; +} + +} // namespace rgw::dbstore::sqlite |