aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/mssql/binding.hxx5
-rw-r--r--odb/mssql/makefile2
-rw-r--r--odb/mssql/mssql-types.hxx15
-rw-r--r--odb/mssql/object-result.hxx126
-rw-r--r--odb/mssql/object-result.txx288
-rw-r--r--odb/mssql/object-statements.txx6
-rw-r--r--odb/mssql/query-const-expr.cxx16
-rw-r--r--odb/mssql/query.cxx390
-rw-r--r--odb/mssql/query.hxx2315
-rw-r--r--odb/mssql/query.ixx28
-rw-r--r--odb/mssql/query.txx111
-rw-r--r--odb/mssql/result.hxx26
-rw-r--r--odb/mssql/statement.cxx39
-rw-r--r--odb/mssql/statement.hxx20
-rw-r--r--odb/mssql/view-result.hxx76
-rw-r--r--odb/mssql/view-result.txx131
-rw-r--r--odb/mssql/view-statements.txx3
17 files changed, 3581 insertions, 16 deletions
diff --git a/odb/mssql/binding.hxx b/odb/mssql/binding.hxx
index f8f4fc4..7c420f9 100644
--- a/odb/mssql/binding.hxx
+++ b/odb/mssql/binding.hxx
@@ -23,9 +23,10 @@ namespace odb
{
public:
typedef mssql::bind bind_type;
+ typedef mssql::change_callback change_callback_type;
binding (bind_type* b, std::size_t n)
- : bind (b), count (n), version (0)
+ : bind (b), count (n), version (0), change_callback (0)
{
}
@@ -33,6 +34,8 @@ namespace odb
std::size_t count;
std::size_t version;
+ change_callback_type* change_callback;
+
private:
binding (const binding&);
binding& operator= (const binding&);
diff --git a/odb/mssql/makefile b/odb/mssql/makefile
index 6e054d5..546bdbf 100644
--- a/odb/mssql/makefile
+++ b/odb/mssql/makefile
@@ -14,6 +14,8 @@ database.cxx \
error.cxx \
exceptions.cxx \
object-statements.cxx \
+query.cxx \
+query-const-expr.cxx \
statement.cxx \
statements-base.cxx \
tracer.cxx \
diff --git a/odb/mssql/mssql-types.hxx b/odb/mssql/mssql-types.hxx
index 43e6d6e..9f3d1be 100644
--- a/odb/mssql/mssql-types.hxx
+++ b/odb/mssql/mssql-types.hxx
@@ -141,6 +141,21 @@ namespace odb
// value 8 indicates the SMALLDATETIME type
// which has no seconds.
};
+
+ // An instance of this structure specifies the function to invoke and
+ // the context to pass when the object/view image is about to be
+ // modified. This mechanism is used by the query machinery to save the
+ // image between result iteration and dereferencing if something gets
+ // executed between these two operations that would overwrite the
+ // image.
+ //
+ struct change_callback
+ {
+ change_callback (): callback (0), context (0) {};
+
+ void (*callback) (void*);
+ void* context;
+ };
}
}
diff --git a/odb/mssql/object-result.hxx b/odb/mssql/object-result.hxx
new file mode 100644
index 0000000..9eaa4f5
--- /dev/null
+++ b/odb/mssql/object-result.hxx
@@ -0,0 +1,126 @@
+// file : odb/mssql/object-result.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_OBJECT_RESULT_HXX
+#define ODB_MSSQL_OBJECT_RESULT_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx> // query, object_statements
+#include <odb/mssql/result.hxx>
+#include <odb/mssql/statement.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ template <typename T>
+ class object_result_impl: public odb::object_result_impl<T>
+ {
+ public:
+ typedef odb::object_result_impl<T> base_type;
+
+ typedef typename base_type::object_type object_type;
+ typedef typename base_type::object_traits object_traits;
+ typedef typename base_type::id_type id_type;
+
+ typedef typename base_type::pointer_type pointer_type;
+ typedef typename base_type::pointer_traits pointer_traits;
+
+ virtual
+ ~object_result_impl ();
+
+ object_result_impl (const query&,
+ details::shared_ptr<select_statement>,
+ object_statements<object_type>&);
+
+ virtual void
+ load (object_type&, bool fetch);
+
+ virtual id_type
+ load_id ();
+
+ virtual void
+ next ();
+
+ virtual void
+ cache ();
+
+ virtual std::size_t
+ size ();
+
+ using base_type::current;
+
+ private:
+ typedef mssql::change_callback change_callback_type;
+
+ static void
+ change_callback (void* context);
+
+ private:
+ details::shared_ptr<select_statement> statement_;
+ object_statements<object_type>& statements_;
+ bool use_copy_;
+ typename object_traits::image_type* image_copy_;
+ };
+
+ template <typename T>
+ class object_result_impl_no_id: public odb::object_result_impl_no_id<T>
+ {
+ public:
+ typedef odb::object_result_impl_no_id<T> base_type;
+
+ typedef typename base_type::object_type object_type;
+ typedef typename base_type::object_traits object_traits;
+
+ typedef typename base_type::pointer_type pointer_type;
+ typedef typename base_type::pointer_traits pointer_traits;
+
+ virtual
+ ~object_result_impl_no_id ();
+
+ object_result_impl_no_id (const query&,
+ details::shared_ptr<select_statement>,
+ object_statements_no_id<object_type>&);
+
+ virtual void
+ load (object_type&);
+
+ virtual void
+ next ();
+
+ virtual void
+ cache ();
+
+ virtual std::size_t
+ size ();
+
+ using base_type::current;
+
+ private:
+ typedef mssql::change_callback change_callback_type;
+
+ static void
+ change_callback (void* context);
+
+ private:
+ details::shared_ptr<select_statement> statement_;
+ object_statements_no_id<object_type>& statements_;
+ bool use_copy_;
+ typename object_traits::image_type* image_copy_;
+ };
+ }
+}
+
+#include <odb/mssql/object-result.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_OBJECT_RESULT_HXX
diff --git a/odb/mssql/object-result.txx b/odb/mssql/object-result.txx
new file mode 100644
index 0000000..338f78a
--- /dev/null
+++ b/odb/mssql/object-result.txx
@@ -0,0 +1,288 @@
+// file : odb/mssql/object-result.txx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <cassert>
+
+#include <odb/callback.hxx>
+#include <odb/exceptions.hxx>
+
+#include <odb/mssql/object-statements.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ //
+ // object_result_impl
+ //
+
+ template <typename T>
+ object_result_impl<T>::
+ ~object_result_impl ()
+ {
+ change_callback_type& cc (statements_.image ().change_callback_);
+
+ if (cc.context == this)
+ {
+ cc.context = 0;
+ cc.callback = 0;
+ }
+
+ delete image_copy_;
+ }
+
+ template <typename T>
+ object_result_impl<T>::
+ object_result_impl (const query&,
+ details::shared_ptr<select_statement> statement,
+ object_statements<object_type>& statements)
+ : base_type (statements.connection ().database ()),
+ statement_ (statement),
+ statements_ (statements),
+ use_copy_ (false),
+ image_copy_ (0)
+ {
+ }
+
+ template <typename T>
+ void object_result_impl<T>::
+ load (object_type& obj, bool)
+ {
+ // This is a top-level call so the statements cannot be locked.
+ //
+ assert (!statements_.locked ());
+ typename object_statements<object_type>::auto_lock l (statements_);
+
+ odb::database& db (this->database ());
+ object_traits::callback (db, obj, callback_event::pre_load);
+
+ typename object_traits::image_type& i (
+ use_copy_ ? *image_copy_ : statements_.image ());
+
+ object_traits::init (obj, i, db);
+
+ // If we are using a copy, make sure the callback information for
+ // long data also comes from the copy.
+ //
+ statement_->stream_result (
+ use_copy_ ? &statements_.image () : 0,
+ use_copy_ ? image_copy_ : 0);
+
+ // 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 ();
+ object_traits::callback (db, obj, callback_event::post_load);
+ }
+
+ template <typename T>
+ typename object_result_impl<T>::id_type
+ object_result_impl<T>::
+ load_id ()
+ {
+ return object_traits::id (
+ use_copy_ ? *image_copy_ : statements_.image ());
+ }
+
+ template <typename T>
+ void object_result_impl<T>::
+ next ()
+ {
+ this->current (pointer_type ());
+
+ typename object_traits::image_type& im (statements_.image ());
+ change_callback_type& cc (im.change_callback_);
+
+ if (cc.context == this)
+ {
+ cc.callback = 0;
+ cc.context = 0;
+ }
+
+ use_copy_ = false;
+
+ if (im.version != statements_.select_image_version ())
+ {
+ binding& b (statements_.select_image_binding ());
+ object_traits::bind (b.bind, im, statement_select);
+ statements_.select_image_version (im.version);
+ b.version++;
+ }
+
+ if (statement_->fetch () == select_statement::no_data)
+ this->end_ = true;
+ else
+ {
+ cc.callback = &change_callback;
+ cc.context = this;
+ }
+ }
+
+ template <typename T>
+ void object_result_impl<T>::
+ cache ()
+ {
+ }
+
+ template <typename T>
+ std::size_t object_result_impl<T>::
+ size ()
+ {
+ throw result_not_cached ();
+ }
+
+ template <typename T>
+ void object_result_impl<T>::
+ change_callback (void* c)
+ {
+ object_result_impl<T>* r (static_cast<object_result_impl<T>*> (c));
+ typename object_traits::image_type& im (r->statements_.image ());
+
+ if (r->image_copy_ == 0)
+ r->image_copy_ = new typename object_traits::image_type (im);
+ else
+ *r->image_copy_ = im;
+
+ im.change_callback_.callback = 0;
+ im.change_callback_.context = 0;
+
+ r->use_copy_ = true;
+ }
+
+ //
+ // object_result_impl_no_id
+ //
+
+ template <typename T>
+ object_result_impl_no_id<T>::
+ ~object_result_impl_no_id ()
+ {
+ change_callback_type& cc (statements_.image ().change_callback_);
+
+ if (cc.context == this)
+ {
+ cc.context = 0;
+ cc.callback = 0;
+ }
+
+ delete image_copy_;
+ }
+
+ template <typename T>
+ object_result_impl_no_id<T>::
+ object_result_impl_no_id (const query&,
+ details::shared_ptr<select_statement> statement,
+ object_statements_no_id<object_type>& statements)
+ : base_type (statements.connection ().database ()),
+ statement_ (statement),
+ statements_ (statements),
+ use_copy_ (false),
+ image_copy_ (0)
+ {
+ }
+
+ template <typename T>
+ void object_result_impl_no_id<T>::
+ load (object_type& obj)
+ {
+ odb::database& db (this->database ());
+
+ object_traits::callback (db, obj, callback_event::pre_load);
+
+ object_traits::init (obj,
+ use_copy_ ? *image_copy_ : statements_.image (),
+ db);
+
+ // If we are using a copy, make sure the callback information for
+ // long data also comes from the copy.
+ //
+ statement_->stream_result (
+ use_copy_ ? &statements_.image () : 0,
+ use_copy_ ? image_copy_ : 0);
+
+ object_traits::callback (db, obj, callback_event::post_load);
+ }
+
+ template <typename T>
+ void object_result_impl_no_id<T>::
+ next ()
+ {
+ this->current (pointer_type ());
+
+ typename object_traits::image_type& im (statements_.image ());
+ change_callback_type& cc (im.change_callback_);
+
+ if (cc.context == this)
+ {
+ cc.callback = 0;
+ cc.context = 0;
+ }
+
+ use_copy_ = false;
+
+ if (im.version != statements_.select_image_version ())
+ {
+ binding& b (statements_.select_image_binding ());
+ object_traits::bind (b.bind, im, statement_select);
+ statements_.select_image_version (im.version);
+ b.version++;
+ }
+
+ if (statement_->fetch () == select_statement::no_data)
+ this->end_ = true;
+ else
+ {
+ cc.callback = &change_callback;
+ cc.context = this;
+ }
+ }
+
+ template <typename T>
+ void object_result_impl_no_id<T>::
+ cache ()
+ {
+ }
+
+ template <typename T>
+ std::size_t object_result_impl_no_id<T>::
+ size ()
+ {
+ throw result_not_cached ();
+ }
+
+ template <typename T>
+ void object_result_impl_no_id<T>::
+ change_callback (void* c)
+ {
+ object_result_impl_no_id<T>* r (
+ static_cast<object_result_impl_no_id<T>*> (c));
+
+ typename object_traits::image_type im (r->statements_.image ());
+
+ if (r->image_copy_ == 0)
+ r->image_copy_ = new typename object_traits::image_type (im);
+ else
+ *r->image_copy_ = im;
+
+ im.change_callback_.callback = 0;
+ im.change_callback_.context = 0;
+
+ r->use_copy_ = true;
+ }
+ }
+}
diff --git a/odb/mssql/object-statements.txx b/odb/mssql/object-statements.txx
index 8b273d8..9b61e7c 100644
--- a/odb/mssql/object-statements.txx
+++ b/odb/mssql/object-statements.txx
@@ -63,8 +63,7 @@ namespace odb
id_image_.version = 0;
id_image_version_ = 0;
- //@@ TODO
- // select_image_binding_.change_callback = image_.change_callback ();
+ select_image_binding_.change_callback = image_.change_callback ();
std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_));
std::memset (update_image_bind_, 0, sizeof (update_image_bind_));
@@ -159,8 +158,7 @@ namespace odb
select_image_version_ = 0;
insert_image_version_ = 0;
- //@@ TODO
- // select_image_binding_.change_callback = image_.change_callback ();
+ select_image_binding_.change_callback = image_.change_callback ();
std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_));
std::memset (select_image_bind_, 0, sizeof (select_image_bind_));
diff --git a/odb/mssql/query-const-expr.cxx b/odb/mssql/query-const-expr.cxx
new file mode 100644
index 0000000..a826a34
--- /dev/null
+++ b/odb/mssql/query-const-expr.cxx
@@ -0,0 +1,16 @@
+// file : odb/mssql/query-const-expr.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <odb/mssql/query.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ // Sun CC cannot handle this in query.cxx.
+ //
+ const query query::true_expr (true);
+ }
+}
diff --git a/odb/mssql/query.cxx b/odb/mssql/query.cxx
new file mode 100644
index 0000000..0e50a79
--- /dev/null
+++ b/odb/mssql/query.cxx
@@ -0,0 +1,390 @@
+// file : odb/mssql/query.cxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <cstddef> // std::size_t
+#include <cstring> // std::memset, std::memcpy
+
+#include <odb/mssql/query.hxx>
+
+using namespace std;
+
+namespace odb
+{
+ namespace mssql
+ {
+ // query_param
+ //
+ query_param::
+ ~query_param ()
+ {
+ }
+
+ // query
+ //
+ query::
+ query (const query& q)
+ : clause_ (q.clause_),
+ parameters_ (q.parameters_),
+ bind_ (q.bind_),
+ binding_ (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++;
+ }
+ }
+
+ query& query::
+ operator= (const query& q)
+ {
+ if (this != &q)
+ {
+ clause_ = q.clause_;
+ parameters_ = q.parameters_;
+ bind_ = q.bind_;
+
+ size_t n (bind_.size ());
+ binding_.bind = n != 0 ? &bind_[0] : 0;
+ binding_.count = n;
+ binding_.version++;
+ }
+
+ return *this;
+ }
+
+ query& query::
+ operator+= (const query& q)
+ {
+ clause_.insert (clause_.end (), q.clause_.begin (), q.clause_.end ());
+
+ size_t n (bind_.size ());
+
+ parameters_.insert (
+ parameters_.end (), q.parameters_.begin (), q.parameters_.end ());
+
+ bind_.insert (
+ bind_.end (), q.bind_.begin (), q.bind_.end ());
+
+ if (n != bind_.size ())
+ {
+ binding_.bind = &bind_[0];
+ binding_.count = bind_.size ();
+ binding_.version++;
+ }
+
+ return *this;
+ }
+
+ void query::
+ append (const string& q)
+ {
+ if (!clause_.empty () && clause_.back ().kind == clause_part::native)
+ {
+ string& s (clause_.back ().part);
+
+ char first (!q.empty () ? q[0] : ' ');
+ char last (!s.empty () ? s[s.size () - 1] : ' ');
+
+ // We don't want extra spaces after '(' as well as before ','
+ // and ')'.
+ //
+ if (last != ' ' && last != '(' &&
+ first != ' ' && first != ',' && first != ')')
+ s += ' ';
+
+ s += q;
+ }
+ else
+ clause_.push_back (clause_part (clause_part::native, q));
+ }
+
+ void query::
+ append (const char* table, const char* column)
+ {
+ string s ("[");
+ s += table;
+ s += "].[";
+ s += column;
+ s += ']';
+
+ clause_.push_back (clause_part (clause_part::column, s));
+ }
+
+ void query::
+ add (details::shared_ptr<query_param> p)
+ {
+ clause_.push_back (clause_part (clause_part::param));
+
+ 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);
+ }
+
+ 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;
+ }
+
+ static bool
+ check_prefix (const string& s)
+ {
+ string::size_type n;
+
+ // It is easier to compare to upper and lower-case versions
+ // rather than getting involved with the portable case-
+ // insensitive string comparison mess.
+ //
+ if (s.compare (0, (n = 5), "WHERE") == 0 ||
+ s.compare (0, (n = 5), "where") == 0 ||
+ s.compare (0, (n = 6), "SELECT") == 0 ||
+ s.compare (0, (n = 6), "select") == 0 ||
+ s.compare (0, (n = 8), "ORDER BY") == 0 ||
+ s.compare (0, (n = 8), "order by") == 0 ||
+ s.compare (0, (n = 8), "GROUP BY") == 0 ||
+ s.compare (0, (n = 8), "group by") == 0 ||
+ s.compare (0, (n = 6), "HAVING") == 0 ||
+ s.compare (0, (n = 6), "having") == 0)
+ {
+ // It either has to be an exact match, or there should be
+ // a whitespace following the keyword.
+ //
+ if (s.size () == n || s[n] == ' ' || s[n] =='\t')
+ return true;
+ }
+
+ return false;
+ }
+
+ void query::
+ optimize ()
+ {
+ // Remove a single TRUE literal or one that is followe by one of
+ // the other clauses. This avoids useless WHERE clauses like
+ //
+ // WHERE TRUE GROUP BY foo
+ //
+ clause_type::iterator i (clause_.begin ()), e (clause_.end ());
+
+ if (i != e && i->kind == clause_part::boolean && i->bool_part)
+ {
+ clause_type::iterator j (i + 1);
+
+ if (j == e ||
+ (j->kind == clause_part::native && check_prefix (j->part)))
+ clause_.erase (i);
+ }
+ }
+
+ const char* query::
+ clause_prefix () const
+ {
+ if (!clause_.empty ())
+ {
+ const clause_part& p (clause_.front ());
+
+ if (p.kind == clause_part::native && check_prefix (p.part))
+ return "";
+
+ return "WHERE ";
+ }
+
+ return "";
+ }
+
+ string query::
+ clause () const
+ {
+ string r;
+
+ for (clause_type::const_iterator i (clause_.begin ()),
+ end (clause_.end ());
+ i != end;
+ ++i)
+ {
+ char last (!r.empty () ? r[r.size () - 1] : ' ');
+
+ switch (i->kind)
+ {
+ case clause_part::column:
+ {
+ if (last != ' ' && last != '(')
+ r += ' ';
+
+ r += i->part;
+ break;
+ }
+ case clause_part::param:
+ {
+ if (last != ' ' && last != '(')
+ r += ' ';
+
+ r += '?';
+ break;
+ }
+ case clause_part::native:
+ {
+ // We don't want extra spaces after '(' as well as before ','
+ // and ')'.
+ //
+ const string& p (i->part);
+ char first (!p.empty () ? p[0] : ' ');
+
+ if (last != ' ' && last != '(' &&
+ first != ' ' && first != ',' && first != ')')
+ r += ' ';
+
+ r += p;
+ break;
+ }
+ case clause_part::boolean:
+ {
+ if (last != ' ' && last != '(')
+ r += ' ';
+
+ // SQL Server does not have "true" TRUE and FALSE boolean
+ // constants (there seem to be TRUE and FALSE literals but
+ // they are interpreted as integers). Boolean values seem
+ // to only be created as the result of boolean expressions.
+ //
+ r += i->bool_part ? "1 = 1" : "1 = 0";
+ break;
+ }
+ }
+ }
+
+ return clause_prefix () + r;
+ }
+
+ query
+ operator&& (const query& x, const query& y)
+ {
+ // Optimize cases where one or both sides are constant truth.
+ //
+ bool xt (x.const_true ()), yt (y.const_true ());
+
+ if (xt && yt)
+ return x;
+
+ if (xt)
+ return y;
+
+ if (yt)
+ return x;
+
+ query r ("(");
+ r += x;
+ r += ") AND (";
+ r += y;
+ r += ")";
+ return r;
+ }
+
+ query
+ operator|| (const query& x, const query& y)
+ {
+ query r ("(");
+ r += x;
+ r += ") OR (";
+ r += y;
+ r += ")";
+ return r;
+ }
+
+ query
+ operator! (const query& x)
+ {
+ query r ("NOT (");
+ r += x;
+ r += ")";
+ return r;
+ }
+
+ //
+ // long_query_param_impl
+ //
+
+ void long_query_param_impl::
+ copy ()
+ {
+ size_ = 0;
+
+ // The below code is the same as in statement.cxx.
+ //
+ const void* buf (&callback_);
+ char tmp_buf[1024];
+
+ size_t position (0);
+ for (;;)
+ {
+ size_t n;
+ chunk_type chunk;
+
+ callback_.callback.param (
+ callback_.context.param,
+ &position,
+ &buf,
+ &n,
+ &chunk,
+ tmp_buf,
+ sizeof (tmp_buf));
+
+ if (chunk != chunk_null)
+ {
+ if (buf_.capacity () < size_ + n)
+ buf_.capacity (size_ + n, size_);
+
+ memcpy (buf_.data () + size_, buf, n);
+ size_ += n;
+ }
+
+ if (chunk == chunk_one ||
+ chunk == chunk_last ||
+ chunk == chunk_null)
+ break;
+ }
+ }
+ }
+}
diff --git a/odb/mssql/query.hxx b/odb/mssql/query.hxx
new file mode 100644
index 0000000..94faceb
--- /dev/null
+++ b/odb/mssql/query.hxx
@@ -0,0 +1,2315 @@
+// file : odb/mssql/query.hxx
+// author : Contantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_QUERY_HXX
+#define ODB_MSSQL_QUERY_HXX
+
+#include <odb/pre.hxx>
+
+#include <string>
+#include <vector>
+#include <cstddef> // std::size_t
+
+#include <odb/query.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx>
+#include <odb/mssql/traits.hxx>
+#include <odb/mssql/binding.hxx>
+#include <odb/mssql/mssql-fwd.hxx>
+#include <odb/mssql/mssql-types.hxx>
+
+#include <odb/details/buffer.hxx>
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/mssql/details/export.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ // For precision, 0 is invalid so we can use it as a special value
+ // to indicate that the precision has not been specified. For scale,
+ // however, 0 is a valid value and for some types (e.g., TIME) if
+ // the scale is not specified, it defaults to something other than
+ // 0. As a result, for scale, the not specific special value will
+ // be 0xFFFF (USHORT_MAX).
+ //
+
+ template <typename T>
+ class val_bind
+ {
+ public:
+ explicit
+ val_bind (const T& v, unsigned short p = 0, unsigned short s = 0xFFFF)
+ : val (v), prec (p), scale (s)
+ {
+ }
+
+ const T& val;
+
+ unsigned short prec;
+ unsigned short scale;
+ };
+
+ template <typename T>
+ class ref_bind
+ {
+ public:
+ explicit
+ ref_bind (const T& r, unsigned short p = 0, unsigned short s = 0xFFFF)
+ : ref (r) , prec (p), scale (s)
+ {
+ }
+
+ const T& ref;
+
+ unsigned short prec;
+ unsigned short scale;
+ };
+
+ struct LIBODB_MSSQL_EXPORT query_param: details::shared_base
+ {
+ typedef mssql::bind bind_type;
+
+ virtual
+ ~query_param ();
+
+ bool
+ reference () const
+ {
+ return value_ != 0;
+ }
+
+ virtual bool
+ init () = 0;
+
+ virtual void
+ bind (bind_type*) = 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_MSSQL_EXPORT query
+ {
+ public:
+ struct clause_part
+ {
+ enum kind_type
+ {
+ column,
+ param,
+ native,
+ boolean
+ };
+
+ clause_part (kind_type k): kind (k) {}
+ clause_part (kind_type k, const std::string& p): kind (k), part (p) {}
+ clause_part (bool p): kind (boolean), bool_part (p) {}
+
+ kind_type kind;
+ std::string part;
+ bool bool_part;
+ };
+
+ query ()
+ : binding_ (0, 0)
+ {
+ }
+
+ // True or false literal.
+ //
+ explicit
+ query (bool v)
+ : binding_ (0, 0)
+ {
+ clause_.push_back (clause_part (v));
+ }
+
+ explicit
+ query (const char* native)
+ : binding_ (0, 0)
+ {
+ clause_.push_back (clause_part (clause_part::native, native));
+ }
+
+ explicit
+ query (const std::string& native)
+ : binding_ (0, 0)
+ {
+ clause_.push_back (clause_part (clause_part::native, native));
+ }
+
+ query (const char* table, const char* column)
+ : binding_ (0, 0)
+ {
+ append (table, column);
+ }
+
+ template <typename T>
+ explicit
+ query (val_bind<T> v)
+ : binding_ (0, 0)
+ {
+ append<T, type_traits<T>::db_type_id> (v);
+ }
+
+ template <typename T>
+ explicit
+ query (ref_bind<T> r)
+ : binding_ (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;
+
+ const char*
+ clause_prefix () const;
+
+ binding&
+ parameters_binding () const;
+
+ public:
+ bool
+ empty () const
+ {
+ return clause_.empty ();
+ }
+
+ static const query true_expr;
+
+ bool
+ const_true () const
+ {
+ return clause_.size () == 1 &&
+ clause_.front ().kind == clause_part::boolean &&
+ clause_.front ().bool_part;
+ }
+
+ void
+ optimize ();
+
+ public:
+ template <typename T>
+ static val_bind<T>
+ _val (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF)
+ {
+ return val_bind<T> (x, prec, scale);
+ }
+
+ template <typename T>
+ static ref_bind<T>
+ _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF)
+ {
+ return ref_bind<T> (x, prec, scale);
+ }
+
+ public:
+ query&
+ operator+= (const query&);
+
+ query&
+ operator+= (const std::string& q)
+ {
+ append (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>);
+
+ void
+ append (const std::string& native);
+
+ void
+ append (const char* table, const char* column);
+
+ private:
+ void
+ add (details::shared_ptr<query_param>);
+
+ private:
+ typedef std::vector<clause_part> clause_type;
+ typedef std::vector<details::shared_ptr<query_param> > parameters_type;
+
+ clause_type clause_;
+ parameters_type parameters_;
+ mutable std::vector<bind> bind_;
+ mutable binding 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;
+ }
+
+ LIBODB_MSSQL_EXPORT query
+ operator&& (const query& x, const query& y);
+
+ LIBODB_MSSQL_EXPORT query
+ operator|| (const query& x, const query& y);
+
+ LIBODB_MSSQL_EXPORT query
+ operator! (const query& x);
+
+ // 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
+ {
+ // Note that we keep shalow copies of the table and column names.
+ //
+ query_column (const char* table,
+ const char* column,
+ unsigned short prec = 0,
+ unsigned short scale = 0xFFFF)
+ : table_ (table), column_ (column), prec_ (prec), scale_ (scale)
+ {
+ }
+
+ const char*
+ table () const
+ {
+ return table_;
+ }
+
+ const char*
+ column () const
+ {
+ return column_;
+ }
+
+ unsigned short
+ prec () const
+ {
+ return prec_;
+ }
+
+ unsigned short
+ scale () const
+ {
+ return scale_;
+ }
+
+ // is_null, is_not_null
+ //
+ public:
+ query
+ is_null () const
+ {
+ query q (table_, column_);
+ q += "IS NULL";
+ return q;
+ }
+
+ query
+ is_not_null () const
+ {
+ query q (table_, column_);
+ 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
+ {
+ v.prec = prec_;
+ v.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ r.prec = prec_;
+ r.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ v.prec = prec_;
+ v.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ r.prec = prec_;
+ r.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ v.prec = prec_;
+ v.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ r.prec = prec_;
+ r.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ v.prec = prec_;
+ v.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ r.prec = prec_;
+ r.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ v.prec = prec_;
+ v.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ r.prec = prec_;
+ r.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ v.prec = prec_;
+ v.scale = scale_;
+
+ query q (table_, column_);
+ 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
+ {
+ r.prec = prec_;
+ r.scale = scale_;
+
+ query q (table_, column_);
+ 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 (table_, column_);
+ q += "=";
+ q.append (c.table (), c.column ());
+ 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 (table_, column_);
+ q += "!=";
+ q.append (c.table (), c.column ());
+ 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 (table_, column_);
+ q += "<";
+ q.append (c.table (), c.column ());
+ 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 (table_, column_);
+ q += ">";
+ q.append (c.table (), c.column ());
+ 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 (table_, column_);
+ q += "<=";
+ q.append (c.table (), c.column ());
+ 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 (table_, column_);
+ q += ">=";
+ q.append (c.table (), c.column ());
+ return q;
+ }
+
+ private:
+ const char* table_;
+ const char* column_;
+
+ unsigned short prec_;
+ unsigned short scale_;
+ };
+
+ // Provide operator+() for using columns to construct native
+ // query fragments (e.g., ORDER BY).
+ //
+ template <typename T, database_type_id ID>
+ inline query
+ operator+ (const query_column<T, ID>& c, const std::string& s)
+ {
+ query q (c.table (), c.column ());
+ q += s;
+ return q;
+ }
+
+ template <typename T, database_type_id ID>
+ inline query
+ operator+ (const std::string& s, const query_column<T, ID>& c)
+ {
+ query q (s);
+ q.append (c.table (), c.column ());
+ return q;
+ }
+
+ template <typename T, database_type_id ID>
+ inline query
+ operator+ (const query_column<T, ID>& c, const query& q)
+ {
+ query r (c.table (), c.column ());
+ r += q;
+ return r;
+ }
+
+ template <typename T, database_type_id ID>
+ inline query
+ operator+ (const query& q, const query_column<T, ID>& c)
+ {
+ query r (q);
+ r.append (c.table (), c.column ());
+ return r;
+ }
+
+ //
+ //
+ template <typename T, database_type_id>
+ struct query_param_impl;
+
+ // id_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 (bind_type* b)
+ {
+ b->type = bind::bit;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_bit>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ unsigned char image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_tinyint.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_tinyint>: 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 (bind_type* b)
+ {
+ b->type = bind::tinyint;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_tinyint>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ unsigned char image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_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 (bind_type* b)
+ {
+ b->type = bind::smallint;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_smallint>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ short image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_int.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_int>: 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 (bind_type* b)
+ {
+ b->type = bind::int_;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_int>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ int image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_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 (bind_type* b)
+ {
+ b->type = bind::bigint;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_bigint>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ long long image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_decimal.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_decimal>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ prec_ (r.prec != 0 ? r.prec : 18), // Default is 18.
+ scale_ (r.scale != 0xFFFF ? r.scale : 0) // Default is 0.
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ prec_ (v.prec != 0 ? v.prec : 18), // Default is 18.
+ scale_ (v.scale)
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::decimal;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ // Encode precision (p) and scale (s) as (p * 100 + s).
+ //
+ b->capacity = static_cast<SQLLEN> (prec_ * 100 + scale_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_decimal>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ unsigned short prec_;
+ unsigned short scale_;
+
+ decimal image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_smallmoney.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_smallmoney>: 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 (bind_type* b)
+ {
+ b->type = bind::smallmoney;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_smallmoney>::set_image (image_, dummy, v);
+ size_ind_ = 4;
+ }
+
+ private:
+ smallmoney image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_money.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_money>: 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 (bind_type* b)
+ {
+ b->type = bind::money;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_money>::set_image (image_, dummy, v);
+ size_ind_ = 8;
+ }
+
+ private:
+ money image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_float4.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_float4>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ prec_ (r.prec != 0 ? r.prec : 24)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ prec_ (v.prec != 0 ? v.prec : 24)
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::float4;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (prec_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_float4>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ unsigned short prec_;
+ float image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_float8.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_float8>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ prec_ (r.prec != 0 ? r.prec : 53)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ prec_ (v.prec != 0 ? v.prec : 53)
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::float8;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (prec_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_float8>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ unsigned short prec_;
+ double image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_string.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_string>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ // Default to short data max (700).
+ buf_ (r.prec != 0 ? r.prec : 700)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ // Default to short data max (700).
+ buf_ (v.prec != 0 ? v.prec : 700)
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::string;
+ b->buffer = buf_.data ();
+ b->size_ind = &size_ind_;
+ // Extra byte for the null terminator (convention).
+ //
+ b->capacity = static_cast<SQLLEN> (buf_.capacity () + 1);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size (0);
+ value_traits<T, id_string>::set_image (
+ buf_.data (), buf_.capacity (), size, dummy, v);
+ size_ind_ = static_cast<SQLLEN> (size);
+ }
+
+ private:
+ details::buffer buf_;
+ SQLLEN size_ind_;
+ };
+
+ // id_nstring.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_nstring>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ // Precision is in 2-byte chars. Default to short data max (700).
+ buf_ (r.prec != 0 ? r.prec * 2 : 700)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ // Precision is in 2-byte chars. Default to short data max (700).
+ buf_ (v.prec != 0 ? v.prec * 2 : 700)
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::nstring;
+ b->buffer = buf_.data ();
+ b->size_ind = &size_ind_;
+ // Extra two bytes for the null terminator (convention).
+ //
+ b->capacity = static_cast<SQLLEN> (buf_.capacity () + 2);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size (0);
+ value_traits<T, id_nstring>::set_image (
+ reinterpret_cast<ucs2_char*> (buf_.data ()),
+ buf_.capacity (),
+ size,
+ dummy,
+ v);
+ size_ind_ = static_cast<SQLLEN> (size);
+ }
+
+ private:
+ details::buffer buf_;
+ SQLLEN size_ind_;
+ };
+
+ // id_binary.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_binary>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ // Default to short data max (700).
+ buf_ (r.prec != 0 ? r.prec : 700)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ // Default to short data max (700).
+ buf_ (v.prec != 0 ? v.prec : 700)
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::binary;
+ b->buffer = buf_.data ();
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (buf_.capacity ());
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size (0);
+ value_traits<T, id_binary>::set_image (
+ buf_.data (), buf_.capacity (), size, dummy, v);
+ size_ind_ = static_cast<SQLLEN> (size);
+ }
+
+ private:
+ details::buffer buf_;
+ SQLLEN size_ind_;
+ };
+
+ // long_query_param_impl
+ //
+ // For long data we cannot assume that the by-value parameter will
+ // still be alive when we execute the query (and when the callback
+ // will be called to provide the data). So we have to make a private
+ // copy of the data and use that when the time comes.
+ //
+ class LIBODB_MSSQL_EXPORT long_query_param_impl
+ {
+ protected:
+ long_query_param_impl (): buf_ (0) {}
+
+ void
+ copy ();
+
+ protected:
+ details::buffer buf_;
+ std::size_t size_;
+ long_callback callback_;
+ };
+
+ // id_long_string.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_long_string>: query_param,
+ long_query_param_impl
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref), prec_ (r.prec)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0), prec_ (v.prec)
+ {
+ init (v.val);
+ copy ();
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ // If this is a by-value parameter then we already have the
+ // buffer containing all the data. So instead of using the
+ // callback mechanism, bind the buffer directly using the
+ // short data approach. SQLLEN (int on 32-bit platforms)
+ // can represent maximum size of 2^31 bytes which happens
+ // to be greater than the maximum size of VARCHAR(max) or
+ // TEXT (both 2^31-1 bytes).
+ //
+ if (reference ())
+ {
+ b->type = bind::long_string;
+ b->buffer = &this->long_query_param_impl::callback_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (prec_);
+ size_ind_ = SQL_DATA_AT_EXEC;
+ }
+ else
+ {
+ b->type = bind::string;
+ b->buffer = buf_.data ();
+ b->size_ind = &size_ind_;
+ // Extra byte for the null terminator (convention).
+ //
+ b->capacity = static_cast<SQLLEN> (prec_ != 0 ? prec_ + 1 : 0);
+ size_ind_ = static_cast<SQLLEN> (size_);
+ }
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_long_string>::set_image (
+ long_query_param_impl::callback_.callback.param,
+ long_query_param_impl::callback_.context.param,
+ dummy,
+ v);
+ }
+
+ private:
+ unsigned short prec_;
+ SQLLEN size_ind_;
+ };
+
+ // id_long_nstring.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_long_nstring>: query_param,
+ long_query_param_impl
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref), prec_ (r.prec)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0), prec_ (v.prec)
+ {
+ init (v.val);
+ copy ();
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ // If this is a by-value parameter then we already have the
+ // buffer containing all the data. So instead of using the
+ // callback mechanism, bind the buffer directly using the
+ // short data approach. SQLLEN (int on 32-bit platforms)
+ // can represent maximum size of 2^31 bytes which happens
+ // to be greater than the maximum size of NVARCHAR(max) or
+ // NTEXT (both 2^31-1 bytes).
+ //
+ if (reference ())
+ {
+ b->type = bind::long_nstring;
+ b->buffer = &this->long_query_param_impl::callback_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (prec_ * 2); // In bytes.
+ size_ind_ = SQL_DATA_AT_EXEC;
+ }
+ else
+ {
+ b->type = bind::nstring;
+ b->buffer = buf_.data ();
+ b->size_ind = &size_ind_;
+ // In bytes, extra character for the null terminator (convention).
+ //
+ b->capacity = static_cast<SQLLEN> (prec_ != 0 ? (prec_ + 1) * 2 : 0);
+ size_ind_ = static_cast<SQLLEN> (size_);
+ }
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_long_nstring>::set_image (
+ long_query_param_impl::callback_.callback.param,
+ long_query_param_impl::callback_.context.param,
+ dummy,
+ v);
+ }
+
+ private:
+ unsigned short prec_;
+ SQLLEN size_ind_;
+ };
+
+ // id_long_binary.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_long_binary>: query_param,
+ long_query_param_impl
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref), prec_ (r.prec)
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0), prec_ (v.prec)
+ {
+ init (v.val);
+ copy ();
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ // If this is a by-value parameter then we already have the
+ // buffer containing all the data. So instead of using the
+ // callback mechanism, bind the buffer directly using the
+ // short data approach. SQLLEN (int on 32-bit platforms)
+ // can represent maximum size of 2^31 bytes which happens
+ // to be greater than the maximum size of VARBINARY(max)
+ // or IMAGE (both 2^31-1 bytes).
+ //
+ if (reference ())
+ {
+ b->type = bind::long_binary;
+ b->buffer = &this->long_query_param_impl::callback_;
+ b->size_ind = &size_ind_;
+ size_ind_ = SQL_DATA_AT_EXEC;
+ }
+ else
+ {
+ b->type = bind::binary;
+ b->buffer = buf_.data ();
+ b->size_ind = &size_ind_;
+ size_ind_ = static_cast<SQLLEN> (size_);
+ }
+
+ b->capacity = static_cast<SQLLEN> (prec_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_long_binary>::set_image (
+ long_query_param_impl::callback_.callback.param,
+ long_query_param_impl::callback_.context.param,
+ dummy,
+ v);
+ }
+
+ private:
+ unsigned short prec_;
+ SQLLEN size_ind_;
+ };
+
+ // id_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 (bind_type* b)
+ {
+ b->type = bind::date;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_date>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ date image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_time.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_time>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7.
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default is 7.
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::time;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (scale_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_time>::set_image (image_, scale_, dummy, v);
+ size_ind_ = static_cast<SQLLEN> (sizeof (image_));
+ }
+
+ private:
+ unsigned short scale_;
+ time image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_datetime.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_datetime>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default to datetime2/7.
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default to datetime2/7.
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::datetime;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (scale_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_datetime>::set_image (image_, scale_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ unsigned short scale_;
+ datetime image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_datetimeoffset.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_datetimeoffset>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7.
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default is 7.
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ return false;
+ }
+
+ virtual void
+ bind (bind_type* b)
+ {
+ b->type = bind::datetimeoffset;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ b->capacity = static_cast<SQLLEN> (scale_);
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_datetimeoffset>::set_image (
+ image_, scale_, dummy, v);
+ size_ind_ = static_cast<SQLLEN> (sizeof (image_));
+ }
+
+ private:
+ unsigned short scale_;
+ datetimeoffset image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_uniqueidentifier.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_uniqueidentifier>: 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 (bind_type* b)
+ {
+ b->type = bind::uniqueidentifier;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_uniqueidentifier>::set_image (image_, dummy, v);
+ size_ind_ = 0;
+ }
+
+ private:
+ uniqueidentifier image_;
+ SQLLEN size_ind_;
+ };
+
+ // id_rowversion.
+ //
+ template <typename T>
+ struct query_param_impl<T, id_rowversion>: 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 (bind_type* b)
+ {
+ b->type = bind::rowversion;
+ b->buffer = &image_;
+ b->size_ind = &size_ind_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ value_traits<T, id_rowversion>::set_image (image_, dummy, v);
+ size_ind_ = 8;
+ }
+
+ private:
+ unsigned char image_[8];
+ SQLLEN size_ind_;
+ };
+ }
+}
+
+// odb::query specialization for SQL Server.
+//
+namespace odb
+{
+ template <typename T>
+ class query<T, mssql::query>: public query_selector<T>::type
+ {
+ public:
+ // We don't define any typedefs here since they may clash with
+ // column names defined by our base type.
+ //
+
+ query ()
+ {
+ }
+
+ explicit
+ query (bool v)
+ : query_selector<T>::type (v)
+ {
+ }
+
+ explicit
+ query (const char* q)
+ : query_selector<T>::type (q)
+ {
+ }
+
+ explicit
+ query (const std::string& q)
+ : query_selector<T>::type (q)
+ {
+ }
+
+ template <typename T2>
+ explicit
+ query (mssql::val_bind<T2> v)
+ : query_selector<T>::type (mssql::query (v))
+ {
+ }
+
+ template <typename T2>
+ explicit
+ query (mssql::ref_bind<T2> r)
+ : query_selector<T>::type (mssql::query (r))
+ {
+ }
+
+ query (const mssql::query& q)
+ : query_selector<T>::type (q)
+ {
+ }
+
+ template <mssql::database_type_id ID>
+ query (const mssql::query_column<bool, ID>& qc)
+ : query_selector<T>::type (qc)
+ {
+ }
+ };
+}
+
+#include <odb/mssql/query.ixx>
+#include <odb/mssql/query.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_QUERY_HXX
diff --git a/odb/mssql/query.ixx b/odb/mssql/query.ixx
new file mode 100644
index 0000000..5772fd0
--- /dev/null
+++ b/odb/mssql/query.ixx
@@ -0,0 +1,28 @@
+// file : odb/mssql/query.ixx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mssql
+ {
+ 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/mssql/query.txx b/odb/mssql/query.txx
new file mode 100644
index 0000000..41e891f
--- /dev/null
+++ b/odb/mssql/query.txx
@@ -0,0 +1,111 @@
+// file : odb/mssql/query.txx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mssql
+ {
+ // query
+ //
+
+ template <database_type_id ID>
+ query::
+ query (const query_column<bool, ID>& c)
+ : binding_ (0, 0)
+ {
+ // Cannot use IS TRUE here since database type can be a non-
+ // integral type.
+ //
+ append (c.table (), c.column ());
+ append ("=");
+ append<bool, ID> (val_bind<bool> (true, c.prec (), c.scale ()));
+ }
+
+ // query_column
+ //
+ template <typename T, database_type_id ID>
+ query query_column<T, ID>::
+ in (const T& v1, const T& v2) const
+ {
+ query q (table_, column_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2, prec_, scale_));
+ 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 (table_, column_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v3, prec_, scale_));
+ 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 (table_, column_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v3, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v4, prec_, scale_));
+ 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 (table_, column_);
+ q += "IN (";
+ q.append<T, ID> (val_bind<T> (v1, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v2, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v3, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v4, prec_, scale_));
+ q += ",";
+ q.append<T, ID> (val_bind<T> (v5, prec_, scale_));
+ 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 (table_, column_);
+ q += "IN (";
+
+ for (I i (begin); i != end; ++i)
+ {
+ if (i != begin)
+ q += ",";
+
+ q.append<T, ID> (val_bind<T> (*i, prec_, scale_));
+ }
+ q += ")";
+ return q;
+ }
+ }
+}
diff --git a/odb/mssql/result.hxx b/odb/mssql/result.hxx
new file mode 100644
index 0000000..4cc94c3
--- /dev/null
+++ b/odb/mssql/result.hxx
@@ -0,0 +1,26 @@
+// file : odb/mssql/result.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_RESULT_HXX
+#define ODB_MSSQL_RESULT_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/traits.hxx>
+#include <odb/result.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_RESULT_HXX
+
+// Include result specializations so that the user code only needs
+// to include this header.
+//
+
+#include <odb/mssql/object-result.hxx>
+#include <odb/mssql/view-result.hxx>
diff --git a/odb/mssql/statement.cxx b/odb/mssql/statement.cxx
index 73c7649..1313bf7 100644
--- a/odb/mssql/statement.cxx
+++ b/odb/mssql/statement.cxx
@@ -247,20 +247,26 @@ namespace odb
case bind::string:
{
buf = (SQLPOINTER) b->buffer;
- col_size = (SQLULEN) b->capacity - 1; // Sans the null-terminator.
+ col_size = b->capacity != 0
+ ? (SQLULEN) b->capacity - 1 // Sans the null-terminator.
+ : SQL_SS_LENGTH_UNLIMITED;
break;
}
case bind::binary:
{
buf = (SQLPOINTER) b->buffer;
- col_size = (SQLULEN) b->capacity;
+ col_size = b->capacity != 0
+ ? (SQLULEN) b->capacity
+ : SQL_SS_LENGTH_UNLIMITED;
break;
}
case bind::nstring:
{
buf = (SQLPOINTER) b->buffer;
- // In characters, not bytes, and sans the null-terminator.
- col_size = (SQLULEN) (b->capacity / 2 - 1);
+ col_size = b->capacity != 0
+ // In characters, not bytes, and sans the null-terminator.
+ ? (SQLULEN) (b->capacity / 2 - 1)
+ : SQL_SS_LENGTH_UNLIMITED;
break;
}
case bind::date:
@@ -552,7 +558,7 @@ namespace odb
}
void statement::
- stream_result (bind* b, size_t i, size_t n)
+ stream_result (bind* b, size_t i, size_t n, void* obase, void* nbase)
{
details::buffer& tmp_buf (conn_.long_buffer ());
@@ -584,7 +590,23 @@ namespace odb
}
}
- long_callback& cb (*static_cast<long_callback*> (b->buffer));
+ void* cbp;
+
+ if (obase == 0)
+ cbp = b->buffer;
+ else
+ {
+ // Re-base the pointer.
+ //
+ char* p (static_cast<char*> (b->buffer));
+ char* ob (static_cast<char*> (obase));
+ char* nb (static_cast<char*> (nbase));
+
+ assert (ob <= p);
+ cbp = nb + (p - ob);
+ }
+
+ long_callback& cb (*static_cast<long_callback*> (cbp));
// First determine if the value is NULL as well as try to
// get the total data size.
@@ -746,6 +768,11 @@ namespace odb
select_statement::result select_statement::
fetch ()
{
+ change_callback* cc (result_.change_callback);
+
+ if (cc != 0 && cc->callback != 0)
+ (cc->callback) (cc->context);
+
SQLRETURN r (SQLFetch (stmt_));
if (r == SQL_NO_DATA)
diff --git a/odb/mssql/statement.hxx b/odb/mssql/statement.hxx
index 15e64a0..3bea55f 100644
--- a/odb/mssql/statement.hxx
+++ b/odb/mssql/statement.hxx
@@ -60,8 +60,18 @@ namespace odb
SQLRETURN
execute ();
+ // The old_base and new_base arguments can be used to "re-base"
+ // the long_callback struct pointer (stored in bind::buffer).
+ // This is used by the query machinery to cause stream_result()
+ // to use the callback information from a copy of the image
+ // instead of the bound image.
+ //
void
- stream_result (bind*, std::size_t start, std::size_t count);
+ stream_result (bind*,
+ std::size_t start,
+ std::size_t count,
+ void* old_base = 0,
+ void* new_base = 0);
protected:
connection& conn_;
@@ -113,10 +123,14 @@ namespace odb
fetch ();
void
- stream_result ()
+ stream_result (void* old_base = 0, void* new_base = 0)
{
if (first_long_ != result_.count)
- statement::stream_result (result_.bind, first_long_, result_.count);
+ statement::stream_result (result_.bind,
+ first_long_,
+ result_.count,
+ old_base,
+ new_base);
}
void
diff --git a/odb/mssql/view-result.hxx b/odb/mssql/view-result.hxx
new file mode 100644
index 0000000..e4a523a
--- /dev/null
+++ b/odb/mssql/view-result.hxx
@@ -0,0 +1,76 @@
+// file : odb/mssql/view-result.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_VIEW_RESULT_HXX
+#define ODB_MSSQL_VIEW_RESULT_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx> // query, view_statements
+#include <odb/mssql/result.hxx>
+#include <odb/mssql/statement.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ template <typename T>
+ class view_result_impl: public odb::view_result_impl<T>
+ {
+ public:
+ typedef odb::view_result_impl<T> base_type;
+
+ typedef typename base_type::view_type view_type;
+ typedef typename base_type::view_traits view_traits;
+
+ typedef typename base_type::pointer_type pointer_type;
+ typedef typename base_type::pointer_traits pointer_traits;
+
+ virtual
+ ~view_result_impl ();
+
+ view_result_impl (const query&,
+ details::shared_ptr<select_statement>,
+ view_statements<view_type>&);
+
+ virtual void
+ load (view_type&);
+
+ virtual void
+ next ();
+
+ virtual void
+ cache ();
+
+ virtual std::size_t
+ size ();
+
+ using base_type::current;
+
+ private:
+ typedef mssql::change_callback change_callback_type;
+
+ static void
+ change_callback (void* context);
+
+ private:
+ details::shared_ptr<select_statement> statement_;
+ view_statements<view_type>& statements_;
+ bool use_copy_;
+ typename view_traits::image_type* image_copy_;
+ };
+ }
+}
+
+#include <odb/mssql/view-result.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_VIEW_RESULT_HXX
diff --git a/odb/mssql/view-result.txx b/odb/mssql/view-result.txx
new file mode 100644
index 0000000..4b5053d
--- /dev/null
+++ b/odb/mssql/view-result.txx
@@ -0,0 +1,131 @@
+// file : odb/mssql/view-result.txx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <odb/callback.hxx>
+#include <odb/exceptions.hxx>
+
+#include <odb/mssql/view-statements.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ template <typename T>
+ view_result_impl<T>::
+ ~view_result_impl ()
+ {
+ change_callback_type& cc (statements_.image ().change_callback_);
+
+ if (cc.context == this)
+ {
+ cc.callback = 0;
+ cc.context = 0;
+ }
+
+ delete image_copy_;
+ }
+
+ template <typename T>
+ view_result_impl<T>::
+ view_result_impl (const query&,
+ details::shared_ptr<select_statement> statement,
+ view_statements<view_type>& statements)
+ : base_type (statements.connection ().database ()),
+ statement_ (statement),
+ statements_ (statements),
+ use_copy_ (false),
+ image_copy_ (0)
+ {
+ }
+
+ template <typename T>
+ void view_result_impl<T>::
+ load (view_type& view)
+ {
+ odb::database& db (this->database ());
+
+ view_traits::callback (db, view, callback_event::pre_load);
+
+ view_traits::init (view,
+ use_copy_ ? *image_copy_ : statements_.image (),
+ db);
+
+ // If we are using a copy, make sure the callback information for
+ // long data also comes from the copy.
+ //
+ statement_->stream_result (
+ use_copy_ ? &statements_.image () : 0,
+ use_copy_ ? image_copy_ : 0);
+
+ view_traits::callback (db, view, callback_event::post_load);
+ }
+
+ template <typename T>
+ void view_result_impl<T>::
+ next ()
+ {
+ this->current (pointer_type ());
+
+ typename view_traits::image_type& im (statements_.image ());
+ change_callback_type& cc (im.change_callback_);
+
+ if (cc.context == this)
+ {
+ cc.callback = 0;
+ cc.context = 0;
+ }
+
+ use_copy_ = false;
+
+ if (im.version != statements_.image_version ())
+ {
+ binding& b (statements_.image_binding ());
+ view_traits::bind (b.bind, im);
+ statements_.image_version (im.version);
+ b.version++;
+ }
+
+ if (statement_->fetch () == select_statement::no_data)
+ this->end_ = true;
+ else
+ {
+ cc.callback = &change_callback;
+ cc.context = this;
+ }
+ }
+
+ template <typename T>
+ void view_result_impl<T>::
+ cache ()
+ {
+ }
+
+ template <typename T>
+ std::size_t view_result_impl<T>::
+ size ()
+ {
+ throw result_not_cached ();
+ }
+
+ template <typename T>
+ void view_result_impl<T>::
+ change_callback (void* c)
+ {
+ view_result_impl<T>* r (static_cast<view_result_impl<T>*> (c));
+
+ typename view_traits::image_type& im (r->statements_.image ());
+
+ if (r->image_copy_ == 0)
+ r->image_copy_ = new typename view_traits::image_type (im);
+ else
+ *r->image_copy_ = im;
+
+ im.change_callback_.callback = 0;
+ im.change_callback_.context = 0;
+
+ r->use_copy_ = true;
+ }
+ }
+}
diff --git a/odb/mssql/view-statements.txx b/odb/mssql/view-statements.txx
index e4e47d8..1b6de05 100644
--- a/odb/mssql/view-statements.txx
+++ b/odb/mssql/view-statements.txx
@@ -24,8 +24,7 @@ namespace odb
image_.version = 0;
image_version_ = 0;
- //@@ TODO
- // image_binding_.change_callback = image_.change_callback ();
+ image_binding_.change_callback = image_.change_callback ();
std::memset (image_bind_, 0, sizeof (image_bind_));
}