0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Remove obsolete pointer indirection, fix warnings and a leak

Leak: The sqlite3 connection handle destructor was
accidentally turned into a default constructor during the
migration of repositories.

Replaced the sqlite3 raw pointer with a unique_ptr to prevent
this kind of accident.
This commit is contained in:
Roland Bock 2022-01-10 07:40:36 +01:00
parent 23ae65dd67
commit d6aef0fa9b
6 changed files with 73 additions and 72 deletions

View File

@ -197,7 +197,7 @@ namespace sqlpp
*value = *value =
(reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)))); (reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))));
*len = sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index)); *len = static_cast<size_t>(sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index)));
} }
void _bind_blob_result(size_t index, const uint8_t** value, size_t* len) void _bind_blob_result(size_t index, const uint8_t** value, size_t* len)
@ -207,7 +207,7 @@ namespace sqlpp
*value = *value =
(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(_handle->sqlite_statement, static_cast<int>(index)))); (reinterpret_cast<const uint8_t*>(sqlite3_column_blob(_handle->sqlite_statement, static_cast<int>(index))));
*len = sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index)); *len = static_cast<size_t>(sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index)));
} }
void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null) void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)

View File

@ -64,51 +64,53 @@ namespace sqlpp
namespace detail namespace detail
{ {
inline void handle_cleanup(::sqlite3* sqlite)
{
sqlite3_close(sqlite);
}
struct connection_handle struct connection_handle
{ {
connection_config config; connection_config config;
::sqlite3* sqlite; std::unique_ptr<::sqlite3, void (*)(::sqlite3*)> sqlite;
connection_handle(connection_config conf) : config(conf), sqlite(nullptr) connection_handle(connection_config conf) : config(conf), sqlite(nullptr, handle_cleanup)
{ {
#ifdef SQLPP_DYNAMIC_LOADING #ifdef SQLPP_DYNAMIC_LOADING
init_sqlite(""); init_sqlite("");
#endif #endif
auto rc = sqlite3_open_v2(conf.path_to_database.c_str(), &sqlite, conf.flags, ::sqlite3* sqlite_ptr;
const auto rc = sqlite3_open_v2(conf.path_to_database.c_str(), &sqlite_ptr, conf.flags,
conf.vfs.empty() ? nullptr : conf.vfs.c_str()); conf.vfs.empty() ? nullptr : conf.vfs.c_str());
if (rc != SQLITE_OK) if (rc != SQLITE_OK)
{ {
const std::string msg = sqlite3_errmsg(sqlite); const std::string msg = sqlite3_errmsg(sqlite_ptr);
sqlite3_close(sqlite); sqlite3_close(sqlite_ptr);
throw sqlpp::exception("Sqlite3 error: Can't open database: " + msg); throw sqlpp::exception("Sqlite3 error: Can't open database: " + msg);
} }
sqlite.reset(sqlite_ptr);
#ifdef SQLITE_HAS_CODEC #ifdef SQLITE_HAS_CODEC
if (conf.password.size() > 0) if (conf.password.size() > 0)
{ {
int ret = sqlite3_key(sqlite, conf.password.data(), conf.password.size()); int ret = sqlite3_key(sqlite.get(), conf.password.data(), conf.password.size());
if (ret != SQLITE_OK) if (ret != SQLITE_OK)
{ {
const std::string msg = sqlite3_errmsg(sqlite); const std::string msg = sqlite3_errmsg(sqlite.get());
sqlite3_close(sqlite); sqlite3_close(sqlite.get());
throw sqlpp::exception("Sqlite3 error: Can't set password to database: " + msg); throw sqlpp::exception("Sqlite3 error: Can't set password to database: " + msg);
} }
} }
#endif #endif
} }
connection_handle()
{
auto rc = sqlite3_close(sqlite);
if (rc != SQLITE_OK)
{
std::cerr << "Sqlite3 error: Can't close database: " << sqlite3_errmsg(sqlite) << std::endl;
}
}
connection_handle(const connection_handle&) = delete; connection_handle(const connection_handle&) = delete;
connection_handle(connection_handle&&) = delete; connection_handle(connection_handle&&) = default;
connection_handle& operator=(const connection_handle&) = delete; connection_handle& operator=(const connection_handle&) = delete;
connection_handle& operator=(connection_handle&&) = delete; connection_handle& operator=(connection_handle&&) = default;
~connection_handle() = default;
}; };
inline detail::prepared_statement_handle_t prepare_statement(detail::connection_handle& handle, inline detail::prepared_statement_handle_t prepare_statement(detail::connection_handle& handle,
@ -119,13 +121,13 @@ namespace sqlpp
detail::prepared_statement_handle_t result(nullptr, handle.config.debug); detail::prepared_statement_handle_t result(nullptr, handle.config.debug);
auto rc = sqlite3_prepare_v2(handle.sqlite, statement.c_str(), static_cast<int>(statement.size()), auto rc = sqlite3_prepare_v2(handle.sqlite.get(), statement.c_str(), static_cast<int>(statement.size()),
&result.sqlite_statement, nullptr); &result.sqlite_statement, nullptr);
if (rc != SQLITE_OK) if (rc != SQLITE_OK)
{ {
throw sqlpp::exception( throw sqlpp::exception(
"Sqlite3 error: Could not prepare statement: " + std::string(sqlite3_errmsg(handle.sqlite)) + "Sqlite3 error: Could not prepare statement: " + std::string(sqlite3_errmsg(handle.sqlite.get())) +
" (statement was >>" + (rc == SQLITE_TOOBIG ? statement.substr(0, 128) + "..." : statement) + "<<\n"); " (statement was >>" + (rc == SQLITE_TOOBIG ? statement.substr(0, 128) + "..." : statement) + "<<\n");
} }
@ -145,7 +147,7 @@ namespace sqlpp
if (handle.config.debug) if (handle.config.debug)
std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl; std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl;
throw sqlpp::exception("Sqlite3 error: Could not execute statement: " + throw sqlpp::exception("Sqlite3 error: Could not execute statement: " +
std::string(sqlite3_errmsg(handle.sqlite))); std::string(sqlite3_errmsg(handle.sqlite.get())));
} }
} }
} // namespace detail } // namespace detail
@ -188,7 +190,7 @@ namespace sqlpp
class SQLPP11_SQLITE3_EXPORT connection : public sqlpp::connection class SQLPP11_SQLITE3_EXPORT connection : public sqlpp::connection
{ {
std::unique_ptr<detail::connection_handle> _handle; detail::connection_handle _handle;
enum class transaction_status_type enum class transaction_status_type
{ {
none, none,
@ -202,7 +204,7 @@ namespace sqlpp
bind_result_t select_impl(const std::string& statement) bind_result_t select_impl(const std::string& statement)
{ {
std::unique_ptr<detail::prepared_statement_handle_t> prepared( std::unique_ptr<detail::prepared_statement_handle_t> prepared(
new detail::prepared_statement_handle_t(prepare_statement(*_handle, statement))); new detail::prepared_statement_handle_t(prepare_statement(_handle, statement)));
if (!prepared) if (!prepared)
{ {
throw sqlpp::exception("Sqlite3 error: Could not store result set"); throw sqlpp::exception("Sqlite3 error: Could not store result set");
@ -213,31 +215,31 @@ namespace sqlpp
size_t insert_impl(const std::string& statement) size_t insert_impl(const std::string& statement)
{ {
auto prepared = prepare_statement(*_handle, statement); auto prepared = prepare_statement(_handle, statement);
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
return sqlite3_last_insert_rowid(_handle->sqlite); return static_cast<size_t>(sqlite3_last_insert_rowid(_handle.sqlite.get()));
} }
size_t update_impl(const std::string& statement) size_t update_impl(const std::string& statement)
{ {
auto prepared = prepare_statement(*_handle, statement); auto prepared = prepare_statement(_handle, statement);
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
return sqlite3_changes(_handle->sqlite); return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
} }
size_t remove_impl(const std::string& statement) size_t remove_impl(const std::string& statement)
{ {
auto prepared = prepare_statement(*_handle, statement); auto prepared = prepare_statement(_handle, statement);
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
return sqlite3_changes(_handle->sqlite); return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
} }
// prepared execution // prepared execution
prepared_statement_t prepare_impl(const std::string& statement) prepared_statement_t prepare_impl(const std::string& statement)
{ {
return {std::unique_ptr<detail::prepared_statement_handle_t>( return {std::unique_ptr<detail::prepared_statement_handle_t>(
new detail::prepared_statement_handle_t(prepare_statement(*_handle, statement)))}; new detail::prepared_statement_handle_t(prepare_statement(_handle, statement)))};
} }
bind_result_t run_prepared_select_impl(prepared_statement_t& prepared_statement) bind_result_t run_prepared_select_impl(prepared_statement_t& prepared_statement)
@ -247,30 +249,30 @@ namespace sqlpp
size_t run_prepared_insert_impl(prepared_statement_t& prepared_statement) size_t run_prepared_insert_impl(prepared_statement_t& prepared_statement)
{ {
execute_statement(*_handle, *prepared_statement._handle.get()); execute_statement(_handle, *prepared_statement._handle.get());
return sqlite3_last_insert_rowid(_handle->sqlite); return static_cast<size_t>(sqlite3_last_insert_rowid(_handle.sqlite.get()));
} }
size_t run_prepared_update_impl(prepared_statement_t& prepared_statement) size_t run_prepared_update_impl(prepared_statement_t& prepared_statement)
{ {
execute_statement(*_handle, *prepared_statement._handle.get()); execute_statement(_handle, *prepared_statement._handle.get());
return sqlite3_changes(_handle->sqlite); return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
} }
size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement) size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement)
{ {
execute_statement(*_handle, *prepared_statement._handle.get()); execute_statement(_handle, *prepared_statement._handle.get());
return sqlite3_changes(_handle->sqlite); return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
} }
size_t run_prepared_execute_impl(prepared_statement_t& prepared_statement) size_t run_prepared_execute_impl(prepared_statement_t& prepared_statement)
{ {
execute_statement(*_handle, *prepared_statement._handle.get()); execute_statement(_handle, *prepared_statement._handle.get());
return sqlite3_changes(_handle->sqlite); return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
} }
public: public:
@ -296,7 +298,7 @@ namespace sqlpp
return ::sqlpp::serialize(t, context); return ::sqlpp::serialize(t, context);
} }
connection(connection_config config) : _handle(new detail::connection_handle(std::move(config))) connection(connection_config config) : _handle(std::move(config))
{ {
} }
@ -411,9 +413,9 @@ namespace sqlpp
//! execute arbitrary command (e.g. create a table) //! execute arbitrary command (e.g. create a table)
size_t execute(const std::string& statement) size_t execute(const std::string& statement)
{ {
auto prepared = prepare_statement(*_handle, statement); auto prepared = prepare_statement(_handle, statement);
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
return sqlite3_changes(_handle->sqlite); return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
} }
template < template <
@ -488,7 +490,7 @@ namespace sqlpp
auto prepare(const T& t) auto prepare(const T& t)
-> decltype(this->_prepare(t, typename sqlpp::prepare_check_t<_serializer_context_t, T>::type{})) -> decltype(this->_prepare(t, typename sqlpp::prepare_check_t<_serializer_context_t, T>::type{}))
{ {
sqlpp::prepare_check_t<_serializer_context_t, T>{}; (void) sqlpp::prepare_check_t<_serializer_context_t, T>{};
return _prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{}); return _prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{});
} }
@ -508,8 +510,8 @@ namespace sqlpp
//! get the currently active transaction isolation level //! get the currently active transaction isolation level
sqlpp::isolation_level get_default_isolation_level() sqlpp::isolation_level get_default_isolation_level()
{ {
auto stmt = prepare_statement(*_handle, "pragma read_uncommitted"); auto stmt = prepare_statement(_handle, "pragma read_uncommitted");
execute_statement(*_handle, stmt); execute_statement(_handle, stmt);
int level = sqlite3_column_int(stmt.sqlite_statement, 0); int level = sqlite3_column_int(stmt.sqlite_statement, 0);
@ -525,8 +527,8 @@ namespace sqlpp
} }
_transaction_status = transaction_status_type::maybe; _transaction_status = transaction_status_type::maybe;
auto prepared = prepare_statement(*_handle, "BEGIN"); auto prepared = prepare_statement(_handle, "BEGIN");
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
_transaction_status = transaction_status_type::active; _transaction_status = transaction_status_type::active;
} }
@ -538,8 +540,8 @@ namespace sqlpp
throw sqlpp::exception("Sqlite3 error: Cannot commit a finished or failed transaction"); throw sqlpp::exception("Sqlite3 error: Cannot commit a finished or failed transaction");
} }
_transaction_status = transaction_status_type::maybe; _transaction_status = transaction_status_type::maybe;
auto prepared = prepare_statement(*_handle, "COMMIT"); auto prepared = prepare_statement(_handle, "COMMIT");
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
_transaction_status = transaction_status_type::none; _transaction_status = transaction_status_type::none;
} }
@ -556,8 +558,8 @@ namespace sqlpp
std::cerr << "Sqlite3 warning: Rolling back unfinished transaction" << std::endl; std::cerr << "Sqlite3 warning: Rolling back unfinished transaction" << std::endl;
} }
_transaction_status = transaction_status_type::maybe; _transaction_status = transaction_status_type::maybe;
auto prepared = prepare_statement(*_handle, "ROLLBACK"); auto prepared = prepare_statement(_handle, "ROLLBACK");
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
_transaction_status = transaction_status_type::none; _transaction_status = transaction_status_type::none;
} }
@ -570,19 +572,19 @@ namespace sqlpp
//! get the last inserted id //! get the last inserted id
uint64_t last_insert_id() noexcept uint64_t last_insert_id() noexcept
{ {
return sqlite3_last_insert_rowid(_handle->sqlite); return static_cast<size_t>(sqlite3_last_insert_rowid(_handle.sqlite.get()));
} }
::sqlite3* native_handle() ::sqlite3* native_handle()
{ {
return _handle->sqlite; return _handle.sqlite.get();
} }
schema_t attach(const connection_config& config, const std::string name) schema_t attach(const connection_config& config, const std::string name)
{ {
auto prepared = auto prepared =
prepare_statement(*_handle, "ATTACH '" + escape(config.path_to_database) + "' AS " + escape(name)); prepare_statement(_handle, "ATTACH '" + escape(config.path_to_database) + "' AS " + escape(name));
execute_statement(*_handle, prepared); execute_statement(_handle, prepared);
return {name}; return {name};
} }

