aboutsummaryrefslogtreecommitdiff
path: root/odb/pgsql/query.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/pgsql/query.cxx')
-rw-r--r--odb/pgsql/query.cxx256
1 files changed, 256 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_;
+ }
+ }
+}