From defe5aec4edc065546d44ad17b48a2dd5290144d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 12 Oct 2012 17:24:45 +0200 Subject: Completion of prepared query support --- odb/header.cxx | 2 +- odb/options.cli | 4 +- odb/relational/header.cxx | 240 +++++++++++++++++++++++++++++++++++++++- odb/relational/header.hxx | 218 +----------------------------------- odb/relational/pgsql/source.cxx | 38 ++++--- odb/relational/source.cxx | 156 +++++++++++++++++++++----- odb/relational/source.hxx | 20 ++-- 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 " << endl; os << "#include " << 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" << 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" << 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 ("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 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 ("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 ("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" << endl + << "query (database&, const query_base_type&);" + << endl; + + if (options.generate_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; + } + + 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 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 ("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 ("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 ("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" << 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 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_; 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 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 (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" << 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& st (pq.stmt);" + << "shared_ptr st (" << endl + << "odb::details::inc_ref (" << endl + << "static_cast (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 ());" << endl << "image_type& im (sts.image ());" @@ -3565,9 +3566,7 @@ traverse_view (type& c) 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, "qs", false); os << "));" << endl << "st->execute ();"; @@ -3581,6 +3580,107 @@ traverse_view (type& c) << "return result (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" << 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 ());" + << 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" << 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 (" << endl + << "odb::details::inc_ref (" << endl + << "static_cast (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 ());" + << 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 (" << endl + << "new (shared) " << db << "::view_result_impl (" << 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 " << endl; if (features.simple_object) -- cgit v1.1