aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-11-01 12:41:02 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-11-01 12:41:02 +0200
commitb820128512133c443799b27265e28a27622497e6 (patch)
treeb17cfca63277072f100455e43164acd74c1bc5dd
parent1adbed32a10e327bc1ab108133fcd2961ea1e07e (diff)
Implement support for optimistic concurrency
New pragmas: optimistic, version. New test: optimistic. New database function: reload().
-rw-r--r--odb/pgsql/object-statements.hxx87
-rw-r--r--odb/pgsql/object-statements.txx32
-rw-r--r--odb/pgsql/statement.cxx48
-rw-r--r--odb/pgsql/statement.hxx2
4 files changed, 133 insertions, 36 deletions
diff --git a/odb/pgsql/object-statements.hxx b/odb/pgsql/object-statements.hxx
index f80ab42..040f7bd 100644
--- a/odb/pgsql/object-statements.hxx
+++ b/odb/pgsql/object-statements.hxx
@@ -106,6 +106,32 @@ namespace odb
bool locked_;
};
+ template <typename T, bool optimistic>
+ struct optimistic_data;
+
+ template <typename T>
+ struct optimistic_data<T, true>
+ {
+ typedef T object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ optimistic_data (bind*, char** nv, int* nl, int* nf);
+
+ // The id + optimistic column binding.
+ //
+ std::size_t id_image_version_;
+ binding id_image_binding_;
+ native_binding id_image_native_binding_;
+
+ details::shared_ptr<delete_statement> erase_;
+ };
+
+ template <typename T>
+ struct optimistic_data<T, false>
+ {
+ optimistic_data (bind*, char**, int*, int*) {}
+ };
+
template <typename T>
class object_statements: public object_statements_base
{
@@ -256,6 +282,17 @@ namespace odb
binding&
id_image_binding () {return id_image_binding_;}
+ // Optimistic id + managed column image binding.
+ //
+ std::size_t
+ optimistic_id_image_version () const {return od_.id_image_version_;}
+
+ void
+ optimistic_id_image_version (std::size_t v) {od_.id_image_version_ = v;}
+
+ binding&
+ optimistic_id_image_binding () {return od_.id_image_binding_;}
+
// Statements.
//
insert_statement_type&
@@ -336,6 +373,25 @@ namespace odb
return *erase_;
}
+ delete_statement_type&
+ optimistic_erase_statement ()
+ {
+ if (od_.erase_ == 0)
+ {
+ od_.erase_.reset (
+ new (details::shared) delete_statement_type (
+ conn_,
+ object_traits::optimistic_erase_statement_name,
+ object_traits::optimistic_erase_statement,
+ object_traits::optimistic_erase_statement_types,
+ id_column_count + managed_optimistic_column_count,
+ od_.id_image_binding_,
+ od_.id_image_native_binding_));
+ }
+
+ return *od_.erase_;
+ }
+
// Container statement cache.
//
container_statement_cache_type&
@@ -357,14 +413,15 @@ namespace odb
private:
// select = total
- // insert = total - inverse
- // update = total - inverse - id - readonly
+ // insert = total - inverse - managed_optimistic
+ // update = total - inverse - managed_optimistic - id - readonly
//
static const std::size_t select_column_count =
object_traits::column_count;
static const std::size_t insert_column_count =
- object_traits::column_count - object_traits::inverse_column_count;
+ object_traits::column_count - object_traits::inverse_column_count -
+ object_traits::managed_optimistic_column_count;
static const std::size_t update_column_count = insert_column_count -
object_traits::id_column_count - object_traits::readonly_column_count;
@@ -372,6 +429,9 @@ namespace odb
static const std::size_t id_column_count =
object_traits::id_column_count;
+ static const std::size_t managed_optimistic_column_count =
+ object_traits::managed_optimistic_column_count;
+
private:
container_statement_cache_type container_statement_cache_;
@@ -397,16 +457,23 @@ namespace odb
// Update binding. Note that the id suffix is bound to id_image_
// below instead of image_ which makes this binding effectively
// bound to two images. As a result, we have to track versions
- // for both of them.
+ // for both of them. If this object uses optimistic concurrency,
+ // then the binding for the managed column (version, timestamp,
+ // etc) comes after the id and the image for such a column is
+ // stored as part of the id image.
//
std::size_t update_image_version_;
std::size_t update_id_image_version_;
binding update_image_binding_;
- bind update_image_bind_[update_column_count + id_column_count];
+ bind update_image_bind_[update_column_count + id_column_count +
+ managed_optimistic_column_count];
native_binding update_image_native_binding_;
- char* update_image_values_[update_column_count + id_column_count];
- int update_image_lengths_[update_column_count + id_column_count];
- int update_image_formats_[update_column_count + id_column_count];
+ char* update_image_values_[update_column_count + id_column_count +
+ managed_optimistic_column_count];
+ int update_image_lengths_[update_column_count + id_column_count +
+ managed_optimistic_column_count];
+ int update_image_formats_[update_column_count + id_column_count +
+ managed_optimistic_column_count];
// Id image binding (only used as a parameter). Uses the suffix in
// the update bind.
@@ -416,6 +483,10 @@ namespace odb
binding id_image_binding_;
native_binding id_image_native_binding_;
+ // Extra data for objects with optimistic concurrency support.
+ //
+ optimistic_data<T, managed_optimistic_column_count != 0> od_;
+
details::shared_ptr<insert_statement_type> persist_;
details::shared_ptr<select_statement_type> find_;
details::shared_ptr<update_statement_type> update_;
diff --git a/odb/pgsql/object-statements.txx b/odb/pgsql/object-statements.txx
index 0e61715..697dd76 100644
--- a/odb/pgsql/object-statements.txx
+++ b/odb/pgsql/object-statements.txx
@@ -17,6 +17,25 @@ namespace odb
namespace pgsql
{
//
+ // optimistic_data
+ //
+
+ template <typename T>
+ optimistic_data<T, true>::
+ optimistic_data (bind* b, char** nv, int* nl, int* nf)
+ : id_image_binding_ (
+ b,
+ object_traits::id_column_count +
+ object_traits::managed_optimistic_column_count),
+ id_image_native_binding_ (
+ nv, nl, nf,
+ object_traits::id_column_count +
+ object_traits::managed_optimistic_column_count)
+ {
+ id_image_version_ = 0;
+ }
+
+ //
// object_statements
//
@@ -41,11 +60,13 @@ namespace odb
insert_column_count),
// update
update_image_binding_ (update_image_bind_,
- update_column_count + id_column_count),
+ update_column_count + id_column_count +
+ managed_optimistic_column_count),
update_image_native_binding_ (update_image_values_,
update_image_lengths_,
update_image_formats_,
- update_column_count + id_column_count),
+ update_column_count + id_column_count +
+ managed_optimistic_column_count),
// id
id_image_binding_ (update_image_bind_ + update_column_count,
id_column_count),
@@ -53,7 +74,12 @@ namespace odb
update_image_values_ + update_column_count,
update_image_lengths_ + update_column_count,
update_image_formats_ + update_column_count,
- id_column_count)
+ id_column_count),
+ // optimistic data
+ od_ (update_image_bind_ + update_column_count,
+ update_image_values_ + update_column_count,
+ update_image_lengths_ + update_column_count,
+ update_image_formats_ + update_column_count)
{
image_.version = 0;
select_image_version_ = 0;
diff --git a/odb/pgsql/statement.cxx b/odb/pgsql/statement.cxx
index f119fd0..049a00d 100644
--- a/odb/pgsql/statement.cxx
+++ b/odb/pgsql/statement.cxx
@@ -9,8 +9,6 @@
#include <libpq-fe.h>
-#include <odb/exceptions.hxx> // object_not_persistent
-
#include <odb/pgsql/pgsql-oid.hxx>
#include <odb/pgsql/statement.hxx>
#include <odb/pgsql/connection.hxx>
@@ -28,6 +26,26 @@ namespace odb
{
using namespace details;
+ static unsigned long long
+ affected_row_count (PGresult* h)
+ {
+ const char* s (PQcmdTuples (h));
+ unsigned long long count;
+
+ if (s[0] != '\0' && s[1] == '\0')
+ count = static_cast<unsigned long long> (s[0] - '0');
+ else
+ {
+ // @@ Using stringstream conversion for now. See if we can optimize
+ // this (atoll possibly, even though it is not standard).
+ //
+ istringstream ss (s);
+ ss >> count;
+ }
+
+ return count;
+ }
+
//
// statement
//
@@ -102,7 +120,7 @@ namespace odb
continue;
}
- n.values[i] = reinterpret_cast<char*> (current_bind.buffer);
+ n.values[i] = static_cast<char*> (current_bind.buffer);
size_t l (0);
@@ -547,7 +565,7 @@ namespace odb
{
}
- void update_statement::
+ unsigned long long update_statement::
execute ()
{
bind_param (native_param_, param_);
@@ -564,11 +582,7 @@ namespace odb
if (!is_good_result (h))
translate_error (conn_, h);
- // PQcmdTuples returns a string representing the number of matching
- // rows found. "0" indicates no match.
- //
- if (PQcmdTuples (h)[0] == '0')
- throw object_not_persistent ();
+ return affected_row_count (h);
}
//
@@ -625,21 +639,7 @@ namespace odb
if (!is_good_result (h))
translate_error (conn_, h);
- const char* s (PQcmdTuples (h));
- unsigned long long count;
-
- if (s[0] != '\0' && s[1] == '\0')
- count = static_cast<unsigned long long> (s[0] - '0');
- else
- {
- // @@ Using stringstream conversion for now. See if we can optimize
- // this (atoll possibly, even though it is not standard).
- //
- istringstream ss (s);
- ss >> count;
- }
-
- return count;
+ return affected_row_count (h);
}
}
}
diff --git a/odb/pgsql/statement.hxx b/odb/pgsql/statement.hxx
index 0432920..8beb01f 100644
--- a/odb/pgsql/statement.hxx
+++ b/odb/pgsql/statement.hxx
@@ -221,7 +221,7 @@ namespace odb
binding& param,
native_binding& native_param);
- void
+ unsigned long long
execute ();
private: