From b134d7b4f2c105870a98a67ec568c16c9f632aba Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 4 Oct 2012 11:33:49 +0200 Subject: Initial support for prepared queries --- odb/header.cxx | 3 + odb/options.cli | 10 ++ odb/relational/header.cxx | 26 ++- odb/relational/header.hxx | 15 +- odb/relational/pgsql/source.cxx | 5 +- odb/relational/source.cxx | 363 +++++++++++++++++++++++++++------------- odb/relational/source.hxx | 24 +-- 7 files changed, 309 insertions(+), 137 deletions(-) (limited to 'odb') diff --git a/odb/header.cxx b/odb/header.cxx index 8bf5453..32dc898 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -60,6 +60,9 @@ namespace header if (ctx.options.generate_query ()) { + if (!ctx.options.omit_prepared ()) + os << "#include " << endl; + os << "#include " << endl; if (ctx.features.simple_object) diff --git a/odb/options.cli b/odb/options.cli index f61aa0e..ce990b0 100644 --- a/odb/options.cli +++ b/odb/options.cli @@ -58,6 +58,16 @@ class options and can only load objects via their ids." }; + bool --omit-prepared + { + "Omit prepared query execution support code." + }; + + bool --omit-unprepared + { + "Omit un-prepared (once-off) query execution support code." + }; + bool --generate-session | -e { "Generate session support code. With this option session support will diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index 41b4960..a78697f 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -680,13 +680,27 @@ traverse_object (type& c) // if (options.generate_query ()) { - os << "static result" << endl - << "query (database&, const query_base_type&);" - << endl; + if (!options.omit_unprepared ()) + { + os << "static result" << endl + << "query (database&, const query_base_type&);" + << endl; - os << "static unsigned long long" << endl - << "erase_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 odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } } // create_schema () diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 9d932ae..fe08a49 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -1124,9 +1124,10 @@ namespace relational // query () // - os << "static result" << endl - << "query (database&, const query_base_type&);" - << endl; + if (!options.omit_unprepared ()) + os << "static result" << endl + << "query (database&, const query_base_type&);" + << endl; view_public_extra_post (c); @@ -1445,8 +1446,12 @@ namespace relational generate () { os << "#include " << endl - << "#include " << endl - << endl; + << "#include " << endl; + + if (options.generate_query ()) + os << "#include " << endl; + + os << endl; os << "#include " << endl << "#include " << endl diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index da07073..e771053 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -829,9 +829,10 @@ namespace relational } virtual void - post_query_ (type&) + post_query_ (type&, bool once_off) { - os << "st->deallocate ();"; + if (once_off) + os << "st->deallocate ();"; } }; entry class_entry_; diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 8981417..4e407b6 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -2564,92 +2564,227 @@ traverse_object (type& c) if (options.generate_query ()) { - // query () - // - os << "result< " << traits << "::object_type >" << endl - << traits << "::" << endl - << "query (database&, const query_base_type& q)" - << "{" - << "using namespace " << db << ";" - << "using odb::details::shared;" - << "using odb::details::shared_ptr;" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection ());" - << endl - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl; + char const* result_type; + if (poly) + result_type = "polymorphic_object_result_impl"; + else if (id != 0) + result_type = "object_result_impl"; + else + result_type = "no_id_object_result_impl"; - // Rebind the image if necessary. + // Unprepared. // - os << "image_type& im (sts.image ());" - << "binding& imb (sts.select_image_binding (" << - (poly_derived ? "depth" : "") << "));" - << endl; - - if (poly_derived) + if (!options.omit_unprepared ()) { - os << "if (imb.version == 0 ||" << endl - << "check_version (sts.select_image_versions (), im))" + // query () + // + os << "result< " << traits << "::object_type >" << endl + << traits << "::" << endl + << "query (database&, const query_base_type& q)" << "{" - << "bind (imb.bind, 0, 0, im, statement_select);" - << "update_version (sts.select_image_versions ()," << endl - << "im," << endl - << "sts.select_image_bindings ());" + << "using namespace " << db << ";" + << "using odb::details::shared;" + << "using odb::details::shared_ptr;" + << endl + << db << "::connection& conn (" << endl + << db << "::transaction::current ().connection ());" + << endl + << "statements_type& sts (" << endl + << "conn.statement_cache ().find_object ());" + << endl; + + // Rebind the image if necessary. + // + os << "image_type& im (sts.image ());" + << "binding& imb (sts.select_image_binding (" << + (poly_derived ? "depth" : "") << "));" + << endl; + + if (poly_derived) + { + os << "if (imb.version == 0 ||" << endl + << "check_version (sts.select_image_versions (), im))" + << "{" + << "bind (imb.bind, 0, 0, im, statement_select);" + << "update_version (sts.select_image_versions ()," << endl + << "im," << endl + << "sts.select_image_bindings ());" + << "}"; + } + else + { + os << "if (im.version != sts.select_image_version () ||" << endl + << "imb.version == 0)" + << "{" + << "bind (imb.bind, im, statement_select);" + << "sts.select_image_version (im.version);" + << "imb.version++;" + << "}"; + } + + os << "q.init_parameters ();" + << "shared_ptr st (" << endl + << "new (shared) select_statement (" << endl; + object_query_statement_ctor_args (c, "q"); + os << "));" << endl + << "st->execute ();"; + + post_query_ (c, true); + + os << endl + << "shared_ptr< odb::" << result_type << " > r (" << endl + << "new (shared) " << db << "::" << result_type << " (" << endl + << "q, st, sts));" + << endl + << "return result (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 ();" << "}"; } - else + + // Prepared. Very similar to unprepared but has some annoying variations + // that make it difficult to factor out something common. + // + if (!options.omit_prepared ()) { - os << "if (im.version != sts.select_image_version () ||" << endl - << "imb.version == 0)" + os << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const query_base_type& q)" << "{" - << "bind (imb.bind, im, statement_select);" - << "sts.select_image_version (im.version);" - << "imb.version++;" + << "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_object ());" + << endl; + + // Rebind the image if necessary. + // + os << "image_type& im (sts.image ());" + << "binding& imb (sts.select_image_binding (" << + (poly_derived ? "depth" : "") << "));" + << endl; + + if (poly_derived) + { + os << "if (imb.version == 0 ||" << endl + << "check_version (sts.select_image_versions (), im))" + << "{" + << "bind (imb.bind, 0, 0, im, statement_select);" + << "update_version (sts.select_image_versions ()," << endl + << "im," << endl + << "sts.select_image_bindings ());" + << "}"; + } + else + { + os << "if (im.version != sts.select_image_version () ||" << endl + << "imb.version == 0)" + << "{" + << "bind (imb.bind, im, statement_select);" + << "sts.select_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;" + << "r->query = q;" + << "r->stmt.reset (" << endl + << "new (shared) select_statement (" << endl; + object_query_statement_ctor_args (c, "r->query"); + os << "));" + << endl + << "return r;" << "}"; - } - os << "shared_ptr st (" << endl - << "new (shared) select_statement (" << endl; - object_query_statement_ctor_args (c); - os << "));" << endl - << "st->execute ();"; + os << "odb::details::shared_ptr" << 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& st (pq.stmt);" + << 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_object ());" + << endl; - post_query_ (c); + // Rebind the image if necessary. + // + os << "image_type& im (sts.image ());" + << "binding& imb (sts.select_image_binding (" << + (poly_derived ? "depth" : "") << "));" + << endl; - char const* result_type; - if (poly) - result_type = "polymorphic_object_result_impl"; - else if (id != 0) - result_type = "object_result_impl"; - else - result_type = "no_id_object_result_impl"; + if (poly_derived) + { + os << "if (imb.version == 0 ||" << endl + << "check_version (sts.select_image_versions (), im))" + << "{" + << "bind (imb.bind, 0, 0, im, statement_select);" + << "update_version (sts.select_image_versions ()," << endl + << "im," << endl + << "sts.select_image_bindings ());" + << "}"; + } + else + { + os << "if (im.version != sts.select_image_version () ||" << endl + << "imb.version == 0)" + << "{" + << "bind (imb.bind, im, statement_select);" + << "sts.select_image_version (im.version);" + << "imb.version++;" + << "}"; + } - os << endl - << "shared_ptr< odb::" << result_type << " > r (" << endl - << "new (shared) " << db << "::" << result_type << " (" << endl - << "q, st, sts));" - << endl - << "return result (r);" - << "}"; + os << "pq.query.init_parameters ();" + << "st->execute ();"; + post_query_ (c, false); + + os << endl + << "return shared_ptr (" << endl + << "new (shared) " << db << "::" << result_type << " (" << endl + << "pq.query, st, sts));" + << "}"; + } - // 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 - << "delete_statement st (" << endl; - object_erase_query_statement_ctor_args (c); - os << ");" - << endl - << "return st.execute ();" - << "}"; } if (embedded_schema) @@ -3396,52 +3531,56 @@ traverse_view (type& c) // query () // - os << "result< " << traits << "::view_type >" << endl - << traits << "::" << endl - << "query (database&, const query_base_type& q)" - << "{" - << "using namespace " << db << ";" - << "using odb::details::shared;" - << "using odb::details::shared_ptr;" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection ());" - << endl - << "view_statements< view_type >& sts (" << endl - << "conn.statement_cache ().find_view ());" - << endl - << "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++;" - << "}"; + if (!options.omit_unprepared ()) + { + os << "result< " << traits << "::view_type >" << endl + << traits << "::" << endl + << "query (database&, const query_base_type& q)" + << "{" + << "using namespace " << db << ";" + << "using odb::details::shared;" + << "using odb::details::shared_ptr;" + << endl + << db << "::connection& conn (" << endl + << db << "::transaction::current ().connection ());" + << endl + << "view_statements< view_type >& sts (" << endl + << "conn.statement_cache ().find_view ());" + << endl + << "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++;" + << "}"; - if (vq.kind == view_query::runtime) - os << "const query_base_type& qs (q);"; - else - os << "const query_base_type& qs (query_statement (q));"; + if (vq.kind == view_query::runtime) + os << "const query_base_type& qs (q);"; + else + os << "const query_base_type& qs (query_statement (q));"; - os << "shared_ptr st (" << endl - << "new (shared) select_statement (" << endl; + os << "qs.init_parameters ();" + << "shared_ptr st (" << endl + << "new (shared) select_statement (" << endl; - view_query_statement_ctor_args (c); + view_query_statement_ctor_args (c); - os << "));" << endl - << "st->execute ();"; + os << "));" << endl + << "st->execute ();"; - post_query_ (c); + post_query_ (c, true); - os << endl - << "shared_ptr< odb::view_result_impl > r (" << endl - << "new (shared) " << db << "::view_result_impl (" << endl - << "qs, st, sts));" - << endl - << "return result (r);" - << "}"; + os << endl + << "shared_ptr< odb::view_result_impl > r (" << endl + << "new (shared) " << db << "::view_result_impl (" << endl + << "qs, st, sts));" + << endl + << "return result (r);" + << "}"; + } } namespace relational diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 123ac55..4f1a9fc 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -3406,7 +3406,7 @@ namespace relational // virtual void - post_query_ (type&) + post_query_ (type&, bool /*once_off*/) { } @@ -3425,20 +3425,20 @@ namespace relational } virtual void - object_query_statement_ctor_args (type&) + object_query_statement_ctor_args (type&, std::string const& q) { - os << "sts.connection ()," << endl - << "query_statement + q.clause ()," << endl - << "q.parameters_binding ()," << endl + os << "conn," << endl + << "query_statement + " << q << ".clause ()," << endl + << q << ".parameters_binding ()," << endl << "imb"; } virtual void - object_erase_query_statement_ctor_args (type&) + object_erase_query_statement_ctor_args (type&, std::string const& q) { os << "conn," << endl - << "erase_query_statement + q.clause ()," << endl - << "q.parameters_binding ()"; + << "erase_query_statement + " << q << ".clause ()," << endl + << q << ".parameters_binding ()"; } virtual void @@ -3456,7 +3456,7 @@ namespace relational virtual void view_query_statement_ctor_args (type&) { - os << "sts.connection ()," << endl + os << "conn," << endl << "qs.clause ()," << endl << "qs.parameters_binding ()," << endl << "imb"; @@ -3663,9 +3663,6 @@ namespace relational if (embedded_schema) os << "#include " << endl; - if (options.generate_query ()) - os << "#include " << endl; - os << endl; os << "#include " << endl @@ -3692,6 +3689,9 @@ namespace relational if (options.generate_query ()) { + if (!options.omit_prepared ()) + os << "#include " << endl; + if (features.simple_object) os << "#include " << endl; -- cgit v1.1