#ifndef SQLITEPP #define SQLITEPP #include #include #include #ifndef WIN32 #include #else #include "sqlite-amalgamation/sqlite3.h" #include #include 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*/ ) { if ( argc > 0 ) *static_cast< std::string * >( d ) = argv[0] ? argv[0] : ""; return 0; } #ifdef WIN32 static int insert_val_ws( void *d, int argc, char **argv, char ** /*UNUSED*/ ) { if ( argc > 0 ) { *static_cast< std::wstring * >( d ) = 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