diff --git a/src/ILog.h b/src/ILog.h index 2a55c96..bee8b24 100644 --- a/src/ILog.h +++ b/src/ILog.h @@ -10,17 +10,25 @@ void ILogDebug(const char*); void queue_error_message(const char*); //Used for error conditions within a destructor because you cannot throw within a destructor void queue_fatal_error(const char*); //Used for fatal error conditions within a destructor in place of FatalException because you cannot throw within a destructor +struct sqlite3; + class MyException: public std::exception { private: std::string err; + int err_number; public: virtual ~MyException() override = default; MyException() = delete; - explicit MyException(const std::string &m) noexcept :err(m){} - explicit MyException(const char* sz) noexcept :err(sz) {} + explicit MyException(const std::string &m) noexcept :err(m.c_str()),err_number(-1){} + explicit MyException(const char* sz) noexcept :err(sz),err_number(-1) {} + explicit MyException(const char* sz, int i) noexcept :err(sz), err_number(i) {} + explicit MyException(int, sqlite3*) noexcept; virtual const char* what() const override { return err.c_str(); } + virtual const int what_num() const { + return err_number; + } }; class FatalException : public MyException { @@ -35,12 +43,6 @@ public: HashReuseException() noexcept; }; -class SQLexception : public MyException { -public: - using MyException::MyException; - SQLexception() noexcept; -}; - class NonUtf8DataInDatabase : public MyException { public: using MyException::MyException; diff --git a/src/ISqlit3Impl.cpp b/src/ISqlit3Impl.cpp index cebd543..20ec69f 100644 --- a/src/ISqlit3Impl.cpp +++ b/src/ISqlit3Impl.cpp @@ -24,7 +24,7 @@ void sqlite3_init() { if (sqlite3_initialize() != SQLITE_OK) { errorCode = 7; szError = "Fatal Error: Sqlite library did not init."; -// Cannot log the error, because logging not set up yet, so logging itself causes an exception + // Cannot log the error, because logging not set up yet, so logging itself causes an exception throw FatalException(szError.c_str()); } } @@ -35,7 +35,7 @@ static int callback(void* NotUsed, int argc, char** argv, char** azColName) { std::string str; str.reserve(256); for (int i = 0; i < argc; i++) { - str =str + "\t\"" + azColName[i]+ R"|("=)|" + (argv[i]!=nullptr ? argv[i] : "NULL"); + str = str + "\t\"" + azColName[i] + R"|("=)|" + (argv[i] != nullptr ? argv[i] : "NULL"); } ILogMessage(str.c_str()); return 0; @@ -52,7 +52,7 @@ public: pdb = nullptr; #endif int rc =sqlite3_open_v2(dbName, &pdb, flags, nullptr); - if (rc != SQLITE_OK) throw SQLexception(error_message(rc, pdb)); + if (rc != SQLITE_OK) throw MyException(rc, pdb); assert(pdb != nullptr); // pdb can never be nullptr, since the sqlite3_open_v2 command always initializes // it even if open fails @@ -62,7 +62,7 @@ public: char* zErrMsg = nullptr; int rc = sqlite3_exec(pdb, szsql, callback, nullptr, &zErrMsg); if (rc != SQLITE_OK) { - SQLexception e(std::string("SQL Exec Error: ") + zErrMsg); + auto e = MyException(zErrMsg, rc); sqlite3_free(zErrMsg); throw e; } @@ -90,6 +90,11 @@ ISqlite3* Sqlite3_open(const char * db_name) { return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE); } +MyException::MyException(int i, sqlite3* pdb) noexcept: + err_number(i), + err(error_message(i, pdb)) +{} + // Factory method to create database. ISqlite3 * Sqlite3_create(const char* db_name) { return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); @@ -101,10 +106,10 @@ class IcompiledImpl_sql : friend class ISqlite3Impl; private: sqlite3_stmt *pStmt; - ISqlite3Impl *pdbImplOwn; + ISqlite3Impl*pdbImplOwn; auto e(int rc) { assert(rc != SQLITE_OK); - return SQLexception(error_message(rc, pdbImplOwn->pdb)); + return MyException(rc, pdbImplOwn->pdb); } public: IcompiledImpl_sql() = delete; @@ -192,7 +197,7 @@ public: // from n blocks to n+1 blocks when a single transaction updates the root and anciliary data. // We will build the blockchain hash table in postfix format, with patricia tree nodes that // have skiplink format stored only in memory and rebuilt each startup so that it grows append only, - throw SQLexception("Abnormal busy database"); + throw MyException("Abnormal busy database", 2^14+2); break; case SQLITE_MISUSE: //ret = MISUSE; diff --git a/src/db_accessors.h b/src/db_accessors.h index c13717e..12172d3 100644 --- a/src/db_accessors.h +++ b/src/db_accessors.h @@ -114,8 +114,9 @@ namespace ro { result step() { return (*this)->Isqlite3_step(); } + void final_step() { - if (step() != result::DONE) throw SQLexception("SQL: Unexpected rows remaining"); + if (step() != result::DONE) throw MyException("SQL: Unexpected rows remaining", 16384); } void reset() { (*this)->Isqlite3_reset(); @@ -199,6 +200,15 @@ public: csql_into_names.do_one(psz); csql_namekey_into_keys.do_one(pt); } + catch (const MyException& e) { + csql_rollback.do_one(); + if (e.what_num() == 19) { + throw MyException("Name already in database"); + } + else { + throw; + } + } catch (const std::exception &) { csql_rollback.do_one(); throw; diff --git a/src/localization.cpp b/src/localization.cpp index 10aca9a..03c35ed 100644 --- a/src/localization.cpp +++ b/src/localization.cpp @@ -129,8 +129,6 @@ FatalException::FatalException() noexcept : MyException(R"|(unspecified fatal exception)|") {}; HashReuseException::HashReuseException() noexcept : MyException(R"|(finalized the same hash constructor twice or more)|") {}; -SQLexception::SQLexception() noexcept : - MyException(R"|(SQL Exception)|") {}; BadDataException::BadDataException() noexcept : MyException(R"|(Bad data exception)|") {}; NonUtf8DataInDatabase::NonUtf8DataInDatabase() noexcept :