From b3a299fbbd80e69554b37d0ae30cf2c45a98d1a6 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 2 Oct 2013 08:29:06 +0200 Subject: Add support for SQLite 3.3.6 That's what is still shipped with RHEL5. --- odb/sqlite/connection.cxx | 14 +++++- odb/sqlite/database.hxx | 9 ++++ odb/sqlite/statement.cxx | 110 +++++++++++++++++++++++++++++++++++++++++++++- odb/sqlite/statement.hxx | 6 ++- 4 files changed, 134 insertions(+), 5 deletions(-) (limited to 'odb') diff --git a/odb/sqlite/connection.cxx b/odb/sqlite/connection.cxx index f4e7259..188d59f 100644 --- a/odb/sqlite/connection.cxx +++ b/odb/sqlite/connection.cxx @@ -51,12 +51,22 @@ namespace odb f |= SQLITE_OPEN_NOMUTEX; #endif - const string& vfs (db.vfs ()); - sqlite3* h (0); + + // sqlite3_open_v2() was only addedin SQLite 3.5.0. + // +#if SQLITE_VERSION_NUMBER >= 3005000 + const string& vfs (db.vfs ()); int e ( sqlite3_open_v2 ( n.c_str (), &h, f, (vfs.empty () ? 0 : vfs.c_str ()))); +#else + // Readonly opening not supported in SQLite earlier than 3.5.0. + // + assert ((f & SQLITE_OPEN_READONLY) == 0); + int e (sqlite3_open (n.c_str (), &h)); +#endif + handle_.reset (h); if (e != SQLITE_OK) diff --git a/odb/sqlite/database.hxx b/odb/sqlite/database.hxx index ee758e5..d2053e5 100644 --- a/odb/sqlite/database.hxx +++ b/odb/sqlite/database.hxx @@ -27,6 +27,15 @@ #include +// We use the sqlite3_open_v2() flags in our interface. Define them +// for SQLite earlier that 3.5.0. +// +#if SQLITE_VERSION_NUMBER < 3005000 +# define SQLITE_OPEN_READONLY 0x00000001 +# define SQLITE_OPEN_READWRITE 0x00000002 +# define SQLITE_OPEN_CREATE 0x00000004 +#endif + namespace odb { namespace sqlite diff --git a/odb/sqlite/statement.cxx b/odb/sqlite/statement.cxx index de71e12..a09e467 100644 --- a/odb/sqlite/statement.cxx +++ b/odb/sqlite/statement.cxx @@ -43,6 +43,11 @@ namespace odb { int e; sqlite3_stmt* stmt (0); + + // sqlite3_prepare_v2() is only available since SQLite 3.3.9 + // but is buggy until 3.3.11. + // +#if SQLITE_VERSION_NUMBER >= 3003011 while ((e = sqlite3_prepare_v2 (conn_.handle (), text, static_cast (text_size), @@ -51,11 +56,23 @@ namespace odb { conn_.wait (); } +#else + e = sqlite3_prepare (conn_.handle (), + text, + static_cast (text_size), + &stmt, + 0); +#endif if (e != SQLITE_OK) translate_error (e, conn_); stmt_.reset (stmt); + +#if SQLITE_VERSION_NUMBER < 3005003 + text_.assign (text, text_size); +#endif + active_ = false; prev_ = 0; @@ -73,7 +90,13 @@ namespace odb const char* statement:: text () const { + // sqlite3_sql() is only available since 3.5.3. + // +#if SQLITE_VERSION_NUMBER >= 3005003 return sqlite3_sql (stmt_); +#else + return text_.c_str (); +#endif } void statement:: @@ -100,7 +123,15 @@ namespace odb case bind::integer: { long long v (*static_cast (b.buffer)); - e = sqlite3_bind_int64 (stmt_, j, static_cast (v)); + e = sqlite3_bind_int64 (stmt_, + j, + // Prior to 3.5.0, sqlite3_int64 was called sqlite_int64. +#if SQLITE_VERSION_NUMBER >= 3005000 + static_cast (v) +#else + static_cast (v) +#endif + ); break; } case bind::real: @@ -295,10 +326,42 @@ namespace odb for (; e == SQLITE_ROW; e = sqlite3_step (stmt_)) r++; + // sqlite3_step() will return a detailed error code only if we used + // sqlite3_prepare_v2(). Otherwise, sqlite3_reset() returns the + // error. + // +#if SQLITE_VERSION_NUMBER >= 3003011 sqlite3_reset (stmt_); if (e != SQLITE_DONE) translate_error (e, conn_); +#else + e = sqlite3_reset (stmt_); + + if (e != SQLITE_OK) + { + // If the schema has changed, try to re-prepare and re-execute the + // statement. That's what newer versions of SQLite do automatically. + // + if (e == SQLITE_SCHEMA) + { + sqlite3_stmt* stmt (0); + e = sqlite3_prepare (h, + text_.c_str (), + static_cast (text_.size () + 1), + &stmt, + 0); + + if (e != SQLITE_OK) + translate_error (e, conn_); + + stmt_.reset (stmt); + return execute (); // Try again by recursively calling ourselves. + } + else + translate_error (e, conn_); + } +#endif if (!result_set_) r = static_cast (sqlite3_changes (h)); @@ -393,10 +456,23 @@ namespace odb if (e != SQLITE_ROW) { - reset (); done_ = true; + // sqlite3_step() will return a detailed error code only if we used + // sqlite3_prepare_v2(). Otherwise, sqlite3_reset() returns the + // error. + // +#if SQLITE_VERSION_NUMBER >= 3003011 + reset (); + if (e != SQLITE_DONE) +#else + e = sqlite3_reset (stmt_); + list_remove (); + active_ = false; + + if (e != SQLITE_OK) +#endif translate_error (e, conn_); } } @@ -468,9 +544,19 @@ namespace odb e = sqlite3_step (stmt_); #endif + // sqlite3_step() will return a detailed error code only if we used + // sqlite3_prepare_v2(). Otherwise, sqlite3_reset() returns the + // error. + // +#if SQLITE_VERSION_NUMBER >= 3003011 sqlite3_reset (stmt_); if (e != SQLITE_DONE) +#else + e = sqlite3_reset (stmt_); + + if (e != SQLITE_OK) +#endif { // SQLITE_CONSTRAINT error code covers more than just a duplicate // primary key. Unfortunately, there is nothing more precise that @@ -539,9 +625,19 @@ namespace odb e = sqlite3_step (stmt_); #endif + // sqlite3_step() will return a detailed error code only if we used + // sqlite3_prepare_v2(). Otherwise, sqlite3_reset() returns the + // error. + // +#if SQLITE_VERSION_NUMBER >= 3003011 sqlite3_reset (stmt_); if (e != SQLITE_DONE) +#else + e = sqlite3_reset (stmt_); + + if (e != SQLITE_OK) +#endif translate_error (e, conn_); return static_cast (sqlite3_changes (h)); @@ -593,9 +689,19 @@ namespace odb e = sqlite3_step (stmt_); #endif + // sqlite3_step() will return a detailed error code only if we used + // sqlite3_prepare_v2(). Otherwise, sqlite3_reset() returns the + // error. + // +#if SQLITE_VERSION_NUMBER >= 3003011 sqlite3_reset (stmt_); if (e != SQLITE_DONE) +#else + e = sqlite3_reset (stmt_); + + if (e != SQLITE_OK) +#endif translate_error (e, conn_); return static_cast (sqlite3_changes (h)); diff --git a/odb/sqlite/statement.hxx b/odb/sqlite/statement.hxx index eb55e58..ccb4762 100644 --- a/odb/sqlite/statement.hxx +++ b/odb/sqlite/statement.hxx @@ -124,6 +124,10 @@ namespace odb connection_type& conn_; auto_handle stmt_; +#if SQLITE_VERSION_NUMBER < 3005003 + std::string text_; +#endif + bool active_; private: @@ -132,7 +136,7 @@ namespace odb // Doubly-linked list of active statements. // - private: + protected: void list_add () { -- cgit v1.1