Savarese Software Research Corporation
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

Savarese Software Research Corporation
Copyright © 2006-2011 Savarese Software Research Corporation. All rights reserved.