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 * http://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 PreparedStatement & bind(const unsigned int index, const long value) 00131 SSRC_DECL_THROW(DatabaseException) 00132 { 00133 if(SQLite3::sqlite3_bind_int64(_statement.get(), index, value) 00134 != SQLITE_OK) 00135 throw DatabaseException(_statement); 00136 return *this; 00137 } 00138 00139 PreparedStatement & bind(const unsigned int index, const unsigned long value) 00140 SSRC_DECL_THROW(DatabaseException) 00141 { 00142 return bind(index, static_cast<long>(value)); 00143 } 00144 00145 PreparedStatement & bind(const unsigned int index, const char * const value, 00146 const unsigned int bytes, 00147 const BindPolicy policy = BindTransient) 00148 SSRC_DECL_THROW(DatabaseException) 00149 { 00150 if(SQLite3::sqlite3_bind_text(_statement.get(), index, value, 00151 bytes, 00152 (policy == BindTransient ? 00153 SQLITE_TRANSIENT : SQLITE_STATIC))) 00154 throw DatabaseException(_statement); 00155 return *this; 00156 } 00157 00158 PreparedStatement & bind(const unsigned int index, const char * const value, 00159 const BindPolicy policy = BindTransient) 00160 SSRC_DECL_THROW(DatabaseException) 00161 { 00162 return bind(index, value, std::strlen(value), policy); 00163 } 00164 00165 PreparedStatement & bind(const unsigned int index, const string & value, 00166 const BindPolicy policy = BindTransient) 00167 SSRC_DECL_THROW(DatabaseException) 00168 { 00169 return bind(index, value.c_str(), value.size(), policy); 00170 } 00171 00172 PreparedStatement & bind(const unsigned int index, const void *value, 00173 const unsigned int bytes, 00174 const BindPolicy policy = BindTransient) 00175 SSRC_DECL_THROW(DatabaseException) 00176 { 00177 if(SQLite3::sqlite3_bind_blob(_statement.get(), index, value, bytes, 00178 (policy == BindTransient ? 00179 SQLITE_TRANSIENT : SQLITE_STATIC))) 00180 throw DatabaseException(_statement); 00181 return *this; 00182 } 00183 00184 PreparedStatement & bind(const unsigned int index, const blob_type & blob, 00185 const BindPolicy policy = BindTransient) 00186 SSRC_DECL_THROW(DatabaseException) 00187 { 00188 return bind(index, blob.first, blob.second, policy); 00189 } 00190 00191 /* 00192 * We allow client code to implement custom bind functions 00193 * by defining a function called bind_column with the following 00194 * signature: 00195 * PreparedStatement & bind_column(PreparedStatement & statement, 00196 * const unsigned int index, 00197 * const T & t); 00198 */ 00199 template<typename T> 00200 PreparedStatement & bind(const unsigned int index, const T & t) 00201 SSRC_DECL_THROW(DatabaseException) 00202 { 00203 return bind_column(*this, index, t); 00204 } 00205 00206 PreparedStatement & unbind(const unsigned int index) 00207 SSRC_DECL_THROW(DatabaseException) 00208 { 00209 if(SQLite3::sqlite3_bind_null(_statement.get(), index) != SQLITE_OK) 00210 throw DatabaseException(_statement); 00211 return *this; 00212 } 00213 00214 PreparedStatement & unbind() SSRC_DECL_THROW(DatabaseException) { 00215 if(SQLite3::sqlite3_clear_bindings(_statement.get()) != SQLITE_OK) 00216 throw DatabaseException(_statement); 00217 return *this; 00218 } 00219 00220 void reset() SSRC_DECL_THROW(DatabaseException) { 00221 if(SQLite3::sqlite3_reset(_statement.get()) != SQLITE_OK) 00222 throw DatabaseException(_statement); 00223 } 00224 00225 QueryResult execute() SSRC_DECL_THROW(DatabaseException) { 00226 int result; 00227 00228 result = detail::step(_statement); 00229 00230 if(result == SQLITE_DONE) { 00231 return 00232 QueryResult(SQLite3::sqlite3_changes(SQLite3::sqlite3_db_handle(_statement.get()))); 00233 } 00234 00235 if(result != SQLITE_ROW) 00236 throw DatabaseException(_statement); 00237 00238 return QueryResult(result_set_ptr(new ResultSet(_statement))); 00239 } 00240 00241 template<typename functor> 00242 unsigned int for_each(const functor & apply) SSRC_DECL_THROW(DatabaseException) { 00243 QueryResult && result = execute(); 00244 00245 if(result.result_set) 00246 return result.result_set->for_each(apply); 00247 00248 return 0; 00249 } 00250 00251 // TODO: Move to ResultSetMetaData? Add other metadata functions. 00252 unsigned int count_columns() { 00253 return SQLite3::sqlite3_column_count(_statement.get()); 00254 } 00255 00256 string column_name(const unsigned int index) { 00257 const char *name = SQLite3::sqlite3_column_name(_statement.get(), index); 00258 00259 return (name ? name : string()); 00260 } 00261 00262 private: 00263 00264 /* _bindp is a support function for compile-time expansion of bind 00265 sequence required by bindp. It has the effect of producing 00266 bind(1,p1).bind(2,p2).bind(3,p3) ... 00267 */ 00268 00269 template<const unsigned int index, typename T> 00270 PreparedStatement & _bindp(const T & t) 00271 SSRC_DECL_THROW(DatabaseException) 00272 { 00273 return bind(index, t); 00274 } 00275 00276 template<const unsigned int index, typename T, typename... P> 00277 PreparedStatement & 00278 _bindp(const T & t, const P & ...p) 00279 SSRC_DECL_THROW(DatabaseException) 00280 { 00281 return bind(index, t)._bindp<index + 1>(p...); 00282 } 00283 00284 public: 00285 00286 template<typename... P> 00287 PreparedStatement & bindp(const P & ...p) SSRC_DECL_THROW(DatabaseException) { 00288 return _bindp<1>(p...); 00289 } 00290 00291 template<typename... P> 00292 QueryResult execute(const P & ...p) SSRC_DECL_THROW(DatabaseException) { 00293 return bindp(p...).execute(); 00294 } 00295 00296 template<typename... P, typename functor> 00297 unsigned int for_each(const functor & apply, const P & ...p) 00298 SSRC_DECL_THROW(DatabaseException) 00299 { 00300 return bindp(p...).for_each(apply); 00301 } 00302 }; 00303 00304 typedef SSRC_UNIQUE_PTR<PreparedStatement> prepared_statement_ptr; 00305 00306 class Database { 00307 00308 sqlite3_ptr _database; 00309 prepared_statement_ptr _begin_transaction; 00310 prepared_statement_ptr _rollback_transaction; 00311 prepared_statement_ptr _end_transaction; 00312 00313 public: 00314 00315 explicit 00316 Database(const string & db_name = ":memory:") SSRC_DECL_THROW(DatabaseException) : 00317 _database(db_name) 00318 { 00319 if(_database.init_error()) 00320 throw DatabaseException("database init error"); 00321 00322 _begin_transaction = prepare("BEGIN"); 00323 _rollback_transaction = prepare("ROLLBACK"); 00324 _end_transaction = prepare("END"); 00325 } 00326 00327 prepared_statement_ptr prepare(const string & statement) 00328 SSRC_DECL_THROW(DatabaseException) 00329 { 00330 return prepared_statement_ptr(new PreparedStatement(_database, statement)); 00331 } 00332 00333 void execute(const string & statement) 00334 SSRC_DECL_THROW(DatabaseException) 00335 { 00336 char *err = 0; 00337 00338 if(SQLite3::sqlite3_exec(_database.get(), statement.c_str(), 0, 0, &err) 00339 != SQLITE_OK && err != 0) 00340 { 00341 string error(err); 00342 SQLite3::sqlite3_free(err); 00343 throw DatabaseException(error); 00344 } 00345 } 00346 00347 bool auto_commit() { 00348 return SQLite3::sqlite3_get_autocommit(_database.get()); 00349 } 00350 00351 void begin_transaction() SSRC_DECL_THROW(DatabaseException) { 00352 _begin_transaction->execute(); 00353 } 00354 00355 void rollback_transaction() SSRC_DECL_THROW(DatabaseException) { 00356 _rollback_transaction->execute(); 00357 } 00358 00359 void end_transaction() SSRC_DECL_THROW(DatabaseException) { 00360 _end_transaction->execute(); 00361 } 00362 }; 00363 00364 __END_NS_SSRC_WSPR_DATABASE 00365 00366 #endif
Copyright © 2006-2010 Savarese Software Research Corporation. All rights reserved.
Copyright © 2011 Savarese Software Research Corporation. All rights reserved