Skip to content

Instantly share code, notes, and snippets.

@phoebe-leong
Last active October 26, 2021 21:19
Show Gist options
  • Save phoebe-leong/dfe7c75685f689b3ea767f89bba01072 to your computer and use it in GitHub Desktop.
Save phoebe-leong/dfe7c75685f689b3ea767f89bba01072 to your computer and use it in GitHub Desktop.
SQLite3 wrapper for C++17
#pragma once
#include <any>
#include <string>
#include <sqlite3.h>
#define SQLITE_HPP_VERSION 1.1
/**
* UNSUPPORTED:
*
* NOTE: Legacy functions/features not included in this list even though most of them are unsupported
*
* sqlite3_config(int, ...); Reason : Unable to find out what "..." was and as extension unable to pass arguments for them
* sqlite3_db_config(sqlite3*, int, ...); Reason : See above reason
* sqlite3_mprintf(const char*, ...); Reason : See first reason
* sqlite3_vmprintf(const char*, va_list); Reason : Insufficient documentation
* sqlite3_snprintf(int, char*, const char*, ...); Reason : See first reason
* sqlite3_vsnprintf(int, char*, const char*, va_list); Reason : Insufficent documentation for va_list
* sqlite3_test_control(int, ...); Reason : See first reason
* sqlite3_str_appendf(sqlite3_str*, const char*, ...); Reason : See above reason
* sqlite3_str_vappend(sqlite3_str*, const char*, va_list); Reason : Insufficient documentation for function
* sqlite3_strnicmp(const char*, const char*, int); Reason : Insufficient documentation
* sqlite3_log(int, const char*, ...); Reason : See first reason
* sqlite3_vtab_config(sqlite3*, int op, ...); Reason : See first reason
*/
/**
* NOTE:
* The documentation associated with these functions
* is quite slim.
* It is recommended to read the official SQLite
* documentation located at https://sqlite.org/docs.html
* (the documentation can also be found within the sqlite3.h file itself)
* along with the documentation provided here.
*/
class sqlite3_cpp
{
private:
bool is_open;
protected:
sqlite3* db;
public:
typedef sqlite3_int64 int64;
typedef sqlite3_uint64 uint64;
typedef sqlite3* sqlite3;
typedef sqlite3_backup* backup;
typedef sqlite3_stmt* statement;
typedef sqlite3_value* value;
typedef sqlite3_blob* blob;
typedef sqlite3_mutex* mutex;
typedef sqlite3_str* str;
typedef sqlite3_vfs* vfs;
typedef sqlite3_module* module;
typedef sqlite3_context* context;
/**
* @brief checks if the SQLite library is threadsafe
* @param none
* @returns compile-time setting of thread safety
*/
static bool threadsafe() { return (sqlite3_threadsafe() == 1 || sqlite3_threadsafe() == 2); }
/**
* @brief closes the open database
* @param none
* @returns result code
*/
int close()
{
int ret = sqlite3_close(db);
if (ret == SQLITE_OK) { is_open = false; }
return ret;
}
/**
* @brief executes SQL code in the current database with no callback functions
* @param sql SQL to execute
* @returns result code
*/
int exec(const std::string sql) { return sqlite3_exec(db, sql.c_str(), 0, NULL, NULL); }
/**
* @brief toggle extended result codes
* @param onoff value to toggle the extended results to
* @returns sqlite3 result codes
*/
int extended_result_codes(bool onoff) { return sqlite3_extended_result_codes(db, onoff); }
/**
* @brief fetches the last inserted row identification number
* @param none
* @returns last inserted row identifier or 0
*/
int64 last_insert_rowid() { return sqlite3_last_insert_rowid(db); }
/**
* @brief sets the last inserted row identification number without adding a row to the database
* @param id identification number to set the last inserted one to
* @returns void
*/
void set_last_insert_rowid(int64 id) { sqlite3_set_last_insert_rowid(db, id); }
/**
* @brief finds the amount of rows modified, removed, or added by the most recent INSERT, UPDATE, or DELETE statement
* @param none
* @returns amount of rows modified, removed, or added by the most recent INSERT, UPDATE, or DELETE statement
*/
int changes() { return sqlite3_changes(db); }
/**
* @brief finds the total amount of rows modified, removed, or added by the most recent INSERT, UPDATE, or DELETE statement
* @param none
* @returns total amount of rows modified, removed, or added by all INSERT, UPDATE, or DELETE statements since the database was opened
*/
int total_changes() { return sqlite3_total_changes(db); }
/**
* @brief causes any pending database operations to abort at their earliest opportunity
* @param none
* @returns void
*/
void interrupt() { return sqlite3_interrupt(db); }
/**
* @brief determines if a SQL statement is complete
* @param sql SQL string to test
* @returns 1 if the SQL statement is complete, 0 if not, and SQLITE_MEM if memory allocation fails
*/
static int complete(const std::string sql) { return sqlite3_complete(sql.c_str()); }
static int complete16(const void* sql) { return sqlite3_complete16(sql); }
/**
* @brief register a callback to handle SQLITE_BUSY errors
* @param callback function to perform when a SQLITE_BUSY error is encountered
* @param argument argument to invoke to the callback function. read the SQLite documentation for more info
* @returns sqlite return codes
*/
int busy_handler(int(*callback)(void*, int), void* argument) { return sqlite3_busy_handler(db, callback, argument); }
/**
* @brief sets amount of time to sleep for when table is locked
* @param ms milliseconds to sleep for
* @returns result code in std::string form (errmsg())
*/
int busy_timeout(int ms) { return sqlite3_busy_timeout(db, ms); }
/**
* @brief allocate a specific amount of bytes of memory
* @param bytes amount of bytes to allocate
* @returns pointer to block of memory allocated
*/
static std::any malloc(int bytes) { return sqlite3_malloc(bytes); }
static std::any malloc64(uint64 bytes) { return sqlite3_malloc64(bytes); }
/**
* @brief resize a memory allocation allocated with sqlite3_cpp::malloc() to a specific size
* @param block block of memory to resize
* @param bytes amount of bytes to resize it to
* @returns pointer to block of memory
*/
static std::any realloc(void* block, int bytes) { return sqlite3_realloc(block, bytes); }
static std::any realloc64(void* block, uint64 bytes) { return sqlite3_realloc64(block, bytes); }
/**
* @brief free a block of memory
* @param block to free
* @returns void
*/
static void free(void* block) { sqlite3_free(block); }
/**
* @brief returns size of memory allocation in bytes
* @param block memory to find the size of
* @returns size of memory allocation
*/
static uint64 mem_size(void* block) { return sqlite3_msize(block); }
/**
* @brief generates a random number
* @param randomness amount of randomess
* @returns the random number
*/
static std::any prng(int randomness)
{
void* out;
sqlite3_randomness(randomness, out);
return out;
}
/**
* @brief register an authoriser callback with the current database
* @param auth function to call
* @param arguments argument\s to pass to the function to call
* @returns sqlite result codes
*/
int set_authoriser(int(*auth)(void*, int, const char*, const char*, const char*, const char*), void* arguments) { return sqlite3_set_authorizer(db, auth, arguments); }
/**
* @brief register a trace callback function against the current database
* @param mask events to trigger the callback function
* @param callback function to call whenever any events marked in mask are invoked
* @param context_p context pointer to be passed to the callback function
* @returns sqlite result codes
*/
int trace(unsigned int mask, int(*callback)(unsigned int, void*, void*, void*), void* context_p) { return sqlite3_trace_v2(db, mask, callback, context_p); }
/**
* @brief periodically invokes a specified function during long calls to exec() and step()
* @param vm_instructions approximate amount of virtual machine instructions that are evaluated during the specified function
* @param func function to invoke
* @param argument the only parameter passed to the invoked function
* @returns void
*/
void progress_handler(int vm_instructions, int(*func)(void*), void* argument) { return sqlite3_progress_handler(db, vm_instructions, func, argument); }
/**
* @brief opens a database file
* @param database file to open
* @returns return code
*/
int open(const std::string database)
{
int ret = sqlite3_open(database.c_str(), &db);
if (ret == SQLITE_OK) { is_open = true; }
return ret;
}
int open16(const void* database)
{
int ret = sqlite3_open16(database, &db);
if (ret == SQLITE_OK) { is_open = true; }
return ret;
}
/**
* @brief open a database with a vfs file
* @param database file to open
* @param flags flags to pass to the function
* @param vfs virtual filesystem to use
* @returns sql return codes
*/
int open_vfs(std::string database, int flags, std::string vfs)
{
int ret = sqlite3_open_v2(database.c_str(), &db, flags, vfs.c_str());
if (ret == SQLITE_OK) { is_open = true; }
return ret;
}
/**
* @brief returns numeric result code
* @param none
* @returns numeric result code of last function sqlite call
*/
int errcode() { return sqlite3_errcode(db); }
int extended_errcode() { return sqlite3_extended_errcode(db); }
/**
* @brief returns error explanation
* @param none
* @returns returns explanation of the last result code in the database
*/
std::string errmsg() { return sqlite3_errmsg(db); }
std::u16string errmsg16() { return (char16_t*)sqlite3_errmsg16(db); }
/**
* @brief returns error explanation of an error code
* @param res_code the error/result code to find the explanation for
* @returns explanation of the specified error code
*/
static std::string errstr(int res_code) { return sqlite3_errstr(res_code); }
/**
* @brief enum for choices of 1st argument of limit()
*/
enum limit_categories
{
LENGTH = 0,
SQL_LENGTH,
COLUMN,
EXPR_DEPTH,
COMPOUND_SELECT,
VDBE_OP,
FUNCTION_ARG,
ATTACHED,
LIKE_PATTERN_LENGTH,
VARIABLE_NUMBER,
TRIGGER_DEPTH,
WORKER_THREADS
};
/**
* @brief change the size of a construct
* @param category class of constructs to be size limited
* @param limit size to change the limit to
* @returns prevous limit's size
*/
int limit(limit_categories category, int limit) { return sqlite3_limit(db, category, limit); }
/**
* @brief prepare a sqlite statement
* @param sql SQL to prepare
* @param statement statement to prepare
* @param tail where to put the unused portion of SQL
* @returns return code
*/
int prepare(const std::string sql, statement& stmt, std::string& tail) { return sqlite3_prepare_v2(db, sql.c_str(), -1, (statement*)&stmt, (const char**)tail.c_str()); }
int prepare16(const void* sql, statement& stmt, const void*& tail) { return sqlite3_prepare16_v2(db, sql, -1, (statement*)&stmt, (const void**)&tail); }
/* w/ flags */
int prepare(const std::string sql, unsigned int flags, statement& stmt, const std::string& tail) { return sqlite3_prepare_v3(db, sql.c_str(), -1, flags, (statement*)stmt, (const char**)tail.c_str()); }
int prepare16(const void* sql, unsigned int flags, statement& stmt, const void*& tail) { return sqlite3_prepare16_v3(db, sql, -1, flags, (statement*)stmt, (const void**)tail); }
/**
* @brief returns sql text that was used to make a statement
* @param stmt statement to retrieve text from
* @returns sql text that was used to make statement
*/
static std::string sql(statement stmt) { return sqlite3_sql(stmt); }
static std::string expanded_sql(statement stmt) { return sqlite3_expanded_sql(stmt); }
/**
* @brief determines whether the statement writes to the database
* @param stmt statement to check
* @returns boolean
*/
static bool stmt_readonly(statement stmt) { return sqlite3_stmt_readonly(stmt); }
/**
* @brief find out if a statement is an explain query plan
* @param stmt statement to check
* @returns 1 if the statement is an explain statement, 2 if the statement is an explain query plan, else 0
*/
static int stmt_isexplain(statement stmt) { return sqlite3_stmt_isexplain(stmt); }
/**
* @brief determine whether a statement has been reset
* @param stmt statement to check
* @returns boolean
*/
static bool stmt_busy(statement stmt) { return sqlite3_stmt_busy(stmt); }
/**
* @brief bind a value to a statement
* @param stmt statement to bind to
* @param index parameter index within the statement to bind to
* @param bind the value to bind
* @param destructor_type type of destructor to destroy the bind with
* @returns result code
*/
static int bind(statement stmt, int index, void* bind, int bytes) { return sqlite3_bind_blob(stmt, index, bind, bytes, SQLITE_STATIC); }
static int bind_blob64(statement stmt, int index, void* bind, int bytes) { return sqlite3_bind_blob64(stmt, index, bind, bytes, SQLITE_STATIC); }
static int bind(statement stmt, int index, double bind) { return sqlite3_bind_double(stmt, index, bind); }
static int bind(statement stmt, int index, int bind) { return sqlite3_bind_int(stmt, index, bind); }
static int bind(statement stmt, int index, int64 bind) { return sqlite3_bind_int64(stmt, index, bind); }
static int bind(statement stmt, int index) { return sqlite3_bind_null(stmt, index); }
static int bind(statement stmt, int index, std::string bind, void(*destructor_type)(void*)) { return sqlite3_bind_text(stmt, index, bind.c_str(), -1, destructor_type); }
static int bind(statement stmt, int index, void* bind, void(*destructor_type)(void*)) { return sqlite3_bind_text16(stmt, index, bind, -1, destructor_type); }
enum encoding
{
UTF8 = 1,
UTF16LE,
UTF16BE,
UTF16,
UTF16_ALIGNED = 8
};
static int bind_text64(statement stmt, int index, std::wstring bind, uint64 bytes, encoding enc) { return sqlite3_bind_text64(stmt, index, (char*)bind.c_str(), bytes, SQLITE_STATIC, (unsigned char)enc); }
static int bind(statement stmt, int index, value bind) { return sqlite3_bind_value(stmt, index, bind); }
/**
* @param pointer pointer to associate the null bind with
*/
static int bind(statement stmt, int index, void* pointer, std::string type, void(*destructor_type)(void*)) { return sqlite3_bind_pointer(stmt, index, pointer, type.c_str(), destructor_type); }
static int bind_zeroblob(statement stmt, int index, int bind) { return sqlite3_bind_zeroblob(stmt, index, bind); }
static int bind(statement stmt, int index, uint64 bind) { return sqlite3_bind_zeroblob64(stmt, index, bind); }
/**
* @brief returns amount of parameters in a prepared statement
* @param stmt statement to find amount of parameters
* @returns amount of parameters in a prepared statement
*/
static int bind_param_count(statement stmt) { return sqlite3_bind_parameter_count(stmt); }
/**
* @brief returns name of a parameter with a specific index
* @param stmt statement to find parameter in
* @param index parameter's index
* @returns name of the paramter specified
*/
static std::string bind_param_name(statement stmt, int index) { return sqlite3_bind_parameter_name(stmt, index); }
/**
* @brief returns index of a parameter with a specific name
* @param stmt statement to find parameter in
* @param name name of the parameter
* @returns index of specified parameter
*/
static int bind_param_index(statement stmt, std::string name) { return sqlite3_bind_parameter_index(stmt, name.c_str()); }
/**
* @brief resets all bindings in a prepared statement
* @param stmt statement to reset
* @returns sql result codes
*/
static int clear_bindings(statement stmt)
{
return sqlite3_clear_bindings(stmt);
}
/**
* @brief finds the number of columns in the result of a prepared statement
* @param stmt prepared statement to search
* @returns number of columns in the statement
*/
static int column_count(statement stmt) { return sqlite3_column_count(stmt); }
/**
* @brief returns the name of a particular column in a completed statement
* @param stmt statement to analyse
* @param index column index to find the name of
* @returns name of a particular column in a statement
*/
static std::string column_name(statement stmt, int index) { return sqlite3_column_name(stmt, index); }
static std::u16string column_name16(statement stmt, int index) { return (char16_t*)sqlite3_column_name16(stmt, index); }
/**
* @brief determine the database of a particular column in a completed statement
* @param stmt statement to analyse
* @param index column index to find the database's name of
* @return database name
*/
static std::string column_database_name(statement stmt, int index) { return sqlite3_column_database_name(stmt, index); }
static std::u16string column_database_name16(statement stmt, int index) { return (char16_t*)sqlite3_column_database_name16(stmt, index); }
/**
* @brief determine which table a particular column of a completed statement is in
* @param stmt statement to analyse
* @param index column index to find the table of
* @returns table name
*/
static std::string column_table_name(statement stmt, int index) { return sqlite3_column_table_name(stmt, index); }
static std::u16string column_table_name16(statement stmt, int index) { return (char16_t*)sqlite3_column_table_name16(stmt, index); }
/**
* @brief determine the table column (origin) of a completed statement
* @param stmt statement to analyse
* @param index column index to find the origin
* @returns table column of completed statement
*/
static std::string column_origin_name(statement stmt, int index) { return sqlite3_column_origin_name(stmt, index); }
static std::u16string column_origin_name16(statement stmt, int index) { return (char16_t*)sqlite3_column_origin_name16(stmt, index); }
/**
* @brief determine the datatype of a completed statement
* @param stmt statement to analyse
* @param index column index to find the datatype of
* @returns datatype of the completed statement
*/
static std::string column_decltype(statement stmt, int index) { return sqlite3_column_decltype(stmt, index); }
static std::u16string column_decltype16(statement stmt, int index) { return (char16_t*)sqlite3_column_decltype16(stmt, index); }
/**
* @brief evalute an SQL statement
* @param stmt statement to evaluate
* @returns return code
*/
static int step(statement stmt) { return sqlite3_step(stmt); }
/**
* @brief returns number of columns in the current row of a prepared statement
* @param stmt statement to evaluate
* @returns amount of columns in current row
*/
static int data_count(statement stmt) { return sqlite3_data_count(stmt); }
/**
* @brief find a column index of a prepared statement
* @param stmt prepared statement to analyse
* @param index column index to find
* @returns column index of the prepared statement
*/
static const std::any column_blob(statement stmt, int index) { return sqlite3_column_blob(stmt, index); }
static double column_double(statement stmt, int index) { return sqlite3_column_double(stmt, index); }
static int column_int(statement stmt, int index) { return sqlite3_column_int(stmt, index); }
static int64 column_int64(statement stmt, int index) { return sqlite3_column_int64(stmt, index); }
static std::string column_text(statement stmt, int index) { return (char*)sqlite3_column_text(stmt, index); }
static std::u16string column_text16(statement stmt, int index) { return (char16_t*)sqlite3_column_text16(stmt, index); }
static value column_value(statement stmt, int index) { return sqlite3_column_value(stmt, index); }
static int column_bytes(statement stmt, int index) { return sqlite3_column_bytes(stmt, index); }
static int column_bytes16(statement stmt, int index) { return sqlite3_column_bytes16(stmt, index); }
/**
* @brief column datatypes for column_type()
*/
enum datatypes
{
INTEGER = 1,
FLOAT,
BLOB,
NULL_,
TEXT
};
/**
* @brief returns datatype of specifed column of a prepared statement
* @param stmt statement to analyse
* @param index column index to find type of
* @returns datatype of specified column
*/
static datatypes column_type(statement stmt, int index) { return (datatypes)sqlite3_column_type(stmt, index); }
/**
* @brief destroy a prepared statement
* @param stmt statement to destroy
* @returns return code
*/
static int destroy(statement stmt) { return sqlite3_finalize(stmt); }
/**
* @brief reset a prepared statement
* @param stmt statement to reset
* @returns return code
*/
static int reset(statement stmt) { return sqlite3_reset(stmt); }
/**
* @brief encoding options for the create_function() functions
*/
enum function_encoding
{
UTF8_ = UTF8,
UTF16LE_,
UTF16BE_,
UTF16_,
UTF16_ALIGNED_ = UTF16_ALIGNED,
UTF8_DETERMINISTIC = UTF8 | SQLITE_DETERMINISTIC,
UTF16LE_DETERMINISTIC = UTF16LE | SQLITE_DETERMINISTIC,
UTF16BE_DETERMINISTIC = UTF16BE | SQLITE_DETERMINISTIC,
UTF16_DETERMINISTIC = UTF16 | SQLITE_DETERMINISTIC,
};
/**
* @brief create a SQL function
* @param function_name the name of the function to be created
* @param argument_amt amount of arguments that the function has
* @param param_encoding specify the text encoding for the functions parameters
* @param pointer arbitrary pointer which can be accessed by user_data()
* @param func function that implements the function to be made. to delete
* an existing function, simply pass NULL to all of the function parameters
* @param step function that implements the function to be made
* @param final function that implements the function to be made
* @returns sqlite result code
*/
int create_function(std::string function_name, int argument_amt, function_encoding param_encoding, void* pointer, void(*func)(context, int, value*), void(*step)(context, int, value*), void(*final)(context)) { return sqlite3_create_function(db, function_name.c_str(), argument_amt, param_encoding, pointer, func, step, final); }
int create_function16(std::string function_name, int argument_amt, function_encoding param_encoding, void* pointer, void(*func)(context, int, value*), void(*step)(context, int, value*), void(*final)(context)) { return sqlite3_create_function16(db, function_name.c_str(), argument_amt, param_encoding, pointer, func, step, final); }
/**
* @param destructor destructor function, invoked when the function is deleted
*/
int create_function(std::string function_name, int argument_amt, function_encoding param_encoding, void* pointer, void(*func)(context, int, value*), void(*step)(context, int, value*), void(*final)(context), void(*destructor)(void*)) { return sqlite3_create_function_v2(db, function_name.c_str(), argument_amt, param_encoding, pointer, func, step, final, destructor); }
/**
* @param inverse function that implements the function to be made
* more info can be found here: https://www.sqlite.org/windowfunctions.html
*/
int create_window_function(std::string function_name, int argument_amt, function_encoding param_encoding, void* pointer, void(*step)(context, int, value*), void(*final)(context), void(*val)(context), void(*inverse)(context, value*), void(*destructor)(void*));
/**
* @brief returns the result of a protected sqlite3 value
* @param val value to find the result of
* @returns result of the value
*/
static const std::any value_blob(value val) { return sqlite3_value_blob(val); }
static double value_double(value val) { return sqlite3_value_double(val); }
static int value_int(value val) { return sqlite3_value_int(val); }
static int64 value_int64(value val) { return sqlite3_value_int64(val); }
/**
* @param string must be the same as the string the value was initialised with
*/
static std::any value_pointer(value val, std::string string) { return sqlite3_value_pointer(val, string.c_str()); }
static std::string value_text(value val) { return (char*)sqlite3_value_text(val); }
static std::u16string value_text16(value val) { return (char16_t*)sqlite3_value_text16(val); }
static std::u16string value_text16le(value val) { return (char16_t*)sqlite3_value_text16le(val); }
static std::u16string value_text16be(value val) { return (char16_t*)sqlite3_value_text16be(val); }
static int value_bytes(value val) { return sqlite3_value_bytes(val); }
static int value_bytes16(value val) { return sqlite3_value_bytes16(val); }
/**
* @brief returns datatype code for the value
* @param val value to find the datatype of
* @returns datatype for the value
*/
static datatypes value_type(value val) { return (datatypes)sqlite3_value_type(val); }
static datatypes value_numeric_type(value val) { return (datatypes)sqlite3_value_numeric_type(val); }
/**
* @brief determines whether a column has been altered by an UPDATE command
* @param val value to check
* @returns boolean
*/
static bool value_nochange(value val) { return sqlite3_value_nochange(val); }
/**
* @brief determines whether value originated from a bind interface
* @param val value to check
* @returns boolean
*/
static bool value_frombind(value val) { return (sqlite3_value_frombind(val) != 0); }
/**
* @brief find the subtype of a value
* @param val value to find the subtype of
* @returns subtype of value
*/
static unsigned int value_subtype(value val) { return sqlite3_value_subtype(val); }
/**
* @brief make a copy of an existing value
* @param val value to copy
* @returns copy of existing value
*/
static value value_dupe(const value val) { return sqlite3_value_dup(val); }
/**
* @brief free a value
* @param val value to free
* @returns void
*/
static void value_free(value val) { sqlite3_value_free(val); }
/**
* @brief obtain aggregate function context
* @param c context variable passed to the step or final function that implements the aggregate function
* @param bytes amount of bytes to allocate
* @returns memory address allocated
*/
static std::any aggregate_context(context c, int bytes) { return sqlite3_aggregate_context(c, bytes); }
/**
* @brief returns a copy of the pointer that was the 5th parameter to create_function()
* @param c context variable to find the pointer of
* @returns copy of the pointer
*/
static std::any user_data(context c) { return sqlite3_user_data(c); }
/**
* @brief returns a copy of the pointer to the 1st parameter to create_function()
* @param c context variable to find the pointer of
* @returns copy of the pointer
*/
static sqlite3 context_db_handle(context c) { return sqlite3_context_db_handle(c); }
/**
* @brief finds a pointer to an argument passed to set_auxdata with a specific index of the application-defined function.
* for a better explanation refer to line 5237 of sqlite3.h
* @param c context variable associated with the application defined function
* @param arg_index index to find
* @returns pointer to argument
*/
static std::any get_auxdata(context c, int arg_index) { return sqlite3_get_auxdata(c, arg_index); }
/**
* @brief set a variable as metadata for an application defined function
* @param c context variable associated with the application defined function
* @param arg_index which parameter of the application defined function to pass the metadata to
* @param metadata metadata to be passed
* @param destructor function to be called when metadata is destroyed
* @returns void
*/
static void set_auxdata(context c, int arg_index, void* metadata, void(*destructor)(void*)) { return sqlite3_set_auxdata(c, arg_index, metadata, destructor); }
/**
* @brief set the result of an SQL function
* @param c context variable used in create_function() linked to the application defined function
* @param res variable to store the function result in
* @param bytes length of the function result variable in bytes
* @param destructor function to execute when the variable is destroyed
* @returns void
*/
static void result_blob(context c, void* res, int bytes, void(*destructor)(void*)) { sqlite3_result_blob(c, res, bytes, destructor); }
static void result_blob(context c, void* res, uint64 bytes, void(*destructor)(void*)) { sqlite3_result_blob64(c, res, bytes, destructor); }
static void result_double(context c, double res) { sqlite3_result_double(c, res); }
static void result_int(context c, int res) { sqlite3_result_int(c, res); }
static void result_int(context c, int64 res) { sqlite3_result_int64(c, res); }
static void result_null(context c) { sqlite3_result_null(c); }
static void result_text(context c, std::string res, int bytes, void(*destructor)(void*)) { sqlite3_result_text(c, res.c_str(), bytes, destructor); }
static void result_text64(context c, std::wstring res, uint64 bytes, void(*destructor)(void*), encoding enc) { sqlite3_result_text64(c, (const char*)res.c_str(), bytes, destructor, (unsigned char)enc); }
static void result_text16(context c, std::u16string res, int bytes, void(*destructor)(void*)) { sqlite3_result_text16(c, (void*)res.c_str(), bytes, destructor); }
static void result_text16le(context c, std::u16string res, int bytes, void(*destructor)(void*)) { sqlite3_result_text16le(c, (void*)res.c_str(), bytes, destructor); }
static void result_text16be(context c, std::u16string res, int bytes, void(*destructor)(void*)) { sqlite3_result_text16be(c, (void*)res.c_str(), bytes, destructor); }
static void result_value(context c, value res) { sqlite3_result_value(c, res); }
/**
* @brief set the subtype of an application defined function
* @param c context variable linked to the application defined func
* @param subtype integer to set the subtype to
* @returns void
*/
static void result_subtype(context c, unsigned int subtype) { sqlite3_result_subtype(c, subtype); }
/**
* @param pointer type that the pointer will be associated with
*/
static void result_pointer(context c, void* res, std::string pointer, void(*destructor)(void*)) { sqlite3_result_pointer(c, res, pointer.c_str(), destructor); }
static void result_zeroblob(context c, int bytes) { sqlite3_result_zeroblob(c, bytes); }
static void result_zeroblob(context c, int64 bytes) { sqlite3_result_zeroblob64(c, bytes); }
/**
* @brief throw an exception
* @param msg error message to throw
* @param bytes_to_take amount of bytes to read from the string (default is up to the null terminator)
*/
static void result_error(context c, std::string msg, int bytes_to_take = -1) { sqlite3_result_error(c, msg.c_str(), bytes_to_take); }
static void result_error(context c, std::u16string msg, int bytes_to_take = -1) { sqlite3_result_error16(c, (void*)msg.c_str(), bytes_to_take); }
static void result_error_toobig(context c) { sqlite3_result_error_toobig(c); }
static void result_error_nomem(context c) { sqlite3_result_error_nomem(c); }
/**
* @brief sets the return value of the application defined function to the second argument
*/
static void result_error_code(context c, int ret) { sqlite3_result_error_code(c, ret); }
/**
* @brief add, remove, or modify a collation
* @param name the name of the collation
* @param enc encoding for the collation
* @param first_arg application data pointer and first argument to the collating function callback
* @param callback collating function
* @returns sqlite3 result codes
*/
int create_collation(std::string name, encoding enc, void* first_arg, int(*compare)(void*, int, const void*, int, const void*)) { return sqlite3_create_collation(db, name.c_str(), enc, first_arg, compare); }
/**
* @param destructor function to call when the collation is destroyed
*/
int create_collation(std::string name, encoding enc, void* first_arg, int(*compare)(void*, int, const void*, int, const void*), void(*destructor)(void*)) { return sqlite3_create_collation_v2(db, name.c_str(), enc, first_arg, compare, destructor); }
int create_collation16(std::u16string name, encoding enc, void* first_arg, int (*compare)(void*, int, const void*, int, const void*)) { return sqlite3_create_collation16(db, (void*)name.c_str(), enc, first_arg, compare); }
/**
* @brief register a collation
* @param first_arg first argument to be passed to the callback function
* @param callback function to be invoked whenever an undefined collation sequence is come across
* @returns sqlite3 result codes
*/
int collation_needed(void* first_arg, void(*callback)(void*, sqlite3, int, const char*)) { return sqlite3_collation_needed(db, first_arg, callback); }
int collation_needed16(void* first_arg, void(*callback)(void*, sqlite3, int, const void*)) { return sqlite3_collation_needed16(db, first_arg, callback); }
/**
* @brief causes the current thread to sleep for at least a specific amount of milliseconds
* @param ms milliseconds to sleep the current thread for
* @returns milliseconds slept
*/
int sleep(int ms) { return sqlite3_sleep(ms); }
/**
* @brief checks if the current database has autocommit turned on
* @param none
* @returns boolean
*/
bool has_autocommit() { return (sqlite3_get_autocommit(db) != 0); }
/**
* @brief find the database handle of a prepared statement
* @param stmt statement to find the handle of
* @returns returns pointer to database connection of the statement
*/
static sqlite3 db_handle(statement stmt) { return sqlite3_db_handle(stmt); }
/**
* @brief find the absolute path of a database file
* @param name type of database, e.g., "temp", "main"
* @returns absolute path to the database file
*/
std::string db_filename(std::string name) { return sqlite3_db_filename(db, name.c_str()); }
/**
* @brief find out if a database is read only
* @param name type of database, e.g., "temp", "main"
* @returns 1 if database is read only, 0 if it's read/write, -1 if the database has the wrong name
*/
int db_readonly(std::string name) { return sqlite3_db_readonly(db, name.c_str()); }
/**
* @brief find the next prepared statement in the current database
* @param stmt statement to find the next from
* @returns next statement
*/
statement next_stmt(statement stmt) { return sqlite3_next_stmt(db, stmt); }
/**
* @brief register a callback to be invoked whenever a transaction is committed
* @param callback callback function to be registered
* @param arg argument to pass to the callback function
*/
std::any commit_hook(int(*callback)(void*), void* arg) { return sqlite3_commit_hook(db, callback, arg); }
/**
* @brief register a callback to be invoked whenever a trnacsaction is rolled back
*/
std::any rollback_hook(void(*callback)(void*), void* arg) { return sqlite3_rollback_hook(db, callback, arg); }
/**
* @brief register a callback to be invoked whenever a row is updated, inserted, or deleted
*/
std::any update_hook(void(*callback)(void*, int, const char*, const char*, int64), void* arg);
/**
* @brief release a specific amount of non-essential library memory
* @param bytes amount of bytes to free
* @returns amount of bytes freed, or 0 if SQLite is not compiled with SQLITE_ENABLE_MEMORY_MANAGEMENT
*/
static int release_memory(int bytes) { return sqlite3_release_memory(bytes); }
/**
* @brief free as much database memory as possible - works a bit like sqlite3_release_memory()
* @param none
* @returns amount of bytes freed
*/
int db_release_memory() { return sqlite3_db_release_memory(db); }
/**
* @brief impose a limit on heap size
* @param limit limit to impose
* @returns previous soft heap limit
*/
static int64 soft_heap_limit(int64 limit) { return sqlite3_soft_heap_limit64(limit); }
/**
* @brief variables to store results of table_column_metadata()
*/
struct table_column_metadata_res
{
std::string datatype, col_sequence;
bool not_null, primary_key, auto_inc;
};
/**
* @brief find data about a column of a table
* @param db_name name of the type of the database, e.g., "main", "temp"
* @param table table to find
* @param col_name column name to find and analyse
* @param res struct to put results in
* @returns standard sql result code
*/
int table_column_metadata(std::string db_name, std::string table, std::string col_name, table_column_metadata_res& res) { return sqlite3_table_column_metadata(db, db_name.c_str(), table.c_str(), col_name.c_str(), (const char**)res.datatype.c_str(), (const char**)res.col_sequence.c_str(), (int*)&res.not_null, (int*)&res.primary_key, (int*)res.auto_inc); }
/**
* @brief register a new virtual table module
* @param name name for the module
* @param mod implementation of the virtual table module
* @param data client data for the function
* @returns sqlite3 result code
*/
int create_module(std::string name, module mod, void* data) { return sqlite3_create_module(db, name.c_str(), mod, data); }
/**
* @param destructor function to call when the module is destroyed
*/
int create_module(std::string name, module mod, void* data, void(*destructor)(void*)) { return sqlite3_create_module_v2(db, name.c_str(), mod, data, destructor); }
/**
* @brief overload a function for a virtual table
* @param func_name name of the function
* @param param_num amount of parameters the function has
* @returns sqlite3 result code
*/
int overload_function(std::string func_name, int param_num) { return sqlite3_overload_function(db, func_name.c_str(), param_num); }
/**
* @brief open a blob handle
* @param db_name symbolic database name. e.g., "main", "temp"
* @param table table in which the blob is stored
* @param col column in which the blob is stored relative to the table
* @param row row in which the blob is stored relative to the column
* @param flags amount of flags to pass to the function
* @param b blob to open
* @returns result code
*/
int blob_open(std::string db_name, std::string table, std::string col, int64 row, int flags, blob& b) { return sqlite3_blob_open(db, db_name.c_str(), table.c_str(), col.c_str(), row, flags, (blob*)b); }
/**
* @brief move an existing blob handle to a different row
* @param b blob to move
* @param row row to move the blob to
* @returns result code
*/
int blob_reopen(blob b, int64 row) { return sqlite3_blob_reopen(b, row); }
/**
* @brief close an open blob handle
* @param b blob to close
* @returns result code
*/
int blob_close(blob b) { return sqlite3_blob_close(b); }
/**
* @brief find the size of an open blob
* @param b blob to find the size of
* @returns size of the blob (in bytes obviously)
*/
int blob_bytes(blob b) { return sqlite3_blob_bytes(b); }
/**
* @brief read from a blob handle
* @param b blob to read from
* @param buffer where to store the read data
* @param bytes amount of bytes to read
* @param offset the byte to start reading at
* @returns return code
*/
int blob_read(blob b, void* buffer, int bytes, int offset = 1) { return sqlite3_blob_read(b, buffer, bytes, offset); }
/**
* @brief write to a blob
* @param b blob to write to
* @param data data to write
* @param bytes amount of bytes to write
* @param offset byte to start at
* @returns return code
*/
int blob_write(blob b, void* data, int bytes, int offset) { return sqlite3_blob_write(b, data, bytes, offset); }
/**
* @brief find a virtual filesystem
* @param vfs_name name of the virtual filesystem
* @returns virtual filesystem
*/
vfs vfs_find(std::string vfs_name) { return sqlite3_vfs_find(vfs_name.c_str()); }
/**
* @brief register a virtual filesystem
* @param reg filesystem to register
* @param def whether to make the filesystem the default
* @returns sqlite3 return code
*/
int vfs_register(vfs reg, bool def) { return sqlite3_vfs_register(reg, def); }
/**
* @brief unregister a virtual filesystem
* @param filesystem filesystem to unregister
* @returns sqlite3 return code
*/
int vfs_unregister(vfs filesystem) { return sqlite3_vfs_unregister(filesystem); }
/**
* @brief mutex constant types to create a mutex with
*/
enum mutex_constants
{
MUTEX_FAST = 0,
MUTEX_RECURSIVE,
MUTEX_STATIC_MASTER,
MUTEX_STATIC_MEM,
MUTEX_STATIC_OPEN,
MUTEX_STATIC_PRNG,
MUTEX_STATIC_LRU,
MUTEX_STATIC_PMEM,
MUTEX_STATIC_APP1,
MUTEX_STATIC_APP2,
MUTEX_STATIC_APP3,
MUTEX_STATIC_VFS1,
MUTEX_STATIC_VFS2,
MUTEX_STATIC_VFS3
};
/**
* @brief create a mutex
* @param flag type of mutex to create
* @returns created mutex
*/
mutex mutex_alloc(mutex_constants flag) { return sqlite3_mutex_alloc(flag); }
/**
* @brief free a mutex
* @param m mutex to be freed
* @returns void
*/
void mutex_free(mutex m) { sqlite3_mutex_free(m); }
/**
* @brief enter a mutex
* @param m mutex to enter
* @returns void
*/
void mutex_enter(mutex m) { sqlite3_mutex_enter(m); }
std::string mutex_try(mutex m) { return errstr(sqlite3_mutex_try(m)); }
/**
* @brief leave a mutex
* @param m mutex to leave
* @returns void
*/
void mutex_leave(mutex m) { sqlite3_mutex_leave(m); }
/**
* @brief retrieve the mutex for the current database connection
* @param none
* @returns mutex for the current database connection
*/
mutex db_mutex() { return sqlite3_db_mutex(db); }
/**
* @brief directly control database files
* @param db_name name of the database schema to control e.g., "main", "temp"
* @param opcode operation code for the function
* @param arguments structure containing possible arguments
* @returns sqlite3 return codes
*/
int file_control(std::string db_name, int opcode, void* arguments) { return sqlite3_file_control(db, db_name.c_str(), opcode, arguments); }
/**
* @brief returns the amount of keywords in SQLite
* @param none
* @returns amount of keywords in SQLite
*/
static int keyword_count() { return sqlite3_keyword_count(); }
/**
* @brief find the name of a keyword with it's index
* @param index index of the keyword to find
* @param word where to store the keyword name
* @param bytes where to store the amount of bytes
* @returns return code
*/
static int keyword_name(int index, std::string& word, int& bytes) { return sqlite3_keyword_name(index, (const char**)word.c_str(), (int*)&bytes); }
/**
* @brief checks whether a string is a keyword
* @param keyword string to check
* @param bytes length of the string
* @returns boolean
*/
static bool keyword_check(std::string keyword, int bytes) { return (sqlite3_keyword_check(keyword.c_str(), bytes) != 0); }
/**
* @brief create a new dynamic string
* @param none
* @returns dynamic string
*/
str str_new() { return sqlite3_str_new(db); }
/**
* @brief finalise, destroy, and free the memory of a dynamic string
* @param string dynamic string to destroy
* @returns void
*/
void str_finish(str string) { free(sqlite3_str_finish(string)); }
/**
* @brief check if a database file is a URI containing a specific query parameter
* @param filename name of the file to check
* @param param parameter query to search for
* @returns parameter if it exists, NULL if it doesn't
*/
std::string uri_parameter(std::string filename, std::string param) { return sqlite3_uri_parameter(filename.c_str(), param.c_str()); }
/**
* @brief check if a database file is a URI containing a specific query parameter
* @param filename name of the file to check
* @param param parameter query to search for
* @param def default return value
* @returns if the query has a truthy value, e.g., "yes", true, "on" then true is returned.
* If the query has a falsy value, e.g., "no", false, "off" then false is returned. Otherwise, (def != true) is returned.
*/
bool uri_boolean(std::string filename, std::string param, bool def) { return sqlite3_uri_boolean(filename.c_str(), param.c_str(), def); }
/**
* @brief check if a database file is a URI containing a specific query parameter
* @param filename name of the file to check
* @param param parameter query to search for
* @param def default return value
* @returns converts the parameter into a 64-bit integer and returns it. If the parameter does not exist, the default parameter is returned.
*/
int64 uri_int64(std::string filename, std::string param, int64 def) { return sqlite3_uri_int64(filename.c_str(), param.c_str(), def); }
/**
* @brief find the error code for a dynamic string
* @param string string to find the error code of
* @returns error code contained inside the string
*/
static int str_errcode(str string) { return sqlite3_str_errcode(string); }
/**
* @brief append a specific amount of bytes to a dynamic string
* @param string string to append to
* @param data string to append
* @param bytes amount of bytes to append (defaults to length of data)
* @returns return code
*/
static int str_append(str string, std::string data, int bytes)
{
sqlite3_str_append(string, data.c_str(), bytes);
return str_errcode(string);
}
static int str_append(str string, std::string data)
{
sqlite3_str_appendall(string, data.c_str());
return str_errcode(string);
}
/**
* @brief append a character to a dynamic string a specific amount of times
* @param str dynamic string to append to
* @param data character to append
* @param amount how many times to append the character (defaults to 1)
* @returns return code
*/
static int str_appendchar(str string, char data, int amount = 1)
{
sqlite3_str_appendchar(string, amount, data);
return str_errcode(string);
}
/**
* @brief reset a dynamic string
* @param string string to reset
* @returns void
*/
static void str_reset(str string) { sqlite3_str_reset(string); }
/**
* @brief find the length of a dynamic string
* @param string string to find the length of
* @return length of string
*/
static int str_length(str string) { return sqlite3_str_length(string); }
/**
* @brief finds the value of a dynamic string
* @param string string to find the value of
* @returns pointer to contents of dynamic string
*/
static std::string str_value(str string) { return sqlite3_str_value(string); }
/**
* @brief options for the first argument to status()
*/
enum status_params
{
MEMORY_USED,
PAGECACHE_USED,
PAGECACHE_OVERFLOW,
MALLOC_SIZE = 5,
PARSER_STACK,
PAGECACHE_SIZE,
MALLOC_COUNT = 9
};
/**
* @brief find runtime status info regarding the performance of SQLite
* @param op which parameter to measure
* @param param_currentval where to store the current value of the requested parameter
* @param param_highwater where to store the highest recorded value of the requested parameter
* @param reset whether to reset the highest recorded value or not
* @returns result code
*/
static int status(status_params op, int& param_currentval, int& param_highwater, bool reset) { return sqlite3_status(op, (int*)&param_currentval, (int*)&param_highwater, (int)reset); }
static int status(status_params op, int64& param_currentval, int64& highwater, bool reset) { return sqlite3_status64(op, (int64*)&param_currentval, (int64*)&highwater, (int)reset); }
/**
* @brief options for the first argument to db_status()
*/
enum db_status_params
{
LOOKASIDE_USED = 0,
CACHE_USED,
SCHEMA_USED,
STMT_USED,
LOOKASIDE_HIT,
LOOKASIDE_MISS_SIZE,
LOOKASIDE_MISS_FULL,
CACHE_HIT,
CACHE_MISS,
CACHE_WRITE,
DEFERRED_FKS,
CACHE_USED_SHARED,
CACHE_SPILL,
MAX
};
/**
* @brief retrieve runtime status info about the selected database
* @param op which parameter to measure
* @param currentval where to store the current value of the specified parameter
* @param highwater where to store the highest value of the specified parameter
* @param reset whether to reset the highest value or not
* @returns result code
*/
int db_status(db_status_params op, int& currentval, int& highwater, bool reset) { return sqlite3_db_status(db, op, (int*)&currentval, (int*)&highwater, (int)reset); }
/**
* @brief options for the second argument to stmt_status()
*/
enum stmt_status_counters
{
FULLSCAN_STEP = 1,
SORT,
AUTOINDEX,
VM_STEP,
REPREPARE,
RUN,
MEMUSED = 99
};
/**
* @brief find the status of a statement counter parameter
* @param stmt statement to find the status of
* @param op counter to retrieve
* @param reset whether to reset the counter to 0
* @returns value of the requested counter
*/
static int stmt_status(statement stmt, stmt_status_counters op, bool reset) { return sqlite3_stmt_status(stmt, op, (int)reset); }
/**
* @brief Copy the content of the current database into another one
* @param destination the object to copy to - function gets the database from it
* @param db_name the symbolic name of the database to copy to. e.g., "main", "temp"
* @param src_db_name the symbolic name of the database that is being copied
* @returns backup object
*/
backup backup_init(sqlite3_cpp destination, std::string db_name, std::string src_db_name) { return sqlite3_backup_init(destination.db, db_name.c_str(), db, src_db_name.c_str()); }
/**
* @brief Copy a specific amount of pages between the source and destination database
* @param b backup to copy from/to
* @param pages amount of pages to be copied (default is all of them)
* @returns result code
*/
static int backup_step(backup b, int pages = -1) { return sqlite3_backup_step(b, pages); }
/**
* @brief destroy a backup
* @param b backup to destroy
* @returns result code
*/
static int backup_destroy(backup b) { return sqlite3_backup_finish(b); }
/**
* @brief find how many pages still need to be copied
* @param b backup to find amount of pages left of
* @returns the amount of pages still left to be copied
*/
static int backup_remaining(backup b) { return sqlite3_backup_remaining(b); }
/**
* @brief find how many pages are in the source database
* @param b backup to find the source database of
* @returns the amount of pages in the source database
*/
static int backup_pagecount(backup b) { return sqlite3_backup_pagecount(b); }
/**
* @brief compare two strings to each other
* @param first the first string to compare
* @param second the second string to compare
* @returns boolean
*/
static bool stricmp(std::string first, std::string second) { return sqlite3_stricmp(first.c_str(), second.c_str()); }
/**
* @brief compares a string to a specific pattern, the specifics of which can be found on line 8175 of sqlite3.h
* @param pattern pattern to compare the string to
* @param string string to compare
* @returns boolean
*/
static bool string_glob(std::string pattern, std::string string) { return sqlite3_strglob(pattern.c_str(), string.c_str()); }
/**
* @brief compares a string to a specific pattern, optionally making use of an escape character.
* Unlike string_glob(), string_like() is case-insensitive.
* @param pattern pattern to compare the string to
* @param string string to compare
* @param esc escape character (defaults to 0)
* @returns boolean
*/
static bool string_like(std::string pattern, std::string string, unsigned int esc = 0) { return sqlite3_strlike(pattern.c_str(), string.c_str(), esc); }
/**
* @brief register a callback function to be invoked whenever data is commited to the database in WAL mode
* @param func function to register
* @param first_arg first argument to the callback function.
* find more info on line 8240 of sqlite3.h
* @returns first_arg (?)
*/
std::any wal_hook(int(*func)(void*, sqlite3, const char*, int), void* first_arg) { return sqlite3_wal_hook(db, func, first_arg); }
/**
* @brief configure an auto-checkpoint
* @param frames amount of frames required to be in the write-ahead log for a checkpoint to be invoked
* @returns sqlite3 return values
*/
int wal_autocheckpoint(int frames);
/**
* @brief accepted inputs for the second argument to wal_checkpoint()
*/
enum checkpoint_modes
{
PASSIVE = 0,
FULL,
RESTART,
TRUNCATE
};
/**
* @brief transfer the content in the write-ahead log to the specified database
* @param db_name database name to transfer from/to
* @param mode the mode of checkpointing
* @param wal_log_frames where to store the size of the log in frames
* @param total_frames where to store the total amount of frames
* @returns result code
*/
int wal_checkpoint(std::string db_name, checkpoint_modes mode, int& wal_log_frames, int& total_frames) { return sqlite3_wal_checkpoint_v2(db, db_name.c_str(), mode, (int*)&wal_log_frames, (int*)&total_frames); }
int wal_checkpoint(std::string db_name) { return sqlite3_wal_checkpoint(db, db_name.c_str()); }
/**
* @brief flush the database's cache
* @param none
* @returns result code
*/
int cacheflush() { return sqlite3_db_cacheflush(db); }
/**
* @brief find the operating system error code that may have caused an internal SQLite error
* @param none
* @returns error code
*/
int system_errno() { return sqlite3_system_errno(db); }
/**
* @brief accepted flags for the second argument of serialise()
*/
enum serialise_flags
{
NO_FLAGS = 0,
NO_COPY
};
/**
* @brief struct to store the output of serialise()
*/
struct serialise_data
{
unsigned char* data;
int64 db_size;
};
/**
* @brief serialise a database
* @param schema schema to serialise. e.g., "main", "temp", etc.
* @param flags flags to alter the serialisation
* @returns struct to pass to deserialise()
*/
serialise_data serialise(std::string schema, serialise_flags flags)
{
serialise_data data;
data.data = sqlite3_serialize(db, schema.c_str(), (int64*)&data.db_size, flags);
return data;
}
enum deserialise_flags
{
N0_FLAGS = 0,
FREE_ON_CLOSE,
RESIZABLE,
READONLY
};
/**
* @brief deserialise a database
* @param schema schema to serialise, e.g., "main", "temp"
* @param data struct with all of the data to be deserialised
* @param flags flags to alter the serialisation
* @returns result code
*/
int deserialise(std::string schema, serialise_data data, deserialise_flags flags) { return sqlite3_deserialize(db, schema.c_str(), data.data, sizeof(data.data), data.db_size, (unsigned int)flags); }
static bool is_compatible() { return ("3.28.0" == (std::string)SQLITE_VERSION); }
sqlite3_cpp(const std::string database = "")
{
sqlite3_initialize();
if (database != "") { open(database); }
}
~sqlite3_cpp()
{
if (is_open) { close(); }
sqlite3_shutdown();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment