libsqlite3x
2007.10.18
|
00001 /* 00002 Copyright (C) 2004-2005 Cory Nelson 00003 Copyright (C) 2006 stephan beal 00004 00005 This software is provided 'as-is', without any express or implied 00006 warranty. In no event will the authors be held liable for any damages 00007 arising from the use of this software. 00008 00009 Permission is granted to anyone to use this software for any purpose, 00010 including commercial applications, and to alter it and redistribute it 00011 freely, subject to the following restrictions: 00012 00013 1. The origin of this software must not be misrepresented; you must not 00014 claim that you wrote the original software. If you use this software 00015 in a product, an acknowledgment in the product documentation would be 00016 appreciated but is not required. 00017 2. Altered source versions must be plainly marked as such, and must not be 00018 misrepresented as being the original software. 00019 3. This notice may not be removed or altered from any source distribution. 00020 00021 Changes made by stephan@s11n.net: 00022 00023 - Changed ~sqlite3_connection() to use this->close() instead of sqlite3_close(). 00024 00025 */ 00026 00027 #include <sqlite3.h> 00028 #include "sqlite3x.hpp" 00029 00030 #include <sstream> 00031 #include <vector> 00032 namespace sqlite3x { 00033 00034 bool rc_is_okay( int rc ) 00035 { 00036 return ((SQLITE_DONE==rc) || (SQLITE_OK==rc) || (SQLITE_ROW==rc)); 00037 } 00038 00039 sqlite3_connection::sqlite3_connection() : m_db(NULL), m_name() {} 00040 00041 sqlite3_connection::sqlite3_connection(std::string const & dbn) 00042 : m_db(NULL), m_name(dbn) 00043 { 00044 this->open(dbn); 00045 } 00046 00047 #if SQLITE3X_USE_WCHAR 00048 sqlite3_connection::sqlite3_connection(const wchar_t *dbn) : m_db(NULL), m_name() { this->open(dbn); } 00049 #endif 00050 00051 sqlite3_connection::sqlite3_connection( sqlite3 * dbh ) 00052 : m_db(0), m_name() 00053 { 00054 if( ! dbh ) 00055 { 00056 throw database_error( "sqlite3_connection(sqlite3*) ctor was passed a null db handle." ); 00057 } 00058 this->take( dbh ); 00059 } 00060 00061 sqlite3_connection::~sqlite3_connection() 00062 { 00063 try 00064 { 00065 this->close(); 00066 } 00067 catch(...) 00068 { 00069 // ignored for the sake of a no-throw dtor. 00070 } 00071 } 00072 00073 00074 void sqlite3_connection::take( sqlite3 * dbh ) 00075 { 00076 00077 if( this->m_db == dbh ) return; 00078 try 00079 { 00080 if( this->m_db || (!dbh) ) 00081 { 00082 this->close(); 00083 } 00084 this->m_db = dbh; 00085 if( dbh ) 00086 { 00087 this->on_open(); 00088 } 00089 } 00090 catch( ... ) 00091 { 00092 this->m_db = dbh; 00093 throw; 00094 } 00095 } 00096 00097 sqlite3 * sqlite3_connection::take() throw() 00098 { 00099 sqlite3 * ret = this->m_db; 00100 this->m_db = 0; 00101 return ret; 00102 } 00103 00104 sqlite3 * sqlite3_connection::db() const 00105 { 00106 return this->m_db; 00107 } 00108 00109 std::string sqlite3_connection::name() const 00110 { 00111 return this->m_name; 00112 } 00113 00114 std::string sqlite3_connection::errormsg() const 00115 { 00116 char const * m = this->m_db ? sqlite3_errmsg(this->m_db) : ""; 00117 return m ? m : ""; 00118 } 00119 00120 void sqlite3_connection::on_open() 00121 { 00122 return; 00123 } 00124 void sqlite3_connection::open( char const * db) { 00125 this->close(); 00126 this->m_name = db ? db : ""; 00127 if(sqlite3_open(db, &this->m_db)!=SQLITE_OK) 00128 throw database_error("unable to open database %s", db ? db : "<null>"); 00129 try 00130 { 00131 // Potential bug: when open() is called from 00132 // the ctor of subclasses as a result of 00133 // calling the parent class ctor, the subclass 00134 // part of the subclass may not be complete, 00135 // and a less derived on_open() may 00136 // potentially be called. ??? 00137 this->on_open(); 00138 } 00139 catch(...) 00140 { 00141 try { this->close(); } 00142 catch(...) { /* ignore */ } 00143 throw; 00144 } 00145 } 00146 00147 void sqlite3_connection::open(std::string const & db) 00148 { 00149 return this->open( db.c_str() ); 00150 } 00151 00152 #if SQLITE3X_USE_WCHAR 00153 void sqlite3_connection::open(const wchar_t *db) { 00154 if(sqlite3_open16(db, &this->m_db)!=SQLITE_OK) 00155 throw database_error("unable to open database"); 00156 try 00157 { 00158 this->on_open(); 00159 } 00160 catch(...) 00161 { 00162 try { this->close(); } 00163 catch(...) { /* ignore */ } 00164 throw; 00165 } 00166 } 00167 #endif 00168 00169 void sqlite3_connection::close() { 00170 if(this->m_db) { 00171 sqlite3 * x = this->m_db; 00172 this->m_db=NULL; 00173 if(sqlite3_close(x)!=SQLITE_OK) 00174 throw database_error(*this); 00175 } 00176 } 00177 00178 int64_t sqlite3_connection::insertid() { 00179 if(!this->m_db) throw database_error("database is not open"); 00180 return sqlite3_last_insert_rowid(this->m_db); 00181 } 00182 00183 int sqlite3_connection::changes() { 00184 if(!this->m_db) throw database_error("database is not open"); 00185 return sqlite3_changes(this->m_db); 00186 } 00187 00188 00189 void sqlite3_connection::setbusytimeout(int ms) { 00190 if(!this->m_db) throw database_error("database is not open"); 00191 00192 if(sqlite3_busy_timeout(this->m_db, ms)!=SQLITE_OK) 00193 throw database_error(*this); 00194 } 00195 00196 void sqlite3_connection::executenonquery(const std::string &sql) { 00197 this->executenonquery( sql.c_str() ); 00198 } 00199 00200 void sqlite3_connection::executenonquery(char const * sql) { 00201 if(!this->m_db) throw database_error("database is not open"); 00202 sqlite3_command(*this, sql).executenonquery(); 00203 } 00204 00205 #if SQLITE3X_USE_WCHAR 00206 void sqlite3_connection::executenonquery(const std::wstring &sql) { 00207 if(!this->m_db) throw database_error("database is not open"); 00208 sqlite3_command(*this, sql).executenonquery(); 00209 } 00210 #endif 00211 00212 int sqlite3_connection::executeint(char const * sql) { 00213 if(!this->m_db) throw database_error("database is not open"); 00214 return sqlite3_command(*this, sql).executeint(); 00215 } 00216 int sqlite3_connection::executeint(const std::string &sql) { 00217 return this->executeint( sql.c_str() ); 00218 } 00219 00220 #if SQLITE3X_USE_WCHAR 00221 int sqlite3_connection::executeint(const std::wstring &sql) { 00222 if(!this->m_db) throw database_error("database is not open"); 00223 return sqlite3_command(*this, sql).executeint(); 00224 } 00225 #endif 00226 00227 int64_t sqlite3_connection::executeint64(char const * sql) { 00228 if(!this->m_db) throw database_error("database is not open"); 00229 return sqlite3_command(*this, sql).executeint64(); 00230 } 00231 00232 int64_t sqlite3_connection::executeint64(const std::string &sql) { 00233 return this->executeint64( sql.c_str() ); 00234 } 00235 00236 #if SQLITE3X_USE_WCHAR 00237 int64_t sqlite3_connection::executeint64(const std::wstring &sql) { 00238 if(!this->m_db) throw database_error("database is not open"); 00239 return sqlite3_command(*this, sql).executeint64(); 00240 } 00241 #endif 00242 00243 double sqlite3_connection::executedouble(char const * sql) { 00244 if(!this->m_db) throw database_error("database is not open"); 00245 return sqlite3_command(*this, sql).executedouble(); 00246 } 00247 00248 double sqlite3_connection::executedouble(const std::string &sql) { 00249 return this->executedouble( sql.c_str() ); 00250 } 00251 00252 #if SQLITE3X_USE_WCHAR 00253 double sqlite3_connection::executedouble(const std::wstring &sql) { 00254 if(!this->m_db) throw database_error("database is not open"); 00255 return sqlite3_command(*this, sql).executedouble(); 00256 } 00257 #endif 00258 00259 std::string sqlite3_connection::executestring(const std::string &sql) { 00260 if(!this->m_db) throw database_error("database is not open"); 00261 return sqlite3_command(*this, sql).executestring(); 00262 } 00263 00264 #if SQLITE3X_USE_WCHAR 00265 std::string sqlite3_connection::executestring(const std::wstring &sql) { 00266 if(!this->m_db) throw database_error("database is not open"); 00267 return sqlite3_command(*this, sql).executestring(); 00268 } 00269 #endif 00270 00271 #if SQLITE3X_USE_WCHAR 00272 std::wstring sqlite3_connection::executestring16(const std::string &sql) { 00273 if(!this->m_db) throw database_error("database is not open"); 00274 return sqlite3_command(*this, sql).executestring16(); 00275 } 00276 #endif 00277 00278 #if SQLITE3X_USE_WCHAR 00279 std::wstring sqlite3_connection::executestring16(const std::wstring &sql) { 00280 if(!this->m_db) throw database_error("database is not open"); 00281 return sqlite3_command(*this, sql).executestring16(); 00282 } 00283 #endif 00284 00285 std::string sqlite3_connection::executeblob(const std::string &sql) { 00286 if(!this->m_db) throw database_error("database is not open"); 00287 return sqlite3_command(*this, sql).executeblob(); 00288 } 00289 00290 #if SQLITE3X_USE_WCHAR 00291 std::string sqlite3_connection::executeblob(const std::wstring &sql) { 00292 if(!this->m_db) throw database_error("database is not open"); 00293 return sqlite3_command(*this, sql).executeblob(); 00294 } 00295 #endif 00296 00297 int sqlite3_connection::executecallback( std::string const & sql, 00298 sqlite3_callback callback, 00299 void * data, 00300 std::string & errmsg ) 00301 { 00302 char * cerrmsg = 0; 00303 int ret = 0; 00304 try 00305 { 00306 // allow callback to safely throw. 00307 ret = sqlite3_exec( this->m_db, sql.c_str(), callback, data, &cerrmsg ); 00308 } 00309 catch( ... ) 00310 { 00311 if( cerrmsg ) 00312 { 00313 errmsg = cerrmsg; 00314 sqlite3_free( cerrmsg ); 00315 } 00316 throw; 00317 } 00318 if( cerrmsg ) 00319 { 00320 errmsg = cerrmsg; 00321 sqlite3_free( cerrmsg ); 00322 } 00323 return ret; 00324 } 00325 00326 int sqlite3_connection::executecallback( std::string const & sql, 00327 sqlite3_callback func, 00328 void * data ) 00329 { 00330 std::string ignored; 00331 return this->executecallback( sql, func, data, ignored ); 00332 } 00333 00334 /** 00335 An internal implementation detail of table_generator. 00336 */ 00337 class table_generator::table_generator_impl 00338 { 00339 00340 public: 00341 sqlite3_connection * db; 00342 std::string name; 00343 std::vector<std::string> list; 00344 }; 00345 00346 // int sqlite3_function_info8::create( sqlite3 * db ) 00347 // { 00348 // return sqlite3_create_function( 00349 // db, 00350 // this->name, 00351 // this->argc, 00352 // 0, 00353 // this->user_data, 00354 // this->func, 00355 // this->step, 00356 // this->final ); 00357 // } 00358 00359 // int sqlite3_function_info16::create( sqlite3 * db ) 00360 // { 00361 // return sqlite3_create_function16( 00362 // db, 00363 // this->name, 00364 // this->argc, 00365 // 1, 00366 // this->user_data, 00367 // this->func, 00368 // this->step, 00369 // this->final ); 00370 // } 00371 00372 table_generator::table_generator( sqlite3_connection & con, std::string const & n ) 00373 : m_pimpl( new table_generator::table_generator_impl ) 00374 { 00375 int check = con.executeint( "select count(*) from sqlite_master where type like 'table' and name like '"+n+"'" ); 00376 // ^^^ we use 'like' here because sqlite3 is case-insensitive 00377 if( 0 != check ) 00378 { 00379 throw database_error( "table_generator() db table '%s' already exists.", n.c_str() ); 00380 } 00381 this->m_pimpl->db = &con; 00382 this->m_pimpl->name = n; 00383 } 00384 00385 table_generator::~table_generator() throw() 00386 { 00387 delete this->m_pimpl; 00388 } 00389 00390 table_generator & table_generator::operator()( std::string const & fld ) 00391 { 00392 this->m_pimpl->list.push_back( fld ); 00393 return *this; 00394 } 00395 00396 void table_generator::create() 00397 { 00398 size_t sz = this->m_pimpl->list.size(); 00399 if( ! sz ) 00400 { 00401 throw database_error( "table_generator::operator(): cannot create a table with no fields. Try using operator()(string) to add fields." ); 00402 } 00403 std::ostringstream os; 00404 os << "create table "<< this->m_pimpl->name << "("; 00405 for( size_t i = 0; i < sz; ++i ) 00406 { 00407 os << this->m_pimpl->list[i]; 00408 if( i < (sz-1) ) os << ","; 00409 } 00410 os << ");"; 00411 this->m_pimpl->db->executenonquery( os.str() ); 00412 } 00413 00414 }