libsqlite3x  2007.10.18
sqlite3x_connection.cpp
1 /*
2  Copyright (C) 2004-2005 Cory Nelson
3  Copyright (C) 2006 stephan beal
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 
21  Changes made by stephan@s11n.net:
22 
23  - Changed ~sqlite3_connection() to use this->close() instead of sqlite3_close().
24 
25 */
26 
27 #include <sqlite3.h>
28 #include "sqlite3x.hpp"
29 
30 #include <sstream>
31 #include <vector>
32 namespace sqlite3x {
33 
34  bool rc_is_okay( int rc )
35  {
36  return ((SQLITE_DONE==rc) || (SQLITE_OK==rc) || (SQLITE_ROW==rc));
37  }
38 
39  sqlite3_connection::sqlite3_connection() : m_db(NULL), m_name() {}
40 
41  sqlite3_connection::sqlite3_connection(std::string const & dbn)
42  : m_db(NULL), m_name(dbn)
43  {
44  this->open(dbn);
45  }
46 
47 #if SQLITE3X_USE_WCHAR
48  sqlite3_connection::sqlite3_connection(const wchar_t *dbn) : m_db(NULL), m_name() { this->open(dbn); }
49 #endif
50 
52  : m_db(0), m_name()
53  {
54  if( ! dbh )
55  {
56  throw database_error( "sqlite3_connection(sqlite3*) ctor was passed a null db handle." );
57  }
58  this->take( dbh );
59  }
60 
62  {
63  try
64  {
65  this->close();
66  }
67  catch(...)
68  {
69  // ignored for the sake of a no-throw dtor.
70  }
71  }
72 
73 
74  void sqlite3_connection::take( sqlite3 * dbh )
75  {
76 
77  if( this->m_db == dbh ) return;
78  try
79  {
80  if( this->m_db || (!dbh) )
81  {
82  this->close();
83  }
84  this->m_db = dbh;
85  if( dbh )
86  {
87  this->on_open();
88  }
89  }
90  catch( ... )
91  {
92  this->m_db = dbh;
93  throw;
94  }
95  }
96 
97  sqlite3 * sqlite3_connection::take() throw()
98  {
99  sqlite3 * ret = this->m_db;
100  this->m_db = 0;
101  return ret;
102  }
103 
104  sqlite3 * sqlite3_connection::db() const
105  {
106  return this->m_db;
107  }
108 
109  std::string sqlite3_connection::name() const
110  {
111  return this->m_name;
112  }
113 
114  std::string sqlite3_connection::errormsg() const
115  {
116  char const * m = this->m_db ? sqlite3_errmsg(this->m_db) : "";
117  return m ? m : "";
118  }
119 
121  {
122  return;
123  }
124  void sqlite3_connection::open( char const * db) {
125  this->close();
126  this->m_name = db ? db : "";
127  if(sqlite3_open(db, &this->m_db)!=SQLITE_OK)
128  throw database_error("unable to open database %s", db ? db : "<null>");
129  try
130  {
131  // Potential bug: when open() is called from
132  // the ctor of subclasses as a result of
133  // calling the parent class ctor, the subclass
134  // part of the subclass may not be complete,
135  // and a less derived on_open() may
136  // potentially be called. ???
137  this->on_open();
138  }
139  catch(...)
140  {
141  try { this->close(); }
142  catch(...) { /* ignore */ }
143  throw;
144  }
145  }
146 
147  void sqlite3_connection::open(std::string const & db)
148  {
149  return this->open( db.c_str() );
150  }
151 
152 #if SQLITE3X_USE_WCHAR
153  void sqlite3_connection::open(const wchar_t *db) {
154  if(sqlite3_open16(db, &this->m_db)!=SQLITE_OK)
155  throw database_error("unable to open database");
156  try
157  {
158  this->on_open();
159  }
160  catch(...)
161  {
162  try { this->close(); }
163  catch(...) { /* ignore */ }
164  throw;
165  }
166  }
167 #endif
168 
170  if(this->m_db) {
171  sqlite3 * x = this->m_db;
172  this->m_db=NULL;
173  if(sqlite3_close(x)!=SQLITE_OK)
174  throw database_error(*this);
175  }
176  }
177 
179  if(!this->m_db) throw database_error("database is not open");
180  return sqlite3_last_insert_rowid(this->m_db);
181  }
182 
184  if(!this->m_db) throw database_error("database is not open");
185  return sqlite3_changes(this->m_db);
186  }
187 
188 
190  if(!this->m_db) throw database_error("database is not open");
191 
192  if(sqlite3_busy_timeout(this->m_db, ms)!=SQLITE_OK)
193  throw database_error(*this);
194  }
195 
196  void sqlite3_connection::executenonquery(const std::string &sql) {
197  this->executenonquery( sql.c_str() );
198  }
199 
200  void sqlite3_connection::executenonquery(char const * sql) {
201  if(!this->m_db) throw database_error("database is not open");
202  sqlite3_command(*this, sql).executenonquery();
203  }
204 
205 #if SQLITE3X_USE_WCHAR
206  void sqlite3_connection::executenonquery(const std::wstring &sql) {
207  if(!this->m_db) throw database_error("database is not open");
208  sqlite3_command(*this, sql).executenonquery();
209  }
210 #endif
211 
212  int sqlite3_connection::executeint(char const * sql) {
213  if(!this->m_db) throw database_error("database is not open");
214  return sqlite3_command(*this, sql).executeint();
215  }
216  int sqlite3_connection::executeint(const std::string &sql) {
217  return this->executeint( sql.c_str() );
218  }
219 
220 #if SQLITE3X_USE_WCHAR
221  int sqlite3_connection::executeint(const std::wstring &sql) {
222  if(!this->m_db) throw database_error("database is not open");
223  return sqlite3_command(*this, sql).executeint();
224  }
225 #endif
226 
228  if(!this->m_db) throw database_error("database is not open");
229  return sqlite3_command(*this, sql).executeint64();
230  }
231 
232  int64_t sqlite3_connection::executeint64(const std::string &sql) {
233  return this->executeint64( sql.c_str() );
234  }
235 
236 #if SQLITE3X_USE_WCHAR
237  int64_t sqlite3_connection::executeint64(const std::wstring &sql) {
238  if(!this->m_db) throw database_error("database is not open");
239  return sqlite3_command(*this, sql).executeint64();
240  }
241 #endif
242 
243  double sqlite3_connection::executedouble(char const * sql) {
244  if(!this->m_db) throw database_error("database is not open");
245  return sqlite3_command(*this, sql).executedouble();
246  }
247 
248  double sqlite3_connection::executedouble(const std::string &sql) {
249  return this->executedouble( sql.c_str() );
250  }
251 
252 #if SQLITE3X_USE_WCHAR
253  double sqlite3_connection::executedouble(const std::wstring &sql) {
254  if(!this->m_db) throw database_error("database is not open");
255  return sqlite3_command(*this, sql).executedouble();
256  }
257 #endif
258 
259  std::string sqlite3_connection::executestring(const std::string &sql) {
260  if(!this->m_db) throw database_error("database is not open");
261  return sqlite3_command(*this, sql).executestring();
262  }
263 
264 #if SQLITE3X_USE_WCHAR
265  std::string sqlite3_connection::executestring(const std::wstring &sql) {
266  if(!this->m_db) throw database_error("database is not open");
267  return sqlite3_command(*this, sql).executestring();
268  }
269 #endif
270 
271 #if SQLITE3X_USE_WCHAR
272  std::wstring sqlite3_connection::executestring16(const std::string &sql) {
273  if(!this->m_db) throw database_error("database is not open");
274  return sqlite3_command(*this, sql).executestring16();
275  }
276 #endif
277 
278 #if SQLITE3X_USE_WCHAR
279  std::wstring sqlite3_connection::executestring16(const std::wstring &sql) {
280  if(!this->m_db) throw database_error("database is not open");
281  return sqlite3_command(*this, sql).executestring16();
282  }
283 #endif
284 
285  std::string sqlite3_connection::executeblob(const std::string &sql) {
286  if(!this->m_db) throw database_error("database is not open");
287  return sqlite3_command(*this, sql).executeblob();
288  }
289 
290 #if SQLITE3X_USE_WCHAR
291  std::string sqlite3_connection::executeblob(const std::wstring &sql) {
292  if(!this->m_db) throw database_error("database is not open");
293  return sqlite3_command(*this, sql).executeblob();
294  }
295 #endif
296 
297  int sqlite3_connection::executecallback( std::string const & sql,
298  sqlite3_callback callback,
299  void * data,
300  std::string & errmsg )
301  {
302  char * cerrmsg = 0;
303  int ret = 0;
304  try
305  {
306  // allow callback to safely throw.
307  ret = sqlite3_exec( this->m_db, sql.c_str(), callback, data, &cerrmsg );
308  }
309  catch( ... )
310  {
311  if( cerrmsg )
312  {
313  errmsg = cerrmsg;
314  sqlite3_free( cerrmsg );
315  }
316  throw;
317  }
318  if( cerrmsg )
319  {
320  errmsg = cerrmsg;
321  sqlite3_free( cerrmsg );
322  }
323  return ret;
324  }
325 
326  int sqlite3_connection::executecallback( std::string const & sql,
327  sqlite3_callback func,
328  void * data )
329  {
330  std::string ignored;
331  return this->executecallback( sql, func, data, ignored );
332  }
333 
334  /**
335  An internal implementation detail of table_generator.
336  */
338  {
339 
340  public:
341  sqlite3_connection * db;
342  std::string name;
343  std::vector<std::string> list;
344  };
345 
346 // int sqlite3_function_info8::create( sqlite3 * db )
347 // {
348 // return sqlite3_create_function(
349 // db,
350 // this->name,
351 // this->argc,
352 // 0,
353 // this->user_data,
354 // this->func,
355 // this->step,
356 // this->final );
357 // }
358 
359 // int sqlite3_function_info16::create( sqlite3 * db )
360 // {
361 // return sqlite3_create_function16(
362 // db,
363 // this->name,
364 // this->argc,
365 // 1,
366 // this->user_data,
367 // this->func,
368 // this->step,
369 // this->final );
370 // }
371 
372  table_generator::table_generator( sqlite3_connection & con, std::string const & n )
373  : m_pimpl( new table_generator::table_generator_impl )
374  {
375  int check = con.executeint( "select count(*) from sqlite_master where type like 'table' and name like '"+n+"'" );
376  // ^^^ we use 'like' here because sqlite3 is case-insensitive
377  if( 0 != check )
378  {
379  throw database_error( "table_generator() db table '%s' already exists.", n.c_str() );
380  }
381  this->m_pimpl->db = &con;
382  this->m_pimpl->name = n;
383  }
384 
386  {
387  delete this->m_pimpl;
388  }
389 
390  table_generator & table_generator::operator()( std::string const & fld )
391  {
392  this->m_pimpl->list.push_back( fld );
393  return *this;
394  }
395 
397  {
398  size_t sz = this->m_pimpl->list.size();
399  if( ! sz )
400  {
401  throw database_error( "table_generator::operator(): cannot create a table with no fields. Try using operator()(string) to add fields." );
402  }
403  std::ostringstream os;
404  os << "create table "<< this->m_pimpl->name << "(";
405  for( size_t i = 0; i < sz; ++i )
406  {
407  os << this->m_pimpl->list[i];
408  if( i < (sz-1) ) os << ",";
409  }
410  os << ");";
411  this->m_pimpl->db->executenonquery( os.str() );
412  }
413 
414 }
int changes()
Returns the number of database rows that were changed (or inserted or deleted) by the most recently c...
std::string name() const
Returns this object&#39;s name.
Encapsulates a command to send to an sqlite3_connection.
Definition: sqlite3x.hpp:592
std::string executestring(const std::string &sql)
Executes the query, which is expected to have a string or blob field as the first result field...
void executenonquery()
Executes the query and provides no way to get the results.
double executedouble(const std::string &sql)
Executes the query, which is expected to have a double field as the first result field.
bool rc_is_okay(int rc)
rc_is_okay() is an easy way to check if rc is one of SQLITE_OK, SQLITE_ROW, or SQLITE_DONE.
~table_generator()
Frees up internal resources.
int64_t insertid()
Returns the rowid of the most recently inserted row on this db.
This namespace encapsulates a C++ API wrapper for sqlite3 databases.
Definition: sqlite3x.hpp:120
int executecallback(std::string const &sql, sqlite3_callback callback, void *data, std::string &errmsg)
Executes the given SQL code, calling callback for each row of the data set.
Represents a connection to an sqlite3 database.
Definition: sqlite3x.hpp:148
std::string executeblob(const std::string &sql)
Executes the query, which is expected to have a string or blob field as the first result field...
table_generator & operator()(std::string const &field_name)
Adds field_name as a field of this table.
std::string executeblob()
Executes the query, which is expected to have a string or blob field as the first result field...
int executeint(const std::string &sql)
Executes the query, which is expected to have an integer field as the first result field...
void close()
Closes this database.
sqlite3 * take()
Transfers ownership of the returned handle to the caller.
sqlite_int64 int64_t
64-bit integer type used by this code.
Definition: sqlite3x.hpp:125
std::string executestring()
Executes the query, which is expected to have a string or blob field as the first result field...
void setbusytimeout(int ms)
See sqlite3_busy_timeout().
int64_t executeint64()
Executes the query, which is expected to have a (int64_t) field as the first result field...
double executedouble()
Executes the query, which is expected to have a double field as the first result field.
virtual void open(char const *)
Creates/opens the given db, throwing on error.
void executenonquery(const std::string &sql)
Executes a command which is assumed to have a single step and a void result.
virtual void on_open()
This function is called when open() succeeds.
void create()
Executes the &#39;create table&#39; statements.
std::string errormsg() const
Returns the equivalent of sqlite3_errmsg(), or an empty string if that function returns null...
An internal implementation detail of table_generator.
table_generator(sqlite3_connection &con, std::string const &name)
Initializes the table generation process.
Exception type used by the sqlite3x classes.
Definition: sqlite3x.hpp:777
virtual ~sqlite3_connection()
Calls this->close() if close() has not already been called.
sqlite3 * db() const
Returns a handle to the underlying sqlite3 database.
int64_t executeint64(const std::string &sql)
Executes the query, which is expected to have a (int64_t) field as the first result field...
int executeint()
Executes the query, which is expected to have an integer field as the first result field...