View File

@ -41,6 +41,8 @@ namespace sqlpp
} }
connection_config(const connection_config&) = default; connection_config(const connection_config&) = default;
connection_config(connection_config&&) = default; connection_config(connection_config&&) = default;
connection_config& operator=(const connection_config&) = default;
connection_config& operator=(connection_config&&) = default;
connection_config(std::string path, int fl = 0, std::string vf = "", bool dbg = false,std::string password="") connection_config(std::string path, int fl = 0, std::string vf = "", bool dbg = false,std::string password="")
: path_to_database(std::move(path)), flags(fl), vfs(std::move(vf)), debug(dbg),password(password) : path_to_database(std::move(path)), flags(fl), vfs(std::move(vf)), debug(dbg),password(password)

View File

@ -37,7 +37,6 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(pragma) SQLPP_ALIAS_PROVIDER(pragma)
SQLPP_ALIAS_PROVIDER(sub) SQLPP_ALIAS_PROVIDER(sub)
@ -103,8 +102,8 @@ int Sample(int, char*[])
.from(tab) .from(tab)
.unconditionally())) .unconditionally()))
{ {
int x = row.alpha; int64_t x = row.alpha;
int a = row.max; int64_t a = row.max;
std::cout << x << ", " << a << std::endl; std::cout << x << ", " << a << std::endl;
} }
tx.commit(); tx.commit();
@ -136,7 +135,7 @@ int Sample(int, char*[])
std::cerr << "--------" << std::endl; std::cerr << "--------" << std::endl;
ps.params.alpha = sqlpp::eval<sqlpp::integer>(db, "last_insert_rowid()"); ps.params.alpha = sqlpp::eval<sqlpp::integer>(db, "last_insert_rowid()");
ps.params.gamma = "false"; ps.params.gamma = false;
for (const auto& row : db(ps)) for (const auto& row : db(ps))
{ {
std::cerr << "bound result: alpha: " << row.alpha << std::endl; std::cerr << "bound result: alpha: " << row.alpha << std::endl;
@ -188,7 +187,7 @@ int Sample(int, char*[])
auto x = custom_query(sqlpp::verbatim("PRAGMA user_version = "), 1); auto x = custom_query(sqlpp::verbatim("PRAGMA user_version = "), 1);
db(x); db(x);
int pragmaValue = const int64_t pragmaValue =
db(custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(sqlpp::value(1).as(pragma)))) db(custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(sqlpp::value(1).as(pragma))))
.front() .front()
.pragma; .pragma;

