Merge branch 'devel'
[aoi.git] / src / sqlite3.hxx
blob062e20b21802d6119fe57639692d2b9be9b05d4a
1 /*
2 Copyright 2013 Karel Matas
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 /*! \file sqlite3.hxx
20 * \date 2013/06/10
23 #ifndef _SQLITE3_HXX
24 #define _SQLITE3_HXX
26 #include "3rdparty/sqlite3.h"
27 #include <exception>
28 #include <vector>
29 #include <string>
30 #include <sstream>
31 #include <cstring>
32 #include <stdexcept>
34 using std::vector;
35 using std::string;
37 namespace SQLite3 {
39 //////////////////////////////////////////////////////////////////////////
40 // EXCEPTIONS
42 class CantOpenDatabase : public std::exception {
43 private:
44 string msg_;
45 public:
46 CantOpenDatabase(const string &filename): msg_(filename) {};
47 const char *what() const noexcept {return msg_.c_str();};
51 class DatabaseError : public std::exception {
52 private:
53 string msg_;
54 string query_;
55 public:
56 DatabaseError(const string &msg, const string &query)
57 : msg_(msg.c_str()), query_(query){};
58 const char *what() const noexcept {return msg_.c_str();};
59 //! Returns details about executed query.
60 const char *query() const {return query_.c_str();};
64 //////////////////////////////////////////////////////////////////////////
65 // FUNCTIONS
67 /*!
68 * Replaces ' with '' and " with \".
70 inline string escape ( const char *s )
72 if ( !strlen(s) )
73 return "";
75 std::stringstream ss;
76 for ( size_t i=0; i<strlen(s); i++ ){
77 ss << s[i];
78 if ( s[i] == '\'' )
79 ss << "'";
80 else if ( s[i] == '"' )
81 ss << "\"";
83 return ss.str();
86 // overloaded inline function must be placed after base inline function
87 inline string escape ( const string &s ){ return escape(s.c_str()); }
90 //////////////////////////////////////////////////////////////////////////
91 // class SQLite3
93 class SQLite3
95 private:
96 sqlite3 *db_ = nullptr;
97 vector<string> data_ = {};
98 vector<string> columns_ = {};
100 public:
102 * Constructor. Calls open().
103 * \param filename Name of the sqlite3 database file.
105 SQLite3 ( const char *filename ) { open( filename ); }
107 //! Destructor. Calls close().
108 ~SQLite3 () { close(); }
111 * Opens sqlite3 database.
112 * \exception CantOpenDatabase
113 * \param filename NAme of the sqlite3 database.
115 void open( const char *filename ){
116 if( sqlite3_open(filename, &db_) != SQLITE_OK ) {
117 close();
118 throw CantOpenDatabase(filename);
122 //! Closes database.
123 void close() { sqlite3_close(db_); }
125 //! sqlite3_exec calls this function for each row
126 static int callback(void *parent, int argc, char **argv, char **column) {
127 // put column names into vector<string> columns_
128 if ( ((SQLite3*)parent)->data_.empty() ) {
129 for( int i=0; i<argc; i++ )
130 ((SQLite3*)parent)->columns_.push_back( column[i] );
132 // put row data into vector<string> data_
133 for( int i=0; i<argc; i++ )
134 ((SQLite3*)parent)->data_.push_back( argv[i] ? argv[i] : "" );
135 return 0;
138 //! Returns all data (same data as query() ).
139 inline vector<string> data () const { return data_; };
141 //! Returns column names
142 inline vector<string> columns () const { return columns_; };
144 //! Returns # of returned rows ( data().size()/columns().size() )
145 inline size_t result_rows () const
146 { return data_.empty() ? 0:data_.size()/columns_.size(); };
149 * Executes SQLite query.
150 * Query can contain more commands separated with semicolon.
151 * \exception CantOpenDatabase
152 * \exception DatabaseError
153 * \param query SQLite query
154 * \return Vector of strings with query results. Order of elements is: row1_col1, row1_col2, .. row1_colN, row2_col1, .. row2_colN, .. , rowM_col1, .., rowM_colN
155 * \sa script()
157 vector<string> query( const char *query ){
158 if ( !db_ )
159 throw CantOpenDatabase("SQLite3::query(): db_ is NULL");
160 char *err = nullptr;
161 if ( !data_.empty() ) data_.clear();
162 if ( !columns_.empty() ) columns_.clear();
163 int rc = sqlite3_exec( db_, query, SQLite3::callback, (void*)this, &err);
164 string s(err?err:"");
165 sqlite3_free(err);
166 if ( rc != SQLITE_OK )
167 throw DatabaseError(s,query);
168 return data_;
172 * Loads and executes file containing SQLite script.
173 * \exception std::runtime_error
174 * \param path path to script file
175 * \sa query()
177 void script ( const char *path ){
178 std::ifstream f(path);
179 if ( f.is_open() ){
180 f.seekg( 0, f.end );
181 size_t size = f.tellg();
182 f.seekg( 0, f.beg );
183 if ( size > 0 ){
184 char buff[ size+1 ];
185 f.read( buff, size );
186 f.close();
187 query( buff );
189 else
190 throw std::runtime_error("File has zero length: " + string(path));
192 else
193 throw std::runtime_error("Can't open file: " + string(path));
197 } // namespace sqlite3
198 #endif //_SQLITE3_HXX