Added a SQLite::Exception class based on std::runtime_error

- Using SQLite::Exception instead of std::runtime_error
- Adding exception spec everywhere
- Simplifing the Database constructor parameters to simply use "flags"
This commit is contained in:
Sebastien Rombauts 2012-03-31 16:16:57 +02:00
parent 26f5b85c3a
commit 047cbcf637
6 changed files with 71 additions and 32 deletions

View File

@ -16,27 +16,21 @@ namespace SQLite
{ {
// Open the provided database UTF-8 filename. // Open the provided database UTF-8 filename.
Database::Database(const char* apFilename, const bool abReadOnly /*= true*/, const bool abCreate /*= false*/) : Database::Database(const char* apFilename, const int aFlags /*= SQLITE_OPEN_READONLY*/) throw (SQLite::Exception) :
mpSQLite(NULL), mpSQLite(NULL),
mFilename (apFilename) mFilename (apFilename)
{ {
int flags = abReadOnly?SQLITE_OPEN_READONLY:SQLITE_OPEN_READWRITE; int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, NULL);
if (abCreate)
{
flags |= SQLITE_OPEN_CREATE;
}
int ret = sqlite3_open_v2(apFilename, &mpSQLite, flags, NULL);
if (SQLITE_OK != ret) if (SQLITE_OK != ret)
{ {
std::string strerr = sqlite3_errmsg(mpSQLite); std::string strerr = sqlite3_errmsg(mpSQLite);
sqlite3_close(mpSQLite); sqlite3_close(mpSQLite);
throw std::runtime_error(strerr); throw SQLite::Exception(strerr);
} }
} }
// Close the SQLite database connection. // Close the SQLite database connection.
Database::~Database(void) Database::~Database(void) throw () // nothrow
{ {
// check for undestroyed statements // check for undestroyed statements
std::vector<Statement*>::iterator iStatement; std::vector<Statement*>::iterator iStatement;
@ -56,13 +50,13 @@ Database::~Database(void)
} }
// Register a Statement object (a SQLite query) // Register a Statement object (a SQLite query)
void Database::registerStatement (Statement& aStatement) void Database::registerStatement (Statement& aStatement) throw (SQLite::Exception)
{ {
mStatementList.push_back (&aStatement); mStatementList.push_back (&aStatement);
} }
// Unregister a Statement object // Unregister a Statement object
void Database::unregisterStatement (Statement& aStatement) void Database::unregisterStatement (Statement& aStatement) throw (SQLite::Exception)
{ {
std::vector<Statement*>::iterator iStatement; std::vector<Statement*>::iterator iStatement;
iStatement = std::find (mStatementList.begin(), mStatementList.end(), &aStatement); iStatement = std::find (mStatementList.begin(), mStatementList.end(), &aStatement);

View File

@ -10,15 +10,16 @@
#pragma once #pragma once
#include <sqlite3.h> #include <sqlite3.h>
#include <stdexcept>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "Exception.h"
namespace SQLite namespace SQLite
{ {
// Forward declaration // Forward declarations
class Statement; class Statement;
class Exception;
/** /**
* @brief Management of a SQLite Database Connection. * @brief Management of a SQLite Database Connection.
@ -34,9 +35,17 @@ public:
/** /**
* @brief Open the provided database UTF-8 filename. * @brief Open the provided database UTF-8 filename.
* *
* Uses sqlite3_open_v2() with readonly default flag, which is the opposite behaviour
* of the old sqlite3_open() function (READWRITE+CREATE).
* This makes sense if you want to use it on a readonly filesystem
* or to prenvent 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. * Exception is thrown in case of error, then the Database object is NOT constructed.
*
* @param[in] apFilename UTF-8 path/uri to the database file ("filename" sqlite3 parameter)
* @param[in] aFlags SQLITE_OPEN_READONLY/SQLITE_OPEN_READWRITE/SQLITE_OPEN_CREATE...
*/ */
explicit Database(const char* apFilename, const bool abReadOnly = true, const bool abCreate = false); explicit Database(const char* apFilename, const int aFlags = SQLITE_OPEN_READONLY) throw (SQLite::Exception);
/** /**
* @brief Close the SQLite database connection. * @brief Close the SQLite database connection.
@ -44,17 +53,17 @@ public:
* All SQLite statements must have been finalized before, * All SQLite statements must have been finalized before,
* so all Statement objects must have been unregistered. * so all Statement objects must have been unregistered.
*/ */
virtual ~Database(void); virtual ~Database(void) throw (); // nothrow
/** /**
* @brief Register a Statement object (a SQLite query) * @brief Register a Statement object (a SQLite query)
*/ */
void registerStatement (Statement& aStatement); void registerStatement (Statement& aStatement) throw (SQLite::Exception);
/** /**
* @brief Unregister a Statement object * @brief Unregister a Statement object
*/ */
void unregisterStatement (Statement& aStatement); void unregisterStatement (Statement& aStatement) throw (SQLite::Exception);
/** /**
* @brief Filename used to open the database * @brief Filename used to open the database

34
src/SQLiteC++/Exception.h Normal file
View File

@ -0,0 +1,34 @@
/**
* @file Exception.h
* @brief Encapsulation of the error message from SQLite3 on a std::runtime_error.
*
* Copyright (c) 2012 Sebastien Rombauts (sebastien dot rombauts at gmail dot com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
*/
#pragma once
#include <stdexcept>
#ifdef _WIN32
#pragma warning(disable:4290) // Disable warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
#endif
namespace SQLite
{
/**
* @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
*/
class Exception : public std::runtime_error
{
public:
Exception(const std::string& aErrorMessage) :
std::runtime_error(aErrorMessage)
{
}
};
}; // namespace SQLite

View File

@ -1,6 +1,6 @@
/** /**
* @file SQLiteC++.h * @file SQLiteC++.h
* @brief SQLiteC++ is a smart and simple C++ SQLite3 wrapper. * @brief SQLiteC++ is a smart and simple C++ SQLite3 wrapper. This file is only "easy include" for other files.
* *
* Copyright (c) 2012 Sebastien Rombauts (sebastien dot rombauts at gmail dot com) * Copyright (c) 2012 Sebastien Rombauts (sebastien dot rombauts at gmail dot com)
* *

View File

@ -16,7 +16,8 @@ namespace SQLite
{ {
// Compile and register the SQL query for the provided SQLite Database Connection // Compile and register the SQL query for the provided SQLite Database Connection
Statement::Statement(Database &aDatabase, const char* apQuery) : Statement::Statement(Database &aDatabase, const char* apQuery) throw (SQLite::Exception) :
mpStmt(NULL),
mDatabase(aDatabase), mDatabase(aDatabase),
mQuery(apQuery), mQuery(apQuery),
mbDone(false) mbDone(false)
@ -24,35 +25,36 @@ Statement::Statement(Database &aDatabase, const char* apQuery) :
int ret = sqlite3_prepare_v2(mDatabase.mpSQLite, mQuery.c_str(), mQuery.size(), &mpStmt, NULL); int ret = sqlite3_prepare_v2(mDatabase.mpSQLite, mQuery.c_str(), mQuery.size(), &mpStmt, NULL);
if (SQLITE_OK != ret) if (SQLITE_OK != ret)
{ {
throw std::runtime_error(sqlite3_errmsg(mDatabase.mpSQLite)); throw SQLite::Exception(sqlite3_errmsg(mDatabase.mpSQLite));
} }
mDatabase.registerStatement(*this); mDatabase.registerStatement(*this);
} }
// Finalize and unregister the SQL query from the SQLite Database Connection. // Finalize and unregister the SQL query from the SQLite Database Connection.
Statement::~Statement(void) Statement::~Statement(void) throw () // nothrow
{ {
int ret = sqlite3_finalize(mpStmt); int ret = sqlite3_finalize(mpStmt);
if (SQLITE_OK != ret) if (SQLITE_OK != ret)
{ {
std::cout << sqlite3_errmsg(mDatabase.mpSQLite); std::cout << sqlite3_errmsg(mDatabase.mpSQLite);
} }
mpStmt = NULL;
mDatabase.unregisterStatement(*this); mDatabase.unregisterStatement(*this);
} }
// Reset the statement to make it ready for a new execution // Reset the statement to make it ready for a new execution
void Statement::reset (void) void Statement::reset (void) throw (SQLite::Exception)
{ {
mbDone = false; mbDone = false;
int ret = sqlite3_reset(mpStmt); int ret = sqlite3_reset(mpStmt);
if (SQLITE_OK != ret) if (SQLITE_OK != ret)
{ {
throw std::runtime_error(sqlite3_errmsg(mDatabase.mpSQLite)); throw SQLite::Exception(sqlite3_errmsg(mDatabase.mpSQLite));
} }
} }
// Execute a step of the query to fetch one row of results // Execute a step of the query to fetch one row of results
bool Statement::executeStep (void) bool Statement::executeStep (void) throw (SQLite::Exception)
{ {
bool bOk = false; bool bOk = false;
@ -70,7 +72,7 @@ bool Statement::executeStep (void)
} }
else else
{ {
throw std::runtime_error(sqlite3_errmsg(mDatabase.mpSQLite)); throw SQLite::Exception(sqlite3_errmsg(mDatabase.mpSQLite));
} }
} }

View File

@ -10,7 +10,7 @@
#pragma once #pragma once
#include <sqlite3.h> #include <sqlite3.h>
#include <stdexcept> #include "Exception.h"
namespace SQLite namespace SQLite
{ {
@ -32,24 +32,24 @@ public:
* *
* Exception is thrown in case of error, then the Statement object is NOT constructed. * Exception is thrown in case of error, then the Statement object is NOT constructed.
*/ */
explicit Statement(Database &aDatabase, const char* apQuery); explicit Statement(Database &aDatabase, const char* apQuery) throw (SQLite::Exception);
/** /**
* @brief Finalize and unregister the SQL query from the SQLite Database Connection. * @brief Finalize and unregister the SQL query from the SQLite Database Connection.
*/ */
virtual ~Statement(void); virtual ~Statement(void) throw (); // nothrow
/** /**
* @brief Reset the statement to make it ready for a new execution. * @brief Reset the statement to make it ready for a new execution.
*/ */
void reset (void); void reset (void) throw (SQLite::Exception);
// TODO bind // TODO bind
/** /**
* @brief Execute a step of the query to fetch one row of results. * @brief Execute a step of the query to fetch one row of results.
*/ */
bool executeStep (void); bool executeStep (void) throw (SQLite::Exception);
/** /**
* @brief UTF-8 SQL Query. * @brief UTF-8 SQL Query.