View File

@ -38,8 +38,6 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
SQLPP_ALIAS_PROVIDER(left)
namespace sql = sqlpp::sqlite3; namespace sql = sqlpp::sqlite3;
const auto tab = TabSample{}; const auto tab = TabSample{};
@ -143,8 +141,8 @@ int Select(int, char*[])
auto tx = start_transaction(db); auto tx = start_transaction(db);
for (const auto& row : db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally())) for (const auto& row : db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally()))
{ {
int x = row.alpha; const int64_t x = row.alpha;
int a = row.max; const int64_t a = row.max;
std::cout << ">>>" << x << ", " << a << std::endl; std::cout << ">>>" << x << ", " << a << std::endl;
} }
for (const auto& row : for (const auto& row :
@ -161,8 +159,8 @@ int Select(int, char*[])
for (const auto& row : db(select(all_of(tab), select(trim(tab.beta)).from(tab)).from(tab).unconditionally())) for (const auto& row : db(select(all_of(tab), select(trim(tab.beta)).from(tab)).from(tab).unconditionally()))
{ {
int x = row.alpha; const int64_t x = row.alpha;
std::string a = row.trim; const std::string a = row.trim;
std::cout << ">>>" << x << ", " << a << std::endl; std::cout << ">>>" << x << ", " << a << std::endl;
} }

View File

@ -57,7 +57,7 @@ int Transaction(int, char*[])
std::cout << "Expecting default isolation level = 1, is " << static_cast<int>(current_level) << std::endl; std::cout << "Expecting default isolation level = 1, is " << static_cast<int>(current_level) << std::endl;
assert(current_level == sqlpp::isolation_level::serializable); assert(current_level == sqlpp::isolation_level::serializable);
int pragmaValue = db(custom_query(sqlpp::verbatim("PRAGMA read_uncommitted")) int64_t pragmaValue = db(custom_query(sqlpp::verbatim("PRAGMA read_uncommitted"))
.with_result_type_of(select(sqlpp::value(1).as(pragma)))) .with_result_type_of(select(sqlpp::value(1).as(pragma))))
.front() .front()
.pragma; .pragma;