libsq3 2007.10.18
sq3.cpp
1#if 0
2# ifndef COUT
3# include <iostream>
4# define COUT std::cerr << "SQ3:"<<__FILE__ << ":" << std::dec<<__LINE__ << ": "
5# endif
6#endif
7
8#include "sq3.hpp"
9#include <vector>
10#include <sstream>
11#include <cstring>
12
13#if SQ3_USE_WCHAR
14#include <cwchar>
15#endif
16
17namespace sq3 {
18
20 {
21 if( st )
22 {
23 st->reset();
24 st = 0;
25 }
26 }
27
28 void sqlite3_stmt_reset_finalizer::operator()( sqlite3_stmt * & st )
29 {
30 if( st )
31 {
32 sqlite3_reset( st );
33 st = 0;
34 }
35 }
36
37 void sqlite3_stmt_finalizer::operator()( sqlite3_stmt * & st )
38 {
39 if( st )
40 {
41 sqlite3_finalize( st );
42 st = 0;
43 }
44 }
45
46 void sqlite3_finalizer::operator()( sqlite3 * & s )
47 {
48 if( s )
49 {
50 sqlite3_close( s );
51 s = 0;
52 }
53 }
54
55
56 bool rc_is_okay( int rc )
57 {
58 return ((SQLITE_DONE==rc) || (SQLITE_OK==rc) || (SQLITE_ROW==rc));
59 }
60
61
62 int statement::prepare( std::string const & sql )
63 {
64 return this->prepare( sql.c_str(), static_cast<int>(sql.size()) );
65 }
66
67 int statement::prepare( char const * sql, int len )
68 {
69 // FIXME: make this function clean up any existing sqlite3_stmt.
70 const char *tail=NULL;
71 if( 0 > len ) len = static_cast<int>(strlen(sql));
72 sqlite3_stmt * st = 0;
73
74 int rc =
75#if (SQLITE_VERSION_NUMBER >= 3003009)
76 sqlite3_prepare_v2
77#else
78 sqlite3_prepare
79#endif
80 (this->m_db.handle(), sql, len, &st, &tail);
81
82 if( SQLITE_OK == rc )
83 {
84 this->m_argc = sqlite3_column_count(st);
85 this->m_stmt.take( st );
86 }
87 else
88 {
89 this->finalize();
90 }
91 return rc;
92 }
93
94#if SQ3_USE_WCHAR
95 int statement::prepare( sqlite3_wstring_t const sql, int byteCount )
96 {
97 void const * tail = NULL;
98 if( 0 > byteCount ) byteCount = ????;
99 sqlite3_stmt * st = 0;
100 int rc =
101#if SQLITE_VERSION_NUMBER >= 3003009
102 sqlite3_prepare16_v2
103#else
104 sqlite3_prepare16
105#endif
106 (this->m_db.handle(), sql, byteCount, &st, &tail);
107 if( SQLITE_OK == rc )
108 {
109 this->m_argc = sqlite3_column_count(st);
110 this->m_stmt.take(st);
111 }
112 else
113 {
114 this->finalize();
115 }
116 return rc;
117
118 }
119#endif // SQ3_USE_WCHAR
120
121
123 {
124 int rc = SQLITE_ERROR;
125 if( this->m_stmt.get() )
126 {
127 rc = SQLITE_OK; // we'll fudge a bit here.
128 //sqlite3_finalize(this->m_stmt.get());
129 this->m_stmt.take(0); // give up ownership.
130 }
131 return rc;
132 }
133
134
136 : m_db(db), m_stmt(0), m_argc(0)
137 {
138 }
139
140 statement::statement( database & db, std::string const & sql )
141 : m_db(db), m_stmt(0), m_argc(0)
142 {
143 this->prepare( sql );
144 }
145 statement::statement( database & db, char const * sql, int byteCount )
146 : m_db(db), m_stmt(0), m_argc(0)
147 {
148 this->prepare( sql, byteCount );
149 }
150
151#if SQ3_USE_WCHAR
152 statement::statement( database & db, std::wstring const & sql )
153 : m_db(db), m_stmt(0), m_argc(0)
154 {
155 this->prepare( sql );
156 }
157 statement::statement( database & db, wchar_t const * sql, int byteCount )
158 : m_db(db), m_stmt(0), m_argc(0)
159 {
160 this->prepare( sql, byteCount );
161 }
162#endif // SQ3_USE_WCHAR
163
164
166 {
167 return 0 != this->m_stmt.get();
168 }
170 {
171 this->finalize();
172 }
173 int statement::bind( int index )
174 {
175 return sqlite3_bind_null( this->m_stmt.get(), index);
176 }
177 int statement::bind( int index, int data )
178 {
179 return sqlite3_bind_int( this->m_stmt.get(), index, data );
180 }
181 int statement::bind( int index, int64_t data )
182 {
183 return sqlite3_bind_int64( this->m_stmt.get(), index, data );
184 }
185 int statement::bind( int index, double data )
186 {
187 return sqlite3_bind_double( this->m_stmt.get(), index, data );
188 }
189 int statement::bind( int index, char const * data, int len )
190 {
191 if( 0 > len ) len = static_cast<int>(strlen(data));
192 return sqlite3_bind_text( this->m_stmt.get(), index, data, len, SQLITE_TRANSIENT );
193 }
194 int statement::bind( int index, void const * data, int len )
195 {
196 return sqlite3_bind_blob( this->m_stmt.get(), index, data, len, SQLITE_TRANSIENT );
197 }
198 //int statement::bind( int index, wchar_t const * data, int len );
199 int statement::bind( int index, std::string const & data )
200 {
201 return this->bind( index, data.c_str(), static_cast<int>(data.size() ) );
202 }
203 //int statement::bind( int index, std::wstring const & data );
204
205 int statement::bind( char const * index )
206 {
207 return sqlite3_bind_null( this->m_stmt.get(),
208 sqlite3_bind_parameter_index( this->m_stmt.get(), index ) );
209 }
210 int statement::bind( char const * index, int data )
211 {
212 return sqlite3_bind_int( this->m_stmt.get(),
213 sqlite3_bind_parameter_index( this->m_stmt.get(), index ), data );
214 }
215 int statement::bind( char const * index, int64_t data )
216 {
217 return sqlite3_bind_int64( this->m_stmt.get(),
218 sqlite3_bind_parameter_index( this->m_stmt.get(), index ), data );
219 }
220 int statement::bind( char const * index, double data )
221 {
222 return sqlite3_bind_double( this->m_stmt.get(),
223 sqlite3_bind_parameter_index( this->m_stmt.get(), index ), data );
224 }
225 int statement::bind( char const * index, char const * data, int len )
226 {
227 if( 0 > len ) len = static_cast<int>(strlen(data) );
228 return sqlite3_bind_text( this->m_stmt.get(),
229 sqlite3_bind_parameter_index( this->m_stmt.get(), index ) , data, len, SQLITE_TRANSIENT );
230 }
231 int statement::bind( char const * index, void const * data, int len )
232 {
233 return sqlite3_bind_blob( this->m_stmt.get(),
234 sqlite3_bind_parameter_index( this->m_stmt.get(), index ) , data, len, SQLITE_TRANSIENT );
235 }
236
237 int statement::bind( char const * index, std::string const & data )
238 {
239 return this->bind( index, data.c_str(), static_cast<int>(data.size() ) );
240 }
241
242
243
244
245
247 {
248 return cursor(*this);
249 }
251 {
252 return this->get_cursor().step();
253 }
254
255#define STATEMENT_EXECUTE_1ARG_IMPL \
256 cursor rd( this->get_cursor() ); \
257 int rc = rd.step(); \
258 if( SQLITE_ROW == rc ) \
259 { \
260 rc = rd.get(0,tgt); \
261 } \
262 return rc;
263
264 int statement::execute( int & tgt )
265 {
266 STATEMENT_EXECUTE_1ARG_IMPL;
267 }
269 {
270 STATEMENT_EXECUTE_1ARG_IMPL;
271 }
272 int statement::execute( double & tgt )
273 {
274 STATEMENT_EXECUTE_1ARG_IMPL;
275 }
276 int statement::execute( std::string & tgt )
277 {
278 STATEMENT_EXECUTE_1ARG_IMPL;
279 }
280#undef STATEMENT_EXECUTE_1ARG_IMPL
281
282 int statement::execute( sqlite3_text_char_t const ** tgt, int & len )
283 {
284 cursor rd( this->get_cursor() );
285 int rc = rd.step();
286 if( SQLITE_ROW == rc )
287 {
288 rc = rd.get(0,tgt,len);
289 }
290 return rc;
291 }
292 int statement::execute( void const ** tgt, int & len )
293 {
294 cursor rd( this->get_cursor() );
295 int rc = rd.step();
296 if( SQLITE_ROW == rc )
297 {
298 rc = rd.get(0,tgt,len);
299 }
300 return rc;
301 }
302
303
305 {
306 return this->m_stmt.get()
307 ? sqlite3_reset( this->m_stmt.get() )
308 : SQLITE_ERROR;
309 }
310
312 {
313 return this->m_stmt.get()
314 ? this->m_argc
315 : -1;
316 }
317
318 char const * statement::colname( int index )
319 {
320 int count = this->colcount();
321 if( -1 == count ) return 0;
322 if( (index < 0) || (index >= count) ) return 0;
323 return sqlite3_column_name(this->m_stmt.get(), index);
324 }
325
326 int statement::colname( int index, char const ** cn )
327 {
328 char const * c = this->colname( index );
329 if( c ) *cn = c;
330 return c ? SQLITE_OK : SQLITE_ERROR;
331 }
332
333
334 cursor::cursor() : m_stmt(0),m_cn(0)
335 {
336 }
337 cursor::cursor( cursor const & cp ) : m_stmt(cp.m_stmt),m_cn(0)
338 {
339 this->copy(cp);
340 }
341
342 cursor::cursor( statement & st ) : m_stmt(&st),m_cn(0)
343 {
344 this->m_stmt.take(&st);
345 }
346
348 {
349 if( &cp == this ) return *this;
350 this->copy(cp);
351 return *this;
352 }
353
354 void cursor::copy( cursor const & rhs )
355 {
356 if( &rhs == this ) return;
357 this->close();
358 this->m_stmt = rhs.m_stmt;
359 if( rhs.m_cn )
360 {
361 this->m_cn = new NameToIndexMap(*rhs.m_cn);
362 }
363 }
364
366 {
367 this->close();
368 }
369
371 {
372 return this->m_stmt.get()
373 ? sqlite3_step(this->m_stmt->m_stmt.get())
374 : SQLITE_ERROR;
375 }
376
378 {
379 delete this->m_cn;
380 this->m_cn = 0;
381 return this->m_stmt.get()
382 ? this->m_stmt->reset()
383 : SQLITE_ERROR;
384 }
386 {
387 this->m_stmt.take(0);
388 if( this->m_cn )
389 {
390 delete this->m_cn;
391 this->m_cn = 0;
392 }
393 }
394
396 {
397 return this->m_stmt.get()
398 ? this->m_stmt->colcount()
399 : -1;
400 }
401
402#define CURSOR_CHECK_INDEX \
403 if( ! this->m_stmt.get() ) return SQLITE_ERROR; \
404 if( (index)>(this->m_stmt->m_argc-1)) return SQLITE_ERROR;
405
406 int cursor::isnull( int index, bool & tgt )
407 {
408 CURSOR_CHECK_INDEX;
409 tgt = sqlite3_column_type( this->m_stmt->m_stmt.get(), index) == SQLITE_NULL;
410 return SQLITE_OK;
411 }
412
413 int cursor::get( int index, int & tgt )
414 {
415 CURSOR_CHECK_INDEX;
416 tgt = sqlite3_column_int( this->m_stmt->m_stmt.get(), index );
417 return SQLITE_OK;
418 }
419 int cursor::get( int index, int64_t & tgt )
420 {
421 CURSOR_CHECK_INDEX;
422 tgt = sqlite3_column_int64( this->m_stmt->m_stmt.get(), index );
423 return SQLITE_OK;
424 }
425 int cursor::get( int index, double & tgt )
426 {
427 CURSOR_CHECK_INDEX;
428 tgt = sqlite3_column_double( this->m_stmt->m_stmt.get(), index );
429 return SQLITE_OK;
430 }
431 int cursor::get( int index, std::string & tgt )
432 {
433 CURSOR_CHECK_INDEX;
434 char const * x = (const char*)sqlite3_column_text(this->m_stmt->m_stmt.get(), index);
435 int sz = sqlite3_column_bytes(this->m_stmt->m_stmt.get(), index);
436 if( 0 < sz )
437 {
438 tgt = std::string( x, x+sz );
439 }
440 else
441 {
442 tgt = std::string();
443 }
444 return SQLITE_OK;
445 }
446 int cursor::get( int index, sqlite3_text_char_t const ** tgt, int & sz )
447 {
448 CURSOR_CHECK_INDEX;
449 sz = sqlite3_column_bytes(this->m_stmt->m_stmt.get(), index);
450 if( 0 < sz )
451 {
452 *tgt = sqlite3_column_text( this->m_stmt->m_stmt.get(), index);
453 }
454 else
455 {
456 tgt = 0;
457 }
458 return SQLITE_OK;
459 }
460 int cursor::get( int index, void const ** tgt, int & sz )
461 {
462 CURSOR_CHECK_INDEX;
463 sz = sqlite3_column_bytes(this->m_stmt->m_stmt.get(), index);
464 if( 0 < sz )
465 {
466 *tgt = sqlite3_column_blob(this->m_stmt->m_stmt.get(), index);
467 }
468 return SQLITE_OK;
469 }
470
471
472 /**
473 CURSOR_GET_STRING_IMPL2 is the implementation for the get(string,xxx) family of funcs
474 which take 2 arguments.
475 */
476#define CURSOR_GET_STRING_IMPL2(vaR,targetNamE) \
477 if( ! this->m_stmt.get() ) return SQLITE_ERROR; \
478 if( 0 == this->index_colnames() ) return SQLITE_ERROR; \
479 NameToIndexMap::const_iterator n2iit = this->m_cn->find( vaR ); \
480 return ( this->m_cn->end() == n2iit ) ? SQLITE_ERROR : this->get( (*n2iit).second, targetNamE );
481
482 /**
483 CURSOR_GET_STRING_IMPL3 is the implementation for the get(string,xxx) family of funcs
484 which take 3 arguments. It is *almost* identicle to CURSOR_GET_STRING_IMPL2.
485 */
486#define CURSOR_GET_STRING_IMPL3(vaR,targetNamE,sizeNamE) \
487 if( ! this->m_stmt.get() ) return SQLITE_ERROR; \
488 if( 0 == this->index_colnames() ) return SQLITE_ERROR; \
489 NameToIndexMap::const_iterator n2iit = this->m_cn->find( vaR ); \
490 return ( this->m_cn->end() == n2iit ) ? SQLITE_ERROR : this->get( (*n2iit).second, targetNamE, sizeNamE );
491
492
493 int cursor::get( std::string const & key, int & tgt )
494 {
495 CURSOR_GET_STRING_IMPL2(key,tgt);
496 }
497 int cursor::get( std::string const & key, int64_t & tgt )
498 {
499 CURSOR_GET_STRING_IMPL2(key,tgt);
500 }
501 int cursor::get( std::string const & key, double & tgt )
502 {
503 CURSOR_GET_STRING_IMPL2(key,tgt);
504 }
505 int cursor::get( std::string const & key, std::string & tgt )
506 {
507 CURSOR_GET_STRING_IMPL2(key,tgt);
508 }
509 int cursor::get( std::string const & key, sqlite3_text_char_t const ** tgt, int & sz )
510 {
511 CURSOR_GET_STRING_IMPL3(key,tgt,sz);
512 }
513 int cursor::get( std::string const & key, void const ** tgt, int & sz )
514 {
515 CURSOR_GET_STRING_IMPL3(key,tgt,sz);
516 }
517
518
519 int cursor::colname( int index, std::string & tgt )
520 {
521 char const * cn = 0;
522 int rc = this->colname( index, &cn );
523 if( SQLITE_OK == rc )
524 {
525 tgt = cn ? cn : "";
526 }
527 return rc;
528 }
529
530 int cursor::colname( int index, char const ** cn )
531 {
532 return this->m_stmt->colname( index, cn );
533 }
534
535
536#undef CURSOR_CHECK_INDEX
537#undef CURSOR_GET_STRING_IMPL2
538#undef CURSOR_GET_STRING_IMPL3
539
540 sqlite3 * database::handle() const
541 {
542 return this->m_dbh.get();
543 }
544 database::database() : m_dbh(0), m_name()
545 {
546 }
547
548
549 database::database( std::string const & dbname )
550 : m_dbh(0), m_name(dbname)
551 {
552 this->open( dbname );
553 }
554
556 {
557 this->close();
558 }
559
560
561
562
563 bool database::is_open() const
564 {
565 return 0 != this->m_dbh.get();
566 }
567 std::string database::name() const
568 {
569 return this->m_name;
570 }
571
573 {
574 return this->m_dbh.take();
575 }
576
577 void database::take_handle( sqlite3 * dbh, std::string const & name )
578 {
579 if( this->m_dbh.get() == dbh ) return;
580 this->close();
581 this->m_name = name;
582 this->m_dbh.take( dbh );
583 }
584
585 std::string database::errormsg() const
586 {
587 char const * m = this->m_dbh.get() ? sqlite3_errmsg( this->m_dbh.get() ) : 0;
588 return m ? m : "";
589 }
590
591 int database::open( char const * dbn, long flags )
592 {
593 if( ! dbn ) return SQLITE_ERROR;
594 int rc = 0;
595 if( this->m_dbh.get() )
596 {
597 rc = this->close();
598 if( 0 != rc ) return rc;
599 }
600 this->m_name = dbn;
601 sqlite3 * sq = 0;
602#if (SQLITE_VERSION_NUMBER >= 3005001)
603 if( ! flags )
604 {
605 rc = sqlite3_open(dbn, &sq);
606 }
607 else
608 {
609 rc = sqlite3_open_v2( dbn, &sq, flags, NULL );
610 }
611#else
612 { int bogus; bogus = flags; } // avoid "unused variable: flags" warning from gcc
613 rc = sqlite3_open(dbn, &sq);
614#endif // sqlite3 >= 3.5.1
615 if( SQLITE_OK == rc )
616 {
617 this->m_dbh.take( sq );
618 rc = this->on_open();
619 }
620 if( SQLITE_OK != rc )
621 {
622 this->close(); // ingore any close() failure in this case
623 }
624 return rc;
625 }
626
627 int database::open( std::string const & dbn, long flags )
628 {
629 return this->open( dbn.c_str(), flags );
630 }
631
633 {
634 return SQLITE_OK;
635 }
636
637#if SQ3_USE_WCHAR
638 int database::open( sqlite3_wstring_t dbn )
639 {
640 //std::wcerr << L"database::open(wchar_t " << dbn << L")\n";
641 this->close();
642 int rc = sqlite3_open16(dbn, &this->m_db);
643 sqlite3 * sq = 0;
644 sqlite3_open(dbn, &sq);
645 if( SQLITE_OK == rc )
646 {
647 this->m_dbh.take( sq );
648 rc = this->on_open();
649 }
650 if( SQLITE_OK != rc )
651 {
652 this->close();
653 }
654 return rc;
655 }
656
657 int database::open( std::wstring const & dbn )
658 {
659 return this->open( dbn.c_str() );
660 }
661#endif // SQ3_USE_WCHAR
662
663 int database::close( bool force )
664 {
665 if(0 == this->m_dbh.get()) return SQLITE_ERROR;
666 if( force )
667 { // do immediately close:
668 return sqlite3_close( this->m_dbh.take() /* transfer ownership to sqlite3 */ );
669 }
670 else
671 { // --reference_count and queue up the close:
672 this->m_dbh.take(0); // drop existing handle.
673 return SQLITE_OK;
674 }
675 }
676
678 {
679 return this->m_dbh.get()
680 ? sqlite3_last_insert_rowid(this->m_dbh.get())
681 : -1;
682 }
683
685 {
686 return this->m_dbh.get()
687 ? sqlite3_changes(this->m_dbh.get())
688 : -1;
689 }
690
692 {
693 return this->m_dbh.get()
694 ? sqlite3_busy_timeout(this->m_dbh.get(), ms)
695 : SQLITE_ERROR;
696 }
697
698 int database::execute(const std::string &sql)
699 {
700 return statement( *this, sql ).execute();
701 }
702
703 int database::execute(char const * sql )
704 {
705 return statement( *this, sql, -1 ).execute();
706 }
707
708 int database::execute(char const * sql, int & tgt)
709 {
710 return statement( *this, sql ).execute( tgt );
711 }
712
713 int database::execute(std::string const & sql, int & tgt)
714 {
715 return statement( *this, sql ).execute( tgt );
716 }
717
718 int database::execute(char const * sql, int64_t & tgt)
719 {
720 return statement( *this, sql, -1 ).execute( tgt );
721 }
722
723 int database::execute(std::string const & sql, int64_t & tgt)
724 {
725 return statement( *this, sql ).execute( tgt );
726 }
727
728 int database::execute(char const * sql, double & tgt)
729 {
730 return statement( *this, sql, -1 ).execute( tgt );
731 }
732
733 int database::execute(std::string const & sql, double & tgt)
734 {
735 return statement( *this, sql ).execute( tgt );
736 }
737
738 int database::execute(char const * sql, std::string & tgt)
739 {
740 return statement( *this, sql ).execute( tgt );
741 }
742
743 int database::execute(std::string const & sql, std::string & tgt)
744 {
745 return statement( *this, sql ).execute( tgt );
746 }
747
748 int database::execute(char const * sql, sqlite3_text_char_t const ** tgt, int & len )
749 {
750 return statement( *this, sql ).execute( tgt, len );
751 }
752
753 int database::execute(std::string const & sql, sqlite3_text_char_t const ** tgt, int & len )
754 {
755 return statement( *this, sql ).execute( tgt, len );
756 }
757
758// int database::execute(char const * sql, std::wstring & tgt);
759// int database::execute(std::string const & sql, std::wstring & tgt);
760 int database::execute(char const * sql, void const ** tgt, int & len )
761 {
762 return statement( *this, sql ).execute( tgt, len );
763 }
764 int database::execute(std::string const & sql, void const ** tgt, int & len )
765 {
766 return statement( *this, sql ).execute( tgt, len );
767 }
768
769 int database::execute( std::string const & sql, sqlite3_callback callback, void * data, std::string & errmsg )
770 {
771 return this->execute( sql.c_str(), callback, data, errmsg );
772 }
773
774 int database::execute( char const * sql, sqlite3_callback callback, void * data, std::string & errmsg )
775 {
776 char * cerrmsg = 0;
777 int ret = 0;
778 try
779 {
780 // allow callback to safely throw.
781 ret = sqlite3_exec( this->m_dbh.get(), sql, callback, data, &cerrmsg );
782 }
783 catch( ... )
784 {
785 if( cerrmsg )
786 {
787 errmsg = cerrmsg;
788 sqlite3_free( cerrmsg );
789 }
790 throw;
791 }
792 if( cerrmsg )
793 {
794 errmsg = cerrmsg;
795 sqlite3_free( cerrmsg );
796 }
797 return ret;
798 }
799
800 int database::execute( std::string const & sql, sqlite3_callback callback, void * data )
801 {
802 std::string ignored;
803 return this->execute( sql, callback, data, ignored );
804 }
805
806 int database::execute( char const * sql, sqlite3_callback callback, void * data )
807 {
808 std::string s( sql ? sql : "" );
809 std::string ignored;
810 return this->execute( s, callback, data, ignored );
811 }
812
813
814 int database::pragma( char const * code )
815 {
816 std::ostringstream os;
817 os << "pragma " << code;
818 std::string sql( os.str() );
819 return this->execute( sql.c_str() );
820 }
821
823 {
824 return this->execute( "vacuum" );
825 }
826
828 {
829 if( ! this->is_open() )
830 {
831 return SQLITE_ERROR;
832 }
833 char const * parts[] = { "view", "trigger", "table", 0 };
834 std::string name;
835 typedef std::vector<std::string> CmdList;
836 CmdList list;
837 int rc = SQLITE_OK;
838 for( int i = 0; i < 3; ++i )
839 {
840 statement master(*this,"select name from sqlite_master where type=? and name not like 'sqlite_%'");
841 rc = master.bind( 1, parts[i] );
842 if( ! rc_is_okay(rc) ) return rc;
843 cursor cur(master.get_cursor());
844 while( SQLITE_ROW == cur.step() )
845 {
846 name = "";
847 rc = cur.get(0, name);
848 if( ! rc_is_okay(rc) ) return rc;
849 list.push_back( std::string("drop ") + parts[i] + "'" + name + "'" );
850 }
851 }
852 CmdList::const_iterator it = list.begin();
853 CmdList::const_iterator et = list.end();
854 for( ; et != it; ++it )
855 {
856 std::string cmd = *it;
857 rc = this->execute( cmd );
858 }
859 return rc;
860 }
861
862
863
864
865
866
867
868
869
870 transaction::transaction( database & db, bool start )
871 : m_db(db), m_intrans(false)
872 {
873 if( start ) this->begin();
874 }
875
877 {
878 this->rollback();
879 }
880
882 {
883 if( this->m_intrans )
884 {
885 return SQLITE_ERROR;
886 }
887 int rc = this->m_db.execute("begin");
888 this->m_intrans = (SQLITE_DONE == rc) || (SQLITE_OK == rc);
889 return rc;
890 }
891
893 {
894 if( ! this->m_intrans )
895 {
896 return SQLITE_ERROR;
897 }
898 int rc = this->m_db.execute("commit");
899 if( SQLITE_BUSY != rc )
900 {
901 // According to the sqlite3 docs, if a COMMIT fails with BUSY
902 // then the transaction is still open.
903 this->m_intrans = false;
904 }
905 return rc;
906 }
908 {
909 if( ! this->m_intrans )
910 {
911 return SQLITE_ERROR;
912 }
913 this->m_intrans = false;
914 return this->m_db.execute("rollback");
915 }
916
917 int cursor::index_colnames()
918 {
919 if( ! this->m_cn )
920 {
921 this->m_cn = new NameToIndexMap;
922 }
923 else
924 if( ! this->m_cn->empty() )
925 {
926 // We're using a cached result
927 return -1;
928 }
929 char const * cname;
930 int cc = this->colcount();
931 int pos = 0;
932 for( int i = 0; i < cc; ++i, ++pos )
933 {
934 cname = 0;
935 if( SQLITE_OK != this->colname( i, &cname ) )
936 //if( ! (cname = this->m_stmt->colname( i ) ) )
937 {
938 break;
939 }
940 (*this->m_cn)[std::string(cname ? cname : "")] = i;
941 }
942 return pos;
943 }
944
945
946} // namespace
This type is for stepping through a db query result.
Definition: sq3.hpp:685
int isnull(int index, bool &tgt)
If column index (0-based) is in bounds then this function check if the value of the given column inde...
Definition: sq3.cpp:406
int reset()
This is functionally the same as calling reset on the underlying prepared statement object to which t...
Definition: sq3.cpp:377
void close()
"Disconnects" this object from the underlying result set, making this object useless for anything but...
Definition: sq3.cpp:385
int step()
Uses sqlite3_step() to step through this object's data set by one step.
Definition: sq3.cpp:370
int get(int index, int &tgt)
If column index (0-based) is in bounds then this function assigns tgt to the value of the given colum...
Definition: sq3.cpp:413
~cursor()
A curious side-effect which one needs to be aware of but very rarely is an issue:
Definition: sq3.cpp:365
cursor()
Creates an empty cursor, whose only valid use is to assign it from another cursor.
Definition: sq3.cpp:334
int colcount()
Returns the column count of the underlying prepared statement.
Definition: sq3.cpp:395
cursor & operator=(cursor const &)
See the copy ctor.
Definition: sq3.cpp:347
int colname(int index, std::string &str)
Sets str to the column name as the given index (0-based).
Definition: sq3.cpp:519
Encapsulates a connection to an sqlite database.
Definition: sq3.hpp:233
database()
Creates an unopened database.
Definition: sq3.cpp:544
int setbusytimeout(int ms)
See sqlite3_busy_timeout().
Definition: sq3.cpp:691
bool is_open() const
Returns true if this db is opened.
Definition: sq3.cpp:563
sqlite3 * handle() const
The low-level handle to the sqlite db.
Definition: sq3.cpp:540
int vacuum()
Convenience wrapper around execute("vacuum").
Definition: sq3.cpp:822
virtual ~database()
Closes this db.
Definition: sq3.cpp:555
int execute(const std::string &sql)
Functionally identical to execute(char const *).
Definition: sq3.cpp:698
int changes()
Returns the number of database rows that were changed (or inserted or deleted) by the most recently c...
Definition: sq3.cpp:684
sqlite3 * take_handle()
Transfers ownership of this->handle() to the caller.
Definition: sq3.cpp:572
std::string name() const
Returns the name of the db file.
Definition: sq3.cpp:567
std::string errormsg() const
Returns the last error message from sqlite, or an empty string if this object is not opened.
Definition: sq3.cpp:585
virtual int open(char const *, long flags=0)
Creates/opens the given db file.
Definition: sq3.cpp:591
virtual int clear()
Looks through sqlite_master for a list of views, triggers, and tables, and drops them all (in that or...
Definition: sq3.cpp:827
int pragma(char const *code)
This is a convenience wrapper for execute( "pragma ..." ).
Definition: sq3.cpp:814
int64_t insertid()
Returns the rowid of the most recently inserted row on this db.
Definition: sq3.cpp:677
virtual int on_open()
This function is called when open() succeeds.
Definition: sq3.cpp:632
int close(bool force=false)
"Closes" this db.
Definition: sq3.cpp:663
cursor get_cursor()
Returns a cursor object ready to step over the result set from this object.
Definition: sq3.cpp:246
int colcount()
Returns the column count of this prepared statement, or -1 on error.
Definition: sq3.cpp:311
int bind(int index)
Binds NULL to the given placeholder index (1-based, not 0-based!).
Definition: sq3.cpp:173
~statement()
Calls this->finalize()
Definition: sq3.cpp:169
int prepare(std::string const &sql)
(Re-)prepares an SQL statement.
Definition: sq3.cpp:62
int execute()
Assumes this object's SQL statement is a single statement.
Definition: sq3.cpp:250
int finalize()
Finizalizes the underlying prepared statement, freeing its resources.
Definition: sq3.cpp:122
statement(database &db)
Initializes a prepared statement without a query.
Definition: sq3.cpp:135
char const * colname(int index)
On success, it returns the null-terminated column name of the given column.
Definition: sq3.cpp:318
int reset()
Calls sqlite3_reset() on the underlying statement handle and returns the result.
Definition: sq3.cpp:304
bool is_prepared() const
Use after construction to ensure that a statement was compiled.
Definition: sq3.cpp:165
int commit()
Commits the active transaction.
Definition: sq3.cpp:892
int begin()
Starts the transaction.
Definition: sq3.cpp:881
~transaction()
Calls this->rollback()
Definition: sq3.cpp:876
int rollback()
Initiates a rollback and returns the result of executing a rollback command.
Definition: sq3.cpp:907
The sq3 namespace encapsulates an OO sqlite3 API very similar to the sqlite3x API,...
Definition: sq3.hpp:77
char unsigned sqlite3_text_char_t
A char type used by some of the sqlite3 API to represent text data.
Definition: sq3.hpp:127
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.
Definition: sq3.cpp:56
sqlite_int64 int64_t
The type used for signed 64-bit integer operations.
Definition: sq3.hpp:82
void operator()(sqlite3 *&t)
Calls sqlite3_close(t) and assigns t to 0.
Definition: sq3.cpp:46
void operator()(sqlite3_stmt *&t)
Calls sqlite3_finalize(t) and assigns t to 0.
Definition: sq3.cpp:37
void operator()(sqlite3_stmt *&t)
Calls sqlite3_reset(t) and assigns t to 0.
Definition: sq3.cpp:28
void operator()(::sq3::statement *&t)
Calls t->reset() and assigns t to 0.
Definition: sq3.cpp:19