266 lines
8.5 KiB
C++
266 lines
8.5 KiB
C++
#ifndef SQLITEPP
|
|
#define SQLITEPP
|
|
|
|
#include <iostream>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <sqlite3.h>
|
|
|
|
#else
|
|
|
|
#include "sqlite3.h"
|
|
#include <codecvt>
|
|
#include <shlobj.h>
|
|
|
|
std::string _w_2_8( const std::wstring &wstring ) {
|
|
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv;
|
|
return wconv.to_bytes( wstring );
|
|
}
|
|
|
|
std::wstring _8_2_w( const std::string &utf8 ) {
|
|
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv;
|
|
return wconv.from_bytes( utf8 );
|
|
}
|
|
|
|
#endif
|
|
|
|
//TODO maybe split this into hpp/cpp
|
|
|
|
namespace SQLite {
|
|
|
|
constexpr size_t OPEN_READONLY = 0x00000001;
|
|
constexpr size_t OPEN_READWRITE = 0x00000002;
|
|
constexpr size_t OPEN_CREATE = 0x00000004;
|
|
constexpr size_t OPEN_URI = 0x00000040;
|
|
constexpr size_t OPEN_MEMORY = 0x00000080;
|
|
constexpr size_t OPEN_NOMUTEX = 0x00008000;
|
|
constexpr size_t OPEN_FULLMUTEX = 0x00010000;
|
|
constexpr size_t OPEN_SHAREDCACHE = 0x00020000;
|
|
constexpr size_t OPEN_PRIVATECACHE = 0x00040000;
|
|
|
|
class Database {
|
|
public:
|
|
Database() {}
|
|
|
|
Database( const std::string &file, size_t options ) {
|
|
open( file, options );
|
|
}
|
|
|
|
#ifdef WIN32
|
|
Database( const std::wstring &file, size_t options ) {
|
|
open( file, options );
|
|
}
|
|
#endif
|
|
|
|
~Database() {
|
|
close();
|
|
}
|
|
|
|
void open( const std::string &file, size_t options ) {
|
|
if ( sqlite3_open_v2( file.c_str(), &db, options, nullptr ) ) {
|
|
throw std::runtime_error( "Could not open database " + file );
|
|
}
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void open( const std::wstring &file, size_t options ) {
|
|
if ( sqlite3_open_v2( _w_2_8( file ).c_str(), &db, options,
|
|
nullptr ) ) {
|
|
throw std::runtime_error( "Could not open database " +
|
|
_w_2_8( file ) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// execute command without output
|
|
void exec( const std::string &command ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, command.c_str(), nullptr, nullptr, &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + command +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void exec( const std::wstring &command ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), nullptr, nullptr,
|
|
&errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
#endif
|
|
|
|
// execute command that should only output 1 result
|
|
void exec( const std::string &command, std::string &output ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, command.c_str(), insert_val_s,
|
|
static_cast< void * >( &output ), &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + command +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void exec( const std::wstring &command, std::wstring &output ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_val_ws,
|
|
static_cast< void * >( &output ), &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
#endif
|
|
|
|
// didn't work with set for some reason, so only vector is allowed
|
|
void exec( const std::string &command,
|
|
std::vector< std::unordered_map< std::string, std::string > >
|
|
&object ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, command.c_str(), insert_col_val,
|
|
static_cast< void * >( &object ), &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + command +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
|
|
#ifdef WIN32
|
|
// didn't work with set for some reason, so only vector is allowed
|
|
void exec( const std::wstring &command,
|
|
std::vector< std::unordered_map< std::wstring, std::wstring > >
|
|
&object ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_col_val_w,
|
|
static_cast< void * >( &object ), &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
#endif
|
|
|
|
// execute command with output and store output in object (store only
|
|
// values) object can by any container as long as it's template is
|
|
// 'std::string'
|
|
template < typename V > void exec( const std::string &command, V &object ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, command.c_str(), insert_val< V >,
|
|
static_cast< void * >( &object ), &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + command +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
|
|
#ifdef WIN32
|
|
template < typename V >
|
|
void exec( const std::wstring &command, V &object ) {
|
|
char *errMsg = nullptr;
|
|
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_val_w< V >,
|
|
static_cast< void * >( &object ), &errMsg );
|
|
if ( rc )
|
|
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
|
"\" resulted in an error:\n" + errMsg );
|
|
sqlite3_free( errMsg );
|
|
}
|
|
#endif
|
|
|
|
void close() {
|
|
sqlite3_close( db );
|
|
}
|
|
|
|
int64_t lastRowID() {
|
|
return sqlite3_last_insert_rowid(db);
|
|
}
|
|
|
|
private:
|
|
sqlite3 *db;
|
|
|
|
static int insert_col_val( void *d, int argc, char **argv,
|
|
char **azColName ) {
|
|
auto &data = *static_cast<
|
|
std::vector< std::unordered_map< std::string, std::string > > * >(
|
|
d );
|
|
std::unordered_map< std::string, std::string > buffer;
|
|
for ( int i = 0; i < argc; i++ ) {
|
|
// insert all columns and values into 'data'
|
|
buffer[azColName[i]] = argv[i] ? argv[i] : "";
|
|
}
|
|
data.insert( data.end(), std::move( buffer ) );
|
|
return 0;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
static int insert_col_val_w( void *d, int argc, char **argv,
|
|
char **azColName ) {
|
|
auto &data = *static_cast<
|
|
std::vector< std::unordered_map< std::wstring, std::wstring > > * >(
|
|
d );
|
|
std::unordered_map< std::wstring, std::wstring > buffer;
|
|
for ( int i = 0; i < argc; i++ ) {
|
|
// insert all columns and values into 'data'
|
|
buffer[_8_2_w( azColName[i] )] = argv[i] ? _8_2_w( argv[i] ) : L"";
|
|
}
|
|
data.insert( data.end(), std::move( buffer ) );
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int insert_val_s( void *d, int argc, char **argv,
|
|
char ** /*UNUSED*/ ) {
|
|
auto &data = *static_cast< std::string * >( d );
|
|
if ( argc > 0 ) {
|
|
data = argv[0] ? argv[0] : "";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
static int insert_val_ws( void *d, int argc, char **argv,
|
|
char ** /*UNUSED*/ ) {
|
|
auto &data = *static_cast< std::wstring * >( d );
|
|
if ( argc > 0 ) {
|
|
data = argv[0] ? _8_2_w( argv[0] ) : L"";
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
template < typename V >
|
|
static int insert_val( void *d, int argc, char **argv,
|
|
char ** /*UNUSED*/ ) {
|
|
auto &data = *static_cast< V * >( d );
|
|
for ( int i = 0; i < argc; i++ ) {
|
|
// insert all values into 'data'
|
|
data.insert( data.end(), argv[i] ? argv[i] : "" );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
template < typename V >
|
|
static int insert_val_w( void *d, int argc, char **argv,
|
|
char ** /*UNUSED*/ ) {
|
|
auto &data = *static_cast< V * >( d );
|
|
for ( int i = 0; i < argc; i++ ) {
|
|
// insert all values into 'data'
|
|
data.insert( data.end(), argv[i] ? _8_2_w( argv[i] ) : L"" );
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
};
|
|
|
|
} // namespace SQLite
|
|
|
|
#endif
|