working test
This commit is contained in:
104
thirdparty/SQLiteCpp/src/Backup.cpp
vendored
Normal file
104
thirdparty/SQLiteCpp/src/Backup.cpp
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file Backup.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Backup is used to backup a database file in a safe and online way.
|
||||
*
|
||||
* Copyright (c) 2015 Shibao HONG (shibaohong@outlook.com)
|
||||
* Copyright (c) 2015-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#include <SQLiteCpp/Backup.h>
|
||||
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
// Initialize resource for SQLite database backup
|
||||
Backup::Backup(Database& aDestDatabase,
|
||||
const char* apDestDatabaseName,
|
||||
Database& aSrcDatabase,
|
||||
const char* apSrcDatabaseName) :
|
||||
mpSQLiteBackup(NULL)
|
||||
{
|
||||
mpSQLiteBackup = sqlite3_backup_init(aDestDatabase.getHandle(),
|
||||
apDestDatabaseName,
|
||||
aSrcDatabase.getHandle(),
|
||||
apSrcDatabaseName);
|
||||
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)
|
||||
{
|
||||
mpSQLiteBackup = sqlite3_backup_init(aDestDatabase.getHandle(),
|
||||
aDestDatabaseName.c_str(),
|
||||
aSrcDatabase.getHandle(),
|
||||
aSrcDatabaseName.c_str());
|
||||
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)
|
||||
{
|
||||
mpSQLiteBackup = sqlite3_backup_init(aDestDatabase.getHandle(),
|
||||
"main",
|
||||
aSrcDatabase.getHandle(),
|
||||
"main");
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
124
thirdparty/SQLiteCpp/src/Column.cpp
vendored
Normal file
124
thirdparty/SQLiteCpp/src/Column.cpp
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file Column.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Encapsulation of a Column in a row of the result pointed by the prepared SQLite::Statement.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* 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),
|
||||
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
|
||||
{
|
||||
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 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));
|
||||
|
||||
// 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
|
303
thirdparty/SQLiteCpp/src/Database.cpp
vendored
Normal file
303
thirdparty/SQLiteCpp/src/Database.cpp
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* @file Database.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Management of a SQLite Database Connection.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* 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),
|
||||
mFilename(apFilename)
|
||||
{
|
||||
const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
|
||||
if (SQLITE_OK != ret)
|
||||
{
|
||||
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
|
||||
sqlite3_close(mpSQLite); // close is required even in case of error on opening
|
||||
throw exception;
|
||||
}
|
||||
if (aBusyTimeoutMs > 0)
|
||||
{
|
||||
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),
|
||||
mFilename(aFilename)
|
||||
{
|
||||
const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? nullptr : aVfs.c_str());
|
||||
if (SQLITE_OK != ret)
|
||||
{
|
||||
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
|
||||
sqlite3_close(mpSQLite); // close is required even in case of error on opening
|
||||
throw exception;
|
||||
}
|
||||
if (aBusyTimeoutMs > 0)
|
||||
{
|
||||
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;
|
||||
|
||||
// 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.
|
||||
*
|
||||
* This is useful in multithreaded program to handle case where a table is locked for writting 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 SQLite::Exception in case of error
|
||||
*/
|
||||
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
|
||||
// (when the underlying temporary Statement and Column objects are destroyed)
|
||||
// this is an issue only for pointer type result (ie. char* and blob)
|
||||
// (use the Column copy-constructor)
|
||||
Column Database::execAndGet(const char* apQuery)
|
||||
{
|
||||
Statement query(*this, 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)
|
||||
{
|
||||
Statement query(*this, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?");
|
||||
query.bind(1, 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 *))
|
||||
{
|
||||
int TextRep = SQLITE_UTF8;
|
||||
// optimization if deterministic function (e.g. of nondeterministic function random())
|
||||
if (abDeterministic)
|
||||
{
|
||||
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)
|
||||
{
|
||||
#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):
|
||||
// Security warning:
|
||||
// It is recommended that the SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION method be used to enable only this interface.
|
||||
// The use of the sqlite3_enable_load_extension() interface should be avoided to keep the SQL load_extension()
|
||||
// disabled and prevent SQL injections from giving attackers access to extension loading capabilities.
|
||||
// (NOTE: not using nullptr: cannot pass object of non-POD type 'std::__1::nullptr_t' through variadic function)
|
||||
int ret = sqlite3_db_config(mpSQLite, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL); // NOTE: not using nullptr
|
||||
#else
|
||||
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
|
||||
{
|
||||
int passLen = static_cast<int>(aKey.length());
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if (passLen > 0)
|
||||
{
|
||||
const int ret = sqlite3_key(mpSQLite, aKey.c_str(), passLen);
|
||||
check(ret);
|
||||
}
|
||||
#else // SQLITE_HAS_CODEC
|
||||
if (passLen > 0)
|
||||
{
|
||||
const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
|
||||
throw exception;
|
||||
}
|
||||
#endif // SQLITE_HAS_CODEC
|
||||
}
|
||||
|
||||
// Reset the key for the current sqlite database instance.
|
||||
void Database::rekey(const std::string& aNewKey) const
|
||||
{
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
int passLen = aNewKey.length();
|
||||
if (passLen > 0)
|
||||
{
|
||||
const int ret = sqlite3_rekey(mpSQLite, aNewKey.c_str(), passLen);
|
||||
check(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int ret = sqlite3_rekey(mpSQLite, nullptr, 0);
|
||||
check(ret);
|
||||
}
|
||||
#else // SQLITE_HAS_CODEC
|
||||
static_cast<void>(aNewKey); // silence unused parameter warning
|
||||
const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
|
||||
throw exception;
|
||||
#endif // SQLITE_HAS_CODEC
|
||||
}
|
||||
|
||||
// Test if a file contains an unencrypted database.
|
||||
bool Database::isUnencrypted(const std::string& aFilename)
|
||||
{
|
||||
if (aFilename.length() > 0)
|
||||
{
|
||||
std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary);
|
||||
char header[16];
|
||||
if (fileBuffer.is_open())
|
||||
{
|
||||
fileBuffer.seekg(0, std::ios::beg);
|
||||
fileBuffer.getline(header, 16);
|
||||
fileBuffer.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
const SQLite::Exception exception("Error opening file: " + aFilename);
|
||||
throw exception;
|
||||
}
|
||||
return strncmp(header, "SQLite format 3\000", 16) == 0;
|
||||
}
|
||||
const SQLite::Exception exception("Could not open database, the aFilename parameter was empty.");
|
||||
throw exception;
|
||||
}
|
||||
|
||||
} // namespace SQLite
|
67
thirdparty/SQLiteCpp/src/Exception.cpp
vendored
Normal file
67
thirdparty/SQLiteCpp/src/Exception.cpp
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file Exception.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Encapsulation of the error message from SQLite3 on a std::runtime_error.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* 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
|
||||
mExtendedErrcode(-1)
|
||||
{
|
||||
}
|
||||
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),
|
||||
mExtendedErrcode(-1)
|
||||
{
|
||||
}
|
||||
|
||||
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)),
|
||||
mExtendedErrcode(sqlite3_extended_errcode(apSQLite))
|
||||
{
|
||||
}
|
||||
|
||||
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
|
519
thirdparty/SQLiteCpp/src/Statement.cpp
vendored
Normal file
519
thirdparty/SQLiteCpp/src/Statement.cpp
vendored
Normal file
@@ -0,0 +1,519 @@
|
||||
/**
|
||||
* @file Statement.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* 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),
|
||||
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),
|
||||
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),
|
||||
mbDone(aStatement.mbDone)
|
||||
{
|
||||
aStatement.mColumnCount = 0;
|
||||
aStatement.mbHasRow = false;
|
||||
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)
|
||||
{
|
||||
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(),
|
||||
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)
|
||||
{
|
||||
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(),
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
const int ret = sqlite3_bind_text(mStmtPtr, index, aValue.c_str(),
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
const int ret = sqlite3_bind_text(mStmtPtr, index, aValue.c_str(),
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
|
||||
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)
|
||||
{
|
||||
const int index = sqlite3_bind_parameter_index(mStmtPtr, 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()
|
||||
{
|
||||
const int ret = tryExecuteStep();
|
||||
if ((SQLITE_ROW != ret) && (SQLITE_DONE != ret)) // on row or no (more) row ready, else it's a problem
|
||||
{
|
||||
if (ret == sqlite3_errcode(mStmtPtr))
|
||||
{
|
||||
throw SQLite::Exception(mStmtPtr, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
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()
|
||||
{
|
||||
const int ret = tryExecuteStep();
|
||||
if (SQLITE_DONE != ret) // the statement has finished executing successfully
|
||||
{
|
||||
if (SQLITE_ROW == ret)
|
||||
{
|
||||
throw SQLite::Exception("exec() does not expect results. Use executeStep.");
|
||||
}
|
||||
else if (ret == sqlite3_errcode(mStmtPtr))
|
||||
{
|
||||
throw SQLite::Exception(mStmtPtr, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
const int ret = sqlite3_step(mStmtPtr);
|
||||
if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
|
||||
{
|
||||
mbHasRow = true;
|
||||
}
|
||||
else if (SQLITE_DONE == ret) // no (more) row ready : the query has finished executing
|
||||
{
|
||||
mbHasRow = false;
|
||||
mbDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mbHasRow = false;
|
||||
mbDone = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Statement needs to be reseted !
|
||||
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
|
||||
{
|
||||
checkRow();
|
||||
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
|
||||
{
|
||||
checkIndex(aIndex);
|
||||
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
|
||||
{
|
||||
// Build the map of column index by name on first call
|
||||
if (mColumnNames.empty())
|
||||
{
|
||||
for (int i = 0; i < mColumnCount; ++i)
|
||||
{
|
||||
const char* pName = sqlite3_column_name(mStmtPtr, i);
|
||||
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() {
|
||||
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),
|
||||
mpRefCount(NULL)
|
||||
{
|
||||
const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast<int>(aQuery.size()), &mpStmt, NULL);
|
||||
if (SQLITE_OK != ret)
|
||||
{
|
||||
throw SQLite::Exception(apSQLite, ret);
|
||||
}
|
||||
// Initialize the reference counter of the sqlite3_stmt :
|
||||
// used to share the mStmtPtr between Statement and Column objects;
|
||||
// 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),
|
||||
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),
|
||||
mpRefCount(aPtr.mpRefCount)
|
||||
{
|
||||
aPtr.mpSQLite = NULL;
|
||||
aPtr.mpStmt = NULL;
|
||||
aPtr.mpRefCount = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Decrement the ref counter and finalize the sqlite3_stmt when it reaches 0
|
||||
*/
|
||||
Statement::Ptr::~Ptr()
|
||||
{
|
||||
if (NULL != mpRefCount)
|
||||
{
|
||||
assert(0 != *mpRefCount);
|
||||
|
||||
// Decrement and check the reference counter of the sqlite3_stmt
|
||||
--(*mpRefCount);
|
||||
if (0 == *mpRefCount)
|
||||
{
|
||||
// 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;
|
||||
mpStmt = NULL;
|
||||
}
|
||||
// else, the finalization will be done later, by the last object
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace SQLite
|
60
thirdparty/SQLiteCpp/src/Transaction.cpp
vendored
Normal file
60
thirdparty/SQLiteCpp/src/Transaction.cpp
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file Transaction.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief A Transaction is way to group multiple SQL statements into an atomic secured operation.
|
||||
*
|
||||
* Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* 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),
|
||||
mbCommited(false)
|
||||
{
|
||||
mDatabase.exec("BEGIN");
|
||||
}
|
||||
|
||||
// Safely rollback the transaction if it has not been committed.
|
||||
Transaction::~Transaction()
|
||||
{
|
||||
if (false == mbCommited)
|
||||
{
|
||||
try
|
||||
{
|
||||
mDatabase.exec("ROLLBACK");
|
||||
}
|
||||
catch (SQLite::Exception&)
|
||||
{
|
||||
// Never throw an exception in a destructor: error if already rollbacked, but no harm is caused by this.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit the transaction.
|
||||
void Transaction::commit()
|
||||
{
|
||||
if (false == mbCommited)
|
||||
{
|
||||
mDatabase.exec("COMMIT");
|
||||
mbCommited = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SQLite::Exception("Transaction already commited.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace SQLite
|
Reference in New Issue
Block a user