summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2010-02-13 09:56:58 +0100
committerAndreas Baumann <abaumann@yahoo.com>2010-02-13 09:56:58 +0100
commit68354c7d41085d1f976a5b1d7ee542479a85f621 (patch)
treeaec761c793093e4a2e4ce18d78b3b531bcb12a42 /src
downloadsqlitexx-68354c7d41085d1f976a5b1d7ee542479a85f621.tar.gz
sqlitexx-68354c7d41085d1f976a5b1d7ee542479a85f621.tar.bz2
imported trunk from sourceforge SVN
Diffstat (limited to 'src')
-rw-r--r--src/GNUmakefile47
-rw-r--r--src/Makefile.W3264
-rw-r--r--src/connection.cpp175
-rw-r--r--src/except.cpp52
-rw-r--r--src/port/sleep.c43
-rw-r--r--src/port/sleep.h36
-rw-r--r--src/port/sqlite.h32
-rwxr-xr-xsrc/port/sqlite3xx.cpp42
-rw-r--r--src/port/string.c43
-rw-r--r--src/port/string.h57
-rw-r--r--src/port/sys_internal.h136
-rw-r--r--src/port/unused.h40
-rw-r--r--src/prepared_statement.cpp221
-rw-r--r--src/result.cpp354
-rw-r--r--src/transaction.cpp142
15 files changed, 1484 insertions, 0 deletions
diff --git a/src/GNUmakefile b/src/GNUmakefile
new file mode 100644
index 0000000..ce527be
--- /dev/null
+++ b/src/GNUmakefile
@@ -0,0 +1,47 @@
+TOPDIR = ..
+
+SUBDIRS =
+
+INCLUDE_DIRS = \
+ $(INCLUDE_FLAGS_SQLITE3) \
+ -I$(TOPDIR)/include \
+ -I.
+
+INCLUDE_LDFLAGS = \
+ $(LDFLAGS_SQLITE3)
+
+INCLUDE_LIBS = \
+ $(LIBS_SQLITE3)
+
+PORT_OBJS = \
+ port/string.o \
+ port/sleep.o
+
+OBJS = \
+ $(PORT_OBJS)
+
+CPP_OBJS = \
+ connection.o \
+ prepared_statement.o \
+ transaction.o \
+ result.o \
+ except.o
+
+STATIC_LIB = libsqlite3xx.a
+
+DYNAMIC_LIB = libsqlite3xx.so
+DYNAMIC_LIB_MAJOR = 0
+DYNAMIC_LIB_MINOR = 0
+DYNAMIC_LIB_PATCH = 0
+
+-include $(TOPDIR)/makefiles/gmake/sub.mk
+
+local_all:
+
+local_clean:
+
+local_distclean:
+
+local_install:
+
+local_uninstall:
diff --git a/src/Makefile.W32 b/src/Makefile.W32
new file mode 100644
index 0000000..a16a0f5
--- /dev/null
+++ b/src/Makefile.W32
@@ -0,0 +1,64 @@
+TOPDIR = ..
+
+SUBDIRS =
+
+INCLUDE_DIRS = \
+ /I$(TOPDIR)\include /I. \
+ /I$(TOPDIR)\sqlite-3.6.22 \
+ /D_WIN32_WINNT=0x400 /I"$(PLATFORM_SDK_DIR)\Include"
+
+INCLUDE_LDFLAGS = \
+ /LIBPATH:"$(PLATFORM_SDK_DIR)\Lib"
+
+INCLUDE_LIBS = \
+ $(TOPDIR)\sqlite-3.6.22\sqlite3.lib
+
+BINS =
+
+LIBRARIES = \
+ sqlite3xx.lib \
+ sqlite3xx.dll
+
+PORT_OBJS = \
+ port\string.obj \
+ port\sleep.obj
+
+OBJS = \
+ $(PORT_OBJS) \
+ connection.obj \
+ prepared_statement.obj \
+ transaction.obj \
+ result.obj \
+ except.obj
+
+DLL_PORT_OBJS = \
+ port\string.dllobj \
+ port\sleep.dllobj
+
+DLL_OBJS = \
+ $(DLL_PORT_OBJS) \
+ connection.dllobj \
+ prepared_statement.dllobj \
+ transaction.dllobj \
+ result.dllobj \
+ except.dllobj \
+ port\sqlite3xx.dllobj
+
+local_all: $(LIBRARIES)
+
+!INCLUDE $(TOPDIR)\makefiles\nmake\sub.mk
+
+sqlite3xx.lib: $(OBJS)
+ $(LINK) /lib /nologo /out:$@ $(LDFLAGS) $(LIBS) $?
+
+sqlite3xx.dll: $(DLL_OBJS)
+ $(LINK) /DLL /nologo /out:$@ $(LDFLAGS) $(LIBS) $?
+
+local_all:
+
+local_clean:
+ @-erase $(LIBRARIES) 2>NUL
+
+local_distclean:
+
+local_test:
diff --git a/src/connection.cpp b/src/connection.cpp
new file mode 100644
index 0000000..ceb5d3e
--- /dev/null
+++ b/src/connection.cpp
@@ -0,0 +1,175 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sqlite3xx/connection.hpp"
+#include "sqlite3xx/except.hpp"
+
+#include "port/sqlite.h"
+#include "port/unused.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+#include <sstream>
+
+namespace sqlite3xx {
+
+connection::connection( ) {
+ db = NULL;
+ _internal_tno = 0;
+ _trace = false;
+}
+
+connection::connection( string filename ) :
+ _filename( filename) {
+ _internal_tno = 0;
+ _trace = false;
+ sqlite3_open( filename.c_str( ), &db );
+}
+
+connection::connection( const connection& c ) {
+ db = c.db;
+ prepared_stmts = c.prepared_stmts;
+ _internal_tno = 0;
+ _trace = false;
+}
+
+connection::~connection( ) {
+ assert( db != NULL );
+ sqlite3_close( db );
+}
+
+extern "C" void profiling_callback( void *a, const char *b, sqlite3_uint64 c ) {
+ SQLITEXX_UNUSED( a );
+ cout << "TRACE: " << b << " (time: " << c / 1000 << " ms)" << endl;
+}
+
+void connection::trace( bool __trace ) {
+ _trace = __trace;
+ if( _trace ) {
+ sqlite3_profile( db, profiling_callback, NULL );
+ } else {
+ sqlite3_profile( db, NULL, NULL );
+ }
+}
+
+ostream& operator<<( ostream& o, const connection& c ) {
+ o << "sqlite3xx::connection(" << c._filename << ")";
+ return o;
+}
+
+result connection::exec( string sql ) {
+ ostringstream s;
+ s << "internal_" << *this << "_" << ++_internal_tno;
+ prepare::declaration decl = prepare( s.str( ), sql );
+ return prepared_exec( s.str( ) );
+}
+
+result connection::prepared_exec( const string& name ) {
+ PSMap::iterator it;
+ prepared_stmt* stmt = find_prepared( name );
+ if( _trace ) cout << "TRACE: exec '" << name << "'" << endl;
+ return result( stmt->getStmt( ) );
+ // TODO: remove the prepared statement again!
+}
+
+prepared_stmt* connection::find_prepared( const string& name ) {
+ PSMap::iterator it;
+ it = prepared_stmts.find( name );
+ if( it == prepared_stmts.end( ) ) {
+ throw invalid_argument( "Unknown prepared statement '" + name + "'" );
+ }
+ return it->second;
+}
+
+prepare::declaration connection::prepare( const string& name, string sql ) {
+ PSMap::iterator it;
+ it = prepared_stmts.find( name );
+ if( it != prepared_stmts.end( ) ) {
+ if( it->second->sql( ) == sql ) {
+ ostringstream s;
+ s << "Inconsistent redefinition "
+ "of prepared statement " << name
+ << "(SQL: " << sql << ")";
+ throw new invalid_argument( s.str( ) );
+ }
+ } else {
+ prepared_stmts.insert( make_pair( name,
+ new prepared_stmt( this->db, sql.c_str( ) ) ) );
+ }
+ if( _trace ) cout << "TRACE: prepared '" << name << "' as '" << sql << "'" << endl;
+ return prepare::declaration( *this, name );
+}
+
+void connection::prepare_param_declare( const string& name, const string& sqltype, prepare::param_treatment& treatment ) {
+ prepared_stmt* stmt = find_prepared( name );
+ stmt->addparam( sqltype, treatment );
+}
+
+void connection::unprepare( string name ) {
+ prepared_stmt* stmt = find_prepared( name );
+ delete stmt;
+ prepared_stmts.erase( name );
+}
+
+void connection::prepared_reset( const string& name ) {
+ prepared_stmt* stmt = find_prepared( name );
+ stmt->reset( );
+}
+
+void connection::prepare_setparam( const string& name, const int pos, const int value ) {
+ prepared_stmt* stmt = find_prepared( name );
+ if( _trace ) cout << "TRACE: prepared '" << name << "' param '" <<
+ pos << "'" << " value: " << value << endl;
+ stmt->setparam( pos, value );
+}
+
+void connection::prepare_setparam( const string& name, const int pos, const char* value ) {
+ prepared_stmt* stmt = find_prepared( name );
+ if( _trace ) cout << "TRACE: prepared '" << name << "' param '" <<
+ pos << "'" << " value: " << value << endl;
+ stmt->setparam( pos, value );
+}
+
+void connection::prepare_setparam( const string& name, const int pos, const double value ) {
+ prepared_stmt* stmt = find_prepared( name );
+ if( _trace ) cout << "TRACE: prepared '" << name << "' param '" <<
+ pos << "'" << " value: " << value << endl;
+ stmt->setparam( pos, value );
+}
+
+void connection::prepare_setparam( const string& name, const int pos, const long value ) {
+ prepared_stmt* stmt = find_prepared( name );
+ if( _trace ) cout << "TRACE: prepared '" << name << "' param '" <<
+ pos << "'" << " value: " << value << endl;
+ stmt->setparam( pos, value );
+}
+
+void connection::prepare_setparam( const string& name, const int pos, const uintmax_t value ) {
+ prepared_stmt* stmt = find_prepared( name );
+ if( _trace ) cout << "TRACE: prepared '" << name << "' param '" <<
+ pos << "'" << " value: " << value << endl;
+ stmt->setparam( pos, value );
+}
+
+} /* namespace sqlite3xx */
diff --git a/src/except.cpp b/src/except.cpp
new file mode 100644
index 0000000..cda8c7f
--- /dev/null
+++ b/src/except.cpp
@@ -0,0 +1,52 @@
+/*
+ sqlite3xx - sqlite3 C++ layer, following ideas of libpqxx
+ Copyright (C) 2009 Andreas Baumann
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "sqlite3xx/except.hpp"
+
+namespace sqlite3xx {
+
+sql_error::sql_error( ) :
+ runtime_error( "failed query" ),
+ _m( ),
+ _q( ) {
+}
+
+sql_error::sql_error( string& __m ) :
+ runtime_error( __m ),
+ _m( __m ),
+ _q( ) {
+}
+
+sql_error::sql_error( string& __m, string& q ) :
+ runtime_error( __m ),
+ _m( __m ),
+ _q( q ) {
+}
+
+sql_error::~sql_error( ) throw( ){
+}
+
+const string& sql_error::msg( ) const throw( ) {
+ return _m;
+}
+
+const string& sql_error::query( ) const throw( ) {
+ return _q;
+}
+
+} /* namespace sqlite3xx */
diff --git a/src/port/sleep.c b/src/port/sleep.c
new file mode 100644
index 0000000..4ab1966
--- /dev/null
+++ b/src/port/sleep.c
@@ -0,0 +1,43 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "port/sleep.h"
+
+/**
+ * There are different sleep functions on POSIX and WIN32 systems.
+ */
+
+#ifdef _WIN32
+#define WIN32_MEAN_AND_LEAN
+#include <windows.h> /* for Sleep */
+#else
+#include <unistd.h> /* for sleep */
+#endif
+
+void sqlitexx_port_sleep( const unsigned int seconds ) {
+#ifdef _WIN32
+ Sleep( seconds * 1000 );
+#else
+ sleep( seconds );
+#endif
+}
+
diff --git a/src/port/sleep.h b/src/port/sleep.h
new file mode 100644
index 0000000..8320f43
--- /dev/null
+++ b/src/port/sleep.h
@@ -0,0 +1,36 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __PORT_SLEEP_H
+#define __PORT_SLEEP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sqlitexx_port_sleep( const unsigned int seconds );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef __PORT_SLEEP_H */
diff --git a/src/port/sqlite.h b/src/port/sqlite.h
new file mode 100644
index 0000000..23bdc86
--- /dev/null
+++ b/src/port/sqlite.h
@@ -0,0 +1,32 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __PORT_SQLITE_H
+#define __PORT_SQLITE_H
+
+/* sqlite3_xxx since 3.5.0 */
+#if SQLITE_VERSION_NUMBER < 3005000
+typedef sqlite_int64 sqlite3_int64;
+typedef sqlite_uint64 sqlite3_uint64;
+#endif
+
+#endif /* ifndef __PORT_SQLITE_H */
diff --git a/src/port/sqlite3xx.cpp b/src/port/sqlite3xx.cpp
new file mode 100755
index 0000000..384a1d4
--- /dev/null
+++ b/src/port/sqlite3xx.cpp
@@ -0,0 +1,42 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef _WIN32
+
+#ifdef BUILD_SHARED
+
+/* entry point for DLL on Windows */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+BOOL APIENTRY DllMain( HANDLE, DWORD, LPVOID ) {
+ return TRUE;
+}
+
+#else
+#error DLL entry poing makesonly sense for a DLL, not for a static library!
+#endif /* defined BUILD_SHARED */
+
+#else
+#error DLL building makes no sence on a non-Windows platform!
+#endif /* !defined _WIN32 */
diff --git a/src/port/string.c b/src/port/string.c
new file mode 100644
index 0000000..e561ebb
--- /dev/null
+++ b/src/port/string.c
@@ -0,0 +1,43 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "port/string.h"
+
+/**
+ * strdup is not always part of the C library or they need insane flags to
+ * be set which would enable too many non-standard things.
+ */
+
+#if !defined HAVE_STRDUP || defined TEST_STRDUP
+
+#include <stdlib.h> /* for malloc, NULL */
+
+char *sqlitexx_port_strdup( const char *s ) {
+ char *d;
+ d = (char *)malloc( strlen( s ) + 1 );
+ if( d == NULL ) return NULL;
+ strcpy( d, s );
+ return d;
+}
+
+#endif /* !defined HAVE_STRDUP || defined TEST_STRDUP */
+
diff --git a/src/port/string.h b/src/port/string.h
new file mode 100644
index 0000000..2b4668b
--- /dev/null
+++ b/src/port/string.h
@@ -0,0 +1,57 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __PORT_STRING_H
+#define __PORT_STRING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "port/sys_internal.h"
+
+#include <string.h>
+
+/* on some platforms we must also include the old strings.h to get
+ * functions like str(n)casecmp */
+#ifdef HAVE_STRINGS_H
+#include <strings.h> /* for strcasecmp and strncasecmp */
+#endif
+
+#include <sys/types.h> /* for size_t */
+
+#if defined _WIN32
+#include <memory.h> /* for memcpy */
+#endif
+
+#if !defined HAVE_STRDUP || defined TEST_STRDUP
+char *sqlitexx_port_strdup( const char *s );
+#endif
+#if !defined HAVE_STRDUP
+#define strdup sqlitexx_port_strdup
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef __PORT_STRING_H */
diff --git a/src/port/sys_internal.h b/src/port/sys_internal.h
new file mode 100644
index 0000000..5b6a0b2
--- /dev/null
+++ b/src/port/sys_internal.h
@@ -0,0 +1,136 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef SQLITE3XX_SYS_INTERNAL_H
+#define SQLITE3XX_SYS_INTERNAL_H
+
+#if defined LINUX
+#if OS_MAJOR_VERSION == 2
+#if OS_MINOR_VERSION == 6
+#define _XOPEN_SOURCE 600
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* defined OS_MINOR_VERSION == 6 */
+#else
+ #error unknown platform
+#endif /* defined OS_MAJOR_VERSION == 2 */
+#endif /* defined LINUX */
+
+#if defined FREEBSD
+#if OS_MAJOR_VERSION == 7
+#if OS_MINOR_VERSION >= 0 && OS_MINOR_VERSION <= 2
+#define _XOPEN_SOURCE 600
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* defined OS_MINOR_VERSION >= 0 && OS_MINOR_VERSION <= 2 */
+#else
+#if OS_MAJOR_VERSION == 6
+#if OS_MINOR_VERSION == 2
+#define _XOPEN_SOURCE 600
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* defined OS_MINOR_VERSION == 2 */
+#else
+ #error unknown platform
+#endif /* defined OS_MAJOR_VERSION == 6 */
+#endif /* defined OS_MAJOR_VERSION == 7 */
+#endif /* defined FREEBSD */
+
+#if defined OPENBSD
+#if OS_MAJOR_VERSION == 4
+#if OS_MINOR_VERSION >= 2 && OS_MINOR_VERSION <= 5
+#define _XOPEN_SOURCE 600
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* defined OS_MINOR_VERSION >= 2 && OS_MINOR_VERSION <= 3 */
+#else
+ #error unknown platform
+#endif /* defined OS_MAJOR_VERSION == 4 */
+#endif /* defined OPENBSD */
+
+#if defined NETBSD
+#if OS_MAJOR_VERSION == 5
+#if OS_MINOR_VERSION == 0
+/* don't enable XOPEN_SOURCE here, we get compatibility problems
+ * with libstdc++: vgwscanf undefined
+ */
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* defined OS_MINOR_VERSION == 2 */
+#else /* defined OS_MAJOR_VERSION == 4 */
+
+#if OS_MAJOR_VERSION == 4
+#if OS_MINOR_VERSION == 0
+#define _XOPEN_SOURCE 600
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* defined OS_MINOR_VERSION == 2 */
+#else
+ #error unknown platform
+#endif /* defined OS_MAJOR_VERSION == 4 */
+#endif /* defined OS_MAJOR_VERSION == 5 */
+#endif /* defined NETBSD */
+
+#if defined SUNOS
+#if OS_MAJOR_VERSION == 5
+#if OS_MINOR_VERSION == 8
+#if !defined __cplusplus
+#define _XOPEN_SOURCE 600
+#define __EXTENSIONS__
+#endif
+#define HAVE_STRDUP
+#else
+#if OS_MINOR_VERSION == 10
+#if !defined __cplusplus
+#define _XOPEN_SOURCE 600
+#define __EXTENSIONS__
+#endif
+#define HAVE_STRDUP
+#else
+ #error unknown platform
+#endif /* OS_MINOR_VERSION == 10 */
+#endif /* OS_MINOR_VERSION == 8 */
+#else
+ #error unknown platform
+#endif /* OS_MAJOR_VERSION == 5 */
+#endif /* defined SUNOS */
+
+#if defined CYGWIN
+#if OS_MAJOR_VERSION == 5
+#if OS_MINOR_VERSION >= 0 && OS_MINOR_VERSION <= 1
+#define _XOPEN_SOURCE 600
+#else
+ #error unknown platform
+#endif /* OS_MINOR_VERSION >= 0 && OS_MINOR_VERSION <= 1 */
+#else
+ #error unknown platform
+#endif /* OS_MAJOR_VERSION == 5 */
+#endif /* defined CYGWIN */
+
+#endif /* ifndef SQLITE3XX_SYS_INTERNAL_H */
diff --git a/src/port/unused.h b/src/port/unused.h
new file mode 100644
index 0000000..241ae2d
--- /dev/null
+++ b/src/port/unused.h
@@ -0,0 +1,40 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+/* mark variables as being unused */
+
+#ifndef __PORT_UNUSED_H
+#define __PORT_UNUSED_H
+
+/**
+ * @brief Macro to avoid unused parameter messages in functions
+ *
+ * We could use __attribute__(unused) but I run into some problems
+ * on OpenBSD 4.5 with it..
+ */
+#ifdef __GNUC__
+#define SQLITEXX_UNUSED( x ) if( 0 && (x) ) { }
+#else
+#define SQLITEXX_UNUSED( x ) { }
+#endif
+
+#endif /* ifndef __PORT_UNUSED_H */
diff --git a/src/prepared_statement.cpp b/src/prepared_statement.cpp
new file mode 100644
index 0000000..4843a86
--- /dev/null
+++ b/src/prepared_statement.cpp
@@ -0,0 +1,221 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sqlite3xx/prepared_statement.hpp"
+
+#include <sstream>
+#include <cstdlib>
+#include <cassert>
+#include <cstring>
+
+#include "sqlite3xx/except.hpp"
+#include "sqlite3xx/connection.hpp"
+
+#include "port/unused.h"
+
+namespace sqlite3xx {
+
+/* declaration */
+
+prepare::declaration::declaration( connection& c, const string& stmt ) :
+ _c( c ),
+ _stmt( stmt ) {
+}
+
+const prepare::declaration&
+prepare::declaration::operator( )( const string& sql_type, param_treatment treat ) const {
+ _c.prepare_param_declare( _stmt, sql_type, treat );
+ return *this;
+}
+
+/* invocation */
+
+prepare::invocation::invocation( connection& c, transaction& t, const string& stmt ) :
+ _c( c ),
+ _t( t ),
+ _stmt( stmt ) {
+ _c.prepared_reset( _stmt );
+ _pos = 0;
+}
+
+result prepare::invocation::exec( ) const {
+ return _c.prepared_exec( _stmt );
+}
+
+prepare::invocation& prepare::invocation::setparam( const int& value, bool nonnull ) {
+ SQLITEXX_UNUSED( nonnull );
+ _pos++;
+ _c.prepare_setparam( _stmt, _pos, value );
+ return *this;
+}
+
+prepare::invocation& prepare::invocation::setparam( const char* value, bool nonnull ) {
+ SQLITEXX_UNUSED( nonnull );
+ _pos++;
+ _c.prepare_setparam( _stmt, _pos, value );
+ return *this;
+}
+
+prepare::invocation& prepare::invocation::setparam( const string& value, bool nonnull ) {
+ SQLITEXX_UNUSED( nonnull );
+ _pos++;
+ _c.prepare_setparam( _stmt, _pos, value.c_str( ) );
+ return *this;
+}
+
+prepare::invocation& prepare::invocation::setparam( const double& value, bool nonnull ) {
+ SQLITEXX_UNUSED( nonnull );
+ _pos++;
+ _c.prepare_setparam( _stmt, _pos, value );
+ return *this;
+}
+
+prepare::invocation& prepare::invocation::setparam( const long& value, bool nonnull ) {
+ SQLITEXX_UNUSED( nonnull );
+ _pos++;
+ _c.prepare_setparam( _stmt, _pos, value );
+ return *this;
+}
+
+prepare::invocation& prepare::invocation::setparam( const uintmax_t& value, bool nonnull ) {
+ SQLITEXX_UNUSED( nonnull );
+ _pos++;
+ _c.prepare_setparam( _stmt, _pos, value );
+ return *this;
+}
+
+/* prepared statement */
+
+prepared_stmt::prepared_stmt( sqlite3 *db, string __sql ) :
+ _db( db ) {
+ int rc;
+ const char *tail;
+ _sql = __sql;
+#if SQLITE_VERSION_NUMBER >= 3005000
+ rc = sqlite3_prepare_v2( db, _sql.c_str( ), -1, &_stmt, &tail );
+#else
+ rc = sqlite3_prepare( db, _sql.c_str( ), -1, &_stmt, &tail );
+#endif
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::prepared_stmt error: " << sqlite3_errmsg( _db );
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+prepared_stmt::~prepared_stmt( ) {
+ assert( _stmt != NULL );
+ sqlite3_finalize( _stmt );
+ _stmt = NULL;
+}
+
+string prepared_stmt::sql( ) {
+ return _sql;
+}
+
+void prepared_stmt::addparam( const string& sqltype, prepare::param_treatment& treatment ) {
+ parameters.push_back( param( sqltype, treatment ) );
+}
+
+void prepared_stmt::reset( ) {
+ int rc;
+ assert( _stmt != NULL );
+ rc = sqlite3_reset( _stmt );
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::reset error: " << sqlite3_errmsg( _db );
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+void prepared_stmt::setparam( const int pos, const int v ) {
+ int rc;
+ assert( _stmt != NULL );
+ rc = sqlite3_bind_int( _stmt, pos, v );
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::setparam bind error: "
+ << sqlite3_errmsg( _db ) << " (rc: " << rc << ")";
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+void prepared_stmt::setparam( const int pos, const char* v ) {
+ int rc;
+ assert( _stmt != NULL );
+ rc = sqlite3_bind_text( _stmt, pos, v, strlen( v ), SQLITE_STATIC );
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::setparam bind error: "
+ << sqlite3_errmsg( _db ) << " (rc: " << rc << ")";
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+void prepared_stmt::setparam( const int pos, const double v ) {
+ int rc;
+ assert( _stmt != NULL );
+ rc = sqlite3_bind_double( _stmt, pos, v );
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::setparam bind error: "
+ << sqlite3_errmsg( _db ) << " (rc: " << rc << ")";
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+void prepared_stmt::setparam( const int pos, const long v ) {
+ int rc;
+ assert( _stmt != NULL );
+ rc = sqlite3_bind_int64( _stmt, pos, v );
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::setparam bind error: "
+ << sqlite3_errmsg( _db ) << " (rc: " << rc << ")";
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+void prepared_stmt::setparam( const int pos, const uintmax_t v ) {
+ int rc;
+ assert( _stmt != NULL );
+ rc = sqlite3_bind_int64( _stmt, pos, v );
+ if( rc != SQLITE_OK ) {
+ ostringstream s;
+ s << "sqlite3::prepared_stmt::setparam bind error: "
+ << sqlite3_errmsg( _db ) << " (rc: " << rc << ")";
+ string msg = s.str( );
+ throw sql_error( msg, _sql );
+ }
+}
+
+sqlite3_stmt* prepared_stmt::getStmt( ) const {
+ return _stmt;
+}
+
+} /* namespace sqlite3xx */
diff --git a/src/result.cpp b/src/result.cpp
new file mode 100644
index 0000000..80406af
--- /dev/null
+++ b/src/result.cpp
@@ -0,0 +1,354 @@
+/*
+ sqlite3xx - sqlite3 C++ layer, following ideas of libpqxx
+ Copyright (C) 2009 Andreas Baumann
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "port/string.h"
+
+#include "sqlite3xx/result.hpp"
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+#include <cassert>
+#include <cstdlib>
+
+#include "sqlite3xx/except.hpp"
+
+#include "port/unused.h"
+#include "port/sleep.h"
+
+using namespace std;
+
+namespace sqlite3xx {
+
+/* field */
+
+ostream& operator<<( ostream& o, const result::field& f ) {
+ int type = f._t.column_type( f._c );
+ switch( type ) {
+ case SQLITE_INTEGER: {
+ int value = f._t.GetValueInt( f._c );
+ o << value;
+ }
+ break;
+
+ case SQLITE3_TEXT: {
+ const unsigned char* value = f._t.GetValueText( f._c );
+ o << value;
+ }
+ break;
+
+ case SQLITE_FLOAT: {
+ double value = f._t.GetValueDouble( f._c );
+ o << value;
+ }
+ break;
+
+ case SQLITE_NULL:
+ o << "(NULL)";
+ break;
+
+ default:
+ o << "(Unknown type " << type << "!)";
+ }
+ return o;
+}
+
+/* result */
+
+void result::Step( ) {
+ int rc;
+
+TRY_AGAIN_STEP:
+ rc = sqlite3_step( _stmt );
+ switch( rc ) {
+ case SQLITE_DONE:
+ if( _crow == 0 ) {
+ /* never had a result, will never read-ahead and buffer */
+ _status = st_nodata;
+ } else {
+ /* last row */
+ _status = st_lastrow;
+ _crow++;
+ }
+ break;
+
+ case SQLITE_ROW:
+ _status = st_hasdata;
+ _crow++;
+ break;
+
+ /* hotfix for ticket #13 */
+ case SQLITE_BUSY:
+ sqlitexx_port_sleep( 1 );
+ goto TRY_AGAIN_STEP;
+
+ default: {
+ ostringstream s;
+ s << "Illegal state after sqlite3_step (sqlite code: " << rc << ")";
+ string str = s.str( );
+ string msg = sqlite3_errmsg( sqlite3_db_handle( _stmt ) );
+ throw sql_error( str, msg );
+ }
+ }
+}
+
+void result::BufferData( ) {
+ const char *tmp = NULL;
+
+ _cache.resize( columns( ) + 1 );
+
+ for( size_type i = 0; i < columns( ); i++ ) {
+ CachedValue value;
+ value.type = column_type( i );
+ switch( value.type ) {
+ case SQLITE_INTEGER:
+ value.value.i = sqlite3_column_int( _stmt, i );
+ break;
+
+ case SQLITE3_TEXT:
+ /* KLUDGE: the documentation is not specific about returning NULL here (but
+ * it happens, see ticket #16). I get the feeling this is undefined behaviour,
+ * so people should not relly on it from outside. */
+ tmp = (const char *)sqlite3_column_text( _stmt, i );
+ if( tmp != NULL ) {
+ value.value.s = (unsigned char *)strdup( tmp );
+ } else {
+ value.type = SQLITE_NULL;
+ value.value.s = NULL;
+ }
+ break;
+
+ case SQLITE_FLOAT:
+ value.value.d = sqlite3_column_double( _stmt, i );
+ break;
+
+ case SQLITE_NULL:
+ value.value.s = NULL;
+ break;
+
+ default: {
+ ostringstream s;
+ s << "Illegal type " << value.type << " when buffering row " << _row;
+ string msg = s.str( );
+ throw logic_error( msg );
+ }
+ }
+ _cache.at( i ) = value;
+ }
+}
+
+void result::FillColNameMap( ) {
+ size_type i;
+ const char* colname;
+ for( i = 0; i < columns( ); i++ ) {
+ colname = sqlite3_column_name( _stmt, i );
+ _colmap.insert( make_pair( string( colname ), i ) );
+ }
+}
+
+void result::FillColTypeMap( ) {
+ size_type i;
+ _coltype.resize( columns( ) + 1 );
+ for( i = 0; i < columns( ); i++ ) {
+ _coltype.at( i ) = sqlite3_column_type( _stmt, i );
+ }
+}
+
+result::result( const result& r ) {
+ _stmt = r._stmt;
+ _status = r._status;
+ _colmap = r._colmap;
+ _coltype = r._coltype;
+ _cache = r._cache;
+ _row = r._row;
+ _crow = r._crow;
+}
+
+
+result::result( sqlite3_stmt* stmt ) {
+ _stmt = stmt;
+ _status = st_nascent;
+ _row = 0;
+ _crow = 0;
+ Step( );
+ if( _status == st_hasdata || _status == st_lastrow ) {
+ FillColNameMap( );
+ FillColTypeMap( );
+ BufferData( );
+ Step( );
+ }
+}
+
+result::~result( ) {
+ switch( _status ) {
+ case st_nascent: /* created no result fetched, weird, but ok */
+ break;
+
+ case st_nodata:
+ /* a command without result data, just reset the prepared statement
+ * so it can be used again for the next set of parameters
+ */
+ break;
+
+ case st_lastrow:
+ break;
+
+ case st_hasdata:
+ case st_nomoredata:
+ /* TODO: free row table data */
+ break;
+
+ default:
+ throw logic_error( "Illegal state in destructor" );
+ }
+}
+
+result& result::operator=( const result& r ) {
+ if( this != &r ) {
+ _stmt = r._stmt;
+ _status = r._status;
+ _colmap = r._colmap;
+ _coltype = r._coltype;
+ _cache = r._cache;
+ _row = r._row;
+ _crow = r._crow;
+ }
+ return *this;
+}
+
+result::size_type result::affected_rows( ) const {
+ switch( _status ) {
+ case st_nascent:
+ throw logic_error( "Called affected_rows() before sqlite3_step!" );
+
+ case st_nodata:
+ return sqlite3_changes( sqlite3_db_handle( _stmt ) );
+
+ case st_hasdata:
+ case st_lastrow:
+ case st_nomoredata:
+ throw logic_error( "Affected rows doesn't make sence in a query!" );
+
+ default:
+ throw logic_error( "Illegal state in affected_rows()" );
+ }
+}
+
+result::size_type result::size( ) const {
+ /* TODO: can we get this value with sqlite3_step, I doubt!
+ * at least we know from the state wheter it's 0 or 1 and more
+ */
+ switch( _status ) {
+ case st_nascent:
+ throw logic_error( "Called size() before sqlite3_step!" );
+
+ case st_nodata:
+ return 0;
+
+ case st_hasdata:
+ /* ..but we know that the result must be at least _row */
+ return _row + 2;
+
+ case st_nomoredata:
+ return _row + 1;
+
+ case st_lastrow:
+ return _row + 1;
+
+ default:
+ throw logic_error( "Illegal state in size()" );
+ }
+}
+
+result::size_type result::columns( ) const {
+ return sqlite3_column_count( _stmt );
+}
+
+const result::tuple result::operator[]( result::size_type i ) throw( ) {
+ if( _row == i ) {
+ return tuple( this, i );
+ } else if( i == _row + 1 ) {
+ _row++;
+ BufferData( );
+ Step( );
+ return tuple( this, i );
+ } else {
+ throw logic_error( "Illegal access outside scope of cursor!" );
+ }
+}
+
+result::size_type result::column_number( string name ) const {
+ ColMap::const_iterator it = _colmap.find( name );
+ if( it == _colmap.end( ) ) {
+ throw invalid_argument( "Unknown column '" + name + "' requested" );
+ }
+ return it->second;
+}
+
+int result::column_type( size_type i ) const {
+ if( _status != st_hasdata && _status != st_lastrow ) {
+ throw logic_error( "Fetching row after sqlite returned no data!" );
+ }
+ return _coltype[i];
+}
+
+/* value caching */
+
+result::CachedValue::CachedValue( const CachedValue& v ) {
+ type = v.type;
+ value = v.value;
+ if( type == SQLITE3_TEXT ) {
+ value.s = (unsigned char *)strdup( (const char *)v.value.s );
+ }
+}
+
+result::CachedValue::~CachedValue( ) {
+ if( type == SQLITE3_TEXT && value.s != NULL ) {
+ free( value.s );
+ value.s = NULL;
+ }
+}
+
+result::CachedValue& result::CachedValue::operator= ( const result::CachedValue& v ) {
+ if( this != &v ) {
+ type = v.type;
+ value = v.value;
+ if( type == SQLITE3_TEXT ) {
+ value.s = (unsigned char *)strdup( (const char *)v.value.s );
+ }
+ }
+ return *this;
+}
+
+/* const iterator for tuples */
+
+result::const_iterator result::const_iterator::operator++( int incr ) {
+ SQLITEXX_UNUSED( incr );
+ const_iterator old( *this );
+ // idx++;
+ return old;
+}
+
+bool result::const_iterator::operator<( const result::const_iterator& i ) const {
+ SQLITEXX_UNUSED( i.dummy );
+ // idx < i.idx
+ return false;
+}
+
+} /* namespace sqlite3xx */
diff --git a/src/transaction.cpp b/src/transaction.cpp
new file mode 100644
index 0000000..a06f223
--- /dev/null
+++ b/src/transaction.cpp
@@ -0,0 +1,142 @@
+/*
+ * sqlite3xx - sqlite3 C++ layer, following the ideas of libpqxx
+ * Copyright (C) 2009 Andreas Baumann
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions of
+ * the GNU Lesser General Public License, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sqlite3xx/transaction.hpp"
+
+#include <stdexcept>
+#include <sstream>
+#include <iostream>
+
+using namespace std;
+
+namespace sqlite3xx {
+
+transaction::transaction( connection &c, string name ) :
+ _c( c ),
+ _name( name ),
+ _status( st_nascent ) {
+}
+
+transaction::~transaction( ) {
+}
+
+void transaction::commit( ) {
+ switch( _status ) {
+ case st_nascent:
+ // skip, nothing to do
+ return;
+
+ case st_active:
+ // continue below, this is what we expect
+ break;
+
+ case st_committed:
+ // already commited, skip
+ // TODO: we should warn the user about double commits
+ break;
+
+ case st_aborted:
+ throw logic_error( "Attempt to commit previously aborted transaction!" );
+
+ default:
+ throw logic_error( "Illegal state in sqlite3::transaction::commit( )!" );
+ }
+
+ ostringstream s;
+ s << "COMMIT TRANSACTION trans_" << _name;
+ _c.exec( s.str( ).c_str( ) );
+ _status = st_committed;
+}
+
+void transaction::abort( ) {
+ switch( _status ) {
+ case st_nascent:
+ // skip, nothing to do
+ return;
+
+ case st_active:
+ // continue below, this is what we expect
+ break;
+
+ case st_committed:
+ throw logic_error( "Attempt to abort previously committed transaction!" );
+
+ case st_aborted:
+ // already aborted, skip
+ // TODO: we should warn the user about double commits
+
+ default:
+ throw logic_error( "Illegal state in sqlite3::transaction::abort( )!" );
+ }
+
+ ostringstream s;
+ s << "ROLLBACK TRANSACTION trans_" << _name;
+ _c.exec( s.str( ).c_str( ) );
+ _status = st_aborted;
+}
+
+void transaction::Begin( ) {
+ switch( _status ) {
+ case st_nascent:
+ break;
+
+ case st_active:
+ case st_committed:
+ case st_aborted:
+ default:
+ throw logic_error( "Illegal state in sqlite3::transaction::Begin( )!" );
+ }
+
+ ostringstream s;
+ s << "BEGIN TRANSACTION trans_" << _name;
+ _c.exec( s.str( ).c_str( ) );
+}
+
+result transaction::exec( string sql ) {
+ switch( _status ) {
+ case st_nascent:
+ Begin( );
+ break;
+
+ case st_active:
+ break;
+
+ case st_committed:
+ case st_aborted:
+ throw logic_error( "Attempt to execute query " + sql + " in a transaction " +
+ "which is already closed" );
+
+ default:
+ throw logic_error( "Illegal state in sqlite3::transaction::exec( )!" );
+ }
+
+ result r = _c.exec( sql );
+ _status = st_active;
+
+ return r;
+}
+
+prepare::invocation transaction::prepared( const string& name ) {
+ return prepare::invocation( _c, *this, name );
+}
+
+} /* namespace sqlite3xx */