aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-08-30 16:10:02 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-08-30 16:10:30 +0200
commit9fce9a7250f63a2a3cceeb0aac7b22d5dd7e6915 (patch)
treedd20f89ddd286f663aaf881835970c03cc628855
parent44a26d189e186ac10c4a80c4dbb68d65927b12a9 (diff)
Implement uniform handle management across all databases
Also use the auto_handle template instead of the raw handle in connection, statement, and result classes. This removes a lot of brittle "exception safety guarantee" code that we had in those classes.
-rw-r--r--odb/pgsql/auto-handle.cxx26
-rw-r--r--odb/pgsql/auto-handle.hxx92
-rw-r--r--odb/pgsql/connection.cxx18
-rw-r--r--odb/pgsql/connection.hxx6
-rw-r--r--odb/pgsql/makefile1
-rw-r--r--odb/pgsql/result-ptr.hxx76
-rw-r--r--odb/pgsql/statement.cxx128
-rw-r--r--odb/pgsql/statement.hxx5
-rw-r--r--odb/pgsql/transaction-impl.cxx11
9 files changed, 190 insertions, 173 deletions
diff --git a/odb/pgsql/auto-handle.cxx b/odb/pgsql/auto-handle.cxx
new file mode 100644
index 0000000..08e3006
--- /dev/null
+++ b/odb/pgsql/auto-handle.cxx
@@ -0,0 +1,26 @@
+// file : odb/pgsql/auto-handle.cxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <libpq-fe.h>
+
+#include <odb/pgsql/auto-handle.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ void handle_traits<PGconn>::
+ release (PGconn* h)
+ {
+ PQfinish (h);
+ }
+
+ void handle_traits<PGresult>::
+ release (PGresult* h)
+ {
+ PQclear (h);
+ }
+ }
+}
diff --git a/odb/pgsql/auto-handle.hxx b/odb/pgsql/auto-handle.hxx
new file mode 100644
index 0000000..2ed58e5
--- /dev/null
+++ b/odb/pgsql/auto-handle.hxx
@@ -0,0 +1,92 @@
+// file : odb/pgsql/auto-handle.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_PGSQL_AUTO_HANDLE_HXX
+#define ODB_PGSQL_AUTO_HANDLE_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/pgsql/version.hxx>
+#include <odb/pgsql/pgsql-fwd.hxx> // PGconn, PGresult
+
+#include <odb/pgsql/details/export.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ template <typename H>
+ struct handle_traits;
+
+ template <>
+ struct LIBODB_PGSQL_EXPORT handle_traits<PGconn>
+ {
+ static void
+ release (PGconn*);
+ };
+
+ template <>
+ struct LIBODB_PGSQL_EXPORT handle_traits<PGresult>
+ {
+ static void
+ release (PGresult*);
+ };
+
+ template <typename H>
+ class auto_handle
+ {
+ public:
+ auto_handle (H* h = 0)
+ : h_ (h)
+ {
+ }
+
+ ~auto_handle ()
+ {
+ if (h_ != 0)
+ handle_traits<H>::release (h_);
+ }
+
+ H*
+ get () const
+ {
+ return h_;
+ }
+
+ void
+ reset (H* h = 0)
+ {
+ if (h_ != 0)
+ handle_traits<H>::release (h_);
+
+ h_ = h;
+ }
+
+ H*
+ release ()
+ {
+ H* h (h_);
+ h_ = 0;
+ return h;
+ }
+
+ operator H* ()
+ {
+ return h_;
+ }
+
+ private:
+ auto_handle (const auto_handle&);
+ auto_handle& operator= (const auto_handle&);
+
+ private:
+ H* h_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_PGSQL_AUTO_HANDLE_HXX
diff --git a/odb/pgsql/connection.cxx b/odb/pgsql/connection.cxx
index be88446..6f0feaf 100644
--- a/odb/pgsql/connection.cxx
+++ b/odb/pgsql/connection.cxx
@@ -16,7 +16,6 @@
#include <odb/pgsql/error.hxx>
#include <odb/pgsql/exceptions.hxx>
#include <odb/pgsql/statement-cache.hxx>
-#include <odb/pgsql/result-ptr.hxx>
using namespace std;
@@ -33,17 +32,12 @@ namespace odb
connection (database_type& db)
: odb::connection (db), db_ (db)
{
- handle_ = PQconnectdb (db.conninfo ().c_str ());
+ handle_.reset (PQconnectdb (db.conninfo ().c_str ()));
if (handle_ == 0)
throw bad_alloc ();
else if (PQstatus (handle_) == CONNECTION_BAD)
- {
- std::string m (PQerrorMessage (handle_));
- PQfinish (handle_);
-
- throw database_exception (m);
- }
+ throw database_exception (PQerrorMessage (handle_));
init ();
}
@@ -77,11 +71,6 @@ namespace odb
connection::
~connection ()
{
- // Deallocate prepared statements before we close the connection.
- //
- statement_cache_.reset ();
-
- PQfinish (handle_);
}
transaction_impl* connection::
@@ -97,8 +86,7 @@ namespace odb
//
string str (s, n);
- result_ptr r (PQexec (handle_, str.c_str ()));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (PQexec (handle_, str.c_str ()));
unsigned long long count (0);
diff --git a/odb/pgsql/connection.hxx b/odb/pgsql/connection.hxx
index 063f8d4..fd74c6e 100644
--- a/odb/pgsql/connection.hxx
+++ b/odb/pgsql/connection.hxx
@@ -19,6 +19,7 @@
#include <odb/pgsql/version.hxx>
#include <odb/pgsql/forward.hxx>
#include <odb/pgsql/transaction-impl.hxx>
+#include <odb/pgsql/auto-handle.hxx>
#include <odb/pgsql/pgsql-fwd.hxx> // PGconn
#include <odb/pgsql/details/export.hxx>
@@ -84,8 +85,11 @@ namespace odb
private:
database_type& db_;
- PGconn* handle_;
+ auto_handle<PGconn> handle_;
+ // Keep statement_cache_ after handle_ so that it is destroyed before
+ // the connection is closed.
+ //
std::auto_ptr<statement_cache_type> statement_cache_;
};
}
diff --git a/odb/pgsql/makefile b/odb/pgsql/makefile
index 7e95f24..8203235 100644
--- a/odb/pgsql/makefile
+++ b/odb/pgsql/makefile
@@ -7,6 +7,7 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make
cxx := \
+auto-handle.cxx \
connection.cxx \
connection-factory.cxx \
database.cxx \
diff --git a/odb/pgsql/result-ptr.hxx b/odb/pgsql/result-ptr.hxx
deleted file mode 100644
index 2c5ee89..0000000
--- a/odb/pgsql/result-ptr.hxx
+++ /dev/null
@@ -1,76 +0,0 @@
-// file : odb/pgsql/result-ptr.hxx
-// author : Constantin Michael <constantin@codesynthesis.com>
-// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
-// license : GNU GPL v2; see accompanying LICENSE file
-
-#ifndef ODB_PGSQL_RESULT_PTR_HXX
-#define ODB_PGSQL_RESULT_PTR_HXX
-
-#include <odb/pre.hxx>
-
-#include <libpq-fe.h>
-
-#include <odb/pgsql/version.hxx>
-
-#include <odb/pgsql/details/export.hxx>
-
-//
-// Note: do not include this header into public headers (i.e., those
-// that may be included, directly or indirectly, by user code) because
-// it includes libpq-fe.h
-//
-
-namespace odb
-{
- namespace pgsql
- {
- class LIBODB_PGSQL_EXPORT result_ptr
- {
- public:
- result_ptr (PGresult* r = 0)
- : r_ (r)
- {
- }
-
- ~result_ptr ()
- {
- if (r_ != 0)
- PQclear (r_);
- }
-
- PGresult*
- get () const
- {
- return r_;
- }
-
- void
- reset (PGresult* r = 0)
- {
- if (r_ != 0)
- PQclear (r_);
-
- r_ = r;
- }
-
- PGresult*
- release ()
- {
- PGresult* r (r_);
- r_ = 0;
- return r;
- }
-
- private:
- result_ptr (const result_ptr&);
- result_ptr& operator= (const result_ptr&);
-
- private:
- PGresult* r_;
- };
- }
-}
-
-#include <odb/post.hxx>
-
-#endif // ODB_PGSQL_RESULT_PTR_HXX
diff --git a/odb/pgsql/statement.cxx b/odb/pgsql/statement.cxx
index 26ae475..7e5b5aa 100644
--- a/odb/pgsql/statement.cxx
+++ b/odb/pgsql/statement.cxx
@@ -14,7 +14,7 @@
#include <odb/pgsql/statement.hxx>
#include <odb/pgsql/connection.hxx>
#include <odb/pgsql/transaction.hxx>
-#include <odb/pgsql/result-ptr.hxx>
+#include <odb/pgsql/auto-handle.hxx>
#include <odb/pgsql/error.hxx>
#include <odb/pgsql/details/endian-traits.hxx>
@@ -53,7 +53,7 @@ namespace odb
s += name_;
s += "\"";
- result_ptr r (PQexec (conn_.handle (), s.c_str ()));
+ auto_handle<PGresult> h (PQexec (conn_.handle (), s.c_str ()));
deallocated_ = true;
}
@@ -67,14 +67,20 @@ namespace odb
name_ (name),
deallocated_ (false)
{
- result_ptr r (PQprepare (conn_.handle (),
- name_.c_str (),
- stmt.c_str (),
- static_cast<int> (types_count),
- types));
-
- if (!is_good_result (r.get ()))
- translate_error (conn_, r.get ());
+ auto_handle<PGresult> h (
+ PQprepare (conn_.handle (),
+ name_.c_str (),
+ stmt.c_str (),
+ static_cast<int> (types_count),
+ types));
+
+ if (!is_good_result (h))
+ translate_error (conn_, h);
+
+ //
+ // If any code after this line throws, the statement will be leaked
+ // (on the server) since deallocate() won't be called for it.
+ //
}
void statement::
@@ -295,8 +301,6 @@ namespace odb
select_statement::
~select_statement ()
{
- if (result_ != 0)
- PQclear (result_);
}
select_statement::
@@ -312,10 +316,8 @@ namespace odb
cond_ (&cond),
native_cond_ (native_cond),
data_ (data),
- result_ (0),
row_count_ (0),
current_row_ (0)
-
{
}
@@ -331,55 +333,39 @@ namespace odb
cond_ (0),
native_cond_ (native_cond),
data_ (data),
- result_ (0),
row_count_ (0),
current_row_ (0)
-
{
}
void select_statement::
execute ()
{
- if (result_ != 0)
- {
- PQclear (result_);
- result_ = 0;
- }
+ result_.reset ();
if (cond_ != 0)
bind_param (native_cond_, *cond_);
- // Use temporary result_ptr to guarantee exception safety.
- //
- result_ptr r (PQexecPrepared (conn_.handle (),
- name_.c_str (),
- native_cond_.count,
- native_cond_.values,
- native_cond_.lengths,
- native_cond_.formats,
- 1));
+ result_.reset (
+ PQexecPrepared (conn_.handle (),
+ name_.c_str (),
+ native_cond_.count,
+ native_cond_.values,
+ native_cond_.lengths,
+ native_cond_.formats,
+ 1));
- PGresult* h (r.get ());
+ if (!is_good_result (result_))
+ translate_error (conn_, result_);
- if (!is_good_result (h))
- translate_error (conn_, h);
-
- row_count_ = static_cast<size_t> (PQntuples (h));
+ row_count_ = static_cast<size_t> (PQntuples (result_));
current_row_ = 0;
-
- result_ = r.release ();
}
void select_statement::
free_result ()
{
- if (result_ != 0)
- {
- PQclear (result_);
- result_ = 0;
- }
-
+ result_.reset ();
row_count_ = 0;
current_row_ = 0;
}
@@ -450,14 +436,15 @@ namespace odb
bind_param (native_data_, data_);
- result_ptr r (PQexecPrepared (conn_.handle (),
- name_.c_str (),
- native_data_.count,
- native_data_.values,
- native_data_.lengths,
- native_data_.formats,
- 1));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (
+ PQexecPrepared (conn_.handle (),
+ name_.c_str (),
+ native_data_.count,
+ native_data_.values,
+ native_data_.lengths,
+ native_data_.formats,
+ 1));
+
ExecStatusType stat (PGRES_FATAL_ERROR);
if (!is_good_result (h, &stat))
@@ -482,10 +469,8 @@ namespace odb
if (id_cached_)
return id_;
- result_ptr r (PQexecParams (conn_.handle (),
- "select lastval ()",
- 0, 0, 0, 0, 0, 1));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (
+ PQexecParams (conn_.handle (), "select lastval ()", 0, 0, 0, 0, 0, 1));
if (!is_good_result (h))
translate_error (conn_, h);
@@ -534,15 +519,14 @@ namespace odb
bind_param (native_data_, data_);
bind_param (native_cond_, cond_);
- result_ptr r (PQexecPrepared (conn_.handle (),
- name_.c_str (),
- native_data_.count + native_cond_.count,
- native_data_.values,
- native_data_.lengths,
- native_data_.formats,
- 1));
-
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (
+ PQexecPrepared (conn_.handle (),
+ name_.c_str (),
+ native_data_.count + native_cond_.count,
+ native_data_.values,
+ native_data_.lengths,
+ native_data_.formats,
+ 1));
if (!is_good_result (h))
translate_error (conn_, h);
@@ -596,14 +580,14 @@ namespace odb
if (cond_ != 0)
bind_param (native_cond_, *cond_);
- result_ptr r (PQexecPrepared (conn_.handle (),
- name_.c_str (),
- native_cond_.count,
- native_cond_.values,
- native_cond_.lengths,
- native_cond_.formats,
- 1));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (
+ PQexecPrepared (conn_.handle (),
+ name_.c_str (),
+ native_cond_.count,
+ native_cond_.values,
+ native_cond_.lengths,
+ native_cond_.formats,
+ 1));
if (!is_good_result (h))
translate_error (conn_, h);
diff --git a/odb/pgsql/statement.hxx b/odb/pgsql/statement.hxx
index 11e04b3..6e5484a 100644
--- a/odb/pgsql/statement.hxx
+++ b/odb/pgsql/statement.hxx
@@ -15,7 +15,8 @@
#include <odb/pgsql/version.hxx>
#include <odb/pgsql/binding.hxx>
-#include <odb/pgsql/pgsql-fwd.hxx>
+#include <odb/pgsql/pgsql-fwd.hxx> // PGresult
+#include <odb/pgsql/auto-handle.hxx>
#include <odb/pgsql/details/export.hxx>
@@ -157,7 +158,7 @@ namespace odb
binding& data_;
- PGresult* result_;
+ auto_handle<PGresult> result_;
std::size_t row_count_;
std::size_t current_row_;
};
diff --git a/odb/pgsql/transaction-impl.cxx b/odb/pgsql/transaction-impl.cxx
index c3ce31d..e4604e3 100644
--- a/odb/pgsql/transaction-impl.cxx
+++ b/odb/pgsql/transaction-impl.cxx
@@ -12,7 +12,7 @@
#include <odb/pgsql/error.hxx>
#include <odb/pgsql/exceptions.hxx>
#include <odb/pgsql/transaction-impl.hxx>
-#include <odb/pgsql/result-ptr.hxx>
+#include <odb/pgsql/auto-handle.hxx>
namespace odb
{
@@ -46,8 +46,7 @@ namespace odb
odb::transaction_impl::connection_ = connection_.get ();
}
- result_ptr r (PQexec (connection_->handle (), "begin"));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (PQexec (connection_->handle (), "begin"));
if (!h || PGRES_COMMAND_OK != PQresultStatus (h))
translate_error (*connection_, h);
@@ -56,8 +55,7 @@ namespace odb
void transaction_impl::
commit ()
{
- result_ptr r (PQexec (connection_->handle (), "commit"));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (PQexec (connection_->handle (), "commit"));
if (!h || PGRES_COMMAND_OK != PQresultStatus (h))
translate_error (*connection_, h);
@@ -66,8 +64,7 @@ namespace odb
void transaction_impl::
rollback ()
{
- result_ptr r (PQexec (connection_->handle (), "rollback"));
- PGresult* h (r.get ());
+ auto_handle<PGresult> h (PQexec (connection_->handle (), "rollback"));
if (!h || PGRES_COMMAND_OK != PQresultStatus (h))
translate_error (*connection_, h);