aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-07-04 10:11:02 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-07-04 10:11:02 +0200
commit0bf87e33b786fc64ae5bf059205de1fa674ab788 (patch)
treec11e4e5a3e24b4a13b950cc55334d4b3dfcfb064
parentbef81b1627c2c31dc22cd2b18920ed8db230a94c (diff)
Add query and result implementation
-rw-r--r--odb/pgsql/query.cxx256
-rw-r--r--odb/pgsql/query.hxx1687
-rw-r--r--odb/pgsql/query.ixx28
-rw-r--r--odb/pgsql/query.txx110
-rw-r--r--odb/pgsql/result.hxx78
-rw-r--r--odb/pgsql/result.txx134
6 files changed, 2293 insertions, 0 deletions
diff --git a/odb/pgsql/query.cxx b/odb/pgsql/query.cxx
new file mode 100644
index 0000000..ba39564
--- /dev/null
+++ b/odb/pgsql/query.cxx
@@ -0,0 +1,256 @@
+// file : odb/pgsql/query.cxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstddef> // std::size_t
+#include <cstring> // std::memset
+#include <cassert>
+#include <sstream>
+
+#include <odb/pgsql/query.hxx>
+
+using namespace std;
+
+namespace odb
+{
+ namespace pgsql
+ {
+ // query_param
+ //
+ query_param::
+ ~query_param ()
+ {
+ }
+
+ query::
+ query (const query& q)
+ : clause_ (q.clause_),
+ parameters_ (q.parameters_),
+ bind_ (q.bind_),
+ binding_ (0, 0),
+ values_ (q.values_),
+ lengths_ (q.lengths_),
+ formats_ (q.formats_),
+ types_ (q.types_),
+ native_binding_ (0, 0, 0, 0)
+ {
+ // Here and below we want to maintain up to date binding info so
+ // that the call to parameters_binding() below is an immutable
+ // operation, provided the query does not have any by-reference
+ // parameters. This way a by-value-only query can be shared
+ // between multiple threads without the need for synchronization.
+ //
+ if (size_t n = bind_.size ())
+ {
+ binding_.bind = &bind_[0];
+ binding_.count = n;
+ binding_.version++;
+
+ native_binding_.values = &values_[0];
+ native_binding_.lengths = &lengths_[0];
+ native_binding_.formats = &formats_[0];
+ native_binding_.count = n;
+
+ assert (values_.size () == n);
+ assert (lengths_.size () == n);
+ assert (formats_.size () == n);
+ assert (types_.size () == n);
+ }
+ }
+
+ query& query::
+ operator= (const query& q)
+ {
+ if (this != &q)
+ {
+ clause_ = q.clause_;
+ parameters_ = q.parameters_;
+ bind_ = q.bind_;
+
+ size_t n (bind_.size ());
+
+ binding_.count = n;
+ binding_.version++;
+
+ values_ = q.values_;
+ lengths_ = q.lengths_;
+ formats_ = q.formats_;
+ types_ = q.types_;
+
+ native_binding_.count = n;
+
+ assert (values_.size () == n);
+ assert (lengths_.size () == n);
+ assert (formats_.size () == n);
+ assert (types_.size () == n);
+
+ if (n != 0)
+ {
+ binding_.bind = &bind_[0];
+
+ native_binding_.values = &values_[0];
+ native_binding_.lengths = &lengths_[0];
+ native_binding_.formats = &formats_[0];
+ }
+ }
+
+ return *this;
+ }
+
+ query& query::
+ operator+= (const query& q)
+ {
+ size_t n (clause_.size ());
+
+ if (n != 0 && clause_[n - 1] != ' ' &&
+ !q.clause_.empty () && q.clause_[0] != ' ')
+ clause_ += ' ';
+
+ clause_ += q.clause_;
+
+ // Reset parameter indexes.
+ //
+ bool unquoted (true);
+ for (std::size_t i (0), e (clause_.size ()), p(1); i < e; ++i)
+ {
+ // $'s are legal in identifiers in PostgreSQL.
+ //
+ if (clause_[i] == '"')
+ unquoted = !unquoted;
+
+ if (unquoted && clause_[i] == '$')
+ {
+ ostringstream ss;
+ ss << p++;
+ clause_[++i] = ss.str()[0];
+ }
+ }
+
+ n = bind_.size ();
+
+ parameters_.insert (
+ parameters_.end (), q.parameters_.begin (), q.parameters_.end ());
+
+ bind_.insert (
+ bind_.end (), q.bind_.begin (), q.bind_.end ());
+
+ values_.insert (
+ values_.end (), q.values_.begin (), q.values_.end ());
+
+ lengths_.insert (
+ lengths_.end (), q.lengths_.begin (), q.lengths_.end ());
+
+ formats_.insert (
+ formats_.end (), q.formats_.begin (), q.formats_.end ());
+
+ types_.insert (
+ types_.end (), q.types_.begin (), q.types_.end ());
+
+ if (n != bind_.size ())
+ {
+ n = bind_.size ();
+
+ binding_.bind = &bind_[0];
+ binding_.count = n;
+ binding_.version++;
+
+ assert (values_.size () == n);
+ assert (lengths_.size () == n);
+ assert (formats_.size () == n);
+ assert (types_.size () == n);
+
+ native_binding_.values = &values_[0];
+ native_binding_.lengths = &lengths_[0];
+ native_binding_.formats = &formats_[0];
+ native_binding_.count = n;
+ }
+
+ return *this;
+ }
+
+ void query::
+ add (details::shared_ptr<query_param> p)
+ {
+ size_t n (clause_.size ());
+
+ if (n != 0 && clause_[n - 1] != ' ')
+ clause_ += ' ';
+
+ ostringstream ss;
+ ss << parameters_.size () + 1;
+
+ clause_ += '$' + ss.str ();
+
+ parameters_.push_back (p);
+ bind_.push_back (bind ());
+ binding_.bind = &bind_[0];
+ binding_.count = bind_.size ();
+ binding_.version++;
+
+ bind* b (&bind_.back ());
+ memset (b, 0, sizeof (bind));
+ p->bind (b);
+
+ values_.push_back (0);
+ lengths_.push_back (0);
+ formats_.push_back (0);
+ native_binding_.values = &values_[0];
+ native_binding_.lengths = &lengths_[0];
+ native_binding_.formats = &formats_[0];
+
+ types_.push_back (p->oid ());
+
+ // native_binding_.count should always equal binding_.count.
+ // At this point, we know that we have added one element to
+ // each array, so there is no need to check.
+ //
+ native_binding_.count = binding_.count;
+ }
+
+ binding& query::
+ parameters_binding () const
+ {
+ size_t n (parameters_.size ());
+ binding& r (binding_);
+
+ if (n == 0)
+ return r;
+
+ bool inc_ver (false);
+ bind* b (&bind_[0]);
+
+ for (size_t i (0); i < n; ++i)
+ {
+ query_param& p (*parameters_[i]);
+
+ if (p.reference ())
+ {
+ if (p.init ())
+ {
+ p.bind (b + i);
+ inc_ver = true;
+ }
+ }
+ }
+
+ if (inc_ver)
+ r.version++;
+
+ return r;
+ }
+
+ std::string query::
+ clause () const
+ {
+ if (clause_.empty () ||
+ clause_.compare (0, 6, "WHERE ") == 0 ||
+ clause_.compare (0, 9, "ORDER BY ") == 0 ||
+ clause_.compare (0, 9, "GROUP BY ") == 0 ||
+ clause_.compare (0, 7, "HAVING ") == 0)
+ return clause_;
+ else
+ return "WHERE " + clause_;
+ }
+ }
+}
diff --git a/odb/pgsql/query.hxx b/odb/pgsql/query.hxx
new file mode 100644
index 0000000..632fde5
--- /dev/null
+++ b/odb/pgsql/query.hxx
@@ -0,0 +1,1687 @@
+// file : odb/pgsql/query.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_PGSQL_QUERY_HXX
+#define ODB_PGSQL_QUERY_HXX
+
+#include <odb/pre.hxx>
+
+#include <string>
+#include <vector>
+#include <cstddef> // std::size_t
+
+#include <odb/query.hxx>
+
+#include <odb/pgsql/version.hxx>
+#include <odb/pgsql/forward.hxx>
+#include <odb/pgsql/traits.hxx>
+#include <odb/pgsql/binding.hxx>
+#include <odb/pgsql/pgsql-oid.hxx>
+
+#include <odb/details/buffer.hxx>
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/pgsql/details/export.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ template <typename T>
+ class val_bind
+ {
+ public:
+ explicit
+ val_bind (const T& v): val (v) {}
+
+ const T& val;
+ };
+
+ template <typename T>
+ class ref_bind
+ {
+ public:
+ explicit
+ ref_bind (const T& r): ref (r) {}
+
+ const T& ref;
+ };
+
+ struct LIBODB_PGSQL_EXPORT query_param: details::shared_base
+ {
+ virtual
+ ~query_param ();
+
+ bool
+ reference () const
+ {
+ return value_ != 0;
+ }
+
+ virtual bool
+ init () = 0;
+
+ virtual void
+ bind (bind*) = 0;
+
+ virtual unsigned int
+ oid () const = 0;
+
+ protected:
+ query_param (const void* value)
+ : value_ (value)
+ {
+ }
+
+ protected:
+ const void* value_;
+ };
+
+ //
+ //
+ template <typename T, database_type_id ID>
+ struct query_column;
+
+ class LIBODB_PGSQL_EXPORT query
+ {
+ public:
+ query ()
+ : binding_ (0, 0), native_binding_ (0, 0, 0, 0)
+ {
+ }
+
+ explicit
+ query (const std::string& q)
+ : clause_ (q), binding_ (0, 0), native_binding_ (0, 0, 0, 0)
+ {
+ }
+
+ template <typename T>
+ explicit
+ query (val_bind<T> v)
+ : binding_ (0, 0), native_binding_ (0, 0, 0, 0)
+ {
+ append<T, type_traits<T>::db_type_id> (v);
+ }
+
+ template <typename T>
+ explicit
+ query (ref_bind<T> r)
+ : binding_ (0, 0), native_binding_ (0, 0, 0, 0)
+ {
+ append<T, type_traits<T>::db_type_id> (r);
+ }
+
+ template <database_type_id ID>
+ query (const query_column<bool, ID>&);
+
+ query (const query&);
+
+ query&
+ operator= (const query&);
+
+ public:
+ std::string
+ clause () const;
+
+ binding&
+ parameters_binding () const;
+
+ native_binding&
+ native_parameters_binding () const
+ {
+ return native_binding_;
+ }
+
+ const unsigned int*
+ parameter_types () const
+ {
+ return types_.empty () ? 0 : &types_[0];
+ }
+
+ std::size_t
+ parameter_count () const
+ {
+ return parameters_.size ();
+ }
+
+ public:
+ template <typename T>
+ static val_bind<T>
+ _val (const T& x)
+ {
+ return val_bind<T> (x);
+ }
+
+ template <typename T>
+ static ref_bind<T>
+ _ref (const T& x)
+ {
+ return ref_bind<T> (x);
+ }
+
+ public:
+ query&
+ operator+= (const query&);
+
+ query&
+ operator+= (const std::string& q)
+ {
+ size_t n (clause_.size ());
+
+ if (n != 0 && clause_[n - 1] != ' ' && !q.empty () && q[0] != ' ')
+ clause_ += ' ';
+
+ clause_ += q;
+ return *this;
+ }
+
+ template <typename T>
+ query&
+ operator+= (val_bind<T> v)
+ {
+ append<T, type_traits<T>::db_type_id> (v);
+ return *this;
+ }
+
+ template <typename T>
+ query&
+ operator+= (ref_bind<T> r)
+ {
+ append<T, type_traits<T>::db_type_id> (r);
+ return *this;
+ }
+
+ public:
+ template <typename T, database_type_id ID>
+ void
+ append (val_bind<T>);
+
+ template <typename T, database_type_id ID>
+ void
+ append (ref_bind<T>);
+
+ private:
+ void
+ add (details::shared_ptr<query_param>);
+
+ private:
+ typedef std::vector<details::shared_ptr<query_param> > parameters_type;
+
+ std::string clause_;
+ parameters_type parameters_;
+
+ mutable std::vector<bind> bind_;
+ mutable binding binding_;
+
+ std::vector<char*> values_;
+ std::vector<int> lengths_;
+ std::vector<int> formats_;
+ std::vector<unsigned int> types_;
+ mutable native_binding native_binding_;
+ };
+
+ inline query
+ operator+ (const query& x, const query& y)
+ {
+ query r (x);
+ r += y;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const query& q, val_bind<T> b)
+ {
+ query r (q);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const query& q, ref_bind<T> b)
+ {
+ query r (q);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (val_bind<T> b, const query& q)
+ {
+ query r;
+ r += b;
+ r += q;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (ref_bind<T> b, const query& q)
+ {
+ query r;
+ r += b;
+ r += q;
+ return r;
+ }
+
+ inline query
+ operator+ (const query& q, const std::string& s)
+ {
+ query r (q);
+ r += s;
+ return r;
+ }
+
+ inline query
+ operator+ (const std::string& s, const query& q)
+ {
+ query r (s);
+ r += q;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const std::string& s, val_bind<T> b)
+ {
+ query r (s);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const std::string& s, ref_bind<T> b)
+ {
+ query r (s);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (val_bind<T> b, const std::string& s)
+ {
+ query r;
+ r += b;
+ r += s;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (ref_bind<T> b, const std::string& s)
+ {
+ query r;
+ r += b;
+ r += s;
+ return r;
+ }
+
+ inline query
+ operator&& (const query& x, const query& y)
+ {
+ query r ("(");
+ r += x;
+ r += ") AND (";
+ r += y;
+ r += ")";
+ return r;
+ }
+
+ inline query
+ operator|| (const query& x, const query& y)
+ {
+ query r ("(");
+ r += x;
+ r += ") OR (";
+ r += y;
+ r += ")";
+ return r;
+ }
+
+ inline query
+ operator! (const query& x)
+ {
+ query r ("NOT (");
+ r += x;
+ r += ")";
+ return r;
+ }
+
+ // query_column
+ //
+
+ template <typename T, typename T2>
+ class copy_bind: public val_bind<T>
+ {
+ public:
+ explicit
+ copy_bind (const T2& v): val_bind<T> (val), val (v) {}
+
+ const T val;
+ };
+
+ template <typename T>
+ const T&
+ type_instance ();
+
+ template <typename T, database_type_id ID>
+ struct query_column
+ {
+ explicit
+ query_column (const char* name)
+ : name_ (name)
+ {
+ }
+
+ const char*
+ name () const
+ {
+ return name_;
+ }
+
+ // is_null, is_not_null
+ //
+ public:
+ query
+ is_null () const
+ {
+ query q (name_);
+ q += "IS NULL";
+ return q;
+ }
+
+ query
+ is_not_null () const
+ {
+ query q (name_);
+ q += "IS NOT NULL";
+ return q;
+ }
+
+ // in
+ //
+ public:
+ query
+ in (const T&, const T&) const;
+
+ query
+ in (const T&, const T&, const T&) const;
+
+ query
+ in (const T&, const T&, const T&, const T&) const;
+
+ query
+ in (const T&, const T&, const T&, const T&, const T&) const;
+
+ template <typename I>
+ query
+ in_range (I begin, I end) const;
+
+ // =
+ //
+ public:
+ query
+ equal (const T& v) const
+ {
+ return equal (val_bind<T> (v));
+ }
+
+ query
+ equal (val_bind<T> v) const
+ {
+ query q (name_);
+ q += "=";
+ q.append<T, ID> (v);
+ return q;
+ }
+
+ template <typename T2>
+ query
+ equal (val_bind<T2> v) const
+ {
+ copy_bind<T, T2> c (v.val);
+ return equal (c);
+ }
+
+ query
+ equal (ref_bind<T> r) const
+ {
+ query q (name_);
+ q += "=";
+ q.append<T, ID> (r);
+ return q;
+ }
+
+ friend query
+ operator== (const query_column& c, const T& v)
+ {
+ return c.equal (v);
+ }
+
+ friend query
+ operator== (const T& v, const query_column& c)
+ {
+ return c.equal (v);
+ }
+
+ friend query
+ operator== (const query_column& c, val_bind<T> v)
+ {
+ return c.equal (v);
+ }
+
+ friend query
+ operator== (val_bind<T> v, const query_column& c)
+ {
+ return c.equal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator== (const query_column& c, val_bind<T2> v)
+ {
+ return c.equal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator== (val_bind<T2> v, const query_column& c)
+ {
+ return c.equal (v);
+ }
+
+ friend query
+ operator== (const query_column& c, ref_bind<T> r)
+ {
+ return c.equal (r);
+ }
+
+ friend query
+ operator== (ref_bind<T> r, const query_column& c)
+ {
+ return c.equal (r);
+ }
+
+ // !=
+ //
+ public:
+ query
+ unequal (const T& v) const
+ {
+ return unequal (val_bind<T> (v));
+ }
+
+ query
+ unequal (val_bind<T> v) const
+ {
+ query q (name_);
+ q += "!=";
+ q.append<T, ID> (v);
+ return q;
+ }
+
+ template <typename T2>
+ query
+ unequal (val_bind<T2> v) const
+ {
+ copy_bind<T, T2> c (v.val);
+ return unequal (c);
+ }
+
+ query
+ unequal (ref_bind<T> r) const
+ {
+ query q (name_);
+ q += "!=";
+ q.append<T, ID> (r);
+ return q;
+ }
+
+ friend query
+ operator!= (const query_column& c, const T& v)
+ {
+ return c.unequal (v);
+ }
+
+ friend query
+ operator!= (const T& v, const query_column& c)
+ {
+ return c.unequal (v);
+ }
+
+ friend query
+ operator!= (const query_column& c, val_bind<T> v)
+ {
+ return c.unequal (v);
+ }
+
+ friend query
+ operator!= (val_bind<T> v, const query_column& c)
+ {
+ return c.unequal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator!= (const query_column& c, val_bind<T2> v)
+ {
+ return c.unequal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator!= (val_bind<T2> v, const query_column& c)
+ {
+ return c.unequal (v);
+ }
+
+ friend query
+ operator!= (const query_column& c, ref_bind<T> r)
+ {
+ return c.unequal (r);
+ }
+
+ friend query
+ operator!= (ref_bind<T> r, const query_column& c)
+ {
+ return c.unequal (r);
+ }
+
+ // <
+ //
+ public:
+ query
+ less (const T& v) const
+ {
+ return less (val_bind<T> (v));
+ }
+
+ query
+ less (val_bind<T> v) const
+ {
+ query q (name_);
+ q += "<";
+ q.append<T, ID> (v);
+ return q;
+ }
+
+ template <typename T2>
+ query
+ less (val_bind<T2> v) const
+ {
+ copy_bind<T, T2> c (v.val);
+ return less (c);
+ }
+
+ query
+ less (ref_bind<T> r) const
+ {
+ query q (name_);
+ q += "<";
+ q.append<T, ID> (r);
+ return q;
+ }
+
+ friend query
+ operator< (const query_column& c, const T& v)
+ {
+ return c.less (v);
+ }
+
+ friend query
+ operator< (const T& v, const query_column& c)
+ {
+ return c.greater (v);
+ }
+
+ friend query
+ operator< (const query_column& c, val_bind<T> v)
+ {
+ return c.less (v);
+ }
+
+ friend query
+ operator< (val_bind<T> v, const query_column& c)
+ {
+ return c.greater (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator< (const query_column& c, val_bind<T2> v)
+ {
+ return c.less (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator< (val_bind<T2> v, const query_column& c)
+ {
+ return c.greater (v);
+ }
+
+ friend query
+ operator< (const query_column& c, ref_bind<T> r)
+ {
+ return c.less (r);
+ }
+
+ friend query
+ operator< (ref_bind<T> r, const query_column& c)
+ {
+ return c.greater (r);
+ }
+
+ // >
+ //
+ public:
+ query
+ greater (const T& v) const
+ {
+ return greater (val_bind<T> (v));
+ }
+
+ query
+ greater (val_bind<T> v) const
+ {
+ query q (name_);
+ q += ">";
+ q.append<T, ID> (v);
+ return q;
+ }
+
+ template <typename T2>
+ query
+ greater (val_bind<T2> v) const
+ {
+ copy_bind<T, T2> c (v.val);
+ return greater (c);
+ }
+
+ query
+ greater (ref_bind<T> r) const
+ {
+ query q (name_);
+ q += ">";
+ q.append<T, ID> (r);
+ return q;
+ }
+
+ friend query
+ operator> (const query_column& c, const T& v)
+ {
+ return c.greater (v);
+ }
+
+ friend query
+ operator> (const T& v, const query_column& c)
+ {
+ return c.less (v);
+ }
+
+ friend query
+ operator> (const query_column& c, val_bind<T> v)
+ {
+ return c.greater (v);
+ }
+
+ friend query
+ operator> (val_bind<T> v, const query_column& c)
+ {
+ return c.less (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator> (const query_column& c, val_bind<T2> v)
+ {
+ return c.greater (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator> (val_bind<T2> v, const query_column& c)
+ {
+ return c.less (v);
+ }
+
+ friend query
+ operator> (const query_column& c, ref_bind<T> r)
+ {
+ return c.greater (r);
+ }
+
+ friend query
+ operator> (ref_bind<T> r, const query_column& c)
+ {
+ return c.less (r);
+ }
+
+ // <=
+ //
+ public:
+ query
+ less_equal (const T& v) const
+ {
+ return less_equal (val_bind<T> (v));
+ }
+
+ query
+ less_equal (val_bind<T> v) const
+ {
+ query q (name_);
+ q += "<=";
+ q.append<T, ID> (v);
+ return q;
+ }
+
+ template <typename T2>
+ query
+ less_equal (val_bind<T2> v) const
+ {
+ copy_bind<T, T2> c (v.val);
+ return less_equal (c);
+ }
+
+ query
+ less_equal (ref_bind<T> r) const
+ {
+ query q (name_);
+ q += "<=";
+ q.append<T, ID> (r);
+ return q;
+ }
+
+ friend query
+ operator<= (const query_column& c, const T& v)
+ {
+ return c.less_equal (v);
+ }
+
+ friend query
+ operator<= (const T& v, const query_column& c)
+ {
+ return c.greater_equal (v);
+ }
+
+ friend query
+ operator<= (const query_column& c, val_bind<T> v)
+ {
+ return c.less_equal (v);
+ }
+
+ friend query
+ operator<= (val_bind<T> v, const query_column& c)
+ {
+ return c.greater_equal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator<= (const query_column& c, val_bind<T2> v)
+ {
+ return c.less_equal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator<= (val_bind<T2> v, const query_column& c)
+ {
+ return c.greater_equal (v);
+ }
+
+ friend query
+ operator<= (const query_column& c, ref_bind<T> r)
+ {
+ return c.less_equal (r);
+ }
+
+ friend query
+ operator<= (ref_bind<T> r, const query_column& c)
+ {
+ return c.greater_equal (r);
+ }
+
+ // >=
+ //
+ public:
+ query
+ greater_equal (const T& v) const
+ {
+ return greater_equal (val_bind<T> (v));
+ }
+
+ query
+ greater_equal (val_bind<T> v) const
+ {
+ query q (name_);
+ q += ">=";
+ q.append<T, ID> (v);
+ return q;
+ }
+
+ template <typename T2>
+ query
+ greater_equal (val_bind<T2> v) const
+ {
+ copy_bind<T, T2> c (v.val);
+ return greater_equal (c);
+ }
+
+ query
+ greater_equal (ref_bind<T> r) const
+ {
+ query q (name_);
+ q += ">=";
+ q.append<T, ID> (r);
+ return q;
+ }
+
+ friend query
+ operator>= (const query_column& c, const T& v)
+ {
+ return c.greater_equal (v);
+ }
+
+ friend query
+ operator>= (const T& v, const query_column& c)
+ {
+ return c.less_equal (v);
+ }
+
+ friend query
+ operator>= (const query_column& c, val_bind<T> v)
+ {
+ return c.greater_equal (v);
+ }
+
+ friend query
+ operator>= (val_bind<T> v, const query_column& c)
+ {
+ return c.less_equal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator>= (const query_column& c, val_bind<T2> v)
+ {
+ return c.greater_equal (v);
+ }
+
+ template <typename T2>
+ friend query
+ operator>= (val_bind<T2> v, const query_column& c)
+ {
+ return c.less_equal (v);
+ }
+
+ friend query
+ operator>= (const query_column& c, ref_bind<T> r)
+ {
+ return c.greater_equal (r);
+ }
+
+ friend query
+ operator>= (ref_bind<T> r, const query_column& c)
+ {
+ return c.less_equal (r);
+ }
+
+ // Column comparison.
+ //
+ public:
+ template <typename T2, database_type_id ID2>
+ query
+ operator== (const query_column<T2, ID2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () == type_instance<T2> ()));
+
+ query q (name_);
+ q += "=";
+ q += c.name ();
+ return q;
+ }
+
+ template <typename T2, database_type_id ID2>
+ query
+ operator!= (const query_column<T2, ID2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () != type_instance<T2> ()));
+
+ query q (name_);
+ q += "!=";
+ q += c.name ();
+ return q;
+ }
+
+ template <typename T2, database_type_id ID2>
+ query
+ operator< (const query_column<T2, ID2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () < type_instance<T2> ()));
+
+ query q (name_);
+ q += "<";
+ q += c.name ();
+ return q;
+ }
+
+ template <typename T2, database_type_id ID2>
+ query
+ operator> (const query_column<T2, ID2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () > type_instance<T2> ()));
+
+ query q (name_);
+ q += ">";
+ q += c.name ();
+ return q;
+ }
+
+ template <typename T2, database_type_id ID2>
+ query
+ operator<= (const query_column<T2, ID2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () <= type_instance<T2> ()));
+
+ query q (name_);
+ q += "<=";
+ q += c.name ();
+ return q;
+ }
+
+ template <typename T2, database_type_id ID2>
+ query
+ operator>= (const query_column<T2, ID2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () >= type_instance<T2> ()));
+
+ query q (name_);
+ q += ">=";
+ q += c.name ();
+ return q;
+ }
+
+ private:
+ const char* name_;
+ };
+
+ //
+ //
+ template <typename T, database_type_id>
+ struct query_param_impl;
+
+ // BOOLEAN
+ //
+ template <typename T>
+ struct query_param_impl<T, id_boolean>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::boolean;
+ b->buffer = &image_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return bool_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_boolean>::set_image (image_, dummy, v);
+ }
+
+ private:
+ bool image_;
+ };
+
+ // SMALLINT
+ //
+ template <typename T>
+ struct query_param_impl<T, id_smallint>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::smallint;
+ b->buffer = &image_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return int2_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_smallint>::set_image (image_, dummy, v);
+ }
+
+ private:
+ short image_;
+ };
+
+ // INTEGER
+ //
+ template <typename T>
+ struct query_param_impl<T, id_integer>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::integer;
+ b->buffer = &image_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return int4_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_integer>::set_image (image_, dummy, v);
+ }
+
+ private:
+ int image_;
+ };
+
+ // BIGINT
+ //
+ template <typename T>
+ struct query_param_impl<T, id_bigint>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::bigint;
+ b->buffer = &image_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return int8_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_bigint>::set_image (image_, dummy, v);
+ }
+
+ private:
+ long long image_;
+ };
+
+ // REAL
+ //
+ template <typename T>
+ struct query_param_impl<T, id_real>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::real;
+ b->buffer = &image_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return float4_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_real>::set_image (image_, dummy, v);
+ }
+
+ private:
+ float image_;
+ };
+
+ // DOUBLE
+ //
+ template <typename T>
+ struct query_param_impl<T, id_double>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::double_;
+ b->buffer = &image_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return float8_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_double>::set_image (image_, dummy, v);
+ }
+
+ private:
+ double image_;
+ };
+
+ // @@ NUMERIC
+ //
+ // template <typename T>
+ // struct query_param_impl<T, id_numeric>: query_param
+ // {
+ // query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ // query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ // virtual bool
+ // init ()
+ // {
+ // return init (*static_cast<const T*> (value_));
+ // }
+
+ // virtual void
+ // bind (pgsql::bind* b)
+ // {
+ // b->type = bind::numeric;
+ // b->buffer = buffer_.data ();
+ // b->buffer_length = static_cast<unsigned long> (buffer_.capacity ());
+ // b->length = &size_;
+ // }
+
+ // private:
+ // bool
+ // init (const T& v)
+ // {
+ // bool dummy;
+ // std::size_t size, cap (buffer_.capacity ());
+ // value_traits<T, id_decimal>::set_image (buffer_, size, dummy, v);
+ // size_ = static_cast<unsigned long> (size);
+ // return cap != buffer_.capacity ();
+ // }
+
+ // private:
+ // details::buffer buffer_;
+ // unsigned long size_;
+ // };
+
+ // @@ DATE
+ //
+ // template <typename T>
+ // struct query_param_impl<T, id_date>: query_param
+ // {
+ // query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ // query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ // virtual bool
+ // init ()
+ // {
+ // init (*static_cast<const T*> (value_));
+ // return false;
+ // }
+
+ // virtual void
+ // bind (MYSQL_BIND* b)
+ // {
+ // b->buffer_type = MYSQL_TYPE_DATE;
+ // b->buffer = &image_;
+ // }
+
+ // private:
+ // void
+ // init (const T& v)
+ // {
+ // bool dummy;
+ // value_traits<T, id_date>::set_image (image_, dummy, v);
+ // }
+
+ // private:
+ // MYSQL_TIME image_;
+ // };
+
+ // @@ TIME
+ //
+ // template <typename T>
+ // struct query_param_impl<T, id_time>: query_param
+ // {
+ // query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ // query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ // virtual bool
+ // init ()
+ // {
+ // init (*static_cast<const T*> (value_));
+ // return false;
+ // }
+
+ // virtual void
+ // bind (MYSQL_BIND* b)
+ // {
+ // b->buffer_type = MYSQL_TYPE_TIME;
+ // b->buffer = &image_;
+ // }
+
+ // private:
+ // void
+ // init (const T& v)
+ // {
+ // bool dummy;
+ // value_traits<T, id_time>::set_image (image_, dummy, v);
+ // }
+
+ // private:
+ // MYSQL_TIME image_;
+ // };
+
+ // @@ TIMESTAMP
+ //
+ // template <typename T>
+ // struct query_param_impl<T, id_timestamp>: query_param
+ // {
+ // query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ // query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ // virtual bool
+ // init ()
+ // {
+ // init (*static_cast<const T*> (value_));
+ // return false;
+ // }
+
+ // virtual void
+ // bind (MYSQL_BIND* b)
+ // {
+ // b->buffer_type = MYSQL_TYPE_TIMESTAMP;
+ // b->buffer = &image_;
+ // }
+
+ // private:
+ // void
+ // init (const T& v)
+ // {
+ // bool dummy;
+ // value_traits<T, id_timestamp>::set_image (image_, dummy, v);
+ // }
+
+ // private:
+ // MYSQL_TIME image_;
+ // };
+
+ // STRING
+ //
+ template <typename T>
+ struct query_param_impl<T, id_string>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ return init (*static_cast<const T*> (value_));
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::text;
+ b->buffer = buffer_.data ();
+ b->capacity = buffer_.capacity ();
+ b->size = &size_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return text_oid;
+ }
+
+ private:
+ bool
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size, cap (buffer_.capacity ());
+ value_traits<T, id_string>::set_image (buffer_, size, dummy, v);
+ size_ = size;
+ return cap != buffer_.capacity ();
+ }
+
+ private:
+ details::buffer buffer_;
+ std::size_t size_;
+ };
+
+ // BYTEA
+ //
+ template <typename T>
+ struct query_param_impl<T, id_bytea>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ return init (*static_cast<const T*> (value_));
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::bytea;
+ b->buffer = buffer_.data ();
+ b->capacity = buffer_.capacity ();
+ b->size = &size_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return bytea_oid;
+ }
+
+ private:
+ bool
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size, cap (buffer_.capacity ());
+ value_traits<T, id_bytea>::set_image (buffer_, size, dummy, v);
+ size_ = size;
+ return cap != buffer_.capacity ();
+ }
+
+ private:
+ details::buffer buffer_;
+ std::size_t size_;
+ };
+
+ // @@ BIT
+ //
+ // template <typename T>
+ // struct query_param_impl<T, id_bit>: query_param
+ // {
+ // query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ // query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ // virtual bool
+ // init ()
+ // {
+ // init (*static_cast<const T*> (value_));
+ // return false;
+ // }
+
+ // virtual void
+ // bind (pgsql::bind* b)
+ // {
+ // b->type = bind::bit;
+ // b->buffer = buffer_;
+ // b->capacity = sizeof (buffer_);
+ // b->size = &size_;
+ // }
+
+ // private:
+ // void
+ // init (const T& v)
+ // {
+ // bool dummy;
+ // std::size_t size;
+ // value_traits<T, id_bit>::set_image (
+ // buffer_, sizeof (buffer_), size, dummy, v);
+ // size_ = static_cast<unsigned long> (size);
+ // }
+
+ // private:
+ // // Max 64 bit.
+ // //
+ // unsigned char buffer_[8];
+ // unsigned long size_;
+ // };
+
+ // VARBIT
+ //
+ template <typename T>
+ struct query_param_impl<T, id_varbit>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ return init (*static_cast<const T*> (value_));
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::varbit;
+ b->buffer = buffer_.data ();
+ b->capacity = buffer_.capacity ();
+ b->size = &size_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return varbit_oid;
+ }
+
+ private:
+ bool
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size, cap (buffer_.capacity ());
+ value_traits<T, id_varbit>::set_image (buffer_, size, dummy, v);
+ size_ = size;
+ return cap != buffer_.capacity ();
+ }
+
+ private:
+ details::buffer buffer_;
+ std::size_t size_;
+ };
+
+ // UUID
+ //
+ template <typename T>
+ struct query_param_impl<T, id_uuid>: query_param
+ {
+ query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+ query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (pgsql::bind* b)
+ {
+ b->type = bind::uuid;
+ b->buffer = buffer_;
+ }
+
+ virtual unsigned int
+ oid () const
+ {
+ return uuid_oid;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_uuid>::set_image (buffer_, dummy, v);
+ }
+
+ private:
+ unsigned char buffer_[16];
+ };
+ }
+}
+
+// odb::query specialization for PostgreSQL.
+//
+namespace odb
+{
+ template <typename T>
+ class query<T, pgsql::query>: public object_traits<T>::query_type
+ {
+ public:
+ // We don't define any typedefs here since they may clash with
+ // column names defined by our base type.
+ //
+
+ query ()
+ {
+ }
+
+ explicit
+ query (const std::string& q)
+ : object_traits<T>::query_type (q)
+ {
+ }
+
+ template <typename T2>
+ explicit
+ query (pgsql::val_bind<T2> v)
+ : object_traits<T>::query_type (pgsql::query (v))
+ {
+ }
+
+ template <typename T2>
+ explicit
+ query (pgsql::ref_bind<T2> r)
+ : object_traits<T>::query_type (pgsql::query (r))
+ {
+ }
+
+ query (const pgsql::query& q)
+ : object_traits<T>::query_type (q)
+ {
+ }
+
+ template <pgsql::database_type_id ID>
+ query (const pgsql::query_column<bool, ID>& qc)
+ : object_traits<T>::query_type (qc)
+ {
+ }
+ };
+}
+
+#include <odb/pgsql/query.ixx>
+#include <odb/pgsql/query.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_PGSQL_QUERY_HXX
diff --git a/odb/pgsql/query.ixx b/odb/pgsql/query.ixx
new file mode 100644
index 0000000..05561a2
--- /dev/null
+++ b/odb/pgsql/query.ixx
@@ -0,0 +1,28 @@
+// file : odb/pgsql/query.ixx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace pgsql
+ {
+ template <typename T, database_type_id ID>
+ inline void query::
+ append (val_bind<T> v)
+ {
+ add (
+ details::shared_ptr<query_param> (
+ new (details::shared) query_param_impl<T, ID> (v)));
+ }
+
+ template <typename T, database_type_id ID>
+ inline void query::
+ append (ref_bind<T> r)
+ {
+ add (
+ details::shared_ptr<query_param> (
+ new (details::shared) query_param_impl<T, ID> (r)));
+ }
+ }
+}
diff --git a/odb/pgsql/query.txx b/odb/pgsql/query.txx
new file mode 100644
index 0000000..7d80f2b
--- /dev/null
+++ b/odb/pgsql/query.txx
@@ -0,0 +1,110 @@
+// file : odb/pgsql/query.txx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace pgsql
+ {
+ // query
+ //
+
+ template <database_type_id ID>
+ query::
+ query (const query_column<bool, ID>& c)
+ : clause_ (c.name ()), binding_ (0, 0), native_binding_ (0, 0, 0, 0)
+ {
+ // Cannot use IS TRUE here since database type can be a non-
+ // integral type.
+ //
+ clause_ += " = ";
+ append<bool, ID> (val_bind<bool> (true));
+ }
+
+ // query_column
+ //
+ template <typename T, database_type_id ID>
+ query query_column<T, ID>::
+ in (const T& v1, const T& v2) const
+ {
+ query q (name_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2));
+ q += ")";
+ return q;
+ }
+
+ template <typename T, database_type_id ID>
+ query query_column<T, ID>::
+ in (const T& v1, const T& v2, const T& v3) const
+ {
+ query q (name_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v3));
+ q += ")";
+ return q;
+ }
+
+ template <typename T, database_type_id ID>
+ query query_column<T, ID>::
+ in (const T& v1, const T& v2, const T& v3, const T& v4) const
+ {
+ query q (name_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v3));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v4));
+ q += ")";
+ return q;
+ }
+
+ template <typename T, database_type_id ID>
+ query query_column<T, ID>::
+ in (const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) const
+ {
+ query q (name_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v3));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v4));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v5));
+ q += ")";
+ return q;
+ }
+
+ template <typename T, database_type_id ID>
+ template <typename I>
+ query query_column<T, ID>::
+ in_range (I begin, I end) const
+ {
+ query q (name_);
+ q += "IN (";
+
+ for (I i (begin); i != end; ++i)
+ {
+ if (i != begin)
+ q += ",";
+
+ q.append<T, ID> (val_bind<T> (*i));
+ }
+ q += ")";
+ return q;
+ }
+ }
+}
diff --git a/odb/pgsql/result.hxx b/odb/pgsql/result.hxx
new file mode 100644
index 0000000..9510680
--- /dev/null
+++ b/odb/pgsql/result.hxx
@@ -0,0 +1,78 @@
+// file : odb/pgsql/result.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_PGSQL_RESULT_HXX
+#define ODB_PGSQL_RESULT_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/result.hxx>
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/pgsql/version.hxx>
+#include <odb/pgsql/forward.hxx> // query, query_params
+#include <odb/pgsql/statement.hxx>
+
+#include <odb/pgsql/details/export.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ template <typename T>
+ class result_impl: public odb::result_impl<T>
+ {
+ public:
+ typedef typename odb::result_impl<T>::pointer_type pointer_type;
+ typedef typename odb::result_impl<T>::pointer_traits pointer_traits;
+
+ typedef typename odb::result_impl<T>::object_type object_type;
+ typedef typename odb::result_impl<T>::id_type id_type;
+ typedef typename odb::result_impl<T>::object_traits object_traits;
+
+
+ virtual
+ ~result_impl ();
+
+ result_impl (const query&,
+ details::shared_ptr<select_statement>,
+ object_statements<object_type>&);
+
+ virtual void
+ load (object_type&);
+
+ virtual id_type
+ load_id ();
+
+ virtual void
+ next ();
+
+ virtual void
+ cache ();
+
+ virtual std::size_t
+ size ();
+
+ using odb::result_impl<T>::current;
+
+ private:
+ void
+ load_image ();
+
+ private:
+ details::shared_ptr<select_statement> statement_;
+ object_statements<object_type>& statements_;
+ std::size_t count_;
+ };
+ }
+}
+
+#include <odb/pgsql/result.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_PGSQL_RESULT_HXX
diff --git a/odb/pgsql/result.txx b/odb/pgsql/result.txx
new file mode 100644
index 0000000..f96fe81
--- /dev/null
+++ b/odb/pgsql/result.txx
@@ -0,0 +1,134 @@
+// file : odb/pgsql/result.txx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/exceptions.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ template <typename T>
+ result_impl<T>::
+ ~result_impl ()
+ {
+ }
+
+ template <typename T>
+ result_impl<T>::
+ result_impl (const query&,
+ details::shared_ptr<select_statement> st,
+ object_statements<object_type>& sts)
+ : odb::result_impl<T> (sts.connection ().database ()),
+ statement_ (st),
+ statements_ (sts),
+ count_ (0)
+ {
+ }
+
+ template <typename T>
+ void result_impl<T>::
+ load (object_type& obj)
+ {
+ load_image ();
+
+ // This is a top-level call so the statements cannot be locked.
+ //
+ assert (!statements_.locked ());
+ typename object_statements<object_type>::auto_lock l (statements_);
+
+ typename object_traits::image_type& i (statements_.image ());
+ object_traits::init (obj, i, this->database ());
+
+ // Initialize the id image and binding and load the rest of the object
+ // (containers, etc).
+ //
+ typename object_traits::id_image_type& idi (statements_.id_image ());
+ object_traits::init (idi, object_traits::id (i));
+
+ binding& idb (statements_.id_image_binding ());
+ if (idi.version != statements_.id_image_version () || idb.version == 0)
+ {
+ object_traits::bind (idb.bind, idi);
+ statements_.id_image_version (idi.version);
+ idb.version++;
+ }
+
+ object_traits::load_ (statements_, obj);
+
+ statements_.load_delayed ();
+ l.unlock ();
+ }
+
+ template <typename T>
+ typename result_impl<T>::id_type result_impl<T>::
+ load_id ()
+ {
+ load_image ();
+ return object_traits::id (statements_.image ());
+ }
+
+ template <typename T>
+ void result_impl<T>::
+ next ()
+ {
+ this->current (pointer_type ());
+
+ // Increment the position and postpone the actual row fetching
+ // until later. This way if the same object is loaded in between
+ // iteration, the image won't be messed up.
+ //
+ if (++count_ > statement_->result_size ())
+ this->end_ = true;
+ }
+
+ template <typename T>
+ void result_impl<T>::
+ load_image ()
+ {
+ // The image can grow between calls to load() as a result of other
+ // statements execution.
+ //
+ typename object_traits::image_type& im (statements_.image ());
+
+ if (im.version != statements_.out_image_version ())
+ {
+ binding& b (statements_.out_image_binding ());
+ object_traits::bind (b.bind, im, true);
+ statements_.out_image_version (im.version);
+ b.version++;
+ }
+
+ select_statement::result r (statement_->fetch ());
+
+ if (r == select_statement::truncated)
+ {
+ if (object_traits::grow (im, statements_.out_image_truncated ()))
+ im.version++;
+
+ if (im.version != statements_.out_image_version ())
+ {
+ binding& b (statements_.out_image_binding ());
+ object_traits::bind (b.bind, im, true);
+ statements_.out_image_version (im.version);
+ b.version++;
+ statement_->refetch ();
+ }
+ }
+ }
+
+ template <typename T>
+ void result_impl<T>::
+ cache ()
+ {
+ }
+
+ template <typename T>
+ std::size_t result_impl<T>::
+ size ()
+ {
+ return statement_->result_size ();
+ }
+ }
+}