#ifndef CSQLITEDB_H #define CSQLITEDB_H #include "sqlite3.h" #include "CSQLiteException.h" #include "GdCPP_Exports.h" class GDCPP_API CSQLiteDB { friend class CSQLiteStatement; public: /// 构造一个实例,未打开数据库 CSQLiteDB() noexcept : dbErrCode(0) , mpSQLite(nullptr) { } /** * @brief Open the provided database UTF-8 filename. * * @param[in] apFilename UTF-8 path/uri to the database file ("filename" sqlite3 parameter) * @param[in] aFlags flags for sqlite3_open_v2() * * 尽量使用后面的openRW()或openRO() */ int open(const char* apFilename, const int aFlags) noexcept; int open(const std::string &apFilename, const int aFlags) noexcept; inline int openRW(const char* apFilename){ return open(apFilename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); } inline int openRW(const std::string& apFilename) { return open(apFilename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); } inline int openRW(const std::filesystem::path& apFilename) { return open(apFilename.string(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); } inline int openRO(const char* apFilename){ return open(apFilename, SQLITE_OPEN_READONLY); } inline int openRO(const std::string& apFilename) { return open(apFilename, SQLITE_OPEN_READONLY); } inline int openRO(const std::filesystem::path& apFilename) { return open(apFilename.string(), SQLITE_OPEN_READONLY); } int openInRam(const char* apFilename); /** * @brief Close the SQLite database connection. * * All SQLite statements must have been finalized before, * so all Statement objects must have been unregistered. * * @warning assert in case of error */ virtual int close(); virtual ~CSQLiteDB() { close(); } int errcode() { return sqlite3_errcode(mpSQLite); } const char* errmsg() { return sqlite3_errmsg(mpSQLite); } /** * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked. * * This is useful in multithreaded program to handle case where a table is locked for writing by a thread. * Any other thread cannot access the table and will receive a SQLITE_BUSY error: * setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error. * Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;". * Default busy timeout is 0ms. * * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY * * @throw CSQLiteExceptionin case of error */ void setBusyTimeout(const int aBusyTimeoutMs); /** * @brief Shortcut to execute one or multiple statements without results. * * This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" : * - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE" * - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP" * - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK" * * @see Statement::exec() to handle precompiled statements (for better performances) without results * @see Statement::executeStep() to handle "SELECT" queries with results * * @param[in] apQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements * * @return number of rows modified by the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements) * @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement. * * @throw CSQLiteExceptionin case of error */ int exec(const char* apQueries); /** * @brief Shortcut to test if a table exists. * * Table names are case sensitive. * * @param[in] apTableName an UTF-8 encoded case sensitive Table name * * @return true if the table exists. * * @throw CSQLiteException in case of error */ bool tableExists(const char* apTableName); /** * @brief Return raw pointer to SQLite Database Connection Handle. * * This is often needed to mix this wrapper with other libraries or for advance usage not supported by SQLiteCpp. */ inline sqlite3* getHandle() const noexcept // nothrow { return mpSQLite; } inline bool isOpened() { return mpSQLite!=nullptr; } int dbErrCode; std::string dbErrMsg; private: /// @{ Database must be non-copyable CSQLiteDB(const CSQLiteDB&); CSQLiteDB& operator=(const CSQLiteDB&); /// @} /** * @brief Check if aRet equal SQLITE_OK, else throw a CSQLiteException with the SQLite error message */ inline void check(const int aRet) const { if (SQLITE_OK != aRet) { throw CSQLiteException(mpSQLite, aRet); } } protected: sqlite3* mpSQLite; ///< Pointer to SQLite Database Connection Handle std::string mFilename; ///< UTF-8 filename used to open the database public: // 获取数据库文件名 const std::string& getFilename() const { return mFilename; } // 以下与事务相关 // 标记是否启动了事务。true未启动事务 bool bInTransaction = false; inline bool startTransaction() { ASSERT(!bInTransaction); ASSERT(isOpened()); try { exec("BEGIN TRANSACTION"); bInTransaction = true; return true; } catch (CSQLiteException&) { return false; } } inline bool Rollback() { ASSERT(bInTransaction); ASSERT(isOpened()); try { int ret = exec("ROLLBACK"); bInTransaction = false; return true; } catch (CSQLiteException&) { return false; } } inline bool Commit() { ASSERT(bInTransaction); ASSERT(isOpened()); try { int ret = exec("COMMIT"); return true; } catch (CSQLiteException&) { return false; } } }; #endif // CSQLITEDB_H