优化,准备使用sqliteCpp重写sqlite模块
This commit is contained in:
@@ -55,6 +55,7 @@ if(ANDROID)
|
||||
${APP_HEADERPP_FILES}
|
||||
${APP_HEADER_FILES}
|
||||
${APP_SRC_FILES}
|
||||
${BREAKPAD_WINDOWS_CC_FILES}
|
||||
${APP_UI_FILES}
|
||||
)
|
||||
else()
|
||||
@@ -65,6 +66,7 @@ else()
|
||||
${APP_HEADERPP_FILES}
|
||||
${APP_HEADER_FILES}
|
||||
${APP_SRC_FILES}
|
||||
${BREAKPAD_WINDOWS_CC_FILES}
|
||||
${APP_UI_FILES} "ff.rc" "icon.qrc")
|
||||
else()
|
||||
message( "/////////////RELEASE///////////////")
|
||||
@@ -75,6 +77,7 @@ else()
|
||||
${APP_HEADERPP_FILES}
|
||||
${APP_HEADER_FILES}
|
||||
${APP_SRC_FILES}
|
||||
${BREAKPAD_WINDOWS_CC_FILES}
|
||||
${APP_UI_FILES} "ff.rc" "icon.qrc" )
|
||||
|
||||
endif()
|
||||
@@ -83,7 +86,6 @@ endif()
|
||||
SET(ALL_DLL
|
||||
${ENV_TARGET}
|
||||
${lib_list}
|
||||
|
||||
)
|
||||
message("all_lib :" ${ALL_DLL})
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
sqlManager::sqlError sqlManager::GetTables(std::vector<std::string>& input)
|
||||
{
|
||||
sqlTableDatas output;
|
||||
dbPtr->Select("", std::vector<std::string>(),"","", output);
|
||||
return success;
|
||||
}
|
||||
std::vector<std::string> getFutureDates(int days)
|
||||
@@ -120,6 +122,8 @@ void sqlManager::initialization(std::string dataBasePath, bool backup)
|
||||
}
|
||||
}
|
||||
std::cout << "SQL init end" << std::endl;
|
||||
std::vector<std::string> input;
|
||||
GetTables(input);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
#include <logService.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#define QtExist 1
|
||||
class core
|
||||
{
|
||||
public:
|
||||
//APP BASIC
|
||||
core() {};
|
||||
logService _logService;
|
||||
};
|
||||
};
|
||||
#pragma once
|
||||
@@ -13,13 +13,10 @@
|
||||
#include <mutex>
|
||||
#include <qfile.h>
|
||||
#include <qcombobox.h>
|
||||
|
||||
static QTextEdit* globalQtTextEdit=nullptr;
|
||||
static QFile* qtLogFile;
|
||||
static QFile* stdLogFile;
|
||||
static QTextStream* globalQtlogFile = nullptr;
|
||||
static QTextStream* globalStdlogFile = nullptr;
|
||||
|
||||
#include <uiModule/components/fancyButton.h>
|
||||
#include <QDate>
|
||||
#include <QString>
|
||||
#include <qline>
|
||||
class logWidget :public QWidget
|
||||
{
|
||||
public:
|
||||
@@ -68,13 +65,13 @@ public:
|
||||
|
||||
stdConsoleOutput.setReadOnly(true);
|
||||
qtConsoleOutput.setReadOnly(true);
|
||||
addConfigWidget(u8"控制台", &stdConsoleOutput, logType::stdConsle);
|
||||
addConfigWidget(u8"QT日志", &qtConsoleOutput, logType::qtConsle);
|
||||
addLogWidget(u8"控制台", &stdConsoleOutput, logType::stdConsle);
|
||||
addLogWidget(u8"QT日志", &qtConsoleOutput, logType::qtConsle);
|
||||
btns[0]->pressed();
|
||||
|
||||
Layout->addWidget(widgets);
|
||||
}
|
||||
void addConfigWidget(QString btnText,QTextEdit* textWidget, logType type)
|
||||
void addLogWidget(QString btnText,QTextEdit* textWidget, logType type)
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::WindowText, Qt::white);
|
||||
@@ -126,35 +123,30 @@ public:
|
||||
toolHLayout->addWidget(lineedit);
|
||||
|
||||
widgetLayout->addWidget(textWidget);
|
||||
if(type==stdConsle)
|
||||
{
|
||||
/*stdConsoleRedirector _stdConsoleRedirector(std::cout, textWidget);
|
||||
stdLogFile = new QFile(QString("./Log/%1StdLog.log").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd")));
|
||||
if (stdLogFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
|
||||
globalStdlogFile = new QTextStream();
|
||||
globalStdlogFile->setCodec("UTF-8");
|
||||
globalStdlogFile->setDevice(stdLogFile);
|
||||
}*/
|
||||
}
|
||||
else if (type == qtConsle)
|
||||
{
|
||||
qtLogFile =new QFile(QString("./Log/%1QtLog.log").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd")));
|
||||
if (qtLogFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
|
||||
globalQtlogFile = new QTextStream();
|
||||
globalQtlogFile->setCodec("UTF-8");
|
||||
globalQtlogFile->setDevice(qtLogFile);
|
||||
}
|
||||
|
||||
globalQtTextEdit = textWidget;
|
||||
//globalQtTextEdit->setUpdatesEnabled(false);
|
||||
/* qInstallMessageHandler(MessageHandler);
|
||||
qInfo() << "This is a Qt Info message.";
|
||||
qWarning() << "This is a Qt Warning message.";
|
||||
qDebug() << "This is a Qt Debug message.";
|
||||
qCritical() << "This is a Qt Critical message.";*/
|
||||
//qFatal("This is a Qt Fatal message.");
|
||||
}
|
||||
textWidget->setStyleSheet("background-color: rgb(30,30,30);");
|
||||
}
|
||||
QString getCurrentDate() {
|
||||
QDate currentDate = QDate::currentDate();
|
||||
return currentDate.toString("yyyy-MM-dd");
|
||||
}
|
||||
QString getCurrentTime() {
|
||||
QTime currentTime = QTime::currentTime();
|
||||
return currentTime.toString("HH:mm:ss.zzz");
|
||||
}
|
||||
public slots:
|
||||
void recvStdLogMsg(QString logMsg)
|
||||
{
|
||||
QString text = "<span style='color: yellow;'>" + getCurrentDate() + "</span> "
|
||||
"<span style='color: yellow;'>" + getCurrentTime() + "</span> "
|
||||
"<span style='color: white;'>" + logMsg + "</span> ";
|
||||
stdConsoleOutput.append(text);
|
||||
}
|
||||
void recvQtLogMsg(QString logMsg)
|
||||
{
|
||||
QString text = "<span style='color: yellow;'>" + getCurrentDate() + "</span> "
|
||||
"<span style='color: yellow;'>" + getCurrentTime() + "</span> "
|
||||
"<span style='color: white;'>" + logMsg + "</span> ";
|
||||
qtConsoleOutput.append(text);
|
||||
}
|
||||
|
||||
};
|
||||
#pragma once
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <appConfig/sqlManager/sqlManager.h>
|
||||
#include <qlabel.h>
|
||||
#include <qstackedwidget.h>
|
||||
#include <FrontendBackendBridge.h>
|
||||
#include <appConfig.hpp>
|
||||
#include <uiModule/components/fancyButton.h>
|
||||
|
||||
class sqliteReader : public QWidget
|
||||
@@ -32,6 +34,7 @@ public:
|
||||
QLabel* icon, * Title;
|
||||
QStackedWidget* widgets = new QStackedWidget();
|
||||
sqliteReader _sqliteReader;
|
||||
QTableWidget* sqlWidget = new QTableWidget();
|
||||
QLabel* disconnnectedLabel = new QLabel("服务已离线");
|
||||
sqlControlWidget()
|
||||
{
|
||||
@@ -55,21 +58,25 @@ public:
|
||||
Title->setPalette(palette);
|
||||
Title->setAlignment(Qt::AlignLeft);
|
||||
|
||||
disconnnectedLabel->setFont(font2);
|
||||
disconnnectedLabel->setPalette(palette);
|
||||
disconnnectedLabel->setAlignment(Qt::AlignCenter);
|
||||
sqlWidget->setFont(font2);
|
||||
sqlWidget->setPalette(palette);
|
||||
//sqlWidget->setAlignment(Qt::AlignCenter);
|
||||
|
||||
Layout->addWidget(Title);
|
||||
|
||||
btnLayout->setContentsMargins(0, 0, 0, 0);
|
||||
btnLayout->setAlignment(Qt::AlignLeft);
|
||||
|
||||
btnLayout->addWidget(disconnnectedLabel);
|
||||
btnLayout->addWidget(sqlWidget);
|
||||
|
||||
Layout->addLayout(btnLayout);
|
||||
|
||||
Layout->addWidget(&_sqliteReader);
|
||||
parsingSqlData();
|
||||
}
|
||||
void parsingSqlData()
|
||||
{
|
||||
bridge._appConfig->_sqlManager;
|
||||
}
|
||||
|
||||
};
|
||||
#pragma once
|
||||
@@ -1,13 +1,52 @@
|
||||
#include <qtLogger.h>
|
||||
#include <stdLogger.hpp>
|
||||
#include <iostream>
|
||||
static std::string logBasePath = "./Log";
|
||||
class logToQtWidget : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void sendStdLogSignal(std::string str)
|
||||
{
|
||||
emit stdLogSignal(QString::fromStdString(str));
|
||||
}
|
||||
void sendQtLogSignal(std::string str)
|
||||
{
|
||||
emit qtLogSignal(QString::fromStdString(str));
|
||||
}
|
||||
signals:
|
||||
void stdLogSignal(QString logMsg);
|
||||
void qtLogSignal(QString logMsg);
|
||||
};
|
||||
class logService
|
||||
{
|
||||
public:
|
||||
stdConsoleRedirector* _stdConsoleRedirector;
|
||||
FileLogger* stdFileLogger;
|
||||
logToQtWidget _logToQtWidget;
|
||||
logService()
|
||||
{
|
||||
//STD日志
|
||||
_stdConsoleRedirector = new stdConsoleRedirector(std::cout);
|
||||
LogMsg::Create(LogMsg::LogMsgType::DebugMsg);
|
||||
//STD日志储存到文件
|
||||
stdFileLogger = new FileLogger(logBasePath);
|
||||
_stdConsoleRedirector->registerCallback([&](const std::string& output) {
|
||||
stdFileLogger->processOutput(output);
|
||||
});
|
||||
//STD日志到Qt界面
|
||||
_stdConsoleRedirector->registerCallback([&](const std::string& output) {
|
||||
_logToQtWidget.sendStdLogSignal(output);
|
||||
});
|
||||
//QT日志
|
||||
LogMsg::Create(LogMsg::LogMsgType::DebugMsg, logBasePath);
|
||||
qtLogCallbacks.push_back(([&](const std::string& output) {
|
||||
_logToQtWidget.sendQtLogSignal(output);
|
||||
}));
|
||||
}
|
||||
};
|
||||
~logService()
|
||||
{
|
||||
delete _stdConsoleRedirector;
|
||||
delete stdFileLogger;
|
||||
}
|
||||
};
|
||||
#pragma once
|
||||
@@ -9,7 +9,7 @@ std::once_flag LogMsg::ms_CreateOnce;
|
||||
QString LogMsg::ms_LogDirPath;
|
||||
LogMsg::LogMsgType LogMsg::ms_LogMstType;
|
||||
QString LogMsg::ms_TrailMSG;
|
||||
|
||||
std::vector<CallbackType> qtLogCallbacks;
|
||||
LogMsg::LogMsg(const LogMsgType logmsgtype)
|
||||
{
|
||||
ms_LogMstType = logmsgtype;
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
|
||||
typedef std::function<void(std::string, std::string)>key_sendMsg;//time msg
|
||||
extern key_sendMsg m_key_callback;
|
||||
|
||||
using CallbackType = std::function<void(const std::string&)>;
|
||||
extern std::vector<CallbackType> qtLogCallbacks;
|
||||
class LogMsg final
|
||||
{
|
||||
private:
|
||||
@@ -57,9 +60,6 @@ public:
|
||||
CriticalMsg,
|
||||
FatalMsg,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static inline void outputMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
if (LogMsgType::InfoMsg == ms_LogMstType && QtDebugMsg == type)
|
||||
@@ -121,27 +121,32 @@ public:
|
||||
const QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz ddd");
|
||||
const QString current_date = QString("(%1)").arg(current_date_time);
|
||||
const QString message = QString("%1 ,%2 ,%3 ,%4 ,%5").arg(current_date).arg(pretext).arg(context_info).arg(msg).arg(ms_TrailMSG) + "\n";
|
||||
const QString message2 = QString("%1 ,%2 ,%3 ,%4 ").arg(pretext).arg(context_info).arg(msg).arg(ms_TrailMSG);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock2(ms_manager->m_LogMsgBufDeqLock);
|
||||
ms_manager->m_LogMsgBufVec.push_back(message);
|
||||
}
|
||||
for (const auto& callback : qtLogCallbacks) {
|
||||
callback(message2.toStdString());
|
||||
}
|
||||
ms_manager->m_BufferCondVar.notify_all();
|
||||
}
|
||||
|
||||
static void SetExtMsg(const std::string& trailmsg)
|
||||
{
|
||||
|
||||
ms_TrailMSG = QString::fromStdString(trailmsg);
|
||||
}
|
||||
|
||||
static int Create(const LogMsgType logmsgtype)
|
||||
static int Create(const LogMsgType logmsgtype,std::string basePath)
|
||||
{
|
||||
int retval{ -1 };
|
||||
std::call_once(ms_CreateOnce, [&]()
|
||||
{
|
||||
const QString workdir = QCoreApplication::applicationDirPath();
|
||||
/*const QString workdir = QCoreApplication::applicationDirPath();
|
||||
ms_LogDirPath = workdir + QDir::separator() + "Log";
|
||||
ms_LogDirPath = QDir::toNativeSeparators(ms_LogDirPath);
|
||||
ms_LogDirPath = QDir::toNativeSeparators(ms_LogDirPath);*/
|
||||
const QString workdir = QString::fromStdString(basePath);
|
||||
ms_LogDirPath = QDir::toNativeSeparators(workdir);
|
||||
const QDir dir(ms_LogDirPath);
|
||||
if (!dir.exists())
|
||||
{
|
||||
|
||||
@@ -2,7 +2,84 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
//SAMPLE
|
||||
class customCallbackFunc {
|
||||
public:
|
||||
virtual void processOutput(const std::string& output) {
|
||||
std::cout << "customCallbackFunc received: " << output;
|
||||
}
|
||||
};
|
||||
|
||||
//输出到文件
|
||||
class FileLogger : public customCallbackFunc {
|
||||
public:
|
||||
FileLogger(std::string basePath):logBasePath(basePath){
|
||||
updateLogFile();
|
||||
}
|
||||
|
||||
~FileLogger() {
|
||||
if (logFile.is_open()) {
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void processOutput(const std::string& output) override {
|
||||
updateLogFileIfNeeded();
|
||||
if (logFile.is_open()) {
|
||||
logFile << (getCurrentTime()+">>>"+output);
|
||||
logFile.flush();
|
||||
}
|
||||
else {
|
||||
std::cerr << "Failed to write to log file: file is not open" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string logBasePath;
|
||||
std::ofstream logFile;
|
||||
std::string currentDate;
|
||||
std::string getCurrentDate() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d");
|
||||
return oss.str();
|
||||
}
|
||||
std::string getCurrentTime() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()) % 1000000;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(std::localtime(&in_time_t), "(%Y-%m-%d %H-%M-%S");
|
||||
oss << " " << std::setfill('0') << std::setw(6) << microseconds.count()<<"):";
|
||||
return oss.str();
|
||||
}
|
||||
void updateLogFile() {
|
||||
currentDate = getCurrentDate();
|
||||
std::string filename = logBasePath+"/"+currentDate + "std.log";
|
||||
if (logFile.is_open()) {
|
||||
logFile.close();
|
||||
}
|
||||
logFile.open(filename, std::ios::app);
|
||||
if (!logFile.is_open()) {
|
||||
throw std::runtime_error("Unable to open log file: " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
void updateLogFileIfNeeded() {
|
||||
std::string newDate = getCurrentDate();
|
||||
if (newDate != currentDate) {
|
||||
updateLogFile();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//截取std::cout的内容
|
||||
class stdConsoleRedirector : public std::streambuf {
|
||||
public:
|
||||
using CallbackType = std::function<void(const std::string&)>;
|
||||
@@ -11,7 +88,6 @@ public:
|
||||
: originalStream(stream), originalBuffer(stream.rdbuf(this)) {}
|
||||
|
||||
~stdConsoleRedirector() {
|
||||
// 恢复原始的缓冲区
|
||||
originalStream.rdbuf(originalBuffer);
|
||||
}
|
||||
|
||||
@@ -21,7 +97,6 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
// 重载overflow方法来拦截输出
|
||||
virtual int overflow(int c) override {
|
||||
if (c == EOF) {
|
||||
return EOF;
|
||||
@@ -30,7 +105,6 @@ protected:
|
||||
char ch = static_cast<char>(c);
|
||||
buffer += ch;
|
||||
if (ch == '\n') {
|
||||
// 当遇到换行符时,调用所有回调函数
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(buffer);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
#include <uiModule/uiModule_imageDoubleCheckQdialog.h>
|
||||
|
||||
#include <core.hpp>
|
||||
|
||||
void connectSignalAndSlots(MainWindow* front, backEndManager* back)
|
||||
void connectSignalAndSlots(MainWindow* front, backEndManager* back, core* _core)
|
||||
{
|
||||
QObject::connect(back, &backEndManager::sendPixmapImageWidget, front, &MainWindow::recvPixmapImageWidget);
|
||||
QObject::connect(back, &backEndManager::sendInitString, front, &MainWindow::recvInitString);
|
||||
@@ -38,9 +37,21 @@ void connectSignalAndSlots(MainWindow* front, backEndManager* back)
|
||||
back, &backEndManager::startManualDetSlot);
|
||||
QObject::connect(front->_displayWidget->_switchProductWidget, &switchProductWidget::startArmProgramSignal,
|
||||
back, &backEndManager::writeArmStartSignal);
|
||||
///////////TEMP
|
||||
QObject::connect(&_core->_logService._logToQtWidget, &logToQtWidget::stdLogSignal,
|
||||
front->_logWidget, &logWidget::recvStdLogMsg);
|
||||
QObject::connect(&_core->_logService._logToQtWidget, &logToQtWidget::qtLogSignal,
|
||||
front->_logWidget, &logWidget::recvQtLogMsg);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
HWND hWnd = GetConsoleWindow();
|
||||
if (hWnd) {
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
}// 隐藏控制台窗口
|
||||
|
||||
core _core;
|
||||
QApplication a(argc, argv);
|
||||
//检测是否已运行
|
||||
@@ -66,7 +77,7 @@ int main(int argc, char* argv[])
|
||||
MainWindow w(&_appConfig);
|
||||
w.show();
|
||||
backEndManager _backEnd(&_appConfig);
|
||||
connectSignalAndSlots(&w,&_backEnd);
|
||||
connectSignalAndSlots(&w,&_backEnd,&_core);
|
||||
_backEnd.initialization();
|
||||
return a.exec();
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file Assertion.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Definition of the SQLITECPP_ASSERT() macro.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* SQLITECPP_ASSERT SQLITECPP_ASSERT() is used in destructors, where exceptions shall not be thrown
|
||||
*
|
||||
* Define SQLITECPP_ENABLE_ASSERT_HANDLER at the project level
|
||||
* and define a SQLite::assertion_failed() assertion handler
|
||||
* to tell SQLiteC++ to use it instead of assert() when an assertion fail.
|
||||
*/
|
||||
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
|
||||
|
||||
// if an assert handler is provided by user code, use it instead of assert()
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
// declaration of the assert handler to define in user code
|
||||
void assertion_failed(const char* apFile, const int apLine, const char* apFunc,
|
||||
const char* apExpr, const char* apMsg);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
// call the assert handler provided by user code
|
||||
#define SQLITECPP_ASSERT(expression, message) \
|
||||
if (!(expression)) SQLite::assertion_failed(__FILE__, __LINE__, __func__, #expression, message)
|
||||
|
||||
} // namespace SQLite
|
||||
|
||||
#else
|
||||
|
||||
// if no assert handler provided by user code, use standard assert()
|
||||
// (note: in release mode assert() does nothing)
|
||||
#define SQLITECPP_ASSERT(expression, message) assert(expression && message)
|
||||
|
||||
#endif
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file Backup.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Backup is used to backup a database file in a safe and online way.
|
||||
*
|
||||
* Copyright (c) 2015 Shibao HONG ([email protected])
|
||||
* Copyright (c) 2015-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Database.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Forward declaration to avoid inclusion of <sqlite3.h> in a header
|
||||
struct sqlite3_backup;
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief RAII encapsulation of a SQLite Database Backup process.
|
||||
*
|
||||
* A Backup object is used to backup a source database file to a destination database file
|
||||
* in a safe and online way.
|
||||
*
|
||||
* See also the a reference implementation of live backup taken from the official site:
|
||||
* https://www.sqlite.org/backup.html
|
||||
*/
|
||||
class SQLITECPP_API Backup
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize a SQLite Backup object.
|
||||
*
|
||||
* Initialize a SQLite Backup object for the source database and destination database.
|
||||
* The database name is "main" for the main database, "temp" for the temporary database,
|
||||
* or the name specified after the AS keyword in an ATTACH statement for an attached database.
|
||||
*
|
||||
* Exception is thrown in case of error, then the Backup object is NOT constructed.
|
||||
*
|
||||
* @param[in] aDestDatabase Destination database connection
|
||||
* @param[in] apDestDatabaseName Destination database name
|
||||
* @param[in] aSrcDatabase Source database connection
|
||||
* @param[in] apSrcDatabaseName Source database name
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Backup(Database& aDestDatabase,
|
||||
const char* apDestDatabaseName,
|
||||
Database& aSrcDatabase,
|
||||
const char* apSrcDatabaseName);
|
||||
|
||||
/**
|
||||
* @brief Initialize a SQLite Backup object.
|
||||
*
|
||||
* Initialize a SQLite Backup object for source database and destination database.
|
||||
* The database name is "main" for the main database, "temp" for the temporary database,
|
||||
* or the name specified after the AS keyword in an ATTACH statement for an attached database.
|
||||
*
|
||||
* Exception is thrown in case of error, then the Backup object is NOT constructed.
|
||||
*
|
||||
* @param[in] aDestDatabase Destination database connection
|
||||
* @param[in] aDestDatabaseName Destination database name
|
||||
* @param[in] aSrcDatabase Source database connection
|
||||
* @param[in] aSrcDatabaseName Source database name
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Backup(Database& aDestDatabase,
|
||||
const std::string& aDestDatabaseName,
|
||||
Database& aSrcDatabase,
|
||||
const std::string& aSrcDatabaseName);
|
||||
|
||||
/**
|
||||
* @brief Initialize a SQLite Backup object for main databases.
|
||||
*
|
||||
* Initialize a SQLite Backup object for source database and destination database.
|
||||
* Backup the main databases between the source and the destination.
|
||||
*
|
||||
* Exception is thrown in case of error, then the Backup object is NOT constructed.
|
||||
*
|
||||
* @param[in] aDestDatabase Destination database connection
|
||||
* @param[in] aSrcDatabase Source database connection
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Backup(Database& aDestDatabase,
|
||||
Database& aSrcDatabase);
|
||||
|
||||
// Backup is non-copyable
|
||||
Backup(const Backup&) = delete;
|
||||
Backup& operator=(const Backup&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Execute a step of backup with a given number of source pages to be copied
|
||||
*
|
||||
* Exception is thrown when SQLITE_IOERR_XXX, SQLITE_NOMEM, or SQLITE_READONLY is returned
|
||||
* in sqlite3_backup_step(). These errors are considered fatal, so there is no point
|
||||
* in retrying the call to executeStep().
|
||||
*
|
||||
* @param[in] aNumPage The number of source pages to be copied, with a negative value meaning all remaining source pages
|
||||
*
|
||||
* @return SQLITE_OK/SQLITE_DONE/SQLITE_BUSY/SQLITE_LOCKED
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
int executeStep(const int aNumPage = -1);
|
||||
|
||||
/// Return the number of source pages still to be backed up as of the most recent call to executeStep().
|
||||
int getRemainingPageCount() const;
|
||||
|
||||
/// Return the total number of pages in the source database as of the most recent call to executeStep().
|
||||
int getTotalPageCount() const;
|
||||
|
||||
private:
|
||||
// Deleter functor to use with smart pointers to close the SQLite database backup in an RAII fashion.
|
||||
struct Deleter
|
||||
{
|
||||
void operator()(sqlite3_backup* apBackup);
|
||||
};
|
||||
|
||||
std::unique_ptr<sqlite3_backup, Deleter> mpSQLiteBackup; ///< Pointer to SQLite Database Backup Handle
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* @file Column.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Encapsulation of a Column in a row of the result pointed by the prepared SQLite::Statement.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Statement.h>
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations to avoid inclusion of <sqlite3.h> in a header
|
||||
struct sqlite3_stmt;
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
SQLITECPP_API extern const int INTEGER; ///< SQLITE_INTEGER
|
||||
SQLITECPP_API extern const int FLOAT; ///< SQLITE_FLOAT
|
||||
SQLITECPP_API extern const int TEXT; ///< SQLITE_TEXT
|
||||
SQLITECPP_API extern const int BLOB; ///< SQLITE_BLOB
|
||||
SQLITECPP_API extern const int Null; ///< SQLITE_NULL
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of a Column in a row of the result pointed by the prepared Statement.
|
||||
*
|
||||
* A Column is a particular field of SQLite data in the current row of result
|
||||
* of the Statement : it points to a single cell.
|
||||
*
|
||||
* Its value can be expressed as a text, and, when applicable, as a numeric
|
||||
* (integer or floating point) or a binary blob.
|
||||
*
|
||||
* Thread-safety: a Column object shall not be shared by multiple threads, because :
|
||||
* 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
|
||||
* provided that no single database connection is used simultaneously in two or more threads."
|
||||
* 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
|
||||
* because of the way it shares the underling SQLite precompiled statement
|
||||
* in a custom shared pointer (See the inner class "Statement::Ptr").
|
||||
*/
|
||||
class SQLITECPP_API Column
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Encapsulation of a Column in a Row of the result.
|
||||
*
|
||||
* @param[in] aStmtPtr Shared pointer to the prepared SQLite Statement Object.
|
||||
* @param[in] aIndex Index of the column in the row of result, starting at 0
|
||||
*/
|
||||
explicit Column(const Statement::TStatementPtr& aStmtPtr, int aIndex);
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the named assigned to this result column (potentially aliased)
|
||||
*
|
||||
* @see getOriginName() to get original column name (not aliased)
|
||||
*/
|
||||
const char* getName() const noexcept;
|
||||
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
/**
|
||||
* @brief Return a pointer to the table column name that is the origin of this result column
|
||||
*
|
||||
* Require definition of the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro :
|
||||
* - when building the SQLite library itself (which is the case for the Debian libsqlite3 binary for instance),
|
||||
* - and also when compiling this wrapper.
|
||||
*/
|
||||
const char* getOriginName() const noexcept;
|
||||
#endif
|
||||
|
||||
/// Return the integer value of the column.
|
||||
int32_t getInt() const noexcept;
|
||||
/// Return the 32bits unsigned integer value of the column (note that SQLite3 does not support unsigned 64bits).
|
||||
uint32_t getUInt() const noexcept;
|
||||
/// Return the 64bits integer value of the column (note that SQLite3 does not support unsigned 64bits).
|
||||
int64_t getInt64() const noexcept;
|
||||
/// Return the double (64bits float) value of the column
|
||||
double getDouble() const noexcept;
|
||||
/**
|
||||
* @brief Return a pointer to the text value (NULL terminated string) of the column.
|
||||
*
|
||||
* @warning The value pointed at is only valid while the statement is valid (ie. not finalized),
|
||||
* thus you must copy it before using it beyond its scope (to a std::string for instance).
|
||||
*/
|
||||
const char* getText(const char* apDefaultValue = "") const noexcept;
|
||||
/**
|
||||
* @brief Return a pointer to the binary blob value of the column.
|
||||
*
|
||||
* @warning The value pointed at is only valid while the statement is valid (ie. not finalized),
|
||||
* thus you must copy it before using it beyond its scope (to a std::string for instance).
|
||||
*/
|
||||
const void* getBlob() const noexcept;
|
||||
/**
|
||||
* @brief Return a std::string for a TEXT or BLOB column.
|
||||
*
|
||||
* Note this correctly handles strings that contain null bytes.
|
||||
*/
|
||||
std::string getString() const;
|
||||
|
||||
/**
|
||||
* @brief Return the type of the value of the column using sqlite3_column_type()
|
||||
*
|
||||
* Return either SQLite::INTEGER, SQLite::FLOAT, SQLite::TEXT, SQLite::BLOB, or SQLite::Null.
|
||||
* This type may change from one row to the next, since
|
||||
* SQLite stores data types dynamically for each value and not per column.
|
||||
* Use Statement::getColumnDeclaredType() to retrieve the declared column type from a SELECT statement.
|
||||
*
|
||||
* @warning After a type conversion (by a call to a getXxx on a Column of a Yyy type),
|
||||
* the value returned by sqlite3_column_type() is undefined.
|
||||
*/
|
||||
int getType() const noexcept;
|
||||
|
||||
/// Test if the column is an integer type value (meaningful only before any conversion)
|
||||
bool isInteger() const noexcept
|
||||
{
|
||||
return (SQLite::INTEGER == getType());
|
||||
}
|
||||
/// Test if the column is a floating point type value (meaningful only before any conversion)
|
||||
bool isFloat() const noexcept
|
||||
{
|
||||
return (SQLite::FLOAT == getType());
|
||||
}
|
||||
/// Test if the column is a text type value (meaningful only before any conversion)
|
||||
bool isText() const noexcept
|
||||
{
|
||||
return (SQLite::TEXT == getType());
|
||||
}
|
||||
/// Test if the column is a binary blob type value (meaningful only before any conversion)
|
||||
bool isBlob() const noexcept
|
||||
{
|
||||
return (SQLite::BLOB == getType());
|
||||
}
|
||||
/// Test if the column is NULL (meaningful only before any conversion)
|
||||
bool isNull() const noexcept
|
||||
{
|
||||
return (SQLite::Null == getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the number of bytes used by the text (or blob) value of the column
|
||||
*
|
||||
* Return either :
|
||||
* - size in bytes (not in characters) of the string returned by getText() without the '\0' terminator
|
||||
* - size in bytes of the string representation of the numerical value (integer or double)
|
||||
* - size in bytes of the binary blob returned by getBlob()
|
||||
* - 0 for a NULL value
|
||||
*/
|
||||
int getBytes() const noexcept;
|
||||
|
||||
/// Alias returning the number of bytes used by the text (or blob) value of the column
|
||||
int size() const noexcept
|
||||
{
|
||||
return getBytes ();
|
||||
}
|
||||
|
||||
/// Inline cast operators to basic types
|
||||
operator char() const
|
||||
{
|
||||
return static_cast<char>(getInt());
|
||||
}
|
||||
operator int8_t() const
|
||||
{
|
||||
return static_cast<int8_t>(getInt());
|
||||
}
|
||||
operator uint8_t() const
|
||||
{
|
||||
return static_cast<uint8_t>(getInt());
|
||||
}
|
||||
operator int16_t() const
|
||||
{
|
||||
return static_cast<int16_t>(getInt());
|
||||
}
|
||||
operator uint16_t() const
|
||||
{
|
||||
return static_cast<uint16_t>(getInt());
|
||||
}
|
||||
operator int32_t() const
|
||||
{
|
||||
return getInt();
|
||||
}
|
||||
operator uint32_t() const
|
||||
{
|
||||
return getUInt();
|
||||
}
|
||||
operator int64_t() const
|
||||
{
|
||||
return getInt64();
|
||||
}
|
||||
operator double() const
|
||||
{
|
||||
return getDouble();
|
||||
}
|
||||
/**
|
||||
* @brief Inline cast operator to char*
|
||||
*
|
||||
* @see getText
|
||||
*/
|
||||
operator const char*() const
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
/**
|
||||
* @brief Inline cast operator to void*
|
||||
*
|
||||
* @see getBlob
|
||||
*/
|
||||
operator const void*() const
|
||||
{
|
||||
return getBlob();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inline cast operator to std::string
|
||||
*
|
||||
* Handles BLOB or TEXT, which may contain null bytes within
|
||||
*
|
||||
* @see getString
|
||||
*/
|
||||
operator std::string() const
|
||||
{
|
||||
return getString();
|
||||
}
|
||||
|
||||
private:
|
||||
Statement::TStatementPtr mStmtPtr; ///< Shared Pointer to the prepared SQLite Statement Object
|
||||
int mIndex; ///< Index of the column in the row of result, starting at 0
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Standard std::ostream text inserter
|
||||
*
|
||||
* Insert the text value of the Column object, using getText(), into the provided stream.
|
||||
*
|
||||
* @param[in] aStream Stream to use
|
||||
* @param[in] aColumn Column object to insert into the provided stream
|
||||
*
|
||||
* @return Reference to the stream used
|
||||
*/
|
||||
SQLITECPP_API std::ostream& operator<<(std::ostream& aStream, const Column& aColumn);
|
||||
|
||||
#if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900) // c++14: Visual Studio 2015
|
||||
|
||||
// Create an instance of T from the first N columns, see declaration in Statement.h for full details
|
||||
template<typename T, int N>
|
||||
T Statement::getColumns()
|
||||
{
|
||||
checkRow();
|
||||
checkIndex(N - 1);
|
||||
return getColumns<T>(std::make_integer_sequence<int, N>{});
|
||||
}
|
||||
|
||||
// Helper function called by getColums<typename T, int N>
|
||||
template<typename T, const int... Is>
|
||||
T Statement::getColumns(const std::integer_sequence<int, Is...>)
|
||||
{
|
||||
return T{Column(mpPreparedStatement, Is)...};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace SQLite
|
||||
+624
@@ -0,0 +1,624 @@
|
||||
/**
|
||||
* @file Database.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Management of a SQLite Database Connection.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Column.h>
|
||||
|
||||
// c++17: MinGW GCC version > 8
|
||||
// c++17: Visual Studio 2017 version 15.7
|
||||
// c++17: macOS unless targetting compatibility with macOS < 10.15
|
||||
#ifndef SQLITECPP_HAVE_STD_EXPERIMENTAL_FILESYSTEM
|
||||
#if __cplusplus >= 201703L
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#if __GNUC__ > 8 // MinGW requires GCC version > 8 for std::filesystem
|
||||
#define SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#endif
|
||||
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
|
||||
// macOS clang won't let us touch std::filesystem if we're targetting earlier than 10.15
|
||||
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_13_0) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_13_0
|
||||
// build for iOS clang won't let us touch std::filesystem if we're targetting earlier than iOS 13
|
||||
#else
|
||||
#define SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#endif
|
||||
#elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
|
||||
#define SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#endif
|
||||
|
||||
// disable the support if the required header is not available
|
||||
#ifdef __has_include
|
||||
#if !__has_include(<filesystem>)
|
||||
#undef SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#endif
|
||||
#if !__has_include(<experimental/filesystem>)
|
||||
#undef SQLITECPP_HAVE_EXPERIMENTAL_FILESYSTEM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// C++17 allow to disable std::filesystem support
|
||||
#ifdef SQLITECPP_DISABLE_STD_FILESYSTEM
|
||||
#undef SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#undef SQLITECPP_HAVE_STD_EXPERIMENTAL_FILESYSTEM
|
||||
#endif
|
||||
|
||||
#ifdef SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#include <filesystem>
|
||||
#endif // c++17 and a suitable compiler
|
||||
|
||||
#else // SQLITECPP_HAVE_STD_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
#define SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
#include <experimental/filesystem>
|
||||
namespace std {
|
||||
namespace filesystem = experimental::filesystem;
|
||||
}
|
||||
|
||||
#endif // SQLITECPP_HAVE_STD_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
|
||||
// Forward declarations to avoid inclusion of <sqlite3.h> in a header
|
||||
struct sqlite3;
|
||||
struct sqlite3_context;
|
||||
|
||||
#ifndef SQLITE_USE_LEGACY_STRUCT // Since SQLITE 3.19 (used by default since SQLiteCpp 2.1.0)
|
||||
typedef struct sqlite3_value sqlite3_value;
|
||||
#else // Before SQLite 3.19 (legacy struct forward declaration can be activated with CMake SQLITECPP_LEGACY_STRUCT var)
|
||||
struct Mem;
|
||||
typedef struct Mem sqlite3_value;
|
||||
#endif
|
||||
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
// Those public constants enable most usages of SQLiteCpp without including <sqlite3.h> in the client application.
|
||||
|
||||
/// The database is opened in read-only mode. If the database does not already exist, an error is returned.
|
||||
SQLITECPP_API extern const int OPEN_READONLY; // SQLITE_OPEN_READONLY
|
||||
/// The database is opened for reading and writing if possible, or reading only if the file is write protected
|
||||
/// by the operating system. In either case the database must already exist, otherwise an error is returned.
|
||||
SQLITECPP_API extern const int OPEN_READWRITE; // SQLITE_OPEN_READWRITE
|
||||
/// With OPEN_READWRITE: The database is opened for reading and writing, and is created if it does not already exist.
|
||||
SQLITECPP_API extern const int OPEN_CREATE; // SQLITE_OPEN_CREATE
|
||||
/// Enable URI filename interpretation, parsed according to RFC 3986 (ex. "file:data.db?mode=ro&cache=private")
|
||||
SQLITECPP_API extern const int OPEN_URI; // SQLITE_OPEN_URI
|
||||
/// Open in memory database
|
||||
SQLITECPP_API extern const int OPEN_MEMORY; // SQLITE_OPEN_MEMORY
|
||||
/// Open database in multi-thread threading mode
|
||||
SQLITECPP_API extern const int OPEN_NOMUTEX; // SQLITE_OPEN_NOMUTEX
|
||||
/// Open database with thread-safety in serialized threading mode
|
||||
SQLITECPP_API extern const int OPEN_FULLMUTEX; // SQLITE_OPEN_FULLMUTEX
|
||||
/// Open database with shared cache enabled
|
||||
SQLITECPP_API extern const int OPEN_SHAREDCACHE; // SQLITE_OPEN_SHAREDCACHE
|
||||
/// Open database with shared cache disabled
|
||||
SQLITECPP_API extern const int OPEN_PRIVATECACHE; // SQLITE_OPEN_PRIVATECACHE
|
||||
/// Database filename is not allowed to be a symbolic link (Note: only since SQlite 3.31.0 from 2020-01-22)
|
||||
SQLITECPP_API extern const int OPEN_NOFOLLOW; // SQLITE_OPEN_NOFOLLOW
|
||||
|
||||
|
||||
SQLITECPP_API extern const int OK; ///< SQLITE_OK (used by check() bellow)
|
||||
|
||||
SQLITECPP_API extern const char* const VERSION; ///< SQLITE_VERSION string from sqlite3.h used at compile time
|
||||
SQLITECPP_API extern const int VERSION_NUMBER; ///< SQLITE_VERSION_NUMBER from sqlite3.h used at compile time
|
||||
|
||||
/// Return SQLite version string using runtime call to the compiled library
|
||||
SQLITECPP_API const char* getLibVersion() noexcept;
|
||||
/// Return SQLite version number using runtime call to the compiled library
|
||||
SQLITECPP_API int getLibVersionNumber() noexcept;
|
||||
|
||||
// Public structure for representing all fields contained within the SQLite header.
|
||||
// Official documentation for fields: https://www.sqlite.org/fileformat.html#the_database_header
|
||||
struct Header {
|
||||
unsigned char headerStr[16];
|
||||
unsigned int pageSizeBytes;
|
||||
unsigned char fileFormatWriteVersion;
|
||||
unsigned char fileFormatReadVersion;
|
||||
unsigned char reservedSpaceBytes;
|
||||
unsigned char maxEmbeddedPayloadFrac;
|
||||
unsigned char minEmbeddedPayloadFrac;
|
||||
unsigned char leafPayloadFrac;
|
||||
unsigned long fileChangeCounter;
|
||||
unsigned long databaseSizePages;
|
||||
unsigned long firstFreelistTrunkPage;
|
||||
unsigned long totalFreelistPages;
|
||||
unsigned long schemaCookie;
|
||||
unsigned long schemaFormatNumber;
|
||||
unsigned long defaultPageCacheSizeBytes;
|
||||
unsigned long largestBTreePageNumber;
|
||||
unsigned long databaseTextEncoding;
|
||||
unsigned long userVersion;
|
||||
unsigned long incrementalVaccumMode;
|
||||
unsigned long applicationId;
|
||||
unsigned long versionValidFor;
|
||||
unsigned long sqliteVersion;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief RAII management of a SQLite Database Connection.
|
||||
*
|
||||
* A Database object manage a list of all SQLite Statements associated with the
|
||||
* underlying SQLite 3 database connection.
|
||||
*
|
||||
* Resource Acquisition Is Initialization (RAII) means that the Database Connection
|
||||
* is opened in the constructor and closed in the destructor, so that there is
|
||||
* no need to worry about memory management or the validity of the underlying SQLite Connection.
|
||||
*
|
||||
* Thread-safety: a Database object shall not be shared by multiple threads, because :
|
||||
* 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
|
||||
* provided that no single database connection is used simultaneously in two or more threads."
|
||||
* 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
|
||||
* because of the way it shares the underling SQLite precompiled statement
|
||||
* in a custom shared pointer (See the inner class "Statement::Ptr").
|
||||
*/
|
||||
class SQLITECPP_API Database
|
||||
{
|
||||
friend class Statement; // Give Statement constructor access to the mSQLitePtr Connection Handle
|
||||
|
||||
public:
|
||||
/**
|
||||
* @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] apFilename UTF-8 path/uri to the database file ("filename" sqlite3 parameter)
|
||||
* @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE...
|
||||
* @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout())
|
||||
* @param[in] apVfs UTF-8 name of custom VFS to use, or nullptr for sqlite3 default
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Database(const char* apFilename,
|
||||
const int aFlags = SQLite::OPEN_READONLY,
|
||||
const int aBusyTimeoutMs = 0,
|
||||
const char* apVfs = nullptr);
|
||||
|
||||
/**
|
||||
* @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...
|
||||
* @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout())
|
||||
* @param[in] aVfs UTF-8 name of custom VFS to use, or empty string for sqlite3 default
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Database(const std::string& aFilename,
|
||||
const int aFlags = SQLite::OPEN_READONLY,
|
||||
const int aBusyTimeoutMs = 0,
|
||||
const std::string& aVfs = "") :
|
||||
Database(aFilename.c_str(), aFlags, aBusyTimeoutMs, aVfs.empty() ? nullptr : aVfs.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef SQLITECPP_HAVE_STD_FILESYSTEM
|
||||
|
||||
/**
|
||||
* @brief Open the provided database std::filesystem::path.
|
||||
*
|
||||
* @note This feature requires std=C++17
|
||||
*
|
||||
* 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] apFilename Path/uri to the database file ("filename" sqlite3 parameter)
|
||||
* @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE...
|
||||
* @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout())
|
||||
* @param[in] apVfs UTF-8 name of custom VFS to use, or nullptr for sqlite3 default
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Database(const std::filesystem::path& apFilename,
|
||||
const int aFlags = SQLite::OPEN_READONLY,
|
||||
const int aBusyTimeoutMs = 0,
|
||||
const std::string& aVfs = "") :
|
||||
Database(reinterpret_cast<const char*>(apFilename.u8string().c_str()),
|
||||
aFlags, aBusyTimeoutMs, aVfs.empty() ? nullptr : aVfs.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
#endif // have std::filesystem
|
||||
|
||||
// Database is non-copyable
|
||||
Database(const Database&) = delete;
|
||||
Database& operator=(const Database&) = delete;
|
||||
|
||||
// Database is movable
|
||||
Database(Database&& aDatabase) = default;
|
||||
Database& operator=(Database&& aDatabase) = default;
|
||||
|
||||
/**
|
||||
* @brief Close the SQLite database connection.
|
||||
*
|
||||
* All SQLite statements must have been finalized before,
|
||||
* so all Statement objects must have been unregistered.
|
||||
*
|
||||
* @warning assert in case of error
|
||||
*/
|
||||
~Database() = default;
|
||||
|
||||
// Deleter functor to use with smart pointers to close the SQLite database connection in an RAII fashion.
|
||||
struct Deleter
|
||||
{
|
||||
SQLITECPP_API void operator()(sqlite3* apSQLite);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
|
||||
*
|
||||
* This is useful in multithreaded program to handle case where a table is locked for writing by a thread.
|
||||
* Any other thread cannot access the table and will receive a SQLITE_BUSY error:
|
||||
* setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error.
|
||||
* Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;".
|
||||
* Default busy timeout is 0ms.
|
||||
*
|
||||
* @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void setBusyTimeout(const int aBusyTimeoutMs);
|
||||
|
||||
/**
|
||||
* @brief Shortcut to execute one or multiple statements without results. Return the number of changes.
|
||||
*
|
||||
* This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
|
||||
* - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
|
||||
* - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
|
||||
* - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
|
||||
*
|
||||
* @see Database::tryExec() to execute, returning the sqlite result code
|
||||
* @see Statement::exec() to handle precompiled statements (for better performances) without results
|
||||
* @see Statement::executeStep() to handle "SELECT" queries with results
|
||||
*
|
||||
* @param[in] apQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements
|
||||
*
|
||||
* @return number of rows modified by the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements)
|
||||
* @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
int exec(const char* apQueries);
|
||||
|
||||
/**
|
||||
* @brief Shortcut to execute one or multiple statements without results.
|
||||
*
|
||||
* This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
|
||||
* - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
|
||||
* - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
|
||||
* - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
|
||||
*
|
||||
* @see Database::tryExec() to execute, returning the sqlite result code
|
||||
* @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 the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements)
|
||||
* @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
int exec(const std::string& aQueries)
|
||||
{
|
||||
return exec(aQueries.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to execute one or multiple statements, returning the sqlite result code.
|
||||
*
|
||||
* This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
|
||||
* - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
|
||||
* - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
|
||||
* - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
|
||||
*
|
||||
* @see exec() to execute, returning number of rows modified
|
||||
*
|
||||
* @param[in] apQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements
|
||||
*
|
||||
* @return the sqlite result code.
|
||||
*/
|
||||
int tryExec(const char* apQueries) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Try to execute one or multiple statements, returning the sqlite result code.
|
||||
*
|
||||
* This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
|
||||
* - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
|
||||
* - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
|
||||
* - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
|
||||
*
|
||||
* @see exec() to execute, returning number of rows modified
|
||||
*
|
||||
* @param[in] aQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements
|
||||
*
|
||||
* @return the sqlite result code.
|
||||
*/
|
||||
int tryExec(const std::string& aQueries) noexcept
|
||||
{
|
||||
return tryExec(aQueries.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @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] apQuery an UTF-8 encoded SQL query
|
||||
*
|
||||
* @return a temporary Column object with the first column of result.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
Column execAndGet(const char* apQuery);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
Column execAndGet(const std::string& aQuery)
|
||||
{
|
||||
return execAndGet(aQuery.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shortcut to test if a table exists.
|
||||
*
|
||||
* Table names are case sensitive.
|
||||
*
|
||||
* @param[in] apTableName an UTF-8 encoded case sensitive Table name
|
||||
*
|
||||
* @return true if the table exists.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
bool tableExists(const char* apTableName) const;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
bool tableExists(const std::string& aTableName) const
|
||||
{
|
||||
return tableExists(aTableName.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the rowid of the most recent successful INSERT into the database from the current connection.
|
||||
*
|
||||
* Each entry in an SQLite table always has a unique 64-bit signed integer key called the rowid.
|
||||
* If the table has a column of type INTEGER PRIMARY KEY, then it is an alias for the rowid.
|
||||
*
|
||||
* @return Rowid of the most recent successful INSERT into the database, or 0 if there was none.
|
||||
*/
|
||||
int64_t getLastInsertRowid() const noexcept;
|
||||
|
||||
/// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
|
||||
int getChanges() const noexcept;
|
||||
|
||||
/// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection (not DROP table).
|
||||
int getTotalChanges() const noexcept;
|
||||
|
||||
/// Return the numeric result code for the most recent failed API call (if any).
|
||||
int getErrorCode() const noexcept;
|
||||
/// Return the extended numeric result code for the most recent failed API call (if any).
|
||||
int getExtendedErrorCode() const noexcept;
|
||||
/// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
|
||||
const char* getErrorMsg() const noexcept;
|
||||
|
||||
/// Return the filename used to open the database.
|
||||
const std::string& getFilename() const noexcept
|
||||
{
|
||||
return mFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return raw pointer to SQLite Database Connection Handle.
|
||||
*
|
||||
* This is often needed to mix this wrapper with other libraries or for advance usage not supported by SQLiteCpp.
|
||||
*/
|
||||
sqlite3* getHandle() const noexcept
|
||||
{
|
||||
return mSQLitePtr.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create or redefine a SQL function or aggregate in the sqlite database.
|
||||
*
|
||||
* This is the equivalent of the sqlite3_create_function_v2 command.
|
||||
* @see http://www.sqlite.org/c3ref/create_function.html
|
||||
*
|
||||
* @note UTF-8 text encoding assumed.
|
||||
*
|
||||
* @param[in] apFuncName Name of the SQL function to be created or redefined
|
||||
* @param[in] aNbArg Number of arguments in the function
|
||||
* @param[in] abDeterministic Optimize for deterministic functions (most are). A random number generator is not.
|
||||
* @param[in] apApp Arbitrary pointer of user data, accessible with sqlite3_user_data().
|
||||
* @param[in] apFunc Pointer to a C-function to implement a scalar SQL function (apStep & apFinal nullptr)
|
||||
* @param[in] apStep Pointer to a C-function to implement an aggregate SQL function (apFunc nullptr)
|
||||
* @param[in] apFinal Pointer to a C-function to implement an aggregate SQL function (apFunc nullptr)
|
||||
* @param[in] apDestroy If not nullptr, then it is the destructor for the application data pointer.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void createFunction(const char* apFuncName,
|
||||
int aNbArg,
|
||||
bool abDeterministic,
|
||||
void* apApp,
|
||||
void (*apFunc)(sqlite3_context *, int, sqlite3_value **),
|
||||
void (*apStep)(sqlite3_context *, int, sqlite3_value **) = nullptr,
|
||||
void (*apFinal)(sqlite3_context *) = nullptr, // NOLINT(readability/casting)
|
||||
void (*apDestroy)(void *) = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Load a module into the current sqlite database instance.
|
||||
*
|
||||
* This is the equivalent of the sqlite3_load_extension call, but additionally enables
|
||||
* module loading support prior to loading the requested module.
|
||||
*
|
||||
* @see http://www.sqlite.org/c3ref/load_extension.html
|
||||
*
|
||||
* @note UTF-8 text encoding assumed.
|
||||
*
|
||||
* @param[in] apExtensionName Name of the shared library containing extension
|
||||
* @param[in] apEntryPointName Name of the entry point (nullptr to let sqlite work it out)
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void loadExtension(const char* apExtensionName, const char* apEntryPointName);
|
||||
|
||||
/**
|
||||
* @brief Set the key for the current sqlite database instance.
|
||||
*
|
||||
* This is the equivalent of the sqlite3_key call and should thus be called
|
||||
* directly after opening the database.
|
||||
* Open encrypted database -> call db.key("secret") -> database ready
|
||||
*
|
||||
* @param[in] aKey Key to decode/encode the database
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void key(const std::string& aKey) const;
|
||||
|
||||
/**
|
||||
* @brief Reset the key for the current sqlite database instance.
|
||||
*
|
||||
* This is the equivalent of the sqlite3_rekey call and should thus be called
|
||||
* after the database has been opened with a valid key. To decrypt a
|
||||
* database, call this method with an empty string.
|
||||
* Open normal database -> call db.rekey("secret") -> encrypted database, database ready
|
||||
* Open encrypted database -> call db.key("secret") -> call db.rekey("newsecret") -> change key, database ready
|
||||
* Open encrypted database -> call db.key("secret") -> call db.rekey("") -> decrypted database, database ready
|
||||
*
|
||||
* @param[in] aNewKey New key to encode the database
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void rekey(const std::string& aNewKey) const;
|
||||
|
||||
/**
|
||||
* @brief Test if a file contains an unencrypted database.
|
||||
*
|
||||
* This is a simple test that reads the first bytes of a database file and
|
||||
* compares them to the standard header for unencrypted databases. If the
|
||||
* header does not match the standard string, we assume that we have an
|
||||
* encrypted file.
|
||||
*
|
||||
* @param[in] aFilename path/uri to a file
|
||||
*
|
||||
* @return true if the database has the standard header.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
static bool isUnencrypted(const std::string& aFilename);
|
||||
|
||||
/**
|
||||
* @brief Parse SQLite header data from a database file.
|
||||
*
|
||||
* This function reads the first 100 bytes of a SQLite database file
|
||||
* and reconstructs groups of individual bytes into the associated fields
|
||||
* in a Header object.
|
||||
*
|
||||
* @param[in] aFilename path/uri to a file
|
||||
*
|
||||
* @return Header object containing file data
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
static Header getHeaderInfo(const std::string& aFilename);
|
||||
|
||||
// Parse SQLite header data from a database file.
|
||||
Header getHeaderInfo() const
|
||||
{
|
||||
return getHeaderInfo(mFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief BackupType for the backup() method
|
||||
*/
|
||||
enum BackupType { Save, Load };
|
||||
|
||||
/**
|
||||
* @brief Load or save the database content.
|
||||
*
|
||||
* This function is used to load the contents of a database file on disk
|
||||
* into the "main" database of open database connection, or to save the current
|
||||
* contents of the database into a database file on disk.
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void backup(const char* apFilename, BackupType aType);
|
||||
|
||||
/**
|
||||
* @brief Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message
|
||||
*/
|
||||
void check(const int aRet) const
|
||||
{
|
||||
if (SQLite::OK != aRet)
|
||||
{
|
||||
throw SQLite::Exception(getHandle(), aRet);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO: perhaps switch to having Statement sharing a pointer to the Connexion
|
||||
std::unique_ptr<sqlite3, Deleter> mSQLitePtr; ///< Pointer to SQLite Database Connection Handle
|
||||
std::string mFilename; ///< UTF-8 filename used to open the database
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @file Exception.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Encapsulation of the error message from SQLite3 on a std::runtime_error.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// Forward declaration to avoid inclusion of <sqlite3.h> in a header
|
||||
struct sqlite3;
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
|
||||
*/
|
||||
class SQLITECPP_API Exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
|
||||
*
|
||||
* @param[in] aErrorMessage The string message describing the SQLite error
|
||||
* @param[in] ret Return value from function call that failed.
|
||||
*/
|
||||
Exception(const char* aErrorMessage, int ret);
|
||||
|
||||
Exception(const std::string& aErrorMessage, int ret) :
|
||||
Exception(aErrorMessage.c_str(), ret)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
|
||||
*
|
||||
* @param[in] aErrorMessage The string message describing the SQLite error
|
||||
*/
|
||||
explicit Exception(const char* aErrorMessage) :
|
||||
Exception(aErrorMessage, -1) // 0 would be SQLITE_OK, which doesn't make sense
|
||||
{
|
||||
}
|
||||
explicit Exception(const std::string& aErrorMessage) :
|
||||
Exception(aErrorMessage.c_str(), -1) // 0 would be SQLITE_OK, which doesn't make sense
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
|
||||
*
|
||||
* @param[in] apSQLite The SQLite object, to obtain detailed error messages from.
|
||||
*/
|
||||
explicit Exception(sqlite3* apSQLite);
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
|
||||
*
|
||||
* @param[in] apSQLite The SQLite object, to obtain detailed error messages from.
|
||||
* @param[in] ret Return value from function call that failed.
|
||||
*/
|
||||
Exception(sqlite3* apSQLite, int ret);
|
||||
|
||||
/// Return the result code (if any, otherwise -1).
|
||||
int getErrorCode() const noexcept
|
||||
{
|
||||
return mErrcode;
|
||||
}
|
||||
|
||||
/// Return the extended numeric result code (if any, otherwise -1).
|
||||
int getExtendedErrorCode() const noexcept
|
||||
{
|
||||
return mExtendedErrcode;
|
||||
}
|
||||
|
||||
/// Return a string, solely based on the error code
|
||||
const char* getErrorStr() const noexcept;
|
||||
|
||||
private:
|
||||
int mErrcode; ///< Error code value
|
||||
int mExtendedErrcode; ///< Detailed error code if any
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @file ExecuteMany.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Convenience function to execute a Statement with multiple Parameter sets
|
||||
*
|
||||
* Copyright (c) 2019 Maximilian Bachmann ([email protected])
|
||||
* Copyright (c) 2019-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
|
||||
|
||||
#include <SQLiteCpp/Statement.h>
|
||||
#include <SQLiteCpp/VariadicBind.h>
|
||||
|
||||
/// @cond
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* \brief Convenience function to execute a Statement with multiple Parameter sets once for each parameter set given.
|
||||
*
|
||||
*
|
||||
* This feature requires a c++14 capable compiler.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* execute_many(db, "INSERT INTO test VALUES (?, ?)",
|
||||
* 1,
|
||||
* std::make_tuple(2),
|
||||
* std::make_tuple(3, "three")
|
||||
* );
|
||||
* \endcode
|
||||
* @param aDatabase Database to use
|
||||
* @param apQuery Query to use with all parameter sets
|
||||
* @param aArg first tuple with parameters
|
||||
* @param aParams the following tuples with parameters
|
||||
*/
|
||||
template <typename Arg, typename... Types>
|
||||
void execute_many(Database& aDatabase, const char* apQuery, Arg&& aArg, Types&&... aParams)
|
||||
{
|
||||
SQLite::Statement query(aDatabase, apQuery);
|
||||
bind_exec(query, std::forward<Arg>(aArg));
|
||||
(void)std::initializer_list<int>
|
||||
{
|
||||
((void)reset_bind_exec(query, std::forward<Types>(aParams)), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convenience function to reset a statement and call bind_exec to
|
||||
* bind new values to the statement and execute it
|
||||
*
|
||||
* This feature requires a c++14 capable compiler.
|
||||
*
|
||||
* @param apQuery Query to use
|
||||
* @param aTuple Tuple to bind
|
||||
*/
|
||||
template <typename TupleT>
|
||||
void reset_bind_exec(Statement& apQuery, TupleT&& aTuple)
|
||||
{
|
||||
apQuery.reset();
|
||||
bind_exec(apQuery, std::forward<TupleT>(aTuple));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convenience function to bind values a the statement and execute it
|
||||
*
|
||||
* This feature requires a c++14 capable compiler.
|
||||
*
|
||||
* @param apQuery Query to use
|
||||
* @param aTuple Tuple to bind
|
||||
*/
|
||||
template <typename TupleT>
|
||||
void bind_exec(Statement& apQuery, TupleT&& aTuple)
|
||||
{
|
||||
SQLite::bind(apQuery, std::forward<TupleT>(aTuple));
|
||||
while (apQuery.executeStep()) {}
|
||||
}
|
||||
|
||||
} // namespace SQLite
|
||||
|
||||
#endif // c++14
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file SQLiteCpp.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief SQLiteC++ is a smart and simple C++ SQLite3 wrapper. This file is only "easy include" for other files.
|
||||
*
|
||||
* Include this main header file in your project to gain access to all functionality provided by the wrapper.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
/**
|
||||
* @defgroup SQLiteCpp SQLiteC++
|
||||
* @brief SQLiteC++ is a smart and simple C++ SQLite3 wrapper. This file is only "easy include" for other files.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
// Include useful headers of SQLiteC++
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Assertion.h>
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
#include <SQLiteCpp/Database.h>
|
||||
#include <SQLiteCpp/Statement.h>
|
||||
#include <SQLiteCpp/Column.h>
|
||||
#include <SQLiteCpp/Transaction.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Version numbers for SQLiteC++ are provided in the same way as sqlite3.h
|
||||
*
|
||||
* The [SQLITECPP_VERSION] C preprocessor macro in the SQLiteC++.h header
|
||||
* evaluates to a string literal that is the SQLite version in the
|
||||
* format "X.Y.Z" where X is the major version number
|
||||
* and Y is the minor version number and Z is the release number.
|
||||
*
|
||||
* The [SQLITECPP_VERSION_NUMBER] C preprocessor macro resolves to an integer
|
||||
* with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same
|
||||
* numbers used in [SQLITECPP_VERSION].
|
||||
*
|
||||
* WARNING: shall always be updated in sync with PROJECT_VERSION in CMakeLists.txt
|
||||
*/
|
||||
#define SQLITECPP_VERSION "3.03.01" // 3.3.1
|
||||
#define SQLITECPP_VERSION_NUMBER 3003001 // 3.3.1
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file SQLiteCppExport.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief File with macros needed in the generation of Windows DLLs
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* #define SQLITECPP_COMPILE_DLL to compile a DLL under Windows
|
||||
* #define SQLITECPP_EXPORT to export symbols when creating the DLL, otherwise it defaults to importing symbols
|
||||
*/
|
||||
|
||||
/* Windows DLL export/import */
|
||||
#if defined(_WIN32)&& !defined(__GNUC__) && defined(SQLITECPP_COMPILE_DLL)
|
||||
#if SQLITECPP_DLL_EXPORT
|
||||
#define SQLITECPP_API __declspec(dllexport)
|
||||
#else
|
||||
#define SQLITECPP_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#define SQLITECPP_API __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define SQLITECPP_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && defined(SQLITECPP_COMPILE_DLL)
|
||||
#pragma warning( disable : 4251 )
|
||||
#pragma warning( disable : 4275 )
|
||||
#endif
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file Savepoint.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief A Savepoint is a way to group multiple SQL statements into an atomic
|
||||
* secured operation. Similar to a transaction while allowing child savepoints.
|
||||
*
|
||||
* Copyright (c) 2020 Kelvin Hammond ([email protected])
|
||||
* Copyright (c) 2020-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt or
|
||||
* copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
// Forward declaration
|
||||
class Database;
|
||||
|
||||
/**
|
||||
* @brief RAII encapsulation of a SQLite Savepoint.
|
||||
*
|
||||
* SAVEPOINTs are a method of creating Transactions, similar to BEGIN and COMMIT,
|
||||
* except that the SAVEPOINT and RELEASE commands are named and may be nested..
|
||||
*
|
||||
* Resource Acquisition Is Initialization (RAII) means that the Savepoint
|
||||
* begins in the constructor and is rolled back in the destructor (unless committed before), so that there is
|
||||
* no need to worry about memory management or the validity of the underlying SQLite Connection.
|
||||
*
|
||||
* This method also offers big performances improvements compared to
|
||||
* individually executed statements.
|
||||
*
|
||||
* Caveats:
|
||||
*
|
||||
* 1) Calling COMMIT or committing a parent transaction or RELEASE on a parent
|
||||
* savepoint will cause this savepoint to be released.
|
||||
*
|
||||
* 2) Calling ROLLBACK TO or rolling back a parent savepoint will cause this
|
||||
* savepoint to be rolled back.
|
||||
*
|
||||
* 3) This savepoint is not saved to the database until this and all savepoints
|
||||
* or transaction in the savepoint stack have been released or committed.
|
||||
*
|
||||
* See also: https://sqlite.org/lang_savepoint.html
|
||||
*
|
||||
* Thread-safety: a Savepoint object shall not be shared by multiple threads, because:
|
||||
* 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
|
||||
* provided that no single database connection is used simultaneously in two or more threads."
|
||||
* 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
|
||||
* because of the way it shares the underling SQLite precompiled statement
|
||||
* in a custom shared pointer (See the inner class "Statement::Ptr").
|
||||
*/
|
||||
class SQLITECPP_API Savepoint
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Begins the SQLite savepoint
|
||||
*
|
||||
* @param[in] aDatabase the SQLite Database Connection
|
||||
* @param[in] aName the name of the Savepoint
|
||||
*
|
||||
* Exception is thrown in case of error, then the Savepoint is NOT
|
||||
* initiated.
|
||||
*/
|
||||
Savepoint(Database& aDatabase, const std::string& aName);
|
||||
|
||||
// Savepoint is non-copyable
|
||||
Savepoint(const Savepoint&) = delete;
|
||||
Savepoint& operator=(const Savepoint&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Safely rollback the savepoint if it has not been committed.
|
||||
*/
|
||||
~Savepoint();
|
||||
|
||||
/**
|
||||
* @brief Commit and release the savepoint.
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* @brief Rollback to the savepoint, but don't release it.
|
||||
*/
|
||||
void rollbackTo();
|
||||
// @deprecated same as rollbackTo();
|
||||
void rollback() { rollbackTo(); }
|
||||
|
||||
private:
|
||||
Database& mDatabase; ///< Reference to the SQLite Database Connection
|
||||
std::string msName; ///< Name of the Savepoint
|
||||
bool mbReleased = false; ///< True when release has been called
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
+711
@@ -0,0 +1,711 @@
|
||||
/**
|
||||
* @file Statement.h
|
||||
* @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-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
#include <SQLiteCpp/Utils.h> // SQLITECPP_PURE_FUNC
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations to avoid inclusion of <sqlite3.h> in a header
|
||||
struct sqlite3;
|
||||
struct sqlite3_stmt;
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
// Forward declaration
|
||||
class Database;
|
||||
class Column;
|
||||
|
||||
SQLITECPP_API extern const int OK; ///< SQLITE_OK
|
||||
|
||||
/**
|
||||
* @brief RAII encapsulation of a prepared SQLite Statement.
|
||||
*
|
||||
* A Statement is a compiled SQL query ready to be executed step by step
|
||||
* to provide results one row at a time.
|
||||
*
|
||||
* Resource Acquisition Is Initialization (RAII) means that the Statement
|
||||
* is compiled in the constructor and finalized in the destructor, so that there is
|
||||
* no need to worry about memory management or the validity of the underlying SQLite Statement.
|
||||
*
|
||||
* Thread-safety: a Statement object shall not be shared by multiple threads, because :
|
||||
* 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
|
||||
* provided that no single database connection is used simultaneously in two or more threads."
|
||||
* 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
|
||||
* because of the way it shares the underling SQLite precompiled statement
|
||||
* in a custom shared pointer (See the inner class "Statement::Ptr").
|
||||
*/
|
||||
class SQLITECPP_API Statement
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Compile and register the SQL query for the provided SQLite Database Connection
|
||||
*
|
||||
* @param[in] aDatabase the SQLite Database Connection
|
||||
* @param[in] apQuery an UTF-8 encoded query string
|
||||
*
|
||||
* Exception is thrown in case of error, then the Statement object is NOT constructed.
|
||||
*/
|
||||
Statement(const Database& aDatabase, const char* apQuery);
|
||||
|
||||
/**
|
||||
* @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(const Database& aDatabase, const std::string& aQuery) :
|
||||
Statement(aDatabase, aQuery.c_str())
|
||||
{}
|
||||
|
||||
// Statement is non-copyable
|
||||
Statement(const Statement&) = delete;
|
||||
Statement& operator=(const Statement&) = delete;
|
||||
|
||||
// TODO: Change Statement move constructor to default
|
||||
Statement(Statement&& aStatement) noexcept;
|
||||
Statement& operator=(Statement&& aStatement) noexcept = default;
|
||||
|
||||
/// Finalize and unregister the SQL query from the SQLite Database Connection.
|
||||
/// The finalization will be done by the destructor of the last shared pointer
|
||||
~Statement() = default;
|
||||
|
||||
/// Reset the statement to make it ready for a new execution by calling sqlite3_reset.
|
||||
/// Throws an exception on error.
|
||||
/// Call this function before any news calls to bind() if the statement was already executed before.
|
||||
/// Calling reset() does not clear the bindings (see clearBindings()).
|
||||
void reset();
|
||||
|
||||
/// Reset the statement. Returns the sqlite result code instead of throwing an exception on error.
|
||||
int tryReset() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Clears away all the bindings of a prepared statement.
|
||||
*
|
||||
* Contrary to the intuition of many, reset() does not reset the bindings on a prepared statement.
|
||||
* Use this routine to reset all parameters to NULL.
|
||||
*/
|
||||
void clearBindings(); // throw(SQLite::Exception)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Bind a value to a parameter of the SQL statement,
|
||||
// in the form "?" (unnamed), "?NNN", ":VVV", "@VVV" or "$VVV".
|
||||
//
|
||||
// Can use the parameter index, starting from "1", to the higher NNN value,
|
||||
// or the complete parameter name "?NNN", ":VVV", "@VVV" or "$VVV"
|
||||
// (prefixed with the corresponding sign "?", ":", "@" or "$")
|
||||
//
|
||||
// Note that for text and blob values, the SQLITE_TRANSIENT flag is used,
|
||||
// which tell the sqlite library to make its own copy of the data before the bind() call returns.
|
||||
// This choice is done to prevent any common misuses, like passing a pointer to a
|
||||
// dynamic allocated and temporary variable (a std::string for instance).
|
||||
// This is under-optimized for static data (a static text define in code)
|
||||
// as well as for dynamic allocated buffer which could be transfer to sqlite
|
||||
// instead of being copied.
|
||||
// => if you know what you are doing, use bindNoCopy() instead of bind()
|
||||
|
||||
SQLITECPP_PURE_FUNC
|
||||
int getIndex(const char * const apName) const;
|
||||
|
||||
/**
|
||||
* @brief Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const int aIndex, const int32_t aValue);
|
||||
/**
|
||||
* @brief Bind a 32bits unsigned int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const int aIndex, const uint32_t aValue);
|
||||
/**
|
||||
* @brief Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const int aIndex, const int64_t aValue);
|
||||
/**
|
||||
* @brief Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const int aIndex, const double aValue);
|
||||
/**
|
||||
* @brief Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const int aIndex, const std::string& aValue);
|
||||
/**
|
||||
* @brief Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const int aIndex, const char* apValue);
|
||||
/**
|
||||
* @brief Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const int aIndex, const void* apValue, const int aSize);
|
||||
/**
|
||||
* @brief Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1).
|
||||
*
|
||||
* The string can contain null characters as it is binded using its size.
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const int aIndex, const std::string& aValue);
|
||||
/**
|
||||
* @brief Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* Main usage is with null-terminated literal text (aka in code static strings)
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const int aIndex, const char* apValue);
|
||||
/**
|
||||
* @brief Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const int aIndex, const void* apValue, const int aSize);
|
||||
/**
|
||||
* @brief Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @see clearBindings() to set all bound parameters to NULL.
|
||||
*/
|
||||
void bind(const int aIndex);
|
||||
|
||||
/**
|
||||
* @brief Bind an int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const char* apName, const int32_t aValue)
|
||||
{
|
||||
bind(getIndex(apName), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a 32bits unsigned int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const char* apName, const uint32_t aValue)
|
||||
{
|
||||
bind(getIndex(apName), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a 64bits int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const char* apName, const int64_t aValue)
|
||||
{
|
||||
bind(getIndex(apName), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a double (64bits float) value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const char* apName, const double aValue)
|
||||
{
|
||||
bind(getIndex(apName), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const char* apName, const std::string& aValue)
|
||||
{
|
||||
bind(getIndex(apName), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const char* apName, const char* apValue)
|
||||
{
|
||||
bind(getIndex(apName), apValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const char* apName, const void* apValue, const int aSize)
|
||||
{
|
||||
bind(getIndex(apName), apValue, aSize);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* The string can contain null characters as it is binded using its size.
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const char* apName, const std::string& aValue)
|
||||
{
|
||||
bindNoCopy(getIndex(apName), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* Main usage is with null-terminated literal text (aka in code static strings)
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const char* apName, const char* apValue)
|
||||
{
|
||||
bindNoCopy(getIndex(apName), apValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const char* apName, const void* apValue, const int aSize)
|
||||
{
|
||||
bindNoCopy(getIndex(apName), apValue, aSize);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a NULL value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* @see clearBindings() to set all bound parameters to NULL.
|
||||
*/
|
||||
void bind(const char* apName) // bind NULL value
|
||||
{
|
||||
bind(getIndex(apName));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Bind an int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const std::string& aName, const int32_t aValue)
|
||||
{
|
||||
bind(aName.c_str(), aValue);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a 32bits unsigned int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*/
|
||||
void bind(const std::string& aName, const uint32_t aValue)
|
||||
{
|
||||
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)
|
||||
*/
|
||||
void bind(const std::string& aName, const int64_t aValue)
|
||||
{
|
||||
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)
|
||||
*/
|
||||
void bind(const std::string& aName, const double aValue)
|
||||
{
|
||||
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 Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const std::string& aName, const std::string& aValue)
|
||||
{
|
||||
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 Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const std::string& aName, const char* apValue)
|
||||
{
|
||||
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 Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
|
||||
*/
|
||||
void bind(const std::string& aName, const void* apValue, const int aSize)
|
||||
{
|
||||
bind(aName.c_str(), apValue, aSize);
|
||||
}
|
||||
/**
|
||||
* @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
|
||||
*
|
||||
* The string can contain null characters as it is binded using its size.
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const std::string& aName, const std::string& aValue)
|
||||
{
|
||||
bindNoCopy(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)
|
||||
*
|
||||
* Main usage is with null-terminated literal text (aka in code static strings)
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const std::string& aName, const char* apValue)
|
||||
{
|
||||
bindNoCopy(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)
|
||||
*
|
||||
* @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement.
|
||||
*/
|
||||
void bindNoCopy(const std::string& aName, const void* apValue, const int aSize)
|
||||
{
|
||||
bindNoCopy(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)
|
||||
*
|
||||
* @see clearBindings() to set all bound parameters to NULL.
|
||||
*/
|
||||
void bind(const std::string& aName) // bind NULL value
|
||||
{
|
||||
bind(aName.c_str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Execute a step of the prepared query to fetch one row of results.
|
||||
*
|
||||
* While true is returned, a row of results is available, and can be accessed
|
||||
* through the getColumn() method
|
||||
*
|
||||
* @see exec() execute a one-step prepared statement with no expected result
|
||||
* @see tryExecuteStep() try to execute a step of the prepared query to fetch one row of results, returning the sqlite result code.
|
||||
* @see Database::exec() is a shortcut to execute one or multiple statements without results
|
||||
*
|
||||
* @return - true (SQLITE_ROW) if there is another row ready : you can call getColumn(N) to get it
|
||||
* then you have to call executeStep() again to fetch more rows until the query is finished
|
||||
* - false (SQLITE_DONE) if the query has finished executing : there is no (more) row of result
|
||||
* (case of a query with no result, or after N rows fetched successfully)
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
bool executeStep();
|
||||
|
||||
/**
|
||||
* @brief Try to execute a step of the prepared query to fetch one row of results, returning the sqlite result code.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see exec() execute a one-step prepared statement with no expected result
|
||||
* @see executeStep() execute a step of the prepared query to fetch one row of results
|
||||
* @see Database::exec() is a shortcut to execute one or multiple statements without results
|
||||
*
|
||||
* @return the sqlite result code.
|
||||
*/
|
||||
int tryExecuteStep() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Execute a one-step query with no expected result, and return the number of changes.
|
||||
*
|
||||
* This method 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"
|
||||
*
|
||||
* It is similar to Database::exec(), but using a precompiled statement, it adds :
|
||||
* - the ability to bind() arguments to it (best way to insert data),
|
||||
* - reusing it allows for better performances (efficient for multiple insertion).
|
||||
*
|
||||
* @see executeStep() execute a step of the prepared query to fetch one row of results
|
||||
* @see tryExecuteStep() try to execute a step of the prepared query to fetch one row of results, returning the sqlite result code.
|
||||
* @see Database::exec() is a shortcut to execute one or multiple statements without results
|
||||
*
|
||||
* @return number of row modified by this SQL statement (INSERT, UPDATE or DELETE)
|
||||
*
|
||||
* @throw SQLite::Exception in case of error, or if row of results are returned while they are not expected!
|
||||
*/
|
||||
int exec();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Return a copy of the column data specified by its index
|
||||
*
|
||||
* Can be used to access the data of the current row of result when applicable,
|
||||
* while the executeStep() method returns true.
|
||||
*
|
||||
* Throw an exception if there is no row to return a Column from:
|
||||
* - if provided index is out of bound
|
||||
* - before any executeStep() call
|
||||
* - after the last executeStep() returned false
|
||||
* - after a reset() call
|
||||
*
|
||||
* Throw an exception if the specified index is out of the [0, getColumnCount()) range.
|
||||
*
|
||||
* @param[in] aIndex Index of the column, starting at 0
|
||||
*
|
||||
* @note This method is not const, reflecting the fact that the returned Column object will
|
||||
* share the ownership of the underlying sqlite3_stmt.
|
||||
*
|
||||
* @warning The resulting Column object must not be memorized "as-is".
|
||||
* Is is only a wrapper around the current result row, so it is only valid
|
||||
* while the row from the Statement remains valid, that is only until next executeStep() call.
|
||||
* Thus, you should instead extract immediately its data (getInt(), getText()...)
|
||||
* and use or copy this data for any later usage.
|
||||
*/
|
||||
Column getColumn(const int aIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Return a copy of the column data specified by its column name (less efficient than using an index)
|
||||
*
|
||||
* Can be used to access the data of the current row of result when applicable,
|
||||
* while the executeStep() method returns true.
|
||||
*
|
||||
* Throw an exception if there is no row to return a Column from :
|
||||
* - if provided name is not one of the aliased column names
|
||||
* - before any executeStep() call
|
||||
* - after the last executeStep() returned false
|
||||
* - after a reset() call
|
||||
*
|
||||
* Throw an exception if the specified name is not an on of the aliased name of the columns in the result.
|
||||
*
|
||||
* @param[in] apName Aliased name of the column, that is, the named specified in the query (not the original name)
|
||||
*
|
||||
* @note Uses a map of column names to indexes, build on first call.
|
||||
*
|
||||
* @note This method is not const, reflecting the fact that the returned Column object will
|
||||
* share the ownership of the underlying sqlite3_stmt.
|
||||
*
|
||||
* @warning The resulting Column object must not be memorized "as-is".
|
||||
* Is is only a wrapper around the current result row, so it is only valid
|
||||
* while the row from the Statement remains valid, that is only until next executeStep() call.
|
||||
* Thus, you should instead extract immediately its data (getInt(), getText()...)
|
||||
* and use or copy this data for any later usage.
|
||||
*
|
||||
* Throw an exception if the specified name is not one of the aliased name of the columns in the result.
|
||||
*/
|
||||
Column getColumn(const char* apName) const;
|
||||
|
||||
#if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900) // c++14: Visual Studio 2015
|
||||
/**
|
||||
* @brief Return an instance of T constructed from copies of the first N columns
|
||||
*
|
||||
* Can be used to access the data of the current row of result when applicable,
|
||||
* while the executeStep() method returns true.
|
||||
*
|
||||
* Throw an exception if there is no row to return a Column from:
|
||||
* - if provided column count is out of bound
|
||||
* - before any executeStep() call
|
||||
* - after the last executeStep() returned false
|
||||
* - after a reset() call
|
||||
*
|
||||
* Throw an exception if the specified column count is out of the [0, getColumnCount()) range.
|
||||
*
|
||||
* @tparam T Object type to construct
|
||||
* @tparam N Number of columns
|
||||
*
|
||||
* @note Requires std=C++14
|
||||
*/
|
||||
template<typename T, int N>
|
||||
T getColumns();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Helper function used by getColumns<typename T, int N> to expand an integer_sequence used to generate
|
||||
* the required Column objects
|
||||
*/
|
||||
template<typename T, const int... Is>
|
||||
T getColumns(const std::integer_sequence<int, Is...>);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Test if the column value is NULL
|
||||
*
|
||||
* @param[in] aIndex Index of the column, starting at 0
|
||||
*
|
||||
* @return true if the column value is NULL
|
||||
*
|
||||
* Throw an exception if the specified index is out of the [0, getColumnCount()) range.
|
||||
*/
|
||||
bool isColumnNull(const int aIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Test if the column value is NULL
|
||||
*
|
||||
* @param[in] apName Aliased name of the column, that is, the named specified in the query (not the original name)
|
||||
*
|
||||
* @return true if the column value is NULL
|
||||
*
|
||||
* Throw an exception if the specified name is not one of the aliased name of the columns in the result.
|
||||
*/
|
||||
bool isColumnNull(const char* apName) const;
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the named assigned to the specified result column (potentially aliased)
|
||||
*
|
||||
* @param[in] aIndex Index of the column in the range [0, getColumnCount()).
|
||||
*
|
||||
* @see getColumnOriginName() to get original column name (not aliased)
|
||||
*
|
||||
* Throw an exception if the specified index is out of the [0, getColumnCount()) range.
|
||||
*/
|
||||
const char* getColumnName(const int aIndex) const;
|
||||
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
/**
|
||||
* @brief Return a pointer to the table column name that is the origin of the specified result column
|
||||
*
|
||||
* Require definition of the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro :
|
||||
* - when building the SQLite library itself (which is the case for the Debian libsqlite3 binary for instance),
|
||||
* - and also when compiling this wrapper.
|
||||
*
|
||||
* Throw an exception if the specified index is out of the [0, getColumnCount()) range.
|
||||
*/
|
||||
const char* getColumnOriginName(const int aIndex) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return the index of the specified (potentially aliased) column name
|
||||
*
|
||||
* @param[in] apName Aliased name of the column, that is, the named specified in the query (not the original name)
|
||||
*
|
||||
* @note Uses a map of column names to indexes, build on first call.
|
||||
*
|
||||
* Throw an exception if the specified name is not known.
|
||||
*/
|
||||
int getColumnIndex(const char* apName) const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the declared type of the specified result column for a SELECT statement.
|
||||
*
|
||||
* This is the type given at creation of the column and not the actual data type.
|
||||
* SQLite stores data types dynamically for each value and not per column.
|
||||
*
|
||||
* @param[in] aIndex Index of the column in the range [0, getColumnCount()).
|
||||
*
|
||||
* Throw an exception if the type can't be determined because:
|
||||
* - the specified index is out of the [0, getColumnCount()) range
|
||||
* - the statement is not a SELECT query
|
||||
* - the column at aIndex is not a table column but an expression or subquery
|
||||
*/
|
||||
const char * getColumnDeclaredType(const int aIndex) const;
|
||||
|
||||
|
||||
/// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
|
||||
int getChanges() const noexcept;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Return the UTF-8 SQL Query.
|
||||
const std::string& getQuery() const
|
||||
{
|
||||
return mQuery;
|
||||
}
|
||||
|
||||
// Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.
|
||||
std::string getExpandedSQL() const;
|
||||
|
||||
/// Return the number of columns in the result set returned by the prepared statement
|
||||
int getColumnCount() const
|
||||
{
|
||||
return mColumnCount;
|
||||
}
|
||||
/// true when a row has been fetched with executeStep()
|
||||
bool hasRow() const
|
||||
{
|
||||
return mbHasRow;
|
||||
}
|
||||
/// true when the last executeStep() had no more row to fetch
|
||||
bool isDone() const
|
||||
{
|
||||
return mbDone;
|
||||
}
|
||||
|
||||
/// Return the number of bind parameters in the statement
|
||||
int getBindParameterCount() const noexcept;
|
||||
|
||||
/// Return the numeric result code for the most recent failed API call (if any).
|
||||
int getErrorCode() const noexcept;
|
||||
/// Return the extended numeric result code for the most recent failed API call (if any).
|
||||
int getExtendedErrorCode() const noexcept;
|
||||
/// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
|
||||
const char* getErrorMsg() const noexcept;
|
||||
|
||||
/// Shared pointer to SQLite Prepared Statement Object
|
||||
using TStatementPtr = std::shared_ptr<sqlite3_stmt>;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Check if a return code equals SQLITE_OK, else throw a SQLite::Exception with the SQLite error message
|
||||
*
|
||||
* @param[in] aRet SQLite return code to test against the SQLITE_OK expected value
|
||||
*/
|
||||
void check(const int aRet) const
|
||||
{
|
||||
if (SQLite::OK != aRet)
|
||||
{
|
||||
throw SQLite::Exception(mpSQLite, aRet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if there is a row of result returned by executeStep(), else throw a SQLite::Exception.
|
||||
*/
|
||||
void checkRow() const
|
||||
{
|
||||
if (false == mbHasRow)
|
||||
{
|
||||
throw SQLite::Exception("No row to get a column from. executeStep() was not called, or returned false.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if there is a Column index is in the range of columns in the result.
|
||||
*/
|
||||
void checkIndex(const int aIndex) const
|
||||
{
|
||||
if ((aIndex < 0) || (aIndex >= mColumnCount))
|
||||
{
|
||||
throw SQLite::Exception("Column index out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepare statement object.
|
||||
*
|
||||
* @return Shared pointer to prepared statement object
|
||||
*/
|
||||
TStatementPtr prepareStatement();
|
||||
|
||||
/**
|
||||
* @brief Return a prepared statement object.
|
||||
*
|
||||
* Throw an exception if the statement object was not prepared.
|
||||
* @return raw pointer to Prepared Statement Object
|
||||
*/
|
||||
sqlite3_stmt* getPreparedStatement() const;
|
||||
|
||||
std::string mQuery; //!< UTF-8 SQL Query
|
||||
sqlite3* mpSQLite; //!< Pointer to SQLite Database Connection Handle
|
||||
TStatementPtr mpPreparedStatement; //!< Shared Pointer to the prepared SQLite Statement Object
|
||||
int mColumnCount = 0; //!< Number of columns in the result of the prepared statement
|
||||
bool mbHasRow = false; //!< true when a row has been fetched with executeStep()
|
||||
bool mbDone = false; //!< true when the last executeStep() had no more row to fetch
|
||||
|
||||
/// Map of columns index by name (mutable so getColumnIndex can be const)
|
||||
mutable std::map<std::string, int> mColumnNames;
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file Transaction.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief A Transaction is way to group multiple SQL statements into an atomic secured operation.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/SQLiteCppExport.h>
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
|
||||
// Forward declaration
|
||||
class Database;
|
||||
|
||||
/**
|
||||
* @brief Transaction behaviors when opening an SQLite transaction.
|
||||
* Names correspond directly to the behavior.
|
||||
*/
|
||||
enum class TransactionBehavior {
|
||||
DEFERRED,
|
||||
IMMEDIATE,
|
||||
EXCLUSIVE,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief RAII encapsulation of a SQLite Transaction.
|
||||
*
|
||||
* A Transaction is a way to group multiple SQL statements into an atomic secured operation;
|
||||
* either it succeeds, with all the changes committed to the database file,
|
||||
* or if it fails, all the changes are rolled back to the initial state.
|
||||
*
|
||||
* Resource Acquisition Is Initialization (RAII) means that the Transaction
|
||||
* begins in the constructor and is rolled back in the destructor (unless committed before), so that there is
|
||||
* no need to worry about memory management or the validity of the underlying SQLite Connection.
|
||||
*
|
||||
* This method also offers big performances improvements compared to individually executed statements.
|
||||
*
|
||||
* Thread-safety: a Transaction object shall not be shared by multiple threads, because :
|
||||
* 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
|
||||
* provided that no single database connection is used simultaneously in two or more threads."
|
||||
* 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
|
||||
* because of the way it shares the underling SQLite precompiled statement
|
||||
* in a custom shared pointer (See the inner class "Statement::Ptr").
|
||||
*/
|
||||
class SQLITECPP_API Transaction
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Begins the SQLite transaction using the default transaction behavior.
|
||||
*
|
||||
* @param[in] aDatabase the SQLite Database Connection
|
||||
*
|
||||
* Exception is thrown in case of error, then the Transaction is NOT initiated.
|
||||
*/
|
||||
explicit Transaction(Database& aDatabase);
|
||||
|
||||
/**
|
||||
* @brief Begins the SQLite transaction with the specified behavior.
|
||||
*
|
||||
* @param[in] aDatabase the SQLite Database Connection
|
||||
* @param[in] behavior the requested transaction behavior
|
||||
*
|
||||
* Exception is thrown in case of error, then the Transaction is NOT initiated.
|
||||
*/
|
||||
explicit Transaction(Database& aDatabase, TransactionBehavior behavior);
|
||||
|
||||
// Transaction is non-copyable
|
||||
Transaction(const Transaction&) = delete;
|
||||
Transaction& operator=(const Transaction&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Safely rollback the transaction if it has not been committed.
|
||||
*/
|
||||
~Transaction();
|
||||
|
||||
/**
|
||||
* @brief Commit the transaction.
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* @brief Rollback the transaction
|
||||
*/
|
||||
void rollback();
|
||||
|
||||
private:
|
||||
Database& mDatabase; ///< Reference to the SQLite Database Connection
|
||||
bool mbCommited = false; ///< True when commit has been called
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file Utils.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Definition of the SQLITECPP_PURE_FUNC macro.
|
||||
*
|
||||
* Copyright (c) 2012-2023 Sebastien Rombauts ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// macro taken from https://github.com/nemequ/hedley/blob/master/hedley.h that was in public domain at this time
|
||||
#if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__) ||\
|
||||
(defined(__INTEL_COMPILER) && __INTEL_COMPILER > 1600) ||\
|
||||
(defined(__ARMCC_VERSION) && __ARMCC_VERSION > 4010000) ||\
|
||||
(\
|
||||
defined(__TI_COMPILER_VERSION__) && (\
|
||||
__TI_COMPILER_VERSION__ > 8003000 ||\
|
||||
(__TI_COMPILER_VERSION__ > 7003000 && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\
|
||||
)\
|
||||
)
|
||||
#if defined(__has_attribute)
|
||||
#if !defined(SQLITECPP_PURE_FUNC) && __has_attribute(pure)
|
||||
#define SQLITECPP_PURE_FUNC __attribute__((pure))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(SQLITECPP_PURE_FUNC)
|
||||
#define SQLITECPP_PURE_FUNC
|
||||
#endif
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file VariadicBind.h
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief Convenience function for Statement::bind(...)
|
||||
*
|
||||
* Copyright (c) 2016 Paul Dreik ([email protected])
|
||||
* Copyright (c) 2016-2023 Sebastien Rombauts ([email protected])
|
||||
* Copyright (c) 2019 Maximilian Bachmann ([email protected])
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SQLiteCpp/Statement.h>
|
||||
|
||||
#if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
|
||||
#include <tuple>
|
||||
#endif // c++14
|
||||
|
||||
/// @cond
|
||||
#include <utility>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace SQLite
|
||||
{
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* \brief Convenience function for calling Statement::bind(...) once for each argument given.
|
||||
*
|
||||
* This takes care of incrementing the index between each calls to bind.
|
||||
*
|
||||
* This feature requires a c++11 capable compiler.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* SQLite::Statement stm("SELECT * FROM MyTable WHERE colA>? && colB=? && colC<?");
|
||||
* SQLite::bind(stm,a,b,c);
|
||||
* //...is equivalent to
|
||||
* stm.bind(1,a);
|
||||
* stm.bind(2,b);
|
||||
* stm.bind(3,c);
|
||||
* \endcode
|
||||
* @param query statement
|
||||
* @param args zero or more args to bind.
|
||||
*/
|
||||
template<class ...Args>
|
||||
void bind(SQLite::Statement& query, const Args& ... args)
|
||||
{
|
||||
int pos = 0;
|
||||
(void)std::initializer_list<int>{
|
||||
((void)query.bind(++pos, std::forward<decltype(args)>(args)), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
#if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
|
||||
|
||||
/**
|
||||
* \brief Convenience function for calling Statement::bind(...) once for each parameter of a tuple,
|
||||
* by forwarding them to the variadic template
|
||||
*
|
||||
* This feature requires a c++14 capable compiler.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* SQLite::Statement stm("SELECT * FROM MyTable WHERE colA>? && colB=? && colC<?");
|
||||
* SQLite::bind(stm, std::make_tuple(a, b, c));
|
||||
* //...is equivalent to
|
||||
* stm.bind(1,a);
|
||||
* stm.bind(2,b);
|
||||
* stm.bind(3,c);
|
||||
* \endcode
|
||||
* @param query statement
|
||||
* @param tuple tuple with values to bind
|
||||
*/
|
||||
template <typename ... Types>
|
||||
void bind(SQLite::Statement& query, const std::tuple<Types...> &tuple)
|
||||
{
|
||||
bind(query, tuple, std::index_sequence_for<Types...>());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convenience function for calling Statement::bind(...) once for each parameter of a tuple,
|
||||
* by forwarding them to the variadic template. This function is just needed to convert the tuples
|
||||
* to parameter packs
|
||||
*
|
||||
* This feature requires a c++14 capable compiler.
|
||||
*
|
||||
* @param query statement
|
||||
* @param tuple tuple with values to bind
|
||||
*/
|
||||
template <typename ... Types, std::size_t ... Indices>
|
||||
void bind(SQLite::Statement& query, const std::tuple<Types...> &tuple, std::index_sequence<Indices...>)
|
||||
{
|
||||
bind(query, std::get<Indices>(tuple)...);
|
||||
}
|
||||
#endif // c++14
|
||||
|
||||
} // namespace SQLite
|
||||
Vendored
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user