user friendly error handling of zooko names

Fixed it while dead drunk
could not walk in a straight line
had difficulty typing
coded rather slowly, but still wrote
smart code.

Realized that the error handling
has to have exception structures in
scope, but not the constructors in
scope

You can forward the constructors,
but if you forward the structs,
exceptions will crash.  Your exception
constructor inputs can use structs that
are out of scope at the exception handler
This commit is contained in:
Cheng 2023-02-25 22:05:53 +08:00
parent badd99b74b
commit 61db535769
No known key found for this signature in database
GPG Key ID: 571C3A9C3B9E6FCA
4 changed files with 33 additions and 18 deletions

View File

@ -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_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 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 { class MyException: public std::exception {
private: private:
std::string err; std::string err;
int err_number;
public: public:
virtual ~MyException() override = default; virtual ~MyException() override = default;
MyException() = delete; MyException() = delete;
explicit MyException(const std::string &m) noexcept :err(m){} explicit MyException(const std::string &m) noexcept :err(m.c_str()),err_number(-1){}
explicit MyException(const char* sz) noexcept :err(sz) {} 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 { virtual const char* what() const override {
return err.c_str(); return err.c_str();
} }
virtual const int what_num() const {
return err_number;
}
}; };
class FatalException : public MyException { class FatalException : public MyException {
@ -35,12 +43,6 @@ public:
HashReuseException() noexcept; HashReuseException() noexcept;
}; };
class SQLexception : public MyException {
public:
using MyException::MyException;
SQLexception() noexcept;
};
class NonUtf8DataInDatabase : public MyException { class NonUtf8DataInDatabase : public MyException {
public: public:
using MyException::MyException; using MyException::MyException;

View File

@ -24,7 +24,7 @@ void sqlite3_init() {
if (sqlite3_initialize() != SQLITE_OK) { if (sqlite3_initialize() != SQLITE_OK) {
errorCode = 7; errorCode = 7;
szError = "Fatal Error: Sqlite library did not init."; 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()); throw FatalException(szError.c_str());
} }
} }
@ -35,7 +35,7 @@ static int callback(void* NotUsed, int argc, char** argv, char** azColName) {
std::string str; std::string str;
str.reserve(256); str.reserve(256);
for (int i = 0; i < argc; i++) { 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()); ILogMessage(str.c_str());
return 0; return 0;
@ -52,7 +52,7 @@ public:
pdb = nullptr; pdb = nullptr;
#endif #endif
int rc =sqlite3_open_v2(dbName, &pdb, flags, nullptr); 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); assert(pdb != nullptr);
// pdb can never be nullptr, since the sqlite3_open_v2 command always initializes // pdb can never be nullptr, since the sqlite3_open_v2 command always initializes
// it even if open fails // it even if open fails
@ -62,7 +62,7 @@ public:
char* zErrMsg = nullptr; char* zErrMsg = nullptr;
int rc = sqlite3_exec(pdb, szsql, callback, nullptr, &zErrMsg); int rc = sqlite3_exec(pdb, szsql, callback, nullptr, &zErrMsg);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
SQLexception e(std::string("SQL Exec Error: ") + zErrMsg); auto e = MyException(zErrMsg, rc);
sqlite3_free(zErrMsg); sqlite3_free(zErrMsg);
throw e; throw e;
} }
@ -90,6 +90,11 @@ ISqlite3* Sqlite3_open(const char * db_name) {
return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE); 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. // Factory method to create database.
ISqlite3 * Sqlite3_create(const char* db_name) { ISqlite3 * Sqlite3_create(const char* db_name) {
return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
@ -101,10 +106,10 @@ class IcompiledImpl_sql :
friend class ISqlite3Impl; friend class ISqlite3Impl;
private: private:
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
ISqlite3Impl *pdbImplOwn; ISqlite3Impl*pdbImplOwn;
auto e(int rc) { auto e(int rc) {
assert(rc != SQLITE_OK); assert(rc != SQLITE_OK);
return SQLexception(error_message(rc, pdbImplOwn->pdb)); return MyException(rc, pdbImplOwn->pdb);
} }
public: public:
IcompiledImpl_sql() = delete; 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. // 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 // 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, // 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; break;
case SQLITE_MISUSE: case SQLITE_MISUSE:
//ret = MISUSE; //ret = MISUSE;

View File

@ -114,8 +114,9 @@ namespace ro {
result step() { result step() {
return (*this)->Isqlite3_step(); return (*this)->Isqlite3_step();
} }
void final_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() { void reset() {
(*this)->Isqlite3_reset(); (*this)->Isqlite3_reset();
@ -199,6 +200,15 @@ public:
csql_into_names.do_one(psz); csql_into_names.do_one(psz);
csql_namekey_into_keys.do_one(pt); 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 &) { catch (const std::exception &) {
csql_rollback.do_one(); csql_rollback.do_one();
throw; throw;

View File

@ -129,8 +129,6 @@ FatalException::FatalException() noexcept :
MyException(R"|(unspecified fatal exception)|") {}; MyException(R"|(unspecified fatal exception)|") {};
HashReuseException::HashReuseException() noexcept : HashReuseException::HashReuseException() noexcept :
MyException(R"|(finalized the same hash constructor twice or more)|") {}; MyException(R"|(finalized the same hash constructor twice or more)|") {};
SQLexception::SQLexception() noexcept :
MyException(R"|(SQL Exception)|") {};
BadDataException::BadDataException() noexcept : BadDataException::BadDataException() noexcept :
MyException(R"|(Bad data exception)|") {}; MyException(R"|(Bad data exception)|") {};
NonUtf8DataInDatabase::NonUtf8DataInDatabase() noexcept : NonUtf8DataInDatabase::NonUtf8DataInDatabase() noexcept :