most features are implemented #4

Merged
MassiveAtoms merged 20 commits from sqlitecpp into master 2019-06-30 18:34:59 +00:00
6 changed files with 172 additions and 282 deletions
Showing only changes of commit 6be7af0933 - Show all commits

View File

@ -10,95 +10,78 @@
* or copy at http://opensource.org/licenses/MIT)
*/
#include <SQLiteCpp/Backup.h>
#include <SQLiteCpp/Exception.h>
#include <sqlite3.h>
namespace SQLite
{
namespace SQLite {
// Initialize resource for SQLite database backup
Backup::Backup(Database& aDestDatabase,
const char* apDestDatabaseName,
Database& aSrcDatabase,
const char* apSrcDatabaseName) :
mpSQLiteBackup(NULL)
const char* apSrcDatabaseName)
: mpSQLiteBackup(NULL)
{
mpSQLiteBackup = sqlite3_backup_init(aDestDatabase.getHandle(),
apDestDatabaseName,
aSrcDatabase.getHandle(),
apSrcDatabaseName);
if (NULL == mpSQLiteBackup)
{
if (NULL == mpSQLiteBackup) {
// If an error occurs, the error code and message are attached to the destination database connection.
throw SQLite::Exception(aDestDatabase.getHandle());
}
}
// Initialize resource for SQLite database backup
Backup::Backup(Database& aDestDatabase,
const std::string& aDestDatabaseName,
Database& aSrcDatabase,
const std::string& aSrcDatabaseName) :
mpSQLiteBackup(NULL)
const std::string& aSrcDatabaseName)
: mpSQLiteBackup(NULL)
{
mpSQLiteBackup = sqlite3_backup_init(aDestDatabase.getHandle(),
aDestDatabaseName.c_str(),
aSrcDatabase.getHandle(),
aSrcDatabaseName.c_str());
if (NULL == mpSQLiteBackup)
{
if (NULL == mpSQLiteBackup) {
// If an error occurs, the error code and message are attached to the destination database connection.
throw SQLite::Exception(aDestDatabase.getHandle());
}
}
// Initialize resource for SQLite database backup
Backup::Backup(Database &aDestDatabase, Database &aSrcDatabase) :
mpSQLiteBackup(NULL)
Backup::Backup(Database& aDestDatabase, Database& aSrcDatabase)
: mpSQLiteBackup(NULL)
{
mpSQLiteBackup = sqlite3_backup_init(aDestDatabase.getHandle(),
"main",
aSrcDatabase.getHandle(),
"main");
if (NULL == mpSQLiteBackup)
{
if (NULL == mpSQLiteBackup) {
// If an error occurs, the error code and message are attached to the destination database connection.
throw SQLite::Exception(aDestDatabase.getHandle());
}
}
// Release resource for SQLite database backup
Backup::~Backup()
{
if (NULL != mpSQLiteBackup)
{
if (NULL != mpSQLiteBackup) {
sqlite3_backup_finish(mpSQLiteBackup);
}
}
// Execute backup step with a given number of source pages to be copied
int Backup::executeStep(const int aNumPage /* = -1 */)
{
const int res = sqlite3_backup_step(mpSQLiteBackup, aNumPage);
if (SQLITE_OK != res && SQLITE_DONE != res && SQLITE_BUSY != res && SQLITE_LOCKED != res)
{
if (SQLITE_OK != res && SQLITE_DONE != res && SQLITE_BUSY != res && SQLITE_LOCKED != res) {
throw SQLite::Exception(sqlite3_errstr(res), res);
}
return res;
}
// Get the number of remaining source pages to be copied in this backup process
int Backup::getRemainingPageCount()
{
return sqlite3_backup_remaining(mpSQLiteBackup);
}
// Get the number of total source pages to be copied in this backup process
int Backup::getTotalPageCount()
{
return sqlite3_backup_pagecount(mpSQLiteBackup);
}
} // namespace SQLite

View File

@ -9,41 +9,33 @@
* or copy at http://opensource.org/licenses/MIT)
*/
#include <SQLiteCpp/Column.h>
#include <sqlite3.h>
#include <iostream>
namespace SQLite
{
const int INTEGER = SQLITE_INTEGER;
const int FLOAT = SQLITE_FLOAT;
const int TEXT = SQLITE_TEXT;
const int BLOB = SQLITE_BLOB;
const int Null = SQLITE_NULL;
// Encapsulation of a Column in a row of the result pointed by the prepared Statement.
Column::Column(Statement::Ptr& aStmtPtr, int aIndex) noexcept : // nothrow
mStmtPtr(aStmtPtr),
Column::Column(Statement::Ptr& aStmtPtr, int aIndex) noexcept
: // nothrow
mStmtPtr(aStmtPtr)
,
mIndex(aIndex)
{
}
// Finalize and unregister the SQL query from the SQLite Database Connection.
Column::~Column()
{
// the finalization will be done by the destructor of the last shared pointer
}
// Return the named assigned to this result column (potentially aliased)
const char* Column::getName() const noexcept // nothrow
{
return sqlite3_column_name(mStmtPtr, mIndex);
}
#ifdef SQLITE_ENABLE_COLUMN_METADATA
// Return the name of the table column that is the origin of this result column
const char* Column::getOriginName() const noexcept // nothrow
@ -51,74 +43,61 @@ const char* Column::getOriginName() const noexcept // nothrow
return sqlite3_column_origin_name(mStmtPtr, mIndex);
}
#endif
// Return the integer value of the column specified by its index starting at 0
int Column::getInt() const noexcept // nothrow
{
return sqlite3_column_int(mStmtPtr, mIndex);
}
// Return the unsigned integer value of the column specified by its index starting at 0
unsigned Column::getUInt() const noexcept // nothrow
{
return static_cast<unsigned>(getInt64());
}
// Return the 64bits integer value of the column specified by its index starting at 0
long long Column::getInt64() const noexcept // nothrow
{
return sqlite3_column_int64(mStmtPtr, mIndex);
}
// Return the double value of the column specified by its index starting at 0
double Column::getDouble() const noexcept // nothrow
{
return sqlite3_column_double(mStmtPtr, mIndex);
}
// Return a pointer to the text value (NULL terminated string) of the column specified by its index starting at 0
const char* Column::getText(const char* apDefaultValue /* = "" */) const noexcept // nothrow
{
const char* pText = reinterpret_cast<const char*>(sqlite3_column_text(mStmtPtr, mIndex));
return (pText?pText:apDefaultValue);
return (pText ? pText : apDefaultValue);
}
// Return a pointer to the blob value (*not* NULL terminated) of the column specified by its index starting at 0
const void* Column::getBlob() const noexcept // nothrow
{
return sqlite3_column_blob(mStmtPtr, mIndex);
}
// Return a std::string to a TEXT or BLOB column
std::string Column::getString() const
{
// Note: using sqlite3_column_blob and not sqlite3_column_text
// - no need for sqlite3_column_text to add a \0 on the end, as we're getting the bytes length directly
const char *data = static_cast<const char *>(sqlite3_column_blob(mStmtPtr, mIndex));
const char* data = static_cast<const char*>(sqlite3_column_blob(mStmtPtr, mIndex));
// SQLite docs: "The safest policy is to invoke… sqlite3_column_blob() followed by sqlite3_column_bytes()"
// Note: std::string is ok to pass nullptr as first arg, if length is 0
return std::string(data, sqlite3_column_bytes(mStmtPtr, mIndex));
}
// Return the type of the value of the column
int Column::getType() const noexcept // nothrow
{
return sqlite3_column_type(mStmtPtr, mIndex);
}
// Return the number of bytes used by the text value of the column
int Column::getBytes() const noexcept // nothrow
{
return sqlite3_column_bytes(mStmtPtr, mIndex);
}
// Standard std::ostream inserter
std::ostream& operator<<(std::ostream& aStream, const Column& aColumn)
{
aStream.write(aColumn.getText(), aColumn.getBytes());
return aStream;
}
} // namespace SQLite

View File

@ -9,52 +9,42 @@
* or copy at http://opensource.org/licenses/MIT)
*/
#include <SQLiteCpp/Database.h>
#include <SQLiteCpp/Statement.h>
#include <SQLiteCpp/Assertion.h>
#include <SQLiteCpp/Exception.h>
#include <sqlite3.h>
#include <fstream>
#include <string.h>
#ifndef SQLITE_DETERMINISTIC
#define SQLITE_DETERMINISTIC 0x800
#endif // SQLITE_DETERMINISTIC
namespace SQLite
{
const int OPEN_READONLY = SQLITE_OPEN_READONLY;
const int OPEN_READWRITE = SQLITE_OPEN_READWRITE;
const int OPEN_CREATE = SQLITE_OPEN_CREATE;
const int OPEN_URI = SQLITE_OPEN_URI;
const int OK = SQLITE_OK;
const char* VERSION = SQLITE_VERSION;
const int VERSION_NUMBER = SQLITE_VERSION_NUMBER;
// Return SQLite version string using runtime call to the compiled library
const char* getLibVersion() noexcept // nothrow
{
return sqlite3_libversion();
}
// Return SQLite version number using runtime call to the compiled library
int getLibVersionNumber() noexcept // nothrow
{
return sqlite3_libversion_number();
}
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const char* apFilename,
const int aFlags /* = SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs /* = 0 */,
const char* apVfs /* = nullptr*/) :
mpSQLite(nullptr),
const char* apVfs /* = nullptr*/)
:
mpSQLite(nullptr)
,
mFilename(apFilename)
{
const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
@ -69,13 +59,14 @@ Database::Database(const char* apFilename,
setBusyTimeout(aBusyTimeoutMs);
}
}
// 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*/,
const int aBusyTimeoutMs /* = 0 */,
const std::string& aVfs /* = "" */) :
mpSQLite(nullptr),
const std::string& aVfs /* = "" */)
:
mpSQLite(nullptr)
,
mFilename(aFilename)
{
const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? nullptr : aVfs.c_str());
@ -90,20 +81,16 @@ Database::Database(const std::string& aFilename,
setBusyTimeout(aBusyTimeoutMs);
}
}
// Close the SQLite database connection.
Database::~Database()
{
const int ret = sqlite3_close(mpSQLite);
// Avoid unreferenced variable warning when build in release mode
(void) ret;
(void)ret;
// Only case of error is SQLITE_BUSY: "database is locked" (some statements are not finalized)
// Never throw an exception in a destructor :
SQLITECPP_ASSERT(SQLITE_OK == ret, "database is locked"); // See SQLITECPP_ENABLE_ASSERT_HANDLER
}
/**
* @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
*
@ -122,17 +109,14 @@ void Database::setBusyTimeout(const int aBusyTimeoutMs)
const int ret = sqlite3_busy_timeout(mpSQLite, aBusyTimeoutMs);
check(ret);
}
// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
int Database::exec(const char* apQueries)
{
const int ret = sqlite3_exec(mpSQLite, apQueries, nullptr, nullptr, nullptr);
check(ret);
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only)
return sqlite3_changes(mpSQLite);
}
// Shortcut to execute a one step query and fetch the first column of the result.
// 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
@ -145,7 +129,6 @@ Column Database::execAndGet(const char* apQuery)
(void)query.executeStep(); // Can return false if no result, which will throw next line in getColumn()
return query.getColumn(0);
}
// Shortcut to test if a table exists.
bool Database::tableExists(const char* apTableName)
{
@ -154,68 +137,60 @@ bool Database::tableExists(const char* apTableName)
(void)query.executeStep(); // Cannot return false, as the above query always return a result
return (1 == query.getColumn(0).getInt());
}
// Get the rowid of the most recent successful INSERT into the database from the current connection.
long long Database::getLastInsertRowid() const noexcept // nothrow
{
return sqlite3_last_insert_rowid(mpSQLite);
}
// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection.
int Database::getTotalChanges() const noexcept // nothrow
{
return sqlite3_total_changes(mpSQLite);
}
// Return the numeric result code for the most recent failed API call (if any).
int Database::getErrorCode() const noexcept // nothrow
{
return sqlite3_errcode(mpSQLite);
}
// Return the extended numeric result code for the most recent failed API call (if any).
int Database::getExtendedErrorCode() const noexcept // nothrow
{
return sqlite3_extended_errcode(mpSQLite);
}
// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
const char* Database::getErrorMsg() const noexcept // nothrow
{
return sqlite3_errmsg(mpSQLite);
}
// Attach a custom function to your sqlite database. Assumes UTF8 text representation.
// Parameter details can be found here: http://www.sqlite.org/c3ref/create_function.html
void Database::createFunction(const char* apFuncName,
int aNbArg,
bool abDeterministic,
void* apApp,
void (*apFunc)(sqlite3_context *, int, sqlite3_value **),
void (*apStep)(sqlite3_context *, int, sqlite3_value **),
void (*apFinal)(sqlite3_context *), // NOLINT(readability/casting)
void (*apDestroy)(void *))
void (*apFunc)(sqlite3_context*, int, sqlite3_value**),
void (*apStep)(sqlite3_context*, int, sqlite3_value**),
void (*apFinal)(sqlite3_context*), // NOLINT(readability/casting)
void (*apDestroy)(void*))
{
int TextRep = SQLITE_UTF8;
// optimization if deterministic function (e.g. of nondeterministic function random())
if (abDeterministic)
{
TextRep = TextRep|SQLITE_DETERMINISTIC;
TextRep = TextRep | SQLITE_DETERMINISTIC;
}
const int ret = sqlite3_create_function_v2(mpSQLite, apFuncName, aNbArg, TextRep,
apApp, apFunc, apStep, apFinal, apDestroy);
check(ret);
}
// Load an extension into the sqlite database. Only affects the current connection.
// Parameter details can be found here: http://www.sqlite.org/c3ref/load_extension.html
void Database::loadExtension(const char* apExtensionName, const char *apEntryPointName)
void Database::loadExtension(const char* apExtensionName, const char* apEntryPointName)
{
#ifdef SQLITE_OMIT_LOAD_EXTENSION
// Unused
(void)apExtensionName;
(void)apEntryPointName;
throw std::runtime_error("sqlite extensions are disabled");
#else
#ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION // Since SQLite 3.13 (2016-05-18):
@ -229,12 +204,10 @@ void Database::loadExtension(const char* apExtensionName, const char *apEntryPoi
int ret = sqlite3_enable_load_extension(mpSQLite, 1);
#endif
check(ret);
ret = sqlite3_load_extension(mpSQLite, apExtensionName, apEntryPointName, 0);
check(ret);
#endif
}
// Set the key for the current sqlite database instance.
void Database::key(const std::string& aKey) const
{
@ -253,7 +226,6 @@ void Database::key(const std::string& aKey) const
}
#endif // SQLITE_HAS_CODEC
}
// Reset the key for the current sqlite database instance.
void Database::rekey(const std::string& aNewKey) const
{
@ -275,7 +247,6 @@ void Database::rekey(const std::string& aNewKey) const
throw exception;
#endif // SQLITE_HAS_CODEC
}
// Test if a file contains an unencrypted database.
bool Database::isUnencrypted(const std::string& aFilename)
{
@ -299,5 +270,4 @@ bool Database::isUnencrypted(const std::string& aFilename)
const SQLite::Exception exception("Could not open database, the aFilename parameter was empty.");
throw exception;
}
} // namespace SQLite

View File

@ -9,59 +9,66 @@
* or copy at http://opensource.org/licenses/MIT)
*/
#include <SQLiteCpp/Exception.h>
#include <sqlite3.h>
namespace SQLite
{
Exception::Exception(const char* aErrorMessage) :
std::runtime_error(aErrorMessage),
mErrcode(-1), // 0 would be SQLITE_OK, which doesn't make sense
Exception::Exception(const char* aErrorMessage)
:
std::runtime_error(aErrorMessage)
,
mErrcode(-1)
, // 0 would be SQLITE_OK, which doesn't make sense
mExtendedErrcode(-1)
{
}
Exception::Exception(const std::string& aErrorMessage) :
std::runtime_error(aErrorMessage),
mErrcode(-1), // 0 would be SQLITE_OK, which doesn't make sense
Exception::Exception(const std::string& aErrorMessage)
:
std::runtime_error(aErrorMessage)
,
mErrcode(-1)
, // 0 would be SQLITE_OK, which doesn't make sense
mExtendedErrcode(-1)
{
}
Exception::Exception(const char* aErrorMessage, int ret) :
std::runtime_error(aErrorMessage),
mErrcode(ret),
Exception::Exception(const char* aErrorMessage, int ret)
:
std::runtime_error(aErrorMessage)
,
mErrcode(ret)
,
mExtendedErrcode(-1)
{
}
Exception::Exception(const std::string& aErrorMessage, int ret) :
std::runtime_error(aErrorMessage),
mErrcode(ret),
Exception::Exception(const std::string& aErrorMessage, int ret)
:
std::runtime_error(aErrorMessage)
,
mErrcode(ret)
,
mExtendedErrcode(-1)
{
}
Exception::Exception(sqlite3* apSQLite) :
std::runtime_error(sqlite3_errmsg(apSQLite)),
mErrcode(sqlite3_errcode(apSQLite)),
Exception::Exception(sqlite3* apSQLite)
:
std::runtime_error(sqlite3_errmsg(apSQLite))
,
mErrcode(sqlite3_errcode(apSQLite))
,
mExtendedErrcode(sqlite3_extended_errcode(apSQLite))
{
}
Exception::Exception(sqlite3* apSQLite, int ret) :
std::runtime_error(sqlite3_errmsg(apSQLite)),
mErrcode(ret),
Exception::Exception(sqlite3* apSQLite, int ret)
:
std::runtime_error(sqlite3_errmsg(apSQLite))
,
mErrcode(ret)
,
mExtendedErrcode(sqlite3_extended_errcode(apSQLite))
{
}
// Return a string, solely based on the error code
const char* Exception::getErrorStr() const noexcept // nothrow
{
return sqlite3_errstr(mErrcode);
}
} // namespace SQLite

