From c1b8b6f16e4881e57aa0da67e6f09ad71ee6099d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 7 Mar 2012 10:21:07 +0200 Subject: Use RAII to free select statement results --- odb/mssql/object-result.txx | 12 ++++++++++ odb/mssql/object-statements.txx | 6 ++++- odb/mssql/statement.cxx | 51 ++++++++++++++--------------------------- odb/mssql/statement.hxx | 34 ++++++++++++++++++++++++++- odb/mssql/view-result.txx | 6 +++++ 5 files changed, 73 insertions(+), 36 deletions(-) diff --git a/odb/mssql/object-result.txx b/odb/mssql/object-result.txx index efaeae9..9f6b2d0 100644 --- a/odb/mssql/object-result.txx +++ b/odb/mssql/object-result.txx @@ -31,6 +31,9 @@ namespace odb } delete image_copy_; + + if (!this->end_) + statement_->free_result (); } template @@ -129,7 +132,10 @@ namespace odb } if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); this->end_ = true; + } else { cc.callback = &change_callback; @@ -184,6 +190,9 @@ namespace odb cc.callback = 0; } + if (!this->end_) + statement_->free_result (); + delete image_copy_; } @@ -252,7 +261,10 @@ namespace odb } if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); this->end_ = true; + } else { cc.callback = &change_callback; diff --git a/odb/mssql/object-statements.txx b/odb/mssql/object-statements.txx index c8753d2..01249d9 100644 --- a/odb/mssql/object-statements.txx +++ b/odb/mssql/object-statements.txx @@ -87,6 +87,10 @@ namespace odb if (!object_traits::find_ (*this, l.id)) throw object_not_persistent (); + // Our find_() version delays result freeing. + // + auto_result ar (*find_); + object_traits::callback (db, *l.obj, callback_event::pre_load); // Our calls to init/load below can result in additional delayed @@ -95,7 +99,7 @@ namespace odb // object_traits::init (*l.obj, image (), &db); find_->stream_result (); - find_->free_result (); // Our find_() version delays result freeing. + ar.free (); object_traits::load_ (*this, *l.obj); // Load containers, etc. if (!delayed_.empty ()) diff --git a/odb/mssql/statement.cxx b/odb/mssql/statement.cxx index 8c3870d..e6cd7b8 100644 --- a/odb/mssql/statement.cxx +++ b/odb/mssql/statement.cxx @@ -694,13 +694,17 @@ namespace odb // // select_statement // + select_statement:: + ~select_statement () + { + } select_statement:: select_statement (connection& conn, const string& t, binding& param, binding& result) - : statement (conn, t), result_ (result), executed_ (false) + : statement (conn, t), result_ (result) { bind_param (param.bind, param.count); first_long_ = bind_result (result.bind, result.count); @@ -712,7 +716,7 @@ namespace odb binding& param, binding& result, bool ct) - : statement (conn, t, ct), result_ (result), executed_ (false) + : statement (conn, t, ct), result_ (result) { bind_param (param.bind, param.count); first_long_ = bind_result (result.bind, result.count); @@ -720,7 +724,7 @@ namespace odb select_statement:: select_statement (connection& conn, const string& t, binding& result) - : statement (conn, t), result_ (result), executed_ (false) + : statement (conn, t), result_ (result) { first_long_ = bind_result (result.bind, result.count); } @@ -730,38 +734,18 @@ namespace odb const char* t, binding& result, bool ct) - : statement (conn, t, ct), result_ (result), executed_ (false) + : statement (conn, t, ct), result_ (result) { first_long_ = bind_result (result.bind, result.count); } - select_statement:: - ~select_statement () - { - if (executed_) - { - try - { - free_result (); - } - catch (...) - { - } - } - } - void select_statement:: execute () { - if (executed_) - free_result (); - SQLRETURN r (statement::execute ()); if (!SQL_SUCCEEDED (r)) translate_error (r, conn_, stmt_); - - executed_ = true; } select_statement::result select_statement:: @@ -786,17 +770,16 @@ namespace odb void select_statement:: free_result () { - if (executed_) - { - // If we cannot close the cursor, there is no point in trying again. - // - executed_ = false; - - SQLRETURN r (SQLCloseCursor (stmt_)); + // Use SQLFreeStmt(SQL_CLOSE) instead of SQLCloseCursor() to avoid an + // error if a cursor is already closed. This can happens, for example, + // if we are trying to close the cursor after the transaction has been + // committed (e.g., when destroying the query result) which also closes + // the cursor. + // + SQLRETURN r (SQLFreeStmt (stmt_, SQL_CLOSE)); - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); } // diff --git a/odb/mssql/statement.hxx b/odb/mssql/statement.hxx index eb95a35..86178e6 100644 --- a/odb/mssql/statement.hxx +++ b/odb/mssql/statement.hxx @@ -147,7 +147,39 @@ namespace odb private: binding& result_; std::size_t first_long_; // First long data column. - bool executed_; + }; + + struct LIBODB_MSSQL_EXPORT auto_result + { + explicit auto_result (select_statement& s): s_ (&s) {} + ~auto_result () {free ();} + + // Extended interface to support delayed freeing. + // + auto_result (): s_ (0) {} + + void + set (select_statement& s) {s_ = &s;} + + void + free () + { + if (s_ != 0) + { + s_->free_result (); + s_ = 0; + } + } + + void + release () {s_ = 0;} + + private: + auto_result (const auto_result&); + auto_result& operator= (const auto_result&); + + private: + select_statement* s_; }; class LIBODB_MSSQL_EXPORT insert_statement: public statement diff --git a/odb/mssql/view-result.txx b/odb/mssql/view-result.txx index de64438..a9b28a3 100644 --- a/odb/mssql/view-result.txx +++ b/odb/mssql/view-result.txx @@ -24,6 +24,9 @@ namespace odb cc.context = 0; } + if (!this->end_) + statement_->free_result (); + delete image_copy_; } @@ -92,7 +95,10 @@ namespace odb } if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); this->end_ = true; + } else { cc.callback = &change_callback; -- cgit v1.1