// file : odb/mysql/connection.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include // std::bad_alloc #include #include #include #include #include #include #include #include using namespace std; namespace odb { namespace mysql { connection:: connection (database_type& db) : odb::connection (db), db_ (db), failed_ (false), handle_ (&mysql_), active_ (0), statement_cache_ (new statement_cache_type (*this)) { if (mysql_init (handle_) == 0) throw bad_alloc (); // Force the CLIENT_FOUND_ROWS flag so that UPDATE returns the // number of found rows, not the number of changed rows. This // is necessary to distinguish between the object-not-persistent // and nothing-changed conditions. // if (mysql_real_connect (handle_, db.host (), db.user (), db.password (), db.db (), db.port (), db.socket (), db.client_flags () | CLIENT_FOUND_ROWS) == 0) { // We cannot use translate_error() here since there is no connection // yet. // unsigned int e (mysql_errno (handle_)); string sqlstate (mysql_sqlstate (handle_)); string message (mysql_error (handle_)); mysql_close (handle_); if (e == CR_OUT_OF_MEMORY) throw bad_alloc (); throw database_exception (e, sqlstate, message); } } connection:: ~connection () { // Deallocate prepared statements before we close the connection. // statement_cache_.reset (); if (stmt_handles_.size () > 0) free_stmt_handles (); mysql_close (handle_); } transaction_impl* connection:: begin () { return new transaction_impl (connection_ptr (inc_ref (this))); } unsigned long long connection:: execute (const char* s, std::size_t n) { clear (); if (mysql_real_query (handle_, s, static_cast (n))) translate_error (*this); // Get the affected row count, if any. If the statement has a result // set (e.g., SELECT), we first need to call mysql_store_result(). // unsigned long long r (0); if (mysql_field_count (handle_) == 0) r = static_cast (mysql_affected_rows (handle_)); else { if (MYSQL_RES* rs = mysql_store_result (handle_)) { r = static_cast (mysql_num_rows (rs)); mysql_free_result (rs); } else translate_error (*this); } return r; } bool connection:: ping () { if (failed ()) return false; if (!mysql_ping (handle_)) return true; switch (mysql_errno (handle_)) { case CR_SERVER_LOST: case CR_SERVER_GONE_ERROR: { mark_failed (); return false; } default: { translate_error (*this); return false; // Never reached. } } } void connection:: clear_ () { active_->cancel (); // Should clear itself from active_. } MYSQL_STMT* connection:: alloc_stmt_handle () { MYSQL_STMT* stmt (mysql_stmt_init (handle_)); if (stmt == 0) throw bad_alloc (); return stmt; } void connection:: free_stmt_handle (MYSQL_STMT* stmt) { if (active_ == 0) mysql_stmt_close (stmt); else stmt_handles_.push_back (stmt); } void connection:: free_stmt_handles () { for (stmt_handles::iterator i (stmt_handles_.begin ()), e (stmt_handles_.end ()); i != e; ++i) { mysql_stmt_close (*i); } stmt_handles_.clear (); } } }