aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-10-12 17:24:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-10-19 11:40:38 +0200
commitdefe5aec4edc065546d44ad17b48a2dd5290144d (patch)
tree68dc4a3284689c1e81e4fab0be264ed43b316de9
parentb134d7b4f2c105870a98a67ec568c16c9f632aba (diff)
Completion of prepared query support
-rw-r--r--odb/header.cxx2
-rw-r--r--odb/options.cli4
-rw-r--r--odb/relational/header.cxx240
-rw-r--r--odb/relational/header.hxx218
-rw-r--r--odb/relational/pgsql/source.cxx38
-rw-r--r--odb/relational/source.cxx156
-rw-r--r--odb/relational/source.hxx20
7 files changed, 405 insertions, 273 deletions
diff --git a/odb/header.cxx b/odb/header.cxx
index 32dc898..8e39b75 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -60,7 +60,7 @@ namespace header
if (ctx.options.generate_query ())
{
- if (!ctx.options.omit_prepared ())
+ if (ctx.options.generate_prepared ())
os << "#include <odb/prepared-query.hxx>" << endl;
os << "#include <odb/result.hxx>" << endl;
diff --git a/odb/options.cli b/odb/options.cli
index ce990b0..cad5db7 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -58,9 +58,9 @@ class options
and can only load objects via their ids."
};
- bool --omit-prepared
+ bool --generate-prepared
{
- "Omit prepared query execution support code."
+ "Generate prepared query execution support code."
};
bool --omit-unprepared
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index a78697f..c6fc9a5 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -685,13 +685,13 @@ traverse_object (type& c)
os << "static result<object_type>" << endl
<< "query (database&, const query_base_type&);"
<< endl;
-
- os << "static unsigned long long" << endl
- << "erase_query (database&, const query_base_type&);"
- << endl;
}
- if (!options.omit_prepared ())
+ os << "static unsigned long long" << endl
+ << "erase_query (database&, const query_base_type&);"
+ << endl;
+
+ if (options.generate_prepared ())
{
os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
<< "prepare_query (connection&, const char*, const query_base_type&);"
@@ -823,6 +823,236 @@ traverse_object (type& c)
<< "};";
}
+void relational::header::class1::
+traverse_view (type& c)
+{
+ string const& type (class_fq_name (c));
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl;
+
+ // class_traits
+ //
+ os << "template <>" << endl
+ << "struct class_traits< " << type << " >"
+ << "{"
+ << "static const class_kind kind = class_view;"
+ << "};";
+
+ // view_traits
+ //
+ os << "template <>" << endl
+ << "class access::view_traits< " << type << " >"
+ << "{"
+ << "public:" << endl;
+
+ // view_type & pointer_type
+ //
+ os << "typedef " << type << " view_type;"
+ << "typedef " << c.get<string> ("object-pointer") << " pointer_type;";
+
+ os << "};";
+
+ // view_traits_impl
+ //
+ os << "template <>" << endl
+ << "class access::view_traits_impl< " << type << ", id_" <<
+ db << " >:" << endl
+ << " public access::view_traits< " << type << " >"
+ << "{"
+ << "public:" << endl;
+
+ view_public_extra_pre (c);
+
+ // image_type
+ //
+ image_type_->traverse (c);
+
+ os << "typedef " << db << "::view_statements<view_type> statements_type;"
+ << endl;
+
+ //
+ // Query.
+ //
+
+ // query_base_type and query_columns (definition generated by class2).
+ //
+ os << "typedef " << db << "::query_base query_base_type;"
+ << "struct query_columns";
+
+ if (c.get<size_t> ("object-count") == 0)
+ os << "{"
+ << "};";
+ else
+ os << ";"
+ << endl;
+
+ //
+ // Functions.
+ //
+
+ // grow ()
+ //
+ if (generate_grow)
+ {
+ os << "static bool" << endl
+ << "grow (image_type&, " << truncated_vector << ");"
+ << endl;
+ }
+
+ // bind (image_type)
+ //
+ os << "static void" << endl
+ << "bind (" << bind_vector << ", image_type&);"
+ << endl;
+
+ // init (view, image)
+ //
+ os << "static void" << endl
+ << "init (view_type&, const image_type&, database*);"
+ << endl;
+
+ // column_count
+ //
+ os << "static const std::size_t column_count = " <<
+ column_count (c).total << "UL;"
+ << endl;
+
+ // Statements.
+ //
+ view_query& vq (c.get<view_query> ("query"));
+
+ if (vq.kind != view_query::runtime)
+ {
+ os << "static query_base_type" << endl
+ << "query_statement (const query_base_type&);"
+ << endl;
+ }
+
+ //
+ // Functions.
+ //
+
+ // callback ()
+ //
+ os << "static void" << endl
+ << "callback (database&, view_type&, callback_event);"
+ << endl;
+
+ // query ()
+ //
+ if (!options.omit_unprepared ())
+ os << "static result<view_type>" << endl
+ << "query (database&, const query_base_type&);"
+ << endl;
+
+ if (options.generate_prepared ())
+ {
+ os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
+ << "prepare_query (connection&, const char*, const query_base_type&);"
+ << endl;
+
+ os << "static odb::details::shared_ptr<result_impl>" << endl
+ << "execute_query (prepared_query_impl&);"
+ << endl;
+ }
+
+ view_public_extra_post (c);
+
+ os << "};";
+
+ // view_traits_impl< , id_default>
+ //
+ os << "template <>" << endl
+ << "class access::view_traits_impl< " << type << ", id_default >:" << endl
+ << " public access::view_traits_impl< " << type << ", " <<
+ "id_" << db << " >"
+ << "{"
+ << "};";
+}
+
+void relational::header::class1::
+traverse_composite (type& c)
+{
+ string const& type (class_fq_name (c));
+
+ os << "// " << class_name (c) << endl
+ << "//" << endl;
+
+ os << "template <>" << endl
+ << "struct class_traits< " << type << " >"
+ << "{"
+ << "static const class_kind kind = class_composite;"
+ << "};";
+
+ os << "template <>" << endl
+ << "class access::composite_value_traits< " << type << ", " <<
+ "id_" << db << " >"
+ << "{"
+ << "public:" << endl;
+
+ // value_type
+ //
+ os << "typedef " << type << " value_type;"
+ << endl;
+
+ // image_type
+ //
+ image_type_->traverse (c);
+
+ // Containers.
+ //
+ {
+ instance<container_traits> t (c);
+ t->traverse (c);
+ }
+
+ // grow ()
+ //
+ if (generate_grow)
+ {
+ os << "static bool" << endl
+ << "grow (image_type&, " << truncated_vector << ");"
+ << endl;
+ }
+
+ // bind (image_type)
+ //
+ os << "static void" << endl
+ << "bind (" << bind_vector << ", image_type&, " <<
+ db << "::statement_kind);"
+ << endl;
+
+ // init (image, value)
+ //
+ os << "static " << (generate_grow ? "bool" : "void") << endl
+ << "init (image_type&, const value_type&, " << db << "::statement_kind);"
+ << endl;
+
+ // init (value, image)
+ //
+ os << "static void" << endl
+ << "init (value_type&, const image_type&, database*);"
+ << endl;
+
+ if (!has_a (c, test_container))
+ {
+ // get_null (image)
+ //
+ os << "static bool" << endl
+ << "get_null (const image_type&);"
+ << endl;
+
+ // set_null (image)
+ //
+ os << "static void" << endl
+ << "set_null (image_type&, " << db << "::statement_kind);"
+ << endl;
+ }
+
+ os << "};";
+}
+
void relational::header::
generate ()
{
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index fe08a49..75cee16 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -997,7 +997,7 @@ namespace relational
}
virtual void
- traverse_object (type& c);
+ traverse_object (type&);
virtual void
view_public_extra_pre (type&)
@@ -1010,222 +1010,10 @@ namespace relational
}
virtual void
- traverse_view (type& c)
- {
- string const& type (class_fq_name (c));
-
- os << "// " << class_name (c) << endl
- << "//" << endl;
-
- // class_traits
- //
- os << "template <>" << endl
- << "struct class_traits< " << type << " >"
- << "{"
- << "static const class_kind kind = class_view;"
- << "};";
-
- // view_traits
- //
- os << "template <>" << endl
- << "class access::view_traits< " << type << " >"
- << "{"
- << "public:" << endl;
-
- // view_type & pointer_type
- //
- os << "typedef " << type << " view_type;"
- << "typedef " << c.get<string> ("object-pointer") << " pointer_type;";
-
- os << "};";
-
- // view_traits_impl
- //
- os << "template <>" << endl
- << "class access::view_traits_impl< " << type << ", id_" <<
- db << " >:" << endl
- << " public access::view_traits< " << type << " >"
- << "{"
- << "public:" << endl;
-
- view_public_extra_pre (c);
-
- // image_type
- //
- image_type_->traverse (c);
-
- //
- // Query.
- //
-
- // query_base_type and query_columns (definition generated by class2).
- //
- os << "typedef " << db << "::query_base query_base_type;"
- << "struct query_columns";
-
- if (c.get<size_t> ("object-count") == 0)
- os << "{"
- << "};";
- else
- os << ";"
- << endl;
-
- //
- // Functions.
- //
-
- // grow ()
- //
- if (generate_grow)
- {
- os << "static bool" << endl
- << "grow (image_type&, " << truncated_vector << ");"
- << endl;
- }
-
- // bind (image_type)
- //
- os << "static void" << endl
- << "bind (" << bind_vector << ", image_type&);"
- << endl;
-
- // init (view, image)
- //
- os << "static void" << endl
- << "init (view_type&, const image_type&, database*);"
- << endl;
-
- // column_count
- //
- os << "static const std::size_t column_count = " <<
- column_count (c).total << "UL;"
- << endl;
-
- // Statements.
- //
- view_query& vq (c.get<view_query> ("query"));
-
- if (vq.kind != view_query::runtime)
- {
- os << "static query_base_type" << endl
- << "query_statement (const query_base_type&);"
- << endl;
- }
-
- //
- // Functions.
- //
-
- // callback ()
- //
- os << "static void" << endl
- << "callback (database&, view_type&, callback_event);"
- << endl;
-
- // query ()
- //
- if (!options.omit_unprepared ())
- os << "static result<view_type>" << endl
- << "query (database&, const query_base_type&);"
- << endl;
-
- view_public_extra_post (c);
-
- os << "};";
-
- // view_traits_impl< , id_default>
- //
- os << "template <>" << endl
- << "class access::view_traits_impl< " << type << ", " <<
- "id_default >:" << endl
- << " public access::view_traits_impl< " << type << ", " <<
- "id_" << db << " >"
- << "{"
- << "};";
- }
+ traverse_view (type&);
virtual void
- traverse_composite (type& c)
- {
- string const& type (class_fq_name (c));
-
- os << "// " << class_name (c) << endl
- << "//" << endl;
-
- os << "template <>" << endl
- << "struct class_traits< " << type << " >"
- << "{"
- << "static const class_kind kind = class_composite;"
- << "};";
-
- os << "template <>" << endl
- << "class access::composite_value_traits< " << type << ", " <<
- "id_" << db << " >"
- << "{"
- << "public:" << endl;
-
- // value_type
- //
- os << "typedef " << type << " value_type;"
- << endl;
-
- // image_type
- //
- image_type_->traverse (c);
-
- // Containers.
- //
- {
- instance<container_traits> t (c);
- t->traverse (c);
- }
-
- // grow ()
- //
- if (generate_grow)
- {
- os << "static bool" << endl
- << "grow (image_type&, " << truncated_vector << ");"
- << endl;
- }
-
- // bind (image_type)
- //
- os << "static void" << endl
- << "bind (" << bind_vector << ", image_type&, " <<
- db << "::statement_kind);"
- << endl;
-
- // init (image, value)
- //
- os << "static " << (generate_grow ? "bool" : "void") << endl
- << "init (image_type&, const value_type&, " <<
- db << "::statement_kind);"
- << endl;
-
- // init (value, image)
- //
- os << "static void" << endl
- << "init (value_type&, const image_type&, database*);"
- << endl;
-
- if (!has_a (c, test_container))
- {
- // get_null (image)
- //
- os << "static bool" << endl
- << "get_null (const image_type&);"
- << endl;
-
- // set_null (image)
- //
- os << "static void" << endl
- << "set_null (image_type&, " << db << "::statement_kind);"
- << endl;
- }
-
- os << "};";
- }
+ traverse_composite (type&);
private:
instance<image_type> image_type_;
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index e771053..58a2292 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -794,14 +794,19 @@ namespace relational
}
virtual void
- object_query_statement_ctor_args (type&)
+ object_query_statement_ctor_args (type&, string const& q, bool prep)
{
- os << "sts.connection ()," << endl
- << "query_statement_name," << endl
- << "query_statement + q.clause ()," << endl
- << "q.parameter_types ()," << endl
- << "q.parameter_count ()," << endl
- << "q.parameters_binding ()," << endl
+ os << "sts.connection ()," << endl;
+
+ if (prep)
+ os << "n," << endl;
+ else
+ os << "query_statement_name," << endl;
+
+ os << "query_statement + " << q << ".clause ()," << endl
+ << q << ".parameter_types ()," << endl
+ << q << ".parameter_count ()," << endl
+ << q << ".parameters_binding ()," << endl
<< "imb";
}
@@ -817,14 +822,19 @@ namespace relational
}
virtual void
- view_query_statement_ctor_args (type&)
+ view_query_statement_ctor_args (type&, string const& q, bool prep)
{
- os << "sts.connection ()," << endl
- << "query_statement_name," << endl
- << "qs.clause ()," << endl
- << "qs.parameter_types ()," << endl
- << "qs.parameter_count ()," << endl
- << "qs.parameters_binding ()," << endl
+ os << "sts.connection ()," << endl;
+
+ if (prep)
+ os << "n," << endl;
+ else
+ os << "query_statement_name," << endl;
+
+ os << q << ".clause ()," << endl
+ << q << ".parameter_types ()," << endl
+ << q << ".parameter_count ()," << endl
+ << q << ".parameters_binding ()," << endl
<< "imb";
}
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 4e407b6..2c5d6cb 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -2625,7 +2625,7 @@ traverse_object (type& c)
os << "q.init_parameters ();"
<< "shared_ptr<select_statement> st (" << endl
<< "new (shared) select_statement (" << endl;
- object_query_statement_ctor_args (c, "q");
+ object_query_statement_ctor_args (c, "q", false);
os << "));" << endl
<< "st->execute ();";
@@ -2638,30 +2638,30 @@ traverse_object (type& c)
<< endl
<< "return result<object_type> (r);"
<< "}";
-
- // erase_query
- //
- os << "unsigned long long " << traits << "::" << endl
- << "erase_query (database&, const query_base_type& q)"
- << "{"
- << "using namespace " << db << ";"
- << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << endl
- << "q.init_parameters ();"
- << "delete_statement st (" << endl;
- object_erase_query_statement_ctor_args (c, "q");
- os << ");"
- << endl
- << "return st.execute ();"
- << "}";
}
+ // erase_query
+ //
+ os << "unsigned long long " << traits << "::" << endl
+ << "erase_query (database&, const query_base_type& q)"
+ << "{"
+ << "using namespace " << db << ";"
+ << endl
+ << db << "::connection& conn (" << endl
+ << db << "::transaction::current ().connection ());"
+ << endl
+ << "q.init_parameters ();"
+ << "delete_statement st (" << endl;
+ object_erase_query_statement_ctor_args (c);
+ os << ");"
+ << endl
+ << "return st.execute ();"
+ << "}";
+
// Prepared. Very similar to unprepared but has some annoying variations
// that make it difficult to factor out something common.
//
- if (!options.omit_prepared ())
+ if (options.generate_prepared ())
{
os << "odb::details::shared_ptr<prepared_query_impl>" << endl
<< traits << "::" << endl
@@ -2715,7 +2715,7 @@ traverse_object (type& c)
<< "r->query = q;"
<< "r->stmt.reset (" << endl
<< "new (shared) select_statement (" << endl;
- object_query_statement_ctor_args (c, "r->query");
+ object_query_statement_ctor_args (c, "r->query", true);
os << "));"
<< endl
<< "return r;"
@@ -2731,7 +2731,9 @@ traverse_object (type& c)
<< endl
<< db << "::prepared_query_impl& pq (" << endl
<< "static_cast<" << db << "::prepared_query_impl&> (q));"
- << "shared_ptr<select_statement>& st (pq.stmt);"
+ << "shared_ptr<select_statement> st (" << endl
+ << "odb::details::inc_ref (" << endl
+ << "static_cast<select_statement*> (pq.stmt.get ())));"
<< endl
<< db << "::connection& conn (" << endl
<< db << "::transaction::current ().connection ());"
@@ -2784,7 +2786,6 @@ traverse_object (type& c)
<< "pq.query, st, sts));"
<< "}";
}
-
}
if (embedded_schema)
@@ -3529,7 +3530,7 @@ traverse_view (type& c)
<< "}";
}
- // query ()
+ // Unprepared.
//
if (!options.omit_unprepared ())
{
@@ -3544,7 +3545,7 @@ traverse_view (type& c)
<< db << "::connection& conn (" << endl
<< db << "::transaction::current ().connection ());"
<< endl
- << "view_statements< view_type >& sts (" << endl
+ << "statements_type& sts (" << endl
<< "conn.statement_cache ().find_view<view_type> ());"
<< endl
<< "image_type& im (sts.image ());"
@@ -3565,9 +3566,7 @@ traverse_view (type& c)
os << "qs.init_parameters ();"
<< "shared_ptr<select_statement> st (" << endl
<< "new (shared) select_statement (" << endl;
-
- view_query_statement_ctor_args (c);
-
+ view_query_statement_ctor_args (c, "qs", false);
os << "));" << endl
<< "st->execute ();";
@@ -3581,6 +3580,107 @@ traverse_view (type& c)
<< "return result<view_type> (r);"
<< "}";
}
+
+ // Prepared. Very similar to unprepared but has some annoying variations
+ // that make it difficult to factor out something common.
+ //
+ if (options.generate_prepared ())
+ {
+ os << "odb::details::shared_ptr<prepared_query_impl>" << endl
+ << traits << "::" << endl
+ << "prepare_query (connection& c, const char* n, " <<
+ "const query_base_type& q)"
+ << "{"
+ << "using namespace " << db << ";"
+ << "using odb::details::shared;"
+ << "using odb::details::shared_ptr;"
+ << endl
+ << db << "::connection& conn (" << endl
+ << "static_cast<" << db << "::connection&> (c));"
+ << endl
+ << "statements_type& sts (" << endl
+ << "conn.statement_cache ().find_view<view_type> ());"
+ << endl;
+
+ // Rebind the image if necessary.
+ //
+ os << "image_type& im (sts.image ());"
+ << "binding& imb (sts.image_binding ());"
+ << endl
+ << "if (im.version != sts.image_version () || imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, im);"
+ << "sts.image_version (im.version);"
+ << "imb.version++;"
+ << "}";
+
+ os << "shared_ptr<" << db << "::prepared_query_impl> r (" << endl
+ << "new (shared) " << db << "::prepared_query_impl);"
+ << "r->name = n;"
+ << "r->execute = &execute_query;";
+
+ if (vq.kind == view_query::runtime)
+ os << "r->query = q;";
+ else
+ os << "r->query = query_statement (q);";
+
+ os << "r->stmt.reset (" << endl
+ << "new (shared) select_statement (" << endl;
+ view_query_statement_ctor_args (c, "r->query", true);
+ os << "));"
+ << endl
+ << "return r;"
+ << "}";
+
+ os << "odb::details::shared_ptr<result_impl>" << endl
+ << traits << "::" << endl
+ << "execute_query (prepared_query_impl& q)"
+ << "{"
+ << "using namespace " << db << ";"
+ << "using odb::details::shared;"
+ << "using odb::details::shared_ptr;"
+ << endl
+ << db << "::prepared_query_impl& pq (" << endl
+ << "static_cast<" << db << "::prepared_query_impl&> (q));"
+ << "shared_ptr<select_statement> st (" << endl
+ << "odb::details::inc_ref (" << endl
+ << "static_cast<select_statement*> (pq.stmt.get ())));"
+ << endl
+ << db << "::connection& conn (" << endl
+ << db << "::transaction::current ().connection ());"
+ << endl
+ << "// The connection used by the current transaction and the" << endl
+ << "// one used to prepare this statement must be the same." << endl
+ << "//" << endl
+ << "assert (&conn == &st->connection ());"
+ << endl
+ << "statements_type& sts (" << endl
+ << "conn.statement_cache ().find_view<view_type> ());"
+ << endl;
+
+ // Rebind the image if necessary.
+ //
+ os << "image_type& im (sts.image ());"
+ << "binding& imb (sts.image_binding ());"
+ << endl
+ << "if (im.version != sts.image_version () || imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, im);"
+ << "sts.image_version (im.version);"
+ << "imb.version++;"
+ << "}";
+
+ os << "pq.query.init_parameters ();"
+ << "st->execute ();";
+
+ post_query_ (c, false);
+
+ os << endl
+ << "return shared_ptr<result_impl> (" << endl
+ << "new (shared) " << db << "::view_result_impl<view_type> (" << endl
+ << "pq.query, st, sts));"
+ << "}";
+ }
}
namespace relational
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 4f1a9fc..a284676 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -3425,7 +3425,9 @@ namespace relational
}
virtual void
- object_query_statement_ctor_args (type&, std::string const& q)
+ object_query_statement_ctor_args (type&,
+ std::string const& q,
+ bool /*prepared*/)
{
os << "conn," << endl
<< "query_statement + " << q << ".clause ()," << endl
@@ -3434,11 +3436,11 @@ namespace relational
}
virtual void
- object_erase_query_statement_ctor_args (type&, std::string const& q)
+ object_erase_query_statement_ctor_args (type&)
{
os << "conn," << endl
- << "erase_query_statement + " << q << ".clause ()," << endl
- << q << ".parameters_binding ()";
+ << "erase_query_statement + q.clause ()," << endl
+ << "q.parameters_binding ()";
}
virtual void
@@ -3454,11 +3456,13 @@ namespace relational
}
virtual void
- view_query_statement_ctor_args (type&)
+ view_query_statement_ctor_args (type&,
+ string const& q,
+ bool /*prepared*/)
{
os << "conn," << endl
- << "qs.clause ()," << endl
- << "qs.parameters_binding ()," << endl
+ << q << ".clause ()," << endl
+ << q << ".parameters_binding ()," << endl
<< "imb";
}
@@ -3689,7 +3693,7 @@ namespace relational
if (options.generate_query ())
{
- if (!options.omit_prepared ())
+ if (options.generate_prepared ())
os << "#include <odb/" << db << "/prepared-query.hxx>" << endl;
if (features.simple_object)