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 =
(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)
@ -207,7 +207,7 @@ namespace sqlpp
*value =
(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)

View File

@ -64,51 +64,53 @@ namespace sqlpp
namespace detail
{
inline void handle_cleanup(::sqlite3* sqlite)
{
sqlite3_close(sqlite);
}
struct connection_handle
{
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
init_sqlite("");
#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());
if (rc != SQLITE_OK)
{
const std::string msg = sqlite3_errmsg(sqlite);
sqlite3_close(sqlite);
const std::string msg = sqlite3_errmsg(sqlite_ptr);
sqlite3_close(sqlite_ptr);
throw sqlpp::exception("Sqlite3 error: Can't open database: " + msg);
}
sqlite.reset(sqlite_ptr);
#ifdef SQLITE_HAS_CODEC
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)
{
const std::string msg = sqlite3_errmsg(sqlite);
sqlite3_close(sqlite);
const std::string msg = sqlite3_errmsg(sqlite.get());
sqlite3_close(sqlite.get());
throw sqlpp::exception("Sqlite3 error: Can't set password to database: " + msg);
}
}
#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(connection_handle&&) = delete;
connection_handle(connection_handle&&) = default;
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,
@ -119,13 +121,13 @@ namespace sqlpp
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);
if (rc != SQLITE_OK)
{
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");
}
@ -145,7 +147,7 @@ namespace sqlpp
if (handle.config.debug)
std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl;
throw sqlpp::exception("Sqlite3 error: Could not execute statement: " +
std::string(sqlite3_errmsg(handle.sqlite)));
std::string(sqlite3_errmsg(handle.sqlite.get())));
}
}
} // namespace detail
@ -188,7 +190,7 @@ namespace sqlpp
class SQLPP11_SQLITE3_EXPORT connection : public sqlpp::connection
{
std::unique_ptr<detail::connection_handle> _handle;
detail::connection_handle _handle;
enum class transaction_status_type
{
none,
@ -202,7 +204,7 @@ namespace sqlpp
bind_result_t select_impl(const std::string& statement)
{
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)
{
throw sqlpp::exception("Sqlite3 error: Could not store result set");
@ -213,31 +215,31 @@ namespace sqlpp
size_t insert_impl(const std::string& statement)
{
auto prepared = prepare_statement(*_handle, statement);
execute_statement(*_handle, prepared);
auto prepared = prepare_statement(_handle, statement);
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)
{
auto prepared = prepare_statement(*_handle, statement);
execute_statement(*_handle, prepared);
return sqlite3_changes(_handle->sqlite);
auto prepared = prepare_statement(_handle, statement);
execute_statement(_handle, prepared);
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
}
size_t remove_impl(const std::string& statement)
{
auto prepared = prepare_statement(*_handle, statement);
execute_statement(*_handle, prepared);
return sqlite3_changes(_handle->sqlite);
auto prepared = prepare_statement(_handle, statement);
execute_statement(_handle, prepared);
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
}
// prepared execution
prepared_statement_t prepare_impl(const std::string& statement)
{
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)
@ -247,30 +249,30 @@ namespace sqlpp
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)
{
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)
{
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)
{
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:
@ -296,7 +298,7 @@ namespace sqlpp
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)
size_t execute(const std::string& statement)
{
auto prepared = prepare_statement(*_handle, statement);
execute_statement(*_handle, prepared);
return sqlite3_changes(_handle->sqlite);
auto prepared = prepare_statement(_handle, statement);
execute_statement(_handle, prepared);
return static_cast<size_t>(sqlite3_changes(_handle.sqlite.get()));
}
template <
@ -488,7 +490,7 @@ namespace sqlpp
auto prepare(const T& t)
-> 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>{});
}
@ -508,8 +510,8 @@ namespace sqlpp
//! get the currently active transaction isolation level
sqlpp::isolation_level get_default_isolation_level()
{
auto stmt = prepare_statement(*_handle, "pragma read_uncommitted");
execute_statement(*_handle, stmt);
auto stmt = prepare_statement(_handle, "pragma read_uncommitted");
execute_statement(_handle, stmt);
int level = sqlite3_column_int(stmt.sqlite_statement, 0);
@ -525,8 +527,8 @@ namespace sqlpp
}
_transaction_status = transaction_status_type::maybe;
auto prepared = prepare_statement(*_handle, "BEGIN");
execute_statement(*_handle, prepared);
auto prepared = prepare_statement(_handle, "BEGIN");
execute_statement(_handle, prepared);
_transaction_status = transaction_status_type::active;
}
@ -538,8 +540,8 @@ namespace sqlpp
throw sqlpp::exception("Sqlite3 error: Cannot commit a finished or failed transaction");
}
_transaction_status = transaction_status_type::maybe;
auto prepared = prepare_statement(*_handle, "COMMIT");
execute_statement(*_handle, prepared);
auto prepared = prepare_statement(_handle, "COMMIT");
execute_statement(_handle, prepared);
_transaction_status = transaction_status_type::none;
}
@ -556,8 +558,8 @@ namespace sqlpp
std::cerr << "Sqlite3 warning: Rolling back unfinished transaction" << std::endl;
}
_transaction_status = transaction_status_type::maybe;
auto prepared = prepare_statement(*_handle, "ROLLBACK");
execute_statement(*_handle, prepared);
auto prepared = prepare_statement(_handle, "ROLLBACK");
execute_statement(_handle, prepared);
_transaction_status = transaction_status_type::none;
}
@ -570,19 +572,19 @@ namespace sqlpp
//! get the last inserted id
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()
{
return _handle->sqlite;
return _handle.sqlite.get();
}
schema_t attach(const connection_config& config, const std::string name)
{
auto prepared =
prepare_statement(*_handle, "ATTACH '" + escape(config.path_to_database) + "' AS " + escape(name));
execute_statement(*_handle, prepared);
prepare_statement(_handle, "ATTACH '" + escape(config.path_to_database) + "' AS " + escape(name));
execute_statement(_handle, prepared);
return {name};
}

View File

@ -41,6 +41,8 @@ namespace sqlpp
}
connection_config(const 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="")
: 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 <vector>
SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(pragma)
SQLPP_ALIAS_PROVIDER(sub)
@ -103,8 +102,8 @@ int Sample(int, char*[])
.from(tab)
.unconditionally()))
{
int x = row.alpha;
int a = row.max;
int64_t x = row.alpha;
int64_t a = row.max;
std::cout << x << ", " << a << std::endl;
}
tx.commit();
@ -136,7 +135,7 @@ int Sample(int, char*[])
std::cerr << "--------" << std::endl;
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))
{
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);
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))))
.front()
.pragma;

View File

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