aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-03-07 10:21:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-03-07 10:21:07 +0200
commitc1b8b6f16e4881e57aa0da67e6f09ad71ee6099d (patch)
treeda1f5c81451d5a75f5ed12ae6752eb3feac969f7
parent2534b3aa626d6a426559c556b20faf7b69b47717 (diff)
Use RAII to free select statement results
-rw-r--r--odb/mssql/object-result.txx12
-rw-r--r--odb/mssql/object-statements.txx6
-rw-r--r--odb/mssql/statement.cxx51
-rw-r--r--odb/mssql/statement.hxx34
-rw-r--r--odb/mssql/view-result.txx6
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 <typename T>
@@ -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;