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>
32namespace 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
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
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
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:
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
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}
Exception type used by the sqlite3x classes.
Definition sqlite3x.hpp:777
Encapsulates a command to send to an sqlite3_connection.
Definition sqlite3x.hpp:592
int executeint()
Executes the query, which is expected to have an integer field as the first result field.
void executenonquery()
Executes the query and provides no way to get the results.
std::string executeblob()
Executes the query, which is expected to have a string or blob field as the first result field.
double executedouble()
Executes the query, which is expected to have a double field as the first result field.
std::string executestring()
Executes the query, which is expected to have a string or blob field as the first result field.
int64_t executeint64()
Executes the query, which is expected to have a (int64_t) field as the first result field.
Represents a connection to an sqlite3 database.
Definition sqlite3x.hpp:149
void close()
Closes this database.
sqlite3 * db() const
Returns a handle to the underlying sqlite3 database.
void executenonquery(const std::string &sql)
Executes a command which is assumed to have a single step and a void result.
virtual void open(char const *)
Creates/opens the given db, throwing on error.
int64_t executeint64(const std::string &sql)
Executes the query, which is expected to have a (int64_t) field as the first result field.
int64_t insertid()
Returns the rowid of the most recently inserted row on this db.
std::string name() const
Returns this object's name.
int changes()
Returns the number of database rows that were changed (or inserted or deleted) by the most recently c...
sqlite3 * take()
Transfers ownership of the returned handle to the caller.
virtual ~sqlite3_connection()
Calls this->close() if close() has not already been called.
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.
double executedouble(const std::string &sql)
Executes the query, which is expected to have a double field as the first result field.
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.
void setbusytimeout(int ms)
See sqlite3_busy_timeout().
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.
std::string errormsg() const
Returns the equivalent of sqlite3_errmsg(), or an empty string if that function returns null.
virtual void on_open()
This function is called when open() succeeds.
int executeint(const std::string &sql)
Executes the query, which is expected to have an integer field as the first result field.
An internal implementation detail of table_generator.
table_generator(sqlite3_connection &con, std::string const &name)
Initializes the table generation process.
~table_generator()
Frees up internal resources.
void create()
Executes the 'create table' statements.
table_generator & operator()(std::string const &field_name)
Adds field_name as a field of this table.
This namespace encapsulates a C++ API wrapper for sqlite3 databases.
Definition sqlite3x.hpp:120
sqlite_int64 int64_t
64-bit integer type used by this code.
Definition sqlite3x.hpp:125
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.