Database.h
Go to the documentation of this file.
00001 /* 00002 * Copyright 2006-2009 Savarese Software Research Corporation 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * https://www.savarese.com/software/ApacheLicense-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00022 #ifndef __SSRC_WSPR_DATABASE_DATABASE_H 00023 #define __SSRC_WSPR_DATABASE_DATABASE_H 00024 00025 #include <ssrc/wispers/database/types.h> 00026 #include <sstream> 00027 #include <cstring> 00028 00029 // TODO: Add support for handling SQLITE_BUSY. Currently we throw! 00030 __BEGIN_NS_SSRC_WSPR_DATABASE 00031 00032 struct QueryResult { 00033 unsigned int changes; 00034 result_set_ptr result_set; 00035 00036 explicit QueryResult(const unsigned int changes = 0) : 00037 changes(changes), result_set() 00038 { } 00039 00040 explicit QueryResult(const result_set_ptr & result_set) : 00041 changes(0), result_set(result_set) 00042 { } 00043 }; 00044 00045 // Forward declaration; 00046 00047 class PreparedStatement { 00048 friend class Database; 00049 00050 sqlite3_stmt_ptr _statement; 00051 00052 PreparedStatement(sqlite3_ptr & db, const string & statement) : 00053 _statement(detail::sqlite3_stmt_initializer(db, statement), 00054 detail::sqlite3_stmt_init()) 00055 { 00056 if(_statement.init_error()) 00057 throw DatabaseException(_statement); 00058 } 00059 00060 public: 00061 00062 enum BindPolicy { BindTransient, BindStatic }; 00063 00064 bool expired() { 00065 return SQLite3::sqlite3_expired(_statement.get()); 00066 } 00067 00068 unsigned int count_parameters() { 00069 return SQLite3::sqlite3_bind_parameter_count(_statement.get()); 00070 } 00071 00072 PreparedStatement & bind(const unsigned int index, const double value) 00073 SSRC_DECL_THROW(DatabaseException) 00074 { 00075 if(SQLite3::sqlite3_bind_double(_statement.get(), index, value) 00076 != SQLITE_OK) 00077 throw DatabaseException(_statement); 00078 return *this; 00079 } 00080 00081 PreparedStatement & bind(const unsigned int index, const int value) 00082 SSRC_DECL_THROW(DatabaseException) 00083 { 00084 if(SQLite3::sqlite3_bind_int(_statement.get(), index, value) != SQLITE_OK) 00085 throw DatabaseException(_statement); 00086 return *this; 00087 } 00088 00089 PreparedStatement & bind(const unsigned int index, const unsigned int value) 00090 SSRC_DECL_THROW(DatabaseException) 00091 { 00092 return bind(index, static_cast<int>(value)); 00093 } 00094 00095 PreparedStatement & bind(const unsigned int index, const std::int16_t value) 00096 SSRC_DECL_THROW(DatabaseException) 00097 { 00098 return bind(index, static_cast<int>(value)); 00099 } 00100 00101 PreparedStatement & bind(const unsigned int index, const std::uint16_t value) 00102 SSRC_DECL_THROW(DatabaseException) 00103 { 00104 return bind(index, static_cast<int>(value)); 00105 } 00106 00107 PreparedStatement & bind(const unsigned int index, const bool value) 00108 SSRC_DECL_THROW(DatabaseException) 00109 { 00110 if(SQLite3::sqlite3_bind_int(_statement.get(), index, value) != SQLITE_OK) 00111 throw DatabaseException(_statement); 00112 return *this; 00113 } 00114 00115 PreparedStatement & bind(const unsigned int index, const std::int64_t value) 00116 SSRC_DECL_THROW(DatabaseException) 00117 { 00118 if(SQLite3::sqlite3_bind_int64(_statement.get(), index, value) 00119 != SQLITE_OK) 00120 throw DatabaseException(_statement); 00121 return *this; 00122 } 00123 00124 PreparedStatement & bind(const unsigned int index, const std::uint64_t value) 00125 SSRC_DECL_THROW(DatabaseException) 00126 { 00127 return bind(index, static_cast<std::int64_t>(value)); 00128 } 00129 00130 #if (LONG_MAX == INT_MAX) 00131 PreparedStatement & bind(const unsigned int index, const long value) 00132 SSRC_DECL_THROW(DatabaseException) 00133 { 00134 if(SQLite3::sqlite3_bind_int64(_statement.get(), index, value) 00135 != SQLITE_OK) 00136 throw DatabaseException(_statement); 00137 return *this; 00138 } 00139 00140 PreparedStatement & bind(const unsigned int index, const unsigned long value) 00141 SSRC_DECL_THROW(DatabaseException) 00142 { 00143 return bind(index, static_cast<long>(value)); 00144 } 00145 #endif 00146 00147 PreparedStatement & bind(const unsigned int index, const char * const value, 00148 const unsigned int bytes, 00149 const BindPolicy policy = BindTransient) 00150 SSRC_DECL_THROW(DatabaseException) 00151 { 00152 if(SQLite3::sqlite3_bind_text(_statement.get(), index, value, 00153 bytes, 00154 (policy == BindTransient ? 00155 SQLITE_TRANSIENT : SQLITE_STATIC))) 00156 throw DatabaseException(_statement); 00157 return *this; 00158 } 00159 00160 PreparedStatement & bind(const unsigned int index, const char * const value, 00161 const BindPolicy policy = BindTransient) 00162 SSRC_DECL_THROW(DatabaseException) 00163 { 00164 return bind(index, value, std::strlen(value), policy); 00165 } 00166 00167 PreparedStatement & bind(const unsigned int index, const string & value, 00168 const BindPolicy policy = BindTransient) 00169 SSRC_DECL_THROW(DatabaseException) 00170 { 00171 return bind(index, value.c_str(), value.size(), policy); 00172 } 00173 00174 PreparedStatement & bind(const unsigned int index, const void *value, 00175 const unsigned int bytes, 00176 const BindPolicy policy = BindTransient) 00177 SSRC_DECL_THROW(DatabaseException) 00178 { 00179 if(SQLite3::sqlite3_bind_blob(_statement.get(), index, value, bytes, 00180 (policy == BindTransient ? 00181 SQLITE_TRANSIENT : SQLITE_STATIC))) 00182 throw DatabaseException(_statement); 00183 return *this; 00184 } 00185 00186 PreparedStatement & bind(const unsigned int index, const blob_type & blob, 00187 const BindPolicy policy = BindTransient) 00188 SSRC_DECL_THROW(DatabaseException) 00189 { 00190 return bind(index, blob.first, blob.second, policy); 00191 } 00192 00193 /* 00194 * We allow client code to implement custom bind functions 00195 * by defining a function called bind_column with the following 00196 * signature: 00197 * PreparedStatement & bind_column(PreparedStatement & statement, 00198 * const unsigned int index, 00199 * const T & t); 00200 */ 00201 template<typename T> 00202 PreparedStatement & bind(const unsigned int index, const T & t) 00203 SSRC_DECL_THROW(DatabaseException) 00204 { 00205 return bind_column(*this, index, t); 00206 } 00207 00208 PreparedStatement & unbind(const unsigned int index) 00209 SSRC_DECL_THROW(DatabaseException) 00210 { 00211 if(SQLite3::sqlite3_bind_null(_statement.get(), index) != SQLITE_OK) 00212 throw DatabaseException(_statement); 00213 return *this; 00214 } 00215 00216 PreparedStatement & unbind() SSRC_DECL_THROW(DatabaseException) { 00217 if(SQLite3::sqlite3_clear_bindings(_statement.get()) != SQLITE_OK) 00218 throw DatabaseException(_statement); 00219 return *this; 00220 } 00221 00222 void reset() SSRC_DECL_THROW(DatabaseException) { 00223 if(SQLite3::sqlite3_reset(_statement.get()) != SQLITE_OK) 00224 throw DatabaseException(_statement); 00225 } 00226 00227 QueryResult execute() SSRC_DECL_THROW(DatabaseException) { 00228 int result; 00229 00230 result = detail::step(_statement); 00231 00232 if(result == SQLITE_DONE) { 00233 return 00234 QueryResult(SQLite3::sqlite3_changes(SQLite3::sqlite3_db_handle(_statement.get()))); 00235 } 00236 00237 if(result != SQLITE_ROW) 00238 throw DatabaseException(_statement); 00239 00240 return QueryResult(result_set_ptr(new ResultSet(_statement))); 00241 } 00242 00243 template<typename functor> 00244 unsigned int for_each(const functor & apply) SSRC_DECL_THROW(DatabaseException) { 00245 QueryResult && result = execute(); 00246 00247 if(result.result_set) 00248 return result.result_set->for_each(apply); 00249 00250 return 0; 00251 } 00252 00253 // TODO: Move to ResultSetMetaData? Add other metadata functions. 00254 unsigned int count_columns() { 00255 return SQLite3::sqlite3_column_count(_statement.get()); 00256 } 00257 00258 string column_name(const unsigned int index) { 00259 const char *name = SQLite3::sqlite3_column_name(_statement.get(), index); 00260 00261 return (name ? name : string()); 00262 } 00263 00264 private: 00265 00266 /* _bindp is a support function for compile-time expansion of bind 00267 sequence required by bindp. It has the effect of producing 00268 bind(1,p1).bind(2,p2).bind(3,p3) ... 00269 */ 00270 00271 template<const unsigned int index, typename T> 00272 PreparedStatement & _bindp(const T & t) 00273 SSRC_DECL_THROW(DatabaseException) 00274 { 00275 return bind(index, t); 00276 } 00277 00278 template<const unsigned int index, typename T, typename... P> 00279 PreparedStatement & 00280 _bindp(const T & t, const P & ...p) 00281 SSRC_DECL_THROW(DatabaseException) 00282 { 00283 return bind(index, t)._bindp<index + 1>(p...); 00284 } 00285 00286 public: 00287 00288 template<typename... P> 00289 PreparedStatement & bindp(const P & ...p) SSRC_DECL_THROW(DatabaseException) { 00290 return _bindp<1>(p...); 00291 } 00292 00293 template<typename... P> 00294 QueryResult execute(const P & ...p) SSRC_DECL_THROW(DatabaseException) { 00295 return bindp(p...).execute(); 00296 } 00297 00298 template<typename... P, typename functor> 00299 unsigned int for_each(const functor & apply, const P & ...p) 00300 SSRC_DECL_THROW(DatabaseException) 00301 { 00302 return bindp(p...).for_each(apply); 00303 } 00304 }; 00305 00306 typedef SSRC_UNIQUE_PTR<PreparedStatement> prepared_statement_ptr; 00307 00308 class Database { 00309 00310 sqlite3_ptr _database; 00311 prepared_statement_ptr _begin_transaction; 00312 prepared_statement_ptr _rollback_transaction; 00313 prepared_statement_ptr _end_transaction; 00314 00315 public: 00316 00317 explicit 00318 Database(const string & db_name = ":memory:") SSRC_DECL_THROW(DatabaseException) : 00319 _database(db_name) 00320 { 00321 if(_database.init_error()) 00322 throw DatabaseException("database init error"); 00323 00324 _begin_transaction = prepare("BEGIN"); 00325 _rollback_transaction = prepare("ROLLBACK"); 00326 _end_transaction = prepare("END"); 00327 } 00328 00329 prepared_statement_ptr prepare(const string & statement) 00330 SSRC_DECL_THROW(DatabaseException) 00331 { 00332 return prepared_statement_ptr(new PreparedStatement(_database, statement)); 00333 } 00334 00335 void execute(const string & statement) 00336 SSRC_DECL_THROW(DatabaseException) 00337 { 00338 char *err = 0; 00339 00340 if(SQLite3::sqlite3_exec(_database.get(), statement.c_str(), 0, 0, &err) 00341 != SQLITE_OK && err != 0) 00342 { 00343 string error(err); 00344 SQLite3::sqlite3_free(err); 00345 throw DatabaseException(error); 00346 } 00347 } 00348 00349 bool auto_commit() { 00350 return SQLite3::sqlite3_get_autocommit(_database.get()); 00351 } 00352 00353 void begin_transaction() SSRC_DECL_THROW(DatabaseException) { 00354 _begin_transaction->execute(); 00355 } 00356 00357 void rollback_transaction() SSRC_DECL_THROW(DatabaseException) { 00358 _rollback_transaction->execute(); 00359 } 00360 00361 void end_transaction() SSRC_DECL_THROW(DatabaseException) { 00362 _end_transaction->execute(); 00363 } 00364 }; 00365 00366 __END_NS_SSRC_WSPR_DATABASE 00367 00368 #endif
Copyright © 2006-2011 Savarese Software Research Corporation. All rights reserved.