From 805135a4fe85023c0d3043d54ea23a872903f986 Mon Sep 17 00:00:00 2001 From: "jh9216.park" Date: Tue, 6 Dec 2022 20:01:05 -0500 Subject: [PATCH] Add class 'DbException' - It is a std::runtime_error but has some additional methods - The class 'Database' will use it to throw exceptions Change-Id: Icf01850e907e3336545f4c4220d6cccb0a3560f2 Signed-off-by: jh9216.park --- tizen-database/database.hpp | 64 +++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/tizen-database/database.hpp b/tizen-database/database.hpp index 516ae1a..a75c644 100644 --- a/tizen-database/database.hpp +++ b/tizen-database/database.hpp @@ -50,6 +50,32 @@ void for_(F func) { using DbType = std::optional>>; +class DbException : public std::runtime_error { + public: + explicit DbException(const std::string& msg, int code = SQLITE_ERROR) + : std::runtime_error(msg), code_(code) { + } + + DbException(const std::string& msg, int code, const std::string& file, + int line) : std::runtime_error(msg), code_(code) { + msg_ = msg + " at " + file + ":" + std::to_string(line); + } + + int code() const { + return code_; + } + + const char* msg() const { + if (msg_.empty()) + return what(); + return msg_.c_str(); + } + + private: + int code_; + std::string msg_; +}; + class AutoDbType { public: AutoDbType() = default; @@ -57,13 +83,13 @@ class AutoDbType { explicit operator int () { if (!db_type_) - throw std::runtime_error("invalid type conversion from nullopt to int"); + throw DbException("invalid type conversion from nullopt to int"); return std::get(*db_type_); } explicit operator std::string () { if (!db_type_) { - throw std::runtime_error( + throw DbException( "invalid type conversion from nullopt to string"); } @@ -72,7 +98,7 @@ class AutoDbType { explicit operator double () { if (!db_type_) { - throw std::runtime_error( + throw DbException( "invalid type conversion from nullopt to double"); } @@ -81,7 +107,7 @@ class AutoDbType { explicit operator std::vector () { if (!db_type_) { - throw std::runtime_error( + throw DbException( "invalid type conversion from nullopt to std::vector"); } @@ -142,9 +168,9 @@ class Database { } explicit TransactionGuard(sqlite3* db) : db_(db) { - if (sqlite3_exec(db, "BEGIN DEFERRED", nullptr, nullptr, nullptr) - != SQLITE_OK) { - throw std::runtime_error("begin transaction failed"); + int r = sqlite3_exec(db, "BEGIN DEFERRED", nullptr, nullptr, nullptr); + if (r != SQLITE_OK) { + throw DbException("begin transaction failed", r); } } @@ -357,14 +383,14 @@ class Database { int len = sqlite3_column_bytes(stmt, pos); if (!val || len < 0) { - throw std::runtime_error("invalid blob");; + throw DbException("invalid blob");; } else { dbt = DbType(std::vector(val, val + len)); } } else if (type == SQLITE_NULL) { dbt = DbType(std::nullopt); } else { - throw std::runtime_error("invalid column type"); + throw DbException("invalid column type", type); } return AutoDbType(dbt); @@ -505,13 +531,13 @@ class Database { Database(std::string db, int flags) { int r = sqlite3_open_v2(db.c_str(), &db_, flags, nullptr); if (r != SQLITE_OK) - throw std::runtime_error("open failed"); + throw DbException("open failed", r); } Database(std::string db, int flags, std::function busy_handler) { int r = sqlite3_open_v2(db.c_str(), &db_, flags, nullptr); if (r != SQLITE_OK) - throw std::runtime_error("sqlite3_open_v2() failed"); + throw DbException("sqlite3_open_v2() failed", r); busy_handler_ = std::move(busy_handler); r = sqlite3_busy_handler(db_, [](void* data, int count) { @@ -523,7 +549,7 @@ class Database { if (r != SQLITE_OK) { sqlite3_close_v2(db_); - throw std::runtime_error("sqlite3_busy_handler() failed"); + throw DbException("sqlite3_busy_handler() failed", r); } } @@ -558,13 +584,13 @@ class Database { return *this; } - TransactionGuard CreateTransactionGuard() { + TransactionGuard CreateTransactionGuard() const { return TransactionGuard(db_); } Result Exec(const Sql& sql) const { if (!db_) - throw std::runtime_error("Not opened"); + throw DbException("Not opened"); sqlite3_stmt* stmt = nullptr; int r = sqlite3_prepare_v2(db_, sql.GetQuery().c_str(), @@ -587,7 +613,7 @@ class Database { for (const auto& i : sql.GetBindingNameMap()) { int pos = sqlite3_bind_parameter_index(stmt, i.first.c_str()); if (pos == 0) - throw std::runtime_error("Invalid binding"); + throw DbException("Invalid binding"); Bind(pos, i.second, stmt); } @@ -601,7 +627,7 @@ class Database { bool Exec(const Sql& sql, const Result& previous_stmt) { if (sql.GetQuery() != previous_stmt.GetQuery()) - throw std::runtime_error("Query is different"); + throw DbException("Query is different"); sqlite3_stmt* stmt = previous_stmt.GetRaw(); if (!stmt) @@ -623,7 +649,7 @@ class Database { for (const auto& i : sql.GetBindingNameMap()) { int pos = sqlite3_bind_parameter_index(stmt, i.first.c_str()); if (pos == 0) - throw std::runtime_error("Invalid binding"); + throw DbException("Invalid binding"); Bind(pos, i.second, stmt); } @@ -640,7 +666,7 @@ class Database { if (!type) { r = sqlite3_bind_null(stmt, pos); if (r != SQLITE_OK) { - throw std::runtime_error("Invalid binding"); + throw DbException("Invalid binding", r); } return; @@ -662,7 +688,7 @@ class Database { } if (r != SQLITE_OK) { - throw std::runtime_error("Invalid binding"); + throw DbException("Invalid binding"); } } -- 2.7.4