From 905c3d7bb57990aec7907e59add89af43c43e989 Mon Sep 17 00:00:00 2001 From: r4d2 Date: Sun, 12 Jan 2014 00:15:10 +0100 Subject: [PATCH] std::string API (implementing issue #13 --- src/Database.cpp | 14 +++++++++ src/Database.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++ src/Statement.cpp | 11 +++++++ src/Statement.h | 68 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+) diff --git a/src/Database.cpp b/src/Database.cpp index 043a6b0..a13dbbf 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -33,6 +33,20 @@ Database::Database(const char* apFilename, const int aFlags /*= SQLITE_OPEN_READ } } +// Open the provided database UTF-8 filename with SQLITE_OPEN_xxx provided flags. +Database::Database(const std::string& aFilename, const int aFlags /*= SQLITE_OPEN_READONLY*/) : // throw(SQLite::Exception) + mpSQLite(NULL), + mFilename(aFilename) +{ + int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, NULL); + if (SQLITE_OK != ret) + { + std::string strerr = sqlite3_errmsg(mpSQLite); + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw SQLite::Exception(strerr); + } +} + // Close the SQLite database connection. Database::~Database(void) throw() // nothrow { diff --git a/src/Database.h b/src/Database.h index c6451ec..a7cfca7 100644 --- a/src/Database.h +++ b/src/Database.h @@ -56,6 +56,21 @@ public: */ Database(const char* apFilename, const int aFlags = SQLITE_OPEN_READONLY); // throw(SQLite::Exception); + /** + * @brief Open the provided database UTF-8 filename. + * + * Uses sqlite3_open_v2() with readonly default flag, which is the opposite behavior + * of the old sqlite3_open() function (READWRITE+CREATE). + * This makes sense if you want to use it on a readonly filesystem + * or to prevent creation of a void file when a required file is missing. + * + * Exception is thrown in case of error, then the Database object is NOT constructed. + * + * @param[in] aFilename UTF-8 path/uri to the database file ("filename" sqlite3 parameter) + * @param[in] aFlags SQLITE_OPEN_READONLY/SQLITE_OPEN_READWRITE/SQLITE_OPEN_CREATE... + */ + Database(const std::string& aFilename, const int aFlags = SQLITE_OPEN_READONLY); // throw(SQLite::Exception); + /** * @brief Close the SQLite database connection. * @@ -83,6 +98,28 @@ public: */ int exec(const char* apQueries); // throw(SQLite::Exception); + /** + * @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 Definition Language (DDL) statements "CREATE", "ALTER" and "DROP" + * - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE" + * - 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] aQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements + * + * @return number of rows modified by those SQL statements (INSERT, UPDATE or DELETE) + * + * @throw SQLite::Exception in case of error + */ + inline int exec(const std::string& aQueries) // throw(SQLite::Exception); + { + return exec(aQueries.c_str()); + } + /** * @brief Shortcut to execute a one step query and fetch the first column of the result. * @@ -104,6 +141,30 @@ public: */ Column execAndGet(const char* apQuery); // throw(SQLite::Exception); + /** + * @brief Shortcut to execute a one step query and fetch the first column of the result. + * + * This is a shortcut to execute a simple statement with a single result. + * This should be used only for non reusable queries (else you should use a Statement with bind()). + * This should be used only for queries with expected results (else an exception is fired). + * + * @warning WARNING: Be very careful with this dangerous method: you have to + * make a COPY OF THE result, else it will be destroy before the next line + * (when the underlying temporary Statement and Column objects are destroyed) + * + * @see also Statement class for handling queries with multiple results + * + * @param[in] aQuery an UTF-8 encoded SQL query + * + * @return a temporary Column object with the first column of result. + * + * @throw SQLite::Exception in case of error + */ + inline Column execAndGet(const std::string& aQuery) // throw(SQLite::Exception); + { + return execAndGet(aQuery.c_str()); + } + /** * @brief Shortcut to test if a table exists. * @@ -117,6 +178,22 @@ public: */ bool tableExists(const char* apTableName); // throw(SQLite::Exception); + /** + * @brief Shortcut to test if a table exists. + * + * Table names are case sensitive. + * + * @param[in] aTableName an UTF-8 encoded case sensitive Table name + * + * @return true if the table exists. + * + * @throw SQLite::Exception in case of error + */ + inline bool tableExists(const std::string& aTableName) // throw(SQLite::Exception); + { + return tableExists(aTableName.c_str()); + } + /** * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked. * diff --git a/src/Statement.cpp b/src/Statement.cpp index 24ac1fb..54f3546 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -30,6 +30,17 @@ Statement::Statement(Database &aDatabase, const char* apQuery) : // throw(SQLite mColumnCount = sqlite3_column_count(mStmtPtr); } +// Compile and register the SQL query for the provided SQLite Database Connection +Statement::Statement(Database &aDatabase, const std::string& aQuery) : // throw(SQLite::Exception) + mQuery(aQuery), + mStmtPtr(aDatabase.mpSQLite, mQuery), // prepare the SQL query, and ref count (needs Database friendship) + mColumnCount(0), + mbOk(false), + mbDone(false) +{ + mColumnCount = sqlite3_column_count(mStmtPtr); +} + // Finalize and unregister the SQL query from the SQLite Database Connection. Statement::~Statement(void) throw() // nothrow { diff --git a/src/Statement.h b/src/Statement.h index dd3f83b..40232d4 100644 --- a/src/Statement.h +++ b/src/Statement.h @@ -54,6 +54,16 @@ public: */ Statement(Database& aDatabase, const char* apQuery); // throw(SQLite::Exception); + /** + * @brief Compile and register the SQL query for the provided SQLite Database Connection + * + * @param[in] aDatabase the SQLite Database Connection + * @param[in] aQuery an UTF-8 encoded query string + * + * Exception is thrown in case of error, then the Statement object is NOT constructed. + */ + Statement(Database& aDatabase, const std::string& aQuery); // throw(SQLite::Exception); + /** * @brief Finalize and unregister the SQL query from the SQLite Database Connection. */ @@ -150,6 +160,64 @@ public: */ void bind(const char* apName); // throw(SQLite::Exception); // bind NULL value + + /** + * @brief Bind an int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + inline void bind(const std::string& aName, const int& aValue) // throw(SQLite::Exception); + { + bind(aName.c_str(), aValue); + } + /** + * @brief Bind a 64bits int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + inline void bind(const std::string& aName, const sqlite3_int64& aValue) // throw(SQLite::Exception); + { + bind(aName.c_str(), aValue); + } + /** + * @brief Bind a double (64bits float) value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + inline void bind(const std::string& aName, const double& aValue) // throw(SQLite::Exception); + { + bind(aName.c_str(), aValue); + } + /** + * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use + */ + inline void bind(const std::string& aName, const std::string& aValue) // throw(SQLite::Exception); + { + bind(aName.c_str(), aValue); + } + /** + * @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use + */ + inline void bind(const std::string& aName, const char* apValue) // throw(SQLite::Exception); + { + bind(aName.c_str(), apValue); + } + /** + * @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use + */ + inline void bind(const std::string& aName, const void* apValue, const int aSize) // throw(SQLite::Exception); + { + bind(aName.c_str(), apValue, aSize); + } + /** + * @brief Bind a NULL value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + inline void bind(const std::string& aName) // throw(SQLite::Exception); // bind NULL value + { + bind(aName.c_str()); + } + + //////////////////////////////////////////////////////////////////////////// /**