// file : odb/sqlite/statement.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include // std::memcpy #include #include // object_not_persistent #include #include #include using namespace std; namespace odb { namespace sqlite { // statement // statement:: ~statement () { sqlite3_finalize (stmt_); } statement:: statement (connection& conn, const string& s) : conn_ (conn) { if (int e = sqlite3_prepare_v2 ( conn_.handle (), s.c_str (), static_cast (s.size () + 1), &stmt_, 0)) { translate_error (e, conn_); } } statement:: statement (connection& conn, const char* s, std::size_t n) : conn_ (conn) { if (int e = sqlite3_prepare_v2 ( conn_.handle (), s, static_cast (n), &stmt_, 0)) { translate_error (e, conn_); } } 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 (i + start_param)); if (*b.is_null) { e = sqlite3_bind_null (stmt_, j); continue; } switch (b.type) { case bind::integer: { long long v (*static_cast (b.buffer)); e = sqlite3_bind_int64 (stmt_, j, static_cast (v)); break; } case bind::real: { double v (*static_cast (b.buffer)); e = sqlite3_bind_double (stmt_, j, v); break; } case bind::text: { e = sqlite3_bind_text (stmt_, j, static_cast (b.buffer), static_cast (*b.size), SQLITE_STATIC); break; } case bind::blob: { e = sqlite3_bind_blob (stmt_, j, b.buffer, static_cast (*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) { bool r (true); for (size_t i (0); i < n; ++i) { const bind& b (p[i]); int j (static_cast (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 (b.buffer) = static_cast (sqlite3_column_int64 (stmt_, j)); break; } case bind::real: { *static_cast (b.buffer) = sqlite3_column_double (stmt_, j); break; } case bind::text: case bind::blob: { *b.size = static_cast (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 // simple_statement:: simple_statement (connection& conn, const string& s) : statement (conn, s), result_set_ (stmt_ ? sqlite3_column_count (stmt_) != 0: false) { } simple_statement:: simple_statement (connection& conn, const char* s, std::size_t n) : statement (conn, s, n), result_set_ (stmt_ ? sqlite3_column_count (stmt_) != 0: false) { } unsigned long long simple_statement:: execute () { if (stmt_ == 0) // Empty statement or comment. return 0; if (int e = sqlite3_reset (stmt_)) translate_error (e, conn_); unsigned long long r (0); int e; for (e = sqlite3_step (stmt_); e == SQLITE_ROW; e = sqlite3_step (stmt_)) r++; if (e != SQLITE_DONE) translate_error (e, conn_); if (!result_set_) r = static_cast ( sqlite3_changes (conn_.handle ())); 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 ( 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 ( sqlite3_changes (conn_.handle ())); } } }