aboutsummaryrefslogtreecommitdiff
path: root/odb/sqlite/statement.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-03-22 15:49:33 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-03-22 15:49:33 +0200
commit878a448f86ddd60e5eb7778e88edd965003ea480 (patch)
treea0efeef1d7fb9af58d9d73a1cb8aa39f6179b586 /odb/sqlite/statement.cxx
parentb1a6710e7d396538617550f1d00b4db2575485c7 (diff)
Implement the rest of statements
Diffstat (limited to 'odb/sqlite/statement.cxx')
-rw-r--r--odb/sqlite/statement.cxx296
1 files changed, 293 insertions, 3 deletions
diff --git a/odb/sqlite/statement.cxx b/odb/sqlite/statement.cxx
index e7d197b..417a746 100644
--- a/odb/sqlite/statement.cxx
+++ b/odb/sqlite/statement.cxx
@@ -3,6 +3,11 @@
// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <cstring> // std::memcpy
+#include <cassert>
+
+#include <odb/exceptions.hxx> // object_not_persistent
+
#include <odb/sqlite/statement.hxx>
#include <odb/sqlite/connection.hxx>
#include <odb/sqlite/error.hxx>
@@ -17,6 +22,12 @@ namespace odb
//
statement::
+ ~statement ()
+ {
+ sqlite3_finalize (stmt_);
+ }
+
+ statement::
statement (connection& conn, const string& s)
: conn_ (conn)
{
@@ -46,12 +57,124 @@ namespace odb
}
}
+ void statement::
+ bind_param (const bind* p, size_t n, size_t start_param)
+ {
+ int e (SQLITE_OK);
+ start_param++; // SQLite parameters are counted from 1.
+ for (size_t i (0); e == SQLITE_OK && i < n; ++i)
+ {
+ const bind& b (p[i]);
+ int j (static_cast<int> (i + start_param));
- statement::
- ~statement ()
+ if (*b.is_null)
+ {
+ e = sqlite3_bind_null (stmt_, j);
+ continue;
+ }
+
+ switch (b.type)
+ {
+ case bind::integer:
+ {
+ long long v (*static_cast<long long*> (b.buffer));
+ e = sqlite3_bind_int64 (stmt_, j, static_cast<sqlite3_int64> (v));
+ break;
+ }
+ case bind::real:
+ {
+ double v (*static_cast<double*> (b.buffer));
+ e = sqlite3_bind_double (stmt_, j, v);
+ break;
+ }
+ case bind::text:
+ {
+ e = sqlite3_bind_text (stmt_,
+ j,
+ static_cast<const char*> (b.buffer),
+ static_cast<int> (*b.size),
+ SQLITE_STATIC);
+ break;
+ }
+ case bind::blob:
+ {
+ e = sqlite3_bind_blob (stmt_,
+ j,
+ b.buffer,
+ static_cast<int> (*b.size),
+ SQLITE_STATIC);
+ break;
+ }
+ }
+ }
+
+ if (e != SQLITE_OK)
+ translate_error (e, conn_);
+ }
+
+ bool statement::
+ bind_result (const bind* p, size_t n, bool truncated)
{
- sqlite3_finalize (stmt_);
+ bool r (true);
+
+ for (size_t i (0); i < n; ++i)
+ {
+ const bind& b (p[i]);
+ int j (static_cast<int> (i));
+
+ if (truncated && !*b.truncated)
+ continue;
+
+ *b.truncated = false;
+
+ // Check for NULL unless we are reloading a truncated result.
+ //
+ if (!truncated)
+ {
+ *b.is_null = sqlite3_column_type (stmt_, j) != SQLITE_NULL;
+
+ if (*b.is_null)
+ continue;
+ }
+
+ switch (b.type)
+ {
+ case bind::integer:
+ {
+ *static_cast<long long*> (b.buffer) =
+ static_cast<long long> (sqlite3_column_int64 (stmt_, j));
+ break;
+ }
+ case bind::real:
+ {
+ *static_cast<double*> (b.buffer) =
+ sqlite3_column_double (stmt_, j);
+ break;
+ }
+ case bind::text:
+ case bind::blob:
+ {
+ *b.size = static_cast<size_t> (sqlite3_column_bytes (stmt_, j));
+
+ if (*b.size > b.capacity)
+ {
+ *b.truncated = true;
+ r = false;
+ continue;
+ }
+
+ const void* d (b.type == bind::text
+ ? sqlite3_column_text (stmt_, j)
+ : sqlite3_column_blob (stmt_, j));
+
+ memcpy (b.buffer, d, *b.size);
+ break;
+ }
+ }
+ }
+
+ return r;
}
// simple_statement
@@ -95,5 +218,172 @@ namespace odb
return r;
}
+
+ // select_statement
+ //
+
+ select_statement::
+ select_statement (connection& conn,
+ const string& s,
+ binding& cond,
+ binding& data)
+ : statement (conn, s), cond_ (cond), data_ (data)
+ {
+ }
+
+ void select_statement::
+ execute ()
+ {
+ done_ = false;
+
+ if (int e = sqlite3_reset (stmt_))
+ translate_error (e, conn_);
+
+ bind_param (cond_.bind, cond_.count);
+ }
+
+ bool select_statement::
+ next ()
+ {
+ if (!done_)
+ {
+ int e (sqlite3_step (stmt_));
+
+ switch (e)
+ {
+ case SQLITE_DONE:
+ {
+ done_ = true;
+ break;
+ }
+ case SQLITE_ROW:
+ {
+ break;
+ }
+ default:
+ {
+ translate_error (e, conn_);
+ }
+ }
+ }
+
+ return !done_;
+ }
+
+ select_statement::result select_statement::
+ load ()
+ {
+ if (done_)
+ return no_data;
+
+ return bind_result (data_.bind, data_.count) ? success : truncated;
+ }
+
+ void select_statement::
+ reload ()
+ {
+ assert (!done_);
+
+ if (!bind_result (data_.bind, data_.count, true))
+ assert (false);
+ }
+
+ // insert_statement
+ //
+
+ insert_statement::
+ insert_statement (connection& conn, const string& s, binding& data)
+ : statement (conn, s), data_ (data)
+ {
+ }
+
+ bool insert_statement::
+ execute ()
+ {
+ if (int e = sqlite3_reset (stmt_))
+ translate_error (e, conn_);
+
+ bind_param (data_.bind, data_.count);
+
+ int e (sqlite3_step (stmt_));
+
+ if (e != SQLITE_DONE)
+ {
+ // SQLITE_CONSTRAINT error code covers more than just a duplicate
+ // primary key. Unfortunately, there is nothing more precise that
+ // we can use (even sqlite3_errmsg() returns generic "constraint
+ // failed").
+ //
+ if (e == SQLITE_CONSTRAINT)
+ return false;
+ else
+ translate_error (e, conn_);
+ }
+
+ return true;
+ }
+
+ unsigned long long insert_statement::
+ id ()
+ {
+ return static_cast<unsigned long long> (
+ sqlite3_last_insert_rowid (conn_.handle ()));
+ }
+
+ // update_statement
+ //
+
+ update_statement::
+ update_statement (connection& conn,
+ const string& s,
+ binding& cond,
+ binding& data)
+ : statement (conn, s), cond_ (cond), data_ (data)
+ {
+ }
+
+ void update_statement::
+ execute ()
+ {
+ if (int e = sqlite3_reset (stmt_))
+ translate_error (e, conn_);
+
+ bind_param (data_.bind, data_.count);
+ bind_param (cond_.bind, cond_.count, data_.count);
+
+ int e (sqlite3_step (stmt_));
+
+ if (e != SQLITE_DONE)
+ translate_error (e, conn_);
+
+ if (sqlite3_changes (conn_.handle ()) == 0)
+ throw object_not_persistent ();
+ }
+
+ // delete_statement
+ //
+
+ delete_statement::
+ delete_statement (connection& conn, const string& s, binding& cond)
+ : statement (conn, s), cond_ (cond)
+ {
+ }
+
+ unsigned long long delete_statement::
+ execute ()
+ {
+ if (int e = sqlite3_reset (stmt_))
+ translate_error (e, conn_);
+
+ bind_param (cond_.bind, cond_.count);
+
+ int e (sqlite3_step (stmt_));
+
+ if (e != SQLITE_DONE)
+ translate_error (e, conn_);
+
+ return static_cast<unsigned long long> (
+ sqlite3_changes (conn_.handle ()));
+ }
}
}