aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-10-12 17:24:44 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-10-19 11:38:24 +0200
commit5b0430fdf4617b396e462872d438a663b174a3a8 (patch)
treee89e0cc5b1fdff4e3f49c9c7b7607d2b90108c31
parent5c705a90d348a2a9428d5121a24eb47d0d73eb39 (diff)
Completion of prepared query support
-rw-r--r--odb/connection.cxx79
-rw-r--r--odb/connection.hxx76
-rw-r--r--odb/connection.ixx58
-rw-r--r--odb/connection.txx43
-rw-r--r--odb/database.hxx68
-rw-r--r--odb/database.ixx91
-rw-r--r--odb/database.txx1
-rw-r--r--odb/details/c-string.hxx31
-rw-r--r--odb/exceptions.cxx48
-rw-r--r--odb/exceptions.hxx40
-rw-r--r--odb/prepared-query.hxx32
-rw-r--r--odb/statement.cxx9
-rw-r--r--odb/statement.hxx22
13 files changed, 574 insertions, 24 deletions
diff --git a/odb/connection.cxx b/odb/connection.cxx
index d14e510..f479131 100644
--- a/odb/connection.cxx
+++ b/odb/connection.cxx
@@ -2,12 +2,91 @@
// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <odb/database.hxx>
#include <odb/connection.hxx>
+#include <odb/exceptions.hxx> // prepared_*
+
+using namespace std;
namespace odb
{
connection::
~connection ()
{
+ for (prepared_map_type::iterator i (prepared_map_.begin ()),
+ e (prepared_map_.end ()); i != e; ++i)
+ {
+ if (i->second.params != 0)
+ i->second.params_deleter (i->second.params);
+ }
+ }
+
+ void connection::
+ cache_query_ (details::shared_ptr<prepared_query_impl> pq,
+ const type_info& ti,
+ void* params,
+ const type_info* params_info,
+ void (*params_deleter) (void*))
+ {
+ pair<prepared_map_type::iterator, bool> r (
+ prepared_map_.insert (
+ prepared_map_type::value_type (pq->name, prepared_entry_type ())));
+
+ if (!r.second)
+ throw prepared_already_cached (pq->name);
+
+ prepared_entry_type& e (r.first->second);
+
+ e.prep_query = pq;
+ e.type_info = &ti;
+
+ // Mark the statement as cached.
+ //
+ pq->stmt->cached (true);
+
+ e.params = params;
+ e.params_info = params_info;
+ e.params_deleter = params_deleter;
+ }
+
+ details::shared_ptr<prepared_query_impl> connection::
+ lookup_query_ (const char* name,
+ const type_info& ti,
+ void** params,
+ const type_info* params_info) const
+ {
+ prepared_map_type::const_iterator i (prepared_map_.find (name));
+
+ if (i == prepared_map_.end ())
+ {
+ // See if there is a factory.
+ //
+ database_type::query_factory_type f (
+ database_.lookup_query_factory (name));
+
+ if (f)
+ {
+ f (name, const_cast<connection&> (*this));
+ i = prepared_map_.find (name);
+ }
+ }
+
+ if (i == prepared_map_.end ())
+ return details::shared_ptr<prepared_query_impl> ();
+
+ // Make sure the types match.
+ //
+ if (*i->second.type_info != ti)
+ throw prepared_type_mismatch (name);
+
+ if (params != 0)
+ {
+ if (*i->second.params_info != *params_info)
+ throw prepared_type_mismatch (name);
+
+ *params = i->second.params;
+ }
+
+ return i->second.prep_query;
}
}
diff --git a/odb/connection.hxx b/odb/connection.hxx
index f274b39..b4a9d5b 100644
--- a/odb/connection.hxx
+++ b/odb/connection.hxx
@@ -7,14 +7,20 @@
#include <odb/pre.hxx>
+#include <map>
#include <string>
-#include <cstddef> // std::size_t
+#include <memory> // std::auto_ptr, std::unique_ptr
+#include <cstddef> // std::size_t
+#include <typeinfo>
#include <odb/forward.hxx>
+#include <odb/traits.hxx>
#include <odb/query.hxx>
#include <odb/prepared-query.hxx>
+#include <odb/details/config.hxx> // ODB_CXX11
#include <odb/details/export.hxx>
+#include <odb/details/c-string.hxx>
#include <odb/details/shared-ptr.hxx>
namespace odb
@@ -57,15 +63,37 @@ namespace odb
public:
template <typename T>
prepared_query<T>
- prepare_query (const char* name, const char* q);
+ prepare_query (const char* name, const char*);
template <typename T>
prepared_query<T>
- prepare_query (const char* name, const std::string& q);
+ prepare_query (const char* name, const std::string&);
template <typename T>
prepared_query<T>
- prepare_query (const char* name, const query<T>& q);
+ prepare_query (const char* name, const query<T>&);
+
+ template <typename T>
+ void
+ cache_query (const prepared_query<T>&);
+
+ template <typename T, typename P>
+ void
+ cache_query (const prepared_query<T>&, std::auto_ptr<P> params);
+
+#ifdef ODB_CXX11
+ template <typename T, typename P>
+ void
+ cache_query (const prepared_query<T>&, std::unique_ptr<P> params);
+#endif
+
+ template <typename T>
+ prepared_query<T>
+ lookup_query (const char* name) const;
+
+ template <typename T, typename P>
+ prepared_query<T>
+ lookup_query (const char* name, P*& params) const;
// SQL statement tracing.
//
@@ -98,10 +126,50 @@ namespace odb
protected:
connection (database_type&);
+ template <typename T,
+ database_id DB,
+ class_kind kind = class_traits<T>::kind>
+ struct query_;
+
+ virtual void
+ cache_query_ (details::shared_ptr<prepared_query_impl> pq,
+ const std::type_info& ti,
+ void* params,
+ const std::type_info* params_info,
+ void (*params_deleter) (void*));
+
+ details::shared_ptr<prepared_query_impl>
+ lookup_query_ (const char* name,
+ const std::type_info& ti,
+ void** params, // out
+ const std::type_info* params_info) const;
+
+ template <typename P>
+ static void
+ params_deleter (void*);
+
private:
connection (const connection&);
connection& operator= (const connection&);
+ // Prepared query cache.
+ //
+ protected:
+ struct prepared_entry_type
+ {
+ details::shared_ptr<prepared_query_impl> prep_query;
+ const std::type_info* type_info;
+ void* params;
+ const std::type_info* params_info;
+ void (*params_deleter) (void*);
+ };
+
+ typedef
+ std::map<const char*, prepared_entry_type, details::c_string_comparator>
+ prepared_map_type;
+
+ prepared_map_type prepared_map_;
+
protected:
database_type& database_;
tracer_type* tracer_;
diff --git a/odb/connection.ixx b/odb/connection.ixx
index fd1a624..8842d8e 100644
--- a/odb/connection.ixx
+++ b/odb/connection.ixx
@@ -3,6 +3,7 @@
// license : GNU GPL v2; see accompanying LICENSE file
#include <cstring> // std::string
+#include <cassert>
namespace odb
{
@@ -44,6 +45,63 @@ namespace odb
return prepare_query<T> (n, query<T> (q));
}
+ template <typename T>
+ inline prepared_query<T> connection::
+ prepare_query (const char* n, const query<T>& q)
+ {
+ return query_<T, id_default>::call (*this, n, q);
+ }
+
+ template <typename T>
+ inline void connection::
+ cache_query (const prepared_query<T>& pq)
+ {
+ assert (pq);
+ cache_query_ (pq.impl_, typeid (T), 0, 0, 0);
+ }
+
+ template <typename T, typename P>
+ inline void connection::
+ cache_query (const prepared_query<T>& pq, std::auto_ptr<P> params)
+ {
+ assert (pq);
+ assert (params.get () != 0);
+ cache_query_ (
+ pq.impl_, typeid (T), params.get (), &typeid (P), &params_deleter<P>);
+ params.release ();
+ }
+
+#ifdef ODB_CXX11
+ template <typename T, typename P>
+ inline void connection::
+ cache_query (const prepared_query<T>& pq, std::unique_ptr<P> params)
+ {
+ assert (pq);
+ assert (params);
+ cache_query_ (
+ pq.impl_, typeid (T), params.get (), &typeid (P), &params_deleter<P>);
+ params.release ();
+ }
+#endif
+
+ template <typename T>
+ inline prepared_query<T> connection::
+ lookup_query (const char* name) const
+ {
+ return prepared_query<T> (lookup_query_ (name, typeid (T), 0, 0));
+ }
+
+ template <typename T, typename P>
+ inline prepared_query<T> connection::
+ lookup_query (const char* name, P*& params) const
+ {
+ return prepared_query<T> (
+ lookup_query_ (name,
+ typeid (T),
+ reinterpret_cast<void**> (&params),
+ &typeid (P)));
+ }
+
inline void connection::
tracer (tracer_type& t)
{
diff --git a/odb/connection.txx b/odb/connection.txx
index c5662d9..7861851 100644
--- a/odb/connection.txx
+++ b/odb/connection.txx
@@ -4,13 +4,42 @@
namespace odb
{
- template <typename T>
- prepared_query<T> connection::
- prepare_query (const char* n, const query<T>& q)
+ template <typename T, database_id DB>
+ struct connection::query_<T, DB, class_object>
{
- //@@ Views. Inline?
- //
- return prepared_query<T> (
- object_traits_impl<T, id_default>::prepare_query (*this, n, q));
+ template <typename Q>
+ static prepared_query<T>
+ call (connection& c, const char* n, const Q& q)
+ {
+ // C++ compiler complaining there is no prepare_query()? Perhaps
+ // you forgot to specify --generate-prepared when compiling your
+ // persistent classes.
+ //
+ return prepared_query<T> (
+ object_traits_impl<T, DB>::prepare_query (c, n, q));
+ }
+ };
+
+ template <typename T, database_id DB>
+ struct connection::query_<T, DB, class_view>
+ {
+ template <typename Q>
+ static prepared_query<T>
+ call (connection& c, const char* n, const Q& q)
+ {
+ // C++ compiler complaining there is no prepare_query()? Perhaps
+ // you forgot to specify --generate-prepared when compiling your
+ // views.
+ //
+ return prepared_query<T> (
+ view_traits_impl<T, DB>::prepare_query (c, n, q));
+ }
+ };
+
+ template <typename P>
+ void connection::
+ params_deleter (void* p)
+ {
+ delete static_cast<P*> (p);
}
}
diff --git a/odb/database.hxx b/odb/database.hxx
index 99205e7..506245f 100644
--- a/odb/database.hxx
+++ b/odb/database.hxx
@@ -7,17 +7,27 @@
#include <odb/pre.hxx>
+#include <odb/details/config.hxx> // ODB_CXX11
+
+#include <map>
#include <string>
+#include <memory> // std::auto_ptr, std::unique_ptr
#include <cstddef> // std::size_t
+#ifdef ODB_CXX11
+# include <functional> // std::function
+#endif
+
#include <odb/traits.hxx>
#include <odb/forward.hxx>
#include <odb/query.hxx>
+#include <odb/prepared-query.hxx>
#include <odb/result.hxx>
#include <odb/connection.hxx>
#include <odb/exceptions.hxx>
#include <odb/details/export.hxx>
+#include <odb/details/c-string.hxx>
namespace odb
{
@@ -214,6 +224,59 @@ namespace odb
result<T>
query (const odb::query<T>&, bool cache = true);
+ // Query preparation.
+ //
+ template <typename T>
+ prepared_query<T>
+ prepare_query (const char* name, const char*);
+
+ template <typename T>
+ prepared_query<T>
+ prepare_query (const char* name, const std::string&);
+
+ template <typename T>
+ prepared_query<T>
+ prepare_query (const char* name, const odb::query<T>&);
+
+ template <typename T>
+ void
+ cache_query (const prepared_query<T>&);
+
+ template <typename T, typename P>
+ void
+ cache_query (const prepared_query<T>&, std::auto_ptr<P> params);
+
+#ifdef ODB_CXX11
+ template <typename T, typename P>
+ void
+ cache_query (const prepared_query<T>&, std::unique_ptr<P> params);
+#endif
+
+ template <typename T>
+ prepared_query<T>
+ lookup_query (const char* name) const;
+
+ template <typename T, typename P>
+ prepared_query<T>
+ lookup_query (const char* name, P*& params) const;
+
+ // Prepared query factory.
+ //
+ public:
+#ifdef ODB_CXX11
+ typedef
+ std::function<void (const char*, connection&)>
+ query_factory_type;
+#else
+ typedef void (*query_factory_type) (const char*, connection&);
+#endif
+
+ void
+ query_factory (const char* name, query_factory_type);
+
+ query_factory_type
+ lookup_query_factory (const char* name) const;
+
// Native database statement execution.
//
public:
@@ -326,8 +389,13 @@ namespace odb
struct query_;
protected:
+ typedef
+ std::map<const char*, query_factory_type, details::c_string_comparator>
+ query_factory_map;
+
database_id id_;
tracer_type* tracer_;
+ query_factory_map query_factory_map_;
};
}
diff --git a/odb/database.ixx b/odb/database.ixx
index aeffdec..5b6f876 100644
--- a/odb/database.ixx
+++ b/odb/database.ixx
@@ -3,6 +3,9 @@
// license : GNU GPL v2; see accompanying LICENSE file
#include <cstring> // std::strlen()
+#include <utility> // std::move
+
+#include <odb/transaction.hxx>
namespace odb
{
@@ -25,6 +28,30 @@ namespace odb
}
inline void database::
+ query_factory (const char* name, query_factory_type f)
+ {
+ if (f)
+#ifdef ODB_CXX11
+ query_factory_map_[name] = std::move (f);
+#else
+ query_factory_map_[name] = f;
+#endif
+ else
+ query_factory_map_.erase (name);
+ }
+
+ inline database::query_factory_type database::
+ lookup_query_factory (const char* name) const
+ {
+ query_factory_map::const_iterator i (query_factory_map_.find (name));
+
+ if (i == query_factory_map_.end ())
+ i = query_factory_map_.find (""); // Wildcard factory.
+
+ return i != query_factory_map_.end () ? i->second : 0;
+ }
+
+ inline void database::
tracer (tracer_type& t)
{
tracer_ = &t;
@@ -410,6 +437,70 @@ namespace odb
return query<T> (odb::query<T> (q), cache);
}
+ template <typename T>
+ inline prepared_query<T> database::
+ prepare_query (const char* n, const char* q)
+ {
+ return prepare_query<T> (n, odb::query<T> (q));
+ }
+
+ template <typename T>
+ inline prepared_query<T> database::
+ prepare_query (const char* n, const std::string& q)
+ {
+ return prepare_query<T> (n, odb::query<T> (q));
+ }
+
+ template <typename T>
+ inline prepared_query<T> database::
+ prepare_query (const char* n, const odb::query<T>& q)
+ {
+ connection_type& c (transaction::current ().connection ());
+ return c.prepare_query (n, q);
+ }
+
+ template <typename T>
+ inline void database::
+ cache_query (const prepared_query<T>& pq)
+ {
+ connection_type& c (transaction::current ().connection ());
+ c.cache_query (pq);
+ }
+
+ template <typename T, typename P>
+ inline void database::
+ cache_query (const prepared_query<T>& pq, std::auto_ptr<P> params)
+ {
+ connection_type& c (transaction::current ().connection ());
+ c.cache_query (pq, params);
+ }
+
+#ifdef ODB_CXX11
+ template <typename T, typename P>
+ inline void database::
+ cache_query (const prepared_query<T>& pq, std::unique_ptr<P> params)
+ {
+ connection_type& c (transaction::current ().connection ());
+ c.cache_query (pq, std::move (params));
+ }
+#endif
+
+ template <typename T>
+ inline prepared_query<T> database::
+ lookup_query (const char* name) const
+ {
+ connection_type& c (transaction::current ().connection ());
+ return c.lookup_query<T> (name);
+ }
+
+ template <typename T, typename P>
+ inline prepared_query<T> database::
+ lookup_query (const char* name, P*& params) const
+ {
+ connection_type& c (transaction::current ().connection ());
+ return c.lookup_query<T, P> (name, params);
+ }
+
// Implementations (i.e., the *_() functions).
//
template <typename T, database_id DB>
diff --git a/odb/database.txx b/odb/database.txx
index 23ea712..5556982 100644
--- a/odb/database.txx
+++ b/odb/database.txx
@@ -3,7 +3,6 @@
// license : GNU GPL v2; see accompanying LICENSE file
#include <odb/exceptions.hxx>
-#include <odb/transaction.hxx>
#include <odb/no-op-cache-traits.hxx>
#include <odb/pointer-traits.hxx>
diff --git a/odb/details/c-string.hxx b/odb/details/c-string.hxx
new file mode 100644
index 0000000..ce029f8
--- /dev/null
+++ b/odb/details/c-string.hxx
@@ -0,0 +1,31 @@
+// file : odb/details/c-string.hxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_C_STRING_HXX
+#define ODB_DETAILS_C_STRING_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstring>
+
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct LIBODB_EXPORT c_string_comparator
+ {
+ bool
+ operator() (const char* x, const char* y) const
+ {
+ return std::strcmp (x, y) < 0;
+ }
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_C_STRING_HXX
diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx
index d56711c..c49d516 100644
--- a/odb/exceptions.cxx
+++ b/odb/exceptions.cxx
@@ -2,8 +2,6 @@
// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
-#include <sstream>
-
#include <odb/exceptions.hxx>
using namespace std;
@@ -106,13 +104,53 @@ namespace odb
return "no type information";
}
+ prepared_already_cached::
+ prepared_already_cached (const char* name)
+ : name_ (name)
+ {
+ what_ = "prepared query '";
+ what_ += name;
+ what_ += "' is already cached";
+ }
+
+ prepared_already_cached::
+ ~prepared_already_cached () throw ()
+ {
+ }
+
+ const char* prepared_already_cached::
+ what () const throw ()
+ {
+ return what_.c_str ();
+ }
+
+ prepared_type_mismatch::
+ prepared_type_mismatch (const char* name)
+ : name_ (name)
+ {
+ what_ = "type mismatch while looking up prepared query '";
+ what_ += name;
+ what_ += "'";
+ }
+
+ prepared_type_mismatch::
+ ~prepared_type_mismatch () throw ()
+ {
+ }
+
+ const char* prepared_type_mismatch::
+ what () const throw ()
+ {
+ return what_.c_str ();
+ }
+
unknown_schema::
unknown_schema (const std::string& name)
: name_ (name)
{
- ostringstream ostr;
- ostr << "unknown database schema '" << name << "'";
- what_ = ostr.str ();
+ what_ = "unknown database schema '";
+ what_ += name;
+ what_ += "'";
}
unknown_schema::
diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx
index 9e37967..90729fc 100644
--- a/odb/exceptions.hxx
+++ b/odb/exceptions.hxx
@@ -127,6 +127,46 @@ namespace odb
what () const throw ();
};
+ // Prepared query support exceptions.
+ //
+ struct LIBODB_EXPORT prepared_already_cached: exception
+ {
+ prepared_already_cached (const char* name);
+ ~prepared_already_cached () throw ();
+
+ const char*
+ name () const
+ {
+ return name_;
+ }
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ const char* name_;
+ std::string what_;
+ };
+
+ struct LIBODB_EXPORT prepared_type_mismatch: exception
+ {
+ prepared_type_mismatch (const char* name);
+ ~prepared_type_mismatch () throw ();
+
+ const char*
+ name () const
+ {
+ return name_;
+ }
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ const char* name_;
+ std::string what_;
+ };
+
// Schema catalog exceptions.
//
struct LIBODB_EXPORT unknown_schema: exception
diff --git a/odb/prepared-query.hxx b/odb/prepared-query.hxx
index 60ae48d..e4c9c2b 100644
--- a/odb/prepared-query.hxx
+++ b/odb/prepared-query.hxx
@@ -10,6 +10,7 @@
#include <odb/forward.hxx>
#include <odb/traits.hxx>
#include <odb/result.hxx>
+#include <odb/statement.hxx>
#include <odb/details/export.hxx>
#include <odb/details/shared-ptr.hxx>
@@ -22,12 +23,19 @@ namespace odb
~prepared_query_impl ();
const char* name;
+ details::shared_ptr<statement> stmt;
details::shared_ptr<result_impl> (*execute) (prepared_query_impl&);
};
template <typename T>
struct prepared_query
{
+ prepared_query () {}
+
+ explicit
+ prepared_query (details::shared_ptr<prepared_query_impl> impl)
+ : impl_ (impl) {}
+
result<T>
execute (bool cache = true)
{
@@ -46,11 +54,29 @@ namespace odb
return r;
}
- explicit
- prepared_query (details::shared_ptr<prepared_query_impl> impl)
- : impl_ (impl) {}
+ const char*
+ name () const
+ {
+ return impl_->name;
+ }
+
+ typedef odb::statement statement_type;
+
+ statement_type&
+ statement () const
+ {
+ return *impl_->stmt;
+ }
+
+ typedef details::shared_ptr<prepared_query_impl>
+ prepared_query::*unspecified_bool_type;
+ operator unspecified_bool_type () const
+ {
+ return impl_ ? &prepared_query::impl_ : 0;
+ }
private:
+ friend class connection;
details::shared_ptr<prepared_query_impl> impl_;
};
diff --git a/odb/statement.cxx b/odb/statement.cxx
index 1d96078..eb99227 100644
--- a/odb/statement.cxx
+++ b/odb/statement.cxx
@@ -2,6 +2,8 @@
// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <cassert>
+
#include <odb/statement.hxx>
namespace odb
@@ -10,4 +12,11 @@ namespace odb
~statement ()
{
}
+
+ void statement::
+ cached (bool cached)
+ {
+ assert (cached);
+ cached_ = true;
+ }
}
diff --git a/odb/statement.hxx b/odb/statement.hxx
index b7295ad..3cd5598 100644
--- a/odb/statement.hxx
+++ b/odb/statement.hxx
@@ -16,6 +16,10 @@ namespace odb
{
class LIBODB_EXPORT statement: public details::shared_base
{
+ private:
+ statement (const statement&);
+ statement& operator= (const statement&);
+
public:
typedef odb::connection connection_type;
@@ -28,12 +32,22 @@ namespace odb
virtual
~statement () = 0;
+ // Statement caching status.
+ //
+ public:
+ bool
+ cached () const
+ {
+ return cached_;
+ }
+
+ virtual void
+ cached (bool);
+
protected:
- statement () {}
+ statement (): cached_ (false) {}
- private:
- statement (const statement&);
- statement& operator= (const statement&);
+ bool cached_;
};
}