// file : odb/mysql/statement.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include #include #include #include #include // @@ tmp using namespace std; namespace odb { namespace mysql { // statement // statement:: statement (connection& conn) : conn_ (conn), stmt_ (conn_.alloc_stmt_handle ()) { } statement:: ~statement () { conn_.free_stmt_handle (stmt_); } void statement:: cancel () { } // query_statement // query_statement:: ~query_statement () { statement* as (conn_.active ()); if (cached_ || as == this) { try { free_result (); } catch (...) { } } if (as == this) conn_.active (0); } query_statement:: query_statement (connection& conn, const string& s, binding& image, MYSQL_BIND* parameters) : statement (conn), end_ (false), cached_ (false), image_ (image), image_version_ (0), parameters_ (parameters) { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_prepare (stmt_, s.c_str (), s.size ()) != 0) throw database_exception (stmt_); } void query_statement:: execute () { if (statement* a = conn_.active ()) a->cancel (); if (cached_) free_result (); end_ = false; if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); if (image_version_ != image_.version) { if (mysql_stmt_bind_result (stmt_, image_.bind)) throw database_exception (stmt_); image_version_ = image_.version; } if (parameters_ != 0) { // @@ versioning // if (mysql_stmt_bind_param (stmt_, parameters_)) throw database_exception (stmt_); } if (mysql_stmt_execute (stmt_)) { unsigned int e (mysql_stmt_errno (stmt_)); if (e == ER_LOCK_DEADLOCK) throw deadlock (); else throw database_exception (stmt_); } conn_.active (this); } void query_statement:: cache () { if (!cached_ && !end_) { if (mysql_stmt_store_result (stmt_)) { std::cerr << "store result failed" << std::endl; throw database_exception (stmt_); } cached_ = true; } } query_statement::result query_statement:: fetch () { // If the result was cached the image can grow between calls // to fetch() as a result of other statements execution. // if (cached_ && image_version_ != image_.version) { if (mysql_stmt_bind_result (stmt_, image_.bind)) throw database_exception (stmt_); image_version_ = image_.version; } int r (mysql_stmt_fetch (stmt_)); switch (r) { case 0: { return success; } case MYSQL_NO_DATA: { end_ = true; return no_data; } case MYSQL_DATA_TRUNCATED: { return truncated; } default: { throw database_exception (stmt_); } } } void query_statement:: refetch () { // Re-fetch columns that were truncated. // for (size_t i (0); i < image_.count; ++i) { if (*image_.bind[i].error) { *image_.bind[i].error = 0; if (mysql_stmt_fetch_column ( stmt_, image_.bind + i, static_cast (i), 0)) throw database_exception (stmt_); } } } void query_statement:: free_result () { end_ = true; cached_ = false; if (mysql_stmt_free_result (stmt_)) throw database_exception (stmt_); } void query_statement:: cancel () { // If we cached the result, don't free it just yet. // if (!cached_) free_result (); conn_.active (0); } // persist_statement // persist_statement:: ~persist_statement () { } persist_statement:: persist_statement (connection& conn, const string& s, binding& image) : statement (conn), image_ (image), version_ (0) { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_prepare (stmt_, s.c_str (), s.size ()) != 0) throw database_exception (stmt_); } void persist_statement:: execute () { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); if (version_ != image_.version) { if (mysql_stmt_bind_param (stmt_, image_.bind)) throw database_exception (stmt_); version_ = image_.version; } if (mysql_stmt_execute (stmt_)) { switch (mysql_stmt_errno (stmt_)) { case ER_DUP_ENTRY: { throw object_already_persistent (); } case ER_LOCK_DEADLOCK: { throw deadlock (); } default: { throw database_exception (stmt_); } } } } // find_statement // find_statement:: ~find_statement () { if (conn_.active () == this) { try { free_result (); } catch (...) { } } } find_statement:: find_statement (connection& conn, const string& s, binding& id, binding& image) : statement (conn), id_ (id), id_version_ (0), image_ (image), image_version_ (0) { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_prepare (stmt_, s.c_str (), s.size ()) != 0) throw database_exception (stmt_); } find_statement::result find_statement:: execute () { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); if (id_version_ != id_.version) { if (mysql_stmt_bind_param (stmt_, id_.bind)) throw database_exception (stmt_); id_version_ = id_.version; } if (image_version_ != image_.version) { if (mysql_stmt_bind_result (stmt_, image_.bind)) throw database_exception (stmt_); image_version_ = image_.version; } if (mysql_stmt_execute (stmt_)) { unsigned int e (mysql_stmt_errno (stmt_)); if (e == ER_LOCK_DEADLOCK) throw deadlock (); else throw database_exception (stmt_); } conn_.active (this); int r (mysql_stmt_fetch (stmt_)); switch (r) { case 0: { return success; } case MYSQL_NO_DATA: { free_result (); return no_data; } case MYSQL_DATA_TRUNCATED: { return truncated; } default: { throw database_exception (stmt_); } } } void find_statement:: refetch () { // Re-fetch columns that were truncated. // for (size_t i (0); i < image_.count; ++i) { if (*image_.bind[i].error) { *image_.bind[i].error = 0; if (mysql_stmt_fetch_column ( stmt_, image_.bind + i, static_cast (i), 0)) throw database_exception (stmt_); } } } void find_statement:: free_result () { if (mysql_stmt_free_result (stmt_)) throw database_exception (stmt_); conn_.active (0); } void find_statement:: cancel () { free_result (); } // update_statement // update_statement:: ~update_statement () { } update_statement:: update_statement (connection& conn, const string& s, binding& id, binding& image) : statement (conn), id_ (id), id_version_ (0), image_ (image), image_version_ (0) { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_prepare (stmt_, s.c_str (), s.size ()) != 0) throw database_exception (stmt_); } void update_statement:: execute () { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); if (image_version_ != image_.version || id_version_ != id_.version) { // Here we assume that the last element in image_.bind is the // id parameter. // if (mysql_stmt_bind_param (stmt_, image_.bind)) throw database_exception (stmt_); id_version_ = id_.version; image_version_ = image_.version; } if (mysql_stmt_execute (stmt_)) { unsigned int e (mysql_stmt_errno (stmt_)); if (e == ER_LOCK_DEADLOCK) throw deadlock (); else throw database_exception (stmt_); } my_ulonglong r (mysql_stmt_affected_rows (stmt_)); if (r > 0) return; if (r == 0) throw object_not_persistent (); else throw database_exception (stmt_); } // erase_statement // erase_statement:: ~erase_statement () { } erase_statement:: erase_statement (connection& conn, const string& s, binding& id) : statement (conn), id_ (id), version_ (0) { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_prepare (stmt_, s.c_str (), s.size ()) != 0) throw database_exception (stmt_); } void erase_statement:: execute () { if (statement* a = conn_.active ()) a->cancel (); if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); if (version_ != id_.version) { if (mysql_stmt_bind_param (stmt_, id_.bind)) throw database_exception (stmt_); version_ = id_.version; } if (mysql_stmt_execute (stmt_)) { unsigned int e (mysql_stmt_errno (stmt_)); if (e == ER_LOCK_DEADLOCK) throw deadlock (); else throw database_exception (stmt_); } my_ulonglong r (mysql_stmt_affected_rows (stmt_)); if (r > 0) return; if (r == 0) throw object_not_persistent (); else throw database_exception (stmt_); } // object_statements_base // object_statements_base:: ~object_statements_base () { } } }