View File

@ -9,45 +9,54 @@
* or copy at http://opensource.org/licenses/MIT)
*/
#include <SQLiteCpp/Statement.h>
#include <SQLiteCpp/Database.h>
#include <SQLiteCpp/Column.h>
#include <SQLiteCpp/Assertion.h>
#include <SQLiteCpp/Exception.h>
#include <sqlite3.h>
namespace SQLite
{
// Compile and register the SQL query for the provided SQLite Database Connection
Statement::Statement(Database &aDatabase, const char* apQuery) :
mQuery(apQuery),
mStmtPtr(aDatabase.mpSQLite, mQuery), // prepare the SQL query, and ref count (needs Database friendship)
mColumnCount(0),
mbHasRow(false),
Statement::Statement(Database& aDatabase, const char* apQuery)
:
mQuery(apQuery)
,
mStmtPtr(aDatabase.mpSQLite, mQuery)
, // prepare the SQL query, and ref count (needs Database friendship)
mColumnCount(0)
,
mbHasRow(false)
,
mbDone(false)
{
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) :
mQuery(aQuery),
mStmtPtr(aDatabase.mpSQLite, mQuery), // prepare the SQL query, and ref count (needs Database friendship)
mColumnCount(0),
mbHasRow(false),
Statement::Statement(Database& aDatabase, const std::string& aQuery)
:
mQuery(aQuery)
,
mStmtPtr(aDatabase.mpSQLite, mQuery)
, // prepare the SQL query, and ref count (needs Database friendship)
mColumnCount(0)
,
mbHasRow(false)
,
mbDone(false)
{
mColumnCount = sqlite3_column_count(mStmtPtr);
}
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)
Statement::Statement(Statement&& aStatement) noexcept :
mQuery(std::move(aStatement.mQuery)),
mStmtPtr(std::move(aStatement.mStmtPtr)),
mColumnCount(aStatement.mColumnCount),
mbHasRow(aStatement.mbHasRow),
Statement::Statement(Statement&& aStatement) noexcept
:
mQuery(std::move(aStatement.mQuery))
,
mStmtPtr(std::move(aStatement.mStmtPtr))
,
mColumnCount(aStatement.mColumnCount)
,
mbHasRow(aStatement.mbHasRow)
,
mbDone(aStatement.mbDone)
{
aStatement.mColumnCount = 0;
@ -55,62 +64,53 @@ Statement::Statement(Statement&& aStatement) noexcept :
aStatement.mbDone = false;
}
#endif
// Finalize and unregister the SQL query from the SQLite Database Connection.
Statement::~Statement()
{
// the finalization will be done by the destructor of the last shared pointer
}
// Reset the statement to make it ready for a new execution (see also #clearBindings() bellow)
void Statement::reset()
{
const int ret = tryReset();
check(ret);
}
int Statement::tryReset() noexcept
{
mbHasRow = false;
mbDone = false;
return sqlite3_reset(mStmtPtr);
}
// Clears away all the bindings of a prepared statement (can be associated with #reset() above).
void Statement::clearBindings()
{
const int ret = sqlite3_clear_bindings(mStmtPtr);
check(ret);
}
// Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const int aValue)
{
const int ret = sqlite3_bind_int(mStmtPtr, aIndex, aValue);
check(ret);
}
// Bind a 32bits unsigned int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const unsigned aValue)
{
const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue);
check(ret);
}
// Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const long long aValue)
{
const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue);
check(ret);
}
// Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const double aValue)
{
const int ret = sqlite3_bind_double(mStmtPtr, aIndex, aValue);
check(ret);
}
// Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const std::string& aValue)
{
@ -118,21 +118,18 @@ void Statement::bind(const int aIndex, const std::string& aValue)
static_cast<int>(aValue.size()), SQLITE_TRANSIENT);
check(ret);
}
// Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const char* apValue)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_TRANSIENT);
check(ret);
}
// Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const void* apValue, const int aSize)
{
const int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_TRANSIENT);
check(ret);
}
// Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const int aIndex, const std::string& aValue)
{
@ -140,29 +137,24 @@ void Statement::bindNoCopy(const int aIndex, const std::string& aValue)
static_cast<int>(aValue.size()), SQLITE_STATIC);
check(ret);
}
// Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const int aIndex, const char* apValue)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_STATIC);
check(ret);
}
// Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const int aIndex, const void* apValue, const int aSize)
{
const int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_STATIC);
check(ret);
}
// Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex)
{
const int ret = sqlite3_bind_null(mStmtPtr, aIndex);
check(ret);
}
// Bind an int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const int aValue)
{
@ -170,7 +162,6 @@ void Statement::bind(const char* apName, const int aValue)
const int ret = sqlite3_bind_int(mStmtPtr, index, aValue);
check(ret);
}
// Bind a 32bits unsigned int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const unsigned aValue)
{
@ -178,7 +169,6 @@ void Statement::bind(const char* apName, const unsigned aValue)
const int ret = sqlite3_bind_int64(mStmtPtr, index, aValue);
check(ret);
}
// Bind a 64bits int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const long long aValue)
{
@ -186,7 +176,6 @@ void Statement::bind(const char* apName, const long long aValue)
const int ret = sqlite3_bind_int64(mStmtPtr, index, aValue);
check(ret);
}
// Bind a double (64bits float) value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const double aValue)
{
@ -194,7 +183,6 @@ void Statement::bind(const char* apName, const double aValue)
const int ret = sqlite3_bind_double(mStmtPtr, index, aValue);
check(ret);
}
// Bind a string value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const std::string& aValue)
{
@ -203,7 +191,6 @@ void Statement::bind(const char* apName, const std::string& aValue)
static_cast<int>(aValue.size()), SQLITE_TRANSIENT);
check(ret);
}
// Bind a text value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const char* apValue)
{
@ -211,7 +198,6 @@ void Statement::bind(const char* apName, const char* apValue)
const int ret = sqlite3_bind_text(mStmtPtr, index, apValue, -1, SQLITE_TRANSIENT);
check(ret);
}
// Bind a binary blob value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName, const void* apValue, const int aSize)
{
@ -219,7 +205,6 @@ void Statement::bind(const char* apName, const void* apValue, const int aSize)
const int ret = sqlite3_bind_blob(mStmtPtr, index, apValue, aSize, SQLITE_TRANSIENT);
check(ret);
}
// Bind a string value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const char* apName, const std::string& aValue)
{
@ -228,7 +213,6 @@ void Statement::bindNoCopy(const char* apName, const std::string& aValue)
static_cast<int>(aValue.size()), SQLITE_STATIC);
check(ret);
}
// Bind a text value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const char* apName, const char* apValue)
{
@ -236,7 +220,6 @@ void Statement::bindNoCopy(const char* apName, const char* apValue)
const int ret = sqlite3_bind_text(mStmtPtr, index, apValue, -1, SQLITE_STATIC);
check(ret);
}
// Bind a binary blob value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const char* apName, const void* apValue, const int aSize)
{
@ -244,7 +227,6 @@ void Statement::bindNoCopy(const char* apName, const void* apValue, const int aS
const int ret = sqlite3_bind_blob(mStmtPtr, index, apValue, aSize, SQLITE_STATIC);
check(ret);
}
// Bind a NULL value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const char* apName)
{
@ -252,8 +234,6 @@ void Statement::bind(const char* apName)
const int ret = sqlite3_bind_null(mStmtPtr, index);
check(ret);
}
// Execute a step of the query to fetch one row of results
bool Statement::executeStep()
{
@ -269,10 +249,8 @@ bool Statement::executeStep()
throw SQLite::Exception("Statement needs to be reseted", ret);
}
}
return mbHasRow; // true only if one row is accessible by getColumn(N)
}
// Execute a one-step query with no expected result
int Statement::exec()
{
@ -292,11 +270,9 @@ int Statement::exec()
throw SQLite::Exception("Statement needs to be reseted", ret);
}
}
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE)
return sqlite3_changes(mStmtPtr);
}
int Statement::tryExecuteStep() noexcept
{
if (false == mbDone)
@ -316,7 +292,6 @@ int Statement::tryExecuteStep() noexcept
mbHasRow = false;
mbDone = false;
}
return ret;
}
else
@ -325,30 +300,24 @@ int Statement::tryExecuteStep() noexcept
return SQLITE_MISUSE;
}
}
// Return a copy of the column data specified by its index starting at 0
// (use the Column copy-constructor)
Column Statement::getColumn(const int aIndex)
{
checkRow();
checkIndex(aIndex);
// Share the Statement Object handle with the new Column created
return Column(mStmtPtr, aIndex);
}
// Return a copy of the column data specified by its column name starting at 0
// (use the Column copy-constructor)
Column Statement::getColumn(const char* apName)
{
checkRow();
const int index = getColumnIndex(apName);
// Share the Statement Object handle with the new Column created
return Column(mStmtPtr, index);
}
// Test if the column is NULL
bool Statement::isColumnNull(const int aIndex) const
{
@ -356,21 +325,18 @@ bool Statement::isColumnNull(const int aIndex) const
checkIndex(aIndex);
return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, aIndex));
}
bool Statement::isColumnNull(const char* apName) const
{
checkRow();
const int index = getColumnIndex(apName);
return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, index));
}
// Return the named assigned to the specified result column (potentially aliased)
const char* Statement::getColumnName(const int aIndex) const
{
checkIndex(aIndex);
return sqlite3_column_name(mStmtPtr, aIndex);
}
#ifdef SQLITE_ENABLE_COLUMN_METADATA
// Return the named assigned to the specified result column (potentially aliased)
const char* Statement::getColumnOriginName(const int aIndex) const
@ -379,7 +345,6 @@ const char* Statement::getColumnOriginName(const int aIndex) const
return sqlite3_column_origin_name(mStmtPtr, aIndex);
}
#endif
// Return the index of the specified (potentially aliased) column name
int Statement::getColumnIndex(const char* apName) const
{
@ -392,60 +357,55 @@ int Statement::getColumnIndex(const char* apName) const
mColumnNames[pName] = i;
}
}
const TColumnNames::const_iterator iIndex = mColumnNames.find(apName);
if (iIndex == mColumnNames.end())
{
throw SQLite::Exception("Unknown column name.");
}
return (*iIndex).second;
}
int Statement::getBindParameterCount() const noexcept
{
return sqlite3_bind_parameter_count(mStmtPtr);
}
// Return the numeric result code for the most recent failed API call (if any).
int Statement::getErrorCode() const noexcept // nothrow
{
return sqlite3_errcode(mStmtPtr);
}
// Return the extended numeric result code for the most recent failed API call (if any).
int Statement::getExtendedErrorCode() const noexcept // nothrow
{
return sqlite3_extended_errcode(mStmtPtr);
}
// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
const char* Statement::getErrorMsg() const noexcept // nothrow
{
return sqlite3_errmsg(mStmtPtr);
}
// Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.
std::string Statement::getExpandedSQL() {
std::string Statement::getExpandedSQL()
{
char* expanded = sqlite3_expanded_sql(mStmtPtr);
std::string expandedString(expanded);
sqlite3_free(expanded);
return expandedString;
}
////////////////////////////////////////////////////////////////////////////////
// Internal class : shared pointer to the sqlite3_stmt SQLite Statement Object
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Prepare the statement and initialize its reference counter
*
* @param[in] apSQLite The sqlite3 database connexion
* @param[in] aQuery The SQL query string to prepare
*/
Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery) :
mpSQLite(apSQLite),
mpStmt(NULL),
Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery)
:
mpSQLite(apSQLite)
,
mpStmt(NULL)
,
mpRefCount(NULL)
{
const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast<int>(aQuery.size()), &mpStmt, NULL);
@ -458,29 +418,32 @@ Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery) :
// This is needed to enable Column objects to live longer than the Statement objet it refers to.
mpRefCount = new unsigned int(1); // NOLINT(readability/casting)
}
/**
* @brief Copy constructor increments the ref counter
*
* @param[in] aPtr Pointer to copy
*/
Statement::Ptr::Ptr(const Statement::Ptr& aPtr) :
mpSQLite(aPtr.mpSQLite),
mpStmt(aPtr.mpStmt),
Statement::Ptr::Ptr(const Statement::Ptr& aPtr)
:
mpSQLite(aPtr.mpSQLite)
,
mpStmt(aPtr.mpStmt)
,
mpRefCount(aPtr.mpRefCount)
{
assert(NULL != mpRefCount);
assert(0 != *mpRefCount);
// Increment the reference counter of the sqlite3_stmt,
// asking not to finalize the sqlite3_stmt during the lifetime of the new objet
++(*mpRefCount);
}
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)
Statement::Ptr::Ptr(Ptr&& aPtr) :
mpSQLite(aPtr.mpSQLite),
mpStmt(aPtr.mpStmt),
Statement::Ptr::Ptr(Ptr&& aPtr)
:
mpSQLite(aPtr.mpSQLite)
,
mpStmt(aPtr.mpStmt)
,
mpRefCount(aPtr.mpRefCount)
{
aPtr.mpSQLite = NULL;
@ -488,7 +451,6 @@ Statement::Ptr::Ptr(Ptr&& aPtr) :
aPtr.mpRefCount = NULL;
}
#endif
/**
* @brief Decrement the ref counter and finalize the sqlite3_stmt when it reaches 0
*/
@ -497,7 +459,6 @@ Statement::Ptr::~Ptr()
if (NULL != mpRefCount)
{
assert(0 != *mpRefCount);
// Decrement and check the reference counter of the sqlite3_stmt
--(*mpRefCount);
if (0 == *mpRefCount)
@ -505,7 +466,6 @@ Statement::Ptr::~Ptr()
// If count reaches zero, finalize the sqlite3_stmt, as no Statement nor Column objet use it anymore.
// No need to check the return code, as it is the same as the last statement evaluation.
sqlite3_finalize(mpStmt);
// and delete the reference counter
delete mpRefCount;
mpRefCount = NULL;
@ -514,6 +474,4 @@ Statement::Ptr::~Ptr()
// else, the finalization will be done later, by the last object
}
}
} // namespace SQLite

View File

@ -9,23 +9,19 @@
* or copy at http://opensource.org/licenses/MIT)
*/
#include <SQLiteCpp/Transaction.h>
#include <SQLiteCpp/Database.h>
#include <SQLiteCpp/Assertion.h>
namespace SQLite
{
// Begins the SQLite transaction
Transaction::Transaction(Database& aDatabase) :
mDatabase(aDatabase),
Transaction::Transaction(Database& aDatabase)
:
mDatabase(aDatabase)
,
mbCommited(false)
{
mDatabase.exec("BEGIN");
}
// Safely rollback the transaction if it has not been committed.
Transaction::~Transaction()
{
@ -41,7 +37,6 @@ Transaction::~Transaction()
}
}
}
// Commit the transaction.
void Transaction::commit()
{
@ -55,6 +50,4 @@ void Transaction::commit()
throw SQLite::Exception("Transaction already commited.");
}
}
} // namespace SQLite