From 823026b58211a4166de06ac243d978dcb9930271 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 22 Jan 2024 15:58:08 +0300 Subject: Turn odb repository into muti-package repository Also remove the autoconf/make-based build system. --- odb/relational/changelog.cxx | 1239 ------- odb/relational/common-query.cxx | 169 - odb/relational/common-query.hxx | 63 - odb/relational/common.cxx | 27 - odb/relational/common.hxx | 273 -- odb/relational/common.txx | 125 - odb/relational/context.cxx | 169 - odb/relational/context.hxx | 289 -- odb/relational/context.ixx | 44 - odb/relational/generate.hxx | 81 - odb/relational/header.cxx | 1146 ------ odb/relational/header.hxx | 1466 -------- odb/relational/inline.cxx | 47 - odb/relational/inline.hxx | 693 ---- odb/relational/model.cxx | 121 - odb/relational/model.hxx | 868 ----- odb/relational/mssql/common.cxx | 603 ---- odb/relational/mssql/common.hxx | 293 -- odb/relational/mssql/context.cxx | 766 ---- odb/relational/mssql/context.hxx | 194 - odb/relational/mssql/header.cxx | 312 -- odb/relational/mssql/inline.cxx | 42 - odb/relational/mssql/model.cxx | 66 - odb/relational/mssql/schema.cxx | 651 ---- odb/relational/mssql/source.cxx | 1201 ------- odb/relational/mysql/common.cxx | 400 --- odb/relational/mysql/common.hxx | 171 - odb/relational/mysql/context.cxx | 868 ----- odb/relational/mysql/context.hxx | 194 - odb/relational/mysql/header.cxx | 136 - odb/relational/mysql/inline.cxx | 42 - odb/relational/mysql/model.cxx | 161 - odb/relational/mysql/schema.cxx | 489 --- odb/relational/mysql/source.cxx | 724 ---- odb/relational/oracle/common.cxx | 522 --- odb/relational/oracle/common.hxx | 203 -- odb/relational/oracle/context.cxx | 795 ----- odb/relational/oracle/context.hxx | 188 - odb/relational/oracle/header.cxx | 230 -- odb/relational/oracle/inline.cxx | 42 - odb/relational/oracle/model.cxx | 64 - odb/relational/oracle/schema.cxx | 696 ---- odb/relational/oracle/source.cxx | 646 ---- odb/relational/pgsql/common.cxx | 351 -- odb/relational/pgsql/common.hxx | 159 - odb/relational/pgsql/context.cxx | 786 ---- odb/relational/pgsql/context.hxx | 192 - odb/relational/pgsql/header.cxx | 285 -- odb/relational/pgsql/inline.cxx | 42 - odb/relational/pgsql/model.cxx | 101 - odb/relational/pgsql/schema.cxx | 266 -- odb/relational/pgsql/source.cxx | 1140 ------ odb/relational/processor.cxx | 1564 -------- odb/relational/processor.hxx | 15 - odb/relational/schema-source.cxx | 281 -- odb/relational/schema-source.hxx | 126 - odb/relational/schema.cxx | 174 - odb/relational/schema.hxx | 1606 --------- odb/relational/source.cxx | 6343 -------------------------------- odb/relational/source.hxx | 7154 ------------------------------------- odb/relational/sqlite/common.cxx | 217 -- odb/relational/sqlite/common.hxx | 147 - odb/relational/sqlite/context.cxx | 490 --- odb/relational/sqlite/context.hxx | 146 - odb/relational/sqlite/header.cxx | 63 - odb/relational/sqlite/inline.cxx | 42 - odb/relational/sqlite/model.cxx | 91 - odb/relational/sqlite/schema.cxx | 455 --- odb/relational/sqlite/source.cxx | 471 --- odb/relational/validator.cxx | 638 ---- odb/relational/validator.hxx | 24 - 71 files changed, 40888 deletions(-) delete mode 100644 odb/relational/changelog.cxx delete mode 100644 odb/relational/common-query.cxx delete mode 100644 odb/relational/common-query.hxx delete mode 100644 odb/relational/common.cxx delete mode 100644 odb/relational/common.hxx delete mode 100644 odb/relational/common.txx delete mode 100644 odb/relational/context.cxx delete mode 100644 odb/relational/context.hxx delete mode 100644 odb/relational/context.ixx delete mode 100644 odb/relational/generate.hxx delete mode 100644 odb/relational/header.cxx delete mode 100644 odb/relational/header.hxx delete mode 100644 odb/relational/inline.cxx delete mode 100644 odb/relational/inline.hxx delete mode 100644 odb/relational/model.cxx delete mode 100644 odb/relational/model.hxx delete mode 100644 odb/relational/mssql/common.cxx delete mode 100644 odb/relational/mssql/common.hxx delete mode 100644 odb/relational/mssql/context.cxx delete mode 100644 odb/relational/mssql/context.hxx delete mode 100644 odb/relational/mssql/header.cxx delete mode 100644 odb/relational/mssql/inline.cxx delete mode 100644 odb/relational/mssql/model.cxx delete mode 100644 odb/relational/mssql/schema.cxx delete mode 100644 odb/relational/mssql/source.cxx delete mode 100644 odb/relational/mysql/common.cxx delete mode 100644 odb/relational/mysql/common.hxx delete mode 100644 odb/relational/mysql/context.cxx delete mode 100644 odb/relational/mysql/context.hxx delete mode 100644 odb/relational/mysql/header.cxx delete mode 100644 odb/relational/mysql/inline.cxx delete mode 100644 odb/relational/mysql/model.cxx delete mode 100644 odb/relational/mysql/schema.cxx delete mode 100644 odb/relational/mysql/source.cxx delete mode 100644 odb/relational/oracle/common.cxx delete mode 100644 odb/relational/oracle/common.hxx delete mode 100644 odb/relational/oracle/context.cxx delete mode 100644 odb/relational/oracle/context.hxx delete mode 100644 odb/relational/oracle/header.cxx delete mode 100644 odb/relational/oracle/inline.cxx delete mode 100644 odb/relational/oracle/model.cxx delete mode 100644 odb/relational/oracle/schema.cxx delete mode 100644 odb/relational/oracle/source.cxx delete mode 100644 odb/relational/pgsql/common.cxx delete mode 100644 odb/relational/pgsql/common.hxx delete mode 100644 odb/relational/pgsql/context.cxx delete mode 100644 odb/relational/pgsql/context.hxx delete mode 100644 odb/relational/pgsql/header.cxx delete mode 100644 odb/relational/pgsql/inline.cxx delete mode 100644 odb/relational/pgsql/model.cxx delete mode 100644 odb/relational/pgsql/schema.cxx delete mode 100644 odb/relational/pgsql/source.cxx delete mode 100644 odb/relational/processor.cxx delete mode 100644 odb/relational/processor.hxx delete mode 100644 odb/relational/schema-source.cxx delete mode 100644 odb/relational/schema-source.hxx delete mode 100644 odb/relational/schema.cxx delete mode 100644 odb/relational/schema.hxx delete mode 100644 odb/relational/source.cxx delete mode 100644 odb/relational/source.hxx delete mode 100644 odb/relational/sqlite/common.cxx delete mode 100644 odb/relational/sqlite/common.hxx delete mode 100644 odb/relational/sqlite/context.cxx delete mode 100644 odb/relational/sqlite/context.hxx delete mode 100644 odb/relational/sqlite/header.cxx delete mode 100644 odb/relational/sqlite/inline.cxx delete mode 100644 odb/relational/sqlite/model.cxx delete mode 100644 odb/relational/sqlite/schema.cxx delete mode 100644 odb/relational/sqlite/source.cxx delete mode 100644 odb/relational/validator.cxx delete mode 100644 odb/relational/validator.hxx (limited to 'odb/relational') diff --git a/odb/relational/changelog.cxx b/odb/relational/changelog.cxx deleted file mode 100644 index 99f72da..0000000 --- a/odb/relational/changelog.cxx +++ /dev/null @@ -1,1239 +0,0 @@ -// file : odb/relational/changelog.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace changelog - { - using namespace sema_rel; - using sema_rel::model; - using sema_rel::changelog; - - typedef map deleted_table_map; - typedef map deleted_column_map; - - namespace - { - // - // diff - // - - struct diff_table: trav_rel::column, - trav_rel::primary_key, - trav_rel::foreign_key, - trav_rel::index - { - enum mode_type {mode_add, mode_drop}; - - diff_table (table& o, - mode_type m, - alter_table& a, - graph& gr, - options const& op, - model_version const* v) - : other (o), mode (m), at (a), g (gr), ops (op), version (v) {} - - virtual void - traverse (sema_rel::column& c) - { - using sema_rel::column; - - if (mode == mode_add) - { - if (column* oc = other.find (c.name ())) - { - if (c.type () != oc->type ()) - diagnose_column (c, "type", oc->type (), c.type ()); - - if (c.null () != oc->null ()) - { - alter_column& ac (g.new_node (c.id ())); - - // Set the alters edge. - // - column* b (at.lookup (c.name ())); - assert (b != 0); - g.new_edge (ac, *b); - - ac.null (c.null ()); - g.new_edge (at, ac, c.name ()); - } - - if (c.default_ () != oc->default_ ()) - diagnose_column ( - c, "default value", oc->default_ (), c.default_ ()); - - if (c.options () != oc->options ()) - diagnose_column (c, "options", oc->options (), c.options ()); - } - else - { - if (version != 0) - { - data_member_path const& mp ( - c.get ("member-path")); - - semantics::data_member* m (context::added_member (mp)); - if (m != 0) - { - // Make sure the addition version is the current version. - // - if (context::added (*m) != version->current) - { - location l (m->get ("added-location")); - error (l) << "member addition version is not the same " << - "as the current model version" << endl; - throw operation_failed (); - } - } - // Warn about hard additions. If the version is closed, then - // we have already seen these warnings so no need to repeat - // them. - // - else if (ops.warn_hard_add () && version->open) - { - // Issue nicer diagnostics for the direct data member case. - // - if (mp.size () == 1) - { - location l (mp.back ()->location ()); - warn (l) << "data member is hard-added" << endl; - } - else - { - semantics::class_& s ( - dynamic_cast ( - mp.front ()->scope ())); - - warn (s.location ()) << "column '" << c.name () << "' " << - "in class '" << s.name () << "' is hard-added" << endl; - - for (data_member_path::const_iterator i (mp.begin ()); - i != mp.end (); ++i) - { - info ((*i)->location ()) << "corresponding hard-" << - "added data member could be '" << (*i)->name () << - "'" << endl; - } - } - } - } - - add_column& ac (g.new_node (c, at, g)); - g.new_edge (at, ac, c.name ()); - } - } - else - { - if (other.find (c.name ()) == 0) - { - if (version != 0) - { - // See if we have an entry for this column in the soft- - // deleted map. - // - deleted_column_map const& dm ( - other.get ("deleted-map")); - deleted_column_map::const_iterator i (dm.find (c.name ())); - - if (i != dm.end ()) - { - if (context::deleted (*i->second) != version->current) - { - location l (i->second->get ("deleted-location")); - error (l) << "member deletion version is not the same " << - "as the current model version" << endl; - throw operation_failed (); - } - } - // Warn about hard deletions. If the version is closed, then - // we have already seen these warnings so no need to repeat - // them. - // - else if (ops.warn_hard_delete () && version->open) - { - // Here all we have is a column name and a class (object) - // or data member (container) corresponding to the table. - // - if (semantics::class_* s = - other.get ("class", 0)) - { - warn (s->location ()) << "column '" << c.name () << "' " << - "in class '" << s->name () << "' is hard-deleted" << endl; - } - else - { - data_member_path const& mp ( - other.get ("member-path")); - - warn (mp.back ()->location ()) << "column '" << - c.name () << "' in container '" << - mp.back ()->name () << "' is hard-deleted" << endl; - } - } - } - - drop_column& dc (g.new_node (c.id ())); - g.new_edge (at, dc, c.name ()); - } - } - } - - virtual void - traverse (sema_rel::primary_key& pk) - { - using sema_rel::primary_key; - - if (mode == mode_add) - { - if (primary_key* opk = other.find (pk.name ())) - { - if (pk.auto_ () != opk->auto_ ()) - diagnose_primary_key (pk, "auto kind"); - - // Database-specific information. - // - for (primary_key::extra_map::const_iterator i ( - pk.extra ().begin ()); i != pk.extra ().end (); ++i) - { - if (opk->extra ().count (i->first) == 0 || - opk->extra ()[i->first] != i->second) - diagnose_primary_key (pk, i->first.c_str ()); - } - - for (primary_key::extra_map::const_iterator i ( - opk->extra ().begin ()); i != opk->extra ().end (); ++i) - { - if (pk.extra ().count (i->first) == 0 || - pk.extra ()[i->first] != i->second) - diagnose_primary_key (pk, i->first.c_str ()); - } - - if (pk.contains_size () != opk->contains_size ()) - diagnose_primary_key (pk, "member set"); - - for (primary_key::contains_size_type i (0); - i != pk.contains_size (); ++i) - { - sema_rel::contains& c (pk.contains_at (i)); - sema_rel::contains& oc (opk->contains_at (i)); - - if (c.column ().name () != oc.column ().name ()) - diagnose_primary_key (pk, "member set"); - } - } - else - { - location const& l (pk.get ("cxx-location")); - error (l) << "adding object id to an existing class is " << - "not supported" << endl; - info (l) << "consider re-implementing this change by adding " << - "a new class with the object id, migrating the data, and " << - "deleteing the old class" << endl; - throw operation_failed (); - } - } - else - { - if (other.find (pk.name ()) == 0) - { - location const& l (other.get ("cxx-location")); - error (l) << "deleting object id from an existing class is " << - "not supported" << endl; - info (l) << "consider re-implementing this change by adding " << - "a new class without the object id, migrating the data, " << - "and deleteing the old class" << endl; - throw operation_failed (); - } - } - } - - virtual void - traverse (sema_rel::foreign_key& fk) - { - using sema_rel::foreign_key; - - if (mode == mode_add) - { - if (foreign_key* ofk = other.find (fk.name ())) - { - if (fk.deferrable () != ofk->deferrable ()) - diagnose_foreign_key (fk, "deferrable mode"); - - if (fk.on_delete () != ofk->on_delete ()) - diagnose_foreign_key (fk, "on delete action"); - - if (fk.referenced_table () != ofk->referenced_table ()) - // See diagnose_foreign_key() if changing this name. - // - diagnose_foreign_key (fk, "pointed-to class"); - - if (fk.referenced_columns () != ofk->referenced_columns ()) - diagnose_foreign_key (fk, "id member set"); - - if (fk.contains_size () != ofk->contains_size ()) - diagnose_foreign_key (fk, "id member set"); - - for (foreign_key::contains_size_type i (0); - i != fk.contains_size (); ++i) - { - sema_rel::contains& c (fk.contains_at (i)); - sema_rel::contains& oc (ofk->contains_at (i)); - - if (c.column ().name () != oc.column ().name ()) - diagnose_foreign_key (fk, "id member set"); - } - } - else - { - add_foreign_key& afk (g.new_node (fk, at, g)); - g.new_edge (at, afk, fk.name ()); - } - } - else - { - if (other.find (fk.name ()) == 0) - { - drop_foreign_key& dfk (g.new_node (fk.id ())); - g.new_edge (at, dfk, fk.name ()); - } - } - } - - virtual void - traverse (sema_rel::index& i) - { - using sema_rel::index; - - if (mode == mode_add) - { - if (index* oi = other.find (i.name ())) - { - if (i.type () != oi->type ()) - diagnose_index (i, "type", oi->type (), i.type ()); - - if (i.method () != oi->method ()) - diagnose_index (i, "method", oi->method (), i.method ()); - - if (i.options () != oi->options ()) - diagnose_index (i, "options", oi->options (), i.options ()); - - if (i.contains_size () != oi->contains_size ()) - diagnose_index (i, "member set", "", ""); - - for (index::contains_size_type j (0); - j != i.contains_size (); ++j) - { - sema_rel::contains& c (i.contains_at (j)); - sema_rel::contains& oc (oi->contains_at (j)); - - if (c.column ().name () != oc.column ().name ()) - diagnose_index (i, "member set", "", ""); - - if (c.options () != oc.options ()) - diagnose_index ( - i, "member options", oc.options (), c.options ()); - } - } - else - { - add_index& ai (g.new_node (i, at, g)); - g.new_edge (at, ai, i.name ()); - } - } - else - { - if (other.find (i.name ()) == 0) - { - drop_index& di (g.new_node (i.id ())); - g.new_edge (at, di, i.name ()); - } - } - } - - void - diagnose_column (sema_rel::column& c, - char const* name, - string const& ov, - string const& nv) - { - table& t (c.table ()); - location const& tl (t.get ("cxx-location")); - location const& cl (c.get ("cxx-location")); - - error (cl) << "change to data member results in the change of " << - "the corresponding column " << name; - - if (!ov.empty () || !nv.empty ()) - cerr << " (old: '" << ov << "', new: '" << nv << "')"; - - cerr << endl; - - error (cl) << "this change is not yet handled automatically" << endl; - info (cl) << "corresponding column '" << c.name () << "' " << - "originates here" << endl; - info (tl) << "corresponding table '" << t.name () << "' " << - "originates here" << endl; - info (cl) << "consider re-implementing this change by adding " << - "a new data member with the desired " << name << ", migrating " << - "the data, and deleting the old data member" << endl; - - throw operation_failed (); - } - - void - diagnose_primary_key (sema_rel::primary_key& pk, char const* name) - { - location const& l (pk.get ("cxx-location")); - - error (l) << "changing object id " << name << " in an existing " << - "class is not supported" << endl; - info (l) << "consider re-implementing this change by adding " << - "a new class with the desired object id " << name << ", " << - "migrating the data, and deleteing the old class" << endl; - - throw operation_failed (); - } - - void - diagnose_foreign_key (sema_rel::foreign_key& fk, char const* name) - { - // This can be an object pointer or a polymorphic base link. - // The latter will trigger this call if we change one base - // to another. - // - using sema_rel::table; - using sema_rel::foreign_key; - - // Polymorphic base link is the first foreign key. - // - table& t (fk.table ()); - table::names_iterator p (t.find (fk.name ())); - - if (t.extra ()["kind"] == "polymorphic derived object" && - (p == t.names_begin () || !(--p)->is_a ())) - { - location const& l (t.get ("cxx-location")); - - if (name == string ("pointed-to class")) - { - error (l) << "changing polymorphic base is not " << - "supported" << endl; - info (l) << "consider re-implementing this change by adding " << - "a new derived class with the desired base, migrating the " << - "data, and deleteing the old class" << endl; - } - else - { - error (l) << "changing polymorphic base " << name << - " is not supported" << endl; - info (l) << "consider re-implementing this change by adding " << - "a new derived class with the desired " << name << ", " << - "migrating the data, and deleteing the old class" << endl; - } - } - else - { - location const& l (fk.get ("cxx-location")); - - error (l) << "changing object pointer " << name << " is not " << - "supported" << endl; - info (l) << "consider re-implementing this change by adding " << - "a new object pointer with the desired " << name << ", " << - "migrating the data, and deleteing the old pointer" << endl; - } - - throw operation_failed (); - } - - void - diagnose_index (sema_rel::index& i, - char const* name, - string const& ov, - string const& nv) - { - table& t (i.table ()); - location const& tl (t.get ("cxx-location")); - location const& il (i.get ("cxx-location")); - - error (il) << "change to index " << name; - - if (!ov.empty () || !nv.empty ()) - cerr << " (old: '" << ov << "', new: '" << nv << "')"; - - cerr << " is not yet handled automatically" << endl; - - info (il) << "corresponding index '" << i.name () << "' " << - "originates here" << endl; - info (tl) << "corresponding table '" << t.name () << "' " << - "originates here" << endl; - info (il) << "consider re-implementing this change by adding " << - "a new index with the desired " << name << " and deleting the " << - "old one" << endl; - - throw operation_failed (); - } - - protected: - table& other; - mode_type mode; - alter_table& at; - graph& g; - options const& ops; - model_version const* version; - }; - - struct diff_model: trav_rel::table - { - enum mode_type {mode_add, mode_drop}; - - diff_model (model& o, - mode_type m, - changeset& s, - graph& gr, - string const& in, - options const& op, - model_version const* v) - : other (o), - mode (m), - cs (s), - g (gr), - in_name (in), - ops (op), - version (v) {} - - virtual void - traverse (sema_rel::table& t) - { - using sema_rel::table; - - if (mode == mode_add) - { - if (table* ot = other.find (t.name ())) - { - // See if there are any changes to the table. - // - alter_table& at (g.new_node (t.id ())); - - // Set the alters edge for lookup. - // - table* bt (cs.lookup (t.name ())); - assert (bt != 0); - alters& ae (g.new_edge (at, *bt)); - - if (t.options () != ot->options ()) - diagnose_table (t, "options", ot->options (), t.options ()); - - if (ot->extra ()["kind"] != t.extra ()["kind"]) - diagnose_table (t, "kind", - ot->extra ()["kind"], t.extra ()["kind"]); - - { - trav_rel::table table; - trav_rel::unames names; - diff_table dtable ( - *ot, diff_table::mode_add, at, g, ops, version); - table >> names >> dtable; - table.traverse (t); - } - - { - trav_rel::table table; - trav_rel::unames names; - diff_table dtable ( - t, diff_table::mode_drop, at, g, ops, version); - table >> names >> dtable; - table.traverse (*ot); - } - - if (!at.names_empty ()) - g.new_edge (cs, at, t.name ()); - else - { - g.delete_edge (at, *bt, ae); - g.delete_node (at); - } - } - else - { - // Soft-add is only applicable to containers. - // - if (version != 0 && t.count ("member-path")) - { - data_member_path const& mp ( - t.get ("member-path")); - - // Make sure the addition version is the current version. - // - semantics::data_member* m (context::added_member (mp)); - if (m != 0) - { - if (context::added (*m) != version->current) - { - location l (m->get ("added-location")); - error (l) << "member addition version is not the same " << - "as the current model version" << endl; - throw operation_failed (); - } - } - // Warn about hard additions. If the version is closed, then - // we have already seen these warnings so no need to repeat - // them. - // - else if (ops.warn_hard_add () && version->open) - { - // Issue nicer diagnostics for the direct data member case. - // - if (mp.size () == 1) - { - location l (mp.back ()->location ()); - warn (l) << "data member is hard-added" << endl; - } - else - { - semantics::class_& s ( - dynamic_cast ( - mp.front ()->scope ())); - - warn (s.location ()) << "container table '" << - t.name () << "' in class '" << s.name () << "' is " << - "hard-added" << endl; - - for (data_member_path::const_iterator i (mp.begin ()); - i != mp.end (); ++i) - { - info ((*i)->location ()) << "corresponding hard-" << - "added data member could be '" << (*i)->name () << - "'" << endl; - } - } - } - } - - add_table& at (g.new_node (t, cs, g)); - g.new_edge (cs, at, t.name ()); - } - } - else - { - if (other.find
(t.name ()) == 0) - { - if (version != 0) - { - // See if we have an entry for this table in the soft- - // deleted map. - // - deleted_table_map const& dm ( - other.get ("deleted-map")); - deleted_table_map::const_iterator i (dm.find (t.name ())); - - if (i != dm.end ()) - { - // This table could be derived either from a class (object) - // or data member (container). - // - semantics::class_* c ( - dynamic_cast (i->second)); - if (c != 0 && context::deleted (*c) != version->current) - { - location l (c->get ("deleted-location")); - error (l) << "class deletion version is not the same " << - "as the current model version" << endl; - throw operation_failed (); - } - - semantics::data_member* m ( - dynamic_cast (i->second)); - if (m != 0 && context::deleted (*m) != version->current) - { - location l (m->get ("deleted-location")); - error (l) << "member deletion version is not the same " << - "as the current model version" << endl; - throw operation_failed (); - } - } - // Warn about hard deletions. If the version is closed, then - // we have already seen these warnings so no need to repeat - // them. - // - // At first, it may seem like a good idea not to warn about - // class deletions since it is not possible to do anything - // useful with a class without referencing it from the code - // (in C++ sense). However, things get tricky once we consider - // polymorphism since the migration code could be "working" - // with the hard-deleted derived class via its base. So we - // are going to warn about polymorphic derived tables. - // - else if (ops.warn_hard_delete () && version->open) - { - string k (t.extra ()["kind"]); - - // We don't have any sensible location. - // - if (k == "container") - { - // We will issue a useless warning if the object table - // that this container references is also deleted. - // While we could detect this, it is going to require - // some effort since we would have to delay the warning - // and check later once we know all the deleted tables. - // - cerr << in_name << ": warning: container table '" << - t.name () << "' is hard-deleted" << endl; - } - else if (k == "polymorphic derived object") - { - // The same as above: the warning will be useless if - // we are dropping the whole hierarchy. - // - cerr << in_name << ": warning: polymorphic derived " << - "object table '" << t.name () << "' is hard-deleted" << - endl; - } - } - } - - drop_table& dt (g.new_node (t.id ())); - g.new_edge (cs, dt, t.name ()); - } - } - } - - void - diagnose_table (sema_rel::table& t, - char const* name, - string const& ov, - string const& nv) - { - location const& tl (t.get ("cxx-location")); - - error (tl) << "change to object or container member results in " - "the change of the corresponding table " << name; - - if (!ov.empty () || !nv.empty ()) - cerr << " (old: '" << ov << "', new: '" << nv << "')"; - - cerr << endl; - - error (tl) << "this change is not yet handled automatically" << endl; - info (tl) << "consider re-implementing this change by adding a " << - "new object or container member with the desired " << name << - ", migrating the data, and deleting the old object or member" << - endl; - - throw operation_failed (); - } - - protected: - model& other; - mode_type mode; - changeset& cs; - graph& g; - string in_name; - options const& ops; - model_version const* version; - }; - - // Assumes the new model has cxx-location set. If version is not 0, - // then assume it is the current model version and the new model is - // the current model which has member paths and deleted maps set. - // - changeset& - diff (model& o, - model& n, - changelog& l, - string const& in_name, - options const& ops, - model_version const* version) - { - changeset& r (l.new_node (n.version ())); - - // Set the alters edge for lookup. If we are diff'ing two models of - // the same version, then use the old model as a base. Otherwise use - // the tip of changelog (it should correspond to the old model). - // - if (o.version () == n.version ()) - l.new_edge (r, o); - else - { - if (l.contains_changeset_empty ()) - { - model& m (l.model ()); - - // The changelog model version may also be equal to the new model - // version if the new base model version is greater than the - // latest changeset. - // - assert (m.version () == o.version () || - m.version () == n.version ()); - - l.new_edge (r, m); - } - else - { - changeset& c (l.contains_changeset_back ().changeset ()); - assert (o.version () == c.version ()); - l.new_edge (r, c); - } - } - - { - trav_rel::model model; - trav_rel::qnames names; - diff_model dmodel ( - o, diff_model::mode_add, r, l, in_name, ops, version); - model >> names >> dmodel; - model.traverse (n); - } - - { - trav_rel::model model; - trav_rel::qnames names; - diff_model dmodel ( - n, diff_model::mode_drop, r, l, in_name, ops, version); - model >> names >> dmodel; - model.traverse (o); - } - - return r; - } - - // - // patch - // - - struct patch_table: trav_rel::add_column, - trav_rel::drop_column, - trav_rel::alter_column, - trav_rel::add_index, - trav_rel::drop_index, - trav_rel::add_foreign_key, - trav_rel::drop_foreign_key - { - patch_table (table& tl, graph& gr): t (tl), g (gr) {} - - virtual void - traverse (sema_rel::add_column& ac) - { - try - { - column& c (g.new_node (ac, t, g)); - g.new_edge (t, c, ac.name ()); - } - catch (duplicate_name const&) - { - cerr << "error: invalid changelog: column '" << ac.name () << - "' already exists in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - } - - virtual void - traverse (sema_rel::drop_column& dc) - { - table::names_iterator i (t.find (dc.name ())); - - if (i == t.names_end () || !i->nameable ().is_a ()) - { - cerr << "error: invalid changelog: column '" << dc.name () << - "' does not exist in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - - g.delete_edge (t, i->nameable (), *i); - } - - virtual void - traverse (sema_rel::alter_column& ac) - { - if (column* c = t.find (ac.name ())) - { - if (ac.null_altered ()) - c->null (ac.null ()); - } - else - { - cerr << "error: invalid changelog: column '" << ac.name () << - "' does not exist in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - } - - virtual void - traverse (sema_rel::add_index& ai) - { - using sema_rel::index; - - try - { - index& i (g.new_node (ai, t, g)); - g.new_edge (t, i, ai.name ()); - } - catch (duplicate_name const&) - { - cerr << "error: invalid changelog: index '" << ai.name () << - "' already exists in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - } - - virtual void - traverse (sema_rel::drop_index& di) - { - using sema_rel::index; - table::names_iterator i (t.find (di.name ())); - - if (i == t.names_end () || !i->nameable ().is_a ()) - { - cerr << "error: invalid changelog: index '" << di.name () << - "' does not exist in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - - g.delete_edge (t, i->nameable (), *i); - } - - virtual void - traverse (sema_rel::add_foreign_key& afk) - { - using sema_rel::foreign_key; - - try - { - foreign_key& fk (g.new_node (afk, t, g)); - g.new_edge (t, fk, afk.name ()); - } - catch (duplicate_name const&) - { - cerr << "error: invalid changelog: foreign key '" << afk.name () << - "' already exists in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - } - - virtual void - traverse (sema_rel::drop_foreign_key& dfk) - { - using sema_rel::foreign_key; - table::names_iterator i (t.find (dfk.name ())); - - if (i == t.names_end () || !i->nameable ().is_a ()) - { - cerr << "error: invalid changelog: foreign key '" << dfk.name () << - "' does not exist in table '" << t.name () << "'" << endl; - throw operation_failed (); - } - - g.delete_edge (t, i->nameable (), *i); - } - - protected: - table& t; - graph& g; - }; - - struct patch_model: trav_rel::add_table, - trav_rel::drop_table, - trav_rel::alter_table - { - patch_model (model& ml, graph& gr): m (ml), g (gr) {} - - virtual void - traverse (sema_rel::add_table& at) - { - try - { - table& t (g.new_node
(at, m, g)); - g.new_edge (m, t, at.name ()); - } - catch (duplicate_name const&) - { - cerr << "error: invalid changelog: table '" << at.name () << - "' already exists in model version " << m.version () << endl; - throw operation_failed (); - } - } - - virtual void - traverse (sema_rel::drop_table& dt) - { - model::names_iterator i (m.find (dt.name ())); - - if (i == m.names_end () || !i->nameable ().is_a
()) - { - cerr << "error: invalid changelog: table '" << dt.name () << - "' does not exist in model version " << m.version () << endl; - throw operation_failed (); - } - - g.delete_edge (m, i->nameable (), *i); - } - - virtual void - traverse (sema_rel::alter_table& at) - { - if (table* t = m.find
(at.name ())) - { - trav_rel::alter_table atable; - trav_rel::unames names; - patch_table ptable (*t, g); - atable >> names >> ptable; - atable.traverse (at); - } - else - { - cerr << "error: invalid changelog: table '" << at.name () << - "' does not exist in model version " << m.version () << endl; - throw operation_failed (); - } - } - - protected: - model& m; - graph& g; - }; - - model& - patch (model& m, changeset& c, graph& g) - { - model& r (g.new_node (m, g)); - - trav_rel::changeset changeset; - trav_rel::qnames names; - patch_model pmodel (r, g); - changeset >> names >> pmodel; - changeset.traverse (c); - - r.version (c.version ()); - return r; - } - } - - cutl::shared_ptr - generate (model& m, - model_version const& mv, - changelog* old, - string const& in_name, - string const& out_name, - options const& ops) - { - database db (ops.database ()[0]); - cutl::shared_ptr cl ( - new (shared) changelog (db.string (), ops.schema_name ()[db])); - graph& g (*cl); - - if (old == 0) - { - // Don't allow changelog initialization if the version is closed. - // This will prevent adding new files to an existing object model - // with a closed version. - // - if (!mv.open) - { - cerr << out_name << ": error: unable to initialize changelog " << - "because current version is closed" << endl; - throw operation_failed (); - } - - if (!ops.init_changelog ()) - cerr << out_name << ": info: initializing changelog with base " << - "version " << mv.base << endl; - - if (mv.base == mv.current) - g.new_edge (*cl, g.new_node (m, g)); - else - { - // In this case we have to create an empty model at the base - // version and a changeset. We do it this way instead of putting - // everything into the base model in order to support adding new - // header files to the project. - // - cerr << out_name << ": warning: base and current versions " << - "differ; assuming base model is empty" << endl; - - model& nm (g.new_node (mv.base)); - g.new_edge (*cl, nm); - changeset& c (diff (nm, m, *cl, in_name, ops, &mv)); - - if (!c.names_empty ()) - { - g.new_edge (c, nm); - g.new_edge (*cl, c); - } - } - - return cl; - } - - // Get the changelog base and current versions and do some sanity - // checks. - // - version bver (old->model ().version ()); - version cver ( - old->contains_changeset_empty () - ? bver - : old->contains_changeset_back ().changeset ().version ()); - - if (mv.base < bver) - { - cerr << in_name << ": error: latest changelog base version is " << - "greater than model base version" << endl; - throw operation_failed (); - } - - if (mv.current < cver) - { - cerr << in_name << ": error: latest changelog current version is " << - "greater than model current version" << endl; - throw operation_failed (); - } - - // Build the new changelog. - // - model& oldm (old->model ()); - - // Now we have a case with a "real" old model (i.e., non-empty - // and with version older than current) as well as zero or more - // changeset. - // - // - model* last (&g.new_node (oldm, g)); - model* base (bver == mv.base && mv.base != mv.current ? last : 0); - if (base != 0) - g.new_edge (*cl, *base); - - for (changelog::contains_changeset_iterator i ( - old->contains_changeset_begin ()); - i != old->contains_changeset_end (); ++i) - { - changeset& cs (i->changeset ()); - - // Don't copy the changeset for the current version. Instead, we - // will re-create it from scratch. - // - if (cs.version () == mv.current) - break; - - model& prev (*last); - last = &patch (prev, cs, g); - - if (base == 0) - { - if (last->version () == mv.base) - { - base = last; - g.new_edge (*cl, *base); - } - else if (last->version () > mv.base) - { - // We have a gap. Plug it with an empty base model. We will - // also need to create a new changeset for this step. - // - base = &g.new_node (mv.base); - g.new_edge (*cl, *base); - - changeset& c (diff (*base, *last, *cl, in_name, ops, 0)); - if (!c.names_empty ()) - { - g.new_edge (c, *base); - g.new_edge (*cl, c); - } - - continue; - } - } - - // Copy the changeset unless it is below or at our base version. - // - if (last->version () <= mv.base) - continue; - - changeset& c ( - g.new_node ( - cs, - cl->contains_changeset_empty () - ? static_cast (*base) // Cannot be NULL. - : cl->contains_changeset_back ().changeset (), - g)); - - g.new_edge (c, prev); - g.new_edge (*cl, c); - } - - // If we still haven't found the new base model, then it means it - // has version greater than any changeset we have seen. - // - if (base == 0) - { - if (mv.base == mv.current) - base = &g.new_node (m, g); - else - { - // Fast-forward the latest model to the new base. - // - base = last; - base->version (mv.base); - } - - g.new_edge (*cl, *base); - } - - // If the current version is closed, make sure the model hasn't - // changed. - // - if (!mv.open) - { - // If the last changeset has the current version, then apply it. - // - model* om (last); - if (!old->contains_changeset_empty ()) - { - changeset& c (old->contains_changeset_back ().changeset ()); - if (c.version () == mv.current) - om = &patch (*last, c, g); - } - - changeset& c (diff (*om, m, *cl, in_name, ops, &mv)); - - if (!c.names_empty ()) - { - qnames& n (*c.names_begin ()); - - cerr << out_name << ": error: current version is closed" << endl; - cerr << out_name << ": info: first new change is " << - n.nameable ().kind () << " '" << n.name () << "'" << endl; - - throw operation_failed (); - } - } - - // Add a changeset for the current version unless it is the same - // as the base version. - // - if (mv.base != mv.current) - { - // Add it even if it is empty. This can be useful, for example, - // for data-only migrations were the user relies on the database - // version being updated in the version table. - // - changeset& c (diff (*last, m, *cl, in_name, ops, &mv)); - g.new_edge (c, *last); - g.new_edge (*cl, c); - } - - return cl; - } - } -} diff --git a/odb/relational/common-query.cxx b/odb/relational/common-query.cxx deleted file mode 100644 index 53321ce..0000000 --- a/odb/relational/common-query.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// file : odb/relational/common-query.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -using namespace std; - -namespace relational -{ - // query_alias_traits - // - - void query_alias_traits:: - generate_decl_body () - { - os << "static const char table_name[];"; - } - - void query_alias_traits:: - generate_def (semantics::data_member& m, semantics::class_& c) - { - // Come up with a table alias. Generally, we want it to be based - // on the column name. This is straightforward for single-column - // references. In case of a composite id, we will need to use the - // column prefix which is based on the data member name, unless - // overridden by the user. In the latter case the prefix can be - // empty, in which case we will just fall back on the member's - // public name. - // - string alias; - { - string n; - - if (composite_wrapper (utype (*id_member (c)))) - { - n = column_prefix (m, key_prefix_, default_name_).prefix; - - if (n.empty ()) - n = public_name_db (m); - else if (n[n.size () - 1] == '_') - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - { - bool dummy; - n = column_name (m, key_prefix_, default_name_, dummy); - } - - alias = column_prefix_.prefix + n; - } - - generate_def (public_name (m), c, alias); - } - - void query_alias_traits:: - generate_def (string const& tag, semantics::class_& c, string const& alias) - { - semantics::class_* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - semantics::class_* poly_base (poly_derived ? &polymorphic_base (c) : 0); - - if (poly_derived) - generate_def (tag, *poly_base, alias); - - os << "const char alias_traits<" - << " " << class_fq_name (c) << "," << endl - << " id_" << db << "," << endl - << " " << scope_ << "::" << tag << "_tag>::" << endl - << "table_name[] = "; - - if (poly_root != 0) - os << strlit (quote_id (alias + "_" + table_name (c).uname ())); - else - os << strlit (quote_id (alias)); - - os << ";" - << endl; - } - - entry query_alias_traits_; - - - // query_columns_base - // - - entry query_columns_base_; - - // query_columns - // - - void query_columns:: - column_ctor (string const& type, string const& name, string const& base) - { - os << name << " ("; - - if (multi_dynamic) - os << "odb::query_column< " << type << " >& qc," << endl; - - os << "const char* t, const char* c, const char* conv)" << endl - << " : " << base << " (" << (multi_dynamic ? "qc, " : "") << - "t, c, conv)" - << "{" - << "}"; - } - - void query_columns:: - column_ctor_args_extra (semantics::data_member&) - { - } - - void query_columns:: - column_common (semantics::data_member& m, - string const& type, - string const& column, - string const& suffix) - { - string name (public_name (m)); - - if (decl_) - { - string type_id (database_type_id (m)); - - os << "// " << name << endl - << "//" << endl; - - os << "typedef" << endl - << db << "::query_column<" << endl - << " " << db << "::value_traits<" << endl - << " " << type << "," << endl - << " " << type_id << " >::query_type," << endl - << " " << type_id << " >" << endl - << name << suffix << ";" - << endl; - } - else - { - // Note that here we don't use suffix. - // - string tmpl (ptr_ ? "pointer_query_columns" : "query_columns"); - tmpl += "< " + fq_name_ + ", id_" + db.string () + ", A >" + scope_; - - os << "template " << endl - << "const typename " << tmpl << "::" << name << "_type_" << endl - << tmpl << "::" << endl - << name << " ("; - - // Pass common query column for registration. - // - if (multi_dynamic) - { - string tmpl (ptr_ ? "pointer_query_columns" : "query_columns"); - tmpl += "< " + fq_name_ + ", id_common, typename A::common_traits >" + - scope_; - - os << tmpl << "::" << name << "," << endl; - } - - os << "A::" << "table_name, " << strlit (quote_id (column)); - - string const& conv (convert_to_expr (column_type (), m)); - os << ", " << (conv.empty () ? "0" : strlit (conv)); - - column_ctor_args_extra (m); - - os << ");" - << endl; - } - } -} diff --git a/odb/relational/common-query.hxx b/odb/relational/common-query.hxx deleted file mode 100644 index c29df6b..0000000 --- a/odb/relational/common-query.hxx +++ /dev/null @@ -1,63 +0,0 @@ -// file : odb/relational/common-query.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_COMMON_QUERY_HXX -#define ODB_RELATIONAL_COMMON_QUERY_HXX - -#include - -namespace relational -{ - // - // - struct query_alias_traits: ::query_alias_traits, virtual context - { - typedef query_alias_traits base_impl; - - query_alias_traits (base const& x): base (x) {} - - virtual void - generate_decl_body (); - - virtual void - generate_def (semantics::data_member&, semantics::class_&); - - virtual void - generate_def (string const& tag, semantics::class_&, string const& alias); - }; - - // - // - struct query_columns_base: ::query_columns_base, virtual context - { - typedef query_columns_base base_impl; - - query_columns_base (base const& x): base (x) {const_ = "const ";} - }; - - // - // - struct query_columns: ::query_columns, virtual context - { - typedef query_columns base_impl; - - query_columns (base const& x): base (x) {const_ = "const ";} - - virtual string - database_type_id (semantics::data_member&) = 0; - - virtual void - column_ctor (string const& type, string const& name, string const& base); - - virtual void - column_ctor_args_extra (semantics::data_member&); - - virtual void - column_common (semantics::data_member&, - string const& type, - string const& column, - string const& suffix); - }; -} - -#endif // ODB_RELATIONAL_COMMON_QUERY_HXX diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx deleted file mode 100644 index 5c9126c..0000000 --- a/odb/relational/common.cxx +++ /dev/null @@ -1,27 +0,0 @@ -// file : odb/relational/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -using namespace std; - -namespace relational -{ - // member_image_type - // - string member_image_type:: - image_type (semantics::data_member&) - { - assert (false); - return string (); - } - - // member_database_type_id - // - string member_database_type_id:: - database_type_id (semantics::data_member&) - { - assert (false); - return string (); - } -} diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx deleted file mode 100644 index 01266a0..0000000 --- a/odb/relational/common.hxx +++ /dev/null @@ -1,273 +0,0 @@ -// file : odb/relational/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_COMMON_HXX -#define ODB_RELATIONAL_COMMON_HXX - -#include -#include - -#include -#include - -namespace relational -{ - struct member_base: traversal::data_member, virtual context - { - typedef member_base base; - - member_base (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix, - object_section* section = 0) - : type_override_ (type), - custom_override_ (ct), - fq_type_override_ (fq_type), - key_prefix_ (key_prefix), - section_ (section), - top_level_ (false) - { - } - - member_base (string const& var, - semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix, - object_section* section = 0) - : var_override_ (var), - type_override_ (type), - custom_override_ (ct), - fq_type_override_ (fq_type), - key_prefix_ (key_prefix), - section_ (section), - top_level_ (false) - { - } - - protected: - // For virtual inheritance only. Should not be actually called. - // - member_base (); - - protected: - string var_override_; - semantics::type* type_override_; - const custom_cxx_type* custom_override_; - string fq_type_override_; - string key_prefix_; - object_section* section_; - - // True during the top-level call of pre() and post() below. Note that - // call via another tarverser (e.g., for a class) is not considered top- - // level. - // - bool top_level_; - }; - - // Template argument is the database SQL type (sql_type). - // - template - struct member_base_impl: virtual member_base - { - typedef member_base_impl base_impl; - - member_base_impl (base const& x): base (x) {} - - protected: - member_base_impl () {} - - public: - virtual T const& - member_sql_type (semantics::data_member&) = 0; - - void - traverse (semantics::data_member& m, bool top_level) - { - top_level_ = top_level; - traverse (m); - top_level_ = false; - } - - struct member_info - { - semantics::data_member& m; // Member. - semantics::type& t; // Cvr-unqualified member C++ type, note - // that m.type () may not be the same as t. - const custom_cxx_type* ct; // Translation used for t, if any. - semantics::class_* ptr; // Pointed-to object if m is an object - // pointer. In this case t is the id type - // while fq_type_ is the pointer fq-type. - semantics::type* wrapper; // Wrapper type if member is a composite or - // container wrapper, also cvr-unqualified. - // In this case t is the wrapped type. - bool cq; // True if the original (wrapper) type - // is const-qualified. - T const* st; // Member SQL type (only simple values). - string& var; // Member variable name with trailing '_'. - - // C++ type fq-name. - // - string - fq_type (bool unwrap = true) const - { - semantics::names* hint; - - if (wrapper != 0 && unwrap) - { - // Use the hint from the wrapper unless the wrapped type - // is qualified. - // - hint = wrapper->get ("wrapper-hint"); - utype (*context::wrapper (*wrapper), hint); - return t.fq_name (hint); - } - - // Use the original type from 'm' instead of 't' since the hint may - // be invalid for a different type. Plus, if a type is overriden, - // then the fq_type must be as well. - // - if (ptr != 0) - { - semantics::type& t (utype (*id_member (*ptr), hint)); - return t.fq_name (hint); - } - else if (fq_type_.empty ()) - { - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - // If we are translated, then fq_type_ contains the original type. - // - return ct == 0 ? fq_type_ : t.fq_name (ct->as_hint); - } - - string - ptr_fq_type () const - { - assert (ptr != 0); - - if (fq_type_.empty ()) - { - // If type is overridden so should fq_type so it is safe to - // get the type from the member. - // - semantics::names* hint; - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - return fq_type_; - } - - string const& fq_type_; - - member_info (semantics::data_member& m_, - semantics::type& t_, - const custom_cxx_type* ct_, - semantics::type* wrapper_, - bool cq_, - string& var_, - string const& fq_type) - : m (m_), - t (t_), - ct (ct_), - ptr (0), - wrapper (wrapper_), - cq (cq_), - st (0), - var (var_), - fq_type_ (fq_type) - { - } - }; - - bool - container (member_info& mi) - { - // This cannot be a container if we have a type override. - // - return type_override_ == 0 && context::container (mi.m); - } - - // The false return value indicates that no further callbacks should be - // called for this member. - // - virtual bool - pre (member_info&) {return true;} - - virtual void - post (member_info&) {} - - // Note: calling these directly will mess up the top_level logic. - // - protected: - virtual void - traverse_composite (member_info&) {} - - virtual void - traverse_container (member_info&) {} - - // Note that by default traverse_pointer() will traverse the - // pointed-to object id type. - // - virtual void - traverse_pointer (member_info&); - - virtual void - traverse_simple (member_info&) {} - - private: - virtual void - traverse (semantics::data_member&); - }; - - // - // - struct member_image_type: virtual member_base - { - typedef member_image_type base; - - member_image_type (): member_base (0, 0, string (), string ()) {} - - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type = string (), - string const& key_prefix = string ()) - : member_base (type, ct, fq_type, key_prefix) {} - - // Has to be overriden. - // - virtual string - image_type (semantics::data_member&); - }; - - // - // - struct member_database_type_id: virtual member_base - { - typedef member_database_type_id base; - - member_database_type_id (): member_base (0, 0, string (), string ()) {} - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type = string (), - string const& key_prefix = string ()) - : member_base (type, ct, fq_type, key_prefix) {} - - // Has to be overriden. - // - virtual string - database_type_id (semantics::data_member&); - }; -} - -#include - -// Other common parts. -// -#include - -#endif // ODB_RELATIONAL_COMMON_HXX diff --git a/odb/relational/common.txx b/odb/relational/common.txx deleted file mode 100644 index 82a4a4a..0000000 --- a/odb/relational/common.txx +++ /dev/null @@ -1,125 +0,0 @@ -// file : odb/relational/common.txx -// license : GNU GPL v3; see accompanying LICENSE file - -namespace relational -{ - // - // member_base_impl - // - - template - void member_base_impl:: - traverse (semantics::data_member& m) - { - if (transient (m)) - return; - - string var; - - if (!var_override_.empty ()) - var = var_override_; - else - { - string const& name (m.name ()); - var = name + (name[name.size () - 1] == '_' ? "" : "_"); - } - - bool cq (type_override_ != 0 ? false : const_member (m)); - const custom_cxx_type* ct (type_override_ != 0 ? custom_override_ : 0); - semantics::type& t (type_override_ != 0 - ? *type_override_ - : utype (m, &ct)); - - semantics::type* cont; - if (semantics::class_* c = object_pointer (t)) - { - // A pointer in view might point to an object without id. - // - data_member_path* id (id_member (*c)); - semantics::type& t (id != 0 ? utype (*id, &ct) : utype (m, &ct)); - semantics::class_* comp (id != 0 ? composite_wrapper (t) : 0); - - member_info mi (m, - (comp != 0 ? *comp : t), - ct, - (comp != 0 && wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); // Pointer type. - - mi.ptr = c; - - // Pointer in views aren't really a "column". - // - if (!view_member (m) && comp == 0) - mi.st = &member_sql_type (m); - - if (pre (mi)) - { - traverse_pointer (mi); - post (mi); - } - } - else if (semantics::class_* c = composite_wrapper (t)) - { - // If t is a wrapper, pass the wrapped type. Also pass the - // original, wrapper type. - // - member_info mi (m, - *c, - ct, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_composite (mi); - post (mi); - } - } - // This cannot be a container if we have a type override. - // - else if (type_override_ == 0 && (cont = context::container (m))) - { - // The same unwrapping logic as for composite values. - // - member_info mi (m, - *cont, - 0, // Cannot be mapped. - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_container (mi); - post (mi); - } - } - else - { - member_info mi (m, t, ct, 0, cq, var, fq_type_override_); - mi.st = &member_sql_type (m); - - if (pre (mi)) - { - traverse_simple (mi); - post (mi); - } - } - } - - template - void member_base_impl:: - traverse_pointer (member_info& mi) - { - if (!view_member (mi.m)) // Not really "as if" pointed-to id member. - { - if (composite (mi.t)) // Already unwrapped. - traverse_composite (mi); - else - traverse_simple (mi); - } - } -} diff --git a/odb/relational/context.cxx b/odb/relational/context.cxx deleted file mode 100644 index 3fba69b..0000000 --- a/odb/relational/context.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// file : odb/relational/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace relational -{ - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context () - : data_ (current ().data_), - model (current ().model), - generate_grow (current ().generate_grow), - need_alias_as (current ().need_alias_as), - insert_send_auto_id (current ().insert_send_auto_id), - delay_freeing_statement_result (current ().delay_freeing_statement_result), - need_image_clone (current ().need_image_clone), - generate_bulk (current ().generate_bulk), - global_index (current ().global_index), - global_fkey (current ().global_fkey), - bind_vector (data_->bind_vector_), - truncated_vector (data_->truncated_vector_) - { - } - - context:: - context (data* d, sema_rel::model* m) - : data_ (d), - model (m), - bind_vector (data_->bind_vector_), - truncated_vector (data_->truncated_vector_) - { - assert (current_ == 0); - current_ = this; - } - - string context:: - index_name (qname const& table, string const& base) - { - string n; - - if (options.index_suffix ().count (db) != 0) - n = base + options.index_suffix ()[db]; - else - n = compose_name (base, "i"); - - // If this database has global index names, then add the table - // name as a prefix (the schema, if needed, will be added by - // database-specific create_index overrides). - // - if (global_index) - n = compose_name (table.uname (), n); - - return transform_name (n, sql_name_index); - } - - string context:: - fkey_name (qname const& table, string const& base) - { - string n; - - if (options.fkey_suffix ().count (db) != 0) - n = base + options.fkey_suffix ()[db]; - else - n = compose_name (base, "fk"); - - // If this database has global index names, then add the table - // name as a prefix (the schema, if needed, will be added by - // database-specific create_foreign_key overrides). - // - if (global_fkey) - n = compose_name (table.uname (), n); - - return transform_name (n, sql_name_fkey); - } - - string context:: - convert (string const& e, string const& c) - { - size_t p (c.find ("(?)")); - string r (c, 0, p); - r += e; - r.append (c, p + 3, string::npos); - return r; - } - - string const& context:: - convert_expr (string const&, semantics::data_member&, bool) - { - assert (false); - throw operation_failed (); - } - - bool context:: - grow_impl (semantics::class_&, user_section*) - { - return false; - } - - bool context:: - grow_impl (semantics::data_member&) - { - return false; - } - - bool context:: - grow_impl (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const&) - { - return false; - } - - string context:: - quote_string_impl (string const& s) const - { - string r; - r.reserve (s.size ()); - r += '\''; - - for (string::size_type i (0), n (s.size ()); i < n; ++i) - { - if (s[i] == '\'') - r += "''"; - else - r += s[i]; - } - - r += '\''; - return r; - } - - string context:: - quote_id_impl (qname const& id) const - { - string r; - - bool f (true); - for (qname::iterator i (id.begin ()); i < id.end (); ++i) - { - if (i->empty ()) - continue; - - if (f) - f = false; - else - r += '.'; - - r += '"'; - r += *i; - r += '"'; - } - - return r; - } -} diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx deleted file mode 100644 index db9b5be..0000000 --- a/odb/relational/context.hxx +++ /dev/null @@ -1,289 +0,0 @@ -// file : odb/relational/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_CONTEXT_HXX -#define ODB_RELATIONAL_CONTEXT_HXX - -#include - -#include -#include - -namespace relational -{ - namespace sema_rel = semantics::relational; - namespace trav_rel = traversal::relational; - - enum statement_kind - { - statement_select, - statement_insert, - statement_update, - statement_delete, - statement_where // WHERE clause. - }; - - // Index. - // - struct index - { - location_t loc; // Location of this index definition. - std::string name; // If empty, then derive from the member name. - std::string type; // E.g., "UNIQUE", etc. - std::string method; // E.g., "BTREE", etc. - std::string options; // Database-specific index options. - - struct member - { - location_t loc; // Location of this member specifier. - std::string name; // Member name, e.g., foo_, foo_.bar_. - data_member_path path; // Member path. - std::string options; // Member options, e.g., "ASC", etc. - }; - typedef std::vector members_type; - - members_type members; - }; - - typedef std::vector indexes; - - // Indexes in the above vector are in location order. - // - struct index_comparator - { - bool - operator() (index const& x, index const& y) const - { - return x.loc < y.loc; - } - }; - - // Custom database type mapping. - // - struct custom_db_type - { - regex type; - std::string as; - std::string to; - std::string from; - location_t loc; - }; - - typedef std::vector custom_db_types; - - class context: public virtual ::context - { - public: - // Return true if an object or value type has members for which - // the image can grow. If section is not specified, then ignore - // separately loaded members. Otherwise ignore members that do - // not belong to the section. - // - bool - grow (semantics::class_&, user_section* = 0); - - // The same for a member's value type. - // - bool - grow (semantics::data_member&); - - bool - grow (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const& key_prefix); - - public: - // Quote SQL string. - // - string - quote_string (string const&) const; - - // Quote SQL identifier. - // - string - quote_id (string const&) const; - - string - quote_id (qname const&) const; - - // Quoted column and table names. - // - string - column_qname (semantics::data_member& m, column_prefix const& cp) const - { - return quote_id (column_name (m, cp)); - } - - string - column_qname (data_member_path const& mp) const - { - return quote_id (column_name (mp)); - } - - string - column_qname (semantics::data_member& m, - string const& key_prefix, - string const& default_name, - column_prefix const& cp) const - { - return quote_id (column_name (m, key_prefix, default_name, cp)); - } - - string - table_qname (semantics::class_& c) const - { - return quote_id (table_name (c)); - } - - string - table_qname (semantics::class_& obj, data_member_path const& mp) const - { - return quote_id (table_name (obj, mp)); - } - - string - table_qname (semantics::data_member& m, table_prefix const& p) const - { - return quote_id (table_name (m, p)); - } - - public: - string - index_name (qname const& table, string const& base); - - string - fkey_name (qname const& table, string const& base); - - // Custom database type conversion. - // - public: - string - convert_to (string const& expr, - string const& sqlt, - semantics::data_member& m) - { - string const& conv (current ().convert_expr (sqlt, m, true)); - return conv.empty () ? expr : convert (expr, conv); - } - - string - convert_from (string const& expr, - string const& sqlt, - semantics::data_member& m) - { - string const& conv (current ().convert_expr (sqlt, m, false)); - return conv.empty () ? expr : convert (expr, conv); - } - - // These shortcut versions should only be used on special members - // (e.g., auto id, version, etc) since they may not determine the - // proper SQL type in other cases (prefixes, composite ids, etc). - // - string - convert_to (string const& expr, semantics::data_member& m) - { - return convert_to (expr, column_type (m), m); - } - - string - convert_from (string const& expr, semantics::data_member& m) - { - return convert_from (expr, column_type (m), m); - } - - // Return the conversion expression itself. - // - string const& - convert_to_expr (string const& sqlt, semantics::data_member& m) - { - return current ().convert_expr (sqlt, m, true); - } - - protected: - virtual string const& - convert_expr (string const& sqlt, semantics::data_member&, bool to); - - string - convert (string const& expr, string const& conv); - - protected: - // The default implementation returns false. - // - virtual bool - grow_impl (semantics::class_&, user_section*); - - virtual bool - grow_impl (semantics::data_member&); - - virtual bool - grow_impl (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const&); - - // The default implementation uses the ISO quoting ('') and - // escapes singe quotes inside the string by double-quoting - // (' -> ''). Some (most?) database systems support escape - // sequences. We may want to provide utilize that to support - // things like \n, \t, etc. - // - virtual string - quote_string_impl (string const&) const; - - // The default implementation uses the ISO quoting (""). - // - virtual string - quote_id_impl (qname const&) const; - - public: - virtual - ~context (); - context (); - - static context& - current () - { - return *current_; - } - - protected: - struct data; - typedef context base_context; - - context (data*, sema_rel::model*); - - private: - static context* current_; - - protected: - struct data: root_context::data - { - data (std::ostream& os): root_context::data (os) {} - - string bind_vector_; - string truncated_vector_; - }; - data* data_; - - public: - sema_rel::model* model; - - bool generate_grow; - bool need_alias_as; - bool insert_send_auto_id; - bool delay_freeing_statement_result; - bool need_image_clone; - bool generate_bulk; - - bool global_index; - bool global_fkey; - - string const& bind_vector; - string const& truncated_vector; - }; -} - -#include - -#endif // ODB_RELATIONAL_CONTEXT_HXX diff --git a/odb/relational/context.ixx b/odb/relational/context.ixx deleted file mode 100644 index abf1fb5..0000000 --- a/odb/relational/context.ixx +++ /dev/null @@ -1,44 +0,0 @@ -// file : odb/relational/context.ixx -// license : GNU GPL v3; see accompanying LICENSE file - -namespace relational -{ - inline bool context:: - grow (semantics::class_& c, user_section* s) - { - return current ().grow_impl (c, s); - } - - inline bool context:: - grow (semantics::data_member& m) - { - return current ().grow_impl (m); - } - - inline bool context:: - grow (semantics::data_member& m, - semantics::type& t, - const custom_cxx_type* ct, - string const& kp) - { - return current ().grow_impl (m, t, ct, kp); - } - - inline context::string context:: - quote_string (string const& str) const - { - return current ().quote_string_impl (str); - } - - inline context::string context:: - quote_id (string const& id) const - { - return current ().quote_id_impl (qname (id)); - } - - inline context::string context:: - quote_id (qname const& id) const - { - return current ().quote_id_impl (id); - } -} diff --git a/odb/relational/generate.hxx b/odb/relational/generate.hxx deleted file mode 100644 index e597fb8..0000000 --- a/odb/relational/generate.hxx +++ /dev/null @@ -1,81 +0,0 @@ -// file : odb/relational/generate.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_GENERATE_HXX -#define ODB_RELATIONAL_GENERATE_HXX - -#include -#include - -#include -#include -#include -#include - -namespace relational -{ - namespace header - { - void - generate (); - } - - namespace inline_ - { - void - generate (); - } - - namespace source - { - void - generate (); - } - - namespace model - { - cutl::shared_ptr - generate (); - } - - namespace changelog - { - // Returns NULL if the changelog is unchanged. - // - cutl::shared_ptr - generate (semantics::relational::model&, - model_version const&, - semantics::relational::changelog* old, // Can be NULL. - std::string const& in_name, - std::string const& out_name, - options const&); - } - - namespace schema - { - void - generate_prologue (); - - void - generate_epilogue (); - - void - generate_drop (); - - void - generate_create (); - - void - generate_migrate_pre (semantics::relational::changeset&); - - void - generate_migrate_post (semantics::relational::changeset&); - - // Generate embedded schema. - // - void - generate_source (semantics::relational::changelog*); - } -} - -#endif // ODB_RELATIONAL_GENERATE_HXX diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx deleted file mode 100644 index 364d48e..0000000 --- a/odb/relational/header.cxx +++ /dev/null @@ -1,1146 +0,0 @@ -// file : odb/relational/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -using namespace std; - -void relational::header::class1:: -traverse_object (type& c) -{ - using semantics::data_member; - - data_member_path* id (id_member (c)); - data_member* idf (id ? id->front () : 0); - data_member* idb (id ? id->back () : 0); - bool auto_id (id && auto_ (*id)); - bool base_id (id && &idf->scope () != &c); // Comes from base. - - data_member* opt (context::optimistic (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - data_member* discriminator (poly ? context::discriminator (*poly_root) : 0); - - bool abst (abstract (c)); - bool reuse_abst (abst && !poly); - - bool versioned (context::versioned (c)); - - string const& type (class_fq_name (c)); - - // Sections. - // - user_sections& uss (c.get ("user-sections")); - - os << "// " << class_name (c) << endl - << "//" << endl; - - // pointer_query_columns & query_columns - // - if (options.generate_query ()) - { - // If we don't have object pointers, then also generate - // query_columns (in this case pointer_query_columns and - // query_columns are the same and the former inherits from - // the latter). Otherwise we have to postpone query_columns - // generation until the second pass to deal with forward- - // declared objects. - // - if (!has_a (c, test_pointer | include_base)) - query_columns_type_->traverse (c); - - pointer_query_columns_type_->traverse (c); - } - - // object_traits_impl - // - os << "template <>" << endl - << "class " << exp << "access::object_traits_impl< " << type << ", " << - "id_" << db << " >:" << endl - << " public access::object_traits< " << type << " >" - << "{" - << "public:" << endl; - - object_public_extra_pre (c); - - // For dynamic multi-database support also generate common traits - // alias (used in query aliasing). - // - if (options.generate_query () && multi_dynamic) - { - os << "typedef access::object_traits_impl< " << type << ", " << - "id_common > common_traits;" - << endl; - } - - // Polymorphic root_traits, base_traits, and discriminator_image_type. - // - if (poly) - { - if (!abst) - os << "typedef polymorphic_entry entry_type;"; - - os << "typedef object_traits_impl " << - "root_traits;"; - - if (poly_derived) - { - os << "typedef object_traits_impl " << - "base_traits;" - << endl; - } - else - { - os << endl - << "struct discriminator_image_type" - << "{"; - - discriminator_image_member_->traverse (*discriminator); - - if (opt != 0) - version_image_member_->traverse (*opt); - - os << "std::size_t version;" - << "};"; - } - } - - // id_image_type - // - if (id != 0) - { - if (base_id) - { - if (poly_derived) - os << "typedef root_traits::id_image_type id_image_type;" - << endl; - else - { - semantics::class_& b ( - dynamic_cast (idf->scope ())); - - os << "typedef object_traits_impl< " << class_fq_name (b) << ", " << - "id_" << db << " >::id_image_type id_image_type;" - << endl; - } - } - else - { - os << "struct id_image_type" - << "{"; - - id_image_member_->traverse (*idb); - - if (opt != 0) - version_image_member_->traverse (*opt); - - os << "std::size_t version;" - << "};"; - } - } - - // Polymorphic map. - // - if (poly) - { - if (!poly_derived) - os << "static map_type* map;"; - - os << "static const " << (abst ? "abstract_" : "") << "info_type info;" - << endl; - } - - // image_type - // - image_type_->traverse (c); - - // Extra (container, section) statement cache (forward declaration). - // - if (!reuse_abst && id != 0) - os << "struct extra_statement_cache_type;" - << endl; - - // - // Containers (abstract and concrete). - // - - { - instance t (c); - t->traverse (c); - } - - // - // Sections (abstract and concrete). - // - - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - instance t (c); - t->traverse (*i); - } - - // - // Query (abstract and concrete). - // - - if (options.generate_query ()) - { - // Generate object pointer tags here unless we are generating dynamic - // multi-database support, in which case they generated in object_traits. - // - if (!multi_dynamic && has_a (c, test_pointer | exclude_base)) - { - query_tags t; // Not customizable. - t.traverse (c); - } - } - - // - // Functions (abstract and concrete). - // - - if (id != 0 || !reuse_abst) - os << "using object_traits::id;" - << endl; - - if (opt != 0) - os << "using object_traits::version;" - << endl; - - if (!poly_derived && id != 0) - { - if (auto_id) - os << "static id_type" << endl - << "id (const id_image_type&);" - << endl; - - if (options.generate_query ()) - os << "static id_type" << endl - << "id (const image_type&);" - << endl; - - if (opt != 0) - os << "static version_type" << endl - << "version (const image_type&);" - << endl; - } - - // discriminator() - // - if (poly && !poly_derived) - os << "static discriminator_type" << endl - << "discriminator (const image_type&);" - << endl; - - // grow () - // - if (generate_grow) - { - // For derived classes in a polymorphic hierarchy, grow() will - // check bases up to the specified depth. If one of the base - // images has grown, then it will increment its version. But - // the return value only indicates the state of this image, - // excluding polymorphic bases (in other words, it is possible - // that one of the bases has grown but this function returns - // false). - // - os << "static bool" << endl - << "grow (image_type&," << endl - << truncated_vector; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - if (poly_derived) - os << "," << endl - << "std::size_t = depth"; - - os << ");" - << endl; - } - - // bind (image_type) - // - os << "static void" << endl - << "bind (" << bind_vector << "," << endl; - - // If we are a derived type in a polymorphic hierarchy, then - // we get the the external id binding. - // - if (poly_derived) - os << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl; - - os << "image_type&," << endl - << db << "::statement_kind"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // bind (id_image_type) - // - if (id != 0) - { - os << "static void" << endl - << "bind (" << bind_vector << ", id_image_type&" << - (opt != 0 ? ", bool bind_version = true" : "") << ");" - << endl; - } - - // init (image, object) - // - os << "static " << (generate_grow ? "bool" : "void") << endl - << "init (image_type&," << endl - << "const object_type&," << endl - << db << "::statement_kind"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // init (object, image) - // - os << "static void" << endl - << "init (object_type&," << endl - << "const image_type&," << endl - << "database*"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - if (poly_derived) - os << "," << endl - << "std::size_t = depth"; - - os << ");" - << endl; - - // init (id_image, id) - // - if (id != 0) - { - os << "static void" << endl - << "init (id_image_type&, const id_type&" << - (opt != 0 ? ", const version_type* = 0" : "") << ");" - << endl; - } - - if (poly_derived) - { - // check_version - // - os << "static bool" << endl - << "check_version (const std::size_t*, const image_type&);" - << endl; - - // update_version - // - os << "static void" << endl - << "update_version (std::size_t*, const image_type&, " << - db << "::binding*);" - << endl; - } - - // The rest does not apply to reuse-abstract objects. - // - if (reuse_abst) - { - object_public_extra_post (c); - os << "};"; - return; - } - - column_count_type const& cc (column_count (c)); - - // Statements typedefs. - // - if (poly) - { - if (poly_derived) - os << "typedef" << endl - << db << "::polymorphic_derived_object_statements" << - "" << endl - << "statements_type;" - << endl - << "typedef" << endl - << db << "::polymorphic_root_object_statements" << endl - << "root_statements_type;" - << endl; - else - os << "typedef" << endl - << db << "::polymorphic_root_object_statements" << endl - << "statements_type;" - << endl - << "typedef statements_type root_statements_type;" - << endl; - } - else - { - if (id != 0) - os << "typedef " << db << "::object_statements " << - "statements_type;" - << endl; - else - os << "typedef " << db << "::no_id_object_statements " << - "statements_type;" - << endl; - } - - // - // Query (concrete). - // - - if (options.generate_query ()) - { - // query_base_type - // - os << "typedef " << db << "::query_base query_base_type;" - << endl; - } - - // - // Containers (concrete). - // - - // - // Sections (concrete). - // - - // column_count - // - os << "static const std::size_t column_count = " << cc.total << "UL;" - << "static const std::size_t id_column_count = " << cc.id << "UL;" - << "static const std::size_t inverse_column_count = " << - cc.inverse << "UL;" - << "static const std::size_t readonly_column_count = " << - cc.readonly << "UL;" - << "static const std::size_t managed_optimistic_column_count = " << - cc.optimistic_managed << "UL;"; - - if (poly && !poly_derived) - os << "static const std::size_t discriminator_column_count = " << - cc.discriminator << "UL;"; - - os << endl - << "static const std::size_t separate_load_column_count = " << - cc.separate_load << "UL;" - << "static const std::size_t separate_update_column_count = " << - cc.separate_update << "UL;" - << endl; - - os << "static const bool versioned = " << versioned << ";" - << endl; - - // Statements. - // - os << "static const char persist_statement[];"; - - if (id != 0) - { - if (poly_derived) - { - char const* n (abst ? "1" : "depth"); - - os << "static const char* const find_statements[" << n << "];" - << "static const std::size_t find_column_counts[" << n << "];"; - } - else - { - os << "static const char find_statement[];"; - - if (poly) - os << "static const char find_discriminator_statement[];"; - } - - if (cc.total != cc.id + cc.inverse + cc.readonly + cc.separate_update) - os << "static const char update_statement[];"; - - os << "static const char erase_statement[];"; - - if (opt != 0 && !poly_derived) - os << "static const char optimistic_erase_statement[];"; - } - - if (options.generate_query ()) - { - os << "static const char query_statement[];" - << "static const char erase_query_statement[];" - << endl - << "static const char table_name[];"; - } - - os << endl; - - // - // Functions (concrete). - // - - // persist () - // - os << "static void" << endl - << "persist (database&, " << (auto_id ? "" : "const ") << "object_type&"; - - if (poly) - os << ", bool top = true, bool dyn = true"; - - os << ");" - << endl; - - if (c.count ("bulk-persist")) - os << "static void" << endl - << "persist (database&, " << (auto_id ? "" : "const ") << - "object_type**, std::size_t, multiple_exceptions&);" - << endl; - - if (id != 0) - { - // find (id) - // - if (c.default_ctor ()) - os << "static pointer_type" << endl - << "find (database&, const id_type&);" - << endl; - - // find (id, obj) - // - os << "static bool" << endl - << "find (database&, const id_type&, object_type&"; - - if (poly) - os << ", bool dyn = true"; - - os << ");" - << endl; - - // reload () - // - os << "static bool" << endl - << "reload (database&, object_type&"; - - if (poly) - os << ", bool dyn = true"; - - os << ");" - << endl; - - // update () - // - // In case of a polymorphic object, we generate update() even if it is - // readonly since the potentially-readwrite base will rely on it to - // initialize the id image. - // - // - if (!readonly (c) || poly) - { - os << "static void" << endl - << "update (database&, const object_type&"; - - if (poly) - os << ", bool top = true, bool dyn = true"; - - os << ");" - << endl; - - if (c.count ("bulk-update")) - os << "static void" << endl - << "update (database&, const object_type**, std::size_t, " << - "multiple_exceptions&);" - << endl; - } - - // erase () - // - os << "static void" << endl - << "erase (database&, const id_type&"; - - if (poly) - os << ", bool top = true, bool dyn = true"; - - os << ");" - << endl; - - os << "static void" << endl - << "erase (database&, const object_type&"; - - if (poly) - os << ", bool top = true, bool dyn = true"; - - os << ");" - << endl; - - if (c.count ("bulk-erase")) - { - os << "static std::size_t" << endl - << "erase (database&, const id_type**, std::size_t, " << - "multiple_exceptions&);" - << endl; - - os << "static void" << endl - << "erase (database&, const object_type**, std::size_t, " << - "multiple_exceptions&);" - << endl; - } - - // Sections. - // - // We treat all polymorphic sections as (potentially) having something - // to load or to update since we cannot predict what will be added to - // them in overrides. - // - if (uss.count (user_sections::count_total | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) != 0) - os << "static bool" << endl - << "load (connection&, object_type&, section&" << - (poly ? ", const info_type* = 0" : "") << ");" - << endl; - - if (uss.count (user_sections::count_total | - user_sections::count_update | - (poly ? user_sections::count_update_empty : 0)) != 0) - os << "static bool" << endl - << "update (connection&, const object_type&, const section&" << - (poly ? ", const info_type* = 0" : "") << ");" - << endl; - } - - // query () - // - if (options.generate_query ()) - { - if (!options.omit_unprepared ()) - { - os << "static result" << endl - << "query (database&, const query_base_type&);" - << endl; - - if (multi_dynamic) - os << "static result" << endl - << "query (database&, const odb::query_base&);" - << endl; - } - - os << "static unsigned long long" << endl - << "erase_query (database&, const query_base_type&);" - << endl; - - if (multi_dynamic) - os << "static unsigned long long" << endl - << "erase_query (database&, const odb::query_base&);" - << endl; - - if (options.generate_prepared ()) - { - os << "static odb::details::shared_ptr" << endl - << "prepare_query (connection&, const char*, const query_base_type&);" - << endl; - - if (multi_dynamic) - os << "static odb::details::shared_ptr" << endl - << "prepare_query (connection&, const char*, " << - "const odb::query_base&);" - << endl; - - os << "static odb::details::shared_ptr" << endl - << "execute_query (prepared_query_impl&);" - << endl; - } - } - - object_public_extra_post (c); - - // Implementation details. - // - os << "public:" << endl; - - if (id != 0) - { - // Load the object image. - // - os << "static bool" << endl - << "find_ (statements_type&," << endl - << "const id_type*"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - if (poly_derived && !abst) - os << "," << endl - << "std::size_t = depth"; - - os << ");" - << endl; - - // Load the rest of the object (containers, etc). Expects the id - // image in the object statements to be initialized to the object - // id. - // - os << "static void" << endl - << "load_ (statements_type&," << endl - << "object_type&," << endl - << "bool reload"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - if (poly_derived) - os << "," << endl - << "std::size_t = depth"; - - os << ");" - << endl; - } - - // discriminator_ () - // - if (poly && !poly_derived) - { - os << "static void" << endl - << "discriminator_ (statements_type&," << endl - << "const id_type&," << endl - << "discriminator_type*"; - - if (opt != 0) - os << "," << endl - << "version_type* = 0"; - - os << ");" - << endl; - } - - // Load the dynamic part of the object. Depth inidicates where - // the dynamic part starts. Expects the id image in the object - // statements to be initialized to the object id. We don't need - // it if we are poly-abstract. - // - if (poly_derived && !abst) - os << "static void" << endl - << "load_ (database&, root_type&, std::size_t);" - << endl; - - // Image chain manipulation. - // - if (poly && need_image_clone && options.generate_query ()) - { - os << "static root_traits::image_type&" << endl - << "root_image (image_type&);" - << endl; - - // Note that the original image is non-const since for some databases - // the copy "steals" stuff from the original (e.g., LOB descriptors in - // Oracle). - // - os << "static image_type*" << endl - << "clone_image (image_type&);" - << endl; - - os << "static void" << endl - << "copy_image (image_type&, image_type&);" - << endl; - - os << "static void" << endl - << "free_image (image_type*);" - << endl; - } - - os << "};"; - - - // object_traits_impl< , id_common> - // - // Note that it is not generated for reuse-abstract classes. - // - if (options.default_database_specified () && - options.default_database () == db) - { - os << "template <>" << endl - << "class access::object_traits_impl< " << type << ", " << - "id_common >:" << endl - << " public access::object_traits_impl< " << type << ", " << - "id_" << db << " >" - << "{" - << "};"; - } -} - -void relational::header::class1:: -traverse_view (type& c) -{ - bool versioned (context::versioned (c)); - - string const& type (class_fq_name (c)); - size_t columns (column_count (c).total); - size_t obj_count (c.get ("object-count")); - - os << "// " << class_name (c) << endl - << "//" << endl; - - // view_traits_impl - // - os << "template <>" << endl - << "class " << exp << "access::view_traits_impl< " << type << ", " << - "id_" << db << " >:" << endl - << " public access::view_traits< " << type << " >" - << "{" - << "public:" << endl; - - view_public_extra_pre (c); - - // For dynamic multi-database support also generate common traits - // alias (used in query aliasing). - // - if (multi_dynamic) - { - os << "typedef access::view_traits_impl< " << type << ", " << - "id_common > common_traits;" - << endl; - } - - // image_type - // - image_type_->traverse (c); - - os << "typedef " << db << "::view_statements statements_type;" - << endl; - - // - // Query. - // - - // Generate associated object tags here unless we are generating dynamic - // multi-database support, in which case they generated in object_traits. - // - if (!multi_dynamic) - { - query_tags t; // Not customizable. - t.traverse (c); - } - - // query_base_type and query_columns (definition generated by class2). - // - os << "typedef " << db << "::query_base query_base_type;" - << "struct query_columns"; - - if (obj_count == 0) - os << "{" - << "};"; - else - os << ";" - << endl; - - os << "static const bool versioned = " << versioned << ";" - << endl; - - // - // Functions. - // - - // grow () - // - if (generate_grow) - { - os << "static bool" << endl - << "grow (image_type&," << endl - << truncated_vector; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ")" << (columns != 0 ? ";\n" : "{}"); - } - - // bind (image_type) - // - os << "static void" << endl - << "bind (" << bind_vector << "," << endl - << "image_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ")" << (columns != 0 ? ";\n" : "{}"); - - // init (view, image) - // - os << "static void" << endl - << "init (view_type&," << endl - << "const image_type&," << endl - << "database*"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ")" << (columns != 0 ? ";\n" : "{}"); - - // column_count - // - os << "static const std::size_t column_count = " << columns << "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. - // - - // query () - // - if (!options.omit_unprepared ()) - { - os << "static result" << endl - << "query (database&, const query_base_type&);" - << endl; - - if (multi_dynamic) - os << "static result" << endl - << "query (database&, const odb::query_base&);" - << endl; - } - - if (options.generate_prepared ()) - { - os << "static odb::details::shared_ptr" << endl - << "prepare_query (connection&, const char*, const query_base_type&);" - << endl; - - if (multi_dynamic) - os << "static odb::details::shared_ptr" << endl - << "prepare_query (connection&, const char*, " << - "const odb::query_base&);" - << endl; - - os << "static odb::details::shared_ptr" << endl - << "execute_query (prepared_query_impl&);" - << endl; - } - - view_public_extra_post (c); - - os << "};"; - - // view_traits_impl< , id_common> - // - if (options.default_database_specified () && - options.default_database () == db) - { - os << "template <>" << endl - << "class access::view_traits_impl< " << type << ", " << - "id_common >:" << endl - << " public access::view_traits_impl< " << type << ", " << - "id_" << db << " >" - << "{" - << "};"; - } -} - -void relational::header::class1:: -traverse_composite (type& c) -{ - bool versioned (context::versioned (c)); - - string const& type (class_fq_name (c)); - - os << "// " << class_name (c) << endl - << "//" << endl; - - // While composite_value_traits is not used directly by user code, we - // still need to export it if the generated code for the same database - // is split into several DLLs. - // - os << "template <>" << endl - << "class " << exp << "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&," << endl - << truncated_vector; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // bind (image_type) - // - os << "static void" << endl - << "bind (" << bind_vector << "," << endl - << "image_type&," << endl - << db << "::statement_kind"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // init (image, value) - // - os << "static " << (generate_grow ? "bool" : "void") << endl - << "init (image_type&," << endl - << "const value_type&," << endl - << db << "::statement_kind"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // init (value, image) - // - os << "static void" << endl - << "init (value_type&," << endl - << "const image_type&," << endl - << "database*"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - if (!has_a (c, test_container)) - { - // get_null (image) - // - os << "static bool" << endl - << "get_null (const image_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // set_null (image) - // - os << "static void" << endl - << "set_null (image_type&," << endl - << db << "::statement_kind"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - column_count_type const& cc (column_count (c)); - os << "static const std::size_t column_count = " << cc.total << "UL;"; - - os << "};"; -} - -void relational::header:: -generate () -{ - context ctx; - ostream& os (ctx.os); - - instance i; - i->generate (); - - os << "namespace odb" - << "{"; - - { - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - instance c; - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (false); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - unit.dispatch (ctx.unit); - } - - { - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - instance c; - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (false); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - unit.dispatch (ctx.unit); - } - - os << "}"; -} diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx deleted file mode 100644 index 964aff2..0000000 --- a/odb/relational/header.hxx +++ /dev/null @@ -1,1466 +0,0 @@ -// file : odb/relational/header.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_HEADER_HXX -#define ODB_RELATIONAL_HEADER_HXX - -#include -#include - -namespace relational -{ - namespace header - { - // - // image_type - // - - struct image_member: virtual member_base - { - typedef image_member base; - - image_member (string const& var = string ()) - : member_base (var, 0, 0, string (), string ()) {} - - image_member (string const& var, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix) {} - }; - - template - struct image_member_impl: image_member, virtual member_base_impl - { - typedef image_member_impl base_impl; - - image_member_impl (base const& x) - : member_base::base (x), // virtual base - base (x), - member_image_type_ (base::type_override_, - base::custom_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - image_type = member_image_type_->image_type (mi.m); - - if (var_override_.empty ()) - os << "// " << mi.m.name () << endl - << "//" << endl; - - return true; - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. - // - if (view_member (mi.m)) - { - using semantics::class_; - - class_& c (*mi.ptr); - class_* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - if (poly_derived) - // Use a helper to create a complete chain of images all - // the way to the root (see libodb/odb/view-image.hxx). - // - os << "view_object_image<" << endl - << " " << class_fq_name (c) << "," << endl - << " " << class_fq_name (*poly_root) << "," << endl - << " id_" << db << " >"; - else - os << "object_traits_impl< " << class_fq_name (c) << ", " << - "id_" << db << " >::image_type"; - - os << " " << mi.var << "value;" - << endl; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << endl; - } - - protected: - string image_type; - instance member_image_type_; - }; - - struct image_base: traversal::class_, virtual context - { - typedef image_base base; - - image_base (): first_ (true) {} - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - if (first_) - { - os << ": "; - first_ = false; - } - else - { - os << "," << endl - << " "; - } - - string const& type (class_fq_name (c)); - - if (obj) - os << "object_traits_impl< " << type << ", id_" << db << - " >::image_type"; - else - os << "composite_value_traits< " << type << ", id_" << db << - " >::image_type"; - } - - private: - bool first_; - }; - - struct image_type: traversal::class_, virtual context - { - typedef image_type base; - - image_type () - { - *this >> names_member_ >> member_; - } - - image_type (image_type const&) - : root_context (), context () //@@ -Wextra - { - *this >> names_member_ >> member_; - } - - virtual void - image_extra (type&) - { - } - - virtual void - traverse (type& c) - { - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - os << "struct image_type"; - - if (!view (c)) - { - // Don't go into the base if we are a derived type in a - // polymorphic hierarchy. - // - if (!poly_derived) - { - instance b; - traversal::inherits i (*b); - inherits (c, i); - } - } - - os << "{"; - - if (poly_derived) - os << "base_traits::image_type* base;" - << endl; - - names (c); - - // We don't need a version if this is a composite value type - // or reuse-abstract object. - // - if (!(composite (c) || (abstract (c) && !polymorphic (c)))) - os << "std::size_t version;" - << endl; - - image_extra (c); - - os << "};"; - } - - private: - instance member_; - traversal::names names_member_; - }; - - // Member-specific traits types for container members. - // - struct container_traits: object_members_base, virtual context - { - typedef container_traits base; - - container_traits (semantics::class_& c) - : object_members_base (true, false, false), c_ (c) - { - } - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&) - { - // We don't want to traverse composite id. - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - if (object (c_)) - object_members_base::traverse_composite (m, c); - else - { - // If we are generating traits for a composite value type, then - // we don't want to go into its bases or it composite members. - // - if (m == 0 && &c == &c_) - names (c); - } - } - - virtual void - container_public_extra_pre (semantics::data_member&, semantics::type&) - { - } - - virtual void - container_public_extra_post (semantics::data_member&, semantics::type&) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& c) - { - using semantics::type; - using semantics::class_; - - // Figure out if this member is from a base object or composite - // value and if it's from an object, whether it is reuse-abstract. - // - bool base, reuse_abst; - - if (object (c_)) - { - base = cur_object != &c_ || - !object (dynamic_cast (m.scope ())); - reuse_abst = abstract (c_) && !polymorphic (c_); - } - else - { - base = false; // We don't go into bases. - reuse_abst = true; // Always abstract. - } - - container_kind_type ck (container_kind (c)); - - const custom_cxx_type* vct (0); - const custom_cxx_type* ict (0); - const custom_cxx_type* kct (0); - - type& vt (container_vt (m, &vct)); - type* it (0); - type* kt (0); - - bool ordered (false); - bool inverse (context::inverse (m, "value")); - - switch (ck) - { - case ck_ordered: - { - if (!unordered (m)) - { - it = &container_it (m, &ict); - ordered = true; - } - break; - } - case ck_map: - case ck_multimap: - { - kt = &container_kt (m, &kct); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - bool smart (!inverse && - (ck != ck_ordered || ordered) && - container_smart (c)); - - string name (flat_prefix_ + public_name (m) + "_traits"); - - // Figure out column counts. - // - size_t id_columns, value_columns, data_columns, cond_columns; - bool versioned (context::versioned (m)); - - if (!reuse_abst) - { - type& idt (container_idt (m)); - - if (class_* idc = composite_wrapper (idt)) - id_columns = column_count (*idc).total; - else - id_columns = 1; - - data_columns = cond_columns = id_columns; - - switch (ck) - { - case ck_ordered: - { - // Add one for the index. - // - if (ordered) - { - data_columns++; - - if (smart) - cond_columns++; - } - break; - } - case ck_map: - case ck_multimap: - { - // Add some for the key. - // - size_t n; - - class_* ptr (object_pointer (*kt)); - semantics::type& t (ptr == 0 ? *kt : utype (*id_member (*ptr))); - - if (class_* comp = composite_wrapper (t)) - n = column_count (*comp).total; - else - n = 1; - - data_columns += n; - - // Key is not currently used (see also bind()). - // - // cond_columns += n; - - break; - } - case ck_set: - case ck_multiset: - { - // Not currently used (see also bind()) - // - // Value is also a key. - // - // class_* ptr (object_pointer (vt)); - // semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr))); - // - // if (class_* comp = composite_wrapper (t)) - // cond_columns += column_count (*comp).total; - // else - // cond_columns++; - // - break; - } - } - - { - class_* ptr (object_pointer (vt)); - semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr))); - - if (class_* comp = composite_wrapper (t)) - value_columns = column_count (*comp).total; - else - value_columns = 1; - - data_columns += value_columns; - } - - // Store column counts for the source generator. - // - m.set ("id-column-count", id_columns); - m.set ("value-column-count", value_columns); - m.set ("cond-column-count", cond_columns); - m.set ("data-column-count", data_columns); - } - - os << "// " << m.name () << endl - << "//" << endl - << "struct " << exp << name; - - if (base) - { - semantics::class_& b (dynamic_cast (m.scope ())); - string const& type (class_fq_name (b)); - - if (object (b)) - os << ": access::object_traits_impl< " << type << ", id_" << - db << " >::" << name; - else - os << ": access::composite_value_traits< " << type << ", id_" << - db << " >::" << public_name (m) << "_traits"; // No prefix_. - } - - os << "{"; - - container_public_extra_pre (m, c); - - if (!reuse_abst) - { - // column_count - // - os << "static const std::size_t id_column_count = " << - id_columns << "UL;"; - - if (smart) - os << "static const std::size_t value_column_count = " << - value_columns << "UL;" - << "static const std::size_t cond_column_count = " << - cond_columns << "UL;"; - - os << "static const std::size_t data_column_count = " << - data_columns << "UL;" - << endl; - - os << "static const bool versioned = " << versioned << ";" - << endl; - - // Statements. - // - os << "static const char insert_statement[];" - << "static const char select_statement[];"; - - if (smart) - os << "static const char update_statement[];"; - - os << "static const char delete_statement[];" - << endl; - } - - if (base) - { - container_public_extra_post (m, c); - os << "};"; - - return; - } - - // container_type - // container_traits - // index_type - // key_type - // value_type - // - os << "typedef "; - - { - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - if (semantics::type* wt = wrapper (t)) - { - // Use the hint from the wrapper unless the wrapped type is - // qualified. In this case use the hint for the unqualified - // type. - // - hint = t.get ("wrapper-hint"); - utype (*wt, hint); - - os << c.fq_name (hint); - } - else - // t and c are the same. - // - os << t.fq_name (hint); - } - - os << " container_type;"; - - os << "typedef" << endl - << "odb::access::container_traits" << endl - << "container_traits_type;"; - - switch (ck) - { - case ck_ordered: - { - os << "typedef container_traits_type::index_type index_type;"; - break; - } - case ck_map: - case ck_multimap: - { - os << "typedef container_traits_type::key_type key_type;"; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "typedef container_traits_type::value_type value_type;" - << endl; - - // functions_type - // - switch (ck) - { - case ck_ordered: - { - os << "typedef " << (smart ? "smart_" : "") << - "ordered_functions functions_type;"; - break; - } - case ck_map: - case ck_multimap: - { - os << "typedef map_functions " << - "functions_type;"; - break; - } - case ck_set: - case ck_multiset: - { - os << "typedef set_functions functions_type;"; - break; - } - } - - os << "typedef " << db << "::" << (smart ? "smart_" : "") - << "container_statements< " << name << " > statements_type;" - << endl; - - // cond_image_type (object id is taken from the object image). - // - // For dumb containers we use the id binding directly. - // - if (smart) - { - os << "struct cond_image_type" - << "{"; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance im ( - "index_", *it, ict, "index_type", "index"); - im->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance im ("key_", *kt, kct, "key_type", "key"); - im->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - os << "// value" << endl - << "//" << endl; - instance im ( - "value_", vt, vct, "value_type", "value"); - im->traverse (m); - break; - } - } - - os << "std::size_t version;" - << "};"; - } - - // data_image_type (object id is taken from the object image) - // - os << "struct data_image_type" - << "{"; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance im ( - "index_", *it, ict, "index_type", "index"); - im->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance im ("key_", *kt, kct, "key_type", "key"); - im->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "// value" << endl - << "//" << endl; - instance im ("value_", vt, vct, "value_type", "value"); - im->traverse (m); - - os << "std::size_t version;" - << "};"; - - // bind (cond_image) - // - if (smart) - os << "static void" << endl - << "bind (" << bind_vector << "," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type&);" - << endl; - - // bind (data_image) - // - os << "static void" << endl - << "bind (" << bind_vector << "," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "data_image_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // bind (cond_image, data_image) (update) - // - if (smart) - { - os << "static void" << endl - << "bind (" << bind_vector << "," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type&," << endl - << "data_image_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // grow () - // - if (generate_grow) - { - os << "static void" << endl - << "grow (data_image_type&," << endl - << truncated_vector; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // init (data_image) - // - if (!inverse) - { - os << "static void" << endl - << "init (data_image_type&," << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "index_type*," << endl; - break; - } - case ck_map: - case ck_multimap: - { - os << "const key_type*," << endl; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "const value_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // init (cond_image) - // - if (smart) - { - os << "static void" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (cond_image_type&, index_type);"; - break; - } - case ck_map: - case ck_multimap: - { - // os << "init (data_image_type&, const key_type&);"; - break; - } - case ck_set: - case ck_multiset: - { - // os << "init (data_image_type&, const value_type&);"; - break; - } - } - - os << endl; - } - - // init (data) - // - os << "static void" << endl - << "init ("; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "index_type&," << endl; - break; - } - case ck_map: - case ck_multimap: - { - os << "key_type&," << endl; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "value_type&," << endl; - os << "const data_image_type&," << endl - << "database*"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // insert - // - os << "static void" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "insert (index_type, const value_type&, void*);"; - break; - } - case ck_map: - case ck_multimap: - { - os << "insert (const key_type&, const value_type&, void*);"; - break; - } - case ck_set: - case ck_multiset: - { - os << "insert (const value_type&, void*);"; - break; - } - } - - os << endl; - - // select - // - os << "static bool" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "select (index_type&, value_type&, void*);"; - break; - } - case ck_map: - case ck_multimap: - { - os << "select (key_type&, value_type&, void*);"; - break; - } - case ck_set: - case ck_multiset: - { - os << "select (value_type&, void*);"; - break; - } - } - - os << endl; - - // update - // - if (smart) - { - os << "static void" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "update (index_type, const value_type&, void*);"; - break; - } - case ck_map: - case ck_multimap: - { - //os << "update (const key_type&, const value_type&, void*);"; - break; - } - case ck_set: - case ck_multiset: - { - //os << "update (const value_type&, const value_type&, void*);"; - break; - } - } - - os << endl; - } - - // delete_ - // - os << "static void" << endl - << "delete_ ("; - - if (smart) - { - switch (ck) - { - case ck_ordered: - { - os << "index_type, "; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - } - - os << "void*);" - << endl; - - // persist - // - if (!inverse) - { - os << "static void" << endl - << "persist (const container_type&," << endl - << "statements_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // load - // - os << "static void" << endl - << "load (container_type&," << endl - << "statements_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - - // update - // - if (!(inverse || readonly (member_path_, member_scope_))) - { - os << "static void" << endl - << "update (const container_type&," << endl - << "statements_type&"; - - if (versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // erase - // - if (!inverse) - { - os << "static void" << endl - << "erase ("; - - if (smart) - os << "const container_type*, "; - - os << "statements_type&);" - << endl; - } - - container_public_extra_post (m, c); - - os << "};"; - } - - protected: - semantics::class_& c_; - }; - - // - // - struct section_traits: virtual context - { - typedef section_traits base; - - section_traits (semantics::class_& c): c_ (c) {} - - virtual void - section_public_extra_pre (user_section&) - { - } - - virtual void - section_public_extra_post (user_section&) - { - } - - virtual void - traverse (user_section& s) - { - semantics::class_* poly_root (polymorphic (c_)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c_); - - semantics::data_member* opt (optimistic (c_)); - - // Treat the special version update sections as abstract in reuse - // inheritance. - // - bool reuse_abst (!poly && - (abstract (c_) || - s.special == user_section::special_version)); - - bool load (s.total != 0 && s.separate_load ()); - bool load_con (s.containers && s.separate_load ()); - bool load_opt (s.optimistic () && s.separate_load ()); - - bool update (s.total != s.inverse + s.readonly); // Always separate. - bool update_con (s.readwrite_containers); - bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); - - // Don't generate anything for empty sections. - // - if (!(load || load_con || load_opt || - update || update_con || update_opt)) - return; - - // If we are adding a new section to a derived class in an optimistic - // hierarchy, then pretend it inherits from the special version update - // section. - // - user_section* rs (0); - if (opt != 0) - { - // Skip overrides and get to the new section if polymorphic. - // - for (rs = &s; poly && rs->base != 0; rs = rs->base) ; - - if (rs != 0) - { - if (rs->object != &opt->scope ()) - rs->base = &(poly ? poly_root : &opt->scope ())-> - get ("user-sections").back (); - else - rs = 0; - } - } - - string name (public_name (*s.member) + "_traits"); - - os << "// " << s.member->name () << endl - << "//" << endl - << "struct " << exp << name - << "{"; - - os << "typedef object_traits_impl::image_type image_type;" - << "typedef object_traits_impl::id_image_type id_image_type;" - << endl; - - section_public_extra_pre (s); - - // bind (id, image_type) - // - // If id is NULL, then id is ignored (select). Otherwise, it is - // copied at the end (update). - // - if (load || load_opt || update || update_opt) - { - os << "static std::size_t" << endl - << "bind (" << bind_vector << "," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "image_type&," << endl - << db << "::statement_kind"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // grow () - // - // We have to have out own version because the truncated vector - // will have different number of elements. - // - if (generate_grow && (load || load_opt)) - { - os << "static bool" << endl - << "grow (image_type&," << endl - << truncated_vector; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // init (object, image) - // - if (load) - { - os << "static void" << endl - << "init (object_type&," << endl - << "const image_type&," << endl - << "database*"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // init (image, object) - // - if (update) - { - os << "static " << (generate_grow ? "bool" : "void") << endl - << "init (image_type&," << endl - << "const object_type&"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration&"; - - os << ");" - << endl; - } - - // The rest does not apply to reuse-abstract sections. - // - if (reuse_abst) - { - section_public_extra_post (s); - os << "};"; - return; - } - - // column_count - // - column_count_type const& cc (column_count (poly ? *poly_root : c_)); - - // Generate load and update column counts even when they are zero so - // that we can instantiate section_statements. - // - os << "static const std::size_t id_column_count = " << cc.id << "UL;"; - - os << "static const std::size_t managed_optimistic_load_column_count" << - " = " << cc.optimistic_managed << "UL;" - << "static const std::size_t load_column_count = " << - (load ? s.total_total () : 0) << "UL;"; - - os << "static const std::size_t managed_optimistic_update_column_count" << - " = " << (poly_derived ? 0 : cc.optimistic_managed) << "UL;" - << "static const std::size_t update_column_count = " << - (update ? s.total - s.inverse - s.readonly : 0) << "UL;" - << endl; - - os << "static const bool versioned = " << s.versioned << ";" - << endl; - - // Statements. - // - if (load || load_opt) - os << "static const char select_statement[];" - << endl; - - if (update || update_opt) - os << "static const char update_statement[];" - << endl; - - // Section statements. - // - if (load || load_opt || update || update_opt) - os << "typedef " << db << "::section_statements< object_type, " << - name << " > statements_type;" - << endl; - - // We pass statement cache instead of just statements because - // we may also need statements for containers. - // - - // load () - // - if (load || load_opt || load_con) - os << "static void" << endl - << "load (extra_statement_cache_type&, object_type&" << - (poly ? ", bool top = true" : "") << ");" - << endl; - - // update () - // - if (update || update_opt || update_con) - os << "static void" << endl - << "update (extra_statement_cache_type&, const object_type&" << - (poly_derived && s.base != 0 ? ", bool base = true" : "") << ");" - << endl; - - section_public_extra_post (s); - - os << "};"; - - if (rs != 0) - rs->base = 0; - } - - protected: - semantics::class_& c_; - }; - - // First pass over objects, views, and composites. Some code must be - // split into two parts to deal with yet undefined types. - // - struct class1: traversal::class_, virtual context - { - typedef class1 base; - - class1 () - : typedefs_ (false), - id_image_member_ ("id_"), - version_image_member_ ("version_"), - discriminator_image_member_ ("discriminator_"), - query_columns_type_ (false, true, false), - pointer_query_columns_type_ (true, true, false) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - } - - class1 (class1 const&) - : root_context (), //@@ -Wextra - context (), - typedefs_ (false), - id_image_member_ ("id_"), - version_image_member_ ("version_"), - discriminator_image_member_ ("discriminator_"), - query_columns_type_ (false, true, false), - pointer_query_columns_type_ (true, true, false) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - } - - virtual void - traverse (type& c) - { - class_kind_type ck (class_kind (c)); - - if (ck == class_other || - (!options.at_once () && class_file (c) != unit.file ())) - return; - - names (c); - - switch (ck) - { - case class_object: traverse_object (c); break; - case class_view: traverse_view (c); break; - case class_composite: traverse_composite (c); break; - default: break; - } - } - - virtual void - object_public_extra_pre (type&) - { - } - - virtual void - object_public_extra_post (type&) - { - } - - virtual void - traverse_object (type&); - - virtual void - view_public_extra_pre (type&) - { - } - - virtual void - view_public_extra_post (type&) - { - } - - virtual void - traverse_view (type&); - - virtual void - traverse_composite (type&); - - private: - traversal::defines defines_; - typedefs typedefs_; - - instance image_type_; - instance id_image_member_; - instance version_image_member_; - instance discriminator_image_member_; - - instance query_columns_type_; - instance pointer_query_columns_type_; - }; - - // Second pass over objects, views, and composites. - // - struct class2: traversal::class_, virtual context - { - typedef class2 base; - - class2 () - : typedefs_ (false), - query_columns_type_ (false, true, false), - query_columns_type_inst_ (false, false, true), - view_query_columns_type_ (true) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - } - - class2 (class2 const&) - : root_context (), //@@ -Wextra - context (), - typedefs_ (false), - query_columns_type_ (false, true, false), - query_columns_type_inst_ (false, false, true), - view_query_columns_type_ (true) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - } - - virtual void - traverse (type& c) - { - class_kind_type ck (class_kind (c)); - - if (ck == class_other || - (!options.at_once () && class_file (c) != unit.file ())) - return; - - names (c); - - switch (ck) - { - case class_object: traverse_object (c); break; - case class_view: traverse_view (c); break; - case class_composite: traverse_composite (c); break; - default: break; - } - } - - virtual void - traverse_object (type& c) - { - if (options.generate_query ()) - { - os << "// " << class_name (c) << endl - << "//" << endl; - - // query_columns - // - // If we don't have any pointers, then query_columns is generated - // in pass 1 (see the comment in class1 for details). - // - if (has_a (c, test_pointer | include_base)) - query_columns_type_->traverse (c); - - // Generate extern template declarations. - // - if (multi_dynamic) - query_columns_type_inst_->traverse (c); - } - - // Move header comment out of if-block if adding any code here. - } - - virtual void - traverse_view (type& c) - { - // query_columns - // - if (c.get ("object-count") != 0) - { - os << "// " << class_name (c) << endl - << "//" << endl; - - view_query_columns_type_->traverse (c); - } - - // Move header comment out of if-block if adding any code here. - } - - virtual void - traverse_composite (type&) - { - } - - private: - traversal::defines defines_; - typedefs typedefs_; - - instance query_columns_type_; - instance query_columns_type_inst_; - instance view_query_columns_type_; - }; - - struct include: virtual context - { - typedef include base; - - virtual void - generate () - { - os << "#include " << endl - << endl; - - os << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl; - - if (options.generate_query ()) - { - os << "#include " << endl; - - if (multi_dynamic) - os << "#include " << endl; - } - - os << endl; - } - }; - } -} - -#endif // ODB_RELATIONAL_HEADER_HXX diff --git a/odb/relational/inline.cxx b/odb/relational/inline.cxx deleted file mode 100644 index 5e60705..0000000 --- a/odb/relational/inline.cxx +++ /dev/null @@ -1,47 +0,0 @@ -// file : odb/relational/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -using namespace std; - -namespace relational -{ - namespace inline_ - { - void - generate () - { - context ctx; - ostream& os (ctx.os); - - instance i; - i->generate (); - - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - class_ c; - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (false); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - os << "namespace odb" - << "{"; - - unit.dispatch (ctx.unit); - - os << "}"; - } - } -} diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx deleted file mode 100644 index a609cc1..0000000 --- a/odb/relational/inline.hxx +++ /dev/null @@ -1,693 +0,0 @@ -// file : odb/relational/inline.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_INLINE_HXX -#define ODB_RELATIONAL_INLINE_HXX - -#include -#include -#include - -namespace relational -{ - namespace inline_ - { - // - // get/set null (composite value only) - // - - struct null_member: virtual member_base - { - typedef null_member base; - - null_member (bool get) - : member_base (0, 0, string (), string ()), get_ (get) {} - - protected: - bool get_; - }; - - template - struct null_member_impl: null_member, virtual member_base_impl - { - typedef null_member_impl base_impl; - - null_member_impl (base const& x): base (x) {} - - typedef typename member_base_impl::member_info member_info; - - virtual bool - pre (member_info& mi) - { - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" - << "{"; - } - - // If the whole value type is readonly, then set will never be - // called with sk == statement_update. - // - if (!get_ && !readonly (*context::top_object)) - { - semantics::class_* c; - - if (readonly (mi.m) || ((c = composite (mi.t)) && readonly (*c))) - os << "if (sk == statement_insert)" << endl; - } - - return true; - } - - virtual void - post (member_info& mi) - { - if (added (mi.m) || deleted (mi.m)) - os << "}"; - } - - virtual void - traverse_composite (member_info& mi) - { - string traits ("composite_value_traits< " + mi.fq_type () + ", id_" + - db.string () + " >"); - - if (get_) - os << "r = r && " << traits << "::get_null (" << - "i." << mi.var << "value"; - else - os << traits << "::set_null (i." << mi.var << "value, sk"; - - if (versioned (*composite (mi.t))) - os << ", svm"; - - os << ");"; - } - }; - - struct null_base: traversal::class_, virtual context - { - typedef null_base base; - - null_base (bool get): get_ (get) {} - - virtual void - traverse (type& c) - { - // Ignore transient bases. - // - if (!composite (c)) - return; - - string traits ("composite_value_traits< " + class_fq_name (c) + - ", id_" + db.string () + " >"); - - // If the derived value type is readonly, then set will never be - // called with sk == statement_update. - // - if (!get_ && readonly (c) && !readonly (*context::top_object)) - os << "if (sk == statement_insert)" << endl; - - if (get_) - os << "r = r && " << traits << "::get_null (i"; - else - os << traits << "::set_null (i, sk"; - - if (versioned (c)) - os << ", svm"; - - os << ");"; - } - - protected: - bool get_; - }; - - // - // - struct class_: traversal::class_, virtual context - { - typedef class_ base; - - class_ () - : typedefs_ (false), - get_null_base_ (true), - get_null_member_ (true), - set_null_base_ (false), - set_null_member_ (false) - { - init (); - } - - class_ (class_ const&) - : root_context (), //@@ -Wextra - context (), - typedefs_ (false), - get_null_base_ (true), - get_null_member_ (true), - set_null_base_ (false), - set_null_member_ (false) - { - init (); - } - - void - init () - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - - get_null_base_inherits_ >> get_null_base_; - get_null_member_names_ >> get_null_member_; - - set_null_base_inherits_ >> set_null_base_; - set_null_member_names_ >> set_null_member_; - } - - virtual void - traverse (type& c) - { - class_kind_type ck (class_kind (c)); - - if (ck == class_other || - (!options.at_once () && class_file (c) != unit.file ())) - return; - - names (c); - - context::top_object = context::cur_object = &c; - - switch (ck) - { - case class_object: traverse_object (c); break; - case class_view: traverse_view (c); break; - case class_composite: traverse_composite (c); break; - default: break; - } - - context::top_object = context::cur_object = 0; - } - - virtual void - object_extra (type&) - { - } - - virtual void - traverse_object (type& c) - { - using semantics::data_member; - - data_member_path* id (id_member (c)); - data_member* idf (id ? id->front () : 0); - bool auto_id (id && auto_ (*id)); - bool base_id (id && &idf->scope () != &c); // Comes from base. - data_member* optimistic (context::optimistic (c)); - - // Base class that contains the object id and version for optimistic - // concurrency. - // - type* base (base_id ? dynamic_cast (&idf->scope ()) : 0); - - type* poly_root (context::polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - bool abst (abstract (c)); - bool reuse_abst (abst && !poly); - - bool versioned (context::versioned (c)); - - string const& type (class_fq_name (c)); - string traits ("access::object_traits_impl< " + type + ", id_" + - db.string () + " >"); - - user_sections& uss (c.get ("user-sections")); - - os << "// " << class_name (c) << endl - << "//" << endl - << endl; - - object_extra (c); - - if (id != 0 && base_id) - { - if (!poly_derived) - { - // id (id_image_type) - // - if (auto_id) - { - os << "inline" << endl - << traits << "::id_type" << endl - << traits << "::" << endl - << "id (const id_image_type& i)" - << "{" - << "return object_traits_impl< " << class_fq_name (*base) << - ", id_" << db << " >::id (i);" - << "}"; - } - - // id (image_type) - // - if (options.generate_query ()) - { - os << "inline" << endl - << traits << "::id_type" << endl - << traits << "::" << endl - << "id (const image_type& i)" - << "{" - << "return object_traits_impl< " << class_fq_name (*base) << - ", id_" << db << " >::id (i);" - << "}"; - } - - // version (image_type) - // - if (optimistic != 0) - { - os << "inline" << endl - << traits << "::version_type" << endl - << traits << "::" << endl - << "version (const image_type& i)" - << "{" - << "return object_traits_impl< " << class_fq_name (*base) << - ", id_" << db << " >::version (i);" - << "}"; - } - } - - // bind (id_image_type) - // - os << "inline" << endl - << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b, id_image_type& i" << - (optimistic != 0 ? ", bool bv" : "") << ")" - << "{" - << "object_traits_impl< " << class_fq_name (*base) << ", id_" << - db << " >::bind (b, i" << (optimistic != 0 ? ", bv" : "") << ");" - << "}"; - - os << "inline" << endl - << "void " << traits << "::" << endl - << "init (id_image_type& i, const id_type& id" << - (optimistic != 0 ? ", const version_type* v" : "") << ")" - << "{" - << "object_traits_impl< " << class_fq_name (*base) << ", id_" << - db << " >::init (i, id" << (optimistic != 0 ? ", v" : "") << ");" - << "}"; - } - - if (poly_derived) - { - size_t depth (polymorphic_depth (c)); - - // check_version - // - os << "inline" << endl - << "bool " << traits << "::" << endl - << "check_version (const std::size_t* v, const image_type& i)" - << "{" - << "return "; - - string image ("i."); - for (size_t i (0); i < depth; ++i) - { - os << (i == 0 ? "" : " ||") << endl - << " v[" << i << "UL] != " << image << "version"; - - image += "base->"; - } - - os << ";" - << "}"; - - // update_version - // - os << "inline" << endl - << "void " << traits << "::" << endl - << "update_version (std::size_t* v, const image_type& i, " << - db << "::binding* b)" - << "{"; - - image = "i."; - for (size_t i (0); i < depth; ++i) - { - os << "v[" << i << "UL] = " << image << "version;"; - image += "base->"; - } - - // A poly-abstract class always has only one entry in the - // bindings array. - // - if (abst) - os << "b[0].version++;"; - else - for (size_t i (0); i < depth; ++i) - os << "b[" << i << "UL].version++;"; - - os << "}"; - } - - // The rest does not apply to reuse-abstract objects. - // - if (reuse_abst) - return; - - // erase (object_type) - // - if (id != 0 && !poly && optimistic == 0 && - !has_a (c, test_smart_container)) - { - os << "inline" << endl - << "void " << traits << "::" << endl - << "erase (database& db, const object_type& obj)" - << "{" - << "callback (db, obj, callback_event::pre_erase);" - << "erase (db, id (obj));"; - - // Note that we don't reset sections since the object is now - // transient and the state of a section in a transient object - // is undefined. - - os << "callback (db, obj, callback_event::post_erase);" - << "}"; - } - - // load (section) [thunk version; poly_derived is true] - // - if (uss.count (user_sections::count_total | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) != 0 && - uss.count (user_sections::count_new | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) == 0) - { - os << "inline" << endl - << "bool " << traits << "::" << endl - << "load (connection& conn, object_type& obj, section& s, " << - "const info_type* pi)" - << "{" - << "return base_traits::load (conn, obj, s, pi);" - << "}"; - } - - // update (section) [thunk version; poly_derived is true] - // - if (uss.count (user_sections::count_total | - user_sections::count_update | - (poly ? user_sections::count_update_empty : 0)) != 0 && - uss.count (user_sections::count_new | - user_sections::count_update | - (poly ? user_sections::count_update_empty : 0)) == 0) - { - os << "inline" << endl - << "bool " << traits << "::" << endl - << "update (connection& conn, const object_type& obj, " << - "const section& s, const info_type* pi)" - << "{" - << "return base_traits::update (conn, obj, s, pi);" - << "}"; - } - - // load_() - // - if (id != 0 && - !(poly_derived || - has_a (c, test_container | include_eager_load, &main_section) || - uss.count (user_sections::count_new | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) != 0)) - { - os << "inline" << endl - << "void " << traits << "::" << endl - << "load_ (statements_type& sts," << endl - << "object_type& obj," << endl - << "bool"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (sts);" - << "ODB_POTENTIALLY_UNUSED (obj);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - // Mark eager sections as loaded. - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip special sections. - // - if (i->special == user_section::special_version) - continue; - - data_member& m (*i->member); - - // If the section is soft- added or deleted, check the version. - // We can only end up here if the object itself is versioned - // (simple value section). - // - unsigned long long av (added (m)); - unsigned long long dv (deleted (m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" << endl; - } - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ("obj") << ".reset (true, false);" - << endl; - } - - os << "}"; - } - - if (poly && need_image_clone && options.generate_query ()) - { - // root_image () - // - os << "inline" << endl - << traits << "::root_traits::image_type&" << endl - << traits << "::" << endl - << "root_image (image_type& i)" - << "{"; - - if (poly_derived) - os << "return base_traits::root_image (*i.base);"; - else - os << "return i;"; - - os << "}"; - - // clone_image () - // - os << "inline" << endl - << traits << "::image_type*" << endl - << traits << "::" << endl - << "clone_image (image_type& i)" - << "{"; - - if (poly_derived) - os << "details::unique_ptr p (" << endl - << "base_traits::clone_image (*i.base));" - << "image_type* c (new image_type (i));" - << "c->base = p.release ();" - << "return c;"; - else - os << "return new image_type (i);"; - - os << "}"; - - // copy_image () - // - os << "inline" << endl - << "void " << traits << "::" << endl - << "copy_image (image_type& d, image_type& s)" - << "{"; - - if (poly_derived) - os << "base_traits::image_type* b (d.base);" - << "base_traits::copy_image (*b, *s.base);" - << "d = s;" // Overwrites the base pointer. - << "d.base = b;"; - else - os << "d = s;"; - - os << "}"; - - // free_image () - // - os << "inline" << endl - << "void " << traits << "::" << endl - << "free_image (image_type* i)" - << "{"; - - if (poly_derived) - os << "base_traits::free_image (i->base);"; - - os << "delete i;" - << "}"; - } - } - - virtual void - view_extra (type&) - { - } - - virtual void - traverse_view (type& c) - { - string const& type (class_fq_name (c)); - string traits ("access::view_traits_impl< " + type + ", id_" + - db.string () + " >"); - - os << "// " << class_name (c) << endl - << "//" << endl - << endl; - - view_extra (c); - } - - virtual void - traverse_composite (type& c) - { - bool versioned (context::versioned (c)); - - string const& type (class_fq_name (c)); - string traits ("access::composite_value_traits< " + type + ", id_" + - db.string () + " >"); - - os << "// " << class_name (c) << endl - << "//" << endl - << endl; - - if (!has_a (c, test_container)) - { - // get_null (image) - // - os << "inline" << endl - << "bool " << traits << "::" << endl - << "get_null (const image_type& i"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);" - << endl; - - os << "bool r (true);"; - - inherits (c, get_null_base_inherits_); - names (c, get_null_member_names_); - - os << "return r;" - << "}"; - - // set_null (image) - // - os << "inline" << endl - << "void " << traits << "::" << endl - << "set_null (image_type& i," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - inherits (c, set_null_base_inherits_); - names (c, set_null_member_names_); - - os << "}"; - } - } - - private: - traversal::defines defines_; - typedefs typedefs_; - - instance get_null_base_; - traversal::inherits get_null_base_inherits_; - instance get_null_member_; - traversal::names get_null_member_names_; - - instance set_null_base_; - traversal::inherits set_null_base_inherits_; - instance set_null_member_; - traversal::names set_null_member_names_; - }; - - struct include: virtual context - { - typedef include base; - - virtual void - generate () - { - if (versioned ()) - os << "#include " << endl - << endl; - - if (features.polymorphic_object && options.generate_query ()) - os << "#include " << endl - << endl; - } - }; - } -} - -#endif // ODB_RELATIONAL_INLINE_HXX diff --git a/odb/relational/model.cxx b/odb/relational/model.cxx deleted file mode 100644 index 45d555a..0000000 --- a/odb/relational/model.cxx +++ /dev/null @@ -1,121 +0,0 @@ -// file : odb/relational/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace model - { - // object_columns - // - string object_columns:: - default_ (semantics::data_member& m) - { - default_value* dv (0); - - semantics::type& t (utype (m)); - - if (m.count ("default")) - dv = &m.get ("default"); - else if (t.count ("default")) - dv = &t.get ("default"); - else - return ""; // No default value for this column. - - switch (dv->kind) - { - case default_value::reset: - { - return ""; // No default value. - } - case default_value::null: - { - return default_null (m); - } - case default_value::boolean: - { - return default_bool (m, dv->literal == "true"); - } - case default_value::integer: - { - return default_integer (m, dv->int_value, dv->literal == "-"); - } - case default_value::floating: - { - return default_float (m, dv->float_value); - } - case default_value::string: - { - return default_string (m, dv->literal); - } - case default_value::enumerator: - { - return default_enum (m, dv->enum_value, dv->literal); - } - } - - return ""; - } - - cutl::shared_ptr - generate () - { - context ctx; - cutl::shared_ptr m ( - new (shared) sema_rel::model ( - ctx.versioned () ? ctx.version ().current : 0)); - m->set ("deleted-map", deleted_table_map ()); - - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - instance c (*m); - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (false); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - try - { - unit.dispatch (ctx.unit); - } - catch (sema_rel::duplicate_name const& e) - { - location const& o (e.orig.get ("cxx-location")); - location const& d (e.dup.get ("cxx-location")); - - error (d) << e.dup.kind () << " name '" << e.name << "' conflicts " - << "with an already defined " << e.orig.kind () << " name" - << endl; - - info (o) << "conflicting " << e.orig.kind () << " is defined here" - << endl; - - if (e.dup.kind () == "index") - info (d) << "use #pragma db index to change its name" << endl; - else if (e.dup.kind () == "table") - info (d) << "use #pragma db table to change its name" << endl; - else - info (d) << "use #pragma db column to change its name" << endl; - - throw operation_failed (); - } - - return m; - } - } -} diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx deleted file mode 100644 index fdfa8fd..0000000 --- a/odb/relational/model.hxx +++ /dev/null @@ -1,868 +0,0 @@ -// file : odb/relational/model.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_MODEL_HXX -#define ODB_RELATIONAL_MODEL_HXX - -#include -#include -#include -#include - -#include - -#include -#include - -namespace relational -{ - namespace model - { - typedef std::set tables; - typedef std::map deleted_table_map; - typedef std::map deleted_column_map; - - struct object_columns: object_columns_base, virtual context - { - typedef object_columns base; - - object_columns (sema_rel::model& model, - sema_rel::table& table, - bool object) - : model_ (model), - table_ (table), - object_ (object), - pkey_ (0), - id_override_ (false) - { - } - - virtual void - traverse_object (semantics::class_& c) - { - if (context::top_object != &c) - { - // We are in one of the bases. Set the id_prefix to its - // (unqualified) name. - // - string t (id_prefix_); - id_prefix_ = class_name (c) + "::"; - object_columns_base::traverse_object (c); - id_prefix_ = t; - } - else - object_columns_base::traverse_object (c); - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - string t (id_prefix_); - - if (m != 0) - // Member of a composite type. Add the data member to id_prefix. - // - if (!id_override_) - id_prefix_ += m->name () + "."; - else - id_override_ = false; - else - // Composite base. Add its unqualified name to id_prefix. - // - id_prefix_ += class_name (c) + "::"; - - object_columns_base::traverse_composite (m, c); - - id_prefix_ = t; - } - - virtual void - traverse (semantics::data_member& m, - semantics::type& t, - string const& kp, - string const& dn, - semantics::class_* to = 0) - { - // This overrides the member name for a composite container value - // or key. - // - if (!kp.empty ()) - { - semantics::class_* c (object_pointer (t)); - if (composite_wrapper (c == 0 ? t : utype (*id_member (*c)))) - { - id_prefix_ = kp + "."; - id_override_ = true; - } - } - - object_columns_base::traverse (m, t, kp, dn, to); - } - - using object_columns_base::traverse; - - virtual bool - traverse_column (semantics::data_member& m, string const& name, bool) - { - if (semantics::data_member* m = deleted_member (member_path_)) - { - table_.get ("deleted-map")[name] = m; - return false; - } - - string col_id (id_prefix_ + - (key_prefix_.empty () ? m.name () : key_prefix_)); - - sema_rel::column& c ( - model_.new_node (col_id, type (m), null (m))); - c.set ("cxx-location", m.location ()); - c.set ("member-path", member_path_); - model_.new_edge (table_, c, name); - - // An id member cannot have a default value. - // - if (!object_columns_base::id ()) - { - string const& d (default_ (m)); - - if (!d.empty ()) - c.default_ (d); - } - - // If we have options, add them. - // - string const& o (column_options (m, key_prefix_)); - - if (!o.empty ()) - c.options (o); - - constraints (m, name, col_id, c); - return true; - } - - virtual string - type (semantics::data_member&) - { - return object_columns_base::column_type (); - } - - virtual bool - null (semantics::data_member&) - { - return !object_columns_base::id () && object_columns_base::null (); - } - - virtual string - default_null (semantics::data_member&) - { - return "NULL"; - } - - virtual string - default_bool (semantics::data_member&, bool v) - { - // Most databases do not support boolean literals. Those that - // do should override this. - // - return (v ? "1" : "0"); - } - - virtual string - default_integer (semantics::data_member&, unsigned long long v, bool neg) - { - std::ostringstream ostr; - ostr << (neg ? "-" : "") << v; - return ostr.str (); - } - - virtual string - default_float (semantics::data_member&, double v) - { - std::ostringstream ostr; - ostr << v; - return ostr.str (); - } - - virtual string - default_string (semantics::data_member&, string const& v) - { - return quote_string (v); - } - - virtual string - default_enum (semantics::data_member&, - tree /*enumerator*/, - string const& /*name*/) - { - // Has to be implemented by the database-specific override. - // - assert (false); - return string (); - } - - virtual void - primary_key (sema_rel::primary_key&) - { - } - - virtual void - constraints (semantics::data_member& m, - string const& /* name */, - string const& /* id */, - sema_rel::column& c) - { - if (object_) - { - if (semantics::data_member* idm = id ()) - { - if (pkey_ == 0) - { - pkey_ = &model_.new_node ( - m.count ("auto")); - pkey_->set ("cxx-location", idm->location ()); - - // In most databases the primary key constraint can be - // manipulated without an explicit name. So we use the special - // empty name for primary keys in order not to clash with - // columns and other constraints. If the target database does - // not support unnamed primary key manipulation, then the - // database-specific code will have to come up with a suitable - // name. - // - model_.new_edge (table_, *pkey_, ""); - primary_key (*pkey_); - } - - model_.new_edge (*pkey_, c); - } - } - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore inverse object pointers. - // - if (inverse (m, key_prefix_)) - return; - - if (deleted (member_path_)) - { - // Still traverse it as columns so that we can populate the - // deleted map. - // - object_columns_base::traverse_pointer (m, c); - return; - } - - // Get the position of the last column. - // - sema_rel::table::names_iterator i (table_.names_end ()); - - while (i != table_.names_begin ()) - { - --i; - if (i->nameable ().is_a ()) - break; - } - - // Traverse the object pointer as columns. - // - object_columns_base::traverse_pointer (m, c); - - // Get to the first column that we have added. - // - if (i != table_.names_end ()) - ++i; // Next column. - else - i = table_.names_begin (); - - foreign_key (m, c, i); - } - - virtual void - traverse_points_to (semantics::data_member& m, semantics::class_& c) - { - if (deleted (member_path_)) - { - // Still traverse it as columns so that we can populate the - // deleted map. - // - object_columns_base::traverse_points_to (m, c); - return; - } - - // Get the position of the last column. - // - sema_rel::table::names_iterator i (table_.names_end ()); - - while (i != table_.names_begin ()) - { - --i; - if (i->nameable ().is_a ()) - break; - } - - // Traverse the data member as columns. - // - object_columns_base::traverse_points_to (m, c); - - // Get to the first column that we have added. - // - if (i != table_.names_end ()) - ++i; // Next column. - else - i = table_.names_begin (); - - foreign_key (m, c, i); - } - - virtual void - foreign_key (semantics::data_member& m, - semantics::class_& c, - sema_rel::table::names_iterator i) - { - using sema_rel::column; - using sema_rel::foreign_key; - - string id (id_prefix_ + - (key_prefix_.empty () ? m.name () : key_prefix_)); - - deferrable def ( - m.get ("deferrable", - options.fkeys_deferrable_mode ()[db])); - - foreign_key::action_type on_delete ( - m.get ( - "on-delete", foreign_key::no_action)); - - foreign_key& fk ( - model_.new_node (id, table_name (c), def, on_delete)); - - fk.set ("cxx-location", m.location ()); - - bool simple; - - // Get referenced columns. - // - { - data_member_path& id (*id_member (c)); - - instance ocl; - ocl->traverse (id); - - for (object_columns_list::iterator i (ocl->begin ()); - i != ocl->end (); ++i) - fk.referenced_columns ().push_back (i->name); - - simple = (fk.referenced_columns ().size () == 1); - } - - // Get referencing columns. - // - for (; i != table_.names_end (); ++i) - { - if (column* c = dynamic_cast (&i->nameable ())) - model_.new_edge (fk, *c); - else - break; - } - - // Derive the constraint name. Generally, we want it to be based - // on the column name. This is straightforward for single-column - // references. In case of a composite id, we will need to use the - // column prefix which is based on the data member name, unless - // overridden by the user. In the latter case the prefix can be - // empty, in which case we will just fall back on the member's - // public name. - // - string name; - - if (simple) - name = fk.contains_begin ()->column ().name (); - else - { - string p (column_prefix (m, key_prefix_, default_name_).prefix); - - if (p.empty ()) - p = public_name_db (m); - else if (p[p.size () - 1] == '_') - p.resize (p.size () - 1); // Remove trailing underscore. - - name = column_prefix_.prefix + p; - } - - model_.new_edge ( - table_, fk, fkey_name (table_.name (), name)); - } - - protected: - string - default_ (semantics::data_member&); - - protected: - sema_rel::model& model_; - sema_rel::table& table_; - bool object_; - sema_rel::primary_key* pkey_; - string id_prefix_; - bool id_override_; - }; - - struct object_indexes: traversal::class_, virtual context - { - typedef object_indexes base; - - object_indexes (sema_rel::model& model, sema_rel::table& table) - : model_ (model), table_ (table) - { - *this >> inherits_ >> *this; - } - - object_indexes (object_indexes const& x) - : root_context (), context (), //@@ -Wextra - model_ (x.model_), table_ (x.table_) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - if (!object (c)) // Ignore transient bases. - return; - - // Polymorphic bases get their own tables. - // - if (!polymorphic (c)) - inherits (c); - - indexes& ins (c.get ("index")); - - for (indexes::iterator i (ins.begin ()); i != ins.end (); ++i) - { - // Using index name as its id. - // - sema_rel::index& in ( - model_.new_node ( - i->name, i->type, i->method, i->options)); - in.set ("cxx-location", location (i->loc)); - model_.new_edge (table_, in, i->name); - - for (index::members_type::iterator j (i->members.begin ()); - j != i->members.end (); ++j) - { - using sema_rel::column; - - index::member& im (*j); - - semantics::type* t (&utype (*im.path.back ())); - - if (semantics::class_* ptr = object_pointer (*t)) - t = &utype (*id_member (*ptr)); - - if (type* comp = composite_wrapper (*t)) - { - // Composite value. Get the list of the columns. Note that - // the column prefix needs to contain all the components. - // - instance ocl ( - column_prefix (im.path, true)); - ocl->traverse (*comp); - - for (object_columns_list::iterator i (ocl->begin ()); - i != ocl->end (); ++i) - { - column* c (table_.find (i->name)); - assert (c != 0); - model_.new_edge (in, *c, im.options); - } - } - else - { - // Simple value. Get the column name and look it up in the - // table. - // - column* c (table_.find (column_name (im.path))); - assert (c != 0); - model_.new_edge (in, *c, im.options); - } - } - } - } - - private: - sema_rel::model& model_; - sema_rel::table& table_; - - traversal::inherits inherits_; - }; - - struct member_create: object_members_base, virtual context - { - typedef member_create base; - - member_create (sema_rel::model& model) - : object_members_base (false, true, false), model_ (model) - { - } - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&) - { - // We don't want to traverse composite id. - } - - virtual void - traverse_object (semantics::class_& c) - { - if (context::top_object != &c) - { - // We are in one of the bases. Set the id_prefix to its - // (unqualified) name. - // - string t (id_prefix_); - id_prefix_ = class_name (c) + "::"; - object_members_base::traverse_object (c); - id_prefix_ = t; - } - else - { - // Top-level object. Set its id as a prefix. - // - id_prefix_ = string (class_fq_name (c), 2) + "::"; - object_members_base::traverse_object (c); - } - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - string t (id_prefix_); - - if (m != 0) - // Member of a composite type. Add the data member to id_prefix. - // - id_prefix_ += m->name () + "."; - else - // Composite base. Add its unqualified name to id_prefix. - // - id_prefix_ += class_name (c) + "::"; - - object_members_base::traverse_composite (m, c); - - id_prefix_ = t; - } - - virtual string - table_options (semantics::data_member& m, semantics::type& ct) - { - return context::table_options (m, ct); - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& ct) - { - using semantics::type; - using semantics::data_member; - - using sema_rel::column; - - // Ignore inverse containers of object pointers. - // - if (inverse (m, "value")) - return; - - container_kind_type ck (container_kind (ct)); - qname const& name (table_name (m, table_prefix_)); - - // Ignore deleted container members. - // - if (semantics::data_member* m = deleted_member (member_path_)) - { - model_.get ("deleted-map")[name] = m; - return; - } - - // Add the [] decorator to distinguish this id from non-container - // ids (we don't want to ever end up comparing, for example, an - // object table to a container table). - // - string id (id_prefix_ + m.name () + "[]"); - - sema_rel::table& t (model_.new_node (id)); - t.set ("cxx-location", m.location ()); - t.set ("member-path", member_path_); - t.set ("deleted-map", deleted_column_map ()); - model_.new_edge (model_, t, name); - - t.options (table_options (m, ct)); - t.extra ()["kind"] = "container"; - - // object_id - // - { - bool f (false); //@@ (im)persfect forwarding. - instance oc (model_, t, f); - oc->traverse (m, container_idt (m), "id", "object_id"); - } - - // Foreign key and index for the object id. Keep this foreign - // key first since we reply on this information to lookup the - // corresponding object table. - // - { - // Derive the name prefix. See the comment for the other foreign - // key code above. - // - // Note also that id_name can be a column prefix (if id is - // composite), in which case it can be empty. In this case - // we just fallback on the default name. - // - // Finally, this is a top-level column, so there is no column - // prefix. - // - string id_name ( - column_name (m, "id", "object_id", column_prefix ())); - - if (id_name.empty ()) - id_name = "object_id"; - - // Foreign key. - // - sema_rel::foreign_key& fk ( - model_.new_node ( - id + ".id", - table_name (*context::top_object), - sema_rel::deferrable::not_deferrable, - sema_rel::foreign_key::cascade)); - fk.set ("cxx-location", m.location ()); - model_.new_edge ( - t, fk, fkey_name (t.name (), id_name)); - - // Get referenced columns. - // - { - data_member_path& id (*id_member (*context::top_object)); - - instance ocl; - ocl->traverse (id); - - for (object_columns_list::iterator i (ocl->begin ()); - i != ocl->end (); ++i) - fk.referenced_columns ().push_back (i->name); - } - - // All the columns we have in this table so far are for the - // object id. Add them to the foreign key. - // - for (sema_rel::table::names_iterator i (t.names_begin ()); - i != t.names_end (); - ++i) - { - if (column* c = dynamic_cast (&i->nameable ())) - model_.new_edge (fk, *c); - } - - // Index. See if we have a custom index. - // - index* sin (m.count ("id-index") ? &m.get ("id-index") : 0); - sema_rel::index* in (0); - - if (sin != 0) - { - in = &model_.new_node ( - id + ".id", sin->type, sin->method, sin->options); - in->set ("cxx-location", location (sin->loc)); - } - else - { - in = &model_.new_node (id + ".id"); - in->set ("cxx-location", m.location ()); - } - - model_.new_edge ( - t, - *in, - sin != 0 && !sin->name.empty () - ? sin->name - : index_name (name, id_name)); - - // All the columns we have in this table so far are for the - // object id. Add them to the index. - // - for (sema_rel::table::names_iterator i (t.names_begin ()); - i != t.names_end (); - ++i) - { - if (column* c = dynamic_cast (&i->nameable ())) - model_.new_edge ( - *in, *c, (sin != 0 ? sin->members.back ().options : "")); - } - } - - // index (simple value) - // - bool ordered (ck == ck_ordered && !unordered (m)); - if (ordered) - { - // Column. - // - { - bool f (false); //@@ (im)persfect forwarding. - instance oc (model_, t, f); - oc->traverse (m, container_it (m), "index", "index"); - } - - // This is a simple value so the name cannot be empty. It is - // also a top-level column, so there is no column prefix. - // - string col (column_name (m, "index", "index", column_prefix ())); - - // Index. See if we have a custom index. - // - index* sin (m.count ("index-index") - ? &m.get ("index-index") - : 0); - sema_rel::index* in (0); - - if (sin != 0) - { - in = &model_.new_node ( - id + ".index", sin->type, sin->method, sin->options); - in->set ("cxx-location", location (sin->loc)); - } - else - { - in = &model_.new_node (id + ".index"); - in->set ("cxx-location", m.location ()); - } - - model_.new_edge ( - t, - *in, - sin != 0 && !sin->name.empty () - ? sin->name - : index_name (name, col)); - - column* c (t.find (col)); - assert (c != 0); - - model_.new_edge ( - *in, - *c, - (sin != 0 ? sin->members.back ().options : "")); - } - - // key - // - if (ck == ck_map || ck == ck_multimap) - { - bool f (false); //@@ (im)persfect forwarding. - instance oc (model_, t, f); - oc->traverse (m, container_kt (m), "key", "key"); - } - - // value - // - { - bool f (false); //@@ (im)persfect forwarding. - instance oc (model_, t, f); - oc->traverse (m, container_vt (m), "value", "value"); - } - } - - protected: - sema_rel::model& model_; - string id_prefix_; - }; - - struct class_: traversal::class_, virtual context - { - typedef class_ base; - - class_ (sema_rel::model& model): model_ (model) {} - - virtual string - table_options (type& c) - { - return context::table_options (c); - } - - virtual void - traverse (type& c) - { - if (!options.at_once () && class_file (c) != unit.file ()) - return; - - if (!object (c)) - return; - - semantics::class_* poly (polymorphic (c)); - - if (abstract (c) && poly == 0) - return; - - qname const& name (table_name (c)); - - // If the table with this name was already seen, assume the - // user knows what they are doing and skip it. - // - if (tables_.count (name)) - return; - - if (deleted (c)) - { - model_.get ("deleted-map")[name] = &c; - return; - } - - string id (class_fq_name (c), 2); // Remove leading '::'. - - sema_rel::table& t (model_.new_node (id)); - t.set ("cxx-location", c.location ()); - t.set ("class", &c); - t.set ("deleted-map", deleted_column_map ()); - model_.new_edge (model_, t, name); - - t.options (table_options (c)); - - t.extra ()["kind"] =(poly == 0 - ? "object" - : (poly == &c - ? "polymorphic root object" - : "polymorphic derived object")); - - // Add columns. - // - { - bool tr (true); //@@ (im)persfect forwarding. - instance oc (model_, t, tr); - oc->traverse (c); - } - - // Add indexes. - // - { - instance oi (model_, t); - oi->traverse (c); - } - - tables_.insert (name); - - // Create tables for members. - // - { - instance mc (model_); - mc->traverse (c); - } - } - - protected: - sema_rel::model& model_; - tables tables_; - }; - } -} - -#endif // ODB_RELATIONAL_MODEL_HXX diff --git a/odb/relational/mssql/common.cxx b/odb/relational/mssql/common.cxx deleted file mode 100644 index 1070d21..0000000 --- a/odb/relational/mssql/common.cxx +++ /dev/null @@ -1,603 +0,0 @@ -// file : odb/relational/mssql/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace relational -{ - namespace mssql - { - // - // member_base - // - - sql_type const& member_base:: - member_sql_type (semantics::data_member& m) - { - return parse_sql_type (column_type (m, key_prefix_), m); - } - - void member_base:: - traverse_simple (member_info& mi) - { - const sql_type& st (*mi.st); - - // The same long/short data test as in context.cxx:long_data(). - // - switch (st.type) - { - // Integral types. - // - case sql_type::BIT: - case sql_type::TINYINT: - case sql_type::SMALLINT: - case sql_type::INT: - case sql_type::BIGINT: - { - traverse_integer (mi); - break; - } - - // Fixed and floating point types. - // - case sql_type::DECIMAL: - { - traverse_decimal (mi); - break; - } - case sql_type::SMALLMONEY: - { - traverse_smallmoney (mi); - break; - } - case sql_type::MONEY: - { - traverse_money (mi); - break; - } - case sql_type::FLOAT: - { - if (st.prec > 24) - traverse_float8 (mi); - else - traverse_float4 (mi); - - break; - } - - // String and binary types. - // - case sql_type::CHAR: - case sql_type::VARCHAR: - { - // Zero precision means max in VARCHAR(max). - // - if (st.prec == 0 || st.prec > options.mssql_short_limit ()) - traverse_long_string (mi); - else - traverse_string (mi); - - break; - } - case sql_type::TEXT: - { - traverse_long_string (mi); - break; - } - case sql_type::NCHAR: - case sql_type::NVARCHAR: - { - // Zero precision means max in NVARCHAR(max). Note that - // the precision is in 2-byte UCS-2 characters, not bytes. - // - if (st.prec == 0 || st.prec * 2 > options.mssql_short_limit ()) - traverse_long_nstring (mi); - else - traverse_nstring (mi); - - break; - } - case sql_type::NTEXT: - { - traverse_long_nstring (mi); - break; - } - case sql_type::BINARY: - case sql_type::VARBINARY: - { - // Zero precision means max in VARCHAR(max). - // - if (st.prec == 0 || st.prec > options.mssql_short_limit ()) - traverse_long_binary (mi); - else - traverse_binary (mi); - - break; - } - case sql_type::IMAGE: - { - traverse_long_binary (mi); - break; - } - - // Date-time types. - // - case sql_type::DATE: - { - traverse_date (mi); - break; - } - case sql_type::TIME: - { - traverse_time (mi); - break; - } - case sql_type::DATETIME: - case sql_type::DATETIME2: - case sql_type::SMALLDATETIME: - { - traverse_datetime (mi); - break; - } - case sql_type::DATETIMEOFFSET: - { - traverse_datetimeoffset (mi); - break; - } - - // Other types. - // - case sql_type::UNIQUEIDENTIFIER: - { - traverse_uniqueidentifier (mi); - break; - } - case sql_type::ROWVERSION: - { - traverse_rowversion (mi); - break; - } - case sql_type::invalid: - { - assert (false); - break; - } - } - } - - // - // member_image_type - // - - static const char* integer_types[] = - { - "unsigned char", - "unsigned char", - "short", - "int", - "long long" - }; - - member_image_type:: - member_image_type (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_image_type:: - member_image_type () - : relational::member_base (0, 0, string (), string ()) {} - - member_image_type:: - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, ct, fq_type, key_prefix) {} - - string member_image_type:: - image_type (semantics::data_member& m) - { - type_.clear (); - member_base::traverse (m, true); - return type_; - } - - void member_image_type:: - traverse_composite (member_info& mi) - { - type_ = "composite_value_traits< " + mi.fq_type () + - ", id_mssql >::image_type"; - } - - void member_image_type:: - traverse_integer (member_info& mi) - { - type_ = integer_types[mi.st->type - sql_type::BIT]; - } - - void member_image_type:: - traverse_decimal (member_info&) - { - type_ = "mssql::decimal"; - } - - void member_image_type:: - traverse_smallmoney (member_info&) - { - type_ = "mssql::smallmoney"; - } - - void member_image_type:: - traverse_money (member_info&) - { - type_ = "mssql::money"; - } - - void member_image_type:: - traverse_float4 (member_info&) - { - type_ = "float"; - } - - void member_image_type:: - traverse_float8 (member_info&) - { - type_ = "double"; - } - - void member_image_type:: - traverse_string (member_info&) - { - type_ = "char*"; - } - - void member_image_type:: - traverse_long_string (member_info&) - { - type_ = "mssql::long_callback"; - } - - void member_image_type:: - traverse_nstring (member_info&) - { - type_ = "mssql::ucs2_char*"; - } - - void member_image_type:: - traverse_long_nstring (member_info&) - { - type_ = "mssql::long_callback"; - } - - void member_image_type:: - traverse_binary (member_info&) - { - type_ = "char*"; - } - - void member_image_type:: - traverse_long_binary (member_info&) - { - type_ = "mssql::long_callback"; - } - - void member_image_type:: - traverse_date (member_info&) - { - type_ = "mssql::date"; - } - - void member_image_type:: - traverse_time (member_info&) - { - type_ = "mssql::time"; - } - - void member_image_type:: - traverse_datetime (member_info&) - { - type_ = "mssql::datetime"; - } - - void member_image_type:: - traverse_datetimeoffset (member_info&) - { - type_ = "mssql::datetimeoffset"; - } - - void member_image_type:: - traverse_uniqueidentifier (member_info&) - { - type_ = "mssql::uniqueidentifier"; - } - - void member_image_type:: - traverse_rowversion (member_info&) - { - type_ = "unsigned char*"; - } - - entry member_image_type_; - - // - // member_database_type - // - - static const char* integer_database_id[] = - { - "mssql::id_bit", - "mssql::id_tinyint", - "mssql::id_smallint", - "mssql::id_int", - "mssql::id_bigint" - }; - - member_database_type_id:: - member_database_type_id (base const& x) - : member_base::base (x), // virtual base - base (x) - { - } - - member_database_type_id:: - member_database_type_id () - : member_base::base (0, 0, string (), string ()), // virtual base - base (0, 0, string (), string ()) - { - } - - member_database_type_id:: - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base::base (type, ct, fq_type, key_prefix), // virtual base - base (type, ct, fq_type, key_prefix) - { - } - - string member_database_type_id:: - database_type_id (semantics::data_member& m) - { - type_id_.clear (); - member_base::traverse (m, true); - return type_id_; - } - - void member_database_type_id:: - traverse_composite (member_info&) - { - assert (false); - } - - void member_database_type_id:: - traverse_integer (member_info& mi) - { - type_id_ = integer_database_id[mi.st->type - sql_type::BIT]; - } - - void member_database_type_id:: - traverse_decimal (member_info&) - { - type_id_ = "mssql::id_decimal"; - } - - void member_database_type_id:: - traverse_smallmoney (member_info&) - { - type_id_ = "mssql::id_smallmoney"; - } - - void member_database_type_id:: - traverse_money (member_info&) - { - type_id_ = "mssql::id_money"; - } - - void member_database_type_id:: - traverse_float4 (member_info&) - { - type_id_ = "mssql::id_float4"; - } - - void member_database_type_id:: - traverse_float8 (member_info&) - { - type_id_ = "mssql::id_float8"; - } - - void member_database_type_id:: - traverse_string (member_info&) - { - type_id_ = "mssql::id_string"; - } - - void member_database_type_id:: - traverse_long_string (member_info&) - { - type_id_ = "mssql::id_long_string"; - } - - void member_database_type_id:: - traverse_nstring (member_info&) - { - type_id_ = "mssql::id_nstring"; - } - - void member_database_type_id:: - traverse_long_nstring (member_info&) - { - type_id_ = "mssql::id_long_nstring"; - } - - void member_database_type_id:: - traverse_binary (member_info&) - { - type_id_ = "mssql::id_binary"; - } - - void member_database_type_id:: - traverse_long_binary (member_info&) - { - type_id_ = "mssql::id_long_binary"; - } - - void member_database_type_id:: - traverse_date (member_info&) - { - type_id_ = "mssql::id_date"; - } - - void member_database_type_id:: - traverse_time (member_info&) - { - type_id_ = "mssql::id_time"; - } - - void member_database_type_id:: - traverse_datetime (member_info&) - { - type_id_ = "mssql::id_datetime"; - } - - void member_database_type_id:: - traverse_datetimeoffset (member_info&) - { - type_id_ = "mssql::id_datetimeoffset"; - } - - void member_database_type_id:: - traverse_uniqueidentifier (member_info&) - { - type_id_ = "mssql::id_uniqueidentifier"; - } - - void member_database_type_id:: - traverse_rowversion (member_info&) - { - type_id_ = "mssql::id_rowversion"; - } - - entry member_database_type_id_; - - // - // query_columns - // - - struct query_columns: relational::query_columns, context - { - query_columns (base const& x): base_impl (x) {} - - virtual string - database_type_id (semantics::data_member& m) - { - return member_database_type_id_.database_type_id (m); - } - - virtual void - column_ctor (string const& type, string const& name, string const& base) - { - os << name << " ("; - - if (multi_dynamic) - os << "odb::query_column< " << type << " >& qc," << endl; - - os << "const char* t," << endl - << "const char* c," << endl - << "const char* conv," << endl - << "unsigned short p = 0," << endl - << "unsigned short s = 0xFFFF)" << endl - << " : " << base << " (" << (multi_dynamic ? "qc, " : "") << - "t, c, conv, p, s)" - << "{" - << "}"; - } - - virtual void - column_ctor_args_extra (semantics::data_member& m) - { - // For some types we need to pass precision and scale. - // - sql_type const& st (parse_sql_type (column_type (), m)); - - switch (st.type) - { - case sql_type::DECIMAL: - { - os << ", " << st.prec << ", " << st.scale; - break; - } - case sql_type::FLOAT: - { - os << ", " << st.prec; - break; - } - case sql_type::CHAR: - case sql_type::VARCHAR: - { - os << ", " << st.prec; - break; - } - case sql_type::TEXT: - { - os << ", 0"; // Unlimited. - break; - } - case sql_type::NCHAR: - case sql_type::NVARCHAR: - { - os << ", " << st.prec; // In 2-byte characters. - break; - } - case sql_type::NTEXT: - { - os << ", 0"; // Unlimited. - break; - } - case sql_type::BINARY: - case sql_type::VARBINARY: - { - os << ", " << st.prec; - break; - } - case sql_type::IMAGE: - { - os << ", 0"; // Unlimited. - break; - } - // Date-time types. - // - case sql_type::TIME: - case sql_type::DATETIME2: - case sql_type::DATETIMEOFFSET: - { - os << ", 0, " << st.scale; // Fractional seconds (scale). - break; - } - case sql_type::DATETIME: - { - os << ", 0, 3"; - break; - } - case sql_type::SMALLDATETIME: - { - os << ", 0, 8"; - break; - } - default: - { - break; - } - } - } - - private: - member_database_type_id member_database_type_id_; - }; - entry query_columns_; - } -} diff --git a/odb/relational/mssql/common.hxx b/odb/relational/mssql/common.hxx deleted file mode 100644 index 42ea412..0000000 --- a/odb/relational/mssql/common.hxx +++ /dev/null @@ -1,293 +0,0 @@ -// file : odb/relational/mssql/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_MSSQL_COMMON_HXX -#define ODB_RELATIONAL_MSSQL_COMMON_HXX - -#include -#include - -namespace relational -{ - namespace mssql - { - struct member_base: virtual relational::member_base_impl, context - { - member_base (base const& x): base (x), base_impl (x) {} - - // This c-tor is for the direct use inside the mssql namespace. - // If you do use this c-tor, you should also explicitly call - // relational::member_base (aka base). - // - member_base () {} - - virtual sql_type const& - member_sql_type (semantics::data_member&); - - virtual void - traverse_simple (member_info&); - - virtual void - traverse_integer (member_info&) - { - } - - virtual void - traverse_decimal (member_info&) - { - } - - virtual void - traverse_smallmoney (member_info&) - { - } - - virtual void - traverse_money (member_info&) - { - } - - virtual void - traverse_float4 (member_info&) - { - } - - virtual void - traverse_float8 (member_info&) - { - } - - virtual void - traverse_string (member_info&) - { - } - - virtual void - traverse_long_string (member_info&) - { - } - - virtual void - traverse_nstring (member_info&) - { - } - - virtual void - traverse_long_nstring (member_info&) - { - } - - virtual void - traverse_binary (member_info&) - { - } - - virtual void - traverse_long_binary (member_info&) - { - } - - virtual void - traverse_date (member_info&) - { - } - - virtual void - traverse_time (member_info&) - { - } - - virtual void - traverse_datetime (member_info&) - { - } - - virtual void - traverse_datetimeoffset (member_info&) - { - } - - virtual void - traverse_uniqueidentifier (member_info&) - { - } - - virtual void - traverse_rowversion (member_info&) - { - } - }; - - struct member_image_type: relational::member_image_type, - member_base - { - member_image_type (base const&); - member_image_type (); - member_image_type (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - virtual string - image_type (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_decimal (member_info&); - - virtual void - traverse_smallmoney (member_info&); - - virtual void - traverse_money (member_info&); - - virtual void - traverse_float4 (member_info&); - - virtual void - traverse_float8 (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_long_string (member_info&); - - virtual void - traverse_nstring (member_info&); - - virtual void - traverse_long_nstring (member_info&); - - virtual void - traverse_binary (member_info&); - - virtual void - traverse_long_binary (member_info&); - - virtual void - traverse_date (member_info&); - - virtual void - traverse_time (member_info&); - - virtual void - traverse_datetime (member_info&); - - virtual void - traverse_datetimeoffset (member_info&); - - virtual void - traverse_uniqueidentifier (member_info&); - - virtual void - traverse_rowversion (member_info&); - - private: - string type_; - }; - - struct member_database_type_id: relational::member_database_type_id, - member_base - { - member_database_type_id (base const&); - member_database_type_id (); - member_database_type_id (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - - virtual string - database_type_id (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_decimal (member_info&); - - virtual void - traverse_smallmoney (member_info&); - - virtual void - traverse_money (member_info&); - - virtual void - traverse_float4 (member_info&); - - virtual void - traverse_float8 (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_long_string (member_info&); - - virtual void - traverse_nstring (member_info&); - - virtual void - traverse_long_nstring (member_info&); - - virtual void - traverse_binary (member_info&); - - virtual void - traverse_long_binary (member_info&); - - virtual void - traverse_date (member_info&); - - virtual void - traverse_time (member_info&); - - virtual void - traverse_datetime (member_info&); - - virtual void - traverse_datetimeoffset (member_info&); - - virtual void - traverse_uniqueidentifier (member_info&); - - virtual void - traverse_rowversion (member_info&); - - private: - string type_id_; - }; - - struct has_long_data: object_columns_base, context - { - has_long_data (bool& r): r_ (r) {} - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - if (!inverse (m, key_prefix_)) - object_columns_base::traverse_pointer (m, c); - } - - virtual bool - traverse_column (semantics::data_member& m, string const&, bool) - { - if (long_data (parse_sql_type (column_type (), m))) - r_ = true; - - return true; - } - - private: - bool& r_; - }; - } -} -#endif // ODB_RELATIONAL_MSSQL_COMMON_HXX diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx deleted file mode 100644 index afe1aa5..0000000 --- a/odb/relational/mssql/context.cxx +++ /dev/null @@ -1,766 +0,0 @@ -// file : odb/relational/mssql/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -#include -#include - -#include - -using namespace std; - -namespace relational -{ - namespace mssql - { - namespace - { - struct type_map_entry - { - char const* const cxx_type; - char const* const db_type; - char const* const db_id_type; - bool const null; - }; - - type_map_entry type_map[] = - { - {"bool", "BIT", 0, false}, - - {"char", "CHAR(1)", 0, false}, - {"wchar_t", "NCHAR(1)", 0, false}, - {"signed char", "TINYINT", 0, false}, - {"unsigned char", "TINYINT", 0, false}, - - {"short int", "SMALLINT", 0, false}, - {"short unsigned int", "SMALLINT", 0, false}, - - {"int", "INT", 0, false}, - {"unsigned int", "INT", 0, false}, - - {"long int", "BIGINT", 0, false}, - {"long unsigned int", "BIGINT", 0, false}, - - {"long long int", "BIGINT", 0, false}, - {"long long unsigned int", "BIGINT", 0, false}, - - {"float", "REAL", 0, false}, - {"double", "FLOAT", 0, false}, - - {"::std::string", "VARCHAR(512)", "VARCHAR(256)", false}, - {"::std::wstring", "NVARCHAR(512)", "NVARCHAR(256)", false}, - - {"::size_t", "BIGINT", 0, false}, - {"::std::size_t", "BIGINT", 0, false}, - - // Windows GUID/UUID (typedef struct _GUID {...} GUID, UUID;). - // - {"::_GUID", "UNIQUEIDENTIFIER", 0, false} - }; - } - - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context (ostream& os, - semantics::unit& u, - options_type const& ops, - features_type& f, - sema_rel::model* m) - : root_context (os, u, ops, f, data_ptr (new (shared) data (os))), - base_context (static_cast (root_context::data_.get ()), m), - data_ (static_cast (base_context::data_)) - { - assert (current_ == 0); - current_ = this; - - generate_grow = false; - need_alias_as = true; - insert_send_auto_id = false; - delay_freeing_statement_result = true; - need_image_clone = true; - generate_bulk = true; - global_index = false; - global_fkey = true; - data_->bind_vector_ = "mssql::bind*"; - - // Populate the C++ type to DB type map. - // - for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i) - { - type_map_entry const& e (type_map[i]); - - type_map_type::value_type v ( - e.cxx_type, - db_type_type ( - e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null)); - - data_->type_map_.insert (v); - } - } - - context:: - context () - : data_ (current ().data_) - { - } - - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - - string context:: - quote_id_impl (qname const& id) const - { - string r; - - bool f (true); - for (qname::iterator i (id.begin ()); i < id.end (); ++i) - { - if (i->empty ()) - continue; - - // Warn if the name is greater than the 128 limit. - // - if (i->size () > 128) - { - cerr << "warning: SQL name '" << *i << "' is longer than the " - << "SQL Server name limit of 128 characters and will be " - << "truncated" << endl; - - cerr << "info: consider shortening it using #pragma db " - << "table/column/index or --*-regex options" << endl; - } - - if (f) - f = false; - else - r += '.'; - - r += '['; - r.append (*i, 0, 128); // Max identifier length is 128. - r += ']'; - } - - return r; - } - - string context:: - database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) - { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - - using semantics::array; - - // char[N] mapping. - // - if (array* a = dynamic_cast (&t)) - { - semantics::type& bt (a->base_type ()); - bool c (bt.is_a ()); - - if (c || bt.is_a ()) - { - unsigned long long n (a->size ()); - - if (n == 0) - return r; - if (n == 1) - r = c ? "CHAR(" : "NCHAR("; - else - { - r = c ? "VARCHAR(" : "NVARCHAR("; - n--; - } - - if (n > (c ? 8000 : 4000)) - r += "max)"; - else - { - ostringstream ostr; - ostr << n; - r += ostr.str (); - r += ')'; - } - } - } - - return r; - } - - bool context:: - long_data (sql_type const& st) - { - bool r (false); - - // The same test as in common.cxx:traverse_simple(). - // - switch (st.type) - { - case sql_type::CHAR: - case sql_type::VARCHAR: - case sql_type::BINARY: - case sql_type::VARBINARY: - { - // Zero precision means max in VARCHAR(max). - // - if (st.prec == 0 || st.prec > options.mssql_short_limit ()) - r = true; - - break; - } - case sql_type::NCHAR: - case sql_type::NVARCHAR: - { - // Zero precision means max in NVARCHAR(max). Note that - // the precision is in 2-byte UCS-2 characters, not bytes. - // - if (st.prec == 0 || st.prec * 2 > options.mssql_short_limit ()) - r = true; - - break; - } - case sql_type::TEXT: - case sql_type::NTEXT: - case sql_type::IMAGE: - { - r = true; - break; - } - default: - break; - } - - return r; - } - - // - // SQL type parsing. - // - - namespace - { - struct sql_parser - { - typedef context::invalid_sql_type invalid_sql_type; - - sql_parser (custom_db_types const* ct): ct_ (ct) {} - - sql_type - parse (std::string sql) - { - r_ = sql_type (); - m_.clear (); - - // First run the type through the custom mapping, if requested. - // - if (ct_ != 0) - { - for (custom_db_types::const_iterator i (ct_->begin ()); - i != ct_->end (); ++i) - { - custom_db_type const& t (*i); - - if (t.type.match (sql)) - { - r_.to = t.type.replace (sql, t.to); - r_.from = t.type.replace (sql, t.from); - sql = t.type.replace (sql, t.as); - break; - } - } - } - - l_.lex (sql); - - bool ok (true); - - try - { - ok = parse_name (); - } - catch (sql_lexer::invalid_input const& e) - { - ok = false; - m_ = "invalid SQL Server type declaration: " + e.message; - } - - if (!ok) - { - if (ct_ == 0) - return sql_type (); - else - throw invalid_sql_type (m_); - } - - return r_; - } - - bool - parse_name () - { - sql_token t (l_.next ()); - - if (t.type () != sql_token::t_identifier) - { - m_ = "expected SQL Server type name instead of '" + - t.string () + "'"; - return false; - } - - string id (upcase (t.identifier ())); - - if (id == "BIT") - { - r_.type = sql_type::BIT; - } - else if (id == "TINYINT") - { - r_.type = sql_type::TINYINT; - } - else if (id == "SMALLINT") - { - r_.type = sql_type::SMALLINT; - } - else if (id == "INT" || - id == "INTEGER") - { - r_.type = sql_type::INT; - } - else if (id == "BIGINT") - { - r_.type = sql_type::BIGINT; - } - else if (id == "DECIMAL" || - id == "NUMERIC" || - id == "DEC") - { - r_.type = sql_type::DECIMAL; - - r_.has_prec = true; - r_.prec = 18; - - r_.has_scale = true; - r_.scale = 0; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "SMALLMONEY") - { - r_.type = sql_type::SMALLMONEY; - } - else if (id == "MONEY") - { - r_.type = sql_type::MONEY; - } - else if (id == "REAL") - { - r_.type = sql_type::FLOAT; - - r_.has_prec = true; - r_.prec = 24; - } - else if (id == "FLOAT") - { - r_.type = sql_type::FLOAT; - - r_.has_prec = true; - r_.prec = 53; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "DOUBLE") - { - t = l_.next (); - - if (t.type () != sql_token::t_identifier || - upcase (t.identifier ()) != "PRECISION") - { - m_ = "expected 'PRECISION' instead of '" + t.string () + "'"; - return false; - } - - r_.type = sql_type::FLOAT; - - r_.has_prec = true; - r_.prec = 53; - - // It appears that DOUBLE PRECISION can be followed by the - // precision specification. - // - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "CHAR" || - id == "CHARACTER") - { - if (!parse_char_trailer (false)) - return false; - } - else if (id == "VARCHAR") - { - r_.type = sql_type::VARCHAR; - - r_.has_prec = true; - r_.prec = 1; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "TEXT") - { - r_.type = sql_type::TEXT; - r_.has_prec = true; - r_.prec = 0; - } - else if (id == "NCHAR") - { - r_.type = sql_type::NCHAR; - - r_.has_prec = true; - r_.prec = 1; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "NVARCHAR") - { - r_.type = sql_type::NVARCHAR; - - r_.has_prec = true; - r_.prec = 1; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "NTEXT") - { - r_.type = sql_type::NTEXT; - r_.has_prec = true; - r_.prec = 0; - } - else if (id == "NATIONAL") - { - t = l_.next (); - - if (t.type () == sql_token::t_identifier) - id = upcase (t.identifier ()); - - if (id == "TEXT") - { - r_.type = sql_type::NTEXT; - r_.has_prec = true; - r_.prec = 0; - } - else if (id == "CHAR" || - id == "CHARACTER") - { - if (!parse_char_trailer (true)) - return false; - } - else - { - m_ = "expected 'CHAR', 'CHARACTER', or 'TEXT' instead of '" - + t.string () + "'"; - return false; - } - } - else if (id == "BINARY") - { - // Can be just BINARY or BINARY VARYING. - // - t = l_.next (); - - if (t.type () == sql_token::t_identifier) - id = upcase (t.identifier ()); - - if (id == "VARYING") - { - r_.type = sql_type::VARBINARY; - t = l_.next (); - } - else - r_.type = sql_type::BINARY; - - r_.has_prec = true; - r_.prec = 1; - - if (!parse_precision (t)) - return false; - } - else if (id == "VARBINARY") - { - r_.type = sql_type::VARBINARY; - - r_.has_prec = true; - r_.prec = 1; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "IMAGE") - { - r_.type = sql_type::IMAGE; - r_.has_prec = true; - r_.prec = 0; - } - else if (id == "DATE") - { - r_.type = sql_type::DATE; - } - else if (id == "TIME") - { - r_.type = sql_type::TIME; - - r_.has_scale = true; - r_.scale = 7; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "DATETIME") - { - r_.type = sql_type::DATETIME; - } - else if (id == "DATETIME2") - { - r_.type = sql_type::DATETIME2; - - r_.has_scale = true; - r_.scale = 7; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "SMALLDATETIME") - { - r_.type = sql_type::SMALLDATETIME; - } - else if (id == "DATETIMEOFFSET") - { - r_.type = sql_type::DATETIMEOFFSET; - - r_.has_scale = true; - r_.scale = 7; - - if (!parse_precision (l_.next ())) - return false; - } - else if (id == "UNIQUEIDENTIFIER") - { - r_.type = sql_type::UNIQUEIDENTIFIER; - } - else if (id == "ROWVERSION" || - id == "TIMESTAMP") - { - r_.type = sql_type::ROWVERSION; - } - else - { - m_ = "unexpected SQL Server type name '" + t.identifier () + "'"; - return false; - } - - return true; - } - - bool - parse_precision (sql_token t) - { - if (t.punctuation () == sql_token::p_lparen) - { - // Parse the precision. - // - t = l_.next (); - - if (t.type () == sql_token::t_identifier && - upcase (t.identifier ()) == "MAX") - { - r_.prec = 0; - r_.has_prec = true; - } - else if (t.type () == sql_token::t_int_lit) - { - unsigned short v; - istringstream is (t.literal ()); - - if (!(is >> v && is.eof ())) - { - m_ = "invalid precision value '" + t.literal () + "' in SQL " - "Server type declaration"; - return false; - } - - switch (r_.type) - { - case sql_type::TIME: - case sql_type::DATETIME2: - case sql_type::DATETIMEOFFSET: - { - r_.scale = v; - r_.has_scale = true; - break; - } - default: - { - r_.prec = v; - r_.has_prec = true; - break; - } - } - } - else - { - m_ = "integer precision expected in SQL Server type declaration"; - return false; - } - - // Parse the scale if present. - // - t = l_.next (); - - if (t.punctuation () == sql_token::p_comma) - { - // Scale can only be specified for the DECIMAL type. - // - if (r_.type != sql_type::DECIMAL) - { - m_ = "unexpected scale in SQL Server type declaration"; - return false; - } - - t = l_.next (); - - if (t.type () != sql_token::t_int_lit) - { - m_ = "integer scale expected in SQL Server type declaration"; - return false; - } - - istringstream is (t.literal ()); - - if (!(is >> r_.scale && is.eof ())) - { - m_ = "invalid scale value '" + t.literal () + "' in SQL " - "Server type declaration"; - return false; - } - - r_.has_scale = true; - t = l_.next (); - } - - if (t.punctuation () != sql_token::p_rparen) - { - m_ = "expected ')' in SQL Server type declaration"; - return false; - } - } - - return true; - } - - bool - parse_char_trailer (bool nat) - { - sql_token t (l_.next ()); - - string id; - - if (t.type () == sql_token::t_identifier) - id = upcase (t.identifier ()); - - if (id == "VARYING") - { - r_.type = nat ? sql_type::NVARCHAR : sql_type::VARCHAR; - t = l_.next (); - } - else - r_.type = nat ? sql_type::NCHAR : sql_type::CHAR; - - r_.has_prec = true; - r_.prec = 1; - - return parse_precision (t); - } - - private: - string - upcase (string const& s) - { - return context::upcase (s); - } - - private: - custom_db_types const* ct_; - sql_lexer l_; - sql_type r_; - string m_; // Error message. - }; - } - - sql_type const& context:: - parse_sql_type (string const& t, semantics::data_member& m, bool custom) - { - // If this proves to be too expensive, we can maintain a cache of - // parsed types across contexts. - // - data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - - if (i != data_->sql_type_cache_.end () - && (custom ? i->second.custom_cached : i->second.straight_cached)) - { - return (custom ? i->second.custom : i->second.straight); - } - else - { - try - { - sql_type st ( - parse_sql_type ( - t, - custom ? &unit.get ("custom-db-types") : 0)); - - if (custom) - return data_->sql_type_cache_[t].cache_custom (st); - else - return data_->sql_type_cache_[t].cache_straight (st); - } - catch (invalid_sql_type const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: " << e.message () << endl; - - throw operation_failed (); - } - } - } - - sql_type context:: - parse_sql_type (string const& sqlt, custom_db_types const* ct) - { - sql_parser p (ct); - return p.parse (sqlt); - } - } -} diff --git a/odb/relational/mssql/context.hxx b/odb/relational/mssql/context.hxx deleted file mode 100644 index 7701aaa..0000000 --- a/odb/relational/mssql/context.hxx +++ /dev/null @@ -1,194 +0,0 @@ -// file : odb/relational/mssql/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_MSSQL_CONTEXT_HXX -#define ODB_RELATIONAL_MSSQL_CONTEXT_HXX - -#include - -#include - -namespace relational -{ - namespace mssql - { - struct sql_type - { - // Keep the order in each block of types. - // - enum core_type - { - // Integral types. - // - BIT, - TINYINT, - SMALLINT, - INT, - BIGINT, - - // Fixed and floating point types. - // - DECIMAL, - SMALLMONEY, - MONEY, - FLOAT, - - // String and binary types. - // - CHAR, - VARCHAR, - TEXT, - - NCHAR, - NVARCHAR, - NTEXT, - - BINARY, - VARBINARY, - IMAGE, - - // Date-time types. - // - DATE, - TIME, - DATETIME, - DATETIME2, - SMALLDATETIME, - DATETIMEOFFSET, - - // Other types. - // - UNIQUEIDENTIFIER, - ROWVERSION, - - // Invalid type. - // - invalid - }; - - sql_type () : - type (invalid), - has_prec (false), prec (0), - has_scale (false), scale (0) - { - } - - core_type type; - - bool has_prec; - unsigned short prec; // Max numeric value is 8000. 0 indicates - // 'max' as in VARCHAR(max). - bool has_scale; - unsigned short scale; // Max value is 38. - - // Conversion expressions for custom database types. - // - std::string to; - std::string from; - }; - - class context: public virtual relational::context - { - public: - sql_type const& - parse_sql_type (string const&, - semantics::data_member&, - bool custom = true); - - // Return true if this type is long data. - // - bool - long_data (sql_type const&); - - public: - struct invalid_sql_type - { - invalid_sql_type (string const& message): message_ (message) {} - - string const& - message () const {return message_;} - - private: - string message_; - }; - - // If custom_db_types is NULL, then this function returns - // invalid type instead of throwing in case an unknown type - // is encountered. - // - static sql_type - parse_sql_type (string const&, custom_db_types const* = 0); - - protected: - virtual string const& - convert_expr (string const&, semantics::data_member&, bool); - - virtual string - quote_id_impl (qname const&) const; - - protected: - virtual string - database_type_impl (semantics::type&, semantics::names*, bool, bool*); - - public: - virtual - ~context (); - - context (); - context (std::ostream&, - semantics::unit&, - options_type const&, - features_type&, - sema_rel::model*); - - static context& - current () - { - return *current_; - } - - private: - static context* current_; - - private: - struct data: base_context::data - { - data (std::ostream& os): base_context::data (os) {} - - struct sql_type_cache_entry - { - sql_type_cache_entry () - : custom_cached (false), straight_cached (false) {} - - sql_type const& - cache_custom (sql_type const& t) - { - custom = t; - custom_cached = true; - return custom; - } - - sql_type const& - cache_straight (sql_type const& t) - { - straight = t; - straight_cached = true; - return straight; - } - - sql_type custom; // With custom mapping. - sql_type straight; // Without custom mapping. - - bool custom_cached; - bool straight_cached; - }; - - typedef std::map sql_type_cache; - sql_type_cache sql_type_cache_; - }; - data* data_; - }; - } -} - -#endif // ODB_RELATIONAL_MSSQL_CONTEXT_HXX diff --git a/odb/relational/mssql/header.cxx b/odb/relational/mssql/header.cxx deleted file mode 100644 index ebdc734..0000000 --- a/odb/relational/mssql/header.cxx +++ /dev/null @@ -1,312 +0,0 @@ -// file : odb/relational/mssql/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -namespace relational -{ - namespace mssql - { - namespace header - { - namespace relational = relational::header; - - struct class1: relational::class1, context - { - class1 (base const& x): base (x) {} - - virtual void - object_public_extra_pre (type& c) - { - bool abst (abstract (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - if (poly_derived || (abst && !poly)) - return; - - // Bulk operations batch size. - // - { - unsigned long long b (c.count ("bulk") - ? c.get ("bulk") - : 1); - - os << "static const std::size_t batch = " << b << "UL;" - << endl; - } - - // rowvesion - // - bool rv (false); - if (semantics::data_member* m = optimistic (c)) - { - sql_type t (parse_sql_type (column_type (*m), *m)); - rv = (t.type == sql_type::ROWVERSION); - } - - os << "static const bool rowversion = " << rv << ";" - << endl; - - // Disable bulk update if we have ROWVERSION since we don't - // yet support batch extraction of the version. - // - if (rv && c.count ("bulk-update")) - c.remove ("bulk-update"); - } - - virtual void - object_public_extra_post (type& c) - { - bool abst (abstract (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - if (poly_derived || (abst && !poly)) - return; - - if (semantics::data_member* m = optimistic (c)) - { - sql_type t (parse_sql_type (column_type (*m), *m)); - if (t.type == sql_type::ROWVERSION) - { - os << "static version_type" << endl - << "version (const id_image_type&);" - << endl; - } - } - } - }; - entry class1_entry_; - - struct section_traits: relational::section_traits, context - { - section_traits (base const& x): base (x) {} - - virtual void - section_public_extra_pre (user_section&) - { - if (abstract (c_) && !polymorphic (c_)) - return; - - // rowvesion - // - bool rv (false); - if (semantics::data_member* m = optimistic (c_)) - { - sql_type t (parse_sql_type (column_type (*m), *m)); - rv = (t.type == sql_type::ROWVERSION); - } - - os << "static const bool rowversion = " << rv << ";" - << endl; - } - }; - entry section_traits_; - - struct image_type: relational::image_type, context - { - image_type (base const& x): base (x) {}; - - virtual void - image_extra (type& c) - { - if (!(composite (c) || (abstract (c) && !polymorphic (c)))) - { - type* poly_root (polymorphic (c)); - - // If this is a polymorphic type, only add callback to the root. - // - if (poly_root == 0 || poly_root == &c) - { - bool gc (options.generate_query ()); - - if (gc) - os << "mssql::change_callback change_callback_;" - << endl; - - os << "mssql::change_callback*" << endl - << "change_callback ()" - << "{"; - - if (gc) - os << "return &change_callback_;"; - else - os << "return 0;"; - - os << "}"; - } - } - } - }; - entry image_type_; - - struct image_member: relational::image_member_impl, - member_base - { - image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_decimal (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_smallmoney (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_money (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_float4 (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_float8 (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - // Extra character for the null-terminator that ODBC always adds. - // - os << "char " << mi.var << "value[" << mi.st->prec + 1 << "];" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << "mutable " << image_type << " " << mi.var << "callback;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_nstring (member_info& mi) - { - // Extra character for the null-terminator that ODBC always adds. - // - os << "mssql::ucs2_char " << mi.var << "value[" << - mi.st->prec + 1 << "];" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_long_nstring (member_info& mi) - { - os << "mutable " << image_type << " " << mi.var << "callback;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_binary (member_info& mi) - { - os << "char " << mi.var << "value[" << mi.st->prec << "];" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_long_binary (member_info& mi) - { - os << "mutable " << image_type << " " << mi.var << "callback;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_date (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_time (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_datetime (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_datetimeoffset (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_uniqueidentifier (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - - virtual void - traverse_rowversion (member_info& mi) - { - os << "unsigned char " << mi.var << "value[8];" - << "SQLLEN " << mi.var << "size_ind;" - << endl; - } - }; - entry image_member_; - } - } -} diff --git a/odb/relational/mssql/inline.cxx b/odb/relational/mssql/inline.cxx deleted file mode 100644 index eb581d6..0000000 --- a/odb/relational/mssql/inline.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/relational/mssql/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mssql - { - namespace inline_ - { - namespace relational = relational::inline_; - - struct null_member: relational::null_member_impl, - member_base - { - null_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_simple (member_info& mi) - { - if (get_) - os << "r = r && i." << mi.var << "size_ind == SQL_NULL_DATA;"; - else - os << "i." << mi.var << "size_ind = SQL_NULL_DATA;"; - } - }; - entry null_member_; - } - } -} diff --git a/odb/relational/mssql/model.cxx b/odb/relational/mssql/model.cxx deleted file mode 100644 index 0f5a85c..0000000 --- a/odb/relational/mssql/model.cxx +++ /dev/null @@ -1,66 +0,0 @@ -// file : odb/relational/mssql/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mssql - { - namespace model - { - namespace relational = relational::model; - - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual string - default_enum (semantics::data_member& m, tree en, string const&) - { - // Make sure the column is mapped to an integer or DECIMAL type. - // - switch (parse_sql_type (column_type (), m, false).type) - { - case sql_type::BIT: - case sql_type::TINYINT: - case sql_type::SMALLINT: - case sql_type::INT: - case sql_type::BIGINT: - case sql_type::DECIMAL: - break; - default: - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column with default value specified as C++ " - << "enumerator must map to SQL Server integer type" << endl; - - throw operation_failed (); - } - } - - using semantics::enumerator; - - enumerator& e (dynamic_cast (*unit.find (en))); - - ostringstream ostr; - - if (e.enum_ ().unsigned_ ()) - ostr << e.value (); - else - ostr << static_cast (e.value ()); - - return ostr.str (); - } - }; - entry object_columns_; - } - } -} diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx deleted file mode 100644 index c5f6bc1..0000000 --- a/odb/relational/mssql/schema.cxx +++ /dev/null @@ -1,651 +0,0 @@ -// file : odb/relational/mssql/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mssql - { - namespace schema - { - namespace relational = relational::schema; - using relational::table_set; - - struct sql_emitter: relational::sql_emitter - { - sql_emitter (const base& x): base (x) {} - - virtual void - post () - { - if (!first_) // Ignore empty statements. - { - os << ';' << endl - << "GO" << endl - << endl; - } - } - }; - entry sql_emitter_; - - // - // File. - // - - struct sql_file: relational::sql_file, context - { - sql_file (const base& x): base (x) {} - - virtual void - prologue () - { - // Suppress the (x rows affected) messages from sqlcmd for DML - // statements. We only use DML for schema version management. - // - if ((model == 0 || model->version () != 0) && - !options.suppress_schema_version ()) - os << "SET NOCOUNT ON;" << endl - << endl; - } - }; - entry sql_file_; - - // - // Drop. - // - - struct drop_column: relational::drop_column, context - { - drop_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::drop_column& dc) - { - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - os << quote_id (dc.name ()); - } - }; - entry drop_column_; - - struct drop_foreign_key: relational::drop_foreign_key, context - { - drop_foreign_key (base const& x): base (x) {} - - virtual void - drop (sema_rel::table& t, sema_rel::foreign_key& fk) - { - bool migration (dropped_ == 0); - - if (migration) - { - if (fk.not_deferrable ()) - pre_statement (); - else - { - if (format_ != schema_format::sql) - return; - - os << "/*" << endl; - } - } - else - { - // Here we drop potentially deferrable keys and also need to - // test if the key exists. - // - pre_statement (); - - os << "IF OBJECT_ID(" << quote_string (fk.name ()) << ", " << - quote_string ("F") << ") IS NOT NULL" << endl - << " "; - } - - os << "ALTER TABLE " << quote_id (t.name ()) << endl - << (migration ? " " : " ") << "DROP CONSTRAINT " << - quote_id (fk.name ()) << endl; - - - if (!migration || fk.not_deferrable ()) - post_statement (); - else - os << "*/" << endl - << endl; - } - - virtual void - traverse (sema_rel::drop_foreign_key& dfk) - { - // Find the foreign key we are dropping in the base model. - // - sema_rel::foreign_key& fk (find (dfk)); - - bool c (!fk.not_deferrable () && !in_comment); - - if (c && format_ != schema_format::sql) - return; - - if (!first_) - os << (c ? "" : ",") << endl - << " "; - - if (c) - os << "/* "; - - os << quote_id (fk.name ()); - - if (c) - os << " */"; - - if (first_) - { - if (c) - // There has to be a real name otherwise the whole statement - // would have been commented out. - // - os << endl - << " "; - else - first_ = false; - } - } - }; - entry drop_foreign_key_; - - struct drop_index: relational::drop_index, context - { - drop_index (base const& x): base (x) {} - - virtual void - drop (sema_rel::index& in) - { - sema_rel::table& t (static_cast (in.scope ())); - - os << "DROP INDEX " << name (in) << " ON " << - quote_id (t.name ()) << endl; - } - }; - entry drop_index_; - - struct drop_table: relational::drop_table, context - { - drop_table (base const& x): base (x) {} - - virtual void - drop (sema_rel::table& t, bool migration) - { - // SQL Server has no IF EXISTS conditional for dropping tables. - // The following approach appears to be the recommended way to - // drop a table if it exists. - // - sema_rel::qname const& name (t.name ()); - - pre_statement (); - - if (!migration) - os << "IF OBJECT_ID(" << quote_string (name.string ()) << - ", " << quote_string ("U") << ") IS NOT NULL" << endl - << " "; - - os << "DROP TABLE " << quote_id (name) << endl; - - post_statement (); - } - }; - entry drop_table_; - - // - // Create. - // - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::add_column& ac) - { - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - create (ac); - } - - virtual void - auto_ (sema_rel::primary_key&) - { - os << " IDENTITY"; - } - }; - entry create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - void - diagnose (sema_rel::foreign_key& fk) - { - if (fk.on_delete () != sema_rel::foreign_key::no_action) - { - cerr << "warning: foreign key '" << fk.name () << "' has " << - "ON DELETE clause but is disabled in SQL Server due to lack " - "of deferrable constraint support" << endl; - - cerr << "info: consider using non-deferrable foreign keys (" << - "--fkeys-deferrable-mode)" << endl; - } - } - - virtual void - traverse_create (sema_rel::foreign_key& fk) - { - // SQL Server does not support deferrable constraint checking. - // Output such foreign keys as comments, for documentation, - // unless we are generating embedded schema. - // - if (fk.not_deferrable ()) - base::traverse_create (fk); - else - { - diagnose (fk); - - // Don't bloat C++ code with comment strings if we are - // generating embedded schema. - // - if (format_ != schema_format::sql) - return; - - os << endl - << " /*" << endl - << " CONSTRAINT "; - create (fk); - os << endl - << " */"; - } - } - - virtual void - traverse_add (sema_rel::foreign_key& fk) - { - bool c (!fk.not_deferrable () && !in_comment); - - if (c) - diagnose (fk); - - if (c && format_ != schema_format::sql) - return; - - if (!first_) - os << (c ? "" : ",") << endl - << " "; - - if (c) - os << "/*" << endl - << " "; - - os << "CONSTRAINT "; - create (fk); - - if (c) - os << endl - << " */"; - - if (first_) - { - if (c) - // There has to be a real key otherwise the whole statement - // would have been commented out. - // - os << endl - << " "; - else - first_ = false; - } - } - - virtual void - deferrable (sema_rel::deferrable) - { - // This will still be called to output the comment. - } - }; - entry create_foreign_key_; - - struct create_table: relational::create_table, context - { - create_table (base const& x): base (x) {} - - // See if there are any undefined foreign keys that are not - // deferrable. - // - bool - check_undefined_fk_deferrable_only (sema_rel::table& t) - { - for (sema_rel::table::names_iterator i (t.names_begin ()); - i != t.names_end (); ++i) - { - using sema_rel::foreign_key; - - if (foreign_key* fk = dynamic_cast (&i->nameable ())) - { - if (!fk->count ("mssql-fk-defined") && - fk->not_deferrable ()) - return false; - } - } - return true; - } - - virtual void - traverse (sema_rel::table& t) - { - if (pass_ == 1) - base::traverse (t); - else - { - // Add undefined foreign keys. - // - if (check_undefined_fk (t)) - { - bool deferrable (check_undefined_fk_deferrable_only (t)); - - if (!deferrable || format_ == schema_format::sql) - { - if (deferrable) - { - os << "/*" << endl; - in_comment = true; - } - else - pre_statement (); - - os << "ALTER TABLE " << quote_id (t.name ()) << endl - << " ADD "; - - instance cfk (*this); - trav_rel::unames n (*cfk); - names (t, n); - os << endl; - - if (deferrable) - { - in_comment = false; - os << "*/" << endl - << endl; - } - else - post_statement (); - } - } - } - } - }; - entry create_table_; - - // - // Alter. - // - - struct alter_column: relational::alter_column, context - { - alter_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::column& c) - { - // Relax (NULL) in pre and tighten (NOT NULL) in post. - // - if (pre_ != c.null ()) - return; - - using sema_rel::table; - table& at (static_cast (c.scope ())); - - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ALTER COLUMN "; - alter (c); - os << endl; - - post_statement (); - } - }; - entry alter_column_; - - struct alter_table_pre: relational::alter_table_pre, context - { - alter_table_pre (base const& x): base (x) {} - - // Check if we are only dropping deferrable foreign keys. - // - bool - check_drop_deferrable_only (sema_rel::alter_table& at) - { - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::foreign_key; - using sema_rel::drop_foreign_key; - - if (drop_foreign_key* dfk = - dynamic_cast (&i->nameable ())) - { - foreign_key& fk (find (*dfk)); - - if (fk.not_deferrable ()) - return false; - } - } - return true; - } - - virtual void - alter (sema_rel::alter_table& at) - { - // SQL Server can only alter one kind of thing at a time. - // - if (check (at)) - { - bool deferrable (check_drop_deferrable_only (at)); - - if (!deferrable || format_ == schema_format::sql) - { - if (deferrable) - { - os << "/*" << endl; - in_comment = true; - } - else - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " DROP CONSTRAINT "; - - instance dfc (*this); - trav_rel::unames n (*dfc); - names (at, n); - os << endl; - - if (deferrable) - { - in_comment = false; - os << "*/" << endl - << endl; - } - else - post_statement (); - } - } - - if (check (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ADD "; - - instance cc (*this); - trav_rel::unames n (*cc); - names (at, n); - os << endl; - - post_statement (); - } - - // For ALTER COLUMN, SQL Server can only have one per ALTER TABLE. - // - { - bool tl (true); // (Im)perfect forwarding. - instance ac (*this, tl); - trav_rel::unames n (*ac); - names (at, n); - } - } - }; - entry alter_table_pre_; - - struct alter_table_post: relational::alter_table_post, context - { - alter_table_post (base const& x): base (x) {} - - // Check if we are only adding deferrable foreign keys. - // - bool - check_add_deferrable_only (sema_rel::alter_table& at) - { - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::add_foreign_key; - - if (add_foreign_key* afk = - dynamic_cast (&i->nameable ())) - { - if (afk->not_deferrable ()) - return false; - } - } - return true; - } - - virtual void - alter (sema_rel::alter_table& at) - { - // SQL Server can only alter one kind of thing at a time. - // - if (check (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " DROP COLUMN "; - - instance dc (*this); - trav_rel::unames n (*dc); - names (at, n); - os << endl; - - post_statement (); - } - - // For ALTER COLUMN, SQL Server can only have one per ALTER TABLE. - // - { - bool fl (false); // (Im)perfect forwarding. - instance ac (*this, fl); - trav_rel::unames n (*ac); - names (at, n); - } - - if (check (at)) - { - bool deferrable (check_add_deferrable_only (at)); - - if (!deferrable || format_ == schema_format::sql) - { - if (deferrable) - { - os << "/*" << endl; - in_comment = true; - } - else - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ADD "; - - instance cfc (*this); - trav_rel::unames n (*cfc); - names (at, n); - os << endl; - - if (deferrable) - { - in_comment = false; - os << "*/" << endl - << endl; - } - else - post_statement (); - } - } - } - }; - entry alter_table_post_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x): base (x) {} - - virtual void - create_table () - { - pre_statement (); - - os << "IF OBJECT_ID(" << quote_string (table_.string ()) << - ", " << quote_string ("U") << ") IS NULL" << endl - << " CREATE TABLE " << qt_ << " (" << endl - << " " << qn_ << " VARCHAR(256) NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " BIGINT NOT NULL," << endl - << " " << qm_ << " BIT NOT NULL)" << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - os << "IF NOT EXISTS (SELECT 1 FROM " << qt_ << " WHERE " << qn_ << - " = " << qs_ << ")" << endl - << " INSERT INTO " << qt_ << " (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", 0)" << endl; - - post_statement (); - } - }; - entry version_table_; - } - } -} diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx deleted file mode 100644 index 573104d..0000000 --- a/odb/relational/mssql/source.cxx +++ /dev/null @@ -1,1201 +0,0 @@ -// file : odb/relational/mssql/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mssql - { - namespace source - { - namespace relational = relational::source; - - // - // - struct query_parameters: relational::query_parameters - { - query_parameters (base const& x): base (x) {} - - virtual string - auto_id (semantics::data_member&, const string&, const string&) - { - return ""; - } - }; - entry query_parameters_; - - // - // - struct object_columns: relational::object_columns, context - { - object_columns (base const& x) - : base (x), rowversion_ (false), column_count_ (0) {} - - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - // Don't add a column for auto id in the INSERT statement. - // Only simple, direct id can be auto. - // - if (sk_ == statement_insert && key_prefix_.empty () && auto_ (m)) - return false; - - // Don't update the ROWVERSION column explicitly. - // - if (sk_ == statement_update) - { - sql_type t (parse_sql_type (column_type (), m)); - if (t.type == sql_type::ROWVERSION) - { - rowversion_ = true; - return false; - } - } - - bool r (base::column (m, table, column)); - - // Count the number of columns in the UPDATE statement, but - // excluding soft-deleted. - // - if (sk_ == statement_update && r && !deleted (member_path_)) - column_count_++; - - return r; - } - - virtual void - traverse_post (semantics::nameable& n) - { - if (rowversion_ && column_count_ == 0) - { - location l (n.location ()); - error (l) << "ROWVERSION in an object without any readwrite " - "data members" << endl; - error (l) << "UPDATE statement will be empty" << endl; - throw operation_failed (); - } - } - - private: - bool rowversion_; - size_t column_count_; - }; - entry object_columns_; - - // - // - struct persist_statement_params: relational::persist_statement_params, - context - { - persist_statement_params (base const& x): base (x) {} - - virtual string - version_value (semantics::data_member& m) - { - sql_type t (parse_sql_type (column_type (), m)); - return t.type == sql_type::ROWVERSION ? "DEFAULT" : "1"; - } - }; - entry persist_statement_params_; - - // - // bind - // - - static const char* integer_buffer_types[] = - { - "mssql::bind::bit", - "mssql::bind::tinyint", - "mssql::bind::smallint", - "mssql::bind::int_", - "mssql::bind::bigint" - }; - - struct bind_member: relational::bind_member_impl, - member_base - { - bind_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_integer (member_info& mi) - { - os << b << ".type = " << - integer_buffer_types[mi.st->type - sql_type::BIT] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;"; - } - - virtual void - traverse_decimal (member_info& mi) - { - os << b << ".type = mssql::bind::decimal;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode precision (p) and scale (s) as (p * 100 + s). - // - << b << ".capacity = " << mi.st->prec * 100 + mi.st->scale << ";"; - } - - virtual void - traverse_smallmoney (member_info& mi) - { - os << b << ".type = mssql::bind::smallmoney;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;"; - } - - virtual void - traverse_money (member_info& mi) - { - os << b << ".type = mssql::bind::money;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;"; - } - - virtual void - traverse_float4 (member_info& mi) - { - os << b << ".type = mssql::bind::float4;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - << b << ".capacity = " << mi.st->prec << ";"; - } - - virtual void - traverse_float8 (member_info& mi) - { - os << b << ".type = mssql::bind::float8;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - << b << ".capacity = " << mi.st->prec << ";"; - } - - virtual void - traverse_string (member_info& mi) - { - os << b << ".type = mssql::bind::string;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - << b << ".capacity = static_cast (sizeof (" << - arg << "." << mi.var << "value));"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << b << ".type = mssql::bind::long_string;" - << b << ".buffer = &" << arg << "." << mi.var << "callback;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode the column size with 0 indicating unlimited. - // - << b << ".capacity = " << mi.st->prec << ";"; - } - - virtual void - traverse_nstring (member_info& mi) - { - os << b << ".type = mssql::bind::nstring;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - << b << ".capacity = static_cast (sizeof (" << - arg << "." << mi.var << "value));"; - } - - virtual void - traverse_long_nstring (member_info& mi) - { - os << b << ".type = mssql::bind::long_nstring;" - << b << ".buffer = &" << arg << "." << mi.var << "callback;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode the column size (in bytes) with 0 indicating unlimited. - // - << b << ".capacity = " << mi.st->prec * 2 << ";"; - } - - virtual void - traverse_binary (member_info& mi) - { - os << b << ".type = mssql::bind::binary;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - << b << ".capacity = static_cast (sizeof (" << - arg << "." << mi.var << "value));"; - } - - virtual void - traverse_long_binary (member_info& mi) - { - os << b << ".type = mssql::bind::long_binary;" - << b << ".buffer = &" << arg << "." << mi.var << "callback;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode the column size with 0 indicating unlimited. - // - << b << ".capacity = " << mi.st->prec << ";"; - } - - virtual void - traverse_date (member_info& mi) - { - os << b << ".type = mssql::bind::date;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;"; - } - - virtual void - traverse_time (member_info& mi) - { - os << b << ".type = mssql::bind::time;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode fractional seconds (scale). - // - << b << ".capacity = " << mi.st->scale << ";"; - } - - virtual void - traverse_datetime (member_info& mi) - { - unsigned short scale (0); - - switch (mi.st->type) - { - case sql_type::DATETIME: - { - // Looks like it is 3 (rounded to 0.000, 0.003, or 0.007). - // - scale = 3; - break; - } - case sql_type::DATETIME2: - { - scale = mi.st->scale; - break; - } - case sql_type::SMALLDATETIME: - { - // No seconds in SMALLDATATIME. Encode it a special precision - // value (8). - // - scale = 8; - break; - } - default: - { - assert (false); - break; - } - } - - os << b << ".type = mssql::bind::datetime;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode fractional seconds (scale). - // - << b << ".capacity = " << scale << ";"; - } - - virtual void - traverse_datetimeoffset (member_info& mi) - { - os << b << ".type = mssql::bind::datetimeoffset;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;" - // Encode fractional seconds (scale). - // - << b << ".capacity = " << mi.st->scale << ";"; - } - - virtual void - traverse_uniqueidentifier (member_info& mi) - { - os << b << ".type = mssql::bind::uniqueidentifier;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;"; - } - - virtual void - traverse_rowversion (member_info& mi) - { - os << b << ".type = mssql::bind::rowversion;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size_ind = &" << arg << "." << mi.var << "size_ind;"; - } - }; - entry bind_member_; - - // - // init image - // - - struct init_image_member: relational::init_image_member_impl, - member_base - { - init_image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - set_null (member_info& mi) - { - os << "i." << mi.var << "size_ind = SQL_NULL_DATA;"; - } - - virtual void - check_accessor (member_info& mi, member_access& ma) - { - // We cannot use accessors that return by-value for long data - // members. - // - if (long_data (*mi.st) && ma.by_value) - { - error (ma.loc) << "accessor returning a value cannot be used " - << "for a data member of SQL Server long data " - << "type" << endl; - info (ma.loc) << "accessor returning a const reference is required" - << endl; - info (mi.m.location ()) << "data member is defined here" << endl; - throw operation_failed (); - } - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_decimal (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_smallmoney (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 4;"; - } - - virtual void - traverse_money (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 8;"; - } - - virtual void - traverse_float4 (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_float8 (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - // Don't mention the extra character for the null-terminator. - << "sizeof (i." << mi.var << "value) - 1," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size_ind =" << endl - << " is_null ? SQL_NULL_DATA : static_cast (size);"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "callback.callback.param," << endl - << "i." << mi.var << "callback.context.param," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size_ind = is_null ? " << - "SQL_NULL_DATA : SQL_DATA_AT_EXEC;"; - } - - virtual void - traverse_nstring (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - // Don't mention the extra character for the null-terminator. - << "sizeof (i." << mi.var << "value) / 2 - 1," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size_ind =" << endl - << " is_null ? SQL_NULL_DATA : static_cast (size * 2);"; - } - - virtual void - traverse_long_nstring (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "callback.callback.param," << endl - << "i." << mi.var << "callback.context.param," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size_ind = is_null ? " << - "SQL_NULL_DATA : SQL_DATA_AT_EXEC;"; - } - - virtual void - traverse_binary (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "sizeof (i." << mi.var << "value)," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size_ind =" << endl - << " is_null ? SQL_NULL_DATA : static_cast (size);"; - } - - virtual void - traverse_long_binary (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "callback.callback.param," << endl - << "i." << mi.var << "callback.context.param," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "size_ind = is_null ? " << - "SQL_NULL_DATA : SQL_DATA_AT_EXEC;"; - } - - virtual void - traverse_date (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_time (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, " << mi.st->scale << ", " << - "is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null" << endl - << " ? SQL_NULL_DATA" << endl - << " : static_cast (sizeof (i." << mi.var << "value));"; - } - - virtual void - traverse_datetime (member_info& mi) - { - // The same code as in bind. - // - unsigned short scale (0); - - switch (mi.st->type) - { - case sql_type::DATETIME: - { - scale = 3; - break; - } - case sql_type::DATETIME2: - { - scale = mi.st->scale; - break; - } - case sql_type::SMALLDATETIME: - { - scale = 8; - break; - } - default: - { - assert (false); - break; - } - } - - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, " << scale << ", " << - "is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_datetimeoffset (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, " << mi.st->scale << ", " << - "is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null" << endl - << " ? SQL_NULL_DATA" << endl - << " : static_cast (sizeof (i." << mi.var << "value));"; - } - - virtual void - traverse_uniqueidentifier (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 0;"; - } - - virtual void - traverse_rowversion (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 8;"; - } - }; - entry init_image_member_; - - // - // init value - // - - struct init_value_member: relational::init_value_member_impl, - member_base - { - init_value_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - get_null (string const& var) const - { - os << "i." << var << "size_ind == SQL_NULL_DATA"; - } - - virtual void - check_modifier (member_info& mi, member_access& ma) - { - // We cannot use by-value modifier for long data members. - // - if (long_data (*mi.st) && ma.placeholder ()) - { - error (ma.loc) << "modifier accepting a value cannot be used " - << "for a data member of SQL Server long data " - << "type" << endl; - info (ma.loc) << "modifier returning a non-const reference is " - << "required" << endl; - info (mi.m.location ()) << "data member is defined here" << endl; - throw operation_failed (); - } - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_decimal (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_smallmoney (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_money (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_float4 (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_float8 (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "static_cast (i." << mi.var << "size_ind)," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "callback.callback.result," << endl - << "i." << mi.var << "callback.context.result);" - << endl; - } - - virtual void - traverse_nstring (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "static_cast (" << - "i." << mi.var << "size_ind / 2)," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_long_nstring (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "callback.callback.result," << endl - << "i." << mi.var << "callback.context.result);" - << endl; - } - - virtual void - traverse_binary (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "static_cast (i." << mi.var << "size_ind)," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_long_binary (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "callback.callback.result," << endl - << "i." << mi.var << "callback.context.result);" - << endl; - } - - virtual void - traverse_date (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_time (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_datetime (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_datetimeoffset (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_uniqueidentifier (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - - virtual void - traverse_rowversion (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size_ind == SQL_NULL_DATA);" - << endl; - } - }; - entry init_value_member_; - - struct statement_columns_common: context - { - void - process (relational::statement_columns& cols, - statement_kind sk, - bool dynamic) - { - using relational::statement_columns; - - // Long data columns must come last in the SELECT statement. If - // this statement is going to be processed at runtime, then this - // will be taken care of then. - // - if (sk != statement_select || dynamic) - return; - - // Go over the columns list while keeping track of how many - // columns we have examined. If the current column is long data, - // then move it to the back. Stop once we have examined all the - // columns. - // - size_t n (cols.size ()); - for (statement_columns::iterator i (cols.begin ()); n != 0; --n) - { - if (long_data (parse_sql_type (i->type, *i->member))) - { - cols.push_back (*i); - i = cols.erase (i); - } - else - ++i; - } - } - }; - - struct container_traits: relational::container_traits, - statement_columns_common - { - container_traits (base const& x): base (x) {} - - virtual void - cache_result (string const&) - { - // Caching is not necessary since with MARS enabled SQL Server - // can execute several interleaving statements. - // - } - - virtual void - init_value_extra () - { - os << "sts.select_statement ().stream_result ();" - << endl; - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool dynamic) - { - statement_columns_common::process (cols, sk, dynamic); - } - }; - entry container_traits_; - - struct section_traits: relational::section_traits, - statement_columns_common - { - section_traits (base const& x): base (x) {} - - virtual void - init_value_extra () - { - os << "st.stream_result ();"; - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool dynamic) - { - statement_columns_common::process (cols, sk, dynamic); - } - - virtual string - optimistic_version_increment (semantics::data_member& m) - { - sql_type t (parse_sql_type (column_type (m), m)); - return t.type != sql_type::ROWVERSION - ? "1" - : "version (sts.id_image ())"; - } - - virtual string - update_statement_extra (user_section&) - { - string r; - - semantics::data_member* ver (optimistic (c_)); - - if (ver == 0 || - parse_sql_type (column_type (*ver), *ver).type != - sql_type::ROWVERSION) - return r; - - // ROWVERSION & SQL Server 2005 incompatibility is detected - // in persist_statement_extra. - // - r = "OUTPUT INSERTED." + - convert_from (column_qname (*ver, column_prefix ()), *ver); - - return r; - } - }; - entry section_traits_; - - struct class_: relational::class_, statement_columns_common - { - class_ (base const& x): - base (x), init_version_value_member_id_image_ ("v", "version_") {} - - virtual void - init_image_pre (type& c) - { - if (options.generate_query () && - !(composite (c) || (abstract (c) && !polymorphic (c)))) - { - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - if (poly_derived) - os << "{" - << "root_traits::image_type& ri (root_image (i));" - << endl; - - string i (poly_derived ? "ri" : "i"); - - os << "if (" << i << ".change_callback_.callback != 0)" << endl - << "(" << i << ".change_callback_.callback) (" << - i << ".change_callback_.context);"; - - if (poly_derived) - os << "}"; - else - os << endl; - } - } - - virtual void - init_value_extra () - { - os << "st.stream_result ();"; - } - - virtual string - persist_statement_extra (type& c, - relational::query_parameters&, - persist_position p) - { - string r; - - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - // If we are a derived type in a polymorphic hierarchy, then - // auto id/version are handled by the root. - // - if (poly_derived) - return r; - - // See if we have auto id or ROWVERSION version. - // - data_member_path* id (id_member (c)); - semantics::data_member* ver (optimistic (c)); - - if (id != 0 && !auto_ (*id)) - id = 0; - - if (ver != 0) - { - sql_type t (parse_sql_type (column_type (*ver), *ver)); - if (t.type != sql_type::ROWVERSION) - ver = 0; - } - - if (id == 0 && ver == 0) - return r; - - // SQL Server 2005 has a bug that causes it to fail on an - // INSERT statement with the OUTPUT clause if data for one - // of the inserted columns is supplied at execution (long - // data). To work around this problem we use the less - // efficient batch of INSERT and SELECT statements. - // - if (options.mssql_server_version () <= mssql_version (9, 0)) - { - bool ld (false); - - if (c.count ("mssql-has-long-data")) - ld = c.get ("mssql-has-long-data"); - else - { - has_long_data t (ld); - t.traverse (c); - c.set ("mssql-has-long-data", ld); - } - - if (ld) - { - if (p == persist_after_values) - { - // SQL Server 2005 has no eqivalent of SCOPE_IDENTITY for - // ROWVERSION. - // - if (ver != 0) - { - error (c.location ()) << "in SQL Server 2005 ROWVERSION " << - "value cannot be retrieved for a persistent class " << - "containing long data" << endl; - throw operation_failed (); - } - - // We also cannot support bulk INSERT. - // - if (c.count ("bulk-persist")) - { - error (c.location ()) << "in SQL Server 2005 bulk " << - "persist operation cannot be implemented for a " << - "persistent class containing long data" << endl; - throw operation_failed (); - } - - r = "; SELECT " + - convert_from ("SCOPE_IDENTITY()", *id->back ()); - } - - return r; - } - } - - if (p == persist_after_columns) - { - r = "OUTPUT "; - - // Top-level auto id column. - // - if (id != 0) - r += "INSERTED." + - convert_from (column_qname (*id), *id->back ()); - - // Top-level version column. - // - if (ver != 0) - { - if (id != 0) - r += ','; - - r += "INSERTED." + convert_from ( - column_qname (*ver, column_prefix ()), *ver); - } - } - - return r; - } - - virtual string - update_statement_extra (type& c) - { - string r; - - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - // If we are a derived type in a polymorphic hierarchy, then - // version is handled by the root. - // - if (poly_derived) - return r; - - semantics::data_member* ver (optimistic (c)); - - if (ver == 0 || - parse_sql_type (column_type (*ver), *ver).type != - sql_type::ROWVERSION) - return r; - - // Long data & SQL Server 2005 incompatibility is detected - // in persist_statement_extra. - // - r = "OUTPUT INSERTED." + - convert_from (column_qname (*ver, column_prefix ()), *ver); - - return r; - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool dynamic) - { - statement_columns_common::process (cols, sk, dynamic); - } - - virtual string - optimistic_version_init (semantics::data_member& m, bool index) - { - sql_type t (parse_sql_type (column_type (m), m)); - return t.type != sql_type::ROWVERSION - ? "1" - : (index - ? "version (sts.id_image (i))" - : "version (sts.id_image ())"); - } - - virtual string - optimistic_version_increment (semantics::data_member& m, bool index) - { - sql_type t (parse_sql_type (column_type (m), m)); - return t.type != sql_type::ROWVERSION - ? "1" - : (index - ? "version (sts.id_image (i))" - : "version (sts.id_image ())"); - } - - virtual bool - optimistic_insert_bind_version (semantics::data_member& m) - { - sql_type t (parse_sql_type (column_type (m), m)); - return t.type == sql_type::ROWVERSION; - } - - virtual void - object_extra (type& c) - { - bool abst (abstract (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - if (poly_derived || (abst && !poly)) - return; - - if (semantics::data_member* m = optimistic (c)) - { - sql_type t (parse_sql_type (column_type (*m), *m)); - if (t.type == sql_type::ROWVERSION) - { - string const& type (class_fq_name (c)); - string traits ("access::object_traits_impl< " + type + ", id_" + - db.string () + " >"); - - os << traits << "::version_type" << endl - << traits << "::" << endl - << "version (const id_image_type& i)" - << "{" - << "version_type v;"; - init_version_value_member_id_image_->traverse (*m); - os << "return v;" - << "}"; - } - } - } - - virtual string - from_trailer (type& c) - { - return c.get ("query").for_update - ? " WITH (UPDLOCK)" - : ""; - } - - virtual string - select_trailer (type&) {return "";} - - private: - // Go via the dynamic creation to get access to the constructor. - // - instance - init_version_value_member_id_image_; - }; - entry class_entry_; - } - } -} diff --git a/odb/relational/mysql/common.cxx b/odb/relational/mysql/common.cxx deleted file mode 100644 index d049443..0000000 --- a/odb/relational/mysql/common.cxx +++ /dev/null @@ -1,400 +0,0 @@ -// file : odb/relational/mysql/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace relational -{ - namespace mysql - { - // - // member_base - // - - sql_type const& member_base:: - member_sql_type (semantics::data_member& m) - { - return parse_sql_type (column_type (m, key_prefix_), m); - } - - void member_base:: - traverse_simple (member_info& mi) - { - switch (mi.st->type) - { - // Integral types. - // - case sql_type::TINYINT: - case sql_type::SMALLINT: - case sql_type::MEDIUMINT: - case sql_type::INT: - case sql_type::BIGINT: - { - traverse_integer (mi); - break; - } - - // Float types. - // - case sql_type::FLOAT: - case sql_type::DOUBLE: - { - traverse_float (mi); - break; - } - case sql_type::DECIMAL: - { - traverse_decimal (mi); - break; - } - - // Data-time types. - // - case sql_type::DATE: - case sql_type::TIME: - case sql_type::DATETIME: - case sql_type::TIMESTAMP: - case sql_type::YEAR: - { - traverse_date_time (mi); - break; - } - - // String and binary types. - // - case sql_type::CHAR: - case sql_type::VARCHAR: - case sql_type::TINYTEXT: - case sql_type::TEXT: - case sql_type::MEDIUMTEXT: - case sql_type::LONGTEXT: - { - // For string types the limit is in characters rather - // than in bytes. The fixed-length pre-allocated buffer - // optimization can only be used for 1-byte encodings. - // To support this we will need the character encoding - // in sql_type. - // - traverse_long_string (mi); - break; - } - case sql_type::BINARY: - case sql_type::TINYBLOB: - { - // BINARY's range is always 255 or less from MySQL 5.0.3. - // TINYBLOB can only store up to 255 bytes. - // - traverse_short_string (mi); - break; - } - case sql_type::VARBINARY: - case sql_type::BLOB: - case sql_type::MEDIUMBLOB: - case sql_type::LONGBLOB: - { - if (mi.st->range && mi.st->range_value <= 255) - traverse_short_string (mi); - else - traverse_long_string (mi); - - break; - } - - // Other types. - // - case sql_type::BIT: - { - traverse_bit (mi); - break; - } - case sql_type::ENUM: - { - traverse_enum (mi); - break; - } - case sql_type::SET: - { - traverse_set (mi); - break; - } - case sql_type::invalid: - { - assert (false); - break; - } - } - } - - // - // member_image_type - // - - static const char* integer_types[] = - { - "char", - "short", - "int", - "int", - "long long" - }; - - static const char* float_types[] = - { - "float", - "double" - }; - - member_image_type:: - member_image_type (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_image_type:: - member_image_type () - : relational::member_base (0, 0, string (), string ()) {} - - member_image_type:: - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, ct, fq_type, key_prefix) {} - - string member_image_type:: - image_type (semantics::data_member& m) - { - type_.clear (); - member_base::traverse (m, true); - return type_; - } - - void member_image_type:: - traverse_composite (member_info& mi) - { - type_ = "composite_value_traits< " + mi.fq_type () + - ", id_mysql >::image_type"; - } - - void member_image_type:: - traverse_integer (member_info& mi) - { - if (mi.st->unsign) - type_ = "unsigned "; - else if (mi.st->type == sql_type::TINYINT) - type_ = "signed "; - - type_ += integer_types[mi.st->type - sql_type::TINYINT]; - } - - void member_image_type:: - traverse_float (member_info& mi) - { - type_ = float_types[mi.st->type - sql_type::FLOAT]; - } - - void member_image_type:: - traverse_decimal (member_info&) - { - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_date_time (member_info& mi) - { - if (mi.st->type == sql_type::YEAR) - type_ = "short"; - else - type_ = "MYSQL_TIME"; - } - - void member_image_type:: - traverse_string (member_info&) - { - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_bit (member_info&) - { - type_ = "unsigned char*"; - } - - void member_image_type:: - traverse_enum (member_info& mi) - { - // Represented as either integer or string. - // - type_ = "mysql::value_traits< " + mi.fq_type () + - ", mysql::id_enum >::image_type"; - } - - void member_image_type:: - traverse_set (member_info&) - { - // Represented as string. - // - type_ = "details::buffer"; - } - - entry member_image_type_; - - // - // member_database_type - // - - static const char* integer_database_id[] = - { - "id_tiny", - "id_utiny", - "id_short", - "id_ushort", - "id_long", // INT24 - "id_ulong", // INT24 UNSIGNED - "id_long", - "id_ulong", - "id_longlong", - "id_ulonglong" - }; - - static const char* float_database_id[] = - { - "id_float", - "id_double" - }; - - static const char* date_time_database_id[] = - { - "id_date", - "id_time", - "id_datetime", - "id_timestamp", - "id_year" - }; - - static const char* char_bin_database_id[] = - { - "id_string", // CHAR - "id_blob", // BINARY, - "id_string", // VARCHAR - "id_blob", // VARBINARY - "id_string", // TINYTEXT - "id_blob", // TINYBLOB - "id_string", // TEXT - "id_blob", // BLOB - "id_string", // MEDIUMTEXT - "id_blob", // MEDIUMBLOB - "id_string", // LONGTEXT - "id_blob" // LONGBLOB - }; - - member_database_type_id:: - member_database_type_id (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_database_type_id:: - member_database_type_id () - : member_base::base (0, 0, string (), string ()), // virtual base - base (0, 0, string (), string ()) {} - - member_database_type_id:: - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base::base (type, ct, fq_type, key_prefix), // virtual base - base (type, ct, fq_type, key_prefix) {} - - string member_database_type_id:: - database_type_id (type& m) - { - type_id_.clear (); - member_base::traverse (m, true); - return type_id_; - } - - void member_database_type_id:: - traverse_composite (member_info&) - { - assert (false); - } - - void member_database_type_id:: - traverse_integer (member_info& mi) - { - size_t i ( - (mi.st->type - sql_type::TINYINT) * 2 + (mi.st->unsign ? 1 : 0)); - type_id_ = string ("mysql::") + integer_database_id[i]; - } - - void member_database_type_id:: - traverse_float (member_info& mi) - { - type_id_ = string ("mysql::") + - float_database_id[mi.st->type - sql_type::FLOAT]; - } - - void member_database_type_id:: - traverse_decimal (member_info&) - { - type_id_ = "mysql::id_decimal"; - } - - void member_database_type_id:: - traverse_date_time (member_info& mi) - { - type_id_ = string ("mysql::") + - date_time_database_id[mi.st->type - sql_type::DATE]; - } - - void member_database_type_id:: - traverse_string (member_info& mi) - { - type_id_ = string ("mysql::") + - char_bin_database_id[mi.st->type - sql_type::CHAR]; - } - - void member_database_type_id:: - traverse_bit (member_info&) - { - type_id_ = "mysql::id_bit"; - } - - void member_database_type_id:: - traverse_enum (member_info&) - { - type_id_ = "mysql::id_enum"; - } - - void member_database_type_id:: - traverse_set (member_info&) - { - type_id_ = "mysql::id_set"; - } - - entry member_database_type_id_; - - // - // query_columns - // - - struct query_columns: relational::query_columns, context - { - query_columns (base const& x): base_impl (x) {} - - virtual string - database_type_id (semantics::data_member& m) - { - return member_database_type_id_.database_type_id (m); - } - - private: - member_database_type_id member_database_type_id_; - }; - entry query_columns_; - } -} diff --git a/odb/relational/mysql/common.hxx b/odb/relational/mysql/common.hxx deleted file mode 100644 index b43dc0d..0000000 --- a/odb/relational/mysql/common.hxx +++ /dev/null @@ -1,171 +0,0 @@ -// file : odb/relational/mysql/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_MYSQL_COMMON_HXX -#define ODB_RELATIONAL_MYSQL_COMMON_HXX - -#include -#include - -namespace relational -{ - namespace mysql - { - struct member_base: virtual relational::member_base_impl, context - { - member_base (base const& x): base (x), base_impl (x) {} - - // This c-tor is for the direct use inside the mysql namespace. - // If you do use this c-tor, you should also explicitly call - // relational::member_base (aka base). - // - member_base () {} - - virtual sql_type const& - member_sql_type (semantics::data_member&); - - virtual void - traverse_simple (member_info&); - - virtual void - traverse_integer (member_info&) - { - } - - virtual void - traverse_float (member_info&) - { - } - - virtual void - traverse_decimal (member_info&) - { - } - - virtual void - traverse_date_time (member_info&) - { - } - - virtual void - traverse_string (member_info&) - { - } - - virtual void - traverse_short_string (member_info& mi) - { - traverse_string (mi); - } - - virtual void - traverse_long_string (member_info& mi) - { - traverse_string (mi); - } - - virtual void - traverse_bit (member_info&) - { - } - - virtual void - traverse_enum (member_info&) - { - } - - virtual void - traverse_set (member_info&) - { - } - }; - - struct member_image_type: relational::member_image_type, - member_base - { - member_image_type (base const&); - member_image_type (); - member_image_type (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - virtual string - image_type (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_float (member_info&); - - virtual void - traverse_decimal (member_info&); - - virtual void - traverse_date_time (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_bit (member_info&); - - virtual void - traverse_enum (member_info&); - - virtual void - traverse_set (member_info&); - - private: - string type_; - }; - - struct member_database_type_id: relational::member_database_type_id, - member_base - { - member_database_type_id (base const&); - member_database_type_id (); - member_database_type_id (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - - virtual string - database_type_id (type&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_float (member_info&); - - virtual void - traverse_decimal (member_info&); - - virtual void - traverse_date_time (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_bit (member_info&); - - virtual void - traverse_enum (member_info&); - - virtual void - traverse_set (member_info&); - - private: - string type_id_; - }; - } -} -#endif // ODB_RELATIONAL_MYSQL_COMMON_HXX diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx deleted file mode 100644 index 8b3d983..0000000 --- a/odb/relational/mysql/context.cxx +++ /dev/null @@ -1,868 +0,0 @@ -// file : odb/relational/mysql/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -#include -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mysql - { - namespace - { - struct type_map_entry - { - char const* const cxx_type; - char const* const db_type; - char const* const db_id_type; - bool const null; - }; - - type_map_entry type_map[] = - { - {"bool", "TINYINT(1)", 0, false}, - - {"char", "CHAR(1)", 0, false}, - {"signed char", "TINYINT", 0, false}, - {"unsigned char", "TINYINT UNSIGNED", 0, false}, - - {"short int", "SMALLINT", 0, false}, - {"short unsigned int", "SMALLINT UNSIGNED", 0, false}, - - {"int", "INT", 0, false}, - {"unsigned int", "INT UNSIGNED", 0, false}, - - {"long int", "BIGINT", 0, false}, - {"long unsigned int", "BIGINT UNSIGNED", 0, false}, - - {"long long int", "BIGINT", 0, false}, - {"long long unsigned int", "BIGINT UNSIGNED", 0, false}, - - {"float", "FLOAT", 0, false}, - {"double", "DOUBLE", 0, false}, - - {"::std::string", "TEXT", "VARCHAR(128)", false}, - - {"::size_t", "BIGINT UNSIGNED", 0, false}, - {"::std::size_t", "BIGINT UNSIGNED", 0, false} - }; - } - - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context (ostream& os, - semantics::unit& u, - options_type const& ops, - features_type& f, - sema_rel::model* m) - : root_context (os, u, ops, f, data_ptr (new (shared) data (os))), - base_context (static_cast (root_context::data_.get ()), m), - data_ (static_cast (base_context::data_)) - { - assert (current_ == 0); - current_ = this; - - generate_grow = true; - need_alias_as = true; - insert_send_auto_id = true; - delay_freeing_statement_result = false; - need_image_clone = false; - generate_bulk = false; - global_index = false; - global_fkey = true; - data_->bind_vector_ = "MYSQL_BIND*"; - data_->truncated_vector_ = "my_bool*"; - - // Populate the C++ type to DB type map. - // - for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i) - { - type_map_entry const& e (type_map[i]); - - type_map_type::value_type v ( - e.cxx_type, - db_type_type ( - e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null)); - - data_->type_map_.insert (v); - } - } - - context:: - context () - : data_ (current ().data_) - { - } - - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - - string context:: - quote_id_impl (qname const& id) const - { - string r; - - bool f (true); - for (qname::iterator i (id.begin ()); i < id.end (); ++i) - { - if (i->empty ()) - continue; - - // Warn if the name is greater than the 64 limit. - // - if (i->size () > 64) - { - cerr << "warning: SQL name '" << *i << "' is longer than " - << "the MySQL name limit of 64 characters and will " - << "be truncated" << endl; - - cerr << "info: consider shortening it using #pragma db " - << "table/column/index or --*-regex options" << endl; - } - - if (f) - f = false; - else - r += '.'; - - r += '`'; - r.append (*i, 0, 64); // Max identifier length is 64. - r += '`'; - } - - return r; - } - - namespace - { - struct has_grow: traversal::class_ - { - has_grow (bool& r, user_section* s) - : r_ (r), section_ (s) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - bool view (context::view (c)); - - // Ignore transient bases. - // - if (!(context::object (c) || view || context::composite (c))) - return; - - if (section_ == 0 && c.count ("mysql-grow")) - r_ = c.get ("mysql-grow"); - else - { - // r_ should be false. - // - if (!view) - inherits (c); - - if (!r_) - names (c); - - if (section_ == 0) - c.set ("mysql-grow", r_); - } - } - - private: - bool& r_; - user_section* section_; - traversal::inherits inherits_; - }; - - struct has_grow_member: member_base - { - has_grow_member (bool& r, user_section* section = 0) - : relational::member_base (0, 0, string (), string (), section), - r_ (r) {} - - has_grow_member (bool& r, - user_section* section, - semantics::type* t, - const custom_cxx_type* ct, - string const& key_prefix = string ()) - : relational::member_base (t, ct, string (), key_prefix, section), - r_ (r) {} - - virtual bool - pre (member_info& mi) - { - // If we have a key prefix (container), then it can't be in a - // section (while mi.m can). The same for top-level -- if we got - // called, then we shouldn't ignore it. - // - return !key_prefix_.empty () || top_level_ || - (section_ == 0 && !separate_load (mi.m)) || - (section_ != 0 && *section_ == section (mi.m)); - } - - virtual void - traverse_composite (member_info& mi) - { - // By calling grow() instead of recursing, we reset any overrides. - // We also don't pass section since they don't apply inside - // composites. - // - r_ = r_ || context::grow (dynamic_cast (mi.t)); - } - - virtual void - traverse_decimal (member_info&) - { - r_ = true; - } - - virtual void - traverse_long_string (member_info&) - { - r_ = true; - } - - virtual void - traverse_short_string (member_info&) - { - r_ = true; // @@ Short string optimization disabled. - } - - virtual void - traverse_enum (member_info&) - { - r_ = true; - } - - virtual void - traverse_set (member_info&) - { - r_ = true; - } - - private: - bool& r_; - }; - } - - bool context:: - grow_impl (semantics::class_& c, user_section* section) - { - if (section == 0 && c.count ("mysql-grow")) - return c.get ("mysql-grow"); - - bool r (false); - has_grow ct (r, section); - has_grow_member mt (r, section); - traversal::names names; - ct >> names >> mt; - ct.traverse (c); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m) - { - bool r (false); - has_grow_member mt (r); - mt.traverse (m, true); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m, - semantics::type& t, - const custom_cxx_type* ct, - string const& kp) - { - bool r (false); - has_grow_member mt (r, 0, &t, ct, kp); - mt.traverse (m, true); - return r; - } - - string context:: - database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) - { - using semantics::enum_; - using semantics::enumerator; - using semantics::array; - - string r; - - // Enum mapping. - // - if (enum_* e = dynamic_cast (&t)) - { - // We can only map to ENUM if the C++ enumeration is contiguous - // and starts with 0. - // - enum_::enumerates_iterator i (e->enumerates_begin ()), - end (e->enumerates_end ()); - - if (i != end) - { - r += "ENUM("; - - for (unsigned long long j (0); i != end; ++i, ++j) - { - enumerator const& er (i->enumerator ()); - - if (er.value () != j) - break; - - if (j != 0) - r += ", "; - - r += quote_string (er.name ()); - } - - if (i == end) - r += ")"; - else - r.clear (); - } - - if (!r.empty ()) - return r; - } - - r = base_context::database_type_impl (t, hint, id, null); - - if (!r.empty ()) - return r; - - // char[N] mapping. - // - else if (array* a = dynamic_cast (&t)) - { - semantics::type& bt (a->base_type ()); - if (bt.is_a ()) - { - unsigned long long n (a->size ()); - - if (n == 0) - return r; - else if (n == 1) - r = "CHAR("; - else - { - r = "VARCHAR("; - n--; - } - - ostringstream ostr; - ostr << n; - r += ostr.str (); - r += ')'; - } - } - - return r; - } - - // - // SQL type parsing. - // - - sql_type const& context:: - parse_sql_type (string const& t, semantics::data_member& m, bool custom) - { - // If this proves to be too expensive, we can maintain a cache of - // parsed types across contexts. - // - data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - - if (i != data_->sql_type_cache_.end () - && (custom ? i->second.custom_cached : i->second.straight_cached)) - { - return (custom ? i->second.custom : i->second.straight); - } - else - { - try - { - sql_type st ( - parse_sql_type ( - t, - custom ? &unit.get ("custom-db-types") : 0)); - - if (custom) - return data_->sql_type_cache_[t].cache_custom (st); - else - return data_->sql_type_cache_[t].cache_straight (st); - } - catch (invalid_sql_type const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: " << e.message () << endl; - - throw operation_failed (); - } - } - } - - inline sql_type - error (bool fail, string const& m) - { - if (!fail) - return sql_type (); - else - throw context::invalid_sql_type (m); - } - - sql_type context:: - parse_sql_type (string sqlt, custom_db_types const* ct) - { - try - { - sql_type r; - - // First run the type through the custom mapping, if requested. - // - if (ct != 0) - { - for (custom_db_types::const_iterator i (ct->begin ()); - i != ct->end (); ++i) - { - custom_db_type const& t (*i); - - if (t.type.match (sqlt)) - { - r.to = t.type.replace (sqlt, t.to); - r.from = t.type.replace (sqlt, t.from); - sqlt = t.type.replace (sqlt, t.as); - break; - } - } - } - - sql_lexer l (sqlt); - - // While most type names use single identifier, there are - // a couple of exceptions to this rule: - // - // NATIONAL CHAR|VARCHAR - // CHAR BYTE (BINARY) - // CHARACTER VARYING (VARCHAR) - // LONG VARBINARY (MEDIUMBLOB) - // LONG VARCHAR (MEDIUMTEXT) - // - // - enum state - { - parse_prefix, - parse_name, - parse_range, - parse_sign, - parse_done - }; - - state s (parse_prefix); - string prefix; - bool flt (false); - - for (sql_token t (l.next ()); - s != parse_done && t.type () != sql_token::t_eos; - t = l.next ()) - { - sql_token::token_type tt (t.type ()); - - switch (s) - { - case parse_prefix: - { - if (tt == sql_token::t_identifier) - { - string const& id (context::upcase (t.identifier ())); - - if (id == "NATIONAL" || - id == "CHAR" || - id == "CHARACTER" || - id == "LONG") - { - prefix = id; - s = parse_name; - continue; - } - } - - s = parse_name; - } - // Fall through. - case parse_name: - { - if (tt == sql_token::t_identifier) - { - bool match (true); - string const& id (context::upcase (t.identifier ())); - - // Numeric types. - // - if (id == "BIT") - { - r.type = sql_type::BIT; - } - else if (id == "TINYINT" || id == "INT1") - { - r.type = sql_type::TINYINT; - } - else if (id == "BOOL" || id == "BOOLEAN") - { - r.type = sql_type::TINYINT; - r.range = true; - r.range_value = 1; - } - else if (id == "SMALLINT" || id == "INT2") - { - r.type = sql_type::SMALLINT; - } - else if (id == "MEDIUMINT" || - id == "INT3" || - id == "MIDDLEINT") - { - r.type = sql_type::MEDIUMINT; - } - else if (id == "INT" || id == "INTEGER" || id == "INT4") - { - r.type = sql_type::INT; - } - else if (id == "BIGINT" || id == "INT8") - { - r.type = sql_type::BIGINT; - } - else if (id == "SERIAL") - { - r.type = sql_type::BIGINT; - r.unsign = true; - } - else if (id == "FLOAT") - { - // Assign a type only once we know the precision of the - // float; it can be either 4 or 8 byte. - // - flt = true; - } - else if (id == "FLOAT4") - { - r.type = sql_type::FLOAT; - } - else if (id == "DOUBLE" || id == "FLOAT8") - { - r.type = sql_type::DOUBLE; - } - else if (id == "DECIMAL" || - id == "DEC" || - id == "NUMERIC" || - id == "FIXED") - { - r.type = sql_type::DECIMAL; - } - // - // Date-time types. - // - else if (id == "DATE") - { - r.type = sql_type::DATE; - } - else if (id == "TIME") - { - r.type = sql_type::TIME; - } - else if (id == "DATETIME") - { - r.type = sql_type::DATETIME; - } - else if (id == "TIMESTAMP") - { - r.type = sql_type::TIMESTAMP; - } - else if (id == "YEAR") - { - r.type = sql_type::YEAR; - } - // - // String and binary types. - // - else if (id == "NCHAR") - { - r.type = sql_type::CHAR; - } - else if (id == "VARCHAR") - { - r.type = prefix == "LONG" - ? sql_type::MEDIUMTEXT - : sql_type::VARCHAR; - } - else if (id == "NVARCHAR") - { - r.type = sql_type::VARCHAR; - } - else if (id == "VARYING" && prefix == "CHARACTER") - { - r.type = sql_type::VARCHAR; - } - else if (id == "BINARY") - { - r.type = sql_type::BINARY; - } - else if (id == "BYTE" && prefix == "CHAR") - { - r.type = sql_type::BINARY; - } - else if (id == "VARBINARY") - { - r.type = prefix == "LONG" - ? sql_type::MEDIUMBLOB - : sql_type::VARBINARY; - } - else if (id == "TINYBLOB") - { - r.type = sql_type::TINYBLOB; - } - else if (id == "TINYTEXT") - { - r.type = sql_type::TINYTEXT; - } - else if (id == "BLOB") - { - r.type = sql_type::BLOB; - } - else if (id == "TEXT") - { - r.type = sql_type::TEXT; - } - else if (id == "MEDIUMBLOB") - { - r.type = sql_type::MEDIUMBLOB; - } - else if (id == "MEDIUMTEXT") - { - r.type = sql_type::MEDIUMTEXT; - } - else if (id == "LONGBLOB") - { - r.type = sql_type::LONGBLOB; - } - else if (id == "LONGTEXT") - { - r.type = sql_type::LONGTEXT; - } - else if (id == "ENUM") - { - r.type = sql_type::ENUM; - } - else if (id == "SET") - { - r.type = sql_type::SET; - } - else - match = false; - - if (match) - { - s = parse_range; - continue; - } - } - - // Some prefixes can also be type names if not followed - // by the actual type name. - // - if (!prefix.empty ()) - { - if (prefix == "CHAR" || prefix == "CHARACTER") - { - r.type = sql_type::CHAR; - } - else if (prefix == "LONG") - { - r.type = sql_type::MEDIUMTEXT; - } - } - - if (r.type == sql_type::invalid) - { - if (tt == sql_token::t_identifier) - { - return error (ct, "unknown MySQL type '" + t.identifier () + - "'"); - } - else - return error (ct, "expected MySQL type name"); - } - - s = parse_range; - } - // Fall through. - case parse_range: - { - if (t.punctuation () == sql_token::p_lparen) - { - t = l.next (); - - // ENUM and SET have a list of members instead of the range. - // - if (r.type == sql_type::ENUM || r.type == sql_type::SET) - { - while (true) - { - if (t.type () != sql_token::t_string_lit) - { - return error (ct, "string literal expected in MySQL " - "ENUM or SET declaration"); - } - - if (r.type == sql_type::ENUM) - r.enumerators.push_back (t.literal ()); - - t = l.next (); - - if (t.punctuation () == sql_token::p_rparen) - break; - else if (t.punctuation () != sql_token::p_comma) - { - return error (ct, "comma expected in MySQL ENUM or " - "SET declaration"); - } - - t = l.next (); - } - } - else - { - if (t.type () != sql_token::t_int_lit) - { - return error (ct, "integer range expected in MySQL type " - "declaration"); - } - - unsigned int v; - istringstream is (t.literal ()); - - if (!(is >> v && is.eof ())) - { - return error (ct, "invalid range value '" + t.literal () + - "' in MySQL type declaration"); - } - - r.range = true; - r.range_value = v; - - t = l.next (); - - if (t.punctuation () == sql_token::p_comma) - { - // We have the second range value. Skip it. - // - // In FLOAT the two-value range means something - // completely different than the single-value. - // Pretend we don't have the range in the former - // case. - // - if (flt) - r.range = false; - - l.next (); - t = l.next (); - } - } - - if (t.punctuation () != sql_token::p_rparen) - { - return error (ct, "expected ')' in MySQL type declaration"); - } - - s = parse_sign; - continue; - } - - s = parse_sign; - } - // Fall through. - case parse_sign: - { - if (tt == sql_token::t_identifier && - context::upcase (t.identifier ()) == "UNSIGNED") - { - r.unsign = true; - } - - s = parse_done; - break; - } - case parse_done: - { - assert (false); - break; - } - } - } - - if (s == parse_name && !prefix.empty ()) - { - // Some prefixes can also be type names if not followed - // by the actual type name. - // - if (prefix == "CHAR" || prefix == "CHARACTER") - { - r.type = sql_type::CHAR; - } - else if (prefix == "LONG") - { - r.type = sql_type::MEDIUMTEXT; - } - } - - if (flt) - { - r.type = !r.range || r.range_value < 24 - ? sql_type::FLOAT - : sql_type::DOUBLE; - } - - if (r.type == sql_type::invalid) - return error (ct, "incomplete MySQL type declaration"); - - // If range is omitted for CHAR or BIT types, it defaults to 1. - // - if ((r.type == sql_type::CHAR || r.type == sql_type::BIT) && !r.range) - { - r.range = true; - r.range_value = 1; - } - - return r; - } - catch (sql_lexer::invalid_input const& e) - { - return error (ct, "invalid MySQL type declaration: " + e.message); - } - } - } -} diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx deleted file mode 100644 index 98574f2..0000000 --- a/odb/relational/mysql/context.hxx +++ /dev/null @@ -1,194 +0,0 @@ -// file : odb/relational/mysql/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_MYSQL_CONTEXT_HXX -#define ODB_RELATIONAL_MYSQL_CONTEXT_HXX - -#include -#include - -#include - -namespace relational -{ - namespace mysql - { - struct sql_type - { - // Keep the order in each block of types. - // - enum core_type - { - // Integral types. - // - TINYINT, - SMALLINT, - MEDIUMINT, - INT, - BIGINT, - - // Float types. - // - FLOAT, - DOUBLE, - DECIMAL, - - // Data-time types. - // - DATE, - TIME, - DATETIME, - TIMESTAMP, - YEAR, - - // String and binary types. - // - CHAR, - BINARY, - VARCHAR, - VARBINARY, - TINYTEXT, - TINYBLOB, - TEXT, - BLOB, - MEDIUMTEXT, - MEDIUMBLOB, - LONGTEXT, - LONGBLOB, - - // Other types. - // - BIT, - ENUM, - SET, - - // Invalid type. - // - invalid - }; - - sql_type () : type (invalid), unsign (false), range (false) {} - - core_type type; - bool unsign; - bool range; - unsigned int range_value; // MySQL max value is 2^32 - 1 (LONGBLOG/TEXT). - std::vector enumerators; // Enumerator strings for ENUM. - - // Conversion expressions for custom database types. - // - std::string to; - std::string from; - }; - - class context: public virtual relational::context - { - public: - sql_type const& - parse_sql_type (string const&, - semantics::data_member&, - bool custom = true); - public: - struct invalid_sql_type - { - invalid_sql_type (string const& message): message_ (message) {} - - string const& - message () const {return message_;} - - private: - string message_; - }; - - // If custom_db_types is NULL, then this function returns - // invalid type instead of throwing in case an unknown type - // is encountered. - // - static sql_type - parse_sql_type (string, custom_db_types const* = 0); - - protected: - virtual string const& - convert_expr (string const&, semantics::data_member&, bool); - - virtual bool - grow_impl (semantics::class_&, user_section*); - - virtual bool - grow_impl (semantics::data_member&); - - virtual bool - grow_impl (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const&); - - protected: - virtual string - quote_id_impl (qname const&) const; - - protected: - virtual string - database_type_impl (semantics::type&, semantics::names*, bool, bool*); - - public: - virtual - ~context (); - context (); - context (std::ostream&, - semantics::unit&, - options_type const&, - features_type&, - sema_rel::model*); - - static context& - current () - { - return *current_; - } - - private: - static context* current_; - - private: - struct data: base_context::data - { - data (std::ostream& os): base_context::data (os) {} - - struct sql_type_cache_entry - { - sql_type_cache_entry () - : custom_cached (false), straight_cached (false) {} - - sql_type const& - cache_custom (sql_type const& t) - { - custom = t; - custom_cached = true; - return custom; - } - - sql_type const& - cache_straight (sql_type const& t) - { - straight = t; - straight_cached = true; - return straight; - } - - sql_type custom; // With custom mapping. - sql_type straight; // Without custom mapping. - - bool custom_cached; - bool straight_cached; - }; - - typedef std::map sql_type_cache; - sql_type_cache sql_type_cache_; - }; - data* data_; - }; - } -} - -#endif // ODB_RELATIONAL_MYSQL_CONTEXT_HXX diff --git a/odb/relational/mysql/header.cxx b/odb/relational/mysql/header.cxx deleted file mode 100644 index 27bae48..0000000 --- a/odb/relational/mysql/header.cxx +++ /dev/null @@ -1,136 +0,0 @@ -// file : odb/relational/mysql/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -namespace relational -{ - namespace mysql - { - namespace header - { - namespace relational = relational::header; - - struct image_member: relational::image_member_impl, - member_base - { - image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_decimal (member_info& mi) - { - // Exchanged as strings. Can have up to 65 digits not counting - // '-' and '.'. If range is not specified, the default is 10. - // - - /* - @@ Disabled. - os << "char " << mi.var << "value[" << - (t.range ? t.range_value : 10) + 3 << "];" - */ - - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "my_bool " << mi.var << "null;" - << endl; - - } - - virtual void - traverse_short_string (member_info& mi) - { - // If range is not specified, the default buffer size is 255. - // - /* - @@ Disabled. - os << "char " << mi.var << "value[" << - (t.range ? t.range_value : 255) + 1 << "];" - */ - - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_bit (member_info& mi) - { - // Valid range is 1 to 64. - // - unsigned int n (mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0)); - - os << "unsigned char " << mi.var << "value[" << n << "];" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as either integer or string. Since we don't know - // at the code generation time which one it is, we have to always - // keep size in case it is a string. - // - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as string. - // - os << image_type << " " << mi.var << "value;" - << "unsigned long " << mi.var << "size;" - << "my_bool " << mi.var << "null;" - << endl; - } - }; - entry image_member_; - } - } -} diff --git a/odb/relational/mysql/inline.cxx b/odb/relational/mysql/inline.cxx deleted file mode 100644 index bfa2c94..0000000 --- a/odb/relational/mysql/inline.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/relational/mysql/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mysql - { - namespace inline_ - { - namespace relational = relational::inline_; - - struct null_member: relational::null_member_impl, - member_base - { - null_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_simple (member_info& mi) - { - if (get_) - os << "r = r && i." << mi.var << "null;"; - else - os << "i." << mi.var << "null = 1;"; - } - }; - entry null_member_; - } - } -} diff --git a/odb/relational/mysql/model.cxx b/odb/relational/mysql/model.cxx deleted file mode 100644 index 17ed4c0..0000000 --- a/odb/relational/mysql/model.cxx +++ /dev/null @@ -1,161 +0,0 @@ -// file : odb/relational/mysql/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mysql - { - namespace model - { - namespace relational = relational::model; - - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual string - default_bool (semantics::data_member&, bool v) - { - // MySQL has TRUE and FALSE as just aliases for 1 and 0. Still - // use them for self-documentation. - // - return v ? "TRUE" : "FALSE"; - } - - virtual string - default_enum (semantics::data_member& m, tree en, string const& name) - { - // Make sure the column is mapped to an ENUM or integer type. - // - sql_type const& t (parse_sql_type (column_type (), m, false)); - - switch (t.type) - { - case sql_type::ENUM: - case sql_type::TINYINT: - case sql_type::SMALLINT: - case sql_type::MEDIUMINT: - case sql_type::INT: - case sql_type::BIGINT: - break; - default: - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column with default value specified as C++ " - << "enumerator must map to MySQL ENUM or integer type" - << endl; - - throw operation_failed (); - } - } - - using semantics::enum_; - using semantics::enumerator; - - enumerator& er (dynamic_cast (*unit.find (en))); - enum_& e (er.enum_ ()); - - if (t.type == sql_type::ENUM) - { - // Assuming the enumerators in the C++ enum and MySQL ENUM are - // in the same order, calculate the poistion of the C++ - // enumerator and use that as an index in the MySQL ENUM. - // - size_t pos (0); - - for (enum_::enumerates_iterator i (e.enumerates_begin ()), - end (e.enumerates_end ()); i != end; ++i) - { - if (&i->enumerator () == &er) - break; - - pos++; - } - - if (pos < t.enumerators.size ()) - return t.enumerators[pos]; - else - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: unable to map C++ enumerator '" << name - << "' to MySQL ENUM value" << endl; - - throw operation_failed (); - } - } - else - { - ostringstream ostr; - - if (e.unsigned_ ()) - ostr << er.value (); - else - ostr << static_cast (er.value ()); - - return ostr.str (); - } - } - }; - entry object_columns_; - - struct member_create: relational::member_create, context - { - member_create (base const& x): base (x) {} - - virtual string - table_options (semantics::data_member& m, semantics::type& c) - { - string r (relational::member_create::table_options (m, c)); - - string const& engine (options.mysql_engine ()); - if (engine != "default") - { - // Note: MySQL table options can be separated with spaces. - // - if (!r.empty ()) - r += ' '; - - r += "ENGINE="; - r += engine; - } - - return r; - } - }; - entry member_create_; - - struct class_: relational::class_, context - { - class_ (base const& x): base (x) {} - - virtual string - table_options (type& c) - { - string r (relational::class_::table_options (c)); - - string const& engine (options.mysql_engine ()); - if (engine != "default") - { - // Note: MySQL table options can be separated with spaces. - // - if (!r.empty ()) - r += ' '; - - r += "ENGINE="; - r += engine; - } - - return r; - } - }; - entry class__; - } - } -} diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx deleted file mode 100644 index 60dc95b..0000000 --- a/odb/relational/mysql/schema.cxx +++ /dev/null @@ -1,489 +0,0 @@ -// file : odb/relational/mysql/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mysql - { - namespace schema - { - namespace relational = relational::schema; - using relational::table_set; - - // - // Drop. - // - - struct drop_foreign_key: relational::drop_foreign_key, context - { - drop_foreign_key (base const& x): base (x) {} - - virtual void - drop (sema_rel::table& t, sema_rel::foreign_key& fk) - { - /* - // @@ This does not work: in MySQL control statements can only - // be used in stored procedures. It seems the only way to - // implement this is to define, execute, and drop a stored - // procedure, which is just too ugly. - // - // Another option would be to use CREATE TABLE IF NOT EXISTS - // to create a dummy table with a dummy constraint that makes - // the following DROP succeed. Note, however, that MySQL issues - // a notice if the table already exist so would need to suppress - // that as well. Still not sure that the utility of this support - // justifies this kind of a hack. - // - os << "IF EXISTS (SELECT NULL FROM information_schema.TABLE_CONSTRAINTS" << endl - << " WHERE CONSTRAINT_TYPE = " << quote_string ("FOREIGN KEY") << "AND" << endl - << " CONSTRAINT_SCHEMA = DATABASE() AND" << endl - << " CONSTRAINT_NAME = " << quote_string (fk.name ()) << ") THEN" << endl - << " ALTER TABLE " << quote_id (t.name ()) << " DROP FOREIGN KEY " << quote_id (fk.name ()) << ";" << endl - << "END IF;" << endl; - */ - - // So for now we only do this in migration. - // - if (dropped_ == 0) - { - if (fk.not_deferrable ()) - pre_statement (); - else - { - if (format_ != schema_format::sql) - return; - - os << "/*" << endl; - } - - os << "ALTER TABLE " << quote_id (t.name ()) << endl - << " DROP FOREIGN KEY " << quote_id (fk.name ()) << endl; - - if (fk.not_deferrable ()) - post_statement (); - else - os << "*/" << endl - << endl; - } - } - - using base::drop; - - virtual void - traverse (sema_rel::drop_foreign_key& dfk) - { - // Find the foreign key we are dropping in the base model. - // - sema_rel::foreign_key& fk (find (dfk)); - - if (fk.not_deferrable () || in_comment) - base::traverse (dfk); - else - { - if (format_ != schema_format::sql) - return; - - os << endl - << " /*" - << endl; - - drop (dfk); - - os << endl - << " */"; - } - } - - virtual void - drop_header () - { - os << "DROP FOREIGN KEY "; - } - }; - entry drop_foreign_key_; - - struct drop_index: relational::drop_index, context - { - drop_index (base const& x): base (x) {} - - virtual void - drop (sema_rel::index& in) - { - sema_rel::table& t (static_cast (in.scope ())); - - os << "DROP INDEX " << name (in) << " ON " << - quote_id (t.name ()) << endl; - } - }; - entry drop_index_; - - // - // Create. - // - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - auto_ (sema_rel::primary_key&) - { - os << " AUTO_INCREMENT"; - } - }; - entry create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - void - diagnose (sema_rel::foreign_key& fk) - { - if (fk.on_delete () != sema_rel::foreign_key::no_action) - { - cerr << "warning: foreign key '" << fk.name () << "' has " << - "ON DELETE clause but is disabled in MySQL due to lack " - "of deferrable constraint support" << endl; - - cerr << "info: consider using non-deferrable foreign keys (" << - "--fkeys-deferrable-mode)" << endl; - } - } - - virtual void - traverse_create (sema_rel::foreign_key& fk) - { - // MySQL does not support deferrable constraint checking. Output - // such foreign keys as comments, for documentation, unless we - // are generating embedded schema. - // - if (fk.not_deferrable ()) - base::traverse_create (fk); - else - { - diagnose (fk); - - // Don't bloat C++ code with comment strings if we are - // generating embedded schema. - // - if (format_ != schema_format::sql) - return; - - os << endl - << " /*" << endl - << " CONSTRAINT "; - create (fk); - os << endl - << " */"; - } - } - - virtual void - traverse_add (sema_rel::foreign_key& fk) - { - if (fk.not_deferrable () || in_comment) - base::traverse_add (fk); - else - { - diagnose (fk); - - if (format_ != schema_format::sql) - return; - - os << endl - << " /*" - << endl; - - add (fk); - - os << endl - << " */"; - } - } - - virtual void - deferrable (sema_rel::deferrable) - { - // This will still be called to output the comment. - } - }; - entry create_foreign_key_; - - struct create_index: relational::create_index, context - { - create_index (base const& x): base (x) {} - - virtual void - create (sema_rel::index& in) - { - os << "CREATE "; - - if (!in.type ().empty ()) - os << in.type () << ' '; - - os << "INDEX " << name (in); - - if (!in.method ().empty ()) - os << " USING " << in.method (); - - os << endl - << " ON " << table_name (in) << " ("; - - columns (in); - - os << ")" << endl; - - if (!in.options ().empty ()) - os << ' ' << in.options () << endl; - } - }; - entry create_index_; - - struct create_table: relational::create_table, context - { - create_table (base const& x): base (x) {} - - // See if there are any undefined foreign keys that are not - // deferrable. - // - bool - check_undefined_fk_deferrable_only (sema_rel::table& t) - { - for (sema_rel::table::names_iterator i (t.names_begin ()); - i != t.names_end (); ++i) - { - using sema_rel::foreign_key; - - if (foreign_key* fk = dynamic_cast (&i->nameable ())) - { - if (!fk->count ("mysql-fk-defined") && - fk->not_deferrable ()) - return false; - } - } - return true; - } - - virtual void - traverse (sema_rel::table& t) - { - if (pass_ == 1) - base::traverse (t); - else - { - // Add undefined foreign keys. - // - if (check_undefined_fk (t)) - { - bool deferrable (check_undefined_fk_deferrable_only (t)); - - if (!deferrable || format_ == schema_format::sql) - { - if (deferrable) - { - os << "/*" << endl; - in_comment = true; - } - else - pre_statement (); - - os << "ALTER TABLE " << quote_id (t.name ()); - - instance cfk (*this); - trav_rel::unames n (*cfk); - names (t, n); - os << endl; - - if (deferrable) - { - in_comment = false; - os << "*/" << endl - << endl; - } - else - post_statement (); - } - } - } - } - }; - entry create_table_; - - // - // Alter. - // - - struct alter_column: relational::alter_column, context - { - alter_column (base const& x): base (x) {} - - virtual void - alter_header () - { - os << "MODIFY COLUMN "; - } - }; - entry alter_column_; - - struct alter_table_pre: relational::alter_table_pre, context - { - alter_table_pre (base const& x): base (x) {} - - // Check if we are only dropping deferrable foreign keys. - // - bool - check_drop_deferrable_only (sema_rel::alter_table& at) - { - if (check (at) || - check_alter_column_null (at, true)) - return false; - - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::foreign_key; - using sema_rel::drop_foreign_key; - - if (drop_foreign_key* dfk = - dynamic_cast (&i->nameable ())) - { - foreign_key& fk (find (*dfk)); - - if (fk.not_deferrable ()) - return false; - } - } - return true; - } - - virtual void - alter (sema_rel::alter_table& at) - { - if (check_drop_deferrable_only (at)) - { - if (format_ != schema_format::sql) - return; - - os << "/*" << endl; - in_comment = true; - - os << "ALTER TABLE " << quote_id (at.name ()); - instance dfk (*this); - trav_rel::unames n (*dfk); - names (at, n); - os << endl; - - in_comment = false; - os << "*/" << endl - << endl; - } - else - base::alter (at); - } - }; - entry alter_table_pre_; - - struct alter_table_post: relational::alter_table_post, context - { - alter_table_post (base const& x): base (x) {} - - // Check if we are only adding deferrable foreign keys. - // - bool - check_add_deferrable_only (sema_rel::alter_table& at) - { - if (check (at) || - check_alter_column_null (at, false)) - return false; - - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::add_foreign_key; - - if (add_foreign_key* afk = - dynamic_cast (&i->nameable ())) - { - if (afk->not_deferrable ()) - return false; - } - } - return true; - } - - virtual void - alter (sema_rel::alter_table& at) - { - if (check_add_deferrable_only (at)) - { - if (format_ != schema_format::sql) - return; - - os << "/*" << endl; - in_comment = true; - - os << "ALTER TABLE " << quote_id (at.name ()); - instance cfk (*this); - trav_rel::unames n (*cfk); - names (at, n); - os << endl; - - in_comment = false; - os << "*/" << endl - << endl; - } - else - base::alter (at); - } - }; - entry alter_table_post_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x): base (x) {} - - virtual void - create_table () - { - pre_statement (); - - os << "CREATE TABLE IF NOT EXISTS " << qt_ << " (" << endl - << " " << qn_ << " VARCHAR(128) NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " BIGINT UNSIGNED NOT NULL," << endl - << " " << qm_ << " TINYINT(1) NOT NULL)" << endl; - - string const& engine (options.mysql_engine ()); - if (engine != "default") - os << " ENGINE=" << engine << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - os << "INSERT IGNORE INTO " << qt_ << " (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", 0)" << endl; - - post_statement (); - } - }; - entry version_table_; - } - } -} diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx deleted file mode 100644 index 9131ea7..0000000 --- a/odb/relational/mysql/source.cxx +++ /dev/null @@ -1,724 +0,0 @@ -// file : odb/relational/mysql/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace mysql - { - namespace source - { - namespace relational = relational::source; - - namespace - { - const char* integer_buffer_types[] = - { - "MYSQL_TYPE_TINY", - "MYSQL_TYPE_SHORT", - "MYSQL_TYPE_LONG", // *_bind_param() doesn't support INT24. - "MYSQL_TYPE_LONG", - "MYSQL_TYPE_LONGLONG" - }; - - const char* float_buffer_types[] = - { - "MYSQL_TYPE_FLOAT", - "MYSQL_TYPE_DOUBLE" - }; - - const char* date_time_buffer_types[] = - { - "MYSQL_TYPE_DATE", - "MYSQL_TYPE_TIME", - "MYSQL_TYPE_DATETIME", - "MYSQL_TYPE_TIMESTAMP", - "MYSQL_TYPE_SHORT" - }; - - const char* char_bin_buffer_types[] = - { - "MYSQL_TYPE_STRING", // CHAR - "MYSQL_TYPE_BLOB", // BINARY, - "MYSQL_TYPE_STRING", // VARCHAR - "MYSQL_TYPE_BLOB", // VARBINARY - "MYSQL_TYPE_STRING", // TINYTEXT - "MYSQL_TYPE_BLOB", // TINYBLOB - "MYSQL_TYPE_STRING", // TEXT - "MYSQL_TYPE_BLOB", // BLOB - "MYSQL_TYPE_STRING", // MEDIUMTEXT - "MYSQL_TYPE_BLOB", // MEDIUMBLOB - "MYSQL_TYPE_STRING", // LONGTEXT - "MYSQL_TYPE_BLOB" // LONGBLOB - }; - } - - // - // - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - // When we store a ENUM column in the MySQL database, if we bind - // an integer parameter, then it is treated as an index and if we - // bind a string, then it is treated as a enumerator. Everything - // would have worked well if the same logic applied to the select - // operation. That is, if we bind integer, then the database sends - // the index and if we bind string then the database sends the - // enumerator. Unfortunately, MySQL always sends the enumerator - // and to get the index one has to resort to the enum+0 hack. - // - // This causes the following problem: at code generation time we - // do not yet know which format we want. This is determined at - // C++ compile time by traits (the reason we don't know this is - // because we don't want to drag database-specific runtimes, - // which define the necessary traits, as well as their - // prerequisites into the ODB compilation process). As a result, - // we cannot decide at code generation time whether we need the - // +0 hack or not. One way to overcome this would be to construct - // the SELECT statements at runtime, something along these lines: - // - // "enum" + enum_traits::hack + "," - // - // However, this complicates the code generator quite a bit: we - // either have to move to std::string storage for all the - // statements and all the databases, which is kind of a waste, - // or do some deep per-database customizations, which is hairy. - // So, instead, we are going to use another hack (hey, what the - // hell, right?) by loading both the index and enumerator - // combined into a string: - // - // CONCAT (enum+0, ' ', enum) - // - // For cases where we need the index, everything works since - // MySQL will convert the leading number and stop at the space. - // For cases where we need the enumerator, we do a bit of pre- - // processing (see enum_traits) before handing the value off - // to value_traits. - // - - string const& type (column_type ()); - - if (sk_ != statement_select || - parse_sql_type (type, m).type != sql_type::ENUM) - { - return base::column (m, table, column); - } - - // Qualified column and conversion expression. - // - string qc; - if (!table.empty ()) - { - qc += table; - qc += '.'; - } - qc += column; - qc = convert_from (qc, type, m); - - string r ("CONCAT(" + qc + "+0,' '," + qc + ")"); - - sc_.push_back ( - relational::statement_column (table, r, type, m, key_prefix_)); - return true; - } - }; - entry object_columns_; - - struct view_columns: relational::view_columns, context - { - view_columns (base const& x): base (x) {} - - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - // The same idea as in object_columns. - // - string const& type (column_type ()); - - if (parse_sql_type (type, m).type != sql_type::ENUM) - { - return base::column (m, table, column); - } - - // Column and conversion expression. - // - string c (convert_from (column, type, m)); - - string r ("CONCAT(" + c + "+0,' '," + c + ")"); - sc_.push_back (relational::statement_column (table, r, type, m)); - return true; - } - }; - entry view_columns_; - - // - // bind - // - - struct bind_member: relational::bind_member_impl, - member_base - { - bind_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_integer (member_info& mi) - { - // While the is_unsigned should indicate whether the - // buffer variable is unsigned, rather than whether the - // database type is unsigned, in case of the image types, - // this is the same. - // - os << b << ".buffer_type = " << - integer_buffer_types[mi.st->type - sql_type::TINYINT] << ";" - << b << ".is_unsigned = " << (mi.st->unsign ? "1" : "0") << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_float (member_info& mi) - { - os << b << ".buffer_type = " << - float_buffer_types[mi.st->type - sql_type::FLOAT] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_decimal (member_info& mi) - { - os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << b << ".buffer_type = " << - date_time_buffer_types[mi.st->type - sql_type::DATE] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;"; - - if (mi.st->type == sql_type::YEAR) - os << b << ".is_unsigned = 0;"; - - os << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_short_string (member_info& mi) - { - // MySQL documentation is quite confusing about the use of - // buffer_length and length when it comes to input parameters. - // Source code, however, tells us that it uses buffer_length - // only if length is NULL. - // - os << b << ".buffer_type = " << - char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << b << ".buffer_type = " << - char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_bit (member_info& mi) - { - // Treated as a BLOB. - // - os << b << ".buffer_type = MYSQL_TYPE_BLOB;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".buffer_length = static_cast (" << endl - << "sizeof (" << arg << "." << mi.var << "value));" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as either integer or string. - // - os << "mysql::enum_traits::bind (" << b << "," << endl - << arg << "." << mi.var << "value," << endl - << arg << "." << mi.var << "size," << endl - << "&" << arg << "." << mi.var << "null);"; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // - os << b << ".buffer_type = MYSQL_TYPE_STRING;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".buffer_length = static_cast (" << endl - << arg << "." << mi.var << "value.capacity ());" - << b << ".length = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - }; - entry bind_member_; - - // - // grow - // - - struct grow_member: relational::grow_member_impl, - member_base - { - grow_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_float (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_decimal (member_info& mi) - { - // @@ Optimization disabled. - // - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_date_time (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_short_string (member_info& mi) - { - // @@ Optimization disabled. - // - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_bit (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as either integer or string (and we don't know - // at the code generation time which one it is). - // - os << "if (" << e << ")" << endl - << "{" - << "if (mysql::enum_traits::grow (" << - "i." << mi.var << "value, " << - "i." << mi.var << "size))" << endl - << "grew = true;" // String - << "else" << endl - << e << " = 0;" // Integer. - << "}"; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - }; - entry grow_member_; - - // - // init image - // - - struct init_image_member: relational::init_image_member_impl, - member_base - { - init_image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - set_null (member_info& mi) - { - os << "i." << mi.var << "null = 1;"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_decimal (member_info& mi) - { - // @@ Optimization: can remove growth check if buffer is fixed. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_short_string (member_info& mi) - { - // @@ Optimization: can remove growth check if buffer is fixed. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_bit (member_info& mi) - { - // Represented as a BLOB. - // - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "sizeof (i." << mi.var << "value)," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = static_cast (size);"; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as either integer or string. - // - os << "if (mysql::enum_traits::set_image (" << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "is_null," << endl - << member << "))" << endl - << "grew = true;" - << endl - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = static_cast (size);" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - }; - entry init_image_member_; - - // - // init value - // - - struct init_value_member: relational::init_value_member_impl, - member_base - { - init_value_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - get_null (string const& var) const - { - os << "i." << var << "null"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_decimal (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_short_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_long_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_bit (member_info& mi) - { - // Represented as a BLOB. - // - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_enum (member_info& mi) - { - // Represented as either integer or string. - // - os << "mysql::enum_traits::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_set (member_info& mi) - { - // Represented as a string. - // - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - }; - entry init_value_member_; - - struct class_: relational::class_, context - { - class_ (base const& x): base (x) {} - - virtual void - init_auto_id (semantics::data_member& m, string const& im) - { - // Don't set the id value to 0 if this is a nullable wrapper. This - // will allow the user to use the NO_AUTO_VALUE_ON_ZERO mode by - // making it NULL when they want the auto semantics: - // - // #pragma db auto - // odb::nullable id; - // - semantics::type& t (utype (m)); - if (wrapper (t) && t.template get ("wrapper-null-handler")) - return; - - os << im << "value = 0;" - << endl; - } - - virtual string - join_syntax (view_object const& vo) - { - if (vo.join == view_object::full) - { - error (vo.loc) - << "FULL OUTER JOIN is not supported by MySQL" << endl; - throw operation_failed (); - } - - return base::join_syntax (vo); - } - }; - entry class_entry_; - - struct include: relational::include, context - { - include (base const& x): base (x) {} - - virtual void - extra_post () - { - os << "#include " << endl; - } - }; - entry include_; - } - } -} diff --git a/odb/relational/oracle/common.cxx b/odb/relational/oracle/common.cxx deleted file mode 100644 index 7caafc9..0000000 --- a/odb/relational/oracle/common.cxx +++ /dev/null @@ -1,522 +0,0 @@ -// file : odb/relational/oracle/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace relational -{ - namespace oracle - { - // - // member_base - // - - sql_type const& member_base:: - member_sql_type (semantics::data_member& m) - { - return parse_sql_type (column_type (m, key_prefix_), m); - } - - void member_base:: - traverse_simple (member_info& mi) - { - switch (mi.st->type) - { - // Numeric types. - // - case sql_type::NUMBER: - { - const sql_type& st (*mi.st); - - if (st.prec) - { - unsigned short r (st.prec_value); - - if (!st.scale) - { - if (r <= 10) - traverse_int32 (mi); - // Only OCI versions 11.2 and later support insertion and - // extraction into a 64 bit integer. - // - else if ( - (options.oracle_client_version () >= oracle_version (11, 2)) && - (r <= 19 || (r == 20 && unsigned_integer (mi.t)))) - traverse_int64 (mi); - else - traverse_big_int (mi); - } - else - { - // We can calculate the decimal exponent of the normalised - // floating point equivalent of the fixed point number using - // e = p - s, where p is the precision, s is the scale, and - // e the exponent. We can then use this to determine whether - // or not a value of Oracle SQL type NUMBER can be completely - // stored in the native floating point type. - // - - // The maximum decimal precision of a float is 7 significant - // digits. The minimum and maximum decimal exponents - // representable by a float are -37 and 38 respectively. - // - if (r <= 7) - { - int e = r - st.scale_value; - - if (e >= -37 && e <= 38) - traverse_float (mi); - else - traverse_double (mi); - } - - // The maximum decimal precision of a double is 15 significant - // digits. The minimum and maximum decimal exponent representable - // by a double exceeds that of the Oracle NUMBER type. - // - else if (r <= 15) - traverse_double (mi); - else - traverse_big_float (mi); - } - } - else - // If there is no precision, then this is a floating-point number. - // - traverse_double (mi); - - break; - } - case sql_type::FLOAT: - { - // We map FLOAT types based exclusively on their binary precision - // seeing that in 99% of cases it is the precision that is the - // limiting factor and not the exponent. - // - if (mi.st->prec_value <= 24) - traverse_float (mi); - else if (mi.st->prec_value <= 53) - traverse_double (mi); - else - traverse_big_float (mi); - - break; - } - case sql_type::BINARY_FLOAT: - { - traverse_float (mi); - break; - } - case sql_type::BINARY_DOUBLE: - { - traverse_double (mi); - break; - } - // Data-time types. - // - case sql_type::DATE: - { - traverse_date (mi); - break; - } - case sql_type::TIMESTAMP: - { - traverse_timestamp (mi); - break; - } - case sql_type::INTERVAL_YM: - { - traverse_interval_ym (mi); - break; - } - case sql_type::INTERVAL_DS: - { - traverse_interval_ds (mi); - break; - } - // String and binary types. - // - case sql_type::CHAR: - case sql_type::NCHAR: - case sql_type::VARCHAR2: - case sql_type::NVARCHAR2: - case sql_type::RAW: - { - traverse_string (mi); - break; - } - case sql_type::BLOB: - case sql_type::CLOB: - case sql_type::NCLOB: - { - traverse_lob (mi); - break; - } - case sql_type::invalid: - { - assert (false); - break; - } - } - } - - // - // member_image_type - // - - member_image_type:: - member_image_type (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_image_type:: - member_image_type () - : relational::member_base (0, 0, string (), string ()) {} - - member_image_type:: - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, ct, fq_type, key_prefix) {} - - string member_image_type:: - image_type (semantics::data_member& m) - { - type_.clear (); - member_base::traverse (m, true); - return type_; - } - - void member_image_type:: - traverse_composite (member_info& mi) - { - type_ = "composite_value_traits< " + mi.fq_type () + - ", id_oracle >::image_type"; - } - - void member_image_type:: - traverse_int32 (member_info& mi) - { - if (unsigned_integer (mi.t)) - type_ = "unsigned int"; - else - type_ = "int"; - } - - void member_image_type:: - traverse_int64 (member_info& mi) - { - if (unsigned_integer (mi.t)) - type_ = "unsigned long long"; - else - type_ = "long long"; - } - - void member_image_type:: - traverse_big_int (member_info&) - { - type_ = "char*"; - } - - void member_image_type:: - traverse_float (member_info&) - { - type_ = "float"; - } - - void member_image_type:: - traverse_double (member_info&) - { - type_ = "double"; - } - - void member_image_type:: - traverse_big_float (member_info&) - { - type_ = "char*"; - } - - void member_image_type:: - traverse_date (member_info&) - { - type_ = "char*"; - } - - void member_image_type:: - traverse_timestamp (member_info&) - { - type_ = "oracle::datetime"; - } - - void member_image_type:: - traverse_interval_ym (member_info&) - { - type_ = "oracle::interval_ym"; - } - - void member_image_type:: - traverse_interval_ds (member_info&) - { - type_ = "oracle::interval_ds"; - } - - void member_image_type:: - traverse_string (member_info&) - { - type_ = "char*"; - } - - void member_image_type:: - traverse_lob (member_info&) - { - type_ = "oracle::lob_callback"; - } - - entry member_image_type_; - - // - // member_database_type - // - - namespace - { - const char* string_bin_database_id[] = - { - "id_string", // CHAR - "id_nstring", // NCHAR - "id_string", // VARCHAR2 - "id_nstring", // NVARCHAR2 - "id_raw" // RAW - }; - - const char* lob_database_id[] = - { - "id_blob", - "id_clob", - "id_nclob" - }; - } - - member_database_type_id:: - member_database_type_id (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_database_type_id:: - member_database_type_id () - : member_base::base (0, 0, string (), string ()), // virtual base - base (0, 0, string (), string ()) {} - - member_database_type_id:: - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base::base (type, ct, fq_type, key_prefix), // virtual base - base (type, ct, fq_type, key_prefix) {} - - string member_database_type_id:: - database_type_id (type& m) - { - type_id_.clear (); - member_base::traverse (m, true); - return type_id_; - } - - void member_database_type_id:: - traverse_composite (member_info&) - { - assert (false); - } - - void member_database_type_id:: - traverse_int32 (member_info&) - { - type_id_ = "oracle::id_int32"; - } - - void member_database_type_id:: - traverse_int64 (member_info&) - { - type_id_ = "oracle::id_int64"; - } - - void member_database_type_id:: - traverse_big_int (member_info&) - { - type_id_ = "oracle::id_big_int"; - } - - void member_database_type_id:: - traverse_float (member_info&) - { - type_id_ = "oracle::id_float"; - } - - void member_database_type_id:: - traverse_double (member_info&) - { - type_id_ = "oracle::id_double"; - } - - void member_database_type_id:: - traverse_big_float (member_info&) - { - type_id_ = "oracle::id_big_float"; - } - - void member_database_type_id:: - traverse_date (member_info&) - { - type_id_ = "oracle::id_date"; - } - - void member_database_type_id:: - traverse_timestamp (member_info&) - { - type_id_ = "oracle::id_timestamp"; - } - - void member_database_type_id:: - traverse_interval_ym (member_info&) - { - type_id_ = "oracle::id_interval_ym"; - } - - void member_database_type_id:: - traverse_interval_ds (member_info&) - { - type_id_ = "oracle::id_interval_ds"; - } - - void member_database_type_id:: - traverse_string (member_info& mi) - { - type_id_ = string ("oracle::") + - string_bin_database_id[mi.st->type - sql_type::CHAR]; - } - - void member_database_type_id:: - traverse_lob (member_info& mi) - { - type_id_ = string ("oracle::") + - lob_database_id[mi.st->type - sql_type::BLOB]; - } - - entry member_database_type_id_; - - // - // query_columns - // - - struct query_columns: relational::query_columns, context - { - query_columns (base const& x): base_impl (x) {} - - void - column_ctor (string const& type, string const& name, string const& base) - { - os << name << " ("; - - if (multi_dynamic) - os << "odb::query_column< " << type << " >& qc," << endl; - - os << "const char* t," << endl - << "const char* c," << endl - << "const char* conv," << endl - << "unsigned short p = 0xFFF," << endl - << "short s = 0xFFF)" << endl - << " : " << base << " (" << (multi_dynamic ? "qc, " : "") << - "t, c, conv, p, s)" - << "{" - << "}"; - } - - virtual void - column_ctor_args_extra (semantics::data_member& m) - { - // For some types we need to pass precision and scale. - // - sql_type const& st (parse_sql_type (column_type (), m)); - - switch (st.type) - { - case sql_type::NUMBER: - { - if (st.prec) - { - os << ", " << st.prec_value; - - if (st.scale) - os << ", " << st.scale_value; - } - break; - } - case sql_type::FLOAT: - { - os << ", " << st.prec_value; - break; - } - case sql_type::TIMESTAMP: - { - os << ", " << st.prec_value; - break; - } - case sql_type::INTERVAL_YM: - { - os << ", " << st.prec_value; - break; - } - case sql_type::INTERVAL_DS: - { - // INTERVAL DAY TO SECOND has two precisions. - // - os << ", " << st.prec_value << ", " << st.scale_value; - break; - } - case sql_type::CHAR: - case sql_type::NCHAR: - case sql_type::VARCHAR2: - case sql_type::NVARCHAR2: - case sql_type::RAW: - { - // The same logic as in header.cxx. - // - size_t n (st.prec ? st.prec_value : 1); - - if (!st.byte_semantics) - n *= 4; - - if (st.type == sql_type::VARCHAR2 || - st.type == sql_type::NVARCHAR2) - n = n > 4000 ? 4000 : n; - else - n = n > 2000 ? 2000 : n; - - os << ", " << n; - break; - } - default: - { - break; - } - } - } - - virtual string - database_type_id (semantics::data_member& m) - { - return member_database_type_id_.database_type_id (m); - } - - private: - member_database_type_id member_database_type_id_; - }; - entry query_columns_; - } -} diff --git a/odb/relational/oracle/common.hxx b/odb/relational/oracle/common.hxx deleted file mode 100644 index 1958aab..0000000 --- a/odb/relational/oracle/common.hxx +++ /dev/null @@ -1,203 +0,0 @@ -// file : odb/relational/oracle/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_ORACLE_COMMON_HXX -#define ODB_RELATIONAL_ORACLE_COMMON_HXX - -#include -#include - -namespace relational -{ - namespace oracle - { - struct member_base: virtual relational::member_base_impl, context - { - member_base (base const& x): base (x), base_impl (x) {} - - // This c-tor is for the direct use inside the oracle namespace. - // If you do use this c-tor, you should also explicitly call - // relational::member_base (aka base). - // - member_base () {} - - virtual sql_type const& - member_sql_type (semantics::data_member&); - - virtual void - traverse_simple (member_info&); - - virtual void - traverse_int32 (member_info&) - { - } - - virtual void - traverse_int64 (member_info&) - { - } - - virtual void - traverse_big_int (member_info&) - { - } - - virtual void - traverse_float (member_info&) - { - } - - virtual void - traverse_double (member_info&) - { - } - - virtual void - traverse_big_float (member_info&) - { - } - - virtual void - traverse_date (member_info&) - { - } - - virtual void - traverse_timestamp (member_info&) - { - } - - virtual void - traverse_interval_ym (member_info&) - { - } - - virtual void - traverse_interval_ds (member_info&) - { - } - - virtual void - traverse_string (member_info&) - { - } - - virtual void - traverse_lob (member_info&) - { - } - }; - - struct member_image_type: relational::member_image_type, - member_base - { - member_image_type (base const&); - member_image_type (); - member_image_type (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - virtual string - image_type (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_int32 (member_info&); - - virtual void - traverse_int64 (member_info&); - - virtual void - traverse_big_int (member_info&); - - virtual void - traverse_float (member_info&); - - virtual void - traverse_double (member_info&); - - virtual void - traverse_big_float (member_info&); - - virtual void - traverse_date (member_info&); - - virtual void - traverse_timestamp (member_info&); - - virtual void - traverse_interval_ym (member_info&); - - virtual void - traverse_interval_ds (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_lob (member_info&); - - private: - string type_; - }; - - struct member_database_type_id: relational::member_database_type_id, - member_base - { - member_database_type_id (base const&); - member_database_type_id (); - member_database_type_id (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - - virtual string - database_type_id (type&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_int32 (member_info&); - - virtual void - traverse_int64 (member_info&); - - virtual void - traverse_big_int (member_info&); - - virtual void - traverse_float (member_info&); - - virtual void - traverse_double (member_info&); - - virtual void - traverse_big_float (member_info&); - - virtual void - traverse_date (member_info&); - - virtual void - traverse_timestamp (member_info&); - - virtual void - traverse_interval_ym (member_info&); - - virtual void - traverse_interval_ds (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_lob (member_info&); - - private: - string type_id_; - }; - } -} -#endif // ODB_RELATIONAL_ORACLE_COMMON_HXX diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx deleted file mode 100644 index 12ce0aa..0000000 --- a/odb/relational/oracle/context.cxx +++ /dev/null @@ -1,795 +0,0 @@ -// file : odb/relational/oracle/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -#include -#include - -#include - -using namespace std; - -namespace relational -{ - namespace oracle - { - namespace - { - struct type_map_entry - { - char const* const cxx_type; - char const* const db_type; - char const* const db_id_type; - bool const null; - }; - - type_map_entry type_map[] = - { - {"bool", "NUMBER(1)", 0, false}, - - {"char", "CHAR(1)", 0, false}, - {"signed char", "NUMBER(3)", 0, false}, - {"unsigned char", "NUMBER(3)", 0, false}, - - {"short int", "NUMBER(5)", 0, false}, - {"short unsigned int", "NUMBER(5)", 0, false}, - - {"int", "NUMBER(10)", 0, false}, - {"unsigned int", "NUMBER(10)", 0, false}, - - {"long int", "NUMBER(19)", 0, false}, - {"long unsigned int", "NUMBER(20)", 0, false}, - - {"long long int", "NUMBER(19)", 0, false}, - {"long long unsigned int", "NUMBER(20)", 0, false}, - - {"float", "BINARY_FLOAT", 0, false}, - {"double", "BINARY_DOUBLE", 0, false}, - - // Oracle treats empty VARCHAR2 (and NVARCHAR2) strings as NULL. - // - {"::std::string", "VARCHAR2(512)", 0, true}, - - {"::size_t", "NUMBER(20)", 0, false}, - {"::std::size_t", "NUMBER(20)", 0, false} - }; - } - - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context (ostream& os, - semantics::unit& u, - options_type const& ops, - features_type& f, - sema_rel::model* m) - : root_context (os, u, ops, f, data_ptr (new (shared) data (os))), - base_context (static_cast (root_context::data_.get ()), m), - data_ (static_cast (base_context::data_)) - { - assert (current_ == 0); - current_ = this; - - generate_grow = false; - need_alias_as = false; - insert_send_auto_id = false; - delay_freeing_statement_result = false; - need_image_clone = true; - generate_bulk = true; - global_index = true; - global_fkey = true; - data_->bind_vector_ = "oracle::bind*"; - - // Populate the C++ type to DB type map. - // - for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i) - { - type_map_entry const& e (type_map[i]); - - type_map_type::value_type v ( - e.cxx_type, - db_type_type ( - e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null)); - - data_->type_map_.insert (v); - } - } - - context:: - context () - : data_ (current ().data_) - { - } - - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - - string context:: - quote_id_impl (qname const& id) const - { - string r; - - bool f (true); - for (qname::iterator i (id.begin ()); i < id.end (); ++i) - { - if (i->empty ()) - continue; - - if (f) - f = false; - else - r += '.'; - - r += '"'; - r.append (*i, 0, 30); // Max identifier length is 30. - r += '"'; - } - - return r; - } - - string context:: - database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) - { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - - using semantics::array; - - // char[N] mapping. - // - if (array* a = dynamic_cast (&t)) - { - semantics::type& bt (a->base_type ()); - if (bt.is_a ()) - { - unsigned long long n (a->size ()); - - if (n == 0) - return r; - else if (n == 1) - r = "CHAR"; - else - { - r = "VARCHAR2"; - n--; - } - - // Oracle VARCHAR2 limit is 4000 bytes. Since there are no good - // alternatives (CLOB?), let the user specify the mapping. - // - if (n > 4000) - return ""; - - // Allow empty VARCHAR2 values. - // - if (null != 0 && r == "VARCHAR2") - *null = true; - - ostringstream ostr; - ostr << n; - r += '('; - r += ostr.str (); - r += ')'; - } - } - - return r; - } - - bool context:: - unsigned_integer (semantics::type& t) - { - semantics::type* wt (wrapper (t)); - const string& s ((wt == 0 ? t : utype (*wt)).name ()); - - return s == "bool" || - s == "unsigned char" || - s == "short unsigned int" || - s == "unsigned int" || - s == "long unsigned int" || - s == "long long unsigned int"; - } - - qname context:: - sequence_name (qname const& table) - { - string n; - - if (options.sequence_suffix ().count (db) != 0) - n = table.uname () + options.sequence_suffix ()[db]; - else - n = compose_name (table.uname (), "seq"); - - n = transform_name (n, sql_name_sequence); - - qname r (table.qualifier ()); - r.append (n); - return r; - } - - // - // SQL type parsing. - // - - sql_type const& context:: - parse_sql_type (string const& t, semantics::data_member& m, bool custom) - { - // If this proves to be too expensive, we can maintain a cache of - // parsed types across contexts. - // - data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - - if (i != data_->sql_type_cache_.end () - && (custom ? i->second.custom_cached : i->second.straight_cached)) - { - return (custom ? i->second.custom : i->second.straight); - } - else - { - try - { - sql_type st ( - parse_sql_type ( - t, - custom ? &unit.get ("custom-db-types") : 0)); - - if (custom) - return data_->sql_type_cache_[t].cache_custom (st); - else - return data_->sql_type_cache_[t].cache_straight (st); - } - catch (invalid_sql_type const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: " << e.message () << endl; - - throw operation_failed (); - } - } - } - - inline sql_type - error (bool fail, string const& m) - { - if (!fail) - return sql_type (); - else - throw context::invalid_sql_type (m); - } - - sql_type context:: - parse_sql_type (string sqlt, custom_db_types const* ct) - { - try - { - sql_type r; - - // First run the type through the custom mapping, if requested. - // - if (ct != 0) - { - for (custom_db_types::const_iterator i (ct->begin ()); - i != ct->end (); ++i) - { - custom_db_type const& t (*i); - - if (t.type.match (sqlt)) - { - r.to = t.type.replace (sqlt, t.to); - r.from = t.type.replace (sqlt, t.from); - sqlt = t.type.replace (sqlt, t.as); - break; - } - } - } - - sql_lexer l (sqlt); - - // While most type names use single identifier, there are - // a couple of exceptions to this rule: - // - // CHARACTER VARYING (VARCHAR2) - // CHAR VARYING (VARCHAR2) - // NATIONAL CHARACTER (NCHAR) - // NATIONAL CHAR (NCHAR) - // NCHAR VARYING (NVARCHAR2) - // NATIONAL CHARACTER VARYING (NVARCHAR2) - // NATIONAL CHAR VARYING (NVARCHAR2) - // NCHAR VARYING (NVARCHAR2) - // DOUBLE PRECISION (FLOAT(126)) - // INTERVAL YEAR TO MONTH - // INTERVAL DAY TO SECOND - // - enum state - { - parse_identifier, - parse_prec, - parse_done - }; - - state s (parse_identifier); - string prefix; - sql_token t (l.next ()); - - while (t.type () != sql_token::t_eos) - { - sql_token::token_type tt (t.type ()); - - switch (s) - { - case parse_identifier: - { - if (tt == sql_token::t_identifier) - { - string const& id (context::upcase (t.identifier ())); - - // - // Numeric types. - // - if ((id == "NUMBER") && prefix.empty ()) - { - // If NUMBER has no precision/scale, then it is a floating- - // point number. We indicate this by having no precision. - // - r.type = sql_type::NUMBER; - s = parse_prec; - } - else if ((id == "DEC" || id == "DECIMAL" || id == "NUMERIC") - && prefix.empty ()) - { - // DEC, DECIMAL, and NUMERIC are equivalent to NUMBER in - // all ways except that they may not represent a floating - // point number. The scale defaults to zero. - // - r.type = sql_type::NUMBER; - s = parse_prec; - } - else if ((id == "INT" || id == "INTEGER" || id == "SMALLINT") - && prefix.empty ()) - { - // INT, INTEGER, and SMALLINT map to NUMBER(38). They may not - // have precision or scale explicitly specified. - // - r.type = sql_type::NUMBER; - r.prec = true; - r.prec_value = 38; - - s = parse_done; - } - // - // Floating point types. - // - else if (id == "FLOAT" && prefix.empty ()) - { - r.type = sql_type::FLOAT; - r.prec = true; - r.prec_value = 126; - - s = parse_prec; - } - else if (id == "DOUBLE" && prefix.empty ()) - { - prefix = id; - } - else if (id == "PRECISION" && prefix == "DOUBLE") - { - r.type = sql_type::FLOAT; - r.prec = true; - r.prec_value = 126; - - s = parse_done; - } - else if (id == "REAL" && prefix.empty ()) - { - r.type = sql_type::FLOAT; - r.prec = true; - r.prec_value = 63; - - s = parse_done; - } - else if (id == "BINARY_FLOAT" && prefix.empty ()) - { - r.type = sql_type::BINARY_FLOAT; - s = parse_done; - } - else if (id == "BINARY_DOUBLE" && prefix.empty ()) - { - r.type = sql_type::BINARY_DOUBLE; - s = parse_done; - } - // - // Date-time types. - // - else if (id == "DATE" && prefix.empty ()) - { - r.type = sql_type::DATE; - s = parse_done; - } - else if (id == "TIMESTAMP" && prefix.empty ()) - { - prefix = id; - } - else if (id == "INTERVAL" && prefix.empty ()) - { - prefix = id; - } - else if (id == "YEAR" && prefix == "INTERVAL") - { - prefix += " "; - prefix += id; - - r.prec = true; - r.prec_value = 2; - s = parse_prec; - } - else if (id == "DAY" && prefix == "INTERVAL") - { - prefix += " "; - prefix += id; - - r.prec = true; - r.prec_value = 2; - s = parse_prec; - } - else if (id == "TO" && - (prefix == "INTERVAL YEAR" || - prefix == "INTERVAL DAY")) - { - prefix += " "; - prefix += id; - } - else if (id == "MONTH" && prefix == "INTERVAL YEAR TO") - { - r.type = sql_type::INTERVAL_YM; - s = parse_done; - } - else if (id == "SECOND" && prefix == "INTERVAL DAY TO") - { - r.type = sql_type::INTERVAL_DS; - - // Store seconds precision in scale since prec holds - // the days precision. - // - r.scale = true; - r.scale_value = 6; - s = parse_prec; - } - // - // Timestamp with time zone (not supported). - // - else if (id == "WITH" && prefix == "TIMESTAMP") - { - prefix += " "; - prefix += id; - } - else if (id == "TIME" && - (prefix == "TIMESTAMP WITH" || - prefix == "TIMESTAMP WITH LOCAL")) - { - prefix += " "; - prefix += id; - } - else if (id == "LOCAL" && prefix == "TIMESTAMP WITH") - { - prefix += " "; - prefix += id; - } - else if (id == "ZONE" && - (prefix == "TIMESTAMP WITH LOCAL TIME" || - prefix == "TIMESTAMP WITH TIME")) - { - return error (ct, "Oracle timestamps with time zones are " - "not currently supported"); - } - // - // String and binary types. - // - else if (id == "CHAR") - { - prefix += prefix.empty () ? "" : " "; - prefix += id; - } - else if (id == "CHARACTER") - { - prefix += prefix.empty () ? "" : " "; - prefix += id; - } - else if (id == "NCHAR") - { - prefix += prefix.empty () ? "" : " "; - prefix += id; - } - else if (id == "VARCHAR" || id == "VARCHAR2") - { - // VARCHAR is currently mapped to VARCHAR2 in Oracle server. - // However, this may change in future versions. - // - r.type = sql_type::VARCHAR2; - r.byte_semantics = true; - s = parse_prec; - } - else if (id == "NVARCHAR2") - { - r.type = sql_type::NVARCHAR2; - r.byte_semantics = false; - s = parse_prec; - } - else if (id == "VARYING") - { - // VARYING always appears at the end of an identifier. - // - if (prefix == "CHAR" || prefix == "CHARACTER") - { - r.type = sql_type::VARCHAR2; - r.byte_semantics = true; - } - else if (prefix == "NCHAR" || - prefix == "NATIONAL CHAR" || - prefix == "NATIONAL CHARACTER") - { - r.type = sql_type::NVARCHAR2; - r.byte_semantics = false; - } - - s = parse_prec; - } - else if (id == "NATIONAL" && prefix.empty ()) - { - prefix = id; - } - else if (id == "RAW" && prefix.empty ()) - { - r.type = sql_type::RAW; - s = parse_prec; - } - // - // LOB types. - // - else if (id == "BLOB" && prefix.empty ()) - { - r.type = sql_type::BLOB; - s = parse_done; - } - else if (id == "CLOB" && prefix.empty ()) - { - r.type = sql_type::CLOB; - s = parse_done; - } - else if (id == "NCLOB" && prefix.empty ()) - { - r.type = sql_type::NCLOB; - s = parse_done; - } - // - // LONG types. - // - else if (id == "LONG") - return error (ct, "Oracle LONG types are not supported"); - else - return error (ct, "unknown Oracle type '" + - t.identifier () + "'"); - - t = l.next (); - continue; - } - else if (!prefix.empty ()) - { - // Some prefixes can also be type names if not followed - // by the actual type name. - // - - if (prefix == "CHAR" || prefix == "CHARACTER") - { - r.type = sql_type::CHAR; - r.byte_semantics = true; - r.prec = true; - r.prec_value = 1; - } - else if (prefix == "NCHAR" || - prefix == "NATIONAL CHAR" || - prefix == "NATIONAL CHARACTER") - { - r.type = sql_type::NCHAR; - r.byte_semantics = false; - r.prec = true; - r.prec_value = 1; - } - else if (prefix == "TIMESTAMP") - { - r.type = sql_type::TIMESTAMP; - r.prec = true; - r.prec_value = 6; - } - else - return error (ct, "incomplete Oracle type declaration: '" + - prefix + "'"); - - // All of the possible types handled in this block can take - // an optional precision specifier. Set the state and fall - // through to the parse_prec handler. - // - s = parse_prec; - } - else - { - assert (r.type == sql_type::invalid); - return error (ct, "unexepected '" + t.literal () + - "' in Oracle type declaration"); - } - } - // Fall through. - case parse_prec: - { - if (t.punctuation () == sql_token::p_lparen) - { - t = l.next (); - - if (t.type () != sql_token::t_int_lit) - { - return error (ct, "integer size/precision expected in " - "Oracle type declaration"); - } - - // Parse the precision. - // - { - unsigned short v; - istringstream is (t.literal ()); - - if (!(is >> v && is.eof ())) - { - return error (ct, "invalid prec value '" + t.literal () + - "' in Oracle type declaration"); - } - - // Store seconds precision in scale since prec holds - // the days precision for INTERVAL DAY TO SECOND. - // - if (r.type == sql_type::INTERVAL_DS) - { - r.scale = true; - r.scale_value = static_cast (v); - } - else - { - r.prec = true; - r.prec_value = v; - } - - t = l.next (); - } - - // Parse the scale if present. - // - if (t.punctuation () == sql_token::p_comma) - { - // Scale can only be specified for NUMBER. - // - if (r.type != sql_type::NUMBER) - { - return error (ct, "invalid scale in Oracle type " - "declaration"); - } - - t = l.next (); - - if (t.type () != sql_token::t_int_lit) - { - return error (ct, "integer scale expected in Oracle type " - "declaration"); - } - - short v; - istringstream is (t.literal ()); - - if (!(is >> v && is.eof ())) - { - return error (ct, "invalid scale value '" + t.literal () + - "' in Oracle type declaration"); - } - - r.scale = true; - r.scale_value = v; - - t = l.next (); - } - else if (t.type () == sql_token::t_identifier) - { - const string& id (context::upcase (t.identifier ())); - - if (id == "CHAR") - r.byte_semantics = false; - else if (id != "BYTE") - { - return error (ct, "invalid keyword '" + t.literal () + - "' in Oracle type declaration"); - } - - t = l.next (); - } - - if (t.punctuation () != sql_token::p_rparen) - { - return error (ct, "expected ')' in Oracle type declaration"); - } - else - t = l.next (); - } - - s = r.type == sql_type::invalid ? parse_identifier : parse_done; - continue; - } - case parse_done: - { - return error (ct, "unexepected '" + t.literal () + "' in Oracle " - "type declaration"); - break; - } - } - } - - // Some prefixes can also be type names if not followed by the actual - // type name. - // - if (r.type == sql_type::invalid) - { - if (!prefix.empty ()) - { - if (prefix == "CHAR" || prefix == "CHARACTER") - { - r.type = sql_type::CHAR; - r.byte_semantics = true; - r.prec = true; - r.prec_value = 1; - } - else if (prefix == "NCHAR" || - prefix == "NATIONAL CHAR" || - prefix == "NATIONAL CHARACTER") - { - r.type = sql_type::NCHAR; - r.byte_semantics = false; - r.prec = true; - r.prec_value = 1; - } - else if (prefix == "TIMESTAMP") - { - r.type = sql_type::TIMESTAMP; - r.prec = true; - r.prec_value = 6; - } - else - return error (ct, "incomplete Oracle type declaration: '" + - prefix + "'"); - } - else - return error (ct, "invalid Oracle type declaration"); - } - - return r; - } - catch (sql_lexer::invalid_input const& e) - { - return error (ct, "invalid Oracle type declaration: " + e.message); - } - } - } -} diff --git a/odb/relational/oracle/context.hxx b/odb/relational/oracle/context.hxx deleted file mode 100644 index 6c55853..0000000 --- a/odb/relational/oracle/context.hxx +++ /dev/null @@ -1,188 +0,0 @@ -// file : odb/relational/oracle/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_ORACLE_CONTEXT_HXX -#define ODB_RELATIONAL_ORACLE_CONTEXT_HXX - -#include - -#include - -namespace relational -{ - namespace oracle - { - struct sql_type - { - // Keep the order in each block of types. - // - enum core_type - { - // Numeric types. - // - NUMBER, - FLOAT, - - // Floating point types. - // - BINARY_FLOAT, - BINARY_DOUBLE, - - // Date-time types. - // - DATE, - TIMESTAMP, - INTERVAL_YM, - INTERVAL_DS, - - // String and binary types. - // - CHAR, - NCHAR, - VARCHAR2, - NVARCHAR2, - RAW, - - // LOB types. - // - BLOB, - CLOB, - NCLOB, - - // Invalid type. - // - invalid - }; - - sql_type () : - type (invalid), prec (false), scale (false), byte_semantics (true) - { - } - - core_type type; - - bool prec; - unsigned short prec_value; // Oracle max value is 4000. - - bool scale; - short scale_value; // Oracle min value is -84. Max value is 127. - - bool byte_semantics; - - // Conversion expressions for custom database types. - // - std::string to; - std::string from; - }; - - class context: public virtual relational::context - { - public: - sql_type const& - parse_sql_type (string const&, - semantics::data_member&, - bool custom = true); - public: - struct invalid_sql_type - { - invalid_sql_type (string const& message): message_ (message) {} - - string const& - message () const {return message_;} - - private: - string message_; - }; - - // If custom_db_types is NULL, then this function returns - // invalid type instead of throwing in case an unknown type - // is encountered. - // - static sql_type - parse_sql_type (string, custom_db_types const* = 0); - - public: - // If necessary, unwraps. - // - static bool - unsigned_integer (semantics::type&); - - public: - // Construct sequence name from a given table name. - // - qname - sequence_name (qname const& table); - - protected: - virtual string const& - convert_expr (string const&, semantics::data_member&, bool); - - virtual string - quote_id_impl (qname const&) const; - - protected: - virtual string - database_type_impl (semantics::type&, semantics::names*, bool, bool*); - - public: - virtual - ~context (); - - context (); - context (std::ostream&, - semantics::unit&, - options_type const&, - features_type&, - sema_rel::model*); - - static context& - current () - { - return *current_; - } - - private: - static context* current_; - - private: - struct data: base_context::data - { - data (std::ostream& os): base_context::data (os) {} - - struct sql_type_cache_entry - { - sql_type_cache_entry () - : custom_cached (false), straight_cached (false) {} - - sql_type const& - cache_custom (sql_type const& t) - { - custom = t; - custom_cached = true; - return custom; - } - - sql_type const& - cache_straight (sql_type const& t) - { - straight = t; - straight_cached = true; - return straight; - } - - sql_type custom; // With custom mapping. - sql_type straight; // Without custom mapping. - - bool custom_cached; - bool straight_cached; - }; - - typedef std::map sql_type_cache; - sql_type_cache sql_type_cache_; - }; - data* data_; - }; - } -} - -#endif // ODB_RELATIONAL_ORACLE_CONTEXT_HXX diff --git a/odb/relational/oracle/header.cxx b/odb/relational/oracle/header.cxx deleted file mode 100644 index bf50bb2..0000000 --- a/odb/relational/oracle/header.cxx +++ /dev/null @@ -1,230 +0,0 @@ -// file : odb/relational/oracle/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -namespace relational -{ - namespace oracle - { - namespace header - { - namespace relational = relational::header; - - struct image_type: relational::image_type, context - { - image_type (base const& x): base (x) {}; - - virtual void - image_extra (type& c) - { - if (!(composite (c) || (abstract (c) && !polymorphic (c)))) - { - type* poly_root (polymorphic (c)); - - // If this is a polymorphic type, only add callback to the root. - // - if (poly_root == 0 || poly_root == &c) - { - bool gc (options.generate_query ()); - - if (gc) - os << "oracle::change_callback change_callback_;" - << endl; - - os << "oracle::change_callback*" << endl - << "change_callback ()" - << "{"; - - if (gc) - os << "return &change_callback_;"; - else - os << "return 0;"; - - os << "}"; - } - } - } - }; - entry image_type_; - - struct image_member: relational::image_member_impl, - member_base - { - image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_int32 (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_int64 (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_big_int (member_info& mi) - { - // Each significant base-100 digit requires a byte of storage - // in the manitissa. The default precision is 38 decimal digits, - // which is equivalent to 19 base-100 digits. - // - size_t n (19); - - if (mi.st->prec) - n = mi.st->prec_value / 2 + mi.st->prec_value % 2; - - // We require an additional byte for each of the exponent and - // negative value terminator values. - // - n += 2; - - os << "char " << mi.var << "value[" << n << "];" - << "ub2 " << mi.var << "size;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_double (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_big_float (member_info& mi) - { - // big_float is mapped to the OCI type SQLT_NUM, which requires 21 - // bytes of storage. - // - os << "char " << mi.var << "value[21];" - << "ub2 " << mi.var << "size;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_date (member_info& mi) - { - os << "char " << mi.var << "value[7];" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_timestamp (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_interval_ym (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_interval_ds (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - size_t n (mi.st->prec ? mi.st->prec_value : 1); - - // National characters can be either UTF-8 or UTF-16 encoded, - // both of which have a maximum character encoding size of 4 - // bytes. Database character set can also be UTF-8 so if the - // size is specified in characters, then conservatively assume - // each character can take up to 4 bytes. - // - if (!mi.st->byte_semantics) // N*CHAR always has CHAR semantics. - n *= 4; - - if (mi.st->type == sql_type::VARCHAR2 || - mi.st->type == sql_type::NVARCHAR2) - n = n > 4000 ? 4000 : n; - else - n = n > 2000 ? 2000 : n; - - os << "char " << mi.var << "value[" << n << "];" - << "ub2 " << mi.var << "size;" - << "sb2 " << mi.var << "indicator;" - << endl; - } - - virtual void - traverse_lob (member_info& mi) - { - os << "mutable " << image_type << " " << mi.var << "callback;" - << "sb2 " << mi.var << "indicator;" - << "oracle::lob " << mi.var << "lob;" - << endl; - } - }; - entry image_member_; - - struct class1: relational::class1 - { - class1 (base const& x): base (x) {} - - virtual void - object_public_extra_pre (type& c) - { - bool abst (abstract (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - if (poly_derived || (abst && !poly)) - return; - - // Bulk operations batch size. - // - { - unsigned long long b (c.count ("bulk") - ? c.get ("bulk") - : 1); - - os << "static const std::size_t batch = " << b << "UL;" - << endl; - } - } - }; - entry class1_entry_; - } - } -} diff --git a/odb/relational/oracle/inline.cxx b/odb/relational/oracle/inline.cxx deleted file mode 100644 index 1b6d606..0000000 --- a/odb/relational/oracle/inline.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/relational/oracle/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace oracle - { - namespace inline_ - { - namespace relational = relational::inline_; - - struct null_member: relational::null_member_impl, - member_base - { - null_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_simple (member_info& mi) - { - if (get_) - os << "r = r && i." << mi.var << "indicator == -1;"; - else - os << "i." << mi.var << "indicator = -1;"; - } - }; - entry null_member_; - } - } -} diff --git a/odb/relational/oracle/model.cxx b/odb/relational/oracle/model.cxx deleted file mode 100644 index b65e201..0000000 --- a/odb/relational/oracle/model.cxx +++ /dev/null @@ -1,64 +0,0 @@ -// file : odb/relational/oracle/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace oracle - { - namespace model - { - namespace relational = relational::model; - - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual string - default_enum (semantics::data_member& m, tree en, string const&) - { - // Make sure the column is mapped to Oracle NUMBER. - // - sql_type const& t (parse_sql_type (column_type (), m, false)); - if (t.type != sql_type::NUMBER) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column with default value specified as C++ " - << "enumerator must map to Oracle NUMBER" << endl; - - throw operation_failed (); - } - - using semantics::enumerator; - - enumerator& e (dynamic_cast (*unit.find (en))); - - ostringstream ostr; - - if (e.enum_ ().unsigned_ ()) - ostr << e.value (); - else - ostr << static_cast (e.value ()); - - return ostr.str (); - } - - virtual void - primary_key (sema_rel::primary_key& pk) - { - if (pk.auto_ ()) - pk.extra ()["sequence"] = sequence_name (table_.name ()).string (); - } - }; - entry object_columns_; - } - } -} diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx deleted file mode 100644 index 75100b1..0000000 --- a/odb/relational/oracle/schema.cxx +++ /dev/null @@ -1,696 +0,0 @@ -// file : odb/relational/oracle/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include // pair - -#include - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace oracle - { - namespace schema - { - namespace relational = relational::schema; - using relational::table_set; - - struct sql_emitter: relational::sql_emitter - { - sql_emitter (const base& x): base (x) {} - - virtual void - line (const std::string& l) - { - // SQLPlus doesn't like empty line in the middle of a statement. - // - if (!l.empty ()) - { - base::line (l); - last_ = l; - } - } - - virtual void - post () - { - if (!first_) // Ignore empty statements. - { - if (last_ == "END;") - os << endl - << '/' << endl - << endl; - - else - os << ';' << endl - << endl; - } - } - - private: - string last_; - }; - entry sql_emitter_; - - // - // File. - // - - struct sql_file: relational::sql_file, context - { - sql_file (const base& x): base (x) {} - - virtual void - prologue () - { - // Quiet down SQLPlus and make sure it exits with an error - // code if there is an error. - // - os << "SET FEEDBACK OFF;" << endl - << "WHENEVER SQLERROR EXIT FAILURE;" << endl - << "WHENEVER OSERROR EXIT FAILURE;" << endl - << endl; - } - - virtual void - epilogue () - { - os << "EXIT;" << endl; - } - }; - entry sql_file_; - - // - // Drop. - // - - struct drop_column: relational::drop_column, context - { - drop_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::drop_column& dc) - { - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - os << quote_id (dc.name ()); - } - }; - entry drop_column_; - - struct drop_foreign_key: relational::drop_foreign_key, context - { - drop_foreign_key (base const& x): base (x) {} - - virtual void - traverse (sema_rel::drop_foreign_key& dfk) - { - os << endl; - drop (dfk); - } - }; - entry drop_foreign_key_; - - struct drop_index: relational::drop_index, context - { - drop_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In Oracle, index names can be qualified with the schema. - // - sema_rel::table& t (static_cast (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - return quote_id (n); - } - }; - entry drop_index_; - - struct drop_table: relational::drop_table, context - { - drop_table (base const& x): base (x) {} - - virtual void - drop (sema_rel::table& t, bool migration) - { - using sema_rel::primary_key; - - sema_rel::table::names_iterator i (t.find ("")); // Special name. - primary_key* pk (i != t.names_end () - ? &dynamic_cast (i->nameable ()) - : 0); - - string qt (quote_id (t.name ())); - string qs (pk != 0 && pk->auto_ () - ? quote_id (qname::from_string (pk->extra ()["sequence"])) - : ""); - - if (migration) - { - pre_statement (); - os << "DROP TABLE " << qt << endl; - post_statement (); - - // Drop the sequence if we have auto primary key. - // - if (!qs.empty ()) - { - pre_statement (); - os << "DROP SEQUENCE " << qs << endl; - post_statement (); - } - } - else - { - // Oracle has no IF EXISTS conditional for dropping objects. The - // PL/SQL approach below seems to be the least error-prone and the - // most widely used of the alternatives. - // - pre_statement (); - os << "BEGIN" << endl - << " BEGIN" << endl - << " EXECUTE IMMEDIATE 'DROP TABLE " << qt << " CASCADE " << - "CONSTRAINTS';" << endl - << " EXCEPTION" << endl - << " WHEN OTHERS THEN" << endl - << " IF SQLCODE != -942 THEN RAISE; END IF;" << endl - << " END;" << endl; - - // Drop the sequence if we have auto primary key. - // - if (!qs.empty ()) - { - os << " BEGIN" << endl - << " EXECUTE IMMEDIATE 'DROP SEQUENCE " << qs << - "';" << endl - << " EXCEPTION" << endl - << " WHEN OTHERS THEN" << endl - << " IF SQLCODE != -2289 THEN RAISE; END IF;" << endl - << " END;" << endl; - } - - os << "END;" << endl; - post_statement (); - } - } - - virtual void - traverse (sema_rel::table& t, bool migration) - { - // For migration drop foreign keys explicitly in pre-migration. - // - if (migration) - { - base::traverse (t, migration); - return; - } - - // For schema creation we use the CASCADE clause to drop foreign - // keys. - // - if (pass_ != 2) - return; - - drop (t, migration); - } - }; - entry drop_table_; - - // - // Create. - // - static sema_rel::uname - truncate (location const& l, const char* kind, sema_rel::uname n, bool w) - { - if (n.size () > 30) - { - if (w) - warn (l) << kind << " name '" << n << "' is longer than 30 " - << "characters and will be truncated" << endl; - - n.resize (30); - } - - return n; - } - - static sema_rel::qname - truncate (location const& l, - const char* kind, - sema_rel::qname const& n, - bool w) - { - // Don't bother verifying the schema name since that is - // specified explicitly and in a single place. - // - qname r (n.qualifier ()); - r.append (truncate (l, kind, n.uname (), w)); - return r; - } - - template - struct scope - { - typedef std::map > map; - - scope (const char* k, const char* p, bool w) - : kind_ (k), prag_ (p), warn_ (w) {} - - void - check (location const& l, N const& n) - { - N tn (truncate (l, kind_, n, warn_)); - - pair r ( - map_.insert (make_pair (tn, make_pair (n, l)))); - - if (r.second) - return; - - error (l) << kind_ << " name '" << tn << "' conflicts with an " - << "already defined " << kind_ << " name" << endl; - - if (tn != n) - info (l) << kind_ << " name '" << tn << "' is truncated '" - << n << "'" << endl; - - N const& n1 (r.first->second.first); - location const& l1 (r.first->second.second); - - info (l1) << "conflicting " << kind_ << " is defined here" << endl; - - if (tn != n) - info (l1) << "conflicting " << kind_ << " name '" << tn - << "' is truncated '" << n1 << "'" << endl; - - info (l) << "use #pragma db " << prag_ << " to change one of " - << "the names" << endl; - - throw operation_failed (); - } - - void - clear () {map_.clear ();} - - const char* kind_; - const char* prag_; - bool warn_; - map map_; - }; - - struct scopes - { - scopes (bool warn) - : tables ("table", "table", warn), - fkeys ("foreign key", "column", warn), // Change column name. - indexes ("index", "index", warn), - sequences ("sequence", "table", warn), // Change table name. - columns ("column", "column", warn) {} - - // In Oracle, all these entities are in their own name spaces, - // as in an index and a foreign key with the same name do not - // conflict. - // - scope tables; - scope fkeys; // Global but can't have schema. - scope indexes; - scope sequences; - scope columns; - }; - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::column& c) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast (context::extra)) - s->columns.check (c.get ("cxx-location"), c.name ()); - - base::traverse (c); - } - - virtual void - traverse (sema_rel::add_column& ac) - { - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - create (ac); - } - - virtual void - constraints (sema_rel::column& c, sema_rel::primary_key* pk) - { - // Oracle wants DEFAULT before NULL even though we can end - // up with mouthfulls like DEFAULT NULL NULL. - // - if (!c.default_ ().empty ()) - os << " DEFAULT " << c.default_ (); - - null (c); - - // If this is a single-column primary key, generate it inline. - // - if (pk != 0 && pk->contains_size () == 1) - primary_key (); - - if (pk != 0 && pk->auto_ ()) - auto_ (*pk); - } - }; - entry create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - virtual void - traverse_create (sema_rel::foreign_key& fk) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast (context::extra)) - s->fkeys.check (fk.get ("cxx-location"), fk.name ()); - - base::traverse_create (fk); - } - - virtual void - traverse_add (sema_rel::foreign_key& fk) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast (context::extra)) - s->fkeys.check (fk.get ("cxx-location"), fk.name ()); - - os << endl - << " ADD CONSTRAINT "; - create (fk); - } - }; - entry create_foreign_key_; - - struct create_index: relational::create_index, context - { - create_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In Oracle, index names can be qualified with the schema. - // - sema_rel::table& t (static_cast (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - - // Check name trunction and conflicts. - // - if (scopes* s = static_cast (context::extra)) - s->indexes.check (in.get ("cxx-location"), n); - - return quote_id (n); - } - }; - entry create_index_; - - struct create_table: relational::create_table, context - { - create_table (base const& x): base (x) {} - - void - traverse (sema_rel::table& t) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast (context::extra)) - { - if (pass_ == 1) - { - s->tables.check (t.get ("cxx-location"), t.name ()); - s->columns.clear (); - } - } - - base::traverse (t); - - if (pass_ == 1) - { - // Create the sequence if we have auto primary key. - // - using sema_rel::primary_key; - - sema_rel::table::names_iterator i (t.find ("")); // Special name. - primary_key* pk (i != t.names_end () - ? &dynamic_cast (i->nameable ()) - : 0); - - if (pk != 0 && pk->auto_ ()) - { - // Already qualified with the table's schema, if any. - // - sema_rel::qname n ( - qname::from_string (pk->extra ()["sequence"])); - - if (scopes* s = static_cast (context::extra)) - s->sequences.check (pk->get ("cxx-location"), n); - - pre_statement (); - os_ << "CREATE SEQUENCE " << quote_id (n) << endl - << " START WITH 1 INCREMENT BY 1" << endl; - post_statement (); - } - } - } - }; - entry create_table_; - - struct create_model: relational::create_model, context - { - create_model (base const& x): base (x) {} - - void - traverse (sema_rel::model& m) - { - scopes s (options.oracle_warn_truncation ()); - context::extra = &s; - base::traverse (m); - context::extra = 0; - } - }; - entry create_model_; - - // - // Alter. - // - - struct alter_column: relational::alter_column, context - { - alter_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::column& c) - { - // Relax (NULL) in pre and tighten (NOT NULL) in post. - // - if (pre_ != c.null ()) - return; - - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - os << quote_id (c.name ()) << (c.null () ? " NULL" : " NOT NULL"); - } - }; - entry alter_column_; - - struct alter_table_pre: relational::alter_table_pre, context - { - alter_table_pre (base const& x): base (x) {} - - virtual void - alter (sema_rel::alter_table& at) - { - // Oracle can only alter certain kinds of things together but - // grouped one at a time. - // - if (check (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()); - - instance dfc (*this); - trav_rel::unames n (*dfc); - names (at, n); - os << endl; - - post_statement (); - } - - if (check (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ADD ("; - - instance cc (*this); - trav_rel::unames n (*cc); - names (at, n); - os << ")" << endl; - - post_statement (); - } - - if (check_alter_column_null (at, true)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " MODIFY ("; - - bool tl (true); // (Im)perfect forwarding. - instance ac (*this, tl); - trav_rel::unames n (*ac); - names (at, n); - os << ")" << endl; - - post_statement (); - } - } - }; - entry alter_table_pre_; - - struct alter_table_post: relational::alter_table_post, context - { - alter_table_post (base const& x): base (x) {} - - virtual void - alter (sema_rel::alter_table& at) - { - // Oracle can only alter certain kinds of things together but - // grouped one at a time. - // - if (check (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " DROP ("; - - instance dc (*this); - trav_rel::unames n (*dc); - names (at, n); - os << ")" << endl; - - post_statement (); - } - - if (check_alter_column_null (at, false)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " MODIFY ("; - - bool fl (false); // (Im)perfect forwarding. - instance ac (*this, fl); - trav_rel::unames n (*ac); - names (at, n); - os << ")" << endl; - - post_statement (); - } - - if (check (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()); - - instance cfc (*this); - trav_rel::unames n (*cfc); - names (at, n); - os << endl; - - post_statement (); - } - } - }; - entry alter_table_post_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x) - : base (x) - { - // If the schema name is empty, replace it with a single space - // to workaround the VARCHAR2 empty/NULL issue. - // - if (qs_ == "''") - qs_ = "' '"; - } - - virtual void - create_table () - { - pre_statement (); - - os << "BEGIN" << endl - << " EXECUTE IMMEDIATE 'CREATE TABLE " << qt_ << " (" << endl - << " " << qn_ << " VARCHAR2(512) NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " NUMBER(20) NOT NULL," << endl - << " " << qm_ << " NUMBER(1) NOT NULL)';" << endl - << "EXCEPTION" << endl - << " WHEN OTHERS THEN" << endl - << " IF SQLCODE != -955 THEN RAISE; END IF;" << endl - << "END;" << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - os << "MERGE INTO " << qt_ << " USING DUAL ON (" << qn_ << " = " << - qs_ << ")" << endl - << " WHEN NOT MATCHED THEN INSERT (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", 0)" << endl; - - post_statement (); - } - }; - entry version_table_; - } - } -} diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx deleted file mode 100644 index adf9864..0000000 --- a/odb/relational/oracle/source.cxx +++ /dev/null @@ -1,646 +0,0 @@ -// file : odb/relational/oracle/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace oracle - { - namespace source - { - namespace relational = relational::source; - - struct query_parameters: relational::query_parameters, context - { - query_parameters (base const& x): base (x), i_ (0) {} - - virtual string - next (semantics::data_member&, const string&, const string&) - { - ostringstream ss; - ss << ":" << ++i_; - - return ss.str (); - } - - virtual string - auto_id (semantics::data_member&, const string&, const string&) - { - return quote_id (sequence_name (table_)) + ".nextval"; - } - - private: - size_t i_; - }; - entry query_parameters_; - - namespace - { - const char* string_buffer_types[] = - { - "oracle::bind::string", // CHAR - "oracle::bind::nstring", // NCHAR - "oracle::bind::string", // VARCHAR2 - "oracle::bind::nstring", // NVARCHAR2 - "oracle::bind::raw" // RAW - }; - - const char* lob_buffer_types[] = - { - "oracle::bind::blob", - "oracle::bind::clob", - "oracle::bind::nclob" - }; - } - - // - // bind - // - - struct bind_member: relational::bind_member_impl, - member_base - { - bind_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_int32 (member_info& mi) - { - os << b << ".type = oracle::bind::" << - (unsigned_integer (mi.t) ? "uinteger" : "integer") << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".capacity = 4;" - << b << ".size = 0;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_int64 (member_info& mi) - { - os << b << ".type = oracle::bind::" << - (unsigned_integer (mi.t) ? "uinteger" : "integer") << ";" - << b << ".buffer= &" << arg << "." << mi.var << "value;" - << b << ".capacity = 8;" - << b << ".size = 0;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_big_int (member_info& mi) - { - os << b << ".type = oracle::bind::number;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".capacity = static_cast (sizeof (" << arg << - "." << mi.var << "value));" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_float (member_info& mi) - { - os << b << ".type = oracle::bind::binary_float;" - << b << ".buffer= &" << arg << "." << mi.var << "value;" - << b << ".capacity = 4;" - << b << ".size = 0;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_double (member_info& mi) - { - os << b << ".type = oracle::bind::binary_double;" - << b << ".buffer= &" << arg << "." << mi.var << "value;" - << b << ".capacity = 8;" - << b << ".size = 0;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_big_float (member_info& mi) - { - os << b << ".type = oracle::bind::number;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".capacity = static_cast (sizeof (" << arg << "." << - mi.var << "value));" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_date (member_info& mi) - { - os << b << ".type = oracle::bind::date;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".capacity = static_cast (sizeof (" << arg << "." << - mi.var << "value));" - << b << ".size = 0;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_timestamp (member_info& mi) - { - os << b << ".type = oracle::bind::timestamp;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_interval_ym (member_info& mi) - { - os << b << ".type = oracle::bind::interval_ym;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_interval_ds (member_info& mi) - { - os << b << ".type = oracle::bind::interval_ds;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << b << ".type = " << - string_buffer_types[mi.st->type - sql_type::CHAR] << ";" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".capacity = static_cast (sizeof (" << arg << - "." << mi.var << "value));" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;"; - } - - virtual void - traverse_lob (member_info& mi) - { - os << b << ".type = " << - lob_buffer_types[mi.st->type - sql_type::BLOB] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "lob;" - << b << ".indicator = &" << arg << "." << mi.var << "indicator;" - << b << ".callback = &" << arg << "." << mi.var << "callback;" - << endl; - } - }; - entry bind_member_; - - // - // init image - // - - struct init_image_member: relational::init_image_member_impl, - member_base - { - init_image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - check_accessor (member_info& mi, member_access& ma) - { - // We cannot use accessors that return by-value for LOB - // members. - // - if ((mi.st->type == sql_type::BLOB || - mi.st->type == sql_type::CLOB || - mi.st->type == sql_type::NCLOB) && - ma.by_value) - { - error (ma.loc) << "accessor returning a value cannot be used " - << "for a data member of Oracle LOB type" << endl; - info (ma.loc) << "accessor returning a const reference is required" - << endl; - info (mi.m.location ()) << "data member is defined here" << endl; - throw operation_failed (); - } - } - - virtual void - set_null (member_info& mi) - { - os << "i." << mi.var << "indicator = -1;"; - } - - virtual void - traverse_int32 (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_int64 (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_big_int (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;" - << "i." << mi.var << "size = static_cast (size);"; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_double (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_big_float (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "sizeof (i." << mi.var << "value)," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;" - << "i." << mi.var << "size = static_cast (size);"; - } - - virtual void - traverse_date (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_timestamp (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_interval_ym (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_interval_ds (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "sizeof (i." << mi.var << "value)," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;" - << "i." << mi.var << "size = static_cast (size);"; - } - - virtual void - traverse_lob (member_info& mi) - { - os << "i." << mi.var << "lob.position = 0;" - << traits << "::set_image (" << endl - << "i." << mi.var << "callback.callback.param," << endl - << "i." << mi.var << "callback.context.param," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "indicator = is_null ? -1 : 0;"; - } - }; - entry init_image_member_; - - // - // init value - // - - struct init_value_member: relational::init_value_member_impl, - member_base - { - init_value_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - get_null (string const& var) const - { - os << "i." << var << "indicator == -1"; - } - - virtual void - check_modifier (member_info& mi, member_access& ma) - { - // We cannot use by-value modifier for LOB members. - // - if ((mi.st->type == sql_type::BLOB || - mi.st->type == sql_type::CLOB || - mi.st->type == sql_type::NCLOB) && - ma.placeholder ()) - { - error (ma.loc) << "modifier accepting a value cannot be used " - << "for a data member of Oracle LOB type" << endl; - info (ma.loc) << "modifier returning a non-const reference is " - << "required" << endl; - info (mi.m.location ()) << "data member is defined here" << endl; - throw operation_failed (); - } - } - - virtual void - traverse_int32 (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_int64 (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_big_int (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_double (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_big_float (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_date (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_timestamp (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_interval_ym (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_interval_ds (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - - virtual void - traverse_lob (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "callback.callback.result," << endl - << "i." << mi.var << "callback.context.result," << endl - << "i." << mi.var << "indicator == -1);" - << endl; - } - }; - entry init_value_member_; - - struct container_traits: relational::container_traits, context - { - container_traits (base const& x): base (x) {} - - virtual void - cache_result (string const&) - { - // Caching is not necessary since Oracle can execute several - // interleaving statements. - // - } - - virtual void - init_value_extra () - { - os << "sts.select_statement ().stream_result ();" - << endl; - } - }; - entry container_traits_; - - struct section_traits: relational::section_traits, context - { - section_traits (base const& x): base (x) {} - - virtual void - init_value_extra () - { - os << "st.stream_result ();"; - } - }; - entry section_traits_; - - struct class_: relational::class_, context - { - class_ (base const& x): base (x) {} - - virtual void - init_image_pre (type& c) - { - if (options.generate_query () && - !(composite (c) || (abstract (c) && !polymorphic (c)))) - { - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - if (poly_derived) - os << "{" - << "root_traits::image_type& ri (root_image (i));" - << endl; - - string i (poly_derived ? "ri" : "i"); - - os << "if (" << i << ".change_callback_.callback != 0)" << endl - << "(" << i << ".change_callback_.callback) (" << - i << ".change_callback_.context);"; - - if (poly_derived) - os << "}"; - else - os << endl; - } - } - - virtual void - init_value_extra () - { - os << "st.stream_result ();"; - } - - virtual string - persist_statement_extra (type& c, - relational::query_parameters& qp, - persist_position p) - { - string r; - - if (p == persist_after_values) - { - data_member_path* id (id_member (c)); - - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - // Top-level auto id. - // - if (id != 0 && !poly_derived && auto_ (*id)) - { - semantics::data_member& idb (*id->back ()); - - const string& name (column_qname (*id)); - const string& type (column_type (idb)); - - r = "RETURNING " + convert_from (name, type, idb) + - " INTO " + qp.next (idb, name, type); - } - } - - return r; - } - - virtual string - select_trailer (type& c) - { - view_query const& vq (c.get ("query")); - - if (vq.for_update && vq.distinct) - { - error (vq.loc) - << "Oracle does not support FOR UPDATE with DISTINCT" << endl; - throw operation_failed (); - } - - return base::select_trailer (c); - } - }; - entry class_entry_; - } - } -} diff --git a/odb/relational/pgsql/common.cxx b/odb/relational/pgsql/common.cxx deleted file mode 100644 index 6a59954..0000000 --- a/odb/relational/pgsql/common.cxx +++ /dev/null @@ -1,351 +0,0 @@ -// file : odb/relational/pgsql/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace relational -{ - namespace pgsql - { - // - // member_base - // - - sql_type const& member_base:: - member_sql_type (semantics::data_member& m) - { - return parse_sql_type (column_type (m, key_prefix_), m); - } - - void member_base:: - traverse_simple (member_info& mi) - { - switch (mi.st->type) - { - // Integral types. - // - case sql_type::BOOLEAN: - case sql_type::SMALLINT: - case sql_type::INTEGER: - case sql_type::BIGINT: - { - traverse_integer (mi); - break; - } - - // Float types. - // - case sql_type::REAL: - case sql_type::DOUBLE: - { - traverse_float (mi); - break; - } - case sql_type::NUMERIC: - { - traverse_numeric (mi); - break; - } - - // Data-time types. - // - case sql_type::DATE: - case sql_type::TIME: - case sql_type::TIMESTAMP: - { - traverse_date_time (mi); - break; - } - - // String and binary types. - // - case sql_type::CHAR: - case sql_type::VARCHAR: - case sql_type::TEXT: - case sql_type::BYTEA: - { - traverse_string (mi); - break; - } - case sql_type::BIT: - { - traverse_bit (mi); - break; - } - case sql_type::VARBIT: - { - traverse_varbit (mi); - break; - } - // Other types. - // - case sql_type::UUID: - { - traverse_uuid (mi); - break; - } - case sql_type::invalid: - { - assert (false); - break; - } - } - } - - // - // member_image_type - // - - namespace - { - const char* integer_types[] = - { - "bool", - "short", - "int", - "long long" - }; - - const char* float_types[] = - { - "float", - "double" - }; - - const char* date_time_types[] = - { - "int", - "long long", - "long long" - }; - } - - member_image_type:: - member_image_type (base const& x) - : member_base::base (x), // virtual base - base (x) - { - } - - member_image_type:: - member_image_type () - : relational::member_base (0, 0, string (), string ()) {} - - member_image_type:: - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, ct, fq_type, key_prefix) {} - - string member_image_type:: - image_type (semantics::data_member& m) - { - type_.clear (); - member_base::traverse (m, true); - return type_; - } - - void member_image_type:: - traverse_composite (member_info& mi) - { - type_ = "composite_value_traits< " + mi.fq_type () + - ", id_pgsql >::image_type"; - } - - void member_image_type:: - traverse_integer (member_info& mi) - { - type_ += integer_types[mi.st->type - sql_type::BOOLEAN]; - } - - void member_image_type:: - traverse_float (member_info& mi) - { - type_ = float_types[mi.st->type - sql_type::REAL]; - } - - void member_image_type:: - traverse_numeric (member_info&) - { - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_date_time (member_info& mi) - { - type_ = date_time_types[mi.st->type - sql_type::DATE]; - } - - void member_image_type:: - traverse_string (member_info&) - { - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_bit (member_info&) - { - type_ = "unsigned char*"; - } - - void member_image_type:: - traverse_varbit (member_info&) - { - type_ = "details::ubuffer"; - } - - void member_image_type:: - traverse_uuid (member_info&) - { - type_ = "unsigned char*"; - } - - entry member_image_type_; - - // - // member_database_type - // - - namespace - { - const char* integer_database_id[] = - { - "id_boolean", - "id_smallint", - "id_integer", - "id_bigint" - }; - - const char* float_database_id[] = - { - "id_real", - "id_double" - }; - - const char* date_time_database_id[] = - { - "id_date", - "id_time", - "id_timestamp" - }; - - const char* char_bin_database_id[] = - { - "id_string", // CHAR - "id_string", // VARCHAR - "id_string", // TEXT, - "id_bytea" // BYTEA - }; - } - - member_database_type_id:: - member_database_type_id (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_database_type_id:: - member_database_type_id () - : member_base::base (0, 0, string (), string ()), // virtual base - base (0, 0, string (), string ()) {} - - member_database_type_id:: - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base::base (type, ct, fq_type, key_prefix), // virtual base - base (type, ct, fq_type, key_prefix) {} - - string member_database_type_id:: - database_type_id (type& m) - { - type_id_.clear (); - member_base::traverse (m, true); - return type_id_; - } - - void member_database_type_id:: - traverse_composite (member_info&) - { - assert (false); - } - - void member_database_type_id:: - traverse_integer (member_info& mi) - { - type_id_ = string ("pgsql::") + - integer_database_id[mi.st->type - sql_type::BOOLEAN]; - } - - void member_database_type_id:: - traverse_float (member_info& mi) - { - type_id_ = string ("pgsql::") + - float_database_id[mi.st->type - sql_type::REAL]; - } - - void member_database_type_id:: - traverse_numeric (member_info&) - { - type_id_ = "pgsql::id_numeric"; - } - - void member_database_type_id:: - traverse_date_time (member_info& mi) - { - type_id_ = string ("pgsql::") + - date_time_database_id[mi.st->type - sql_type::DATE]; - } - - void member_database_type_id:: - traverse_string (member_info& mi) - { - type_id_ = string ("pgsql::") + - char_bin_database_id[mi.st->type - sql_type::CHAR]; - } - - void member_database_type_id:: - traverse_bit (member_info&) - { - type_id_ = "pgsql::id_bit"; - } - - void member_database_type_id:: - traverse_varbit (member_info&) - { - type_id_ = "pgsql::id_varbit"; - } - - void member_database_type_id:: - traverse_uuid (member_info&) - { - type_id_ = "pgsql::id_uuid"; - } - - entry member_database_type_id_; - - // - // query_columns - // - - struct query_columns: relational::query_columns, context - { - query_columns (base const& x): base_impl (x) {} - - virtual string - database_type_id (semantics::data_member& m) - { - return member_database_type_id_.database_type_id (m); - } - - private: - member_database_type_id member_database_type_id_; - }; - entry query_columns_; - } -} diff --git a/odb/relational/pgsql/common.hxx b/odb/relational/pgsql/common.hxx deleted file mode 100644 index 1d383bf..0000000 --- a/odb/relational/pgsql/common.hxx +++ /dev/null @@ -1,159 +0,0 @@ -// file : odb/relational/pgsql/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_PGSQL_COMMON_HXX -#define ODB_RELATIONAL_PGSQL_COMMON_HXX - -#include -#include - -namespace relational -{ - namespace pgsql - { - struct member_base: virtual relational::member_base_impl, context - { - member_base (base const& x): base (x), base_impl (x) {} - - // This c-tor is for the direct use inside the pgsql namespace. - // If you do use this c-tor, you should also explicitly call - // relational::member_base (aka base). - // - member_base () {} - - virtual sql_type const& - member_sql_type (semantics::data_member&); - - virtual void - traverse_simple (member_info&); - - virtual void - traverse_integer (member_info&) - { - } - - virtual void - traverse_float (member_info&) - { - } - - virtual void - traverse_numeric (member_info&) - { - } - - virtual void - traverse_date_time (member_info&) - { - } - - virtual void - traverse_string (member_info&) - { - } - - virtual void - traverse_bit (member_info&) - { - } - - virtual void - traverse_varbit (member_info&) - { - } - - virtual void - traverse_uuid (member_info&) - { - } - }; - - struct member_image_type: relational::member_image_type, - member_base - { - member_image_type (base const&); - member_image_type (); - member_image_type (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - virtual string - image_type (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_float (member_info&); - - virtual void - traverse_numeric (member_info&); - - virtual void - traverse_date_time (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_bit (member_info&); - - virtual void - traverse_varbit (member_info&); - - virtual void - traverse_uuid (member_info&); - - private: - string type_; - }; - - struct member_database_type_id: relational::member_database_type_id, - member_base - { - member_database_type_id (base const&); - member_database_type_id (); - member_database_type_id (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - - virtual string - database_type_id (type&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_float (member_info&); - - virtual void - traverse_numeric (member_info&); - - virtual void - traverse_date_time (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_bit (member_info&); - - virtual void - traverse_varbit (member_info&); - - virtual void - traverse_uuid (member_info&); - - private: - string type_id_; - }; - } -} -#endif // ODB_RELATIONAL_PGSQL_COMMON_HXX diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx deleted file mode 100644 index 7f99f5d..0000000 --- a/odb/relational/pgsql/context.cxx +++ /dev/null @@ -1,786 +0,0 @@ -// file : odb/relational/pgsql/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -#include - -#include -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace pgsql - { - namespace - { - struct type_map_entry - { - char const* const cxx_type; - char const* const db_type; - char const* const db_id_type; - bool const null; - }; - - type_map_entry type_map[] = - { - {"bool", "BOOLEAN", 0, false}, - - {"char", "CHAR(1)", 0, false}, - {"signed char", "SMALLINT", 0, false}, - {"unsigned char", "SMALLINT", 0, false}, - - {"short int", "SMALLINT", 0, false}, - {"short unsigned int", "SMALLINT", 0, false}, - - {"int", "INTEGER", 0, false}, - {"unsigned int", "INTEGER", 0, false}, - - {"long int", "BIGINT", 0, false}, - {"long unsigned int", "BIGINT", 0, false}, - - {"long long int", "BIGINT", 0, false}, - {"long long unsigned int", "BIGINT", 0, false}, - - {"float", "REAL", 0, false}, - {"double", "DOUBLE PRECISION", 0, false}, - - {"::std::string", "TEXT", 0, false}, - - {"::size_t", "BIGINT", 0, false}, - {"::std::size_t", "BIGINT", 0, false} - }; - } - - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context (ostream& os, - semantics::unit& u, - options_type const& ops, - features_type& f, - sema_rel::model* m) - : root_context (os, u, ops, f, data_ptr (new (shared) data (os))), - base_context (static_cast (root_context::data_.get ()), m), - data_ (static_cast (base_context::data_)) - { - assert (current_ == 0); - current_ = this; - - generate_grow = true; - need_alias_as = true; - insert_send_auto_id = false; - delay_freeing_statement_result = false; - need_image_clone = false; - generate_bulk = true; - global_index = true; - global_fkey = false; - data_->bind_vector_ = "pgsql::bind*"; - data_->truncated_vector_ = "bool*"; - - // Populate the C++ type to DB type map. - // - for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i) - { - type_map_entry const& e (type_map[i]); - - type_map_type::value_type v ( - e.cxx_type, - db_type_type ( - e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null)); - - data_->type_map_.insert (v); - } - } - - context:: - context () - : data_ (current ().data_) - { - } - - namespace - { - struct has_grow: traversal::class_ - { - has_grow (bool& r, user_section* s) - : r_ (r), section_ (s) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - // Ignore transient bases. - // - if (!(context::object (c) || context::composite (c))) - return; - - if (section_ == 0 && c.count ("pgsql-grow")) - r_ = c.get ("pgsql-grow"); - else - { - // r_ should be false. - // - inherits (c); - - if (!r_) - names (c); - - if (section_ == 0) - c.set ("pgsql-grow", r_); - } - } - - private: - bool& r_; - user_section* section_; - traversal::inherits inherits_; - }; - - struct has_grow_member: member_base - { - has_grow_member (bool& r, user_section* section = 0) - : relational::member_base (0, 0, string (), string (), section), - r_ (r) {} - - has_grow_member (bool& r, - user_section* section, - semantics::type* t, - const custom_cxx_type* ct, - string const& key_prefix = string ()) - : relational::member_base (t, ct, string (), key_prefix, section), - r_ (r) {} - - virtual bool - pre (member_info& mi) - { - // If we have a key prefix (container), then it can't be in a - // section (while mi.m can). The same for top-level -- if we got - // called, then we shouldn't ignore it. - // - return !key_prefix_.empty () || top_level_ || - (section_ == 0 && !separate_load (mi.m)) || - (section_ != 0 && *section_ == section (mi.m)); - } - - virtual void - traverse_composite (member_info& mi) - { - // By calling grow() instead of recursing, we reset any overrides. - // We also don't pass section since they don't apply inside - // composites. - // - r_ = r_ || context::grow (dynamic_cast (mi.t)); - } - - virtual void - traverse_numeric (member_info&) - { - r_ = true; - } - - virtual void - traverse_string (member_info&) - { - r_ = true; - } - - virtual void - traverse_varbit (member_info&) - { - r_ = true; - } - - private: - bool& r_; - }; - } - - bool context:: - grow_impl (semantics::class_& c, user_section* section) - { - if (section == 0 && c.count ("pgsql-grow")) - return c.get ("pgsql-grow"); - - bool r (false); - has_grow ct (r, section); - has_grow_member mt (r, section); - traversal::names names; - ct >> names >> mt; - ct.traverse (c); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m) - { - bool r (false); - has_grow_member mt (r); - mt.traverse (m, true); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m, - semantics::type& t, - const custom_cxx_type* ct, - string const& kp) - { - bool r (false); - has_grow_member mt (r, 0, &t, ct, kp); - mt.traverse (m, true); - return r; - } - - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - - string context:: - quote_id_impl (qname const& id) const - { - string r; - - bool f (true); - for (qname::iterator i (id.begin ()); i < id.end (); ++i) - { - if (i->empty ()) - continue; - - // Warn if the name is greater than the (NAMEDATALEN - 1) limit, - // which is 63 in the default PG build. - // - if (i->size () > 63) - { - cerr << "warning: SQL name '" << *i << "' is longer than " - << "the default PostgreSQL name limit of 63 characters " - << "and may be truncated" << endl; - - cerr << "info: consider shortening it using #pragma db " - << "table/column/index or --*-regex options" << endl; - } - - if (f) - f = false; - else - r += '.'; - - r += '"'; - r += *i; - r += '"'; - } - - return r; - } - - string context:: - statement_name (string const& type, string const& name, semantics::node& n) - { - // Put the type first so that in the case of truncation it - // remains thus lowering the chance of a clash. - // - string r (type); - r += '_'; - r += name; - - r = transform_name (r, sql_name_statement); - - // Warn if the name is greater than the (NAMEDATALEN - 1) limit, - // which is 63 in the default PG build. - // - // Note that we have to do it in addition to the above since this - // name doesn't go through quote_id(). - // - if (r.size () > 63) - { - location const& l (n.location ()); - - warn (l) << "prepared statement name '" << r << "' is longer than " - << "the default PostgreSQL name limit of 63 characters " - << "and may be truncated" << endl; - - info (l) << "consider shortening the corresponding namespace " - << "name, class name, or data member name" << endl; - - info (l) << "or shortening the statement name itself using the " - << "--statement-regex option" << endl; - } - - return r; - } - - string context:: - database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) - { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - - using semantics::array; - - // char[N] mapping. - // - if (array* a = dynamic_cast (&t)) - { - semantics::type& bt (a->base_type ()); - if (bt.is_a ()) - { - unsigned long long n (a->size ()); - - if (n == 0) - return r; - else if (n == 1) - r = "CHAR("; - else - { - r = "VARCHAR("; - n--; - } - - ostringstream ostr; - ostr << n; - r += ostr.str (); - r += ')'; - } - } - - return r; - } - - // - // SQL type parsing. - // - - sql_type const& context:: - parse_sql_type (string const& t, semantics::data_member& m, bool custom) - { - // If this proves to be too expensive, we can maintain a cache of - // parsed types across contexts. - // - data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - - if (i != data_->sql_type_cache_.end () - && (custom ? i->second.custom_cached : i->second.straight_cached)) - { - return (custom ? i->second.custom : i->second.straight); - } - else - { - try - { - sql_type st ( - parse_sql_type ( - t, - custom ? &unit.get ("custom-db-types") : 0)); - - if (custom) - return data_->sql_type_cache_[t].cache_custom (st); - else - return data_->sql_type_cache_[t].cache_straight (st); - } - catch (invalid_sql_type const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: " << e.message () << endl; - - throw operation_failed (); - } - } - } - - inline sql_type - error (bool fail, string const& m) - { - if (!fail) - return sql_type (); - else - throw context::invalid_sql_type (m); - } - - sql_type context:: - parse_sql_type (string sqlt, custom_db_types const* ct) - { - try - { - sql_type r; - - // First run the type through the custom mapping, if requested. - // - if (ct != 0) - { - for (custom_db_types::const_iterator i (ct->begin ()); - i != ct->end (); ++i) - { - custom_db_type const& t (*i); - - if (t.type.match (sqlt)) - { - r.to = t.type.replace (sqlt, t.to); - r.from = t.type.replace (sqlt, t.from); - sqlt = t.type.replace (sqlt, t.as); - break; - } - } - } - - sql_lexer l (sqlt); - - // While most type names use single identifier, there are - // a couple of exceptions to this rule: - // - // BIT VARYING (VARBIT) - // CHARACTER VARYING (VARRCHAR) - // DOUBLE PRECISION (DOUBLE) - // TIME WITH TIME ZONE (not currently supported) - // TIMESTAMP WITH TIME ZONE (not currently supported) - // - - enum state - { - parse_prefix, - parse_name, - parse_range, - parse_suffix, - parse_done - }; - - state s (parse_prefix); - string prefix; - bool flt (false); - - for (sql_token t (l.next ()); - s != parse_done && t.type () != sql_token::t_eos; - t = l.next ()) - { - sql_token::token_type tt (t.type ()); - - switch (s) - { - case parse_prefix: - { - if (tt == sql_token::t_identifier) - { - string const& id (context::upcase (t.identifier ())); - - if (id == "BIT" || - id == "CHARACTER" || - id == "DOUBLE") - { - prefix = id; - s = parse_name; - continue; - } - } - - s = parse_name; - } - // Fall through. - case parse_name: - { - if (tt == sql_token::t_identifier) - { - bool match (true); - string const& id (context::upcase (t.identifier ())); - - // - // Numeric types. - // - if (id == "BOOL" || id == "BOOLEAN") - { - r.type = sql_type::BOOLEAN; - } - else if (id == "SMALLINT" || id == "INT2") - { - r.type = sql_type::SMALLINT; - } - else if (id == "INT" || - id == "INTEGER" || - id == "INT4") - { - r.type = sql_type::INTEGER; - } - else if (id == "BIGINT") - { - r.type = sql_type::BIGINT; - } - else if (id == "REAL" || id == "FLOAT4") - { - r.type = sql_type::REAL; - } - else if ((id == "PRECISION" && prefix == "DOUBLE") || - id == "FLOAT8") - { - r.type = sql_type::DOUBLE; - } - else if (id == "FLOAT") - { - // Assign a type only once we know the precision of the - // float. - // - flt = true; - } - else if (id == "NUMERIC" || id == "DECIMAL") - { - r.type = sql_type::NUMERIC; - } - // - // Date-time types. - // - else if (id == "DATE") - { - r.type = sql_type::DATE; - } - else if (id == "TIME") - { - r.type = sql_type::TIME; - } - else if (id == "TIMETZ") - { - return error (ct, "PostgreSQL time zones are not currently " - "supported"); - } - else if (id == "TIMESTAMP") - { - r.type = sql_type::TIMESTAMP; - } - else if (id == "TIMESTAMPTZ") - { - return error (ct, "PostgreSQL time zones are not currently " - "supported"); - } - // - // String and binary types. - // - else if (id == "CHAR") - { - r.type = sql_type::CHAR; - } - else if (id == "VARCHAR") - { - r.type = sql_type::VARCHAR; - } - else if (id == "TEXT") - { - r.type = sql_type::TEXT; - } - else if (id == "VARYING") - { - if (prefix == "BIT") - r.type = sql_type::VARBIT; - else if (prefix == "CHARACTER") - r.type = sql_type::VARCHAR; - } - else if (id == "BYTEA") - { - r.type = sql_type::BYTEA; - } - else if (id == "VARBIT") - { - r.type = sql_type::VARBIT; - } - // - // Other types. - // - else if (id == "UUID") - { - r.type = sql_type::UUID; - } - else - match = false; - - if (match) - { - s = parse_range; - continue; - } - } - - // Some prefixes can also be type names if not followed - // by the actual type name. - // - if (!prefix.empty ()) - { - if (prefix == "BIT") - { - r.type = sql_type::BIT; - } - else if (prefix == "CHARACTER") - { - r.type = sql_type::CHAR; - } - } - - if (r.type == sql_type::invalid) - { - return error ( - ct, - tt == sql_token::t_identifier - ? "unknown PostgreSQL type '" + t.identifier () + "'" - : "expected PostgreSQL type name"); - } - - s = parse_range; - } - // Fall through. - case parse_range: - { - if (t.punctuation () == sql_token::p_lparen) - { - t = l.next (); - - if (t.type () != sql_token::t_int_lit) - { - return error (ct, "integer range expected in PostgreSQL " - "type declaration"); - } - - unsigned int v; - istringstream is (t.literal ()); - - if (!(is >> v && is.eof ())) - { - return error (ct, "invalid range value '" + t.literal () + - "' in PostgreSQL type declaration"); - } - - r.range = true; - r.range_value = v; - - t = l.next (); - - if (t.punctuation () == sql_token::p_comma) - { - // We have the second range value. Skip it. - // - l.next (); - t = l.next (); - } - - if (t.punctuation () != sql_token::p_rparen) - { - return error (ct, "expected ')' in PostgreSQL type " - "declaration"); - } - - s = parse_suffix; - continue; - } - - s = parse_suffix; - } - // Fall through. - case parse_suffix: - { - if (r.type == sql_type::TIME || r.type == sql_type::TIMESTAMP) - { - string const& id1 (context::upcase (t.identifier ())); - - if (id1 == "WITH") - { - t = l.next (); - tt = t.type (); - - if (tt == sql_token::t_identifier) - { - string const& id2 (context::upcase (t.identifier ())); - - if (id2 == "TIME") - { - t = l.next (); - tt = t.type (); - - if (tt == sql_token::t_identifier) - { - string const& id3 (context::upcase (t.identifier ())); - - if (id3 == "ZONE") - { - // This code shall not fall through. - // - return error (ct, "PostgreSQL time zones are not " - "currently supported"); - } - } - } - } - } - } - - return error ( - ct, - tt == sql_token::t_identifier - ? "unknown PostgreSQL type '" + t.identifier () + "'" - : "unknown PostgreSQL type"); - } - case parse_done: - { - assert (false); - break; - } - } - } - - if (s == parse_name && !prefix.empty ()) - { - // Some prefixes can also be type names if not followed - // by the actual type name. - // - if (prefix == "BIT") - { - r.type = sql_type::BIT; - } - else if (prefix == "CHARACTER") - { - r.type = sql_type::CHAR; - } - } - - if (flt) - { - r.type = r.range && r.range_value < 25 ? - sql_type::REAL : - sql_type::DOUBLE; - } - - if (r.type == sql_type::invalid) - return error (ct, "incomplete PostgreSQL type declaration"); - - // If range is omitted for CHAR or BIT types, it defaults to 1. - // - if ((r.type == sql_type::CHAR || r.type == sql_type::BIT) && !r.range) - { - r.range = true; - r.range_value = 1; - } - - return r; - } - catch (sql_lexer::invalid_input const& e) - { - return error (ct, "invalid PostgreSQL type declaration: " + e.message); - } - } - } -} diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx deleted file mode 100644 index 64e0b1a..0000000 --- a/odb/relational/pgsql/context.hxx +++ /dev/null @@ -1,192 +0,0 @@ -// file : odb/relational/pgsql/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_PGSQL_CONTEXT_HXX -#define ODB_RELATIONAL_PGSQL_CONTEXT_HXX - -#include - -#include - -namespace relational -{ - namespace pgsql - { - struct sql_type - { - // Keep the order in each block of types. - // - enum core_type - { - // Integral types. - // - BOOLEAN, - SMALLINT, - INTEGER, - BIGINT, - - // Float types. - // - REAL, - DOUBLE, - NUMERIC, - - // Data-time types. - // - DATE, - TIME, - TIMESTAMP, - - // String and binary types. - // - CHAR, - VARCHAR, - TEXT, - BYTEA, - BIT, - VARBIT, - - // Other types. - // - UUID, - - // Invalid type. - // - invalid - }; - - sql_type () : type (invalid), range (false) {} - - core_type type; - - // VARBIT maximum length is 2^31 - 1 bit. String types can hold a - // maximum of 1GB of data. - // - bool range; - unsigned int range_value; - - // Conversion expressions for custom database types. - // - std::string to; - std::string from; - }; - - class context: public virtual relational::context - { - public: - sql_type const& - parse_sql_type (string const&, - semantics::data_member&, - bool custom = true); - public: - struct invalid_sql_type - { - invalid_sql_type (string const& message): message_ (message) {} - - string const& - message () const {return message_;} - - private: - string message_; - }; - - // If custom_db_types is NULL, then this function returns - // invalid type instead of throwing in case an unknown type - // is encountered. - // - static sql_type - parse_sql_type (string, custom_db_types const* = 0); - - public: - // Construct statement name from a given type and name. - // - string - statement_name (string const& type, - string const& name, - semantics::node&); - - protected: - virtual string const& - convert_expr (string const&, semantics::data_member&, bool); - - virtual string - quote_id_impl (qname const&) const; - - virtual bool - grow_impl (semantics::class_&, user_section*); - - virtual bool - grow_impl (semantics::data_member&); - - virtual bool - grow_impl (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const&); - - protected: - virtual string - database_type_impl (semantics::type&, semantics::names*, bool, bool*); - - public: - virtual - ~context (); - - context (); - context (std::ostream&, - semantics::unit&, - options_type const&, - features_type&, - sema_rel::model*); - - static context& - current () - { - return *current_; - } - - private: - static context* current_; - - private: - struct data: base_context::data - { - data (std::ostream& os): base_context::data (os) {} - - struct sql_type_cache_entry - { - sql_type_cache_entry () - : custom_cached (false), straight_cached (false) {} - - sql_type const& - cache_custom (sql_type const& t) - { - custom = t; - custom_cached = true; - return custom; - } - - sql_type const& - cache_straight (sql_type const& t) - { - straight = t; - straight_cached = true; - return straight; - } - - sql_type custom; // With custom mapping. - sql_type straight; // Without custom mapping. - - bool custom_cached; - bool straight_cached; - }; - - typedef std::map sql_type_cache; - sql_type_cache sql_type_cache_; - }; - data* data_; - }; - } -} - -#endif // ODB_RELATIONAL_PGSQL_CONTEXT_HXX diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx deleted file mode 100644 index c3efc3e..0000000 --- a/odb/relational/pgsql/header.cxx +++ /dev/null @@ -1,285 +0,0 @@ -// file : odb/relational/pgsql/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -namespace relational -{ - namespace pgsql - { - namespace header - { - namespace relational = relational::header; - - struct class1: relational::class1 - { - class1 (base const& x): base (x) {} - - virtual void - object_public_extra_post (type& c) - { - bool abst (abstract (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - if (abst && !poly) - return; - - data_member_path* id (id_member (c)); - semantics::data_member* optimistic (context::optimistic (c)); - - column_count_type const& cc (column_count (c)); - - size_t update_columns ( - cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update); - - // Statement names. - // - os << "static const char persist_statement_name[];"; - - if (id != 0) - { - if (poly_derived) - os << "static const char* const find_statement_names[" << - (abst ? "1" : "depth") << "];"; - else - os << "static const char find_statement_name[];"; - - if (poly && !poly_derived) - os << "static const char find_discriminator_statement_name[];"; - - if (update_columns != 0) - os << "static const char update_statement_name[];"; - - os << "static const char erase_statement_name[];"; - - if (optimistic != 0) - os << "static const char optimistic_erase_statement_name[];"; - } - - // Query statement name. - // - if (options.generate_query ()) - os << "static const char query_statement_name[];" - << "static const char erase_query_statement_name[];"; - - os << endl; - - // Statement types. - // - os << "static const unsigned int persist_statement_types[];"; - - if (id != 0) - { - os << "static const unsigned int find_statement_types[];"; - - if (update_columns != 0) - os << "static const unsigned int update_statement_types[];"; - - if (optimistic != 0) - os << "static const unsigned int " << - "optimistic_erase_statement_types[];"; - } - - os << endl; - - if (poly_derived) - return; - - // Bulk operations batch size. - // - { - unsigned long long b (c.count ("bulk") - ? c.get ("bulk") - : 1); - - os << "static const std::size_t batch = " << b << "UL;" - << endl; - } - } - - virtual void - view_public_extra_post (type&) - { - // Statement names. - // - os << "static const char query_statement_name[];" - << endl; - } - }; - entry class1_entry_; - - struct container_traits: relational::container_traits, context - { - container_traits (base const& x): base (x) {} - - virtual void - container_public_extra_pre (semantics::data_member& m, - semantics::type& t) - { - if (!object (c_) || (abstract (c_) && !polymorphic (c_))) - return; - - bool smart (!inverse (m, "value") && !unordered (m) && - container_smart (t)); - - // Container statement names. - // - os << "static const char select_name[];" - << "static const char insert_name[];"; - - if (smart) - os << "static const char update_name[];"; - - os << "static const char delete_name[];" - << endl; - - // Container statement types. - // - os << "static const unsigned int insert_types[];"; - - if (smart) - os << "static const unsigned int update_types[];" - << "static const unsigned int delete_types[];"; - - os << endl; - } - }; - entry container_traits_; - - struct section_traits: relational::section_traits, context - { - section_traits (base const& x): base (x) {} - - virtual void - section_public_extra_post (user_section& s) - { - semantics::class_* poly_root (polymorphic (c_)); - bool poly (poly_root != 0); - - if (!poly && (abstract (c_) || - s.special == user_section::special_version)) - return; - - bool load (s.total != 0 && s.separate_load ()); - bool load_opt (s.optimistic () && s.separate_load ()); - - bool update (s.total != s.inverse + s.readonly); // Always separate. - bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); - - // Statement names. - // - if (load || load_opt) - os << "static const char select_name[];" - << endl; - - if (update || update_opt) - os << "static const char update_name[];" - << endl; - - // Statement types. - // - if (update || update_opt) - os << "static const unsigned int update_types[];"; - } - }; - entry section_traits_; - - struct image_member: relational::image_member_impl, - member_base - { - image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_numeric (member_info& mi) - { - // Exchanged as strings. Can have up to 1000 digits not counting - // '-' and '.'. - // - - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_bit (member_info& mi) - { - // Additional 4 bytes at the beginning of the array specify - // the number of significant bits in the image. This number - // is stored in network byte order. - // - unsigned int n (4 + mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0)); - - os << "unsigned char " << mi.var << "value[" << n << "];" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_varbit (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_uuid (member_info& mi) - { - // UUID is a 16-byte sequence. - // - os << "unsigned char " << mi.var << "value[16];" - << "bool " << mi.var << "null;" - << endl; - } - }; - entry image_member_; - } - } -} diff --git a/odb/relational/pgsql/inline.cxx b/odb/relational/pgsql/inline.cxx deleted file mode 100644 index 08688c3..0000000 --- a/odb/relational/pgsql/inline.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/relational/pgsql/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace pgsql - { - namespace inline_ - { - namespace relational = relational::inline_; - - struct null_member: relational::null_member_impl, - member_base - { - null_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_simple (member_info& mi) - { - if (get_) - os << "r = r && i." << mi.var << "null;"; - else - os << "i." << mi.var << "null = true;"; - } - }; - entry null_member_; - } - } -} diff --git a/odb/relational/pgsql/model.cxx b/odb/relational/pgsql/model.cxx deleted file mode 100644 index 092f8bb..0000000 --- a/odb/relational/pgsql/model.cxx +++ /dev/null @@ -1,101 +0,0 @@ -// file : odb/relational/pgsql/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace pgsql - { - namespace model - { - namespace relational = relational::model; - - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual void - traverse_object (semantics::class_& c) - { - base::traverse_object (c); - - if (context::top_object == &c) - { - // Make sure that the auto id type is INTEGER or BIGINT. - // - if (pkey_ != 0 && pkey_->auto_ ()) - { - // Should be a single column. - // - sema_rel::column& c (pkey_->contains_begin ()->column ()); - - // This should never fail since we have already parsed this. - // - sql_type const& t (parse_sql_type (c.type ())); - - if (t.type != sql_type::INTEGER && t.type != sql_type::BIGINT) - { - location const& l (c.get ("cxx-location")); - error (l) << "automatically assigned object id must map " - << "to PostgreSQL INTEGER or BIGINT" << endl; - throw operation_failed (); - } - } - } - } - - virtual string - default_bool (semantics::data_member&, bool v) - { - return v ? "TRUE" : "FALSE"; - } - - virtual string - default_enum (semantics::data_member& m, tree en, string const&) - { - // Make sure the column is mapped to an integer type. - // - switch (parse_sql_type (column_type (), m, false).type) - { - case sql_type::SMALLINT: - case sql_type::INTEGER: - case sql_type::BIGINT: - break; - default: - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column with default value specified as C++ " - << "enumerator must map to PostgreSQL integer type" << endl; - - throw operation_failed (); - } - } - - using semantics::enumerator; - - enumerator& e (dynamic_cast (*unit.find (en))); - - ostringstream ostr; - - if (e.enum_ ().unsigned_ ()) - ostr << e.value (); - else - ostr << static_cast (e.value ()); - - return ostr.str (); - } - }; - entry object_columns_; - } - } -} diff --git a/odb/relational/pgsql/schema.cxx b/odb/relational/pgsql/schema.cxx deleted file mode 100644 index b9c3f2e..0000000 --- a/odb/relational/pgsql/schema.cxx +++ /dev/null @@ -1,266 +0,0 @@ -// file : odb/relational/pgsql/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace pgsql - { - namespace schema - { - namespace relational = relational::schema; - using relational::table_set; - - // - // Drop. - // - - struct drop_table: relational::drop_table, context - { - drop_table (base const& x): base (x) {} - - virtual void - traverse (sema_rel::table& t, bool migration) - { - // For migration drop foreign keys explicitly in pre-migration. - // - if (migration) - { - base::traverse (t, migration); - return; - } - - // For schema creation we use the CASCADE clause to drop foreign - // keys. - // - if (pass_ != 2) - return; - - pre_statement (); - os << "DROP TABLE " << (migration ? "" : "IF EXISTS ") << - quote_id (t.name ()) << " CASCADE" << endl; - post_statement (); - } - }; - entry drop_table_; - - // - // Create. - // - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - type (sema_rel::column& c, bool auto_) - { - if (auto_) - { - // This should never fail since we have already parsed this. - // - sql_type const& t (parse_sql_type (c.type ())); - - // The model creation code makes sure it is one of these type. - // - if (t.type == sql_type::INTEGER) - os << "SERIAL"; - else if (t.type == sql_type::BIGINT) - os << "BIGSERIAL"; - } - else - base::type (c, auto_); - } - }; - entry create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - virtual void - deferrable (sema_rel::deferrable d) - { - os << endl - << " INITIALLY " << d; - } - }; - entry create_foreign_key_; - - struct create_index: relational::create_index, context - { - create_index (base const& x): base (x) {} - - virtual void - create (sema_rel::index& in) - { - os << "CREATE "; - - if (!in.type ().empty ()) - { - // Handle the CONCURRENTLY keyword. - // - string const& t (in.type ()); - - if (t == "concurrently" || t == "CONCURRENTLY") - { - os << "INDEX " << t; - } - else - { - size_t p (t.rfind (' ')); - string s (t, (p != string::npos ? p + 1 : 0), string::npos); - - if (s == "concurrently" || s == "CONCURRENTLY") - os << string (t, 0, p) << " INDEX " << s; - else - os << t << " INDEX"; - } - } - else - os << "INDEX"; - - os << " " << name (in) << endl - << " ON " << table_name (in); - - if (!in.method ().empty ()) - os << " USING " << in.method (); - - os << " ("; - columns (in); - os << ")" << endl; - - if (!in.options ().empty ()) - os << ' ' << in.options () << endl; - } - }; - entry create_index_; - - // - // Alter. - // - - struct alter_column: relational::alter_column, context - { - alter_column (base const& x): base (x) {} - - virtual void - alter (sema_rel::column& c) - { - os << quote_id (c.name ()) << " " << - (c.null () ? "DROP" : "SET") << " NOT NULL"; - } - }; - entry alter_column_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x): base (x) {} - - // PostgreSQL prior to 9.1 doesn't support IF NOT EXISTS in - // CREATE TABLE. We also cannot use IF-ELSE construct in plain - // SQL. To make it at least work for a single schema, we are - // going to drop the schema version table after the DROP - // statements and then unconditionally create it after CREATE. - // - virtual void - create_table () - { - if (options.pgsql_server_version () >= pgsql_version (9, 1)) - { - pre_statement (); - - os << "CREATE TABLE IF NOT EXISTS " << qt_ << " (" << endl - << " " << qn_ << " TEXT NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " BIGINT NOT NULL," << endl - << " " << qm_ << " BOOLEAN NOT NULL)" << endl; - - post_statement (); - } - } - - virtual void - drop () - { - pre_statement (); - - if (options.pgsql_server_version () >= pgsql_version (9, 1)) - os << "DELETE FROM " << qt_ << endl - << " WHERE " << qn_ << " = " << qs_ << endl; - else - os << "DROP TABLE IF EXISTS " << qt_ << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - if (options.pgsql_server_version () >= pgsql_version (9, 1)) - { - os << "INSERT INTO " << qt_ << " (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " SELECT " << qs_ << ", " << v << ", FALSE" << endl - << " WHERE NOT EXISTS (" << endl - << " SELECT 1 FROM " << qt_ << " WHERE " << qn_ << " = " << - qs_ << ")" << endl; - } - else - { - os << "CREATE TABLE " << qt_ << " (" << endl - << " " << qn_ << " TEXT NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " BIGINT NOT NULL," << endl - << " " << qm_ << " BOOLEAN NOT NULL)" << endl; - - post_statement (); - pre_statement (); - - os << "INSERT INTO " << qt_ << " (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", FALSE)" << endl; - } - - post_statement (); - } - - virtual void - migrate_pre (sema_rel::version v) - { - pre_statement (); - - os << "UPDATE " << qt_ << endl - << " SET " << qv_ << " = " << v << ", " << qm_ << " = TRUE" << endl - << " WHERE " << qn_ << " = " << qs_ << endl; - - post_statement (); - } - - virtual void - migrate_post () - { - pre_statement (); - - os << "UPDATE " << qt_ << endl - << " SET " << qm_ << " = FALSE" << endl - << " WHERE " << qn_ << " = " << qs_ << endl; - - post_statement (); - } - - }; - entry version_table_; - } - } -} diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx deleted file mode 100644 index b881e48..0000000 --- a/odb/relational/pgsql/source.cxx +++ /dev/null @@ -1,1140 +0,0 @@ -// file : odb/relational/pgsql/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace pgsql - { - namespace source - { - namespace relational = relational::source; - - struct query_parameters: relational::query_parameters - { - query_parameters (base const& x): base (x), i_ (0) {} - - virtual string - next (semantics::data_member&, const string&, const string&) - { - ostringstream ss; - ss << "$" << ++i_; - - return ss.str (); - } - - virtual string - auto_id (semantics::data_member&, const string&, const string&) - { - return "DEFAULT"; - } - - private: - size_t i_; - }; - entry query_parameters_; - - namespace - { - const char* integer_buffer_types[] = - { - "pgsql::bind::boolean_", - "pgsql::bind::smallint", - "pgsql::bind::integer", - "pgsql::bind::bigint" - }; - - const char* float_buffer_types[] = - { - "pgsql::bind::real", - "pgsql::bind::double_" - }; - - const char* char_bin_buffer_types[] = - { - "pgsql::bind::text", // CHAR - "pgsql::bind::text", // VARCHAR - "pgsql::bind::text", // TEXT - "pgsql::bind::bytea" // BYTEA - }; - - const char* date_time_buffer_types[] = - { - "pgsql::bind::date", - "pgsql::bind::time", - "pgsql::bind::timestamp" - }; - - const char* oids[] = - { - "pgsql::bool_oid", // BOOLEAN - "pgsql::int2_oid", // SMALLINT - "pgsql::int4_oid", // INTEGER - "pgsql::int8_oid", // BIGINT - "pgsql::float4_oid", // REAL - "pgsql::float8_oid", // DOUBLE - "pgsql::numeric_oid", // NUMERIC - "pgsql::date_oid", // DATE - "pgsql::time_oid", // TIME - "pgsql::timestamp_oid", // TIMESTAMP - "pgsql::text_oid", // CHAR - "pgsql::text_oid", // VARCHAR - "pgsql::text_oid", // TEXT - "pgsql::bytea_oid", // BYTEA - "pgsql::bit_oid", // BIT - "pgsql::varbit_oid", // VARBIT - "pgsql::uuid_oid" // UUID - }; - } - - struct statement_oids: object_columns_base, context - { - statement_oids (statement_kind sk, - bool first = true, - object_section* section = 0) - : object_columns_base (first, column_prefix (), section), sk_ (sk) - { - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section for - // SELECT statements. - // - return section_ == 0 || - *section_ == s || - (sk_ == statement_select && - *section_ == main_section && - !s.separate_load ()); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore certain columns depending on what kind statement we are - // generating. See object_columns in common source generator for - // details. - // - if (!(inverse (m, key_prefix_) && sk_ != statement_select)) - object_columns_base::traverse_pointer (m, c); - } - - virtual bool - traverse_column (semantics::data_member& m, - string const&, - bool first) - { - // Ignore certain columns depending on what kind statement we are - // generating. See object_columns in common source generator for - // details. - // - if (id ()) - { - if (sk_ == statement_update || - (sk_ == statement_insert && auto_ (m))) - return false; - } - - if (sk_ == statement_update && - readonly (member_path_, member_scope_)) - return false; - - if ((sk_ == statement_insert || sk_ == statement_update) && - version (m)) - return false; - - if (!first) - os << ',' << endl; - - os << oids[parse_sql_type (column_type (), m).type]; - - return true; - } - - private: - statement_kind sk_; - }; - - // - // bind - // - - struct bind_member: relational::bind_member_impl, - member_base - { - bind_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_integer (member_info& mi) - { - os << b << ".type = " << - integer_buffer_types[mi.st->type - sql_type::BOOLEAN] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_float (member_info& mi) - { - os << b << ".type = " << - float_buffer_types[mi.st->type - sql_type::REAL] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_numeric (member_info& mi) - { - os << b << ".type = pgsql::bind::numeric;" - << b << ".buffer = " << arg << "." << mi.var << "value.data_ptr ();" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << b << ".type = " << - date_time_buffer_types[mi.st->type - sql_type::DATE] << ";" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << b << ".type = " << - char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" - << b << ".buffer = " << arg << "." << mi.var << "value.data_ptr ();" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_bit (member_info& mi) - { - os << b << ".type = pgsql::bind::bit;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".capacity = sizeof (" << arg << "." << mi.var << "value);" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_varbit (member_info& mi) - { - os << b << ".type = pgsql::bind::varbit;" - << b << ".buffer = " << arg << "." << mi.var << "value.data_ptr ();" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_uuid (member_info& mi) - { - os << b << ".type = pgsql::bind::uuid;" - << b << ".buffer = " << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - }; - entry bind_member_; - - // - // grow - // - - struct grow_member: relational::grow_member_impl, - member_base - { - grow_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_float (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_numeric (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_date_time (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_bit (member_info&) - { - os << e << " = 0;" - << endl; - } - - virtual void - traverse_varbit (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_uuid (member_info&) - { - os << e << " = 0;" - << endl; - } - }; - entry grow_member_; - - // - // init image - // - - struct init_image_member: relational::init_image_member_impl, - member_base - { - init_image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - set_null (member_info& mi) - { - os << "i." << mi.var << "null = true;"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_numeric (member_info& mi) - { - // @@ Optimization: can remove growth check if buffer is fixed. - // - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = size;" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = size;" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_bit (member_info& mi) - { - os << "std::size_t size (0);" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "sizeof (i." << mi.var << "value)," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = size;"; - } - - virtual void - traverse_varbit (member_info& mi) - { - os << "std::size_t size (0);" - << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "i." << mi.var << "size = size;" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_uuid (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");" - << "i." << mi.var << "null = is_null;"; - } - }; - entry init_image_member_; - - // - // init value - // - - struct init_value_member: relational::init_value_member_impl, - member_base - { - init_value_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - get_null (string const& var) const - { - os << "i." << var << "null"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_float (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_numeric (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_date_time (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_bit (member_info& mi) - { - // Presented as byte. - // - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_varbit (member_info& mi) - { - // Presented as bytea. - // - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_uuid (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - }; - entry init_value_member_; - - struct class_: relational::class_, context - { - class_ (base const& x): base (x) {} - - virtual string - persist_statement_extra (type& c, - relational::query_parameters&, - persist_position p) - { - string r; - - if (p == persist_after_values) - { - data_member_path* id (id_member (c)); - - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - // Top-level auto id. - // - if (id != 0 && !poly_derived && auto_ (*id)) - r = "RETURNING " + - convert_from (column_qname (*id), *id->back ()); - } - - return r; - } - - virtual void - object_extra (type& c) - { - bool abst (abstract (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - if (abst && !poly) - return; - - data_member_path* id (id_member (c)); - semantics::data_member* optimistic (context::optimistic (c)); - - column_count_type const& cc (column_count (c)); - - size_t update_columns ( - cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update); - - string const& n (class_fq_name (c)); - string const& fn (flat_name (n)); - string traits ("access::object_traits_impl< " + n + ", id_pgsql >"); - - os << "const char " << traits << "::" << endl - << "persist_statement_name[] = " << - strlit (statement_name ("persist", fn, c)) << ";" - << endl; - - if (id != 0) - { - if (poly_derived) - { - os << "const char* const " << traits << "::" << endl - << "find_statement_names[] =" - << "{"; - - for (size_t i (0), n (abst ? 1 : polymorphic_depth (c)); - i < n; - ++i) - { - if (i != 0) - os << "," << endl; - - ostringstream ostr; - ostr << "find_" << i; - os << strlit (statement_name (ostr.str (), fn, c)); - } - - os << "};"; - } - else - os << "const char " << traits << "::" << endl - << "find_statement_name[] = " << - strlit (statement_name ("find", fn, c)) << ";" - << endl; - - if (poly && !poly_derived) - os << "const char " << traits << "::" << endl - << "find_discriminator_statement_name[] = " << - strlit (statement_name ("find_discriminator", fn, c)) << ";" - << endl; - - if (update_columns != 0) - os << "const char " << traits << "::" << endl - << "update_statement_name[] = " << - strlit (statement_name ("update", fn, c)) << ";" - << endl; - - os << "const char " << traits << "::" << endl - << "erase_statement_name[] = " << - strlit (statement_name ("erase", fn, c)) << ";" - << endl; - - if (optimistic != 0) - os << "const char " << traits << "::" << endl - << "optimistic_erase_statement_name[] = " << - strlit (statement_name ("erase_optimistic", fn, c)) << ";" - << endl; - } - - // Query statement name. - // - if (options.generate_query ()) - { - os << "const char " << traits << "::" << endl - << "query_statement_name[] = " << - strlit (statement_name ("query", fn, c)) << ";" - << endl - << "const char " << traits << "::" << endl - << "erase_query_statement_name[] = " << - strlit (statement_name ("erase_query", fn, c)) << ";" - << endl; - } - - // Statement types. - // - - // persist_statement_types. - // - { - os << "const unsigned int " << traits << "::" << endl - << "persist_statement_types[] =" - << "{"; - - statement_oids st (statement_insert); - st.traverse (c); - - // Empty array is not portable. So add a dummy member if we - // are not sending anything with the insert statement. - // - if (cc.total == cc.inverse + cc.optimistic_managed + - (id != 0 && !poly_derived && auto_ (*id) ? cc.id : 0)) - os << "0"; - - os << "};"; - } - - // find_statement_types. - // - if (id != 0) - { - os << "const unsigned int " << traits << "::" << endl - << "find_statement_types[] =" - << "{"; - - statement_oids st (statement_select, true); - st.traverse (*id); - - os << "};"; - } - - // update_statement_types. - // - if (id != 0 && update_columns != 0) - { - os << "const unsigned int " << traits << "::" << endl - << "update_statement_types[] =" - << "{"; - - { - statement_oids st (statement_update, true, &main_section); - st.traverse (c); - } - - // Not the same as update_columns. - // - bool first (cc.total == cc.id + cc.inverse + cc.readonly + - cc.separate_update + cc.optimistic_managed); - - statement_oids st (statement_where, first); - st.traverse (*id); - - if (optimistic != 0) - st.traverse (*optimistic); - - os << "};"; - } - - if (id != 0 && optimistic != 0) - { - os << "const unsigned int " << traits << "::" << endl - << "optimistic_erase_statement_types[] =" - << "{"; - - statement_oids st (statement_where); - st.traverse (*id); - st.traverse (*optimistic); - - os << "};"; - } - } - - virtual void - extra_statement_cache_extra_args (bool c, bool s) - { - bool u (c || s); - - os << "," << endl - << db << "::native_binding&" << (u ? " idn" : "") << "," << endl - << "const unsigned int*" << (u ? " idt" : ""); - } - - virtual void - view_extra (type& c) - { - string const& n (class_fq_name (c)); - string const& fn (flat_name (n)); - string traits ("access::view_traits_impl< " + n + ", id_pgsql >"); - - os << "const char " << traits << "::" << endl - << "query_statement_name[] = " << - strlit (statement_name ("query", fn, c)) << ";" - << endl; - } - - virtual void - object_query_statement_ctor_args (type&, - string const& q, - bool process, - bool prep) - { - os << "sts.connection ()," << endl; - - if (prep) - os << "n," << endl; - else - os << "query_statement_name," << endl; - - os << "text," << endl - << process << "," << endl // Process. - << "true," << endl // Optimize. - << q << ".parameter_types ()," << endl - << q << ".parameter_count ()," << endl - << q << ".parameters_binding ()," << endl - << "imb"; - } - - virtual void - object_erase_query_statement_ctor_args (type&) - { - os << "conn," << endl - << "erase_query_statement_name," << endl - << "text," << endl - << "q.parameter_types ()," << endl - << "q.parameter_count ()," << endl - << "q.parameters_binding ()"; - } - - virtual void - view_query_statement_ctor_args (type&, - string const& q, - bool process, - bool prep) - { - os << "sts.connection ()," << endl; - - if (prep) - os << "n," << endl; - else - os << "query_statement_name," << endl; - - os << q << ".clause ()," << endl - << process << "," << endl // Process. - << "true," << endl // Optimize. - << q << ".parameter_types ()," << endl - << q << ".parameter_count ()," << endl - << q << ".parameters_binding ()," << endl - << "imb"; - } - - virtual void - post_query_ (type&, bool once_off) - { - if (once_off) - os << "st->deallocate ();"; - } - }; - entry class_entry_; - - struct container_traits : relational::container_traits, context - { - container_traits (base const& x): base (x) {} - - virtual void - container_extra (semantics::data_member& m, semantics::type& t) - { - if (!object (c_) || (abstract (c_) && !polymorphic (c_))) - return; - - container_kind_type ck (container_kind (t)); - - string const& pn (public_name (m)); - string scope (scope_ + "::" + flat_prefix_ + pn + "_traits"); - - data_member_path* imp (inverse (m, "value")); - bool inv (imp != 0); - - bool smart (!inv && !unordered (m) && container_smart (t)); - - // Statment names. - // - - // Prefix top-object name to avoid conflicts with inherited - // member statement names. - // - string fn ( - flat_name ( - class_fq_name (*top_object) + "_" + flat_prefix_ + pn)); - - os << "const char " << scope << "::" << endl - << "select_name[] = " << - strlit (statement_name ("select", fn, m)) << ";" - << endl - << "const char " << scope << "::" << endl - << "insert_name[] = " << - strlit (statement_name ("insert", fn, m)) << ";" - << endl; - - if (smart) - os << "const char " << scope << "::" << endl - << "update_name[] = " << - strlit (statement_name ("update", fn, m)) << ";" - << endl; - - os << "const char " << scope << "::" << endl - << "delete_name[] = " << - strlit (statement_name ("delete", fn, m)) << ";" - << endl; - - // Statement types. - // - - semantics::type& vt (container_vt (m)); - semantics::type& idt (container_idt (m)); - - // insert statement types. - // - { - os << "const unsigned int " << scope << "::" << endl - << "insert_types[] =" - << "{"; - - if (!inv) - { - statement_oids so (statement_insert); - - so.traverse (m, idt, "id", "object_id"); - - switch (ck) - { - case ck_ordered: - { - if (!unordered (m)) - so.traverse (m, container_it (m), "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - so.traverse (m, container_kt (m), "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - so.traverse (m, vt, "value", "value"); - } - else - // MSVC does not allow zero length arrays or uninitialized - // non-extern const values. - // - os << "0"; - - os << "};"; - } - - // update statement types. - // - if (smart) - { - os << "const unsigned int " << scope << "::" << endl - << "update_types[] =" - << "{"; - - { - // Use insert instead of update to include read-only members. - // - statement_oids so (statement_insert); - so.traverse (m, vt, "value", "value"); - } - - statement_oids so (statement_where, false); - so.traverse (m, idt, "id", "object_id"); - - switch (ck) - { - case ck_ordered: - { - if (!unordered (m)) - so.traverse (m, container_it (m), "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - //so.traverse (m, container_kt (t), "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - //so.traverse (m, vt, "value", "value"); - break; - } - } - - os << "};"; - } - - // delete statement types. - // - if (smart) - { - os << "const unsigned int " << scope << "::" << endl - << "delete_types[] =" - << "{"; - - statement_oids so (statement_where); - so.traverse (m, idt, "id", "object_id"); - - switch (ck) - { - case ck_ordered: - { - if (!unordered (m)) - so.traverse (m, container_it (m), "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - //so.traverse (m, container_kt (t), "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - //so.traverse (m, vt, "value", "value"); - break; - } - } - - os << "};"; - } - } - }; - entry container_traits_; - - struct section_traits : relational::section_traits, context - { - section_traits (base const& x): base (x) {} - - virtual void - section_extra (user_section& s) - { - semantics::class_* poly_root (polymorphic (c_)); - bool poly (poly_root != 0); - - if (!poly && (abstract (c_) || - s.special == user_section::special_version)) - return; - - semantics::data_member* opt (optimistic (c_)); - - bool load (s.total != 0 && s.separate_load ()); - bool load_opt (s.optimistic () && s.separate_load ()); - - bool update (s.total != s.inverse + s.readonly); // Always separate. - bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); - - string name (public_name (*s.member)); - string scope (scope_ + "::" + name + "_traits"); - - // Statment names. - // - - // Prefix object name to avoid conflicts with inherited member - // statement names. - // - string fn (flat_name (class_fq_name (c_) + "_" + name)); - - if (load || load_opt) - os << "const char " << scope << "::" << endl - << "select_name[] = " << - strlit (statement_name ("select", fn, *s.member)) << ";" - << endl; - - if (update || update_opt) - os << "const char " << scope << "::" << endl - << "update_name[] = " << - strlit (statement_name ("update", fn, *s.member)) << ";" - << endl; - - // Statement types. - // - if (update || update_opt) - { - os << "const unsigned int " << scope << "::" << endl - << "update_types[] =" - << "{"; - - { - statement_oids st (statement_update, true, &s); - st.traverse (c_); - } - - statement_oids st (statement_where, !update); - st.traverse (*id_member (c_)); - - if (s.optimistic ()) // Note: not update_opt. - st.traverse (*opt); - - os << "};"; - } - } - }; - entry section_traits_; - - struct container_cache_init_members: - relational::container_cache_init_members - { - container_cache_init_members (base const& x): base (x) {} - - virtual void - extra_members () - { - os << ", idn, idt"; - } - }; - entry container_cache_init_members_; - - struct section_cache_init_members: - relational::section_cache_init_members - { - section_cache_init_members (base const& x): base (x) {} - - virtual void - extra_members () - { - os << ", idn, idt"; - } - }; - entry section_cache_init_members_; - } - } -} diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx deleted file mode 100644 index 0f60359..0000000 --- a/odb/relational/processor.cxx +++ /dev/null @@ -1,1564 +0,0 @@ -// file : odb/relational/processor.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace - { - // Indirect (dynamic) context values. - // - static string - id_column_type () - { - context& c (context::current ()); - data_member_path& id (*context::id_member (*c.top_object)); - return id.back ()->get ("column-id-type"); - } - - struct data_member: traversal::data_member, context - { - virtual void - traverse (semantics::data_member& m) - { - if (transient (m)) - return; - - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - semantics::type* wt; - semantics::names* whint (0); - if ((wt = wrapper (t, whint))) - wt = &utype (*wt, whint); - - // Determine the member kind. - // - enum {simple, composite, container, unknown} kind (unknown); - - // See if this is a composite value type. - // - if (composite_wrapper (t)) - kind = composite; - - // If not, see if it is a simple value. - // - if (kind == unknown) - { - string type, id_type; - - if (m.count ("id-type")) - id_type = m.get ("id-type"); - - if (m.count ("type")) - { - type = m.get ("type"); - - if (id_type.empty ()) - id_type = type; - } - - if (semantics::class_* c = object_pointer (t)) - { - // An object pointer in view doesn't really have a "column" - // so pretend that it has already been handled. - // - if (view_member (m)) - kind = simple; - else - { - // This is an object pointer. The column type is the pointed-to - // object id type. - // - semantics::data_member& id (*id_member (*c)->back ()); - - semantics::names* idhint; - semantics::type& idt (utype (id, idhint)); - - // The id type can be a composite value type. - // - if (composite_wrapper (idt)) - kind = composite; - else - { - semantics::type* wt; - semantics::names* whint (0); - if ((wt = wrapper (idt, whint))) - wt = &utype (*wt, whint); - - if (type.empty () && id.count ("id-type")) - type = id.get ("id-type"); - - if (type.empty () && id.count ("type")) - type = id.get ("type"); - - // The rest should be identical to the code for the id_type in - // the else block. - // - if (type.empty () && idt.count ("id-type")) - type = idt.get ("id-type"); - - if (type.empty () && wt != 0 && wt->count ("id-type")) - type = wt->get ("id-type"); - - if (type.empty () && idt.count ("type")) - type = idt.get ("type"); - - if (type.empty () && wt != 0 && wt->count ("type")) - type = wt->get ("type"); - - if (type.empty ()) - type = database_type (idt, idhint, true); - - if (type.empty () && wt != 0) - type = database_type (*wt, whint, true); - - id_type = type; - } - } - } - else - { - if (id_type.empty () && t.count ("id-type")) - id_type = t.get ("id-type"); - - if (id_type.empty () && wt != 0 && wt->count ("id-type")) - id_type = wt->get ("id-type"); - - if (type.empty () && t.count ("type")) - type = t.get ("type"); - - if (type.empty () && wt != 0 && wt->count ("type")) - type = wt->get ("type"); - - if (id_type.empty ()) - id_type = type; - - if (id_type.empty ()) - id_type = database_type (t, hint, true); - - if (id_type.empty () && wt != 0) - id_type = database_type (*wt, whint, true); - - bool null (false); - if (type.empty ()) - type = database_type (t, hint, false, &null); - - if (type.empty () && wt != 0) - type = database_type (*wt, whint, false, &null); - - // Use id mapping for discriminators. - // - if (id (m) || discriminator (m)) - type = id_type; - // Allow NULL if requested by the default mapping. - // - else if (null && !m.count ("not-null")) - m.set ("null", true); - } - - if (kind == unknown && !type.empty ()) - { - m.set ("column-type", type); - m.set ("column-id-type", id_type); - - // Issue a warning if we are relaxing null-ness. - // - if (m.count ("null") && t.count ("not-null")) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " warning: data member declared null while its type is " - << "declared not null" << endl; - } - - kind = simple; - } - } - - // If not a simple value, see if this is a container. - // - if (kind == unknown && context::container (m)) - { - process_container (m, (wt != 0 ? *wt : t)); - kind = container; - } - - // If it is none of the above then we have an error. - // - if (kind == unknown) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: unable to map C++ type '" << t.fq_name (hint) - << "' used in data member '" << m.name () << "' to a " - << db.name () << " database type" << endl; - - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " info: use '#pragma db type' to specify the database type" - << endl; - - throw operation_failed (); - } - - if (m.count ("polymorphic-ref")) - { - // Copy the column name from the root's id member, if specified. - // - { - semantics::class_& r (*object_pointer (t)); - semantics::data_member& id (*id_member (r)->front ()); - - if (id.count ("column")) - m.set ("column", id.get ("column")); - } - - m.set ("not-null", true); - m.set ("deferrable", - sema_rel::deferrable (sema_rel::deferrable::not_deferrable)); - m.set ("on-delete", sema_rel::foreign_key::cascade); - } - - process_index (m); - } - - // Convert index/unique specifiers to the index entry in the object. - // - void - process_index (semantics::data_member& m) - { - bool ip (m.count ("index")); - bool up (m.count ("unique")); - - if (ip || up) - { - using semantics::class_; - class_& c (dynamic_cast (m.scope ())); - - indexes& ins (c.count ("index") - ? c.get ("index") - : c.set ("index", indexes ())); - - index in; - in.loc = m.get ( - ip ? "index-location" : "unique-location"); - - if (up) - in.type = "UNIQUE"; - - index::member im; - im.loc = in.loc; - im.name = m.name (); - im.path.push_back (&m); - in.members.push_back (im); - - // Insert it in the location order. - // - ins.insert ( - lower_bound (ins.begin (), ins.end (), in, index_comparator ()), - in); - } - } - - void - process_container_value (semantics::type& t, - semantics::names* hint, - semantics::data_member& m, - string const& prefix, - bool obj_ptr) - { - if (composite_wrapper (t)) - return; - - semantics::names* wh (0); - semantics::type* wt (wrapper (t, wh)); - - string type; - semantics::type& ct (utype (m)); - - // Custom mapping can come from these places (listed in the order - // of priority): member, container type, value type. To complicate - // things a bit, for object references, it can also come from the - // member and value type of the id member. - // - if (m.count (prefix + "-type")) - type = m.get (prefix + "-type"); - - if (type.empty () && ct.count (prefix + "-type")) - type = ct.get (prefix + "-type"); - - semantics::class_* c; - if (obj_ptr && (c = object_pointer (t))) - { - // This is an object pointer. The column type is the pointed-to - // object id type. - // - semantics::data_member& id (*id_member (*c)->back ()); - - semantics::names* idhint; - semantics::type& idt (utype (id, idhint)); - - // Nothing to do if this is a composite value type. - // - if (composite_wrapper (idt)) - return; - - semantics::type* wt (0); - semantics::names* whint (0); - if ((wt = wrapper (idt, whint))) - wt = &utype (*wt, whint); - - if (type.empty () && id.count ("id-type")) - type = id.get ("id-type"); - - if (type.empty () && id.count ("type")) - type = id.get ("type"); - - // The rest of the code is identical to the else block except here - // we have to check for "id-type" before checking for "type". - // - - if (type.empty () && idt.count ("id-type")) - type = idt.get ("id-type"); - - if (type.empty () && wt != 0 && wt->count ("id-type")) - type = wt->get ("id-type"); - - if (type.empty () && idt.count ("type")) - type = idt.get ("type"); - - if (type.empty () && wt != 0 && wt->count ("type")) - type = wt->get ("type"); - - if (type.empty ()) - type = database_type (idt, idhint, true); - - if (type.empty () && wt != 0) - type = database_type (*wt, whint, true); - } - else - { - if (type.empty () && t.count ("type")) - type = t.get ("type"); - - if (type.empty () && wt != 0 && wt->count ("type")) - type = wt->get ("type"); - - bool null (false); - if (type.empty ()) - type = database_type (t, hint, false, &null); - - if (type.empty () && wt != 0) - type = database_type (*wt, wh, false, &null); - - // Allow NULL if requested by the default mapping. - // - if (null && !m.count (prefix + "-not-null")) - m.set (prefix + "-null", true); - } - - if (!type.empty ()) - { - m.set (prefix + "-column-type", type); - m.set (prefix + "-column-id-type", type); - return; - } - - // We do not support nested containers so skip that test. - // - - // If it is none of the above then we have an error. - // - string fq_type (t.fq_anonymous () ? "" : t.fq_name ()); - - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: unable to map C++ type '" << fq_type << "' used in " - << "data member '" << m.name () << "' to a " << db.name () - << " database type" << endl; - - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " info: use '#pragma db " << prefix << "_type' to specify the " - << "database type" << endl; - - throw operation_failed (); - } - - void - process_container (semantics::data_member& m, semantics::type& t) - { - container_kind_type ck (t.get ("container-kind")); - - semantics::names* vh (0); - semantics::names* ih (0); - semantics::names* kh (0); - - semantics::type* vt (&utype (m, vh, "value")); - semantics::type* it (ck == ck_ordered ? &utype (m, ih, "index") : 0); - semantics::type* kt (ck == ck_map || ck == ck_multimap - ? &utype (m, kh, "key") - : 0); - - // Process member data. - // - m.set ("id-column-type", &id_column_type); - - process_container_value (*vt, vh, m, "value", true); - - if (it != 0) - process_container_value (*it, ih, m, "index", false); - - if (kt != 0) - process_container_value (*kt, kh, m, "key", true); - } - }; - - // - // - struct view_data_member: traversal::data_member, context - { - view_data_member (semantics::class_& c) - : view_ (c), - query_ (c.get ("query")), - amap_ (c.get ("alias-map")), - omap_ (c.get ("object-map")) - { - } - - struct assoc_member - { - semantics::data_member* m; - view_object* vo; - }; - - typedef vector assoc_members; - - virtual void - traverse (semantics::data_member& m) - { - using semantics::data_member; - - if (transient (m)) - return; - - semantics::type& t (utype (m)); - - // Object pointers are associated with objects. - // - if (object_pointer (t)) - return; - - data_member* src_m (0); // Source member. - - // Resolve member references in column expressions. - // - if (m.count ("column")) - { - // Column literal. - // - if (query_.kind != view_query::condition) - { - warn (m.get ("column-location")) - << "db pragma column ignored in a view with " - << (query_.kind == view_query::runtime ? "runtime" : "complete") - << " query" << endl; - } - - return; - } - else if (m.count ("column-expr")) - { - column_expr& e (m.get ("column-expr")); - - if (query_.kind != view_query::condition) - { - warn (e.loc) - << "db pragma column ignored in a view with " - << (query_.kind == view_query::runtime ? "runtime" : "complete") - << " query" << endl; - return; - } - - for (column_expr::iterator i (e.begin ()); i != e.end (); ++i) - { - // This code is quite similar to translate_expression in the - // source generator. - // - try - { - using semantics::scope; - using semantics::class_; - - if (i->kind != column_expr_part::reference) - continue; - - lex_.start (i->value); - - string tl; - tree tn; - cpp_ttype tt (lex_.next (tl, &tn)); - - data_member* m (0); - view_object* vo (0); - - // Check if this is an alias. - // - if (tt == CPP_NAME) - { - view_alias_map::iterator j (amap_.find (tl)); - - if (j != amap_.end ()) - { - vo = j->second; - - // Skip '::'. - // - if (lex_.next (tl, &tn) != CPP_SCOPE) - { - error (i->loc) << "member name expected after an alias " << - "in db pragma column" << endl; - throw operation_failed (); - } - - if (lex_.next (tl, &tn) != CPP_NAME) - throw lookup::invalid_name (); - - m = &vo->obj->lookup ( - tl, scope::include_hidden); - - tt = lex_.next (tl, &tn); - } - } - - // If it is not an alias, do the normal lookup. - // - if (vo == 0) - { - // Also get the object type. We need to do it so that - // we can get the correct (derived) table name (the - // member itself can come from a base class). - // - scope* s; - string name; - cpp_ttype ptt; // Not used. - m = &lookup::resolve_scoped_name ( - lex_, tt, tl, tn, ptt, - dynamic_cast (*unit.find (i->scope)), - name, - false, - &s); - - view_object_map::iterator j ( - omap_.find (dynamic_cast (s))); - - if (j == omap_.end ()) - { - error (i->loc) << "name '" << name << "' in db pragma " << - "column does not refer to a data member of a " << - "persistent class that is used in this view" << endl; - throw operation_failed (); - } - - vo = j->second; - } - - i->member_path.push_back (m); - - // Figure out the table name/alias for this member. - // - if (class_* root = polymorphic (*vo->obj)) - { - // If the object is polymorphic, then figure out which of the - // bases this member comes from and use the corresponding - // table. - // - class_* c (&static_cast (m->scope ())); - - // If this member's class is not polymorphic (root uses reuse - // inheritance), then use the root table. - // - if (!polymorphic (*c)) - c = root; - - // In a polymorphic hierarchy we have several tables and the - // provided alias is used as a prefix together with the table - // name to form the actual alias. - // - qname const& t (table_name (*c)); - - if (vo->alias.empty ()) - i->table = t; - else - i->table = qname (vo->alias + "_" + t.uname ()); - } - else - i->table = vo->alias.empty () - ? table_name (*vo->obj) - : qname (vo->alias); - - // Finally, resolve nested members if any. - // - for (; tt == CPP_DOT; tt = lex_.next (tl, &tn)) - { - lex_.next (tl, &tn); // Get CPP_NAME. - - // Check that the outer member is composite and also - // unwrap it while at it. - // - class_* comp (composite_wrapper (utype (*m))); - if (comp == 0) - { - error (i->loc) << "data member '" << m->name () << "' " << - "specified in db pragma column is not composite" << endl; - throw operation_failed (); - } - - m = &comp->lookup (tl, class_::include_hidden); - i->member_path.push_back (m); - } - - // If the expression is just this reference, then we have - // a source member. - // - if (e.size () == 1) - src_m = m; - } - catch (lookup::invalid_name const&) - { - error (i->loc) << "invalid name in db pragma column" << endl; - throw operation_failed (); - } - catch (semantics::unresolved const& e) - { - if (e.type_mismatch) - error (i->loc) << "name '" << e.name << "' in db pragma " << - "column does not refer to a data member" << endl; - else - error (i->loc) << "unable to resolve data member '" << - e.name << "' specified with db pragma column" << endl; - - throw operation_failed (); - } - catch (semantics::ambiguous const& e) - { - error (i->loc) << "data member name '" << e.first.name () << - "' specified with db pragma column is ambiguous" << endl; - - info (e.first.named ().location ()) << "could resolve to " << - "this data member" << endl; - - info (e.second.named ().location ()) << "or could resolve " << - "to this data member" << endl; - - throw operation_failed (); - } - } - - // Check that the source member is not transient or inverse. Also - // check that the C++ types are the same (sans cvr-qualification - // and wrapping) and issue a warning if they differ. In rare cases - // where this is not a mistake, the user can use a phony expression - // (e.g., "" + person:name) to disable the warning. Note that in - // this case there will be no type pragma copying, which is probably - // ok seeing that the C++ types are different. - // - // - if (src_m != 0) - { - string reason; - - if (transient (*src_m)) - reason = "transient"; - else if (inverse (*src_m)) - reason = "inverse"; - - if (!reason.empty ()) - { - error (e.loc) - << "object data member '" << src_m->name () << "' specified " - << "in db pragma column is " << reason << endl; - throw operation_failed (); - } - - if (!member_resolver::check_types (utype (*src_m), utype (m))) - { - warn (e.loc) - << "object data member '" << src_m->name () << "' specified " - << "in db pragma column has a different type compared to the " - << "view data member" << endl; - - info (src_m->file (), src_m->line (), src_m->column ()) - << "object data member is defined here" << endl; - - info (m.file (), m.line (), m.column ()) - << "view data member is defined here" << endl; - } - } - } - // This member has no column information. If we are generating our - // own query, try to find a member with the same (or similar) name - // in one of the associated objects. - // - else if (query_.kind == view_query::condition) - { - view_objects& objs (view_.get ("objects")); - - assoc_members exact_members, pub_members; - member_resolver resolver (exact_members, pub_members, m); - - for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) - { - if (i->kind == view_object::object) - resolver.traverse (*i); - } - - assoc_members& members ( - !exact_members.empty () ? exact_members : pub_members); - - // Issue diagnostics if we didn't find any or found more - // than one. - // - if (members.empty ()) - { - error (m.file (), m.line (), m.column ()) - << "unable to find a corresponding data member for '" - << m.name () << "' in any of the associated objects" << endl; - - info (m.file (), m.line (), m.column ()) - << "use db pragma column to specify the corresponding data " - << "member or column name" << endl; - - throw operation_failed (); - } - else if (members.size () > 1) - { - error (m.file (), m.line (), m.column ()) - << "corresponding data member for '" << m.name () << "' is " - << "ambiguous" << endl; - - info (m.file (), m.line (), m.column ()) - << "candidates are:" << endl; - - for (assoc_members::const_iterator i (members.begin ()); - i != members.end (); - ++i) - { - info (i->m->file (), i->m->line (), i->m->column ()) - << " '" << i->m->name () << "' in object '" - << i->vo->name () << "'" << endl; - } - - info (m.file (), m.line (), m.column ()) - << "use db pragma column to resolve this ambiguity" << endl; - - throw operation_failed (); - } - - // Synthesize the column expression for this member. - // - assoc_member const& am (members.back ()); - - column_expr& e (m.set ("column-expr", column_expr ())); - e.push_back (column_expr_part ()); - column_expr_part& ep (e.back ()); - - ep.kind = column_expr_part::reference; - - - // If this object is polymorphic, then figure out which of the - // bases this member comes from and use the corresponding table. - // - using semantics::class_; - - if (class_* root = polymorphic (*am.vo->obj)) - { - class_* c (&static_cast (am.m->scope ())); - - // If this member's class is not polymorphic (root uses reuse - // inheritance), then use the root table. - // - if (!polymorphic (*c)) - c = root; - - // In a polymorphic hierarchy we have several tables and the - // provided alias is used as a prefix together with the table - // name to form the actual alias. - // - qname const& t (table_name (*c)); - - if (am.vo->alias.empty ()) - ep.table = t; - else - ep.table = qname (am.vo->alias + "_" + t.uname ()); - } - else - ep.table = am.vo->alias.empty () - ? table_name (*am.vo->obj) - : qname (am.vo->alias); - - ep.member_path.push_back (am.m); - - src_m = am.m; - } - - // If we have the source member and don't have the type pragma of - // our own, but the source member does, then copy the columnt type - // over. In case the source member is a pointer, also check the id - // member. - // - if (src_m != 0 && !m.count ("type")) - { - if (src_m->count ("type")) - m.set ("column-type", src_m->get ("column-type")); - else if (semantics::class_* c = object_pointer (utype (*src_m))) - { - semantics::data_member& id (*id_member (*c)->back ()); - - if (id.count ("type")) - m.set ("column-type", id.get ("column-type")); - } - } - - // Check the return statements above if you add any extra logic - // here. - } - - struct member_resolver: traversal::class_ - { - member_resolver (assoc_members& members, - assoc_members& pub_members, - semantics::data_member& m) - : member_ (members, pub_members, m) - { - *this >> names_ >> member_; - *this >> inherits_ >> *this; - } - - void - traverse (view_object& vo) - { - member_.vo_ = &vo; - - // First look for an exact match. - // - { - member_.exact_ = true; - member_.found_ = false; - traverse (*vo.obj); - } - - // If we didn't find an exact match, then look for a public - // name match. - // - if (!member_.found_) - { - member_.exact_ = false; - traverse (*vo.obj); - } - } - - virtual void - traverse (type& c) - { - if (!object (c)) - return; // Ignore transient bases. - - names (c); - - // If we already found a match in one of the derived classes, - // don't go into bases to get the standard "hiding" behavior. - // - if (!member_.found_) - inherits (c); - } - - public: - static bool - check_types (semantics::type& ot, semantics::type& vt) - { - using semantics::type; - - // Require that the types be the same sans the wrapping and - // cvr-qualification. If the object member type is a pointer, - // use the id type of the pointed-to object. - // - type* t1; - - if (semantics::class_* c = object_pointer (ot)) - t1 = &utype (*id_member (*c)); - else - t1 = &ot; - - type* t2 (&vt); - - if (type* wt1 = context::wrapper (*t1)) - t1 = &utype (*wt1); - - if (type* wt2 = context::wrapper (*t2)) - t2 = &utype (*wt2); - - if (t1 != t2) - return false; - - return true; - } - - private: - struct data_member: traversal::data_member - { - data_member (assoc_members& members, - assoc_members& pub_members, - semantics::data_member& m) - : members_ (members), - pub_members_ (pub_members), - name_ (m.name ()), - pub_name_ (context::current ().public_name (m)), - type_ (utype (m)) - { - } - - virtual void - traverse (type& m) - { - if (exact_) - { - if (name_ == m.name () && check (m)) - { - assoc_member am; - am.m = &m; - am.vo = vo_; - members_.push_back (am); - found_ = true; - } - } - else - { - if (pub_name_ == context::current ().public_name (m) && - check (m)) - { - assoc_member am; - am.m = &m; - am.vo = vo_; - pub_members_.push_back (am); - found_ = true; - } - } - } - - bool - check (semantics::data_member& m) - { - // Make sure that the found node can possibly match. - // - if (context::transient (m) || - context::inverse (m) || - m.count ("polymorphic-ref")) - return false; - - return check_types (utype (m), type_); - } - - assoc_members& members_; - assoc_members& pub_members_; - - string name_; - string pub_name_; - semantics::type& type_; - - view_object* vo_; - bool exact_; - bool found_; - }; - - traversal::names names_; - data_member member_; - traversal::inherits inherits_; - }; - - private: - semantics::class_& view_; - view_query& query_; - view_alias_map& amap_; - view_object_map& omap_; - cxx_string_lexer lex_; - }; - - struct class_: traversal::class_, context - { - class_ () - : typedefs_ (true) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - - member_names_ >> member_; - } - - virtual void - traverse (type& c) - { - class_kind_type k (class_kind (c)); - - if (k == class_other) - return; - - names (c); // Process nested classes. - names (c, member_names_); - - if (k == class_object) - traverse_object (c); - else if (k == class_view) - traverse_view (c); - } - - // - // Object. - // - - virtual void - traverse_object (type& c) - { - // Remove the bulk pragma if this database doesn't support bulk - // operations. - // - if (c.count ("bulk") && !generate_bulk) - c.remove ("bulk"); - - // Process indexes. Here we need to do two things: resolve member - // names to member paths and assign names to unnamed indexes. We - // are also going to handle the special container indexes. - // - indexes& ins (c.count ("index") - ? c.get ("index") - : c.set ("index", indexes ())); - - for (indexes::iterator i (ins.begin ()); i != ins.end ();) - { - index& in (*i); - - // This should never happen since a db index pragma without - // the member specifier will be treated as a member pragma. - // - assert (!in.members.empty ()); - - // First resolve member names. - // - index::members_type::iterator j (in.members.begin ()); - for (; j != in.members.end (); ++j) - { - index::member& im (*j); - - if (!im.path.empty ()) - continue; // Already resolved. - - im.path = resolve_data_members (c, im.name, im.loc, lex_); - - if (container (*im.path.back ())) - break; - } - - // Add the table prefix if this database has global index names. - // - if (!in.name.empty () && global_index) - in.name = table_name_prefix (class_scope (c)) + in.name; - - // Handle container indexes. - // - if (j != in.members.end ()) - { - // Do some sanity checks. - // - if (in.members.size () != 1) - { - error (in.loc) << "multiple data members specified for a " - << "container index" << endl; - throw operation_failed (); - } - - string tl; - if (lex_.next (tl) != CPP_DOT || lex_.next (tl) != CPP_NAME || - (tl != "id" && tl != "index")) - { - error (j->loc) << ".id or .index special member expected in a " - << "container index" << endl; - throw operation_failed (); - } - - string n (tl); - - if (lex_.next (tl) != CPP_EOF) - { - error (j->loc) << "unexpected text after ." << n << " in " - << "db pragma member" << endl; - throw operation_failed (); - } - - // Move this index to the container member. - // - j->path.back ()->set (n + "-index", *i); - i = ins.erase (i); - continue; - } - - // Now assign the name if the index is unnamed. We have to - // add table name as a prefix here since there is not way - // to distinguish between user-assigned and auto-derived - // names in the model. - // - if (in.name.empty ()) - { - // Make sure there is only one member. - // - if (in.members.size () > 1) - { - error (in.loc) << "unnamed index with more than one data " - << "member" << endl; - throw operation_failed (); - } - - // Generally, we want the index name to be based on the column - // name. This is straightforward for single-column members. In - // case of a composite member, we will need to use the column - // prefix which is based on the data member name, unless - // overridden by the user. In the latter case the prefix can - // be empty, in which case we will just fall back on the - // member's public name. - // - string n (column_prefix (in.members.front ().path, true).prefix); - - if (n.empty ()) - n = public_name_db (*in.members.front ().path.back ()); - else if (n[n.size () - 1] == '_') - n.resize (n.size () - 1); // Remove trailing underscore. - - in.name = index_name (table_name (c), n); - } - - ++i; - } - } - - // - // View. - // - - struct relationship - { - semantics::data_member* member; - string name; - view_object* pointer; - view_object* pointee; - }; - - typedef vector relationships; - - virtual void - traverse_view (type& c) - { - bool has_q (c.count ("query")); - bool has_o (c.count ("objects")); - - // Determine the kind of query template we've got. - // - view_query& vq (has_q - ? c.get ("query") - : c.set ("query", view_query ())); - if (has_q) - { - if (!vq.literal.empty ()) - { - string q (upcase (vq.literal)); - - //@@ We need to recognize database-specific list of prefixes. For - // example, PG has WITH. Alternatively (or in addition) we could - // do the same comment trick (e.g., /*SELECT*/ to treat it as a - // SELECT-like queiry). - // - if (q.compare (0, 7, "SELECT ") == 0) - vq.kind = view_query::complete_select; - else if (q.compare (0, 5, "EXEC ") == 0 || - q.compare (0, 5, "CALL ") == 0 || - q.compare (0, 8, "EXECUTE ") == 0) - vq.kind = view_query::complete_execute; - // - // Hint for databases that use SELECT for stored procedure - // calls (e.g., PostgreSQL). - // - else if (q.compare (0, 8, "/*CALL*/") == 0) - { - vq.literal = string (vq.literal, q[8] == ' ' ? 9 : 8); - vq.kind = view_query::complete_execute; - } - else - vq.kind = view_query::condition; - } - else if (!vq.expr.empty ()) - { - // If the first token in the expression is a string and - // it starts with "SELECT " or is equal to "SELECT" or - // one of the stored procedure call keywords, then we - // have a complete query. - // - if (vq.expr.front ().type == CPP_STRING) - { - string q (upcase (vq.expr.front ().literal)); - - if (q.compare (0, 7, "SELECT ") == 0 || q == "SELECT") - vq.kind = view_query::complete_select; - else if (q.compare (0, 5, "EXEC ") == 0 || q == "EXEC" || - q.compare (0, 5, "CALL ") == 0 || q == "CALL" || - q.compare (0, 8, "EXECUTE ") == 0 || q == "EXECUTE") - vq.kind = view_query::complete_execute; - else if (q.compare (0, 8, "/*CALL*/") == 0) - { - vq.expr.front ().literal = - string (vq.expr.front ().literal, q[8] == ' ' ? 9 : 8); - vq.kind = view_query::complete_execute; - } - else - vq.kind = view_query::condition; - } - else - vq.kind = view_query::condition; - } - else - vq.kind = (vq.distinct || vq.for_update) - ? view_query::condition // The query(distinct) case. - : view_query::runtime; - } - else - vq.kind = has_o ? view_query::condition : view_query::runtime; - - if ((vq.distinct || vq.for_update) && vq.kind != view_query::condition) - { - error (vq.loc) - << "result modifier specified for " - << (vq.kind == view_query::runtime ? "runtime" : "native") - << " query" << endl; - - throw operation_failed (); - } - - // We cannot have an incomplete query if there are not objects - // to derive the rest from. - // - if (vq.kind == view_query::condition && !has_o) - { - error (c.file (), c.line (), c.column ()) - << "view '" << class_fq_name (c) << "' has an incomplete query " - << "template and no associated objects" << endl; - - info (c.file (), c.line (), c.column ()) - << "use db pragma query to provide a complete query template" - << endl; - - info (c.file (), c.line (), c.column ()) - << "or use db pragma object to associate one or more objects " - << "with the view" - << endl; - - throw operation_failed (); - } - - // Process join conditions. - // - if (has_o) - { - view_objects& objs (c.get ("objects")); - - for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) - { - if (i == objs.begin () && i->join != view_object::left) - { - error (i->loc) - << "no join type can be specified for the first associated " - << (i->kind == view_object::object ? "object" : "table") - << endl; - throw operation_failed (); - } - - if (i->kind != view_object::object) - { - // Make sure we have join conditions for tables unless it - // is the first entry. - // - if (i != objs.begin () && i->cond.empty ()) - { - error (i->loc) - << "missing join condition in db pragma table" << endl; - - throw operation_failed (); - } - - continue; - } - - // If we have to generate the query and there was no JOIN - // condition specified by the user, try to come up with one - // automatically based on object relationships. CROSS JOIN - // has no condition. - // - if (vq.kind == view_query::condition && - i->cond.empty () && - i != objs.begin () && - i->join != view_object::cross) - { - relationships rs; - - // Check objects specified prior to this one for any - // relationships. We don't examine objects that were - // specified after this one because that would require - // rearranging the JOIN order. - // - for (view_objects::iterator j (objs.begin ()); j != i; ++j) - { - if (j->kind != view_object::object) - continue; // Skip tables. - - // First see if any of the objects that were specified - // prior to this object point to it. - // - { - relationship_resolver r (rs, *i, true); - r.traverse (*j); - } - - // Now see if this object points to any of the objects - // specified prior to it. - // - { - relationship_resolver r (rs, *j, false); - r.traverse (*i); - } - } - - // Issue diagnostics if we didn't find any or found more - // than one. - // - if (rs.empty ()) - { - error (i->loc) - << "unable to find an object relationship involving " - << "object '" << i->name () << "' and any of the previously " - << "associated objects" << endl; - - info (i->loc) - << "use the join condition clause in db pragma object " - << "to specify a custom join condition" << endl; - - throw operation_failed (); - } - else if (rs.size () > 1) - { - error (i->loc) - << "object relationship for object '" << i->name () << "' " - << "is ambiguous" << endl; - - info (i->loc) - << "candidates are:" << endl; - - for (relationships::const_iterator j (rs.begin ()); - j != rs.end (); - ++j) - { - semantics::data_member& m (*j->member); - - info (m.file (), m.line (), m.column ()) - << " '" << j->name << "' " - << "in object '" << j->pointer->name () << "' " - << "pointing to '" << j->pointee->name () << "'" - << endl; - } - - info (i->loc) - << "use the join condition clause in db pragma object " - << "to resolve this ambiguity" << endl; - - throw operation_failed (); - } - - // Synthesize the condition. - // - relationship const& r (rs.back ()); - - string name (r.pointer->alias.empty () - ? class_fq_name (*r.pointer->obj) - : r.pointer->alias); - name += "::"; - name += r.name; - - lex_.start (name); - - string t; - for (cpp_ttype tt (lex_.next (t)); - tt != CPP_EOF; - tt = lex_.next (t)) - { - i->cond.push_back (cxx_token (lex_.location (), tt, t)); - } - } - } - } - - // Handle forced versioning. When versioning is forced, ignore - // it for native views. - // - if (force_versioned && vq.kind == view_query::condition) - c.set ("versioned", true); - - // Handle data members. - // - { - view_data_member t (c); - traversal::names n (t); - names (c, n); - } - } - - struct relationship_resolver: object_members_base - { - relationship_resolver (relationships& rs, - view_object& pointee, - bool forward) - // Look in polymorphic bases only for previously-associated - // objects since backward pointers from bases will result in - // the pathological case (we will have to join the base table - // first, which means we will get both bases and derived objects - // instead of just derived). - // - : object_members_base (false, false, true, forward), - relationships_ (rs), - // Ignore self-references if we are looking for backward - // pointers since they were already added to the list in - // the previous pass. - // - self_pointer_ (forward), - pointer_ (0), - pointee_ (pointee) - { - } - - void - traverse (view_object& pointer) - { - pointer_ = &pointer; - object_members_base::traverse (*pointer.obj); - } - - using object_members_base::traverse; // Unhide. - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - // Ignore inverse sides of the same relationship to avoid - // phony conflicts caused by the direct side that will end - // up in the relationship list as well. Unless the inverse - // member is in the polymorphic base in which case we will - // miss it since we don't examine inside poly bases on the - // backwards scan (see above). - // - if (data_member_path* imp = inverse (m)) - { - if (&imp->front ()->scope () == &c) // Direct member. - return; - } - - // Ignore self-pointers if requested. - // - if (!self_pointer_ && pointer_->obj == &c) - return; - - if (pointee_.obj == &c) - { - relationships_.push_back (relationship ()); - relationships_.back ().member = &m; - relationships_.back ().name = member_prefix_ + m.name (); - relationships_.back ().pointer = pointer_; - relationships_.back ().pointee = &pointee_; - } - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - if (semantics::class_* c = - object_pointer (context::container_vt (m))) - { - if (inverse (m, "value")) - return; - - // Ignore self-pointers if requested. - // - if (!self_pointer_ && pointer_->obj == c) - return; - - if (pointee_.obj == c) - { - relationships_.push_back (relationship ()); - relationships_.back ().member = &m; - relationships_.back ().name = member_prefix_ + m.name (); - relationships_.back ().pointer = pointer_; - relationships_.back ().pointee = &pointee_; - } - } - } - - private: - relationships& relationships_; - bool self_pointer_; - view_object* pointer_; - view_object& pointee_; - }; - - private: - cxx_string_lexer lex_; - - traversal::defines defines_; - typedefs typedefs_; - - data_member member_; - traversal::names member_names_; - }; - } - - void - process () - { - context ctx; - - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (true); - traversal::namespace_ ns; - class_ c; - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (true); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - unit.dispatch (ctx.unit); - } -} diff --git a/odb/relational/processor.hxx b/odb/relational/processor.hxx deleted file mode 100644 index 71b8643..0000000 --- a/odb/relational/processor.hxx +++ /dev/null @@ -1,15 +0,0 @@ -// file : odb/relational/processor.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_PROCESSOR_HXX -#define ODB_RELATIONAL_PROCESSOR_HXX - -namespace relational -{ - // Issues diagnostics and throws operation_failed in case of an error. - // - void - process (); -} - -#endif // ODB_RELATIONAL_PROCESSOR_HXX diff --git a/odb/relational/schema-source.cxx b/odb/relational/schema-source.cxx deleted file mode 100644 index 5659485..0000000 --- a/odb/relational/schema-source.cxx +++ /dev/null @@ -1,281 +0,0 @@ -// file : odb/relational/schema-source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -using namespace std; - -namespace relational -{ - namespace schema - { - void - generate_source (sema_rel::changelog* log) - { - context ctx; - ostream& os (ctx.os); - database db (ctx.db); - options const& ops (ctx.options); - sema_rel::model& model (*ctx.model); - string const& schema_name (ops.schema_name ()[db]); - - if (log != 0 && ops.suppress_migration ()) - log = 0; - - bool schema_version ( - model.version () != 0 && !ctx.options.suppress_schema_version ()); - - instance emitter; - emitter_ostream emitter_os (*emitter); - schema_format format (schema_format::embedded); - - if (!model.names_empty () || log != 0 || schema_version) - os << "namespace odb" - << "{"; - - // Schema. - // - if (!model.names_empty () || schema_version) - { - os << "static bool" << endl - << "create_schema (database& db, unsigned short pass, bool drop)" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << "ODB_POTENTIALLY_UNUSED (pass);" - << "ODB_POTENTIALLY_UNUSED (drop);" - << endl; - - // Drop. - // - if (!ops.omit_drop ()) - { - bool close (false); - - os << "if (drop)" - << "{"; - - instance dmodel (*emitter, emitter_os, format); - instance dtable (*emitter, emitter_os, format); - trav_rel::qnames names; - dmodel >> names >> dtable; - - for (unsigned short pass (1); pass < 3; ++pass) - { - emitter->pass (pass); - dmodel->pass (pass); - dtable->pass (pass); - - dmodel->traverse (model); - - close = close || !emitter->empty (); - } - - if (schema_version) - { - instance vt (*emitter, emitter_os, format); - vt->create_table (); - vt->drop (); - close = true; - } - - if (close) // Close the last case and the switch block. - os << "return false;" - << "}" // case - << "}"; // switch - - os << "}"; - } - - // Create. - // - if (!ops.omit_create ()) - { - bool close (false); - - if (ops.omit_drop ()) - os << "if (!drop)"; - else - os << "else"; - - os << "{"; - - instance cmodel (*emitter, emitter_os, format); - instance ctable (*emitter, emitter_os, format); - trav_rel::qnames names; - cmodel >> names >> ctable; - - for (unsigned short pass (1); pass < 3; ++pass) - { - emitter->pass (pass); - cmodel->pass (pass); - ctable->pass (pass); - - cmodel->traverse (model); - - close = close || !emitter->empty (); - } - - if (schema_version) - { - instance vt (*emitter, emitter_os, format); - vt->create_table (); - vt->create (model.version ()); - close = true; - } - - if (close) // Close the last case and the switch block. - os << "return false;" - << "}" // case - << "}"; // switch - - os << "}"; - } - - os << "return false;" - << "}"; - - os << "static const schema_catalog_create_entry" << endl - << "create_schema_entry_ (" << endl - << "id_" << db << "," << endl - << context::strlit (schema_name) << "," << endl - << "&create_schema);" - << endl; - } - - // Migration. - // - if (log != 0) - { - // Create NULL migration entry for the base version so that we - // get the complete version range (base, current) at runtime. - // Code in schema_catalog relies on this. - // - os << "static const schema_catalog_migrate_entry" << endl - << "migrate_schema_entry_" << log->model ().version () << - "_ (" << endl - << "id_" << db << "," << endl - << context::strlit (schema_name) << "," << endl - << log->model ().version () << "ULL," << endl - << "0);" - << endl; - - for (sema_rel::changelog::contains_changeset_iterator i ( - log->contains_changeset_begin ()); - i != log->contains_changeset_end (); ++i) - { - sema_rel::changeset& cs (i->changeset ()); - - os << "static bool" << endl - << "migrate_schema_" << cs.version () << " (database& db, " << - "unsigned short pass, bool pre)" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << "ODB_POTENTIALLY_UNUSED (pass);" - << "ODB_POTENTIALLY_UNUSED (pre);" - << endl; - - // Pre. - // - { - bool close (false); - - os << "if (pre)" - << "{"; - - instance changeset (*emitter, emitter_os, format); - instance ctable (*emitter, emitter_os, format); - instance atable (*emitter, emitter_os, format); - trav_rel::qnames names; - changeset >> names; - names >> ctable; - names >> atable; - - for (unsigned short pass (1); pass < 3; ++pass) - { - emitter->pass (pass); - changeset->pass (pass); - ctable->pass (pass); - atable->pass (pass); - - changeset->traverse (cs); - - close = close || !emitter->empty (); - } - - if (!ctx.options.suppress_schema_version ()) - { - instance vt (*emitter, emitter_os, format); - vt->migrate_pre (cs.version ()); - close = true; - } - - if (close) // Close the last case and the switch block. - os << "return false;" - << "}" // case - << "}"; // switch - - os << "}"; - } - - // Post. - // - { - bool close (false); - - os << "else" - << "{"; - - instance changeset (*emitter, emitter_os, format); - instance dtable (*emitter, emitter_os, format); - instance atable (*emitter, emitter_os, format); - trav_rel::qnames names; - changeset >> names; - names >> dtable; - names >> atable; - - for (unsigned short pass (1); pass < 3; ++pass) - { - emitter->pass (pass); - changeset->pass (pass); - dtable->pass (pass); - atable->pass (pass); - - changeset->traverse (cs); - - close = close || !emitter->empty (); - } - - if (!ctx.options.suppress_schema_version ()) - { - instance vt (*emitter, emitter_os, format); - vt->migrate_post (); - close = true; - } - - if (close) // Close the last case and the switch block. - os << "return false;" - << "}" // case - << "}"; // switch - - os << "}"; - } - - os << "return false;" - << "}"; - - os << "static const schema_catalog_migrate_entry" << endl - << "migrate_schema_entry_" << cs.version () << "_ (" << endl - << "id_" << db << "," << endl - << context::strlit (schema_name) << "," << endl - << cs.version () << "ULL," << endl - << "&migrate_schema_" << cs.version () << ");" - << endl; - } - } - - if (!model.names_empty () || log != 0 || schema_version) - os << "}"; // namespace odb - } - } -} diff --git a/odb/relational/schema-source.hxx b/odb/relational/schema-source.hxx deleted file mode 100644 index d2235f5..0000000 --- a/odb/relational/schema-source.hxx +++ /dev/null @@ -1,126 +0,0 @@ -// file : odb/relational/schema-source.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SCHEMA_SOURCE_HXX -#define ODB_RELATIONAL_SCHEMA_SOURCE_HXX - -#include - -#include -#include -#include - -namespace relational -{ - namespace schema - { - struct cxx_emitter: emitter, virtual context - { - typedef cxx_emitter base; - - void - pass (unsigned short p) - { - empty_ = true; - pass_ = p; - new_pass_ = true; - - if (pass_ == 1) - empty_passes_ = 0; // New set of passes. - - // Assume this pass is empty. - // - empty_passes_++; - } - - // Did this pass produce anything? - // - bool - empty () const - { - return empty_; - } - - virtual void - pre () - { - first_ = true; - } - - virtual void - line (const string& l) - { - if (l.empty ()) - return; // Ignore empty lines. - - if (first_) - { - first_ = false; - - // If this line starts a new pass, then output the switch/case - // blocks. - // - if (new_pass_) - { - new_pass_ = false; - empty_ = false; - empty_passes_--; // This pass is not empty. - - // Output case statements for empty preceeding passes, if any. - // - if (empty_passes_ != 0) - { - unsigned short s (pass_ - empty_passes_); - - if (s == 1) - os << "switch (pass)" - << "{"; - else - os << "return true;" // One more pass. - << "}"; - - for (; s != pass_; ++s) - os << "case " << s << ":" << endl; - - os << "{"; - empty_passes_ = 0; - } - - if (pass_ == 1) - os << "switch (pass)" - << "{"; - else - os << "return true;" // One more pass. - << "}"; - - os << "case " << pass_ << ":" << endl - << "{"; - } - - os << "db.execute ("; - } - else - os << strlit (line_ + '\n') << endl; - - line_ = l; - } - - virtual void - post () - { - if (!first_) // Ignore empty statements. - os << strlit (line_) << ");"; - } - - private: - std::string line_; - bool first_; - bool empty_; - bool new_pass_; - unsigned short pass_; - unsigned short empty_passes_; // Number of preceding empty passes. - }; - } -} - -#endif // ODB_RELATIONAL_SCHEMA_SOURCE_HXX diff --git a/odb/relational/schema.cxx b/odb/relational/schema.cxx deleted file mode 100644 index dd70bfa..0000000 --- a/odb/relational/schema.cxx +++ /dev/null @@ -1,174 +0,0 @@ -// file : odb/relational/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace schema - { - void - generate_prologue () - { - instance file; - file->prologue (); - } - - void - generate_epilogue () - { - instance file; - file->epilogue (); - } - - void - generate_drop () - { - context ctx; - instance em; - emitter_ostream emos (*em); - - schema_format f (schema_format::sql); - - instance model (*em, emos, f); - instance table (*em, emos, f); - trav_rel::qnames names; - - model >> names >> table; - - // Pass 1 and 2. - // - for (unsigned short pass (1); pass < 3; ++pass) - { - model->pass (pass); - table->pass (pass); - - model->traverse (*ctx.model); - } - - if (ctx.model->version () != 0 && - !ctx.options.suppress_schema_version ()) - { - instance vt (*em, emos, f); - vt->create_table (); - vt->drop (); - } - } - - void - generate_create () - { - context ctx; - instance em; - emitter_ostream emos (*em); - - schema_format f (schema_format::sql); - - instance model (*em, emos, f); - instance table (*em, emos, f); - trav_rel::qnames names; - - model >> names >> table; - - // Pass 1 and 2. - // - for (unsigned short pass (1); pass < 3; ++pass) - { - model->pass (pass); - table->pass (pass); - - model->traverse (*ctx.model); - } - - if (ctx.model->version () != 0 && - !ctx.options.suppress_schema_version ()) - { - instance vt (*em, emos, f); - - if (ctx.options.omit_drop ()) - vt->create_table (); - - vt->create (ctx.model->version ()); - } - } - - void - generate_migrate_pre (sema_rel::changeset& cs) - { - context ctx; - instance em; - emitter_ostream emos (*em); - - schema_format f (schema_format::sql); - - instance changeset (*em, emos, f); - instance ctable (*em, emos, f); - instance atable (*em, emos, f); - trav_rel::qnames names; - - changeset >> names; - names >> ctable; - names >> atable; - - // Pass 1 and 2. - // - for (unsigned short pass (1); pass < 3; ++pass) - { - changeset->pass (pass); - ctable->pass (pass); - atable->pass (pass); - - changeset->traverse (cs); - } - - if (!ctx.options.suppress_schema_version ()) - { - instance vt (*em, emos, f); - vt->migrate_pre (cs.version ()); - } - } - - void - generate_migrate_post (sema_rel::changeset& cs) - { - context ctx; - instance em; - emitter_ostream emos (*em); - - schema_format f (schema_format::sql); - - instance changeset (*em, emos, f); - instance dtable (*em, emos, f); - instance atable (*em, emos, f); - trav_rel::qnames names; - - changeset >> names; - names >> dtable; - names >> atable; - - // Pass 1 and 2. - // - for (unsigned short pass (1); pass < 3; ++pass) - { - changeset->pass (pass); - dtable->pass (pass); - atable->pass (pass); - - changeset->traverse (cs); - } - - if (!ctx.options.suppress_schema_version ()) - { - instance vt (*em, emos, f); - vt->migrate_post (); - } - } - } -} diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx deleted file mode 100644 index cd975b7..0000000 --- a/odb/relational/schema.hxx +++ /dev/null @@ -1,1606 +0,0 @@ -// file : odb/relational/schema.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SCHEMA_HXX -#define ODB_RELATIONAL_SCHEMA_HXX - -#include -#include -#include - -#include -#include -#include - -namespace relational -{ - namespace schema - { - typedef std::set table_set; - - struct common: virtual context - { - typedef ::emitter emitter_type; - - common (emitter_type& e, ostream& os, schema_format f) - : e_ (e), os_ (os), format_ (f) {} - - void - pre_statement () - { - e_.pre (); - diverge (os_); - } - - void - post_statement () - { - restore (); - e_.post (); - } - - emitter_type& - emitter () const - { - return e_; - } - - ostream& - stream () const - { - return os_; - } - - public: - // Find an entity corresponding to the drop node in alter_table. - // - template - T& - find (D& d) - { - using sema_rel::model; - using sema_rel::changeset; - using sema_rel::table; - using sema_rel::alter_table; - - alter_table& at (dynamic_cast (d.scope ())); - changeset& cs (dynamic_cast (at.scope ())); - model& bm (cs.base_model ()); - table* bt (bm.find
(at.name ())); - assert (bt != 0); - T* b (bt->find (d.name ())); - assert (b != 0); - return *b; - } - - protected: - emitter_type& e_; - ostream& os_; - schema_format format_; - }; - - // - // Drop. - // - - // Only used in migration. - // - struct drop_column: trav_rel::drop_column, common - { - typedef drop_column base; - - drop_column (common const& c, bool* first = 0) - : common (c), - first_ (first != 0 ? *first : first_data_), - first_data_ (true) - { - } - - drop_column (drop_column const& c) - : root_context (), // @@ -Wextra - context (), - common (c), - first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), - first_data_ (c.first_data_) - { - } - - virtual void - drop_header () - { - // By default ADD COLUMN though some databases use just ADD. - // - os << "DROP COLUMN "; - } - - virtual void - traverse (sema_rel::drop_column& dc) - { - if (first_) - first_ = false; - else - os << ","; - - os << endl - << " "; - drop_header (); - os << quote_id (dc.name ()); - } - - protected: - bool& first_; - bool first_data_; - }; - - // Normally only used in migration but some databases use it as a - // base to also drop foreign keys in schema. - // - struct drop_foreign_key: trav_rel::foreign_key, - trav_rel::drop_foreign_key, - trav_rel::add_foreign_key, // Override. - common - { - typedef drop_foreign_key base; - - // Schema constructor. - // - drop_foreign_key (common const& c, table_set& dropped, bool* first = 0) - : common (c), - dropped_ (&dropped), - first_ (first != 0 ? *first : first_data_), - first_data_ (true) - { - } - - // Migration constructor. - // - drop_foreign_key (common const& c, bool* first = 0) - : common (c), - dropped_ (0), - first_ (first != 0 ? *first : first_data_), - first_data_ (true) - { - } - - drop_foreign_key (drop_foreign_key const& c) - : root_context (), // @@ -Wextra - context (), - common (c), - dropped_ (c.dropped_), - first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), - first_data_ (c.first_data_) - { - } - - virtual void - drop_header () - { - os << "DROP CONSTRAINT "; - } - - virtual void - traverse (sema_rel::foreign_key& fk) - { - // If the table which we reference is droped before us, then - // we need to drop the constraint first. Similarly, if the - // referenced table is not part if this model, then assume - // it is dropped before us. In migration we always do this - // first. - // - sema_rel::table& t (dynamic_cast (fk.scope ())); - - if (dropped_ != 0) - { - sema_rel::qname const& rt (fk.referenced_table ()); - sema_rel::model& m (dynamic_cast (t.scope ())); - - if (dropped_->find (rt) == dropped_->end () && - m.find (rt) != m.names_end ()) - return; - } - - drop (t, fk); - } - - virtual void - drop (sema_rel::table& t, sema_rel::foreign_key& fk) - { - // When generating schema we would need to check if the key exists. - // So this implementation will need to be customize on the per- - // database level. - // - pre_statement (); - - os << "ALTER TABLE " << quote_id (t.name ()) << endl - << " "; - drop_header (); - os << quote_id (fk.name ()) << endl; - - post_statement (); - } - - virtual void - traverse (sema_rel::drop_foreign_key& dfk) - { - if (first_) - first_ = false; - else - os << ","; - - os << endl; - drop (dfk); - } - - virtual void - drop (sema_rel::drop_foreign_key& dfk) - { - os << " "; - drop_header (); - os << quote_id (dfk.name ()); - } - - protected: - table_set* dropped_; - bool& first_; - bool first_data_; - }; - - // Currently only used in migration. - // - struct drop_index: trav_rel::drop_index, common - { - typedef drop_index base; - - enum index_type {unique, non_unique, all}; - - drop_index (common const& c, index_type t = all) - : common (c), type_ (t) {} - - virtual void - traverse (sema_rel::drop_index& di) - { - // Find the index we are dropping in the base model. - // - traverse (find (di)); - } - - virtual void - traverse (sema_rel::index& in) - { - if (type_ == unique && - in.type ().find ("UNIQUE") == string::npos && - in.type ().find ("unique") == string::npos) - return; - - if (type_ == non_unique && ( - in.type ().find ("UNIQUE") != string::npos || - in.type ().find ("unique") != string::npos)) - return; - - pre_statement (); - drop (in); - post_statement (); - } - - virtual string - name (sema_rel::index& in) - { - return quote_id (in.name ()); - } - - virtual void - drop (sema_rel::index& in) - { - os << "DROP INDEX " << name (in) << endl; - } - - protected: - index_type type_; - }; - - struct drop_table: trav_rel::table, - trav_rel::drop_table, - trav_rel::add_table, // Override. - trav_rel::alter_table, // Override. - common - { - typedef drop_table base; - - drop_table (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) {} - - virtual void - drop (sema_rel::table& t, bool migration) - { - pre_statement (); - os << "DROP TABLE " << (migration ? "" : "IF EXISTS ") << - quote_id (t.name ()) << endl; - post_statement (); - } - - virtual void - delete_ (sema_rel::qname const& rtable, - sema_rel::qname const& dtable, - sema_rel::primary_key& rkey, - sema_rel::primary_key& dkey) - { - pre_statement (); - - // This might not be the most efficient way for every database. - // - os << "DELETE FROM " << quote_id (rtable) << endl - << " WHERE EXISTS (SELECT 1 FROM " << quote_id (dtable) << endl - << " WHERE "; - - for (size_t i (0); i != rkey.contains_size (); ++i) - { - if (i != 0) - os << endl - << " AND "; - - os << quote_id (rtable) << "." << - quote_id (rkey.contains_at (i).column ().name ()) << " = " << - quote_id (dtable) << "." << - quote_id (dkey.contains_at (i).column ().name ()); - } - - os << ")" << endl; - - post_statement (); - } - - virtual void - traverse (sema_rel::table& t, bool migration) - { - // By default drop foreign keys referencing tables that would - // have already been dropped on the first pass. - // - if (pass_ == 1) - { - // Drop constraints. In migration this is always done on pass 1. - // - if (migration) - { - instance dfk (*this); - trav_rel::unames n (*dfk); - names (t, n); - } - else - { - dropped_.insert (t.name ()); // Add it before to cover self-refs. - - instance dfk (*this, dropped_); - trav_rel::unames n (*dfk); - names (t, n); - } - } - else - { - if (migration && t.extra ()["kind"] == "polymorphic derived object") - { - // If we are dropping a polymorphic derived object, then we - // also have to clean the base tables. Note that this won't - // trigger cascade deletion since we have dropped all the - // keys on pass 1. But we still need to do this in the base - // to root order in order not to trigger other cascades. - // - using sema_rel::model; - using sema_rel::table; - using sema_rel::primary_key; - using sema_rel::foreign_key; - - model& m (dynamic_cast (t.scope ())); - - table* p (&t); - do - { - // The polymorphic link is the first primary key. - // - for (table::names_iterator i (p->names_begin ()); - i != p->names_end (); ++i) - { - if (foreign_key* fk = dynamic_cast ( - &i->nameable ())) - { - p = m.find
(fk->referenced_table ()); - assert (p != 0); // Base table should be there. - break; - } - } - - primary_key& rkey (*p->find ("")); - primary_key& dkey (*t.find ("")); - assert (rkey.contains_size () == dkey.contains_size ()); - delete_ (p->name (), t.name (), rkey, dkey); - } - while (p->extra ()["kind"] != "polymorphic root object"); - } - - drop (t, migration); - } - } - - virtual void - traverse (sema_rel::table& t) - { - traverse (t, false); - } - - virtual void - traverse (sema_rel::drop_table& dt) - { - using sema_rel::model; - using sema_rel::changeset; - using sema_rel::table; - - // Find the table we are dropping in the base model. - // - changeset& cs (dynamic_cast (dt.scope ())); - model& bm (cs.base_model ()); - table* t (bm.find
(dt.name ())); - assert (t != 0); - traverse (*t, true); - } - - using add_table::traverse; // Unhide. - using alter_table::traverse; // Unhide. - - using table::names; - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - table_set dropped_; - }; - - struct drop_model: trav_rel::model, common - { - typedef drop_model base; - - drop_model (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) - { - } - - virtual void - traverse (sema_rel::model& m) - { - // Traverse named entities in the reverse order. This way we - // drop them in the order opposite to creating. - // - for (sema_rel::model::names_iterator begin (m.names_begin ()), - end (m.names_end ()); begin != end;) - dispatch (*--end); - } - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - }; - - // - // Create. - // - - struct create_column: trav_rel::column, - trav_rel::add_column, - trav_rel::alter_column, // Override. - common - { - typedef create_column base; - - create_column (common const& c, - bool override_null = true, - bool* first = 0) - : common (c), - override_null_ (override_null), - first_ (first != 0 ? *first : first_data_), - first_data_ (true) - { - } - - create_column (create_column const& c) - : root_context (), // @@ -Wextra - context (), - common (c), - override_null_ (c.override_null_), - first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), - first_data_ (c.first_data_) - { - } - - virtual void - traverse (sema_rel::column& c) - { - if (first_) - first_ = false; - else - os << ","; - - os << endl - << " "; - create (c); - } - - virtual void - add_header () - { - // By default ADD COLUMN though some databases use just ADD. - // - os << "ADD COLUMN "; - } - - virtual void - traverse (sema_rel::add_column& ac) - { - if (first_) - first_ = false; - else - os << ","; - - os << endl - << " "; - add_header (); - create (ac); - } - - virtual void - create (sema_rel::column& c) - { - using sema_rel::column; - - // See if this column is (part of) a primary key. - // - sema_rel::primary_key* pk (0); - - for (column::contained_iterator i (c.contained_begin ()); - i != c.contained_end (); - ++i) - { - if ((pk = dynamic_cast (&i->key ()))) - break; - } - - os << quote_id (c.name ()) << " "; - - type (c, pk != 0 && pk->auto_ ()); - constraints (c, pk); - - if (!c.options ().empty ()) - os << " " << c.options (); - } - - virtual void - constraints (sema_rel::column& c, sema_rel::primary_key* pk) - { - null (c); - - if (!c.default_ ().empty ()) - os << " DEFAULT " << c.default_ (); - - // If this is a single-column primary key, generate it inline. - // - if (pk != 0 && pk->contains_size () == 1) - primary_key (); - - if (pk != 0 && pk->auto_ ()) - auto_ (*pk); - } - - virtual void - type (sema_rel::column& c, bool /*auto*/) - { - os << c.type (); - } - - virtual void - null (sema_rel::column& c) - { - bool n (c.null ()); - - // If we are adding a new column that doesn't allow NULL nor has - // a default value, add it as NULL. Later, after migration, we - // will convert it to NOT NULL. - // - if (override_null_ && c.is_a () && - !n && c.default_ ().empty ()) - n = true; - - // Specify both cases explicitly for better readability, - // especially in ALTER COLUMN clauses. - // - os << (n ? " NULL" : " NOT NULL"); - } - - virtual void - primary_key () - { - os << " PRIMARY KEY"; - } - - virtual void - auto_ (sema_rel::primary_key&) - { - } - - protected: - bool override_null_; // Override NOT NULL in add_column. - bool& first_; - bool first_data_; - bool add_; - }; - - struct create_primary_key: trav_rel::primary_key, common - { - typedef create_primary_key base; - - create_primary_key (common const& c): common (c) {} - - virtual void - traverse (sema_rel::primary_key& pk) - { - // Single-column primary keys are generated inline in the - // column declaration. - // - if (pk.contains_size () == 1) - return; - - // We will always follow a column. - // - os << "," << endl; - - create (pk); - } - - virtual void - create (sema_rel::primary_key& pk) - { - using sema_rel::primary_key; - - // By default we create unnamed primary key constraint. - // - - os << " PRIMARY KEY ("; - - for (primary_key::contains_iterator i (pk.contains_begin ()); - i != pk.contains_end (); - ++i) - { - if (i != pk.contains_begin ()) - os << "," << endl - << " "; - - os << quote_id (i->column ().name ()); - } - - os << ")"; - } - }; - - struct create_foreign_key: trav_rel::foreign_key, - trav_rel::add_foreign_key, - common - { - typedef create_foreign_key base; - - // Schema constructor, pass 1. - // - create_foreign_key (common const& c, table_set& created, bool* first = 0) - : common (c), - created_ (&created), - first_ (first != 0 ? *first : first_data_), - first_data_ (true) - { - } - - // Schema constructor, pass 2 and migration constructor. - // - create_foreign_key (common const& c, bool* first = 0) - : common (c), - created_ (0), - first_ (first != 0 ? *first : first_data_), - first_data_ (true) - { - } - - create_foreign_key (create_foreign_key const& c) - : root_context (), // @@ -Wextra - context (), - common (c), - created_ (c.created_), - first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), - first_data_ (c.first_data_) - { - } - - virtual void - traverse (sema_rel::foreign_key& fk) - { - if (created_ != 0) - { - // Pass 1. - // - // If the referenced table has already been defined, do the - // foreign key definition in the table definition. Otherwise - // postpone it until pass 2 where we do it via ALTER TABLE. - // - if (created_->find (fk.referenced_table ()) != created_->end ()) - { - traverse_create (fk); - fk.set (db.string () + "-fk-defined", true); // Mark it as defined. - } - } - else - { - // Pass 2. - // - if (!fk.count (db.string () + "-fk-defined")) - traverse_add (fk); - } - } - - virtual void - traverse_create (sema_rel::foreign_key& fk) - { - if (first_) - first_ = false; - else - os << ","; - - os << endl - << " CONSTRAINT "; - create (fk); - } - - virtual void - traverse_add (sema_rel::foreign_key& fk) - { - if (first_) - first_ = false; - else - os << ","; - - os << endl; - add (fk); - } - - virtual void - traverse (sema_rel::add_foreign_key& afk) - { - traverse_add (afk); - } - - virtual void - add_header () - { - os << "ADD CONSTRAINT "; - } - - virtual void - add (sema_rel::foreign_key& fk) - { - os << " "; - add_header (); - create (fk); - } - - virtual void - create (sema_rel::foreign_key& fk) - { - using sema_rel::foreign_key; - - os << name (fk) << endl - << " FOREIGN KEY ("; - - for (foreign_key::contains_iterator i (fk.contains_begin ()); - i != fk.contains_end (); - ++i) - { - if (i != fk.contains_begin ()) - os << "," << endl - << " "; - - os << quote_id (i->column ().name ()); - } - - string tn (table_name (fk)); - string tn_pad (tn.size (), ' '); - - os << ")" << endl - << " REFERENCES " << tn << " ("; - - foreign_key::columns const& refs (fk.referenced_columns ()); - for (foreign_key::columns::const_iterator i (refs.begin ()); - i != refs.end (); - ++i) - { - if (i != refs.begin ()) - os << "," << endl - << " " << tn_pad; - - os << quote_id (*i); - } - - os << ")"; - - if (fk.on_delete () != foreign_key::no_action) - on_delete (fk.on_delete ()); - - if (!fk.not_deferrable ()) - deferrable (fk.deferrable ()); - } - - virtual string - name (sema_rel::foreign_key& fk) - { - return quote_id (fk.name ()); - } - - virtual string - table_name (sema_rel::foreign_key& fk) - { - return quote_id (fk.referenced_table ()); - } - - virtual void - on_delete (sema_rel::foreign_key::action_type a) - { - using sema_rel::foreign_key; - - switch (a) - { - case foreign_key::no_action: - break; - case foreign_key::cascade: - { - os << endl - << " ON DELETE CASCADE"; - break; - } - case foreign_key::set_null: - { - os << endl - << " ON DELETE SET NULL"; - break; - } - } - } - - virtual void - deferrable (sema_rel::deferrable d) - { - os << endl - << " DEFERRABLE INITIALLY " << d; - } - - protected: - table_set* created_; - bool& first_; - bool first_data_; - }; - - struct create_index: trav_rel::index, common - { - typedef create_index base; - - enum index_type {unique, non_unique, all}; - - create_index (common const& c, index_type t = all) - : common (c), type_ (t) {} - - virtual void - traverse (sema_rel::index& in) - { - if (type_ == unique && - in.type ().find ("UNIQUE") == string::npos && - in.type ().find ("unique") == string::npos) - return; - - if (type_ == non_unique && ( - in.type ().find ("UNIQUE") != string::npos || - in.type ().find ("unique") != string::npos)) - return; - - pre_statement (); - create (in); - post_statement (); - } - - virtual string - name (sema_rel::index& in) - { - return quote_id (in.name ()); - } - - virtual string - table_name (sema_rel::index& in) - { - return quote_id (static_cast (in.scope ()).name ()); - } - - virtual void - columns (sema_rel::index& in) - { - using sema_rel::index; - - for (index::contains_iterator i (in.contains_begin ()); - i != in.contains_end (); - ++i) - { - if (in.contains_size () > 1) - { - if (i != in.contains_begin ()) - os << ","; - - os << endl - << " "; - } - - os << quote_id (i->column ().name ()); - - if (!i->options ().empty ()) - os << ' ' << i->options (); - } - } - - virtual void - create (sema_rel::index& in) - { - // Default implementation that ignores the method. - // - os << "CREATE "; - - if (!in.type ().empty ()) - os << in.type () << ' '; - - os << "INDEX " << name (in) << endl - << " ON " << table_name (in) << " ("; - - columns (in); - - os << ")" << endl; - - if (!in.options ().empty ()) - os << ' ' << in.options () << endl; - } - - protected: - index_type type_; - }; - - struct create_table: trav_rel::table, - trav_rel::alter_table, // Override. - common - { - typedef create_table base; - - using trav_rel::table::names; - - create_table (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) {} - - virtual void - create_pre (sema_rel::qname const& table) - { - os << "CREATE TABLE " << quote_id (table) << " ("; - } - - virtual void - create_post (sema_rel::table& t) - { - os << ")" << endl; - - if (!t.options ().empty ()) - os << " " << t.options () << endl; - } - - virtual void - create (sema_rel::table& t) - { - pre_statement (); - create_pre (t.name ()); - - instance c (*this); - instance pk (*this); - - // We will always follow a column, so set first to false. - // - bool f (false); // (Im)perfect forwarding. - bool* pf (&f); // (Im)perfect forwarding. - instance fk (*this, created_, pf); - - trav_rel::unames n; - n >> c; - n >> pk; - n >> fk; - - names (t, n); - - create_post (t); - post_statement (); - - // Create indexes. - // - { - instance in (*this); - trav_rel::unames n (*in); - names (t, n); - } - } - - // See if there are any undefined foreign keys that we need to - // add with ALTER TABLE. - // - bool - check_undefined_fk (sema_rel::table& t) - { - for (sema_rel::table::names_iterator i (t.names_begin ()); - i != t.names_end (); ++i) - { - if (i->nameable ().is_a () && - !i->nameable ().count (db.string () + "-fk-defined")) - return true; - } - return false; - } - - virtual void - traverse (sema_rel::table& t) - { - // By default add foreign keys referencing tables that haven't - // yet been defined on the second pass. - // - if (pass_ == 1) - { - // In migration we always add foreign keys on pass 2. - // - if (!t.is_a ()) - created_.insert (t.name ()); // Add it before to cover self-refs. - - create (t); - } - else - { - // Add undefined foreign keys. - // - if (check_undefined_fk (t)) - { - pre_statement (); - os << "ALTER TABLE " << quote_id (t.name ()); - - instance cfk (*this); - trav_rel::unames n (*cfk); - names (t, n); - os << endl; - - post_statement (); - } - } - } - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - table_set created_; - }; - - struct create_model: trav_rel::model, common - { - typedef create_model base; - - create_model (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) {} - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - }; - - // - // Alter. - // - - struct alter_column: trav_rel::alter_column, - trav_rel::add_column, - common - { - typedef alter_column base; - - alter_column (common const& c, bool pre, bool* first = 0) - : common (c), - pre_ (pre), - first_ (first != 0 ? *first : first_data_), - first_data_ (true), - fl_ (false), - def_ (c, fl_) - { - } - - alter_column (alter_column const& c) - : root_context (), // @@ -Wextra - context (), - common (c), - pre_ (c.pre_), - first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), - first_data_ (c.first_data_), - fl_ (false), - def_ (c, fl_) - { - } - - virtual void - alter_header () - { - os << "ALTER COLUMN "; - } - - virtual void - alter (sema_rel::column& c) - { - // By default use the whole definition. - // - def_->create (c); - } - - virtual void - traverse (sema_rel::column& c) - { - // Relax (NULL) in pre and tighten (NOT NULL) in post. - // - if (pre_ != c.null ()) - return; - - if (first_) - first_ = false; - else - os << ","; - - os << endl - << " "; - alter_header (); - alter (c); - } - - virtual void - traverse (sema_rel::alter_column& ac) - { - assert (ac.null_altered ()); - traverse (static_cast (ac)); - } - - virtual void - traverse (sema_rel::add_column& ac) - { - // We initially add NOT NULL columns without default values as - // NULL. Now, after the migration, we convert them to NOT NULL. - // - if (!ac.null () && ac.default_ ().empty ()) - traverse (static_cast (ac)); - } - - protected: - bool pre_; - bool& first_; - bool first_data_; - bool fl_; // (Im)perfect forwarding. - instance def_; - }; - - struct alter_table_common: trav_rel::alter_table, common - { - alter_table_common (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) {} - - template - T* - check (sema_rel::alter_table& at) - { - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - if (T* x = dynamic_cast (&i->nameable ())) - return x; - } - return 0; - } - - sema_rel::column* - check_alter_column_null (sema_rel::alter_table& at, bool v) - { - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::add_column; - using sema_rel::alter_column; - - if (alter_column* ac = dynamic_cast (&i->nameable ())) - { - if (ac->null_altered () && ac->null () == v) - return ac; - } - - // If we are testing for NOT NULL, also look for new columns that - // we initially add as NULL and later convert to NOT NULL. - // - if (!v) - { - if (add_column* ac = dynamic_cast (&i->nameable ())) - { - if (!ac->null () && ac->default_ ().empty ()) - return ac; - } - } - } - return 0; - } - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - }; - - struct alter_table_pre: alter_table_common - { - typedef alter_table_pre base; - - alter_table_pre (emitter_type& e, ostream& os, schema_format f) - : alter_table_common (e, os, f) {} - - // Check if there will be any clauses in ALTER TABLE. - // - using alter_table_common::check; - - virtual bool - check (sema_rel::alter_table& at) - { - // If changing the below test, make sure to also update tests - // in database-specific code. - // - return - check (at) || - check (at) || - check_alter_column_null (at, true); - } - - virtual void - alter (sema_rel::alter_table& at) - { - // By default we generate all the alterations in a single ALTER TABLE - // statement. Quite a few databases don't support this. - // - pre_statement (); - os << "ALTER TABLE " << quote_id (at.name ()); - - bool f (true); // Shared first flag. - bool* pf (&f); // (Im)perfect forwarding. - bool tl (true); // (Im)perfect forwarding. - instance cc (*this, tl, pf); - instance ac (*this, tl, pf); - instance dfk (*this, pf); - trav_rel::unames n; - n >> cc; - n >> ac; - n >> dfk; - names (at, n); - os << endl; - - post_statement (); - } - - virtual void - traverse (sema_rel::alter_table& at) - { - if (pass_ == 1) - { - // Drop unique indexes. - // - { - drop_index::index_type it (drop_index::unique); - instance in (*this, it); - trav_rel::unames n (*in); - names (at, n); - } - - if (check (at)) - alter (at); - } - else - { - // Add non-unique indexes. - // - { - create_index::index_type it (create_index::non_unique); - instance in (*this, it); - trav_rel::unames n (*in); - names (at, n); - } - } - } - }; - - struct changeset_pre: trav_rel::changeset, common - { - typedef changeset_pre base; - - changeset_pre (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) {} - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - }; - - struct alter_table_post: alter_table_common - { - typedef alter_table_post base; - - alter_table_post (emitter_type& e, ostream& os, schema_format f) - : alter_table_common (e, os, f) {} - - // Check if there will be any clauses in ALTER TABLE. - // - using alter_table_common::check; - - virtual bool - check (sema_rel::alter_table& at) - { - // If changing the below test, make sure to also update tests - // in database-specific code. - // - return - check (at) || - check (at) || - check_alter_column_null (at, false); - } - - virtual void - alter (sema_rel::alter_table& at) - { - // By default we generate all the alterations in a single ALTER TABLE - // statement. Quite a few databases don't support this. - // - pre_statement (); - os << "ALTER TABLE " << quote_id (at.name ()); - - bool f (true); // Shared first flag. - bool* pf (&f); // (Im)perfect forwarding. - bool fl (false); // (Im)perfect forwarding. - instance dc (*this, pf); - instance ac (*this, fl, pf); - instance fk (*this, pf); - - trav_rel::unames n; - n >> dc; - n >> ac; - n >> fk; - names (at, n); - os << endl; - - post_statement (); - } - - virtual void - traverse (sema_rel::alter_table& at) - { - if (pass_ == 1) - { - // Drop non-unique indexes. - // - { - drop_index::index_type it (drop_index::non_unique); - instance in (*this, it); - trav_rel::unames n (*in); - names (at, n); - } - } - else - { - if (check (at)) - alter (at); - - // Add unique indexes. - // - { - create_index::index_type it (create_index::unique); - instance in (*this, it); - trav_rel::unames n (*in); - names (at, n); - } - } - } - }; - - struct changeset_post: trav_rel::changeset, common - { - typedef changeset_post base; - - changeset_post (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f) {} - - virtual void - traverse (sema_rel::changeset& m) - { - // Traverse named entities in the reverse order. This way we - // drop them in the order opposite to creating. - // - for (sema_rel::changeset::names_iterator begin (m.names_begin ()), - end (m.names_end ()); begin != end;) - dispatch (*--end); - } - - void - pass (unsigned short p) - { - pass_ = p; - } - - protected: - unsigned short pass_; - }; - - // - // Schema version table. - // - - struct version_table: common - { - typedef version_table base; - - version_table (emitter_type& e, ostream& os, schema_format f) - : common (e, os, f), - table_ (options.schema_version_table ()[db]), - qt_ (quote_id (table_)), - qs_ (quote_string (options.schema_name ()[db])), - qn_ (quote_id ("name")), - qv_ (quote_id ("version")), - qm_ (quote_id ("migration")) - { - } - - // Create the version table if it doesn't exist. - // - virtual void - create_table () {} - - // Remove the version entry. Called after the DROP statements. - // - virtual void - drop () - { - pre_statement (); - - os << "DELETE FROM " << qt_ << endl - << " WHERE " << qn_ << " = " << qs_ << endl; - - post_statement (); - } - - // Set the version. Called after the CREATE statements. - // - virtual void - create (sema_rel::version) {} - - // Set the version and migration state to true. Called after - // the pre migration statements. - // - virtual void - migrate_pre (sema_rel::version v) - { - pre_statement (); - - os << "UPDATE " << qt_ << endl - << " SET " << qv_ << " = " << v << ", " << qm_ << " = 1" << endl - << " WHERE " << qn_ << " = " << qs_ << endl; - - post_statement (); - } - - // Set migration state to false. Called after the post migration - // statements. - // - virtual void - migrate_post () - { - pre_statement (); - - os << "UPDATE " << qt_ << endl - << " SET " << qm_ << " = 0" << endl - << " WHERE " << qn_ << " = " << qs_ << endl; - - post_statement (); - } - - protected: - sema_rel::qname table_; - string qt_; // Quoted table. - string qs_; // Quoted schema name string. - string qn_; // Quoted name column. - string qv_; // Quoted version column. - string qm_; // Quoted migration column. - }; - - // - // SQL output. - // - - struct sql_emitter: emitter, virtual context - { - typedef sql_emitter base; - - virtual void - pre () - { - first_ = true; - } - - virtual void - line (const std::string& l) - { - if (first_ && !l.empty ()) - first_ = false; - else - os << endl; - - os << l; - } - - virtual void - post () - { - if (!first_) // Ignore empty statements. - os << ';' << endl - << endl; - } - - protected: - bool first_; - }; - - struct sql_file: virtual context - { - typedef sql_file base; - - virtual void - prologue () - { - } - - virtual void - epilogue () - { - } - }; - } -} - -#endif // ODB_RELATIONAL_SCHEMA_HXX diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx deleted file mode 100644 index e00626a..0000000 --- a/odb/relational/source.cxx +++ /dev/null @@ -1,6343 +0,0 @@ -// file : odb/relational/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include -#include - -#include -#include - -using namespace std; - -void relational::source::class_:: -traverse_object (type& c) -{ - using semantics::data_member; - - data_member_path* id (id_member (c)); - data_member* idf (id ? id->front () : 0); - data_member* idb (id ? id->back () : 0); - bool auto_id (id && auto_ (*id)); - bool base_id (id && &idf->scope () != &c); // Comes from base. - - data_member* opt (optimistic (c)); - - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - type* poly_base (poly_derived ? &polymorphic_base (c) : 0); - size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1); - data_member* discriminator (poly ? context::discriminator (*poly_root) : 0); - - bool abst (abstract (c)); - bool reuse_abst (abst && !poly); - bool readonly (context::readonly (c)); - - bool grow (false); - bool grow_id (false); - - if (generate_grow) - { - grow = context::grow (c); - grow_id = (id ? context::grow (*idb) : false) || - (opt ? context::grow (*opt) : false); - } - - column_count_type const& cc (column_count (c)); - bool versioned (context::versioned (c)); - - // Schema name as a string literal or empty. - // - string schema_name (options.schema_name ()[db]); - if (!schema_name.empty ()) - schema_name = strlit (schema_name); - - string const& type (class_fq_name (c)); - string traits ("access::object_traits_impl< " + type + ", id_" + - db.string () + " >"); - - user_sections& uss (c.get ("user-sections")); - user_sections* buss (poly_base != 0 - ? &poly_base->get ("user-sections") - : 0); - - os << "// " << class_name (c) << endl - << "//" << endl - << endl; - - object_extra (c); - - // - // Query (abstract and concrete). - // - - // query_columns - // - if (options.generate_query ()) - query_columns_type_->traverse (c); - - // Statement cache (definition). - // - if (!reuse_abst && id != 0) - { - bool sections (false); - bool containers (has_a (c, test_container)); - - os << "struct " << traits << "::extra_statement_cache_type" - << "{"; - - instance cm; - cm->traverse (c); - - if (containers) - os << endl; - - instance sm; - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip the special version update section in reuse inheritance (we - // always treat it as abstract). - // - if (i->special == user_section::special_version && !poly) - continue; - - // Generate an entry for a readonly section in optimistic - // polymorphic root since it can be overridden and we may - // need to update the version. - // - if (!i->empty () || (poly && i->optimistic ())) - { - sm->traverse (*i); - sections = true; - } - } - - if (sections) - os << endl; - - os << "extra_statement_cache_type (" << endl - << db << "::connection&" << (containers || sections ? " c" : "") << - "," << endl - << "image_type&" << (sections ? " im" : "") << "," << endl - << "id_image_type&" << (sections ? " idim" : "") << "," << endl - << db << "::binding&" << (containers || sections ? " id" : "") << - "," << endl - << db << "::binding&" << (sections ? " idv" : ""); - - extra_statement_cache_extra_args (containers, sections); - - os << ")"; - - instance cim; - cim->traverse (c); - - instance sim (!containers); - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - if (i->special == user_section::special_version && !poly) - continue; - - if (!i->empty () || (poly && i->optimistic ())) - sim->traverse (*i); - } - - os << "{" - << "}" - << "};"; - } - - // - // Containers (abstract and concrete). - // - - { - instance t (c); - t->traverse (c); - } - - // - // Sections (abstract and concrete). - // - - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - instance t (c); - t->traverse (*i); - } - - // - // Functions (abstract and concrete). - // - - // id(), version() - // - if (!poly_derived && id != 0 && !base_id) - { - // id (id_image_type) - // - if (auto_id) - { - os << traits << "::id_type" << endl - << traits << "::" << endl - << "id (const id_image_type& i)" - << "{" - << db << "::database* db (0);" - << "ODB_POTENTIALLY_UNUSED (db);" - << endl - << "id_type id;"; - init_id_value_member_id_image_->traverse (*idb); - os << "return id;" - << "}"; - } - - // id (image) - // - if (options.generate_query ()) - { - os << traits << "::id_type" << endl - << traits << "::" << endl - << "id (const image_type& i)" - << "{" - << db << "::database* db (0);" - << "ODB_POTENTIALLY_UNUSED (db);" - << endl - << "id_type id;"; - - // Handle nested id. - // - if (id->size () > 1) - { - string var; - - for (data_member_path::const_iterator i (id->begin ()); - i != id->end (); - ++i) - { - // The same logic as in member_base. - // - if (!var.empty ()) - var += "value."; // Composite. - - string const& name ((*i)->name ()); - var += name; - - if (name[name.size () - 1] != '_') - var += '_'; - } - - instance t ("id", var); - t->traverse (*idb); - } - else - init_id_value_member_->traverse (*idb); - - os << "return id;" - << "}"; - } - - // version (image) - // - if (opt != 0) - { - os << traits << "::version_type" << endl - << traits << "::" << endl - << "version (const image_type& i)" - << "{" - << "version_type v;"; - init_version_value_member_->traverse (*opt); - os << "return v;" - << "}"; - } - } - - // discriminator(image) - // - if (poly && !poly_derived) - { - os << traits << "::discriminator_type" << endl - << traits << "::" << endl - << "discriminator (const image_type& i)" - << "{" - << db << "::database* db (0);" - << "ODB_POTENTIALLY_UNUSED (db);" - << endl - << "discriminator_type d;"; - init_discriminator_value_member_->traverse (*discriminator); - os << "return d;" - << "}"; - } - - // grow () - // - if (generate_grow) - { - os << "bool " << traits << "::" << endl - << "grow (image_type& i," << endl - << truncated_vector << " t"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - if (poly_derived) - os << "," << endl - << "std::size_t d"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "bool grew (false);" - << endl; - - index_ = 0; - - if (poly_derived) - { - // Select column count for this class. - // - size_t cols (cc.total - cc.id); - - os << "// " << class_name (*poly_base) << " base" << endl - << "//" << endl - << "if (--d != 0)" - << "{" - << "if (base_traits::grow (*i.base, " << - "t + " << cols << "UL" << - (context::versioned (*poly_base) ? ", svm" : "") << - (poly_base != poly_root ? ", d" : "") << "))" << endl - << "i.base->version++;" - << "}"; - } - else - inherits (c, grow_base_inherits_); - - names (c, grow_member_names_); - - os << "return grew;" - << "}"; - } - - // bind (image_type) - // - os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b," << endl; - - // If we are a derived type in a polymorphic hierarchy, then - // we get the external id binding. - // - if (poly_derived) - os << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl; - - os << "image_type& i," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - if (readonly) - os << "assert (sk != statement_update);" - << endl; - - os << "std::size_t n (0);" - << endl; - - if (poly_derived) - { - // The id reference comes first in the insert statement. - // - os << "// " << idf->name () << endl - << "//" << endl - << "if (sk == statement_insert)" - << "{" - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << "}"; - } - else - inherits (c, bind_base_inherits_); - - names (c, bind_member_names_); - - if (poly_derived) - { - // The id reference comes last in the update statement. - // - if (!readonly) - os << "// " << idf->name () << endl - << "//" << endl - << "if (sk == statement_update)" - << "{" - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << "}"; - - // Bind the image chain for the select statement. Seeing that - // this is the last statement in the function, we don't care - // about updating n. - // - os << "// " << class_name (*poly_base) << " base" << endl - << "//" << endl - << "if (sk == statement_select)" << endl - << "base_traits::bind (b + n, "; - - if (poly_base != poly_root) - os << "id, id_size, "; - - os << "*i.base, sk" << - (context::versioned (*poly_base) ? ", svm" : "") << ");"; - } - - os << "}"; - - // bind (id_image_type) - // - if (!poly_derived && id != 0 && !base_id) - { - os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b, id_image_type& i" << - (opt != 0 ? ", bool bv" : "") << ")" - << "{" - << "std::size_t n (0);"; - - if (composite_wrapper (utype (*id))) - os << db << "::statement_kind sk (" << db << "::statement_select);"; - - bind_id_member_->traverse (*idb); - - if (opt != 0) - { - os << "if (bv)" - << "{" - << "n += " << column_count (c).id << ";" - << endl; - - bind_version_member_->traverse (*opt); - os << "}"; - } - - os << "}"; - } - - // init (image, object) - // - os << (generate_grow ? "bool " : "void ") << traits << "::" << endl - << "init (image_type& i," << endl - << "const object_type& o," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - if (readonly) - os << "assert (sk != statement_update);" - << endl; - - init_image_pre (c); - - if (generate_grow) - os << "bool grew (false);" - << endl; - - if (!poly_derived) - inherits (c, init_image_base_inherits_); - - names (c, init_image_member_names_); - - if (generate_grow) - os << "return grew;"; - - os << "}"; - - // init (object, image) - // - os << "void " << traits << "::" << endl - << "init (object_type& o," << endl - << "const image_type& i," << endl - << "database* db"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - if (poly_derived) - os << "," << endl - << "std::size_t d"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - if (poly_derived) - { - os << "// " << class_name (*poly_base) << " base" << endl - << "//" << endl - << "if (--d != 0)" << endl - << "base_traits::init (o, *i.base, db" << - (context::versioned (*poly_base) ? ", svm" : "") << - (poly_base != poly_root ? ", d" : "") << ");" - << endl; - } - else - inherits (c, init_value_base_inherits_); - - names (c, init_value_member_names_); - - os << "}"; - - // init (id_image, id) - // - if (id != 0 && !base_id) - { - os << "void " << traits << "::" << endl - << "init (id_image_type& i, const id_type& id" << - (opt != 0 ? ", const version_type* v" : "") << ")" - << "{"; - - if (grow_id) - os << "bool grew (false);"; - - if (composite_wrapper (utype (*id))) - os << db << "::statement_kind sk (" << db << "::statement_select);"; - - init_id_image_member_->traverse (*idb); - - if (opt != 0) - { - // Here we rely on the fact that init_image_member - // always wraps the statements in a block. - // - os << "if (v != 0)"; - init_version_image_member_->traverse (*opt); - } - - if (grow_id) - os << "if (grew)" << endl - << "i.version++;"; - - os << "}"; - } - - // The rest does not apply to reuse-abstract objects. - // - if (reuse_abst) - return; - - // - // Containers (concrete). - // - - // - // Sections (concrete). - // - - // Polymorphic map. - // - if (poly) - { - if (!poly_derived) - os << traits << "::map_type*" << endl - << traits << "::map;" - << endl; - - // Sections. Do we have any new sections or overrides? - // - bool sections ( - uss.count (user_sections::count_new | - user_sections::count_override | - user_sections::count_load | - user_sections::count_update | - user_sections::count_special_version | - (poly ? user_sections::count_optimistic : 0)) != 0); - if (sections) - { - string const& fn (flat_name (type)); - - size_t n (uss.count (user_sections::count_total | - user_sections::count_all | - user_sections::count_special_version)); - - map m; - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - m[i->index] = &*i; - - os << "static const "<< traits << "::" << (abst ? "abstract_" : "") << - "info_type::section_functions" << endl - << "section_functions_for_" << fn << "[] =" - << "{"; - - for (size_t i (0); i != n; ++i) - { - os << (i != 0 ? "," : "") << "{"; - - map::iterator j (m.find (i)); - - if (j != m.end ()) - { - user_section& s (*j->second); - string n (public_name (*s.member)); - - // load - // - if (s.load_empty ()) - os << "0"; - else - os << "&odb::section_load_impl< " << type << ", id_" << db << - ", " << traits << "::" << n << "_traits >"; - - os << "," << endl; - - // update - // - // Generate an entry for a readonly section in optimistic - // polymorphic root since it can be overridden and we may - // need to update the version. - // - if (s.update_empty () && !(poly && s.optimistic ())) - os << "0"; - else - os << "&odb::section_update_impl< " << type << ", id_" << db << - ", " << traits << "::" << n << "_traits >"; - } - else - os << "0," << endl - << "0"; - - os << "}"; - } - - os << "};"; - - os << "static const "<< traits << "::" << (abst ? "abstract_" : "") << - "info_type::section_list" << endl - << "section_list_for_" << fn << " =" - << "{" - << n << "UL," << endl - << "section_functions_for_" << fn - << "};"; - } - - // - // - os << "const " << traits << "::" << (abst ? "abstract_" : "") << - "info_type" << endl - << traits << "::info (" << endl - << "typeid (" << type << ")," << endl; - - if (poly_derived) - os << "&object_traits_impl< " << class_fq_name (*poly_base) << - ", id_" << db << " >::info," << endl; - else - os << "0," << endl; - - // Sections. - // - if (sections) - os << "§ion_list_for_" << flat_name (type); - else - os << "0"; - - if (!abst) - { - os << "," << endl - << strlit (string (type, 2, string::npos)) << "," << endl - << "&odb::create_impl< " << type << " >," << endl - << "&odb::dispatch_impl< " << type << ", id_" << db << " >," << endl; - - if (poly_derived) - os << "&statements_type::delayed_loader"; - else - os << "0"; - } - - os << ");" - << endl; - - if (!abst) - os << "static const " << traits << "::entry_type" << endl - << "polymorphic_entry_for_" << flat_name (type) << ";" - << endl; - } - - // - // Statements. - // - bool update_columns ( - cc.total != cc.id + cc.inverse + cc.readonly + cc.separate_update); - - qname table (table_name (c)); - string qtable (quote_id (table)); - - // persist_statement - // - { - string sep (versioned ? "\n" : " "); - - statement_columns sc; - { - statement_kind sk (statement_insert); // Imperfect forwarding. - instance ct (sk, sc); - ct->traverse (c); - process_statement_columns (sc, statement_insert, versioned); - } - - bool dv (sc.empty ()); // The DEFAULT VALUES syntax. - - os << "const char " << traits << "::persist_statement[] =" << endl - << strlit ("INSERT INTO " + qtable + sep) << endl; - - for (statement_columns::const_iterator b (sc.begin ()), i (b), - e (sc.end ()); i != e;) - { - string s; - - if (i == b) - s += '('; - s += i->column; - s += (++i != e ? ',' : ')'); - s += sep; - - os << strlit (s) << endl; - } - - instance qp (statement_insert, table); - - string extra (persist_statement_extra (c, *qp, persist_after_columns)); - - if (!extra.empty ()) - os << strlit (extra + sep) << endl; - - string values; - if (!dv) - { - os << strlit ("VALUES" + sep) << endl; - - values += '('; - instance pt (values, *qp, sep); - pt->traverse (c); - values += ')'; - } - else - values = "DEFAULT VALUES"; - - extra = persist_statement_extra (c, *qp, persist_after_values); - - if (!extra.empty ()) - values += sep; - - os << strlit (values); - - if (!extra.empty ()) - os << endl - << strlit (extra); - - os << ";" - << endl; - } - - // Index of the first empty SELECT statement in poly-derived - // statement list. All subsequent statements are also empty. - // The first statement can never be empty (contains id and - // type_id). - // - size_t empty_depth (0); - - if (id != 0) - { - string sep (versioned ? "\n" : " "); - - instance id_cols; - id_cols->traverse (*id); - - std::vector find_column_counts (abst ? 1 : poly_depth); - - // find_statement - // - if (poly_derived) - os << "const char* const " << traits << "::find_statements[] =" - << "{"; - else - os << "const char " << traits << "::find_statement[] =" << endl; - - for (size_t d (poly_depth); d != 0;) - { - statement_columns sc; - { - statement_kind sk (statement_select); // Imperfect forwarding. - object_section* s (&main_section); // Imperfect forwarding. - instance t (qtable, sk, sc, d, s); - t->traverse (c); - process_statement_columns (sc, statement_select, versioned); - find_column_counts[poly_depth - d] = sc.size (); - } - - if (sc.size () != 0) - { - os << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - os << strlit ("FROM " + qtable + sep) << endl; - - if (d != 1) - { - bool f (false); // @@ (im)perfect forwarding - size_t d1 (d - 1); //@@ (im)perfect forward. - instance j (c, f, d1); - j->traverse (polymorphic_base (c)); - - for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) - os << strlit (*i + sep) << endl; - } - - { - // For the find statement, don't join section members. - // - bool f (false); // @@ (im)perfect forwarding - object_section* s (&main_section); // @@ (im)perfect forwarding - instance j (c, f, d, s); - j->traverse (c); - - for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) - os << strlit (*i + sep) << endl; - } - - string where ("WHERE "); - instance qp (statement_select, table); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where); - } - else - os << strlit (""); // Empty SELECT statement. - - if (abst) - break; - - if (--d != 0) - os << "," << endl - << endl; - } - - if (poly_derived) - os << "};"; - else - os << ";" - << endl; - - // find_column_counts - // - if (poly_derived) - { - os << "const std::size_t " << traits << "::find_column_counts[] =" - << "{"; - - for (std::vector::iterator b (find_column_counts.begin ()), - i (b), e (find_column_counts.end ()); i != e;) - { - os << *i << "UL"; - - if (*i == 0 && empty_depth == 0) - empty_depth = i - b; - - if (++i != e) - os << ',' << endl; - } - - os << "};"; - } - - // find_discriminator_statement - // - if (poly && !poly_derived) - { - statement_columns sc; - { - statement_kind sk (statement_select); // Imperfect forwarding. - instance t (qtable, sk, sc); - t->traverse (*discriminator); - - if (opt != 0) - t->traverse (*opt); - - process_statement_columns (sc, statement_select, false); - } - - os << "const char " << traits << "::" << endl - << "find_discriminator_statement[] =" << endl - << strlit ("SELECT ") << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? ", " : " ")) << endl; - } - - os << strlit ("FROM " + qtable + " ") << endl; - - string where ("WHERE "); - instance qp (statement_select, table); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where) << ";" - << endl; - } - - // update_statement - // - if (update_columns) - { - string sep (versioned ? "\n" : " "); - - instance qp (statement_update, table); - - statement_columns sc; - { - query_parameters* p (qp.get ()); // Imperfect forwarding. - statement_kind sk (statement_update); // Imperfect forwarding. - object_section* s (&main_section); // Imperfect forwarding. - instance t (sk, sc, p, s); - t->traverse (c); - process_statement_columns (sc, statement_update, versioned); - } - - os << "const char " << traits << "::update_statement[] =" << endl - << strlit ("UPDATE " + qtable + sep) << endl - << strlit ("SET" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - // This didn't work out: cannot change the identity column. - // - //if (sc.empty ()) - //{ - // // We can end up with nothing to set if we need to "touch" a row - // // in order to increment its optimistic concurrency version. In - // // this case just do a dummy assignment based on the id column. - // // - // string const& c (quote_id (id_cols->begin ()->name)); - // os << strlit (c + "=" + c) << endl; - //} - - string extra (update_statement_extra (c)); - - if (!extra.empty ()) - os << strlit (extra + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - // Top-level version column. - // - if (opt != 0 && !poly_derived) - { - string name (column_qname (*opt, column_prefix ())); - string type (column_type (*opt)); - - where += " AND " + name + "=" + - convert_to (qp->next (*opt, name, type), type, *opt); - } - - os << strlit (where) << ";" - << endl; - } - - // erase_statement - // - { - instance qp (statement_delete, table); - os << "const char " << traits << "::erase_statement[] =" << endl - << strlit ("DELETE FROM " + qtable + " ") << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where) << ";" - << endl; - } - - if (opt != 0 && !poly_derived) - { - instance qp (statement_delete, table); - - os << "const char " << traits << "::optimistic_erase_statement[] " << - "=" << endl - << strlit ("DELETE FROM " + qtable + " ") << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - // Top-level version column. - // - string name (column_qname (*opt, column_prefix ())); - string type (column_type (*opt)); - - where += " AND " + name + "=" + - convert_to (qp->next (*opt, name, type), type, *opt); - - os << strlit (where) << ";" - << endl; - } - } - - // query_statement - // - bool query_optimize (false); - if (options.generate_query ()) - { - // query_statement - // - strings joins; - if (poly_depth != 1) - { - bool t (true); //@@ (im)perfect forwarding - size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j (c, t, d); - j->traverse (polymorphic_base (c)); - joins = j->joins; - } - - if (id != 0) - { - // For the query statement we also join section members so that they - // can be used in the WHERE clause. - // - bool t (true); //@@ (im)perfect forwarding - instance j (c, t, poly_depth); - j->traverse (c); - joins.insert (joins.end (), j->begin (), j->end ()); - } - - query_optimize = !joins.empty (); - - statement_columns sc; - { - statement_kind sk (statement_select); //@@ Imperfect forwarding. - object_section* s (&main_section); //@@ Imperfect forwarding. - instance oc (qtable, sk, sc, poly_depth, s); - oc->traverse (c); - process_statement_columns ( - sc, statement_select, versioned || query_optimize); - } - - string sep (versioned || query_optimize ? "\n" : " "); - - os << "const char " << traits << "::query_statement[] =" << endl - << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - string prev ("FROM " + qtable); - - for (strings::const_iterator i (joins.begin ()); i != joins.end (); ++i) - { - os << strlit (prev + sep) << endl; - prev = *i; - } - - os << strlit (prev) << ";" - << endl; - - // erase_query_statement - // - os << "const char " << traits << "::erase_query_statement[] =" << endl - << strlit ("DELETE FROM " + qtable) << ";" - << endl; - - // table_name - // - os << "const char " << traits << "::table_name[] =" << endl - << strlit (qtable) << ";" // Use quoted name. - << endl; - } - - // persist () - // - size_t persist_containers (has_a (c, test_straight_container)); - bool persist_versioned_containers ( - persist_containers > - has_a (c, - test_straight_container | - exclude_deleted | exclude_added | exclude_versioned)); - - os << "void " << traits << "::" << endl - << "persist (database& db, " << (auto_id ? "" : "const ") << - "object_type& obj"; - - if (poly) - os << ", bool top, bool dyn"; - - os << ")" - << "{"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (top);" - << endl; - - os << "using namespace " << db << ";" - << endl; - - if (poly) - os << "if (dyn)" << endl - << "{" - << "const std::type_info& t (typeid (obj));" - << endl - << "if (t != info.type)" - << "{" - << "const info_type& pi (root_traits::map->find (t));" - << "pi.dispatch (info_type::call_persist, db, &obj, 0);" - << "return;" - << "}" - << "}"; - - // If we are database-poly-abstract but not C++-abstract, then make - // sure we are not trying to persist an instance of an abstract class. - // - if (abst && !c.abstract ()) - os << "if (top)" << endl - << "throw abstract_class ();" - << endl; - - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned || - persist_versioned_containers || - uss.count (user_sections::count_new | - user_sections::count_all | - user_sections::count_versioned_only) != 0) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << endl; - - // Call callback (pre_persist). - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" << endl; - - os << "callback (db," << endl - << (auto_id ? "static_cast (obj)," : "obj,") << endl - << "callback_event::pre_persist);" - << endl; - } - - // Call our base if we are a derived type in a polymorphic - // hierarchy. - // - if (poly_derived) - os << "base_traits::persist (db, obj, false, false);" - << endl; - - os << "image_type& im (sts.image ());" - << "binding& imb (sts.insert_image_binding ());"; - - if (poly_derived) - os << "const binding& idb (sts.id_image_binding ());"; - - os << endl; - - if (generate_grow) - os << "if ("; - - os << "init (im, obj, statement_insert" << (versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "im.version++"; - - os << ";" - << endl; - - if (!poly_derived && auto_id && insert_send_auto_id) - { - string const& n (idf->name ()); - string var ("im." + n + (n[n.size () - 1] == '_' ? "" : "_")); - init_auto_id (*idf, var); // idf == idb, since auto - } - - os << "if ("; - - if (poly_derived) - os << "idb.version != sts.insert_id_binding_version () ||" << endl; - - os << "im.version != sts.insert_image_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, "; - - if (poly_derived) - os << "idb.bind, idb.count, "; - - os << "im, statement_insert" << (versioned ? ", svm" : "") << ");"; - - if (poly_derived) - os << "sts.insert_id_binding_version (idb.version);"; - - os << "sts.insert_image_version (im.version);" - << "imb.version++;" - << "}"; - - // Bind id image since that's where the returned id and/or version will - // be extracted. - // - if (!poly_derived) - { - bool bv (opt != 0 && optimistic_insert_bind_version (*opt)); - if (bv || auto_id) - { - os << "{" - << "id_image_type& i (sts.id_image ());" - << "binding& b (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || b.version == 0)" - << "{" - << "bind (b.bind, i);" - << "sts.id_image_version (i.version);" - << "b.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}" - << "}"; - } - } - - os << "insert_statement& st (sts.persist_statement ());" - << "if (!st.execute ())" << endl - << "throw object_already_persistent ();" - << endl; - - if (!poly_derived && auto_id) // idf == idb since auto - { - set_member (*idf, "obj", "id (sts.id_image ())", "db", "id_type"); - os << endl; - } - - // Set the optimistic concurrency version in the object member. - // - if (opt != 0 && !poly_derived) - { - // If we don't have auto id, then obj is a const reference. - // - set_member (*opt, - (auto_id ? "obj" : "const_cast (obj)"), - optimistic_version_init (*opt), - "", // No database. - "version_type"); - os << endl; - } - - // Initialize id_image and binding if we are a root of a polymorphic - // hierarchy or if we have non-inverse containers. - // - if (!poly_derived && (poly || persist_containers)) - { - // If this is a polymorphic root without containers, then we only - // need to do this if we are not a top-level call. If we are poly- - // abstract, then top will always be false. - // - if (poly && !persist_containers && !abst) - os << "if (!top)" - << "{"; - - os << "id_image_type& i (sts.id_image ());" - << "init (i, id (obj));" - << endl - << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - - if (poly && !persist_containers && !abst) - os << "}"; - } - - if (persist_containers) - { - os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());" - << endl; - - instance t (container_calls::persist_call); - t->traverse (c); - } - - // Reset sections: loaded, unchanged. - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip special sections. - // - if (i->special == user_section::special_version) - continue; - - // Skip overridden sections; they have been reset by the base. - // - if (i->base != 0 && poly_derived) - continue; - - data_member& m (*i->member); - - // If the section is soft- added or deleted, check the version. - // - unsigned long long av (added (m)); - unsigned long long dv (deleted (m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" << endl; - } - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ("obj") << ".reset (true, false);" - << endl; - } - - // Call callback (post_persist). - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" << endl; - - os << "callback (db," << endl - << (auto_id ? "static_cast (obj)," : "obj,") << endl - << "callback_event::post_persist);"; - } - - os << "}"; - - // persist() bulk - // - if (c.count ("bulk-persist")) - { - os << "void " << traits << "::" << endl - << "persist (database& db," << endl - << (auto_id ? "" : "const ") << "object_type** objs," << endl - << "std::size_t n," << endl - << "multiple_exceptions& mex)" - << "{" - << "using namespace " << db << ";" - << endl; - - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned || - uss.count (user_sections::count_new | - user_sections::count_all | - user_sections::count_versioned_only) != 0) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << endl; - - os << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "const object_type& obj (*objs[i]);" - << "callback (db, obj, callback_event::pre_persist);" - //@@ assumption: generate_grow is false or it only affects select (like - // in pgsql) so all we have to do is to increment image - // version if it grew. - //@@ assumption: insert_send_auto_id is false - << "image_type& im (sts.image (i));"; - - if (generate_grow) - os << "if ("; - - os << "init (im, obj, statement_insert" << (versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << " && i == 0)" << endl - << "im.version++"; - - os << ";" - << "}"; - - //@@ assumption: generate_grow: as above - os << "binding& imb (sts.insert_image_binding ());" - << "if (imb.version == 0)" - << "{" - << "bind (imb.bind, sts.image (), statement_insert" << - (versioned ? ", svm" : "") << ");" - << "imb.version++;" - << "}"; - - // Bind id image since that's where the returned id and/or version will - // be extracted. - // - bool bv (opt != 0 && optimistic_insert_bind_version (*opt)); - if (bv || auto_id) - { - os << "binding& idb (sts.id_image_binding ());" - //@@ assumption: generate_grow: as above - << "if (idb.version == 0)" - << "{" - << "bind (idb.bind, sts.id_image ());" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - } - - os << "insert_statement& st (sts.persist_statement ());" - << "n = st.execute (n, mex);" // Actual number of rows attempted. - << endl; - - os << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "bool r (st.result (i));" // Sets current in mex. - << endl - << "if (mex[i] != 0)" << endl // Pending exception for this position. - << "continue;" - << endl - << "if (!r)" - << "{" - << "mex.insert (i, object_already_persistent ());" - << "continue;" - << "}" - << "if (mex.fatal ())" << endl // Don't do any extra work. - << "continue;" - << endl - << (auto_id ? "" : "const ") << "object_type& obj (*objs[i]);" - << endl; - - // Extract auto id. - // - if (auto_id) // idb == idf, since auto - { - set_member (*idf, "obj", "id (sts.id_image (i))", "db", "id_type"); - os << endl; - } - - // Set the optimistic concurrency version. - // - if (opt != 0) - { - // If we don't have auto id, then obj is a const reference. - // - set_member (*opt, - (auto_id ? "obj" : "const_cast (obj)"), - optimistic_version_init (*opt, true), - "", // No database. - "version_type"); - os << endl; - } - - // Reset sections: loaded, unchanged. - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip special sections. - // - if (i->special == user_section::special_version) - continue; - - data_member& m (*i->member); - - // If the section is soft- added or deleted, check the version. - // - unsigned long long av (added (m)); - unsigned long long dv (deleted (m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" << endl; - } - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ("obj") << ".reset (true, false);" - << endl; - } - - os << "callback (db," << endl - << (auto_id ? "static_cast (obj)," : "obj,") << endl - << "callback_event::post_persist);" - << "}" // for - << "}"; // persist () - } - - // update () - // - if (id != 0 && (!readonly || poly)) - { - size_t update_containers ( - has_a (c, test_readwrite_container, &main_section)); - - bool update_versioned_containers ( - update_containers > - has_a (c, - test_readwrite_container | - exclude_deleted | exclude_added | exclude_versioned, - &main_section)); - - // See if we have any sections that we might have to update. - // - bool sections (false); - bool versioned_sections (false); - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // This test will automatically skip the special version update section. - // - if (i->update_empty () || i->update == user_section::update_manual) - continue; - - sections = true; - - if (added (*i->member) || deleted (*i->member)) - versioned_sections = true; - - // For change-updated sections, also check if we have any - // versioned smart containers. - // - if (i->update != user_section::update_change) - continue; - - if (has_a (c, test_smart_container, &*i) != - has_a (c, test_smart_container | exclude_deleted | exclude_added, &*i)) - versioned_sections = true; - } - - os << "void " << traits << "::" << endl - << "update (database& db, const object_type& obj"; - - if (poly) - os << ", bool top, bool dyn"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (top);"; - - os << endl - << "using namespace " << db << ";" - << "using " << db << "::update_statement;" - << endl; - - if (poly) - os << "if (dyn)" << endl - << "{" - << "const std::type_info& t (typeid (obj));" - << endl - << "if (t != info.type)" - << "{" - << "const info_type& pi (root_traits::map->find (t));" - << "pi.dispatch (info_type::call_update, db, &obj, 0);" - << "return;" - << "}" - << "}"; - - // If we are database-poly-abstract but not C++-abstract, then make - // sure we are not trying to update an instance of an abstract class. - // - if (abst && !c.abstract ()) - os << "if (top)" << endl - << "throw abstract_class ();" - << endl; - - // If we are readonly, then there is nothing else to do. - // - if (!readonly) - { - // Call callback (pre_update). - // - if (!abst) // If we are poly-abstract then top will always be false. - { - if (poly) - os << "if (top)" << endl; - - os << "callback (db, obj, callback_event::pre_update);" - << endl; - } - - bool sts (false); - - if ((versioned && update_columns) || - update_versioned_containers || - versioned_sections) - { - sts = true; - os << db << "::transaction& tr (" << db << - "::transaction::current ());" - << db << "::connection& conn (tr.connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl; - - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));" - << endl; - } - - // If we have change-updated sections that contain change-tracking - // containers, then mark such sections as changed if any of the - // containers were changed. Do this before calling the base so that - // we account for the whole hierarchy before we actually start - // updating any sections (important for optimistic concurrency - // version). - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - user_section& s (*i); - - if (s.update != user_section::update_change) - continue; - - if (!has_a (c, test_smart_container, &s)) - continue; - - data_member& m (*s.member); - - os << "// " << m.name () << endl - << "//" << endl; - - // If the section is soft- added or deleted, check the version. - // - unsigned long long av (added (m)); - unsigned long long dv (deleted (m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")"; - } - - os << "{"; - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // VC++ cannot grok the constructor syntax. - // - os << "const odb::section& s = " << ma.translate ("obj") << ";" - << endl; - - os << "if ("; - - // Unless we are always loaded, test for being loaded. - // - if (s.load != user_section::load_eager) - os << "s.loaded () && "; - - // And for not already being changed. - // - os << "!s.changed ())" - << "{"; - - instance t (container_calls::section_call, &s); - t->traverse (c); - - os << "}" // if - << "}"; - } - - if (poly_derived) - { - bool readonly_base (context::readonly (*poly_base)); - - if (!sts && (readonly_base || - update_columns || - update_containers || - sections)) - { - os << db << "::transaction& tr (" << db << - "::transaction::current ());" - << db << "::connection& conn (tr.connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl; - } - - // Unless our base is readonly, call it first. - // - if (!readonly_base) - { - os << "base_traits::update (db, obj, false, false);" - << endl; - } - else - { - // Otherwise, we have to initialize the id image ourselves. If - // we don't have any columns, containers or sections to update, - // then we only have to do it if this is not a top-level call. - // If we are abstract, then top is always false. - // - if (!update_columns && !update_containers && !sections && !abst) - os << "if (!top)"; - - os << "{" - << "id_image_type& i (sts.id_image ());" - << "init (i, id (obj));" - << endl; - - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;" - // Optimistic poly base cannot be readonly. - << "}" - << "}"; - } - - if (update_columns) - { - // Initialize the object image. - // - os << "image_type& im (sts.image ());"; - - if (generate_grow) - os << "if ("; - - os << "init (im, obj, statement_update" << - (versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "im.version++"; - - os << ";" - << endl; - - os << "const binding& idb (sts.id_image_binding ());" - << "binding& imb (sts.update_image_binding ());" - << "if (idb.version != sts.update_id_binding_version () ||" << endl - << "im.version != sts.update_image_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, idb.bind, idb.count, im, statement_update" << - (versioned ? ", svm" : "") << ");" - << "sts.update_id_binding_version (idb.version);" - << "sts.update_image_version (im.version);" - << "imb.version++;" - << "}"; - - os << "update_statement& st (sts.update_statement ());" - << "if ("; - - if (versioned) - os << "!st.empty () && "; - - os << "st.execute () == 0)" << endl - << "throw object_not_persistent ();" - << endl; - } - - // Otherwise, nothing else to do here if we don't have any columns - // to update. - } - else if (update_columns) - { - if (!sts) - os << db << "::transaction& tr (" << db << - "::transaction::current ());" - << db << "::connection& conn (tr.connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl; - - // Initialize id image. - // - if (opt != 0) - os << "const version_type& v (version (obj));"; - - os << "id_image_type& idi (sts.id_image ());" - << "init (idi, id (obj)" << (opt != 0 ? ", &v" : "") << ");" - << endl; - - // Initialize object image. - // - os << "image_type& im (sts.image ());"; - - if (generate_grow) - os << "if ("; - - os << "init (im, obj, statement_update" << - (versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "im.version++"; - - os << ";" - << endl; - - // The update binding is bound to two images (object and id) - // so we have to track both versions. - // - os << "bool u (false);" // Avoid incrementing version twice. - << "binding& imb (sts.update_image_binding ());" - << "if (im.version != sts.update_image_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, im, statement_update" << - (versioned ? ", svm" : "") << ");" - << "sts.update_image_version (im.version);" - << "imb.version++;" - << "u = true;" - << "}"; - - // To update the id part of the update binding we have to do - // it indirectly via the id binding, which just points to the - // suffix of the update bind array (see object_statements). - // - os << "binding& idb (sts.id_image_binding ());" - << "if (idi.version != sts.update_id_image_version () ||" << endl - << "idb.version == 0)" - << "{" - // If the id binding is up-to-date, then that means update - // binding is too and we just need to update the versions. - // - << "if (idi.version != sts.id_image_version () ||" << endl - << "idb.version == 0)" - << "{" - << "bind (idb.bind, idi);" - // Update the id binding versions since we may use them later - // to update containers. - // - << "sts.id_image_version (idi.version);" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}" - << "sts.update_id_image_version (idi.version);" - << endl - << "if (!u)" << endl - << "imb.version++;" - << "}"; - - os << "update_statement& st (sts.update_statement ());" - << "if ("; - - if (versioned) - os << "!st.empty () && "; - - os << "st.execute () == 0)" << endl; - - if (opt == 0) - os << "throw object_not_persistent ();"; - else - os << "throw object_changed ();"; - - os << endl; - } - else if (poly || update_containers || sections) - { - // We don't have any columns to update but we may still need - // to initialize the id image if we are polymorphic or have - // any containers or sections. - // - if (!sts) - os << db << "::transaction& tr (" << db << - "::transaction::current ());" - << db << "::connection& conn (tr.connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl; - - // The same rationale as a couple of screens up. - // - if (poly && !update_containers && !sections && !abst) - os << "if (!top)"; - - os << "{" - << "id_image_type& i (sts.id_image ());" - << "init (i, id (obj));" - << endl; - - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;" - // Cannot be optimistic. - << "}" - << "}"; - } - - if (update_containers || sections) - os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());" - << endl; - - if (update_containers) - { - instance t (container_calls::update_call, - &main_section); - t->traverse (c); - } - - // Update the optimistic concurrency version in the object member. - // Do it before updating sections since they will update it as well. - // The same code as in section_traits. - // - if (opt != 0 && !poly_derived) - { - // Object is passed as const reference so we need to cast away - // constness. - // - const char* obj ("const_cast (obj)"); - string inc (optimistic_version_increment (*opt)); - - if (inc == "1") - inc_member (*opt, obj, "obj", "version_type"); - else - set_member (*opt, obj, inc, "", "version_type"); - - os << endl; - } - - // Update sections that are loaded and need updating. - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - if (i->update_empty () || i->update == user_section::update_manual) - continue; - - // Here is the deal: for polymorphic section overrides, we could - // have used the same approach as in load_() where the class that - // defines the section data member initiates the section update. - // However, if we used this approach, then we would get what can - // be called "interleaved" update statements. That is, a section - // update would update the section data in "derived" tables before - // updating the main section in these derived tables. While this - // does not feel right, it can also cause more real problems if, - // for example, there are constraints or some such. Generally, - // we always want to update the main section data first for each - // table in the hierarchy. - // - // So what we are going to do instead is call section traits - // update at each override point (and indicate to it not to - // call base). One tricky aspect is who is going to reset the - // changed state. We have to do it at the top since otherwise - // overrides won't know the section has changed. Finding out - // whether we are the final override (in section terms, not - // object terms) is tricky. - // - data_member& m (*i->member); - - // If the section is soft- added or deleted, check the version. - // - unsigned long long av (added (m)); - unsigned long long dv (deleted (m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" - << "{"; - } - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << "if ("; - - // Unless we are always loaded, test for being loaded. - // - string sep; - if (i->load != user_section::load_eager) - { - os << ma.translate ("obj") << ".loaded ()"; - sep = " && "; - } - - // If change-updated section, check that it has changed. - // - if (i->update == user_section::update_change) - os << sep << ma.translate ("obj") << ".changed ()"; - - os << ")" - << "{"; - - // Re-initialize the id+ver image with new version which may - // have changed. Here we take a bit of a shortcut and not - // re-bind the image since we know only version may have - // changed and that is always an integer (cannot grow). - // - if (opt != 0) - { - os << "const version_type& v (version (obj));" - << "init (sts.id_image (), id (obj), &v);" - << endl; - } - - os << public_name (m) << "_traits::update (esc, obj"; - - if (poly_derived && i->base != 0) - { - // Normally we don't want to call base (base object's update() - // would have called it; see comment above). There is one - // exception, however, and that is a readonly base section - // in optimistic class. In this case, base object's update() - // won't call it (it is readonly) but it needs to be called - // in order to increment the version. - // - bool base (false); - for (user_section* b (i->base); !base && b != 0; b = b->base) - { - if (b->total != b->inverse + b->readonly || - b->readwrite_containers) - break; // We have a readwrite base. - else if (b->optimistic ()) - base = true; // We have a readonly optimistic root. - } - - os << ", " << base; - } - - os << ");"; - - // Clear the change flag and arm the transaction rollback callback. - // - if (i->update == user_section::update_change) - { - // If polymorphic, do it only if we are the final override. - // - if (poly) - os << "if (root_traits::map->find (typeid (obj))." << - "final_section_update (info, " << i->index << "UL))" << endl; - - os << ma.translate ("obj") << ".reset (true, false, &tr);"; - } - - os << "}"; - - if (av != 0 || dv != 0) - os << "}"; - } - - // Call callback (post_update). - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" - << "{"; - - os << "callback (db, obj, callback_event::post_update);" - << "pointer_cache_traits::update (db, obj);"; - - if (poly) - os << "}"; - } - } // readonly - - os << "}"; - } - - // update () bulk - // - if (id != 0 && !readonly && c.count ("bulk-update")) - { - os << "void " << traits << "::" << endl - << "update (database& db," << endl - << "const object_type** objs," << endl - << "std::size_t n," << endl - << "multiple_exceptions& mex)" - << "{" - << "using namespace " << db << ";" - << "using " << db << "::update_statement;" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "const object_type& obj (*objs[i]);" - << "callback (db, obj, callback_event::pre_update);"; - - if (opt != 0) - os << "const version_type& v (version (obj));"; - - os << "init (sts.id_image (i), id (obj)" << (opt != 0 ? ", &v" : "") << ");"; - - //@@ assumption: generate_grow is false or it only affects select (like - // in pgsql) so all we have to do is to increment image - // version if it grew. - - os << "image_type& im (sts.image (i));"; - - if (generate_grow) - os << "if ("; - - os << "init (im, obj, statement_update" << (versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << " && i == 0)" << endl - << "im.version++"; - - os << ";" - << "}"; - - // Update bindings. - // - os << "binding& idb (sts.id_image_binding ());" - << "binding& imb (sts.update_image_binding ());" - << endl; - - //@@ assumption: generate_grow: as above - // - os << "bool u (false);" // Avoid incrementing version twice. - << "if (imb.version == 0)" - << "{" - << "bind (imb.bind, sts.image (), statement_update" << - (versioned ? ", svm" : "") << ");" - << "imb.version++;" - << "u = true;" - << "}"; - - //@@ assumption: generate_grow: as above - // - os << "if (idb.version == 0)" - << "{" - << "bind (idb.bind, sts.id_image ());" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << endl - << "if (!u)" << endl - << "imb.version++;" - << "}"; - - // We don't need the versioned check here since the statement cannot - // be empty; otherwise it would have been an empty object which is - // illegal. - // - os << "update_statement& st (sts.update_statement ());" - << "n = st.execute (n, mex);"; // Actual number of rows attempted. - - os << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "unsigned long long r (st.result (i));" // Also sets current in mex. - << endl - << "if (mex[i] != 0)" << endl // Pending exception from result(). - << "continue;" - << endl - << "if (r != 1)" - << "{" - << "mex.insert (i," << endl - //@@ assumption: result_unknown - << "(r == update_statement::result_unknown)," << endl - << (opt == 0 ? "object_not_persistent" : "object_changed") << " ());" - << "continue;" - << "}" - << "if (mex.fatal ())" << endl // Don't do any extra work. - << "continue;" - << endl - << "const object_type& obj (*objs[i]);"; - - // Update the optimistic concurrency version in the object member. - // - if (opt != 0) - { - // Object is passed as const reference so we need to cast away - // constness. - // - const char* obj ("const_cast (obj)"); - string inc (optimistic_version_increment (*opt)); - - if (inc == "1") - inc_member (*opt, obj, "obj", "version_type"); - else - set_member (*opt, obj, inc, "", "version_type"); - - os << endl; - } - - os << "callback (db, obj, callback_event::post_update);" - << "pointer_cache_traits::update (db, obj);" - << "}" // for - << "}"; // update() - } - - // erase (id) - // - size_t erase_containers (has_a (c, test_straight_container)); - bool erase_versioned_containers ( - erase_containers > - has_a (c, test_straight_container | exclude_deleted | exclude_added)); - - if (id != 0) - { - os << "void " << traits << "::" << endl - << "erase (database& db, const id_type& id"; - - if (poly) - os << ", bool top, bool dyn"; - - os << ")" - << "{" - << "using namespace " << db << ";"; - - if (poly) - os << endl - << "ODB_POTENTIALLY_UNUSED (top);"; - - os << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl; - - // Get the discriminator and determine the dynamic type of - // this object. - // - if (poly) - { - os << "if (dyn)" << endl - << "{" - << "discriminator_type d;" - << "root_traits::discriminator_ (sts.root_statements (), id, &d);"; - - if (!abst) - os << endl - << "if (d != info.discriminator)" - << "{"; - - os << "const info_type& pi (root_traits::map->find (d));" - << endl - // Check that the dynamic type is derived from the static type. - // - << "if (!pi.derived (info))" << endl - << "throw object_not_persistent ();" - << endl - << "pi.dispatch (info_type::call_erase, db, 0, &id);" - << "return;"; - - if (!abst) - os << "}"; - - os << "}"; - } - - // Initialize id image. - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" - << "{"; - - os << "id_image_type& i (sts.id_image ());" - << "init (i, id);" - << endl; - - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - - if (poly) - os << "}"; - } - - // Erase containers first so that there are no reference - // violations (we don't want to rely on ON DELETE CASCADE - // here since in case of a custom schema, it might not be - // there). - // - if (erase_containers) - { - os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());"; - - if (erase_versioned_containers) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << endl; - - instance t (container_calls::erase_id_call); - t->traverse (c); - } - - os << "if (sts.erase_statement ().execute () != 1)" << endl - << "throw object_not_persistent ();" - << endl; - - if (poly_derived) - { - // Call our base last (we erase polymorphic objects from base - // to derived in order not to trigger cascading deletes). - // - os << "base_traits::erase (db, id, false, false);" - << endl; - } - - // Remove from the object cache. - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" << endl; - - os << "pointer_cache_traits::erase (db, id);"; - } - - os << "}"; - } - - // erase (id) bulk - // - if (id != 0 && c.count ("bulk-erase")) - { - os << "std::size_t " << traits << "::" << endl - << "erase (database& db," << endl - << "const id_type** ids," << endl - << "std::size_t n," << endl - << "multiple_exceptions& mex)" - << "{" - << "using namespace " << db << ";" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl - << "for (std::size_t i (0); i != n; ++i)" << endl - << "init (sts.id_image (i), *ids[i]);" - << endl - << "binding& idb (sts.id_image_binding ());" - //@@ assumption: generate_grow is false or it only affects select (like - // in pgsql). - << "if (idb.version == 0)" - << "{" - << "bind (idb.bind, sts.id_image ());" - << "idb.version++;" - << (opt != 0 ? "sts.optimistic_id_image_binding ().version++;" : "") - << "}" - << "delete_statement& st (sts.erase_statement ());" - << "n = st.execute (n, mex);" // Set to actual number of rows attempted. - << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "unsigned long long r (st.result (i));" // Sets current in mex. - << endl - << "if (mex[i] != 0)" << endl // Pending exception from result(). - << "continue;" - << endl - << "if (r != 1)" - << "{" - << "mex.insert (i," << endl - //@@ assumption: result_unknown - << "(r == delete_statement::result_unknown)," << endl - << "object_not_persistent ());" - << "continue;" - << "}" - << "if (mex.fatal ())" << endl // Don't do any extra work. - << "continue;" - << "pointer_cache_traits::erase (db, *ids[i]);" - << "}" // for - << "return n;" - << "}"; // erase() - } - - // erase (object) - // - bool erase_smart_containers (has_a (c, test_smart_container)); - - if (id != 0 && (poly || opt != 0 || erase_smart_containers)) - { - os << "void " << traits << "::" << endl - << "erase (database& db, const object_type& obj"; - - if (poly) - os << ", bool top, bool dyn"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (top);"; - - os << endl; - - if (poly) - os << "if (dyn)" << endl - << "{" - << "const std::type_info& t (typeid (obj));" - << endl - << "if (t != info.type)" - << "{" - << "const info_type& pi (root_traits::map->find (t));" - << "pi.dispatch (info_type::call_erase, db, &obj, 0);" - << "return;" - << "}" - << "}"; - - // If we are database-poly-abstract but not C++-abstract, then make - // sure we are not trying to erase an instance of an abstract class. - // - if (abst && !c.abstract ()) - os << "if (top)" << endl - << "throw abstract_class ();" - << endl; - - if (opt != 0 || erase_smart_containers) - { - string rsts (poly_derived ? "rsts" : "sts"); - - os << "using namespace " << db << ";" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (poly_derived) - os << endl - << "root_statements_type& rsts (sts.root_statements ());" - << "ODB_POTENTIALLY_UNUSED (rsts);"; - - os << endl; - - // Call callback (pre_erase). - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" << endl; - - os << "callback (db, obj, callback_event::pre_erase);" - << endl; - } - - if (!abst || erase_containers) - { - os << "const id_type& id (object_traits_impl::id (obj));" - << endl; - } - - // Smart containers case. - // - if (opt == 0) - { - // Initialize id image. - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" - << "{"; - - os << "id_image_type& i (" << rsts << ".id_image ());" - << "init (i, id);" - << endl; - - os << "binding& idb (" << rsts << ".id_image_binding ());" - << "if (i.version != " << rsts << ".id_image_version () || " << - "idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << rsts << ".id_image_version (i.version);" - << "idb.version++;" - // Cannot be optimistic. - << "}"; - - if (poly) - os << "}"; - } - - // Erase containers first so that there are no reference - // violations (we don't want to rely on ON DELETE CASCADE - // here since in case of a custom schema, it might not be - // there). - // - - if (erase_containers) - { - os << "extra_statement_cache_type& esc (" << - "sts.extra_statement_cache ());"; - - if (erase_versioned_containers) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << endl; - - instance t (container_calls::erase_obj_call); - t->traverse (c); - } - - os << "if (sts.erase_statement ().execute () != 1)" << endl - << "throw object_not_persistent ();" - << endl; - } - // Optimistic case. - // - else - { - // Initialize id + managed column image. - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" - << "{"; - - os << "const version_type& v (version (obj));" - << "id_image_type& i (" << rsts << ".id_image ());" - << "init (i, id, &v);" - << endl; - - os << "binding& idb (" << rsts << ".id_image_binding ());" - << "if (i.version != " << rsts << ".id_image_version () ||" << endl - << "idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << rsts << ".id_image_version (i.version);" - << "idb.version++;" - << rsts << ".optimistic_id_image_binding ().version++;" - << "}"; - - if (poly) - os << "}"; // if (top) - } - - // If this is a derived type in a polymorphic hierarchy, then we - // need to check the version (stored in root) before we go ahead - // and start deleting things. Also use the same code for root with - // containers since it is more efficient than the find_() method - // below. - // - bool svm (false); - if (poly_derived || (poly && erase_containers)) - { - // Only do the check in the top-level call. - // - if (!abst) // If we are poly-abstract, then top will always be false. - { - os << "if (top)" - << "{" - << "version_type v;" - << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);" - << endl; - - os << "if (v != version (obj))" << endl - << "throw object_changed ();" - << "}"; - } - } - else if (erase_containers) - { - // Things get complicated here: we don't want to trash the - // containers and then find out that the versions don't match - // and we therefore cannot delete the object. After all, there - // is no guarantee that the user will abort the transaction. - // In fact, a perfectly reasonable scenario is to reload the - // object, re-check the condition, decide not to delete the - // object, and then commit the transaction. - // - // There doesn't seem to be anything better than first making - // sure we can delete the object, then deleting the container - // data, and then deleting the object. To check that we can - // delete the object we are going to use find_() and then - // compare the versions. A special-purpose SELECT query would - // have been more efficient but it would complicated and bloat - // things significantly. - // - - if (versioned) - { - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));" - << endl; - svm = true; - } - - os << "if (!find_ (sts, &id" << - (versioned ? ", svm" : "") << "))" << endl - << "throw object_changed ();" - << endl; - - if (delay_freeing_statement_result) - os << "sts.find_statement ().free_result ();" - << endl; - - os << "if (version (sts.image ()) != version (obj))" << endl - << "throw object_changed ();" - << endl; - } - - // Erase containers first so that there are no reference - // violations (we don't want to rely on ON DELETE CASCADE - // here since in case of a custom schema, it might not be - // there). - // - if (erase_containers) - { - os << "extra_statement_cache_type& esc (" << - "sts.extra_statement_cache ());"; - - if (erase_versioned_containers && !svm) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << endl; - - instance t (container_calls::erase_obj_call); - t->traverse (c); - } - - const char* st ( - poly_derived ? "erase_statement" : "optimistic_erase_statement"); - - os << "if (sts." << st << " ().execute () != 1)" << endl - << "throw object_changed ();" - << endl; - } - - if (poly_derived) - { - // Call our base last (we erase polymorphic objects from base - // to derived in order not to trigger cascading deletes). - // - os << "base_traits::erase (db, obj, false, false);" - << endl; - } - - if (!abst) // If we are poly-abstract, then top will always be false. - { - if (poly) - os << "if (top)" - << "{"; - - // Note that we don't reset sections since the object is now - // transient and the state of a section in a transient object - // is undefined. - - // Remove from the object cache. - // - os << "pointer_cache_traits::erase (db, id);"; - - // Call callback (post_erase). - // - os << "callback (db, obj, callback_event::post_erase);"; - - if (poly) - os << "}"; - } - } - else - { - os << "callback (db, obj, callback_event::pre_erase);" - << "erase (db, id (obj), true, false);" - << "callback (db, obj, callback_event::post_erase);"; - } - - os << "}"; - } - - // erase (object) bulk - // - if (id != 0 && c.count ("bulk-erase")) - { - os << "void " << traits << "::" << endl - << "erase (database& db," << endl - << "const object_type** objs," << endl - << "std::size_t n," << endl - << "multiple_exceptions& mex)" - << "{"; - - // In non-optimistic case delegate to erase(id). - // - if (opt == 0) - { - os << "id_type a[batch];" - << "const id_type* p[batch];" - << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "const object_type& obj (*objs[i]);" - << "callback (db, obj, callback_event::pre_erase);" - << "a[i] = id (obj);" - << "p[i] = a + i;" - << "}" - << "n = erase (db, p, n, mex);" - << endl - << "if (mex.fatal ())" << endl // Don't do any extra work. - << "return;" - << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "if (mex[i] == 0)" << endl // No pending exception. - << "callback (db, *objs[i], callback_event::post_erase);" - << "}"; // for - } - else - { - os << "using namespace " << db << ";" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "const object_type& obj (*objs[i]);" - << "callback (db, obj, callback_event::pre_erase);" - << "const version_type& v (version (obj));" - << "init (sts.id_image (i), id (obj), &v);" - << "}"; - - os << "binding& idb (sts.id_image_binding ());" - //@@ assumption: generate_grow is false or it only affects select - // (like in pgsql). - << "if (idb.version == 0)" - << "{" - << "bind (idb.bind, sts.id_image ());" - << "idb.version++;" - << "sts.optimistic_id_image_binding ().version++;" - << "}" - << "delete_statement& st (sts.optimistic_erase_statement ());" - << "n = st.execute (n, mex);" // Set to actual number of attempted. - << endl - << "for (std::size_t i (0); i != n; ++i)" - << "{" - << "unsigned long long r (st.result (i));" // Sets current in mex. - << endl - << "if (mex[i] != 0)" << endl // Pending exception from result(). - << "continue;" - << endl - << "if (r != 1)" - << "{" - << "mex.insert (i," << endl - //@@ assumption: result_unknown - << "(r == delete_statement::result_unknown)," << endl - << "object_changed ());" - << "continue;" - << "}" - << "if (mex.fatal ())" << endl // Don't do any extra work. - << "continue;" - << endl - << "const object_type& obj (*objs[i]);" - << "pointer_cache_traits::erase (db, id (obj));" - << "callback (db, obj, callback_event::post_erase);" - << "}"; // for - } - - os << "}"; // erase() - } - - // find (id) - // - if (id != 0 && c.default_ctor ()) - { - string rsts (poly_derived ? "rsts" : "sts"); - - os << traits << "::pointer_type" << endl - << traits << "::" << endl - << "find (database& db, const id_type& id)" - << "{" - << "using namespace " << db << ";" - << endl; - - // First check the session. - // - os << "{"; - - if (poly_derived) - os << "root_traits::pointer_type rp (pointer_cache_traits::find (" << - "db, id));" - << endl - << "if (!root_traits::pointer_traits::null_ptr (rp))" << endl - << "return" << endl - << " root_traits::pointer_traits::dynamic_pointer_cast<" << - "object_type> (rp);"; - else - os << "pointer_type p (pointer_cache_traits::find (db, id));" - << endl - << "if (!pointer_traits::null_ptr (p))" << endl - << "return p;"; - - os << "}"; - - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - if (poly_derived) - os << "root_statements_type& rsts (sts.root_statements ());"; - - os << endl - << "statements_type::auto_lock l (" << rsts << ");"; - - if (delay_freeing_statement_result) - os << "auto_result ar;"; - - if (poly) - os << "root_traits::discriminator_type d;"; - - os << endl - << "if (l.locked ())" - << "{" - << "if (!find_ (sts, &id" << (versioned ? ", svm" : "") << "))" << endl - << "return pointer_type ();"; - - if (delay_freeing_statement_result) - os << endl - << "ar.set (sts.find_statement (" << (poly_derived ? "depth" : "") << - "));"; - - if (poly) - os << "d = root_traits::discriminator (" << rsts << ".image ());"; - - os << "}"; - - if (poly) - { - // If statements are locked, then get the discriminator by - // executing a special SELECT statement. We need it to be - // able to create an object of the correct dynamic type - // which will be loaded later. - // - os << "else" << endl - << "root_traits::discriminator_ (" << rsts << ", id, &d);" - << endl; - - if (abst) - os << "const info_type& pi (root_traits::map->find (d));" - << endl; - else - os << "const info_type& pi (" << endl - << "d == info.discriminator ? info : root_traits::map->find (d));" - << endl; - } - - // Create the object. - // - if (poly_derived) - { - os << "root_traits::pointer_type rp (pi.create ());" - << "pointer_type p (" << endl - << "root_traits::pointer_traits::static_pointer_cast " << - "(rp));" - << "pointer_traits::guard pg (p);" - << endl; - - // Insert it as a root pointer (for non-unique pointers, rp should - // still be valid and for unique pointers this is a no-op). - // - os << "pointer_cache_traits::insert_guard ig (" << endl - << "pointer_cache_traits::insert (db, id, rp));" - << endl; - } - else - { - if (poly) - os << "pointer_type p (pi.create ());"; - else - os << "pointer_type p (" << endl - << "access::object_factory::create ());"; - - os << "pointer_traits::guard pg (p);" - << endl; - - os << "pointer_cache_traits::insert_guard ig (" << endl - << "pointer_cache_traits::insert (db, id, p));" - << endl; - } - - os << "object_type& obj (pointer_traits::get_ref (p));" - << endl - << "if (l.locked ())" - << "{" - << "select_statement& st (sts.find_statement (" << - (poly_derived ? "depth" : "") << "));" - << "ODB_POTENTIALLY_UNUSED (st);" - << endl; - - if (poly) - os << "callback_event ce (callback_event::pre_load);" - << "pi.dispatch (info_type::call_callback, db, &obj, &ce);"; - else - os << "callback (db, obj, callback_event::pre_load);"; - - os << "init (obj, sts.image (), &db" << (versioned ? ", svm" : "") << ");"; - - init_value_extra (); - - if (delay_freeing_statement_result) - os << "ar.free ();"; - - os << "load_ (sts, obj, false" << (versioned ? ", svm" : "") << ");"; - - if (poly) - // Load the dynamic part of the object unless static and dynamic - // types are the same. - // - os << endl - << "if (&pi != &info)" - << "{" - << "std::size_t d (depth);" - << "pi.dispatch (info_type::call_load, db, &obj, &d);" - << "}"; - - os << rsts << ".load_delayed (" << (versioned ? "&svm" : "0") << ");" - << "l.unlock ();"; - - if (poly) - os << "ce = callback_event::post_load;" - << "pi.dispatch (info_type::call_callback, db, &obj, &ce);"; - else - os << "callback (db, obj, callback_event::post_load);"; - - os << "pointer_cache_traits::load (ig.position ());" - << "}" - << "else" << endl - << rsts << ".delay_load (id, obj, ig.position ()" << - (poly ? ", pi.delayed_loader" : "") << ");" - << endl; - - os << "ig.release ();" - << "pg.release ();" - << "return p;" - << "}"; - } - - // find (id, obj) - // - if (id != 0) - { - string rsts (poly_derived ? "rsts" : "sts"); - - os << "bool " << traits << "::" << endl - << "find (database& db, const id_type& id, object_type& obj"; - - if (poly) - os << ", bool dyn"; - - os << ")" - << "{"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (dyn);" - << endl; - - os << "using namespace " << db << ";" - << endl; - - if (poly) - { - if (!abst) - os << "if (dyn)" << endl - << "{"; - - os << "const std::type_info& t (typeid (obj));"; - - if (!abst) - os << endl - << "if (t != info.type)" - << "{"; - - os << "const info_type& pi (root_traits::map->find (t));" - << "return pi.dispatch (info_type::call_find, db, &obj, &id);"; - - if (!abst) - os << "}" - << "}"; - } - - if (!abst) - { - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - if (poly_derived) - os << "root_statements_type& rsts (sts.root_statements ());"; - - // This can only be top-level call so auto_lock must succeed. - // - os << endl - << "statements_type::auto_lock l (" << rsts << ");" - << "assert (l.locked ()) /* Must be a top-level call. */;" - << endl; - - os << "if (!find_ (sts, &id" << - (versioned ? ", svm" : "") << "))" << endl - << "return false;" - << endl; - - os << "select_statement& st (sts.find_statement (" << - (poly_derived ? "depth" : "") << "));" - << "ODB_POTENTIALLY_UNUSED (st);" - << endl; - - if (delay_freeing_statement_result) - os << "auto_result ar (st);"; - - os << "reference_cache_traits::position_type pos (" << endl - << "reference_cache_traits::insert (db, id, obj));" - << "reference_cache_traits::insert_guard ig (pos);" - << endl - << "callback (db, obj, callback_event::pre_load);" - << "init (obj, sts.image (), &db" << - (versioned ? ", svm" : "") << ");"; - - init_value_extra (); - - if (delay_freeing_statement_result) - os << "ar.free ();"; - - os << "load_ (sts, obj, false" << (versioned ? ", svm" : "") << ");" - << rsts << ".load_delayed (" << (versioned ? "&svm" : "0") << ");" - << "l.unlock ();" - << "callback (db, obj, callback_event::post_load);" - << "reference_cache_traits::load (pos);" - << "ig.release ();" - << "return true;"; - } - - os << "}"; - } - - // reload () - // - if (id != 0) - { - string rsts (poly_derived ? "rsts" : "sts"); - - // This implementation is almost exactly the same as find(id, obj) - // above except that it doesn't interract with the object cache and, - // in case of optimistic concurrency, checks if the object actually - // needs to be reloaded. - // - os << "bool " << traits << "::" << endl - << "reload (database& db, object_type& obj"; - - if (poly) - os << ", bool dyn"; - - os << ")" - << "{"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (dyn);" - << endl; - - os << "using namespace " << db << ";" - << endl; - - if (poly) - { - if (!abst) - os << "if (dyn)" << endl - << "{"; - - os << "const std::type_info& t (typeid (obj));"; - - if (!abst) - os << endl - << "if (t != info.type)" - << "{"; - - os << "const info_type& pi (root_traits::map->find (t));" - << "return pi.dispatch (info_type::call_reload, db, &obj, 0);"; - - if (!abst) - os << "}" - << "}"; - } - - if (!abst) - { - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - if (poly_derived) - os << "root_statements_type& rsts (sts.root_statements ());"; - - // This can only be top-level call so auto_lock must succeed. - // - os << endl - << "statements_type::auto_lock l (" << rsts << ");" - << "assert (l.locked ()) /* Must be a top-level call. */;" - << endl; - - os << "const id_type& id (object_traits_impl::id (obj));" - << "if (!find_ (sts, &id" << - (versioned ? ", svm" : "") << "))" << endl - << "return false;" - << endl; - - os << "select_statement& st (sts.find_statement (" << - (poly_derived ? "depth" : "") << "));" - << "ODB_POTENTIALLY_UNUSED (st);" - << endl; - - if (delay_freeing_statement_result) - os << "auto_result ar (st);" - << endl; - - if (opt != 0) - { - const char* tr (poly_derived ? "root_traits::" : ""); - - os << "if (" << tr << "version (" << rsts << ".image ()) == " << - tr << "version (obj))" << endl - << "return true;" - << endl; - } - - os << "callback (db, obj, callback_event::pre_load);" - << "init (obj, sts.image (), &db" << - (versioned ? ", svm" : "") << ");"; - - init_value_extra (); - - if (delay_freeing_statement_result) - os << "ar.free ();"; - - os << "load_ (sts, obj, true" << (versioned ? ", svm" : "") << ");" - << rsts << ".load_delayed (" << (versioned ? "&svm" : "0") << ");" - << "l.unlock ();" - << "callback (db, obj, callback_event::post_load);" - << "return true;"; - } - - os << "}"; - } - - // load (section) [non-thunk version] - // - if (uss.count (user_sections::count_new | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) != 0) - { - string rsts (poly_derived ? "rsts" : "sts"); - - os << "bool " << traits << "::" << endl - << "load (connection& conn, object_type& obj, section& s" << - (poly ? ", const info_type* pi" : "") << ")" - << "{" - << "using namespace " << db << ";" - << endl; - - if (poly) - { - // Resolve type information if we are doing indirect calls. - // - os << "bool top (pi == 0);" // Top-level call. - << "if (top)" - << "{" - << "const std::type_info& t (typeid (obj));"; - - if (!abst) - os << endl - << "if (t == info.type)" << endl - << "pi = &info;" - << "else" << endl; - - os << "pi = &root_traits::map->find (t);" - << "}"; - } - - // Lock the statements for the object itself. We need to do this since we - // are using the id image and loading of object pointers can overwrite it. - // - os << db << "::connection& c (static_cast<" << db << - "::connection&> (conn));" - << "statements_type& sts (c.statement_cache ()." << - "find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - if (poly_derived) - os << "root_statements_type& rsts (sts.root_statements ());"; - - os << endl - << "statements_type::auto_lock l (" << rsts << ");"; - - // It this is a top-level call, then auto_lock must succeed. - // - if (poly) - os << "if (top)" << endl; - - os << "assert (l.locked ()) /* Must be a top-level call. */;" - << endl; - - os << "bool r (false);" - << endl; - - // If our poly-base has load sections, then call the base version - // first. Besides checking for sections, it will also initialize - // the id image. - // - if (poly_derived && - buss->count (user_sections::count_total | - user_sections::count_load | - user_sections::count_load_empty) != 0) - { - os << "if (base_traits::load (conn, obj, s, pi))" << endl - << "r = true;" - << endl; - } - else - { - // Initialize id image (all this is equivalent to using rsts). - // - os << "id_image_type& i (sts.id_image ());" - << "init (i, id (obj));" - << endl; - - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - } - - // Resolve extra statements if we are doing direct calls. - // - if (!poly) - os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());" - << endl; - - // Dispatch. - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip special sections. - // - if (i->special == user_section::special_version) - continue; - - if (i->load == user_section::load_eager) - continue; - - // Overridden sections are handled by the base. - // - if (poly_derived && i->base != 0) - continue; - - data_member& m (*i->member); - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << "if (!r && &s == &" << ma.translate ("obj") << ")" - << "{"; - - if (!poly) - os << public_name (m) << "_traits::load (esc, obj);"; - else - { - // If this is an empty section, then there may not be any - // overrides. - // - os << "info_type::section_load sl (" << - "pi->find_section_load (" << i->index << "UL));"; - - if (i->load_empty ()) - os << "if (sl != 0)" << endl; - - os << "sl (conn, obj, true);"; - } - - os << "r = true;" - << "}"; - } - - if (poly) - os << "if (top)" - << "{"; - - os << rsts << ".load_delayed (" << (versioned ? "&svm" : "0") << ");" - << "l.unlock ();"; - - if (poly) - os << "}"; - - os << "return r;" - << "}"; - } - - // update (section) [non-thunk version] - // - if (uss.count (user_sections::count_new | - user_sections::count_update | - (poly ? user_sections::count_update_empty : 0)) != 0) - { - os << "bool " << traits << "::" << endl - << "update (connection& conn, const object_type& obj, " << - "const section& s" << (poly ? ", const info_type* pi" : "") << ")" - << "{" - << "using namespace " << db << ";" - << endl; - - if (poly) - { - // Resolve type information if we are doing indirect calls. - // - os << "if (pi == 0)" // Top-level call. - << "{" - << "const std::type_info& t (typeid (obj));"; - - if (!abst) - os << endl - << "if (t == info.type)" << endl - << "pi = &info;" - << "else" << endl; - - os << "pi = &root_traits::map->find (t);" - << "}"; - } - - // If our poly-base has update sections, then call the base version - // first. Besides checking for sections, it will also initialize the - // id image. - // - if (poly_derived && - buss->count (user_sections::count_total | - user_sections::count_update | - user_sections::count_update_empty) != 0) - { - os << "if (base_traits::update (conn, obj, s, pi))" << endl - << "return true;" - << endl; - } - else - { - // Resolve extra statements if we are doing direct calls. - // - os << db << "::connection& c (static_cast<" << db << - "::connection&> (conn));" - << "statements_type& sts (c.statement_cache ()." << - "find_object ());"; - - if (!poly) - os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());"; - - os << endl; - - // Initialize id image. This is not necessarily the root of the - // polymorphic hierarchy. - // - if (opt != 0) - os << "const version_type& v (version (obj));"; - - os << "id_image_type& i (sts.id_image ());"; - - os << "init (i, id (obj)" << (opt != 0 ? ", &v" : "") << ");" - << endl; - - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - } - - // Dispatch. - // - bool e (false); - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip special sections. - // - if (i->special == user_section::special_version) - continue; - - // Overridden sections are handled by the base. - // - if (poly_derived && i->base != 0) - continue; - - // Skip read-only sections. Polymorphic sections are always - // (potentially) read-write. - // - if (!poly && i->update_empty ()) - continue; - - data_member& m (*i->member); - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - if (e) - os << "else "; - else - e = true; - - os << "if (&s == &" << ma.translate ("obj") << ")"; - - if (!poly) - os << public_name (m) << "_traits::update (esc, obj);"; - else - { - // If this is a readonly section, then there may not be any - // overrides. - // - os << "{" - << "info_type::section_update su (" << - "pi->find_section_update (" << i->index << "UL));"; - - if (i->update_empty ()) - { - // For optimistic section, also check that we are not the - // final override, since otherwise we will increment the - // version without updating anything. - // - if (i->optimistic ()) - os << "if (su != 0 && su != info.sections->functions[" << - i->index << "UL].update)" << endl; - else - os << "if (su != 0)" << endl; - } - - os << "su (conn, obj);" - << "}"; - } - } - - os << "else" << endl - << "return false;" - << endl - << "return true;" - << "}"; - } - - // find_ () - // - if (id != 0) - { - os << "bool " << traits << "::" << endl - << "find_ (statements_type& sts," << endl - << "const id_type* id"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - if (poly_derived && !abst) - os << "," << endl - << "std::size_t d"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl; - - // Initialize id image. - // - if (poly_derived && !abst) - os << "if (d == depth)" - << "{"; - - os << "id_image_type& i (sts.id_image ());" - << "init (i, *id);" - << endl; - - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (opt != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - - if (poly_derived && !abst) - os << "}"; - - // Rebind data image. - // - os << "image_type& im (sts.image ());" - << "binding& imb (sts.select_image_binding (" << - (poly_derived ? (abst ? "depth" : "d") : "") << "));" - << 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" << - (versioned ? ", svm" : "") << ");" - << "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" << - (versioned ? ", svm" : "") << ");" - << "sts.select_image_version (im.version);" - << "imb.version++;" - << "}"; - } - - os << "select_statement& st (sts.find_statement (" << - (poly_derived ? (abst ? "depth" : "d") : "") << "));" - << endl; - - // The dynamic loader SELECT statement can be dynamically empty. - // - if (versioned && poly_derived && !abst) - os << "if (st.empty ())" << endl - << "return true;" - << endl; - - os << "st.execute ();" - << "auto_result ar (st);" - << "select_statement::result r (st.fetch ());" - << endl; - - if (grow) - { - os << "if (r == select_statement::truncated)" - << "{" - << "if (grow (im, sts.select_image_truncated ()" << - (versioned ? ", svm" : "") << - (poly_derived ? (abst ? ", depth" : ", d") : "") << "))" << endl - << "im.version++;" - << endl; - - if (poly_derived) - { - os << "if (check_version (sts.select_image_versions (), im))" - << "{" - << "bind (imb.bind, 0, 0, im, statement_select" << - (versioned ? ", svm" : "") << ");" - << "update_version (sts.select_image_versions ()," << endl - << "im," << endl - << "sts.select_image_bindings ());" - << "st.refetch ();" - << "}"; - } - else - { - os << "if (im.version != sts.select_image_version ())" - << "{" - << "bind (imb.bind, im, statement_select" << - (versioned ? ", svm" : "") << ");" - << "sts.select_image_version (im.version);" - << "imb.version++;" - << "st.refetch ();" - << "}"; - } - - os << "}"; - } - - // If we are delaying, only free the result if it is empty. - // - if (delay_freeing_statement_result) - os << "if (r != select_statement::no_data)" - << "{" - << "ar.release ();" - << "return true;" - << "}" - << "else" << endl - << "return false;"; - else - os << "return r != select_statement::no_data;"; - - os << "}"; - } - - // load_() - // - // Load containers, reset/reload sections. - // - size_t load_containers ( - has_a (c, test_container | include_eager_load, &main_section)); - - if (poly_derived || - load_containers || - uss.count (user_sections::count_new | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) != 0) - { - bool load_versioned_containers ( - load_containers > - has_a (c, - test_container | include_eager_load | - exclude_deleted | exclude_added | exclude_versioned, - &main_section)); - - os << "void " << traits << "::" << endl - << "load_ (statements_type& sts," << endl - << "object_type& obj," << endl - << "bool reload"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - if (poly_derived) - os << "," << endl - << "std::size_t d"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (reload);"; - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - os << endl; - - if (poly_derived) - os << "if (--d != 0)" << endl - << "base_traits::load_ (sts.base_statements (), obj, reload" << - (context::versioned (*poly_base) ? ", svm" : "") << - (poly_base != poly_root ? ", d" : "") << ");" - << endl; - - if (load_containers || - (!poly && uss.count (user_sections::count_new | - user_sections::count_load) != 0)) - os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());" - << endl; - - if (!versioned && ( - load_versioned_containers || - uss.count (user_sections::count_new | - user_sections::count_all | - user_sections::count_versioned_only) != 0)) - { - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));" - << endl; - } - - if (load_containers) - { - instance t (container_calls::load_call, &main_section); - t->traverse (c); - } - - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - // Skip special sections. - // - if (i->special == user_section::special_version) - continue; - - // Skip overridden sections; they are handled by the base. - // - if (i->base != 0 && poly_derived) - continue; - - data_member& m (*i->member); - - // If the section is soft- added or deleted, check the version. - // - unsigned long long av (added (m)); - unsigned long long dv (deleted (m)); - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" - << "{"; - } - - // Section access is always by reference. - // - member_access& ma (m.get ("get")); - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - if (i->load == user_section::load_eager) - { - // Mark an eager section as loaded. - // - os << ma.translate ("obj") << ".reset (true, false);" - << endl; - continue; - } - - os << "if (reload)" - << "{" - // Reload sections that have been loaded, clear change state. - // - << "if (" << ma.translate ("obj") << ".loaded ())" - << "{"; - - if (!poly) - os << public_name (m) << "_traits::load (esc, obj);"; - else - { - os << "info_type::section_load sl (" << endl - << "root_traits::map->find (typeid (obj)).find_section_load (" << - i->index << "UL));"; - - if (i->load_empty ()) - os << "if (sl != 0)" << endl; - - os << "sl (sts.connection (), obj, true);"; - } - - os << ma.translate ("obj") << ".reset (true, false);" - << "}" - << "}" - << "else" << endl - // Reset to unloaded, unchanged state. - << ma.translate ("obj") << ".reset ();"; - - if (av != 0 || dv != 0) - os << "}"; - else - os << endl; - } - - os << "}"; - } - - // load_() - // - // Load the dynamic part of the object. We don't need it if we are - // poly-abstract. - // - if (poly_derived && !abst) - { - os << "void " << traits << "::" << endl - << "load_ (database& db, root_type& r, std::size_t d)" - << "{" - << "using namespace " << db << ";" - << endl - << "object_type& obj (static_cast (r));" - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());" - << endl - << "d = depth - d;" // Convert to distance from derived. - << endl; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));" - << endl; - - // Avoid trying to execute an empty SELECT statement. - // - if (empty_depth != 0) - os << "if (d > " << (poly_depth - empty_depth) << "UL)" - << "{"; - - os << "if (!find_ (sts, 0" << (versioned ? ", svm" : "") << ", d))" << endl - << "throw object_not_persistent ();" // Database inconsistency. - << endl; - - os << "select_statement& st (sts.find_statement (d));" - << "ODB_POTENTIALLY_UNUSED (st);" - << endl; - - // The resulting SELECT statement may end up being dynamically empty. - // - if (versioned) - os << "if (!st.empty ())" - << "{"; - - if (delay_freeing_statement_result) - os << "auto_result ar (st);"; - - os << "init (obj, sts.image (), &db" << (versioned ? ", svm" : "") << - ", d);"; - - init_value_extra (); - - if (delay_freeing_statement_result) - os << "ar.free ();"; - - if (versioned) - os << "}"; - - if (empty_depth != 0) - os << "}"; - - os << "load_ (sts, obj, false, " << (versioned ? "svm, " : "") << "d);" - << "}"; - } - - // discriminator_ () - // - if (poly && !poly_derived) - { - os << "void " << traits << "::" << endl - << "discriminator_ (statements_type& sts," << endl - << "const id_type& id," << endl - << "discriminator_type* pd"; - - if (opt != 0) - os << "," << endl - << "version_type* pv"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl; - - // Initialize id image. - // - os << "id_image_type& idi (sts.discriminator_id_image ());" - << "init (idi, id);" - << endl; - - os << "binding& idb (sts.discriminator_id_image_binding ());" - << "if (idi.version != sts.discriminator_id_image_version () ||" << endl - << "idb.version == 0)" - << "{" - << "bind (idb.bind, idi" << (opt != 0 ? ", false" : "") << ");" - << "sts.discriminator_id_image_version (idi.version);" - << "idb.version++;" - << "}"; - - // Rebind data image. - // - os << "discriminator_image_type& i (sts.discriminator_image ());" - << "binding& imb (sts.discriminator_image_binding ());" - << endl - << "if (i.version != sts.discriminator_image_version () ||" << endl - << "imb.version == 0)" - << "{" - // Generate bind code inline. For now discriminator is simple - // value so we don't need statement kind (sk). - // - << bind_vector << " b (imb.bind);" - << "std::size_t n (0);" - << "{"; - bind_discriminator_member_->traverse (*discriminator); - os << "}"; - - if (opt != 0) - { - os << "n++;" // For now discriminator is a simple value. - << "{"; - bind_version_member_->traverse (*opt); - os << "}"; - } - - os << "sts.discriminator_image_version (i.version);" - << "imb.version++;" - << "}"; - - os << "{" - << "select_statement& st (sts.find_discriminator_statement ());" - << "st.execute ();" - << "auto_result ar (st);" - << "select_statement::result r (st.fetch ());" - << endl - << "if (r == select_statement::no_data)" - << "{"; - - if (opt != 0) - os << "if (pv != 0)" << endl - << "throw object_changed ();" - << "else" << endl; - - os << "throw object_not_persistent ();" - << "}"; - - if (generate_grow && - (context::grow (*discriminator) || - (opt != 0 && context::grow (*opt)))) - { - os << "else if (r == select_statement::truncated)" - << "{"; - - // Generate grow code inline. - // - os << "bool grew (false);" - << truncated_vector << " t (sts.discriminator_image_truncated ());" - << endl; - - index_ = 0; - grow_discriminator_member_->traverse (*discriminator); - - if (opt != 0) - grow_version_member_->traverse (*opt); - - os << "if (grew)" << endl - << "i.version++;" - << endl; - - os << "if (i.version != sts.discriminator_image_version ())" - << "{" - // Generate bind code inline. The same code as above. - // - << bind_vector << " b (imb.bind);" - << "std::size_t n (0);" - << "{"; - bind_discriminator_member_->traverse (*discriminator); - os << "}"; - - if (opt != 0) - { - os << "n++;" // For now discriminator is a simple value. - << "{"; - bind_version_member_->traverse (*opt); - os << "}"; - } - - os << "sts.discriminator_image_version (i.version);" - << "imb.version++;" - << "st.refetch ();" - << "}" - << "}"; - } - - // Discriminator cannot be long data (no streaming). - // - os << "}"; - - // Initialize value inline instead of generating a separate - // init() function. For now discriminator is simple value so - // we don't need the database (db). - // - os << "if (pd != 0)" - << "{" - << "discriminator_type& d (*pd);"; - init_named_discriminator_value_member_->traverse (*discriminator); - os << "}"; - - if (opt != 0) - { - os << "if (pv != 0)" - << "{" - << "version_type& v (*pv);"; - init_named_version_value_member_->traverse (*opt); - os << "}"; - } - - os << "}"; - } - - if (options.generate_query ()) - { - 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"; - - string sep (versioned || query_optimize ? "\n" : " "); - - // Unprepared. - // - if (!options.omit_unprepared ()) - { - // query () - // - os << "result< " << traits << "::object_type >" << endl - << traits << "::" << endl - << "query (database& db, const query_base_type& q)" - << "{" - << "using namespace " << db << ";" - << "using odb::details::shared;" - << "using odb::details::shared_ptr;" - << endl; - - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << endl - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << 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" << - (versioned ? ", svm" : "") << ");" - << "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" << - (versioned ? ", svm" : "") << ");" - << "sts.select_image_version (im.version);" - << "imb.version++;" - << "}"; - } - - os << "std::string text (query_statement);" - << "if (!q.empty ())" - << "{" - << "text += " << strlit (sep) << ";" - << "text += q.clause ();" - << "}"; - - os << "q.init_parameters ();" - << "shared_ptr st (" << endl - << "new (shared) select_statement (" << endl; - object_query_statement_ctor_args ( - c, "q", versioned || query_optimize, false); - 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, " << (versioned ? "&svm" : "0") << "));" - << endl - << "return result (r);" - << "}"; - - // query(odb::query_base) - // - if (multi_dynamic) - os << "result< " << traits << "::object_type >" << endl - << traits << "::" << endl - << "query (database& db, const odb::query_base& q)" - << "{" - << "return query (db, query_base_type (q));" - << "}"; - } - - // erase_query - // - os << "unsigned long long " << traits << "::" << endl - << "erase_query (database& db, const query_base_type& q)" - << "{" - << "using namespace " << db << ";" - << endl - << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << endl - << "std::string text (erase_query_statement);" - << "if (!q.empty ())" - << "{" - << "text += ' ';" - << "text += q.clause ();" - << "}" - << "q.init_parameters ();" - << "delete_statement st (" << endl; - object_erase_query_statement_ctor_args (c); - os << ");" - << endl - << "return st.execute ();" - << "}"; - - // erase_query(odb::query_base) - // - if (multi_dynamic) - os << "unsigned long long " << traits << "::" << endl - << "erase_query (database& db, const odb::query_base& q)" - << "{" - << "return erase_query (db, query_base_type (q));" - << "}"; - - // Prepared. Very similar to unprepared but has some annoying variations - // that make it difficult to factor out something common. - // - if (options.generate_prepared ()) - { - // prepare_query - // - 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; - - os << db << "::connection& conn (" << endl - << "static_cast<" << db << "::connection&> (c));" - << endl - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << 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" << - (versioned ? ", svm" : "") << ");" - << "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" << - (versioned ? ", svm" : "") << ");" - << "sts.select_image_version (im.version);" - << "imb.version++;" - << "}"; - } - - os << "std::string text (query_statement);" - << "if (!q.empty ())" - << "{" - << "text += " << strlit (sep) << ";" - << "text += q.clause ();" - << "}"; - - os << "shared_ptr<" << db << "::prepared_query_impl> r (" << endl - << "new (shared) " << db << "::prepared_query_impl (conn));" - << "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", versioned || query_optimize, true); - os << "));" - << endl - << "return r;" - << "}"; - - // prepare_query(odb::query_base) - // - if (multi_dynamic) - os << "odb::details::shared_ptr" << endl - << traits << "::" << endl - << "prepare_query (connection& c, const char* n, " << - "const odb::query_base& q)" - << "{" - << "return prepare_query (c, n, query_base_type (q));" - << "}"; - - // execute_query - // - 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; - - os << db << "::transaction& tr (" << db << "::transaction::current ());" - << endl - << "// The connection used by the current transaction and the" << endl - << "// one used to prepare this statement must be the same." << endl - << "//" << endl - << "assert (q.verify_connection (tr));" - << endl - << "statements_type& sts (" << endl - << "st->connection ().statement_cache ().find_object ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << 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" << - (versioned ? ", svm" : "") << ");" - << "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" << - (versioned ? ", svm" : "") << ");" - << "sts.select_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 << "::" << result_type << " (" << endl - << "pq.query, st, sts, " << (versioned ? "&svm" : "0") << "));" - << "}"; - } - } - - // Generate function table registration for dynamic multi-database - // support. - // - if (multi_dynamic) - { - string fn (flat_name (type)); - string dt ("access::object_traits_impl< " + type + ", id_common >"); - - os << "static const" << endl - << dt << "::" << endl - << "function_table_type function_table_" << fn << "_ =" - << "{"; - - // persist () - // - os << "&" << traits << "::persist"; - - if (id != 0) - { - // find (id) - // - if (c.default_ctor ()) - os << "," << endl - << "&" << traits << "::find"; - - // find (id, obj) - // - os << "," << endl - << "&" << traits << "::find"; - - // reload () - // - os << "," << endl - << "&" << traits << "::reload"; - - // update () - // - if (!readonly || poly) - os << "," << endl - << "&" << traits << "::update"; - - // erase () - // - os << "," << endl - << "&" << traits << "::erase"; - - os << "," << endl - << "&" << traits << "::erase"; - - // Sections. - // - if (uss.count (user_sections::count_total | - user_sections::count_load | - (poly ? user_sections::count_load_empty : 0)) != 0) - os << "," << endl - << "&" << traits << "::load"; - - if (uss.count (user_sections::count_total | - user_sections::count_update | - (poly ? user_sections::count_update_empty : 0)) != 0) - os << "," << endl - << "&" << traits << "::update"; - } - - if (options.generate_query ()) - { - if (!options.omit_unprepared ()) - os << "," << endl - << "&" << traits << "::query"; - - os << "," << endl - << "&" << traits << "::erase_query"; - - if (options.generate_prepared ()) - { - os << "," << endl - << "&" << traits << "::prepare_query"; - - os << "," << endl - << "&" << traits << "::execute_query"; - } - } - - os << "};"; - - os << "static const object_function_table_entry< " << type << ", " << - "id_" << db << " >" << endl - << "function_table_entry_" << fn << "_ (" << endl - << "&function_table_" << fn << "_);" - << endl; - } -} - -void relational::source::class_:: -traverse_view (type& c) -{ - view_query& vq (c.get ("query")); - - // Only process the view query if it is versioned since the query text - // (e.g., in the native view) must be structured. We also shouldn't try - // to optimize JOINs (since the objects are JOINed explicitly by the - // user), unless we are adding poly-base/derived JOINs. - // - bool versioned (context::versioned (c)); - bool query_optimize (false); - - string const& type (class_fq_name (c)); - string traits ("access::view_traits_impl< " + type + ", id_" + - db.string () + " >"); - - size_t columns (column_count (c).total); - - // Schema name as a string literal or empty. - // - string schema_name (options.schema_name ()[db]); - if (!schema_name.empty ()) - schema_name = strlit (schema_name); - - // Generate the from-list. Also collect relationships via which - // the objects are joined. - // - strings from; - view_relationship_map rel_map; - - if (vq.kind == view_query::condition) - { - view_objects& objs (c.get ("objects")); - - for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) - { - bool first (i == objs.begin ()); - string l; - - // - // Tables. - // - - if (i->kind == view_object::table) - { - if (first) - { - l = "FROM "; - l += quote_id (i->tbl_name); - - if (!i->alias.empty ()) - l += (need_alias_as ? " AS " : " ") + quote_id (i->alias); - - l += from_trailer (c); - - from.push_back (l); - continue; - } - - l = join_syntax (*i); - l += ' '; - l += quote_id (i->tbl_name); - - if (!i->alias.empty ()) - l += (need_alias_as ? " AS " : " ") + quote_id (i->alias); - - if (i->join == view_object::cross) // No ON condition for CROSS JOIN. - { - from.push_back (l); - continue; - } - - semantics::scope& scope ( - dynamic_cast (*unit.find (i->scope))); - - expression e ( - translate_expression ( - c, i->cond, scope, i->loc, "table")); - - if (e.kind != expression::literal) - { - error (i->loc) << "invalid join condition in db pragma " << - "table" << endl; - throw operation_failed (); - } - - l += " ON"; - - // Add the pragma location for easier error tracking. - // - from.push_back (l); - from.push_back ("// From " + location_string (i->loc, true)); - from.push_back (e.value); - continue; - } - - // - // Objects. - // - semantics::class_& o (*i->obj); - - bool poly (polymorphic (o)); - size_t poly_depth (poly ? polymorphic_depth (o) : 1); - - string alias (i->alias); - - // For polymorphic objects, alias is just a prefix. - // - if (poly && !alias.empty ()) - alias += "_" + table_name (o).uname (); - - // First object. - // - if (first) - { - l = "FROM "; - l += table_qname (o); - - if (!alias.empty ()) - l += (need_alias_as ? " AS " : " ") + quote_id (alias); - - l += from_trailer (c); - - from.push_back (l); - - if (poly_depth != 1) - { - bool t (true); //@@ (im)perfect forwarding - size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j (o, t, d, i->alias); - j->traverse (polymorphic_base (o)); - - from.insert (from.end (), j->begin (), j->end ()); - query_optimize = query_optimize || !j->joins.empty (); - } - continue; - } - - semantics::scope& scope ( - dynamic_cast (*unit.find (i->scope))); - - expression e (i->join == view_object::cross - ? expression ("") // Dummy literal expression. - : translate_expression ( - c, i->cond, scope, i->loc, "object")); - - // Literal expression. - // - if (e.kind == expression::literal) - { - l = join_syntax (*i); - l += ' '; - l += table_qname (o); - - if (!alias.empty ()) - l += (need_alias_as ? " AS " : " ") + quote_id (alias); - - if (i->join == view_object::cross) // No ON condition for CROSS JOIN. - { - from.push_back (l); - continue; - } - - l += " ON"; - - // Add the pragma location for easier error tracking. - // - from.push_back (l); - from.push_back ("// From " + location_string (i->loc, true)); - from.push_back (e.value); - - if (poly_depth != 1) - { - bool t (true); //@@ (im)perfect forwarding - size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j (o, t, d, i->alias); - j->traverse (polymorphic_base (o)); - - from.insert (from.end (), j->begin (), j->end ()); - query_optimize = query_optimize || !j->joins.empty (); - } - continue; - } - - // We have an object relationship (pointer) for which we need - // to come up with the corresponding JOIN condition. If this - // is a to-many relationship, then we first need to JOIN the - // container table. This code is similar to object_joins. - // - // Note that this cannot be CROSS JOIN; we've handled that case - // above. - // - using semantics::data_member; - - data_member& m (*e.member_path.back ()); - data_member_path* imp (inverse (m)); - - // Resolve the pointed-to object to view_object and do - // some sanity checks while at it. - // - semantics::class_* c (0); - - if (container (m)) - c = object_pointer (container_vt (m)); - else - c = object_pointer (utype (m)); - - view_object* vo (0); - - // Check if the pointed-to object has been previously associated - // with this view and is unambiguous. A pointer to ourselves is - // always assumed to point to this association. - // - if (&o == c) - vo = &*i; - else - { - bool ambig (false); - - for (view_objects::iterator j (objs.begin ()); j != i; ++j) - { - if (j->obj != c) - continue; - - if (vo == 0) - { - vo = &*j; - continue; - } - - // If it is the first ambiguous object, issue the - // error. - // - if (!ambig) - { - error (i->loc) << "pointed-to object '" << class_name (*c) << - "' is ambiguous" << endl; - info (i->loc) << "candidates are:" << endl; - info (vo->loc) << " '" << vo->name () << "'" << endl; - ambig = true; - } - - info (j->loc) << " '" << j->name () << "'" << endl; - } - - if (ambig) - { - info (i->loc) << "use the other side of the relationship " << - "or full join condition clause in db pragma object to " << - "resolve this ambiguity" << endl; - throw operation_failed (); - } - - if (vo == 0) - { - error (i->loc) << "pointed-to object '" << class_name (*c) << - "' specified in the join condition has not been " << - "previously associated with this view" << endl; - throw operation_failed (); - } - } - - // JOIN relationship points to us: - // vo - us - // e.vo - other side - // e.member_path - in other side - // - // JOIN relationship points to other side: - // vo - other side - // e.vo - us - // e.member_path - in us - // - if (imp == 0) - rel_map.insert (make_pair (e.member_path, make_pair (e.vo, vo))); - else - rel_map.insert (make_pair (*imp, make_pair (vo, e.vo))); - - // Left and right-hand side table names. - // - qname lt; - { - using semantics::class_; - - class_& o (*e.vo->obj); - string const& a (e.vo->alias); - - if (class_* root = polymorphic (o)) - { - // If the object is polymorphic, then figure out which of the - // bases this member comes from and use the corresponding - // table. - // - class_* c ( - &static_cast ( - e.member_path.front ()->scope ())); - - // If this member's class is not polymorphic (root uses reuse - // inheritance), then use the root table. - // - if (!polymorphic (*c)) - c = root; - - qname const& t (table_name (*c)); - - if (a.empty ()) - lt = t; - else - lt = qname (a + "_" + t.uname ()); - } - else - lt = a.empty () ? table_name (o) : qname (a); - } - - qname rt; - { - qname t (table_name (*vo->obj)); - string const& a (vo->alias); - rt = a.empty () - ? t - : qname (polymorphic (*vo->obj) ? a + "_" + t.uname () : a); - } - - // First join the container table if necessary. - // - semantics::type* cont (container (imp != 0 ? *imp->back () : m)); - - string ct; // Container table. - if (cont != 0) - { - l = join_syntax (*i); - l += ' '; - - // The same relationship can be used by multiple associated - // objects. So if the object that contains this container has - // an alias, then also construct one for the table that we - // are joining. - // - { - using semantics::class_; - - qname t; - - // In a polymorphic hierarchy the member can be in a base (see - // above). - // - if (class_* root = polymorphic (imp != 0 ? *vo->obj : *e.vo->obj)) - { - class_* c; - if (imp == 0) - { - c = &static_cast (e.member_path.front ()->scope ()); - - if (!polymorphic (*c)) - c = root; - - t = table_name (*c, e.member_path); - } - else - { - c = &static_cast (imp->front ()->scope ()); - - if (!polymorphic (*c)) - c = root; - - t = table_name (*c, *imp); - } - } - else - t = imp != 0 - ? table_name (*vo->obj, *imp) - : table_name (*e.vo->obj, e.member_path); - - // The tricky part is to figure out which view_object, vo - // or e.vo we should use. We want to use the alias from the - // object that actually contains this container. The following - // might not make intuitive sense, but it has been verified - // with the truth table. - // - string const& a (imp != 0 ? vo->alias : e.vo->alias); - - if (a.empty ()) - { - ct = quote_id (t); - l += ct; - } - else - { - ct = quote_id (a + '_' + t.uname ()); - l += quote_id (t); - l += (need_alias_as ? " AS " : " ") + ct; - } - } - - l += " ON"; - from.push_back (l); - - // If we are the pointed-to object, then we have to turn - // things around. This is necessary to have the proper - // JOIN order. There seems to be a pattern there but it - // is not yet intuitively clear what it means. - // - instance c_cols; // Container columns. - instance o_cols; // Object columns. - - qname* ot; // Object table (either lt or rt). - - if (imp != 0) - { - semantics::data_member& imb (*imp->back ()); - - if (&o == c) - { - // container.value = pointer.id - // - data_member_path& id (*id_member (*e.vo->obj)); - - c_cols->traverse (imb, utype (id), "value", "value"); - o_cols->traverse (id); - ot = < - } - else - { - // container.id = pointed-to.id - // - data_member_path& id (*id_member (*vo->obj)); - - c_cols->traverse (imb, utype (id), "id", "object_id", vo->obj); - o_cols->traverse (id); - ot = &rt; - } - } - else - { - if (&o == c) - { - // container.id = pointer.id - // - data_member_path& id (*id_member (*e.vo->obj)); - - c_cols->traverse ( - m, utype (id), "id", "object_id", e.vo->obj); - o_cols->traverse (id); - ot = < - } - else - { - // container.value = pointed-to.id - // - data_member_path& id (*id_member (*vo->obj)); - - c_cols->traverse (m, utype (id), "value", "value"); - o_cols->traverse (id); - ot = &rt; - } - } - - for (object_columns_list::iterator b (c_cols->begin ()), i (b), - j (o_cols->begin ()); i != c_cols->end (); ++i, ++j) - { - l.clear (); - - if (i != b) - l += "AND "; - - l += ct; - l += '.'; - l += quote_id (i->name); - l += '='; - l += quote_id (*ot); - l += '.'; - l += quote_id (j->name); - - from.push_back (strlit (l)); - } - } - - // If we have already joined the container with the desired - // join type, then use LEFT JOIN to join the object to the - // container. This is the right thing to do since an entry - // in the container can only point (either via id or value) - // to a single object. - // - l = (cont == 0 ? join_syntax (*i) : "LEFT JOIN"); - l += ' '; - - l += table_qname (o); - - if (!alias.empty ()) - l += (need_alias_as ? " AS " : " ") + quote_id (alias); - - l += " ON"; - from.push_back (l); - - if (cont != 0) - { - instance c_cols; // Container columns. - instance o_cols; // Object columns. - - qname* ot; // Object table (either lt or rt). - - if (imp != 0) - { - semantics::data_member& imb (*imp->back ()); - - if (&o == c) - { - // container.id = pointed-to.id - // - data_member_path& id (*id_member (*vo->obj)); - - c_cols->traverse (imb, utype (id), "id", "object_id", vo->obj); - o_cols->traverse (id); - ot = &rt; - } - else - { - // container.value = pointer.id - // - data_member_path& id (*id_member (*e.vo->obj)); - - c_cols->traverse (imb, utype (id), "value", "value"); - o_cols->traverse (id); - ot = < - } - } - else - { - if (&o == c) - { - // container.value = pointed-to.id - // - data_member_path& id (*id_member (*vo->obj)); - - c_cols->traverse (m, utype (id), "value", "value"); - o_cols->traverse (id); - ot = &rt; - } - else - { - // container.id = pointer.id - // - data_member_path& id (*id_member (*e.vo->obj)); - - c_cols->traverse (m, utype (id), "id", "object_id", e.vo->obj); - o_cols->traverse (id); - ot = < - } - } - - for (object_columns_list::iterator b (c_cols->begin ()), i (b), - j (o_cols->begin ()); i != c_cols->end (); ++i, ++j) - { - l.clear (); - - if (i != b) - l += "AND "; - - l += ct; - l += '.'; - l += quote_id (i->name); - l += '='; - l += quote_id (*ot); - l += '.'; - l += quote_id (j->name); - - from.push_back (strlit (l)); - } - } - else - { - instance l_cols; - instance r_cols; - - if (imp != 0) - { - // our.id = pointed-to.pointer - // - l_cols->traverse (*id_member (*e.vo->obj)); - r_cols->traverse (*imp->back (), column_prefix (*imp)); - } - else - { - // our.pointer = pointed-to.id - // - l_cols->traverse (*e.member_path.back (), - column_prefix (e.member_path)); - r_cols->traverse (*id_member (*vo->obj)); - } - - for (object_columns_list::iterator b (l_cols->begin ()), i (b), - j (r_cols->begin ()); i != l_cols->end (); ++i, ++j) - { - l.clear (); - - if (i != b) - l += "AND "; - - l += quote_id (lt); - l += '.'; - l += quote_id (i->name); - l += '='; - l += quote_id (rt); - l += '.'; - l += quote_id (j->name); - - from.push_back (strlit (l)); - } - } - - if (poly_depth != 1) - { - bool t (true); //@@ (im)perfect forwarding - size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j (o, t, d, i->alias); - j->traverse (polymorphic_base (o)); - - from.insert (from.end (), j->begin (), j->end ()); - query_optimize = query_optimize || !j->joins.empty (); - } - } // End JOIN-generating for-loop. - } - - // Check that pointed-to objects inside objects that we are loading - // have session support enabled (required to have a shared copy). - // Also see if we need to throw if there is no session. - // - bool need_session (false); - if (vq.kind == view_query::condition) - { - view_objects& objs (c.get ("objects")); - for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) - { - if (i->kind != view_object::object || i->ptr == 0) - continue; // Not an object or not loaded. - - instance t (*i, rel_map); - t->traverse (*i->obj); - need_session = need_session || t->session_; - } - } - - os << "// " << class_name (c) << endl - << "//" << endl - << endl; - - view_extra (c); - - // query_columns - // - if (c.get ("object-count") != 0) - view_query_columns_type_->traverse (c); - - // - // Functions. - // - - // grow () - // - if (generate_grow && columns != 0) - { - os << "bool " << traits << "::" << endl - << "grow (image_type& i," << endl - << truncated_vector << " t"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "bool grew (false);" - << endl; - - index_ = 0; - names (c, grow_member_names_); - - os << "return grew;" - << "}"; - } - - // bind (image_type) - // - if (columns != 0) - { - os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "image_type& i"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);" - << endl; - - os << "using namespace " << db << ";" - << endl - << db << "::statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "std::size_t n (0);" - << endl; - - names (c, bind_member_names_); - - os << "}"; - } - - // init (view, image) - // - if (columns != 0) - { - os << "void " << traits << "::" << endl - << "init (view_type& o," << endl - << "const image_type& i," << endl - << "database* db"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - if (need_session) - os << "if (!" << options.session_type () << "::_has_cache ())" << endl - << "throw session_required ();" - << endl; - - // Note: db must be not NULL in order to load pointers. - // - if (has_a (c, test_pointer)) - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (*db));" - << endl; - - names (c, init_view_pointer_member_pre_names_); - names (c, init_value_member_names_); - names (c, init_view_pointer_member_post_names_); - - os << "}"; - } - - // query_statement() - // - if (vq.kind != view_query::runtime) - { - os << traits << "::query_base_type" << endl - << traits << "::" << endl - << "query_statement (const query_base_type& q)" - << "{"; - - if (vq.kind == view_query::complete_select || - vq.kind == view_query::complete_execute) - { - os << "query_base_type r (" << endl; - - bool ph (false); - bool pred (vq.kind == view_query::complete_select); - - if (!vq.literal.empty ()) - { - // See if we have the '(?)' placeholder. - // - // @@ Ideally we would need to make sure we don't match - // this inside strings and quoted identifier. So the - // proper way to handle this would be to tokenize the - // statement using sql_lexer, once it is complete enough. - // - string::size_type p (vq.literal.find ("(?)")); - - if (p != string::npos) - { - ph = true; - // For the SELECT query we keep the parenthesis in (?) and - // also handle the case where the query expression is empty. - // - if (pred) - os << strlit (string (vq.literal, 0, p + 1)) << " +" << endl - << "(q.empty () ? query_base_type::true_expr : q) +" << endl - << strlit (string (vq.literal, p + 2)); - else - { - os << strlit (string (vq.literal, 0, p)) << " + q"; - - p += 3; - if (p != vq.literal.size ()) - os << " + " << strlit (string (vq.literal, p)); - } - } - else - os << strlit (vq.literal); - } - else - { - semantics::scope& scope ( - dynamic_cast (*unit.find (vq.scope))); - - // Output the pragma location for easier error tracking. - // - os << "// From " << location_string (vq.loc, true) << endl - << translate_expression ( - c, vq.expr, scope, vq.loc, "query", &ph, pred).value; - } - - os << ");"; - - // If there was no placeholder, add the query condition - // at the end. - // - if (!ph) - os << endl - << "if (!q.empty ())" - << "{" - << "r += " << strlit (versioned ? "\n" : " ") << ";" - << "r += q.clause_prefix ();" - << "r += q;" - << "}"; - } - else // vq.kind == view_query::condition - { - // Use the from-list generated above. - // - statement_columns sc; - { - instance t (sc, from, rel_map); - t->traverse (c); - process_statement_columns ( - sc, statement_select, versioned || query_optimize); - } - - string sep (versioned || query_optimize ? "\n" : " "); - - os << "query_base_type r (" << endl - << strlit ((vq.distinct ? "SELECT DISTINCT" : "SELECT") + sep); - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << endl - << strlit (c + (++i != e ? "," : "") + sep); - } - - os << ");" - << endl; - - // It is much easier to add the separator at the beginning of the - // next line since the JOIN condition may not be a string literal. - // - for (strings::const_iterator i (from.begin ()); i != from.end (); ++i) - { - if (i->compare (0, 5, "FROM ") == 0) - os << "r += " << strlit (*i) << ";"; - else if (i->compare (0, 3, "// ") == 0) - os << *i << endl; - else - { - // See if this is a JOIN. The exact spelling is database-dependent, - // but we know there is the JOIN word in there somewhere and before - // it we should only have keywords and spaces. - // - size_t p (i->find ("JOIN ")); - if (p != string::npos) - { - // Make sure before it we only have A-Z and spaces. - // - for (char c; p != 0; --p) - { - c = (*i)[p - 1]; - if ((c < 'A' || c > 'Z') && c != ' ') - break; - } - - if (p == 0) - os << endl - << "r += " << strlit (sep + *i) << ";"; - } - - // Something else, assume already a string literal. - // - if (p != 0) - os << "r += " << *i << ";"; - } - } - - // Generate the query condition. - // - if (!vq.literal.empty () || !vq.expr.empty ()) - { - os << endl - << "query_base_type c (" << endl; - - bool ph (false); - - if (!vq.literal.empty ()) - { - // See if we have the '(?)' placeholder. - // - // @@ Ideally we would need to make sure we don't match - // this inside strings and quoted identifier. So the - // proper way to handle this would be to tokenize the - // statement using sql_lexer, once it is complete enough. - // - string::size_type p (vq.literal.find ("(?)")); - - if (p != string::npos) - { - ph = true; - os << strlit (string (vq.literal, 0, p + 1))<< " +" << endl - << "(q.empty () ? query_base_type::true_expr : q) +" << endl - << strlit (string (vq.literal, p + 2)); - } - else - os << strlit (vq.literal); - - os << ");"; - } - else - { - semantics::scope& scope ( - dynamic_cast (*unit.find (vq.scope))); - - // Output the pragma location for easier error tracking. - // - os << "// From " << location_string (vq.loc, true) << endl - << translate_expression ( - c, vq.expr, scope, vq.loc, "query", &ph).value; - - os << ");"; - - // Optimize the query if it had a placeholder. This gets - // rid of useless clauses like WHERE TRUE. - // - if (ph) - os << endl - << "c.optimize ();"; - } - - if (!ph) - os << endl - << "c += q;"; - - os << endl - << "if (!c.empty ())" - << "{" - << "r += " << strlit (sep) << ";" - << "r += c.clause_prefix ();" - << "r += c;" - << "}"; - - string st (select_trailer (c)); - if (!st.empty ()) - { - os << "r += " << strlit (sep) << ";" - << "r += " << strlit (st) << ";"; - } - } - else - { - os << endl - << "if (!q.empty ())" - << "{" - << "r += " << strlit (sep) << ";" - << "r += q.clause_prefix ();" - << "r += q;" - << "}"; - } - } - - os << "return r;" - << "}"; - } - - // Unprepared. - // - if (!options.omit_unprepared ()) - { - os << "result< " << traits << "::view_type >" << endl - << traits << "::" << endl - << "query (database& db, const query_base_type& q)" - << "{" - << "using namespace " << db << ";" - << "using odb::details::shared;" - << "using odb::details::shared_ptr;" - << endl; - - os << db << "::connection& conn (" << endl - << db << "::transaction::current ().connection (db));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_view ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << 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" << (versioned ? ", svm" : "") << ");" - << "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));"; - - os << "qs.init_parameters ();" - << "shared_ptr st (" << endl - << "new (shared) select_statement (" << endl; - view_query_statement_ctor_args ( - c, "qs", versioned || query_optimize, false); - os << "));" << endl - << "st->execute ();"; - - post_query_ (c, true); - - os << endl - << "shared_ptr< odb::view_result_impl > r (" << endl - << "new (shared) " << db << "::view_result_impl (" << endl - << "qs, st, sts, " << (versioned ? "&svm" : "0") << "));" - << endl - << "return result (r);" - << "}"; - - // query(odb::query_base) - // - if (multi_dynamic) - os << "result< " << traits << "::view_type >" << endl - << traits << "::" << endl - << "query (database& db, const odb::query_base& q)" - << "{" - << "return query (db, query_base_type (q));" - << "}"; - } - - // Prepared. Very similar to unprepared but has some annoying variations - // that make it difficult to factor out something common. - // - if (options.generate_prepared ()) - { - // prepare_query - // - 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; - - os << db << "::connection& conn (" << endl - << "static_cast<" << db << "::connection&> (c));" - << "statements_type& sts (" << endl - << "conn.statement_cache ().find_view ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << 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" << (versioned ? ", svm" : "") << ");" - << "sts.image_version (im.version);" - << "imb.version++;" - << "}"; - - os << "shared_ptr<" << db << "::prepared_query_impl> r (" << endl - << "new (shared) " << db << "::prepared_query_impl (conn));" - << "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", versioned || query_optimize, true); - os << "));" - << endl - << "return r;" - << "}"; - - // prepare_query(odb::query_base) - // - if (multi_dynamic) - os << "odb::details::shared_ptr" << endl - << traits << "::" << endl - << "prepare_query (connection& c, const char* n, " << - "const odb::query_base& q)" - << "{" - << "return prepare_query (c, n, query_base_type (q));" - << "}"; - - // execute_query - // - 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; - - os << db << "::transaction& tr (" << db << "::transaction::current ());" - << endl - << "// The connection used by the current transaction and the" << endl - << "// one used to prepare this statement must be the same." << endl - << "//" << endl - << "assert (q.verify_connection (tr));" - << endl - << "statements_type& sts (" << endl - << "st->connection ().statement_cache ().find_view ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration (" << schema_name << "));"; - - os << 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" << (versioned ? ", svm" : "") << ");" - << "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, " << (versioned ? "&svm" : "0") << "));" - << "}"; - } - - // Generate function table registration for dynamic multi-database - // support. - // - if (multi_dynamic) - { - string fn (flat_name (type)); - string dt ("access::view_traits_impl< " + type + ", id_common >"); - - os << "static const" << endl - << dt << "::" << endl - << "function_table_type function_table_" << fn << "_ =" - << "{"; - - if (!options.omit_unprepared ()) - os << "&" << traits << "::query"; - - if (options.generate_prepared ()) - { - if (!options.omit_unprepared ()) - os << "," << endl; - - os << "&" << traits << "::prepare_query" << "," << endl - << "&" << traits << "::execute_query"; - } - - os << "};"; - - os << "static const view_function_table_entry< " << type << ", " << - "id_" << db << " >" << endl - << "function_table_entry_" << fn << "_ (" << endl - << "&function_table_" << fn << "_);" - << endl; - } -} - -namespace relational -{ - namespace source - { - static inline void - add_space (string& s) - { - string::size_type n (s.size ()); - if (n != 0 && s[n - 1] != ' ') - s += ' '; - } - - static string - translate_name_trailer (cxx_lexer& l, - cpp_ttype& tt, - string& tl, - tree& tn, - cpp_ttype& ptt) - { - string r; - - for (; tt != CPP_EOF; ptt = tt, tt = l.next (tl, &tn)) - { - bool done (false); - - switch (tt) - { - case CPP_SCOPE: - case CPP_DOT: - { - r += cxx_lexer::token_spelling[tt]; - break; - } - default: - { - // Handle CPP_KEYWORD here to avoid a warning (it is not - // part of the cpp_ttype enumeration). - // - if (tt == CPP_NAME || tt == CPP_KEYWORD) - { - // For names like 'foo::template bar'. - // - if (ptt == CPP_NAME || ptt == CPP_KEYWORD) - r += ' '; - - r += tl; - } - else - done = true; - - break; - } - } - - if (done) - break; - } - - return r; - } - - static class_::expression - translate_name (cxx_lexer& l, - cpp_ttype& tt, - string& tl, - tree& tn, - cpp_ttype& ptt, - semantics::scope& start_scope, - location_t loc, - string const& prag, - bool check_ptr, - view_alias_map const& amap, - view_object_map const& omap) - { - using semantics::scope; - using semantics::data_member; - typedef class_::expression expression; - - bool multi_obj ((amap.size () + omap.size ()) > 1); - - bool fail (false); - string name; - string r ("query_columns"); - context& ctx (context::current ()); - - // This code is quite similar to view_data_members in the type - // processor. - // - try - { - data_member* m (0); - view_object* vo (0); - - // Check if this is an alias. - // - if (tt == CPP_NAME) - { - view_alias_map::const_iterator i (amap.find (tl)); - - if (i != amap.end ()) - { - if (multi_obj) - { - r += "::"; - r += i->first; - } - - vo = i->second; - fail = true; // This must be a data member. - - // Skip '::'. - // - ptt = tt; - tt = l.next (tl, &tn); - - if (tt != CPP_SCOPE) - { - error (loc) << "member name expected after an alias in db " << - "pragma " << prag << endl; - throw operation_failed (); - } - - ptt = tt; - if (l.next (tl, &tn) != CPP_NAME) - throw lookup::invalid_name (); - - m = &vo->obj->lookup (tl, scope::include_hidden); - - tt = l.next (tl, &tn); - } - } - - // If it is not an alias, do the normal lookup. - // - if (vo == 0) - { - // Also get the object type. We need to do it so that - // we can get the correct (derived) object name (the - // member itself can come from a base class). - // - scope* s; - cpp_ttype ptt; // Not used. - m = &lookup::resolve_scoped_name ( - l, tt, tl, tn, ptt, - start_scope, - name, - false, - &s); - - view_object_map::const_iterator i ( - omap.find (dynamic_cast (s))); - - if (i == omap.end ()) - { - // Not an object associated with this view. Assume it - // is some other valid name. - // - return expression ( - name + translate_name_trailer (l, tt, tl, tn, ptt)); - } - - vo = i->second; - - if (multi_obj) - { - r += "::"; - r += context::class_name (*vo->obj); - } - } - - expression e (vo); - r += "::"; - r += ctx.public_name (*m); - - // Assemble the member path if we may need to return a pointer - // expression. - // - if (check_ptr) - e.member_path.push_back (m); - - fail = true; // Now we definitely fail if anything goes wrong. - - // Finally, resolve nested members if any. - // - for (; tt == CPP_DOT; ptt = tt, tt = l.next (tl, &tn)) - { - // Check if this member is actually of a composite value type. - // This is to handle expressions like "object::member.is_null ()" - // correctly. The remaining issue here is that in the future - // is_null()/is_not_null() will be valid for composite values - // as well. - // - semantics::class_* comp ( - context::composite_wrapper (context::utype (*m))); - if (comp == 0) - break; - - ptt = tt; - tt = l.next (tl, &tn); - - if (tt != CPP_NAME) - { - error (loc) << "name expected after '.' in db pragma " << - prag << endl; - throw operation_failed (); - } - - m = &comp->lookup (tl, scope::include_hidden); - - r += '.'; - r += ctx.public_name (*m); - - if (check_ptr) - e.member_path.push_back (m); - } - - // If requested, check if this member is a pointer. We only do this - // if there is nothing after this name. - // - if (check_ptr && tt == CPP_EOF) - { - using semantics::type; - - type* t; - - if (context::container (*m)) - t = &context::container_vt (*m); - else - t = &context::utype (*m); - - if (context::object_pointer (*t)) - return e; - } - - // Read the remainder of the expression (e.g., '.is_null ()') if - // the member is not composite and we bailed out from the above - // loop. - // - if (tt == CPP_DOT) - r += translate_name_trailer (l, tt, tl, tn, ptt); - - return expression (r); - } - catch (lookup::invalid_name const&) - { - if (!fail) - return expression ( - name + translate_name_trailer (l, tt, tl, tn, ptt)); - - error (loc) << "invalid name in db pragma " << prag << endl; - throw operation_failed (); - } - catch (semantics::unresolved const& e) - { - if (!fail) - return expression ( - name + translate_name_trailer (l, tt, tl, tn, ptt)); - - if (e.type_mismatch) - error (loc) << "name '" << e.name << "' in db pragma " << prag << - " does not refer to a data member" << endl; - else - error (loc) << "unable to resolve data member '" << e.name << - "' specified with db pragma " << prag << endl; - - throw operation_failed (); - } - catch (semantics::ambiguous const& e) - { - error (loc) << "data member name '" << e.first.name () << "' " << - "specified with db pragma " << prag << " is ambiguous" << endl; - - info (e.first.named ().location ()) << "could resolve to this " << - "data member" << endl; - - info (e.second.named ().location ()) << "or could resolve to this " << - "data member" << endl; - - throw operation_failed (); - } - } - - class_::expression class_:: - translate_expression (type& c, - cxx_tokens const& ts, - semantics::scope& scope, - location_t loc, - string const& prag, - bool* placeholder, - bool predicate) - { - // This code is similar to translate() from context.cxx. - // - - // The overall idea is as folows: read in tokens and add them - // to the string. If a token starts a name, try to resolve it - // to an object member (taking into account aliases). If this - // was successful, translate it to the query column reference. - // Otherwise, output it as is. - // - // If the placeholder argument is not NULL, then we need to - // detect the special '(?)' token sequence and replace it - // with the query variable ('q'). - // - expression e (""); - string& r (e.value); - - view_alias_map const& amap (c.get ("alias-map")); - view_object_map const& omap (c.get ("object-map")); - - cxx_tokens_lexer l; - l.start (ts); - - tree tn; - string tl; - for (cpp_ttype tt (l.next (tl, &tn)), ptt (CPP_EOF); tt != CPP_EOF;) - { - // Try to format the expression to resemble the style of the - // generated code. - // - switch (tt) - { - case CPP_NOT: - { - add_space (r); - r += '!'; - break; - } - case CPP_COMMA: - { - r += ", "; - break; - } - case CPP_OPEN_PAREN: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD) - add_space (r); - - r += '('; - break; - } - case CPP_CLOSE_PAREN: - { - r += ')'; - break; - } - case CPP_OPEN_SQUARE: - { - r += '['; - break; - } - case CPP_CLOSE_SQUARE: - { - r += ']'; - break; - } - case CPP_OPEN_BRACE: - { - add_space (r); - r += "{ "; - break; - } - case CPP_CLOSE_BRACE: - { - add_space (r); - r += '}'; - break; - } - case CPP_SEMICOLON: - { - r += ';'; - break; - } - case CPP_ELLIPSIS: - { - add_space (r); - r += "..."; - break; - } - case CPP_PLUS: - case CPP_MINUS: - { - bool unary (ptt != CPP_NAME && - ptt != CPP_SCOPE && - ptt != CPP_NUMBER && - ptt != CPP_STRING && - ptt != CPP_CLOSE_PAREN && - ptt != CPP_PLUS_PLUS && - ptt != CPP_MINUS_MINUS); - - if (!unary) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - - if (!unary) - r += ' '; - break; - } - case CPP_PLUS_PLUS: - case CPP_MINUS_MINUS: - { - if (ptt != CPP_NAME && - ptt != CPP_CLOSE_PAREN && - ptt != CPP_CLOSE_SQUARE) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_DEREF: - case CPP_DEREF_STAR: - case CPP_DOT: - case CPP_DOT_STAR: - { - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_STRING: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += strlit (tl); - break; - } - case CPP_NUMBER: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - break; - } - case CPP_SCOPE: - case CPP_NAME: - { - // Start of a name. - // - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - // Check if this is a pointer expression. - // - // If r is not empty, then it means this is not just the - // name. If placeholder is not 0, then we are translating - // a query expression, not a join condition. - // - expression e ( - translate_name ( - l, tt, tl, tn, ptt, - scope, loc, prag, - r.empty () && placeholder == 0, amap, omap)); - - if (e.kind == expression::literal) - r += e.value; - else - return e; - - continue; // We have already extracted the next token. - } - case CPP_QUERY: - { - if (placeholder != 0 && !*placeholder) - { - if (ptt == CPP_OPEN_PAREN) - { - // Get the next token and see if it is ')'. - // - ptt = tt; - tt = l.next (tl, &tn); - - if (tt == CPP_CLOSE_PAREN) - { - *placeholder = true; - - // Predicate is true if this is a SELECT statement clause. - // Otherwise it is a stored procedure parameters. - // - if (predicate) - r += "q.empty () ? query_base_type::true_expr : q"; - else - { - r.resize (r.size () - 1); // Remove opening paren. - r += "q"; - break; // Skip the closing paren as well. - } - } - else - { - // The same as in the default case. - // - add_space (r); - r += "? "; - } - continue; // We have already gotten the next token. - } - } - } - // Fall through. - default: - { - // Handle CPP_KEYWORD here to avoid a warning (it is not - // part of the cpp_ttype enumeration). - // - if (tt == CPP_KEYWORD) - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - } - else - { - // All the other operators. - // - add_space (r); - r += cxx_lexer::token_spelling[tt]; - r += ' '; - } - break; - } - } - - // - // Watch out for the continue statements above if you add any - // logic here. - // - - ptt = tt; - tt = l.next (tl, &tn); - } - - return e; - } - - void - generate () - { - context ctx; - ostream& os (ctx.os); - - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - instance c; - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (false); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - instance i; - i->generate (); - - os << "namespace odb" - << "{"; - - unit.dispatch (ctx.unit); - - os << "}"; - } - } -} diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx deleted file mode 100644 index 3c6f5da..0000000 --- a/odb/relational/source.hxx +++ /dev/null @@ -1,7154 +0,0 @@ -// file : odb/relational/source.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SOURCE_HXX -#define ODB_RELATIONAL_SOURCE_HXX - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -namespace relational -{ - namespace source - { - // Column literal in a statement (e.g., in select-list, etc). - // - struct statement_column - { - statement_column (): member (0) {} - statement_column (std::string const& tbl, - std::string const& col, - std::string const& t, - semantics::data_member& m, - std::string const& kp = "") - : table (tbl), column (col), type (t), member (&m), key_prefix (kp) - { - } - - std::string table; // Schema-qualifed and quoted table name. - std::string column; // Table-qualifed and quoted column expr. - std::string type; // Column SQL type. - semantics::data_member* member; - std::string key_prefix; - }; - - typedef std::list statement_columns; - - // Query parameter generator. A new instance is created for each - // query, so the customized version can have a counter to implement, - // for example, numbered parameters (e.g., $1, $2, etc). The auto_id() - // function is called instead of next() for the automatically-assigned - // object id member when generating the persist statement. If empty - // string is returned, then parameter is ignored. - // - struct query_parameters: virtual context - { - typedef query_parameters base; - - query_parameters (statement_kind sk, qname const& table) - : sk_ (sk), table_ (table) {} - - virtual string - next (semantics::data_member&, - const std::string& /*column*/, // Table qualified and quoted. - const std::string& /*sqlt*/) - { - return "?"; - } - - virtual string - auto_id (semantics::data_member& m, - const std::string& column, - const std::string& sqlt) - { - return next (m, column, sqlt); - } - - string - next (const object_columns_list::column& c) - { - return next (*c.member, quote_id (c.name), c.type); - } - - string - next (const statement_column& c) - { - return next (*c.member, c.column, c.type); - } - - protected: - statement_kind sk_; - qname table_; - }; - - struct object_columns: object_columns_base, virtual context - { - typedef object_columns base; - - // If provided, used to resolve table/alias names for inverse - // pointed-to and base objects. Returns qualified name. - // - struct table_name_resolver - { - virtual string - resolve_pointer (semantics::data_member&) const = 0; - - virtual string - resolve_base (semantics::class_&) const = 0; - }; - - object_columns (statement_kind sk, - statement_columns& sc, - query_parameters* param = 0, - object_section* section = 0) - : object_columns_base (true, true, section), - sk_ (sk), - ro_ (true), - sc_ (sc), - param_ (param), - table_name_resolver_ (0), - depth_ (1) - { - } - - object_columns (statement_kind sk, - bool ignore_ro, - statement_columns& sc, - query_parameters* param) - : object_columns_base (true, true, 0), - sk_ (sk), - ro_ (ignore_ro), - sc_ (sc), - param_ (param), - table_name_resolver_ (0), - depth_ (1) - { - } - - object_columns (std::string const& table_qname, - statement_kind sk, - statement_columns& sc, - size_t depth = 1, - object_section* section = 0, - table_name_resolver* tnr = 0) - : object_columns_base (true, true, section), - sk_ (sk), - ro_ (true), - sc_ (sc), - param_ (0), - table_name_ (table_qname), - table_name_resolver_ (tnr), - depth_ (depth) - { - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section for - // SELECT statements. Also include optimistic version into - // section's SELECT and UPDATE statements. - // - return section_ == 0 || - *section_ == s || - (sk_ == statement_select && - *section_ == main_section && - !s.separate_load ()) || - (version (mp) && - (sk_ == statement_update || sk_ == statement_select)); - } - - virtual void - traverse_object (semantics::class_& c) - { - // If we are generating a select statement and this is a derived - // type in a polymorphic hierarchy, then we need to include base - // columns, but do it in reverse order as well as switch the table - // name (base columns come from different tables). - // - semantics::class_* poly_root (polymorphic (c)); - if (poly_root != 0 && poly_root != &c) - { - names (c); - - if (sk_ == statement_select && --depth_ != 0) - { - semantics::class_& b (polymorphic_base (c)); - - table_name_ = table_name_resolver_ != 0 - ? table_name_resolver_->resolve_base (b) - : table_qname (b); - - inherits (c); - } - } - else - object_columns_base::traverse_object (c); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references for select statements. - // - if (sk_ == statement_select && m.count ("polymorphic-ref")) - return; - - data_member_path* imp (inverse (m, key_prefix_)); - - // Ignore certain columns depending on what kind of statement we are - // generating. Columns corresponding to the inverse members are - // only present in the select statements. - // - if (imp != 0 && sk_ != statement_select) - return; - - // Inverse object pointers come from a joined table. - // - if (imp != 0) - { - bool poly (polymorphic (c) != 0); - semantics::data_member& imf (*imp->front ()); - semantics::data_member& imb (*imp->back ()); - - // In a polymorphic hierarchy the inverse member can be in - // the base class, in which case we should use that table. - // - semantics::class_& imc ( - poly ? dynamic_cast (imf.scope ()) : c); - - data_member_path& id (*id_member (imc)); - semantics::type& idt (utype (id)); - - if (container (imb)) - { - // This container is a direct member of the class so the table - // prefix is just the class table name. We don't assign join - // aliases for container tables so use the actual table name. - // Note that the if(!table_name_.empty ()) test may look wrong - // at first but it is not; if table_name_ is empty then we are - // generating a container table where we don't qualify columns - // with tables. - // - string table; - - if (!table_name_.empty ()) - { - if (table_name_resolver_ != 0) - table = table_name_resolver_->resolve_pointer (m); - else - table = table_qname (imc, *imp); - } - - instance oc (table, sk_, sc_); - oc->traverse (imb, idt, "id", "object_id", &imc); - } - else - { - // Use the join alias instead of the actual table name unless we - // are handling a container. Generally, we want the join alias - // to be based on the column name. This is straightforward for - // single-column references. In case of a composite id, we will - // need to use the column prefix which is based on the data - // member name, unless overridden by the user. In the latter - // case the prefix can be empty, in which case we will just - // fall back on the member's public name. Note that the - // if(!table_name_.empty ()) test may look wrong at first but - // it is not; if table_name_ is empty then we are generating a - // container table where we don't qualify columns with tables. - // - string alias; - - if (!table_name_.empty ()) - { - if (table_name_resolver_ != 0) - alias = table_name_resolver_->resolve_pointer (m); - else - { - string n; - - if (composite_wrapper (idt)) - { - n = column_prefix (m, key_prefix_, default_name_).prefix; - - if (n.empty ()) - n = public_name_db (m); - else if (n[n.size () - 1] == '_') - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - { - bool dummy; - n = column_name (m, key_prefix_, default_name_, dummy); - } - - alias = column_prefix_.prefix + n; - - if (poly) - { - qname const& table (table_name (imc)); - alias = quote_id (alias + "_" + table.uname ()); - } - else - alias = quote_id (alias); - } - } - - instance oc (alias, sk_, sc_); - oc->traverse (id); - } - } - else - object_columns_base::traverse_pointer (m, c); - } - - virtual bool - traverse_column (semantics::data_member& m, string const& name, bool) - { - // Ignore certain columns depending on what kind statement we are - // generating. Id and readonly columns are not present in the update - // statements. - // - if ((id () || readonly (member_path_, member_scope_)) && - sk_ == statement_update && ro_) - return false; - - return column (m, table_name_, quote_id (name)); - } - - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - string r; - - if (!table.empty ()) - { - r += table; // Already quoted. - r += '.'; - } - - r += column; // Already quoted. - - string const& sqlt (column_type ()); - - // Version column (optimistic concurrency) requires special - // handling in the UPDATE statement. - // - // - if (sk_ == statement_update && version (m)) - { - r += "=" + r + "+1"; - } - else if (param_ != 0) - { - r += '='; - r += convert_to (param_->next (m, column, sqlt), sqlt, m); - } - else if (sk_ == statement_select) - r = convert_from (r, sqlt, m); - - sc_.push_back (statement_column (table, r, sqlt, m, key_prefix_)); - return true; - } - - protected: - statement_kind sk_; - bool ro_; - statement_columns& sc_; - query_parameters* param_; - string table_name_; - table_name_resolver* table_name_resolver_; - size_t depth_; - }; - - struct view_columns: object_columns_base, - object_columns::table_name_resolver, - virtual context - { - typedef view_columns base; - - view_columns (statement_columns& sc, - strings& from, - const view_relationship_map& rm) - : sc_ (sc), from_ (from), rel_map_ (rm), in_composite_ (false) {} - - // Implementation of table_name_resolver for object_columns. - // - virtual string - resolve_pointer (semantics::data_member& m) const - { - view_object& us (*ptr_->get ("view-object")); - - data_member_path& imp (*inverse (m)); - semantics::data_member& imf (*imp.front ()); - semantics::data_member& imb (*imp.back ()); - - using semantics::class_; - typedef view_relationship_map::const_iterator iterator; - - std::pair r (rel_map_.equal_range (imp)); - - for (; r.first != r.second; ++r.first) - { - if (r.first->second.second != &us) // Not our associated. - continue; - - view_object& vo (*r.first->second.first); // First because inverse. - - // Derive the table name the same way as the JOIN code. - // - class_* c (vo.obj); - if (class_* root = polymorphic (*c)) - { - // Can be in base. - // - c = &static_cast (imf.scope ()); - - if (!polymorphic (*c)) - c = root; - } - - string const& a (vo.alias); - - if (container (imb)) - { - // If this is a container, then object_columns will use the - // column from the container table, not from the object table - // (which, strictly speaking, might not have been JOIN'ed). - // - qname t (table_name (*c, imp)); - return a.empty () - ? quote_id (t) - : quote_id (a + '_' + t.uname ()); - } - else - { - qname t; - if (a.empty ()) - t = table_name (*c); - else - { - if (polymorphic (*c)) - t = qname (a + "_" + table_name (*c).uname ()); - else - t = qname (a); - } - return quote_id (t); - } - } - - // So there is no associated object for this column. The initial - // plan was to complain and ask the user to explicitly associate - // the object. This is not a bad plan except for one thing: if - // the direct side of the relationship is a container, then - // associating that object explicitly will result in both the - // container table and the object table being JOIN'ed. But we - // only need the container table (for the object id) So we will - // be joining a table for nothing, which is not very clean. So - // the alternative, and more difficult, plan is to go ahead and - // add the necessary JOIN's automatically. - // - // This code follows the normal JOIN generation code. - // - class_* o (object_pointer (utype (m))); - if (class_* root = polymorphic (*o)) - { - o = &static_cast (imf.scope ()); - - if (!polymorphic (*o)) - o = root; - } - - string const& a (us.alias); - string lt (a.empty () ? table_qname (*us.obj) : quote_id (a)); - string rt; - qname ct (container (imb) ? table_name (*o, imp) : table_name (*o)); - - string l ("LEFT JOIN "); - - if (a.empty ()) - { - rt = quote_id (ct); - l += rt; - } - else - { - // The same relationship can be used by multiple associated - // objects. So if we have an alias, then also construct one - // for the table that we are joining. - // - rt = quote_id (a + '_' + ct.uname ()); - l += quote_id (ct); - l += (need_alias_as ? " AS " : " ") + rt; - } - - l += " ON"; - from_.push_back (l); - - instance l_cols; // Our id columns. - instance r_cols; // Other side id columns. - - data_member_path& id (*id_member (*us.obj)); - - l_cols->traverse (id); - - if (container (imb)) - r_cols->traverse (imb, utype (id), "value", "value"); - else - r_cols->traverse (imb, column_prefix (imp)); - - for (object_columns_list::iterator b (l_cols->begin ()), i (b), - j (r_cols->begin ()); i != l_cols->end (); ++i, ++j) - { - l.clear (); - - if (i != b) - l += "AND "; - - l += lt; - l += '.'; - l += quote_id (i->name); - l += '='; - l += rt; - l += '.'; - l += quote_id (j->name); - - from_.push_back (strlit (l)); - } - - return rt; - - /* - // The alternative implementation: - // - location const& l1 (m.location ()); - location const& l2 (ptr_->location ()); - - string n1 (class_name (*object_pointer (utype (m)))); - string n2 (class_name (*object_pointer (utype (*ptr_)))); - - error (l1) << "object '" << n1 << "' pointed-to by the inverse " - << "data member in object '" << n2 << "' must be " - << "explicitly associated with the view" << endl; - - info (l2) << "view data member that loads '" << n2 << "' is " - << "defined here" << endl; - - throw operation_failed (); - */ - } - - virtual string - resolve_base (semantics::class_& b) const - { - view_object& vo (*ptr_->get ("view-object")); - - qname t (vo.alias.empty () - ? table_name (b) - : qname (vo.alias + "_" + table_name (b).uname ())); - - return quote_id (t); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - type* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1); - - view_object& vo (*m.get ("view-object")); - string const& a (vo.alias); - - qname t; - if (a.empty ()) - t = table_name (c); - else - { - if (poly) - t = qname (a + "_" + table_name (c).uname ()); - else - t = qname (a); - } - string qt (quote_id (t)); - - ptr_ = &m; - - statement_kind sk (statement_select); // Imperfect forwarding. - object_section* s (&main_section); // Imperfect forwarding. - instance oc (qt, sk, sc_, poly_depth, s, this); - oc->traverse (c); - } - - virtual void - traverse_composite (semantics::data_member* pm, semantics::class_& c) - { - if (in_composite_) - { - object_columns_base::traverse_composite (pm, c); - return; - } - - // Override the column prerix. - // - semantics::data_member& m (*pm); - - // If we have literal column specified, use that. - // - if (m.count ("column")) - { - table_column const& tc (m.get ("column")); - - if (!tc.table.empty ()) - table_prefix_ = tc.table; - - column_prefix_ = object_columns_base::column_prefix (m); - } - // Otherwise, see if there is a column expression. For composite - // members in a view, this should be a single reference. - // - else if (m.count ("column-expr")) - { - column_expr const& e (m.get ("column-expr")); - - if (e.size () > 1) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column expression specified for a data member " - << "of a composite value type" << endl; - - throw operation_failed (); - } - - data_member_path const& mp (e.back ().member_path); - - if (mp.size () > 1) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: invalid data member in db pragma column" - << endl; - - throw operation_failed (); - } - - table_prefix_ = e.back ().table; - column_prefix_ = object_columns_base::column_prefix (*mp.back ()); - } - else - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: no column prefix provided for a view data member" - << endl; - - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": info: use db pragma column to specify the column prefix" - << endl; - - throw operation_failed (); - } - - in_composite_ = true; - object_columns_base::traverse_composite (pm, c); - in_composite_ = false; - } - - virtual bool - traverse_column (semantics::data_member& m, string const& name, bool) - { - string tbl; - string col; - - // If we are inside a composite value, use the standard - // column name machinery. - // - if (in_composite_) - { - if (!table_prefix_.empty ()) - { - tbl = quote_id (table_prefix_); - col += tbl; - col += '.'; - } - - col += quote_id (name); - } - // If we have literal column specified, use that. - // - else if (m.count ("column")) - { - table_column const& tc (m.get ("column")); - - if (!tc.expr) - { - if (!tc.table.empty ()) - { - tbl = quote_id (tc.table); - col += tbl; - col += '.'; - } - - col += quote_id (tc.column); - } - else - col += tc.column; - } - // Otherwise, see if there is a column expression. - // - else if (m.count ("column-expr")) - { - column_expr const& e (m.get ("column-expr")); - - for (column_expr::const_iterator i (e.begin ()); i != e.end (); ++i) - { - switch (i->kind) - { - case column_expr_part::literal: - { - col += i->value; - break; - } - case column_expr_part::reference: - { - tbl = quote_id (i->table); - col += tbl; - col += '.'; - col += column_qname (i->member_path); - break; - } - } - } - } - else - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: no column name provided for a view data member" - << endl; - - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": info: use db pragma column to specify the column name" - << endl; - - throw operation_failed (); - } - - return column (m, tbl, col); - } - - // The column argument is a qualified and quoted column or - // expression. - // - virtual bool - column (semantics::data_member& m, - string const& table, - string const& column) - { - string const& sqlt (column_type ()); - sc_.push_back ( - statement_column ( - table, convert_from (column, sqlt, m), sqlt, m)); - return true; - } - - protected: - statement_columns& sc_; - strings& from_; - const view_relationship_map& rel_map_; - - bool in_composite_; - qname table_prefix_; // Table corresponding to column_prefix_; - - // Set to the current pointer data member that we are traversing. - // - semantics::data_member* ptr_; - }; - - struct polymorphic_object_joins: object_columns_base, virtual context - { - typedef polymorphic_object_joins base; - - polymorphic_object_joins (semantics::class_& obj, - bool query, - size_t depth, - string const& alias = "", - user_section* section = 0) - : object_columns_base (true, true), - obj_ (obj), - query_ (query), - depth_ (depth), - section_ (section), - alias_ (alias) - { - // Get the table and id columns. - // - table_ = alias_.empty () - ? table_qname (obj_) - : quote_id (alias_ + "_" + table_name (obj_).uname ()); - - cols_->traverse (*id_member (obj_)); - } - - virtual void - traverse_object (semantics::class_& c) - { - // If section is specified, skip bases that don't add anything - // to load. - // - bool skip (false), stop (false); - if (section_ != 0) - { - skip = true; - - if (section_->object == &c) - { - user_section& s (*section_); - - if (s.total != 0 || s.optimistic ()) - skip = false; - - section_ = s.base; // Move to the next base. - - if (section_ == 0) - stop = true; // Stop at this base if there are no more overrides. - } - } - // Skip intermediates that don't add any data members. - // - else if (!query_) - { - column_count_type const& cc (column_count (c)); - if (cc.total == cc.id + cc.separate_load) - skip = true; - } - - if (!skip) - { - std::ostringstream cond; - - qname table (table_name (c)); - string alias (alias_.empty () - ? quote_id (table) - : quote_id (alias_ + "_" + table.uname ())); - - for (object_columns_list::iterator b (cols_->begin ()), i (b); - i != cols_->end (); - ++i) - { - if (i != b) - cond << " AND "; - - string qn (quote_id (i->name)); - cond << alias << '.' << qn << '=' << table_ << '.' << qn; - } - - string line ("LEFT JOIN " + quote_id (table)); - - if (!alias_.empty ()) - line += (need_alias_as ? " AS " : " ") + alias; - - line += " ON " + cond.str (); - - joins.push_back (line); - } - - if (!stop && --depth_ != 0) - inherits (c); - } - - public: - strings joins; - - strings::const_iterator - begin () const {return joins.begin ();} - - strings::const_iterator - end () const {return joins.end ();} - - private: - semantics::class_& obj_; - bool query_; - size_t depth_; - user_section* section_; - string alias_; - string table_; - instance cols_; - }; - - struct object_joins: object_columns_base, virtual context - { - typedef object_joins base; - - //@@ context::{cur,top}_object; might have to be created every time. - // - object_joins (semantics::class_& scope, - bool query, - size_t depth, - object_section* section = 0) - : object_columns_base (true, true, section), - query_ (query), - depth_ (depth), - table_ (table_qname (scope)), - id_ (*id_member (scope)) - { - id_cols_->traverse (id_); - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section. - // - return section_ == 0 || - *section_ == s || - (*section_ == main_section && !s.separate_load ()); - } - - virtual void - traverse_object (semantics::class_& c) - { - // If this is a derived type in a polymorphic hierarchy, then we - // need to include base joins, but do it in reverse order as well - // as switch the table name (base columns come from different - // tables). - // - semantics::class_* poly_root (polymorphic (c)); - if (poly_root != 0 && poly_root != &c) - { - names (c); - - if (query_ || --depth_ != 0) - { - table_ = table_qname (polymorphic_base (c)); - inherits (c); - } - } - else - object_columns_base::traverse_object (c); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references; they are joined by - // polymorphic_object_joins in a special way. - // - if (m.count ("polymorphic-ref")) - return; - - string t, a, dt, da; - std::ostringstream cond, dcond; // @@ diversion? - - // Derive table alias for this member. Generally, we want the - // alias to be based on the column name. This is straightforward - // for single-column references. In case of a composite id, we - // will need to use the column prefix which is based on the data - // member name, unless overridden by the user. In the latter - // case the prefix can be empty, in which case we will just - // fall back on the member's public name. - // - string alias; - { - string n; - - if (composite_wrapper (utype (*id_member (c)))) - { - n = column_prefix (m, key_prefix_, default_name_).prefix; - - if (n.empty ()) - n = public_name_db (m); - else if (n[n.size () - 1] == '_') - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - { - bool dummy; - n = column_name (m, key_prefix_, default_name_, dummy); - } - - alias = column_prefix_.prefix + n; - } - - semantics::class_* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - - semantics::class_* joined_obj (0); - - if (data_member_path* imp = inverse (m, key_prefix_)) - { - semantics::data_member& imf (*imp->front ()); - semantics::data_member& imb (*imp->back ()); - - // In a polymorphic hierarchy the inverse member can be in - // the base class, in which case we should use that table. - // - semantics::class_& imc ( - poly ? dynamic_cast (imf.scope ()) : c); - - if (container (imb)) - { - // This container is a direct member of the class so the table - // prefix is just the class table name. - // - t = table_qname (imc, *imp); - - // Container's value is our id. - // - instance id_cols; - id_cols->traverse (imb, utype (id_), "value", "value"); - - for (object_columns_list::iterator b (id_cols->begin ()), i (b), - j (id_cols_->begin ()); i != id_cols->end (); ++i, ++j) - { - - if (i != b) - cond << " AND "; - - cond << t << '.' << quote_id (i->name) << '=' << - table_ << '.' << quote_id (j->name); - } - - // Add the join for the object itself so that we are able to - // use it in the WHERE clause. - // - if (query_) - { - // Here we can use the most derived class instead of the - // one containing the inverse member. - // - qname const& table (table_name (c)); - - dt = quote_id (table); - da = quote_id (poly ? alias + "_" + table.uname () : alias); - - data_member_path& id (*id_member (c)); - - instance oid_cols, cid_cols; - oid_cols->traverse (id); - cid_cols->traverse (imb, utype (id), "id", "object_id", &c); - - for (object_columns_list::iterator b (cid_cols->begin ()), i (b), - j (oid_cols->begin ()); i != cid_cols->end (); ++i, ++j) - { - - if (i != b) - dcond << " AND "; - - dcond << da << '.' << quote_id (j->name) << '=' << - t << '.' << quote_id (i->name); - } - - joined_obj = &c; - } - } - else - { - qname const& table (table_name (imc)); - - t = quote_id (table); - a = quote_id (poly ? alias + "_" + table.uname () : alias); - - instance id_cols; - id_cols->traverse (imb, column_prefix (*imp)); - - for (object_columns_list::iterator b (id_cols->begin ()), i (b), - j (id_cols_->begin ()); i != id_cols->end (); ++i, ++j) - { - if (i != b) - cond << " AND "; - - cond << a << '.' << quote_id (i->name) << '=' << - table_ << '.' << quote_id (j->name); - } - - // If we are generating query, JOIN base/derived classes so - // that we can use their data in the WHERE clause. - // - if (query_) - joined_obj = &imc; - } - } - else if (query_) - { - // We need the join to be able to use the referenced object - // in the WHERE clause. - // - qname const& table (table_name (c)); - - t = quote_id (table); - a = quote_id (poly ? alias + "_" + table.uname () : alias); - - instance oid_cols (column_prefix_); - oid_cols->traverse (m); - - instance pid_cols; - pid_cols->traverse (*id_member (c)); - - for (object_columns_list::iterator b (pid_cols->begin ()), i (b), - j (oid_cols->begin ()); i != pid_cols->end (); ++i, ++j) - { - - if (i != b) - cond << " AND "; - - cond << a << '.' << quote_id (i->name) << '=' << - table_ << '.' << quote_id (j->name); - } - - joined_obj = &c; - } - - if (!t.empty ()) - { - string line ("LEFT JOIN "); - line += t; - - if (!a.empty ()) - line += (need_alias_as ? " AS " : " ") + a; - - line += " ON "; - line += cond.str (); - - joins.push_back (line); - } - - // Add dependent join (i.e., an object table join via the - // container table). - // - if (!dt.empty ()) - { - string line ("LEFT JOIN "); - line += dt; - - if (!da.empty ()) - line += (need_alias_as ? " AS " : " ") + da; - - line += " ON "; - line += dcond.str (); - - joins.push_back (line); - } - - // If we joined the object that is part of a polymorphic type - // hierarchy, then we may need join its bases as well as its - // derived types. This is only done for queries. - // - if (joined_obj != 0 && poly) - { - size_t depth (polymorphic_depth (*joined_obj)); - - // Join "up" (derived). - // - if (joined_obj != &c) - { - bool t (true); //@@ (im)perfect forward. - size_t d (polymorphic_depth (c) - depth); //@@ (im)perfect forward. - instance j (*joined_obj, t, d, alias); - j->traverse (c); - joins.insert (joins.end (), j->joins.begin (), j->joins.end ()); - } - - // Join "down" (base). - // - if (joined_obj != poly_root) - { - bool t (true); //@@ (im)perfect forward. - size_t d (depth - 1); //@@ (im)perfect forward. - instance j (*joined_obj, t, d, alias); - j->traverse (polymorphic_base (*joined_obj)); - joins.insert (joins.end (), j->joins.begin (), j->joins.end ()); - } - } - } - - public: - strings joins; - - strings::const_iterator - begin () const {return joins.begin ();} - - strings::const_iterator - end () const {return joins.end ();} - - private: - bool query_; - size_t depth_; - string table_; - data_member_path& id_; - instance id_cols_; - }; - - // Check that eager object pointers in the objects that a view loads - // can be loaded from the cache (i.e., they have session support - // enabled). - // - struct view_object_check: object_members_base - { - typedef view_object_check base; - - view_object_check (view_object& vo, view_relationship_map& rm) - : object_members_base (false, &main_section), - session_ (false), vo_ (vo), rel_map_ (rm) {} - - virtual bool - section_test (data_member_path const& mp) - { - // Include eager loaded members into the main section. - // - object_section& s (section (mp)); - return *section_ == s || !s.separate_load (); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - check (m, inverse (m), utype (m), c); - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - semantics::type& vt (container_vt (m)); - - if (semantics::class_* cvt = composite_wrapper (vt)) - { - // Check this composite value for any pointers. - // - instance t (vo_, rel_map_); - t->traverse (*cvt); - - session_ = session_ || t->session_; - } - else if (semantics::class_* c = object_pointer (vt)) - check (m, inverse (m, "value"), vt, *c); - } - - void - check (semantics::data_member& m, - data_member_path* imp, - semantics::type& pt, // Pointer type. - semantics::class_& c) - { - // We don't care about lazy pointers. - // - if (lazy_pointer (pt)) - return; - - // First check the pointed-to object recursively. - // - if (!c.count ("view-object-check-seen")) - { - c.set ("view-object-check-seen", true); - instance t (vo_, rel_map_); - t->traverse (c); - - // We may come again for another view. - // - c.remove ("view-object-check-seen"); - - session_ = session_ || t->session_; - } - - // See if the pointed-to object in this relationship is loaded - // by this view. - // - typedef view_relationship_map::const_iterator iterator; - - std::pair r ( - rel_map_.equal_range (imp != 0 ? *imp : member_path_)); - - if (r.first == r.second) - return; // This relationship does not figure in the view. - - view_object& vo (*(imp != 0 - ? r.first->second.first - : r.first->second.second)); - - assert (vo.obj == &c); // Got the above right? - - if (vo.ptr == 0) - return; // This object is not loaded by the view. - - // The pointed-to object in this relationship is loaded - // by the view. The hard question, of course, is whether - // it has anything to do with us. We assume it does. - // - if (!session (c)) - { - // Always direct data member. - // - semantics::class_& v ( - dynamic_cast (vo.ptr->scope ())); - - location const& l1 (c.location ()); - location const& l2 (m.location ()); - location const& l3 (vo_.ptr->location ()); - location const& l4 (vo.ptr->location ()); - - string on (class_name (c)); - string vn (class_name (v)); - - error (l1) << "object '" << on << "' has session support disabled " - << "but may be loaded by view '" << vn << "' via " - << "several data members" << endl; - - info (l2) << "indirectly via this data member..." << endl; - info (l3) << "...as a result of this object load" << endl; - info (l4) << "and directly as a result of this load" << endl; - info (l1) << "session support is required to only load one copy " - << "of the object" << endl; - info (l1) << "and don't forget to create a session instance when " - << "using this view" << endl; - - throw operation_failed (); - } - - session_ = true; - } - - bool session_; - - private: - view_object& vo_; - view_relationship_map& rel_map_; - }; - - // - // bind - // - - struct bind_member: virtual member_base - { - typedef bind_member base; - - // NULL section means we are generating object bind(). - // - bind_member (string const& var = string (), - string const& arg = string (), - object_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - arg_override_ (arg) {} - - bind_member (string const& var, - string const& arg, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), - arg_override_ (arg) {} - - protected: - string arg_override_; - }; - - template - struct bind_member_impl: bind_member, virtual member_base_impl - { - typedef bind_member_impl base_impl; - - bind_member_impl (base const& x): base (x) {} - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - // Treat version as present in every section. - // - if (section_ != 0 && !version (mi.m) && *section_ != section (mi.m)) - return false; - - // Ignore polymorphic id references; they are bound in a special - // way. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - std::ostringstream ostr; - ostr << "b[n]"; - b = ostr.str (); - - arg = arg_override_.empty () ? string ("i") : arg_override_; - - if (var_override_.empty ()) - { - // Ignore inverse, separately-loaded members in the main - // section (nothing to persist). - // - if (section_ == 0 && separate_load (mi.m) && inverse (mi.m)) - return false; - - semantics::class_* comp (composite (mi.t)); - - os << "// " << mi.m.name () << endl - << "//" << endl; - - // Order of these tests is important. - // - if (!insert_send_auto_id && auto_ (mi.m)) - os << "if (sk != statement_insert && sk != statement_update)" - << "{"; - else if (section_ == 0 && separate_load (mi.m)) - os << "if (sk == statement_insert)" - << "{"; - else if (inverse (mi.m, key_prefix_) || version (mi.m)) - os << "if (sk == statement_select)" - << "{"; - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - else if (!readonly (*context::top_object)) - { - if (id (mi.m) || - readonly (mi.m) || - (comp != 0 && readonly (*comp)) || - (section_ == 0 && separate_update (mi.m))) - os << "if (sk != statement_update)" - << "{"; - } - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - // If this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" - << "{"; - } - } - - return true; - } - - virtual void - post (member_info& mi) - { - if (var_override_.empty ()) - { - semantics::class_* comp (composite (mi.t)); - - // We need to increment the index even if we skipped this - // member due to the schema version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - os << "}"; - - if (mi.ptr != 0 && view_member (mi.m)) - { - // See column_count_impl for details on what's going on here. - // - column_count_type cc; - if (semantics::class_* root = polymorphic (*mi.ptr)) - { - for (semantics::class_* b (mi.ptr);; b = &polymorphic_base (*b)) - { - column_count_type const& ccb (column_count (*b)); - - cc.total += ccb.total - (b != root ? ccb.id : 0); - cc.separate_load += ccb.separate_load; - - if (b == root) - break; - } - } - else - cc = column_count (*mi.ptr); - - os << "n += " << cc.total - cc.separate_load << "UL;"; - } - else if (comp != 0) - { - bool ro (readonly (*comp)); - column_count_type const& cc (column_count (*comp)); - - os << "n += " << cc.total << "UL"; - - // select = total - // insert = total - inverse - // update = total - inverse - readonly - // - if (cc.inverse != 0 || (!ro && cc.readonly != 0)) - { - os << " - (" << endl - << "sk == statement_select ? 0 : "; - - if (cc.inverse != 0) - os << cc.inverse << "UL"; - - if (!ro && cc.readonly != 0) - { - if (cc.inverse != 0) - os << " + "; - - os << "(" << endl - << "sk == statement_insert ? 0 : " << - cc.readonly << "UL)"; - } - - os << ")"; - } - - os << ";"; - } - else - os << "n++;"; - - bool block (false); - - // The same logic as in pre(). - // - if (!insert_send_auto_id && auto_ (mi.m)) - block = true; - else if (section_ == 0 && separate_load (mi.m)) - block = true; - else if (inverse (mi.m, key_prefix_) || version (mi.m)) - block = true; - else if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c)) || - (section_ == 0 && separate_update (mi.m))) - block = true; - } - - if (block) - os << "}"; - else - os << endl; - } - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. - // - if (view_member (mi.m)) - { - semantics::class_& c (*mi.ptr); - semantics::class_* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - os << "object_traits_impl< " << class_fq_name (c) << ", id_" << - db << " >::bind (" << endl - << "b + n, " << (poly_derived ? "0, 0, " : "") << arg << "." << - mi.var << "value, sk" << (versioned (c) ? ", svm" : "") << ");"; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - os << "composite_value_traits< " << mi.fq_type () << ", id_" << - db << " >::bind (" << endl - << "b + n, " << arg << "." << mi.var << "value, sk" << - (versioned (*composite (mi.t)) ? ", svm" : "") << ");"; - } - - protected: - string b; - string arg; - }; - - struct bind_base: traversal::class_, virtual context - { - typedef bind_base base; - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - // If the derived class is readonly, then we will never be - // called with sk == statement_update. - // - bool ro (readonly (c)); - bool check (ro && !readonly (*context::top_object)); - - if (check) - os << "if (sk != statement_update)" - << "{"; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::bind (b + n, i, sk" << - (versioned (c) ? ", svm" : "") << ");"; - - column_count_type const& cc (column_count (c)); - - os << "n += "; - - // select = total - separate_load - // insert = total - inverse - optimistic_managed - id(auto & !sending) - // update = total - inverse - optimistic_managed - id - readonly - - // separate_update - // - size_t select (cc.total - cc.separate_load); - size_t insert (cc.total - cc.inverse - cc.optimistic_managed); - size_t update (insert - cc.id - cc.readonly - cc.separate_update); - - data_member_path* id; - if (!insert_send_auto_id && (id = id_member (c)) != 0 && auto_ (*id)) - insert -= cc.id; - - if (select == insert && insert == update) - os << select << "UL;"; - else if (select != insert && insert == update) - os << "sk == statement_select ? " << select << "UL : " << - insert << "UL;"; - else if (select == insert && insert != update) - os << "sk == statement_update ? " << update << "UL : " << - select << "UL;"; - else - os << "sk == statement_select ? " << select << "UL : " << - "sk == statement_insert ? " << insert << "UL : " << - update << "UL;"; - - if (check) - os << "}"; - else - os << endl; - } - }; - - // - // grow - // - - struct grow_member: virtual member_base - { - typedef grow_member base; - - grow_member (size_t& index, - string const& var = string (), - user_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - index_ (index) {} - - grow_member (size_t& index, - string const& var, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), index_ (index) {} - - protected: - size_t& index_; - }; - - template - struct grow_member_impl: grow_member, virtual member_base_impl - { - typedef grow_member_impl base_impl; - - grow_member_impl (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - // If we have a key prefix (container), then it can't be in a section - // (while mi.m can). The same for top-level -- if we got called, then - // we shouldn't ignore it. (Same logic as in has_grow_member). - // - if (!(!key_prefix_.empty () || top_level_ || - (section_ == 0 && !separate_load (mi.m)) || - (section_ != 0 && *section_ == section (mi.m)))) - return false; - - // Ignore polymorphic id references; they are not returned by - // the select statement. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - std::ostringstream ostr; - ostr << "t[" << index_ << "UL]"; - e = ostr.str (); - - if (var_override_.empty ()) - { - os << "// " << mi.m.name () << endl - << "//" << endl; - - semantics::class_* comp (composite (mi.t)); - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - // If this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" - << "{"; - } - } - - return true; - } - - virtual void - post (member_info& mi) - { - semantics::class_* comp (composite (mi.t)); - - if (var_override_.empty ()) - { - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - os << "}"; - } - - if (mi.ptr != 0 && view_member (mi.m)) - { - // See column_count_impl for details on what's going on here. - // - column_count_type cc; - if (semantics::class_* root = polymorphic (*mi.ptr)) - { - for (semantics::class_* b (mi.ptr);; b = &polymorphic_base (*b)) - { - column_count_type const& ccb (column_count (*b)); - - cc.total += ccb.total - (b != root ? ccb.id : 0); - cc.separate_load += ccb.separate_load; - - if (b == root) - break; - } - } - else - cc = column_count (*mi.ptr); - - index_ += cc.total - cc.separate_load; - } - else if (comp != 0) - index_ += column_count (*comp).total; - else - index_++; - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. They - // can only be immediate members of the view class. - // - if (view_member (mi.m)) - { - semantics::class_& c (*mi.ptr); - - os << "if (object_traits_impl< " << class_fq_name (c) << - ", id_" << db << " >::grow (" << endl - << "i." << mi.var << "value, t + " << index_ << "UL" << - (versioned (c) ? ", svm" : "") << "))" << endl - << "grew = true;" - << endl; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - semantics::class_& c (*composite (mi.t)); - - os << "if (composite_value_traits< " << mi.fq_type () << - ", id_" << db << " >::grow (" << endl - << "i." << mi.var << "value, t + " << index_ << "UL" << - (versioned (c) ? ", svm" : "") << "))" << endl - << "grew = true;" - << endl; - } - - protected: - string e; - }; - - struct grow_base: traversal::class_, virtual context - { - typedef grow_base base; - - grow_base (size_t& index): index_ (index) {} - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - os << "if ("; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::grow (" << endl - << "i, t + " << index_ << "UL" << - (versioned (c) ? ", svm" : "") << "))" << endl - << "grew = true;" - << endl; - - index_ += column_count (c).total; - } - - protected: - size_t& index_; - }; - - // - // init image - // - - struct init_image_member: virtual member_base - { - typedef init_image_member base; - - init_image_member (string const& var = string (), - string const& member = string (), - user_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - member_override_ (member) - { - } - - init_image_member (string const& var, - string const& member, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), - member_override_ (member) - { - } - - protected: - string member_override_; - }; - - template - struct init_image_member_impl: init_image_member, - virtual member_base_impl - { - typedef init_image_member_impl base_impl; - - init_image_member_impl (base const& x) - : base (x), - member_database_type_id_ (base::type_override_, - base::custom_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual void - set_null (member_info&) = 0; - - virtual void - check_accessor (member_info&, member_access&) {} - - virtual bool - pre (member_info& mi) - { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (section_ != 0 && *section_ != section (mi.m)) - return false; - - // Ignore polymorphic id references; they are initialized in a - // special way. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - semantics::class_* comp (composite (mi.t)); - - if (!member_override_.empty ()) - { - member = member_override_; - os << "{"; - } - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - // If we don't send auto id in INSERT statement, ignore this - // member altogether (we never send auto id in UPDATE). - // - if (!insert_send_auto_id && auto_ (mi.m)) - return false; - - os << "// " << mi.m.name () << endl - << "//" << endl; - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - // If this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" - << "{"; - } - - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - if (id (mi.m) || - readonly (mi.m) || - (section_ == 0 && separate_update (mi.m)) || - (comp != 0 && readonly (*comp))) // Can't be id. - { - // If we are generating section init(), then sk can only be - // statement_update. - // - if (section_ == 0) - os << "if (sk == statement_insert)"; - } - } - - os << "{"; - - if (discriminator (mi.m)) - member = "di.discriminator"; - else - { - // Get the member using the accessor expression. - // - member_access& ma (mi.m.template get ("get")); - - // Make sure this kind of member can be accessed with this - // kind of accessor (database-specific, e.g., streaming). - // - if (comp == 0) - check_accessor (mi, ma); - - // If this is not a synthesized expression, then output - // its location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // Use the original type to form the const reference. VC++ - // cannot grok the constructor syntax. - // - os << member_ref_type (mi.m, true, "v") << " =" << endl - << " " << ma.translate ("o") << ";" - << endl; - - member = "v"; - } - } - - // Translate. - // - if (mi.ct != 0) - { - os << "// From " << location_string (mi.ct->loc, true) << endl - << type_ref_type (*mi.ct->as, mi.ct->as_hint, true, "vt") << - " =" << endl - << " " << mi.ct->translate_to (member) << ";" - << endl; - - member = "vt"; - } - - // If this is a wrapped composite value, then we need to "unwrap" - // it. If this is a NULL wrapper, then we also need to handle that. - // For simple values this is taken care of by the value_traits - // specializations. - // - if (mi.wrapper != 0 && comp != 0) - { - // The wrapper type, not the wrapped type. - // - string const& wt (mi.fq_type (false)); - - // If this is a NULL wrapper and the member can be NULL, then - // we need to handle the NULL value. - // - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - { - os << "if (wrapper_traits< " << wt << " >::get_null (" << - member << "))" << endl - << "composite_value_traits< " << mi.fq_type () << ", id_" << - db << " >::set_null (" << endl - << "i." << mi.var << "value, sk" << - (versioned (*comp) ? ", svm" : "") << ");" - << "else" - << "{"; - } - - os << "const" << mi.fq_type () << "& vw = " << endl - << " wrapper_traits< " + wt + " >::get_ref (" + member + ");" - << endl; - - member = "vw"; - } - - if (discriminator (mi.m)) - os << "const info_type& di (map->find (typeid (o)));" - << endl; - - if (mi.ptr != 0) - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& pt (utype (mi.m, key_prefix_)); - - type = "obj_traits::id_type"; - - // Handle NULL pointers and extract the id. - // - os << "typedef object_traits< " << class_fq_name (*mi.ptr) << - " > obj_traits;"; - - if (weak_pointer (pt)) - { - os << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << - " > wptr_traits;" - << "typedef odb::pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << - " > ptr_traits;" - << endl; - - os << "bool is_null (ptr_traits::null_ptr (" << member << "));" - << "if (!is_null)" - << "{" - << "const " << type << "& ptr_id (" << endl; - - if (lazy_pointer (pt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "ptr_id"; - } - else if (comp != 0) - type = mi.fq_type (); - else - { - type = mi.fq_type (); - - // Indicate to the value_traits whether this column can be NULL. - // - os << "bool is_null (" << null (mi.m, key_prefix_) << ");"; - } - - if (comp != 0) - traits = "composite_value_traits< " + type + ", id_" + - db.string () + " >"; - else - { - db_type_id = member_database_type_id_->database_type_id (mi.m); - traits = db.string () + "::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) - { - semantics::class_* comp (composite (mi.t)); - - if (mi.ptr != 0) - { - os << "}" - << "else" << endl; - - if (!null (mi.m, key_prefix_)) - os << "throw null_pointer ();"; - else if (comp != 0) - os << traits << "::set_null (i." << mi.var << "value, sk" << - (versioned (*comp) ? ", svm" : "") << ");"; - else - set_null (mi); - } - - if (mi.wrapper != 0 && comp != 0) - { - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - os << "}"; - } - - os << "}"; - - if (member_override_.empty ()) - { - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - os << "}"; - } - } - - virtual void - traverse_composite (member_info& mi) - { - bool grow (generate_grow && - context::grow (mi.m, mi.t, mi.ct, key_prefix_)); - - if (grow) - os << "if ("; - - os << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk"; - - if (versioned (*composite (mi.t))) - os << "," << endl - << "svm"; - - os << ")"; - - if (grow) - os << ")" << endl - << "grew = true"; - - os << ";"; - } - - protected: - string type; - string db_type_id; - string member; - string traits; - - instance member_database_type_id_; - }; - - struct init_image_base: traversal::class_, virtual context - { - typedef init_image_base base; - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - // If the derived class is readonly, then we will never be - // called with sk == statement_update. - // - bool check (readonly (c) && !readonly (*context::top_object)); - - if (check) - os << "if (sk != statement_update)" - << "{"; - - if (generate_grow) - os << "if ("; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::init (i, o, sk" << - (versioned (c) ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "grew = true"; - - os << ";"; - - if (check) - os << "}"; - else - os << endl; - } - }; - - // - // init value - // - - struct init_value_member: virtual member_base - { - typedef init_value_member base; - - init_value_member (string const& member = string (), - string const& var = string (), - bool ignore_implicit_discriminator = true, - user_section* section = 0) - : member_base (var, 0, 0, string (), string (), section), - member_override_ (member), - ignore_implicit_discriminator_ (ignore_implicit_discriminator) - { - } - - init_value_member (string const& var, - string const& member, - semantics::type& t, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base (var, &t, ct, fq_type, key_prefix), - member_override_ (member), - ignore_implicit_discriminator_ (true) - { - } - - virtual void - get_null (string const& /*var*/) const {}; - - protected: - string member_override_; - bool ignore_implicit_discriminator_; - }; - - template - struct init_value_member_impl: init_value_member, - virtual member_base_impl - { - typedef init_value_member_impl base_impl; - - init_value_member_impl (base const& x) - : base (x), - member_database_type_id_ (base::type_override_, - base::custom_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - typedef typename member_base_impl::member_info member_info; - - using member_base_impl::container; - - virtual void - get_null (string const& var) const = 0; - - virtual void - check_modifier (member_info&, member_access&) {} - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (section_ != 0 && *section_ != section (mi.m)) - return false; - - // Ignore polymorphic id references; they are initialized in a - // special way. - // - if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) - return false; - - // Ignore implicit discriminators. - // - if (ignore_implicit_discriminator_ && discriminator (mi.m)) - return false; - - semantics::class_* comp (composite (mi.t)); - - if (!member_override_.empty ()) - { - os << "{"; - member = member_override_; - } - else - { - // Ignore separately loaded members. - // - if (section_ == 0 && separate_load (mi.m)) - return false; - - os << "// " << mi.m.name () << endl - << "//" << endl; - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - // If this is a composite member, see if it is summarily - // added/deleted. - // - if (comp != 0) - { - unsigned long long cav (added (*comp)); - unsigned long long cdv (deleted (*comp)); - - if (cav != 0 && (av == 0 || av < cav)) - av = cav; - - if (cdv != 0 && (dv == 0 || dv > cdv)) - dv = cdv; - } - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")"; - } - - os << "{"; - - if (mi.ptr != 0 && view_member (mi.m)) - return true; // That's enough for the object pointer in view. - - // Set the member using the modifier expression. - // - member_access& ma (mi.m.template get ("set")); - - // Make sure this kind of member can be modified with this - // kind of accessor (database-specific, e.g., streaming). - // - if (comp == 0) - check_modifier (mi, ma); - - // If this is not a synthesized expression, then output - // its location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // See if we are modifying via a reference or proper modifier. - // - if (ma.placeholder ()) - os << member_val_type (mi.m, false, "v") << ";" - << endl; - else - { - // Use the original type to form the reference. VC++ cannot - // grok the constructor syntax. - // - os << member_ref_type (mi.m, false, "v") << " =" << endl - << " "; - - // If this member is const and we have a synthesized direct - // access, then cast away constness. Otherwise, we assume - // that the user-provided expression handles this. - // - bool cast (mi.cq && ma.direct ()); - if (cast) - os << "const_cast< " << member_ref_type (mi.m, false) << - " > (" << endl; - - os << ma.translate ("o"); - - if (cast) - os << ")"; - - os << ";" - << endl; - } - - member = "v"; - } - - // Translate. - // - if (mi.ct != 0) - { - os << type_val_type (*mi.ct->as, mi.ct->as_hint, false, "vt") << ";" - << endl; - - translate_member = member; - member = "vt"; - } - - // If this is a wrapped composite value, then we need to "unwrap" it. - // If this is a NULL wrapper, then we also need to handle that. For - // simple values this is taken care of by the value_traits - // specializations. - // - if (mi.wrapper != 0 && comp != 0) - { - // The wrapper type, not the wrapped type. - // - string const& wt (mi.fq_type (false)); - - // If this is a NULL wrapper and the member can be NULL, then - // we need to handle the NULL value. - // - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - { - os << "if (composite_value_traits< " << mi.fq_type () << - ", id_" << db << " >::get_null (" << endl - << "i." << mi.var << "value" << - (versioned (*comp) ? ", svm" : "") << "))" << endl - << "wrapper_traits< " << wt << " >::set_null (" << member + ");" - << "else" - << "{"; - } - - os << mi.fq_type () << "& vw =" << endl - << " wrapper_traits< " + wt + " >::set_ref (" + member + ");" - << endl; - - wrap_member = member; - member = "vw"; - } - - if (mi.ptr != 0) - { - type = "obj_traits::id_type"; - - // Handle NULL pointers and extract the id. - // - os << "typedef object_traits< " << class_fq_name (*mi.ptr) << - " > obj_traits;" - << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << - " > ptr_traits;" - << endl; - - os << "if ("; - - if (comp != 0) - os << "composite_value_traits< " << type << ", id_" << db << - " >::get_null (" << endl - << "i." << mi.var << "value" << - (versioned (*comp) ? ", svm" : "") << ")"; - else - get_null (mi.var); - - os << ")" << endl; - - // Don't throw null_pointer if we can't have NULLs and the pointer - // is NULL since this can be useful during migration. Instead, we - // rely on the database enforcing this. - // - os << member << " = ptr_traits::pointer_type ();"; - - os << "else" - << "{"; - - os << type << " ptr_id;"; - - member = "ptr_id"; - } - else - type = mi.fq_type (); - - if (comp != 0) - traits = "composite_value_traits< " + type + ", id_" + - db.string () + " >"; - else - { - db_type_id = member_database_type_id_->database_type_id (mi.m); - traits = db.string () + "::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) - { - if (mi.ptr != 0) - { - if (view_member (mi.m)) - { - // The object pointer in view doesn't need any of this. - os << "}"; - return; - } - - // Restore the member variable name. - // - member = member_override_.empty () ? "v" : member_override_; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& pt (utype (mi.m, key_prefix_)); - - if (lazy_pointer (pt)) - os << member << " = ptr_traits::pointer_type (" << endl - << "*static_cast<" << db << "::database*> (db), ptr_id);"; - else - { - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "static_cast<" << db << "::database*> (db)->load<" << endl - << " obj_traits::object_type > (ptr_id));"; - - // If we are loading into an eager weak pointer, make sure there - // is someone else holding a strong pointer to it (normally a - // session). Otherwise, the object will be loaded and immediately - // deleted. Besides not making much sense, this also breaks the - // delayed loading machinery which expects the object to be around - // at least until the top-level load() returns. - // - if (weak_pointer (pt)) - { - os << endl - << "if (odb::pointer_traits<" << - "ptr_traits::strong_pointer_type>::null_ptr (" << endl - << "ptr_traits::lock (" << member << ")))" << endl - << "throw session_required ();"; - } - } - - os << "}"; - } - - // Wrap back (so to speak). - // - if (mi.wrapper != 0 && composite (mi.t) != 0) - { - if (null (mi.m, key_prefix_) && - mi.wrapper->template get ("wrapper-null-handler")) - os << "}"; - - member = wrap_member; - } - - // Untranslate. - // - if (mi.ct != 0) - { - //@@ Use move() in C++11? Or not. - // - os << "// From " << location_string (mi.ct->loc, true) << endl - << translate_member << " = " << - mi.ct->translate_from (member) << ";"; - - member = translate_member; - } - - // Call the modifier if we are using a proper one. - // - if (member_override_.empty ()) - { - member_access& ma (mi.m.template get ("set")); - - if (ma.placeholder ()) - { - // If this is not a synthesized expression, then output its - // location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ( - "o", "v", "*static_cast<" + db.string () + "::database*> (db)") - << ";"; - } - } - - os << "}"; - } - - virtual void - traverse_pointer (member_info& mi) - { - // Object pointers in views require special treatment. - // - if (view_member (mi.m)) - { - // This is the middle part. The pre and post parts are generated - // by init_view_pointer_member below. - // - using semantics::class_; - - class_& c (*mi.ptr); - class_* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - - string o_tp (mi.var + "object_type"); - string o_tr (mi.var + "object_traits"); - string r_tr (poly_derived ? mi.var + "root_traits" : o_tr); - string i_tp (mi.var + "info_type"); - - string id (mi.var + "id"); - string o (mi.var + "o"); - string pi (mi.var + "pi"); // Polymorphic type info. - - // If load_() will be loading containers or the rest of the - // polymorphic object, then we need to perform several extra - // things. We need to initialize the id image in the object - // statements. We also have to lock the statements so that - // nobody messes up this id image. - // - bool init_id ( - poly || - has_a (c, test_container | include_eager_load, &main_section)); - - bool versioned (context::versioned (c)); - - os << "if (" << o << " != 0)" - << "{"; - - if (poly) - os << "callback_event ce (callback_event::pre_load);" - << pi << "->dispatch (" << i_tp << "::call_callback, " << - "*db, " << o << ", &ce);"; - else - os << o_tr << "::callback (*db, *" << o << - ", callback_event::pre_load);"; - - os << o_tr << "::init (*" << o << ", i." << mi.var << "value, db" << - (versioned ? ", svm" : "") << ");"; - - // Call load_() to load the rest of the object (containers, etc). - // - if (id_member (poly ? *poly_root : c) != 0) - { - const char* s (poly_derived ? "osts" : "sts"); - - os << o_tr << "::statements_type& " << s << " (" << endl - << "conn.statement_cache ().find_object<" << o_tp << "> ());"; - - if (poly_derived) - os << r_tr << "::statements_type& sts (osts.root_statements ());"; - - if (init_id) - { - // This can only be top-level call so lock must succeed. - // - os << r_tr << "::statements_type::auto_lock l (sts);" - << "assert (l.locked ()) /* Must be a top-level call. */;" - << endl - << r_tr << "::id_image_type& i (sts.id_image ());" - << r_tr << "::init (i, " << id << ");" - << db << "::binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || " << - "idb.version == 0)" - << "{" - << r_tr << "::bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;"; - if (optimistic (poly ? *poly_root : c) != 0) - os << "sts.optimistic_id_image_binding ().version++;"; - os << "}"; - } - - os << o_tr << "::load_ (" << s << ", *" << o << ", false" << - (versioned ? ", svm" : "") << ");"; - - // Load the dynamic part of the object unless static and dynamic - // types are the same. - // - if (poly) - os << endl - << "if (" << pi << " != &" << o_tr << "::info)" - << "{" - << "std::size_t d (" << o_tr << "::depth);" - << pi << "->dispatch (" << i_tp << "::call_load, *db, " << - o << ", &d);" - << "}"; - - if (init_id) - os << "sts.load_delayed (" << (versioned ? "&svm" : "0") << ");" - << "l.unlock ();"; - } - - os << "}"; - } - else - member_base_impl::traverse_pointer (mi); - } - - virtual void - traverse_composite (member_info& mi) - { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db"; - - if (versioned (*composite (mi.t))) - os << "," << endl - << "svm"; - - os << ");" - << endl; - } - - protected: - string type; - string db_type_id; - string traits; - string member; - string translate_member; // Untranslated member. - string wrap_member; // Wrapped member. - - instance member_database_type_id_; - }; - - // This class generates the pre and post parts. The middle part is - // generated by init_value_member above. - // - struct init_view_pointer_member: virtual member_base, - member_base_impl // Dummy SQL type. - { - typedef init_view_pointer_member base; - - init_view_pointer_member (bool pre, init_value_member const& ivm) - : member_base (0, 0, string (), string (), 0), - pre_ (pre), init_value_member_ (ivm) {} - - virtual bool - pre (member_info& mi) - { - // Only interested in object pointers inside views. - // - return mi.ptr != 0 && view_member (mi.m); - } - - virtual void - traverse_pointer (member_info& mi) - { - using semantics::class_; - - class_& c (*mi.ptr); - bool abst (abstract (c)); - class_* poly_root (polymorphic (c)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1); - - data_member_path* idm (id_member (poly ? *poly_root : c)); - - os << "// " << mi.m.name () << (pre_ ? " pre" : " post") << endl - << "//" << endl; - - string o_tp (mi.var + "object_type"); - string o_tr (mi.var + "object_traits"); - string r_tr (poly_derived ? mi.var + "root_traits" : o_tr); - string i_tp (mi.var + "info_type"); - string p_tp (mi.var + "pointer_type"); - string p_tr (mi.var + "pointer_traits"); - string c_tr (mi.var + "cache_traits"); - - string id (mi.var + "id"); // Object id. - string p (mi.var + "p"); // Object pointer. - string pg (mi.var + "pg"); // Pointer guard. - string ig (mi.var + "ig"); // Cache insert guard. - string o (mi.var + "o"); // Object. - string pi (mi.var + "pi"); // Polymorphic type info. - - bool op_raw (c.get ("object-pointer-raw")); - bool mp_raw (utype (mi.m).is_a ()); - - // Output aliases and variables before any schema version if- - // blocks since we need to be able to access them across all - // three parts. - // - if (pre_) - { - os << "typedef " << class_fq_name (c) << " " << o_tp << ";" - << "typedef object_traits_impl<" << o_tp << ", id_" << db << - "> " << o_tr << ";"; - - if (poly_derived) - os << "typedef " << o_tr << "::root_traits " << r_tr << ";"; - - if (poly) - os << "typedef " << r_tr << "::info_type " << i_tp << ";"; - - os << "typedef " << r_tr << "::pointer_type " << p_tp << ";" - << "typedef " << r_tr << "::pointer_traits " << p_tr << ";"; - if (idm != 0) - os << "typedef " << r_tr << "::pointer_cache_traits " << - c_tr << ";"; - os << endl; - - if (idm != 0) - os << r_tr << "::id_type " << id << ";"; - os << p_tp << " " << p << (op_raw ? " = 0" : "") << ";" // VC++ - << p_tr << "::guard " << pg << ";"; - if (idm != 0) - os << c_tr << "::insert_guard " << ig << ";"; - os << o_tp << "* " << o << " (0);"; - - if (poly) - os << "const " << i_tp << "* " << pi << " = 0;"; // VC++ - - os << endl; - } - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (mi.m)); - unsigned long long dv (deleted (mi.m)); - - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")"; - } - - os << "{"; - - if (pre_) - { - string id_im; - if (idm != 0) - { - // Check for NULL. - // - string id_var; - { - id_im = mi.var + "value"; - - // In a polymorphic class, the id is in the root image. - // - for (size_t i (0); i < poly_depth - 1; ++i) - id_im += (i == 0 ? ".base" : "->base"); - - string n; - for (data_member_path::const_iterator i (idm->begin ()); - i != idm->end (); - ++i) - { - // The same logic as in member_base. - // - if (!n.empty ()) - n += "value."; // Composite. - - string const& name ((*i)->name ()); - n += name; - - if (n[n.size () - 1] != '_') - n += '_'; - } - - id_var = id_im + (poly_derived ? "->" : ".") + n; - id_im = (poly_derived ? "*i." : "i.") + id_im; - } - - os << "if ("; - - if (semantics::class_* comp = composite (mi.t)) - os << "!composite_value_traits< " << o_tr << "::id_type, id_" << - db << " >::get_null (" << endl - << "i." << id_var << "value" << - (versioned (*comp) ? ", svm" : "") << ")"; - else - { - os << "!("; - init_value_member_.get_null (id_var); - os << ")"; - } - - os << ")" - << "{"; - - // Check cache. - // - os << id << " = " << r_tr << "::id (" << id_im << ");" - << p << " = " << c_tr << "::find (*db, " << id << ");" - << endl; - - os << "if (" << p_tr << "::null_ptr (" << p << "))" - << "{"; - } - - // To support by-value object loading, we are going to load - // into an existing instance if the pointer is already not - // NULL. To limit the potential misuse (especially when it - // comes to sessions), we are going to limit this support - // only to raw pointers. Furthermore, we will only insert - // such an object into the cache if its object pointer is - // also raw. - // - if (mp_raw && !poly) - { - // Get the member using the accessor expression. - // - member_access& ma (mi.m.get ("get")); - - // If this is not a synthesized expression, then output - // its location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // Use the original type to form the const reference. VC++ - // cannot grok the constructor syntax. - // - os << member_ref_type (mi.m, true, "m") << " =" << endl - << " " << ma.translate ("o") << ";" - << endl; - - os << "if (m != 0)" - << "{"; - - if (op_raw) - os << ig << ".reset (" << c_tr << "::insert (*db, " << id << - ", m));"; - - os << o << " = m;" - << "}" - << "else" - << "{"; - } - - if (poly) - { - os << r_tr << "::discriminator_type d (" << endl - << r_tr << "::discriminator (" << id_im << "));"; - - if (abst) - os << pi << " = &" << r_tr << "::map->find (d);"; - else - os << pi << " = (d == " << o_tr << "::info.discriminator" << endl - << "? &" << o_tr << "::info" << endl - << ": &" << r_tr << "::map->find (d));"; - - os << p << " = " << pi << "->create ();"; - } - else - os << p << " = object_factory<" << o_tp << ", " << p_tp << - ">::create ();"; - - os << pg << ".reset (" << p << ");"; - if (idm != 0) - os << ig << ".reset (" << c_tr << "::insert (*db, " << id << - ", " << p << "));"; - - if (poly_derived) - os << o << " = static_cast<" << o_tp << "*> (" << p_tr << - "::get_ptr (" << p << "));"; - else - os << o << " = " << p_tr << "::get_ptr (" << p << ");"; - - if (mp_raw && !poly) - os << "}"; - - if (idm != 0) - os << "}" // Cache. - << "}"; // NULL. - } - else - { - os << "if (" << o << " != 0)" - << "{"; - - if (poly) - os << "callback_event ce (callback_event::post_load);" - << pi << "->dispatch (" << i_tp << "::call_callback, " << - "*db, " << o << ", &ce);"; - else - os << o_tr << "::callback (*db, *" << o << - ", callback_event::post_load);"; - - if (idm != 0) - { - if (mp_raw && !op_raw && !poly) - os << "if (!" << p_tr << "::null_ptr (" << p << "))" - << "{"; - - os << c_tr << "::load (" << ig << ".position ());" - << ig << ".release ();"; - - if (mp_raw && !op_raw && !poly) - os << "}"; - } - - os << pg << ".release ();"; - - os << "}"; - - // If member pointer is not raw, then result is in p. - // If both member and object are raw, then result is in o. - // If member is raw but object is not, then result is in - // p if it is not NULL, and in o (either NULL or the same - // as the member value) otherwise. - // - member_access& ma (mi.m.get ("set")); - - if (ma.empty () && !poly) - { - // It is ok to have empty modifier expression as long as - // the member pointer is raw. This is the by-value load - // and the user is not interested in learning whether the - // object is NULL. - // - if (!mp_raw) - { - error (ma.loc) << "non-empty modifier expression required " << - "for loading an object via a smart pointer" << endl; - throw operation_failed (); - } - - os << "// Empty modifier expression was specified for this\n" - << "// object so make sure we have actually loaded the\n" - << "// data into the existing instance rather than, say,\n" - << "// finding the object in the cache or creating a new one.\n" - << "//\n" - << "assert (" << p_tr << "::null_ptr (" << p << "));"; - } - else - { - if (!(mp_raw && op_raw) || poly) - { - string r (options.std () >= cxx_version::cxx11 - ? "std::move (" + p + ")" - : p); - - if (poly_derived) - // This pointer could have come from cache, so use dynamic - // cast. - // - r = p_tr + "::dynamic_pointer_cast<" + o_tp + "> (\n" + - r + ")"; - - // Unless the pointer is raw, explicitly construct the - // smart pointer from the object pointer so that we get - // the behavior similar to calling database::load() (in - // both cases we are the "ownership end-points"; unless - // the object was already in the session before loading - // this view (in which case using raw pointers as object - // pointers is a really stupid idea), this logic will do - // the right thing and what the user most likely expects. - // - if (!mp_raw) - r = member_val_type (mi.m, false) + " (\n" + r + ")"; - - if (mp_raw && !op_raw) - os << "if (!" << p_tr << "::null_ptr (" << p << "))" << endl; - - os << "// If a compiler error points to the line below, then\n" - << "// it most likely means that a pointer used in view\n" - << "// member cannot be initialized from an object pointer.\n" - << "//" << endl; - - set_member (mi.m, "o", r, "db"); - } - - if (mp_raw && !poly) - { - if (!op_raw) - os << "else" << endl; // NULL p - - set_member (mi.m, "o", o, "db"); - } - } - } - - os << "}"; - } - - virtual bool const& - member_sql_type (semantics::data_member&) {return pre_;}; - - protected: - bool pre_; - init_value_member const& init_value_member_; - }; - - struct init_value_base: traversal::class_, virtual context - { - typedef init_value_base base; - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. Not used for views. - // - if (!(obj || composite (c))) - return; - - os << "// " << class_name (c) << " base" << endl - << "//" << endl; - - if (obj) - os << "object_traits_impl< "; - else - os << "composite_value_traits< "; - - os << class_fq_name (c) << ", id_" << db << " >::init (o, i, db" << - (versioned (c) ? ", svm" : "") << ");" - << endl; - } - }; - - // Member-specific traits types for container members. - // - struct container_traits: object_members_base, virtual context - { - typedef container_traits base; - - container_traits (semantics::class_& c) - : object_members_base ( - true, - object (c), // Only build table prefix for objects. - false), - c_ (c) - { - scope_ = object (c) - ? "access::object_traits_impl< " - : "access::composite_value_traits< "; - - scope_ += class_fq_name (c) + ", id_" + db.string () + " >"; - } - - // Unless the database system can execute several interleaving - // statements, cache the result set. - // - virtual void - cache_result (string const& statement) - { - os << statement << ".cache ();"; - } - - // Additional code that need to be executed following the call to - // init_value. - // - virtual void - init_value_extra () - { - } - - virtual void - process_statement_columns (statement_columns&, - statement_kind, - bool /*dynamic*/) - { - } - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&) - { - // We don't want to traverse composite id. - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - if (object (c_)) - object_members_base::traverse_composite (m, c); - else - { - // If we are generating traits for a composite value type, then - // we don't want to go into its bases or it composite members. - // - if (m == 0 && &c == &c_) - names (c); - } - } - - virtual void - container_extra (semantics::data_member&, semantics::type&) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& t) - { - using semantics::type; - - // Figure out if this member is from a base object or composite - // value and if it's from an object, whether it is reuse-abstract. - // - bool base, reuse_abst; - - if (object (c_)) - { - base = cur_object != &c_ || - !object (dynamic_cast (m.scope ())); - reuse_abst = abstract (c_) && !polymorphic (c_); - } - else - { - base = false; // We don't go into bases. - reuse_abst = true; // Always abstract. - } - - container_kind_type ck (container_kind (t)); - - const custom_cxx_type* vct (0); - const custom_cxx_type* ict (0); - const custom_cxx_type* kct (0); - - type& vt (container_vt (m, &vct)); - type* it (0); - type* kt (0); - - data_member_path* imp (context::inverse (m, "value")); - - bool ordered (false); - bool inverse (imp != 0); - bool grow (false); - - switch (ck) - { - case ck_ordered: - { - if (!unordered (m)) - { - it = &container_it (m, &ict); - ordered = true; - - if (generate_grow) - grow = grow || context::grow (m, *it, ict, "index"); - } - - break; - } - case ck_map: - case ck_multimap: - { - kt = &container_kt (m, &kct); - - if (generate_grow) - grow = grow || context::grow (m, *kt, kct, "key"); - - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - bool smart (!inverse && - (ck != ck_ordered || ordered) && - container_smart (t)); - - if (generate_grow) - grow = grow || context::grow (m, vt, vct, "value"); - - bool eager_ptr (is_a (member_path_, - member_scope_, - test_eager_pointer, - vt, - "value")); - if (!eager_ptr) - { - if (semantics::class_* cvt = composite_wrapper (vt)) - eager_ptr = has_a (*cvt, test_eager_pointer); - } - - bool versioned (context::versioned (m)); - - string name (flat_prefix_ + public_name (m) + "_traits"); - string scope (scope_ + "::" + name); - - os << "// " << m.name () << endl - << "//" << endl - << endl; - - container_extra (m, t); - - // - // Statements. - // - if (!reuse_abst) - { - string sep (versioned ? "\n" : " "); - - semantics::type& idt (container_idt (m)); - - qname table (table_name (m, table_prefix_)); - string qtable (quote_id (table)); - instance id_cols; - instance ik_cols; // index/key columns - - if (smart) - { - switch (ck) - { - case ck_ordered: - { - ik_cols->traverse (m, *it, "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - } - - // select_statement - // - os << "const char " << scope << "::" << endl - << "select_statement[] =" << endl; - - if (inverse) - { - semantics::class_* c (object_pointer (vt)); - semantics::data_member& imf (*imp->front ()); - semantics::data_member& imb (*imp->back ()); - - // In a polymorphic hierarchy the inverse member can be in - // the base class, in which case we should use that class - // for the table name, etc. - // - if (polymorphic (*c)) - c = &dynamic_cast (imf.scope ()); - - data_member_path& inv_id (*id_member (*c)); - - qname inv_table; // Other table name. - string inv_qtable; - instance inv_id_cols; // Other id column. - instance inv_fid_cols; // Other foreign id - // column (ref to us). - statement_columns sc; - - if (container (imb)) - { - // many(i)-to-many - // - - // This other container is a direct member of the class so the - // table prefix is just the class table name. - // - inv_table = table_name (*c, *imp); - inv_qtable = quote_id (inv_table); - - inv_id_cols->traverse (imb, utype (inv_id), "id", "object_id", c); - inv_fid_cols->traverse (imb, idt, "value", "value"); - - for (object_columns_list::iterator i (inv_id_cols->begin ()); - i != inv_id_cols->end (); ++i) - { - // If this is a simple id, then pass the "id" key prefix. If - // it is a composite id, then the members have no prefix. - // - sc.push_back ( - statement_column ( - inv_qtable, - inv_qtable + "." + quote_id (i->name), - i->type, - *i->member, - inv_id_cols->size () == 1 ? "id" : "")); - } - } - else - { - // many(i)-to-one - // - inv_table = table_name (*c); - inv_qtable = quote_id (inv_table); - - inv_id_cols->traverse (inv_id); - inv_fid_cols->traverse (imb, column_prefix (*imp)); - - for (object_columns_list::iterator i (inv_id_cols->begin ()); - i != inv_id_cols->end (); ++i) - { - sc.push_back ( - statement_column ( - inv_qtable, - inv_qtable + "." + quote_id (i->name), - i->type, - *i->member)); - } - } - - process_statement_columns (sc, statement_select, versioned); - - os << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - instance qp (statement_select, inv_table); - os << strlit ("FROM " + inv_qtable + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (inv_fid_cols->begin ()), - i (b); i != inv_fid_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += inv_qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - os << strlit (where); - } - else - { - id_cols->traverse (m, idt, "id", "object_id"); - - statement_columns sc; - statement_kind sk (statement_select); // Imperfect forwarding. - instance t (qtable, sk, sc); - - switch (ck) - { - case ck_ordered: - { - if (ordered) - t->traverse (m, *it, "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - t->traverse (m, *kt, "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - t->traverse (m, vt, "value", "value"); - - process_statement_columns (sc, statement_select, versioned); - - os << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - instance qp (statement_select, table); - os << strlit ("FROM " + qtable + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - if (ordered) - { - // Top-level column. - // - string const& col ( - column_qname (m, "index", "index", column_prefix ())); - - where += " ORDER BY " + qtable + "." + col; - } - - os << strlit (where); - } - - os << ";" - << endl; - - // insert_statement - // - os << "const char " << scope << "::" << endl - << "insert_statement[] =" << endl; - - if (inverse) - os << strlit ("") << ";" - << endl; - else - { - statement_columns sc; - statement_kind sk (statement_insert); // Imperfect forwarding. - instance t (sk, sc); - - t->traverse (m, idt, "id", "object_id"); - - switch (ck) - { - case ck_ordered: - { - if (ordered) - t->traverse (m, *it, "index", "index"); - break; - } - case ck_map: - case ck_multimap: - { - t->traverse (m, *kt, "key", "key"); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - t->traverse (m, vt, "value", "value"); - - process_statement_columns (sc, statement_insert, versioned); - - os << strlit ("INSERT INTO " + qtable + sep) << endl; - - for (statement_columns::const_iterator b (sc.begin ()), i (b), - e (sc.end ()); i != e;) - { - string s; - - if (i == b) - s += '('; - s += i->column; - s += (++i != e ? ',' : ')'); - s += sep; - - os << strlit (s) << endl; - } - - os << strlit ("VALUES" + sep) << endl; - - string values ("("); - instance qp (statement_insert, table); - for (statement_columns::const_iterator b (sc.begin ()), i (b), - e (sc.end ()); i != e; ++i) - { - if (i != b) - { - values += ','; - values += sep; - } - - values += convert_to (qp->next (*i), i->type, *i->member); - } - values += ')'; - - os << strlit (values) << ";" - << endl; - } - - // update_statement - // - if (smart) - { - os << "const char " << scope << "::" << endl - << "update_statement[] =" << endl - << strlit ("UPDATE " + qtable + sep) << endl - << strlit ("SET" + sep) << endl; - - instance qp (statement_update, table); - statement_columns sc; - { - bool f (false); // Imperfect forwarding. - query_parameters* p (qp.get ()); // Imperfect forwarding. - statement_kind sk (statement_update); // Imperfect forwarding. - instance t (sk, f, sc, p); - t->traverse (m, vt, "value", "value"); - process_statement_columns (sc, statement_update, versioned); - } - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - for (object_columns_list::iterator b (ik_cols->begin ()), i (b); - i != ik_cols->end (); ++i) - { - where += " AND " + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where) << ";" - << endl; - } - - // delete_statement - // - os << "const char " << scope << "::" << endl - << "delete_statement[] =" << endl; - - if (inverse) - os << strlit ("") << ";" - << endl; - else - { - instance qp (statement_delete, table); - - os << strlit ("DELETE FROM " + qtable + " ") << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - if (smart) - { - for (object_columns_list::iterator b (ik_cols->begin ()), i (b); - i != ik_cols->end (); ++i) - { - where += " AND " + quote_id (i->name) + - (ck == ck_ordered ? ">=" : "=") + - convert_to (qp->next (*i), i->type, *i->member); - } - } - - os << strlit (where) << ";" - << endl; - } - } - - if (base) - return; - - // - // Functions. - // - - // bind (cond_image_type) - // - if (smart) - { - os << "void " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type& c)" - << "{" - << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "std::size_t n (0);" - << endl; - - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - // We don't need to update the bind index since this is the - // last element. - // - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance bm ( - "index_", "c", *it, ict, "index_type", "index"); - bm->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance bm ( - "key_", "c", *kt, kct, "key_type", "key"); - bm->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "c", vt, vct, "value_type", "value"); - bm->traverse (m); - break; - } - } - os << "}"; - } - - // bind (data_image_type) - // - { - os << "void " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "data_image_type& d"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - // In the case of containers, insert and select column sets are - // the same since we can't have inverse members as container - // elements. - // - << "statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "size_t n (0);" - << endl; - - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance bm ( - "index_", "d", *it, ict, "index_type", "index"); - bm->traverse (m); - os << "n++;" // Simple value. - << endl; - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance bm ( - "key_", "d", *kt, kct, "key_type", "key"); - bm->traverse (m); - - if (semantics::class_* c = composite_wrapper (*kt)) - os << "n += " << column_count (*c).total << "UL;" - << endl; - else - os << "n++;" - << endl; - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - // We don't need to update the bind index since this is the - // last element. - // - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "d", vt, vct, "value_type", "value"); - bm->traverse (m); - - os << "}"; - } - - // bind (cond_image, data_image) (update) - // - if (smart) - { - os << "void " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type& c," << endl - << "data_image_type& d"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - // Use insert instead of update to include read-only members. - // - << "statement_kind sk (statement_insert);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl - << "std::size_t n (0);" - << endl; - - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "d", vt, vct, "value_type", "value"); - bm->traverse (m); - - if (semantics::class_* c = composite_wrapper (vt)) - os << "n += " << column_count (*c).total << "UL;" - << endl; - else - os << "n++;" - << endl; - - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - // We don't need to update the bind index since this is the - // last element. - // - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance bm ( - "index_", "c", *it, ict, "index_type", "index"); - bm->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance bm ( - "key_", "c", *kt, kct, "key_type", "key"); - bm->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - os << "// value" << endl - << "//" << endl; - instance bm ( - "value_", "c", vt, vct, "value_type", "value"); - bm->traverse (m); - break; - } - } - os << "}"; - } - - // grow () - // - if (generate_grow) - { - size_t index (0); - - os << "void " << scope << "::" << endl - << "grow (data_image_type& i," << endl - << truncated_vector << " t"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "bool grew (false);" - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - instance gm ( - index, "index_", *it, ict, "index_type", "index"); - gm->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance gm ( - index, "key_", *kt, kct, "key_type", "key"); - gm->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "// value" << endl - << "//" << endl; - instance gm ( - index, "value_", vt, vct, "value_type", "value"); - gm->traverse (m); - - os << "if (grew)" << endl - << "i.version++;" - << "}"; - } - - // init (data_image) - // - if (!inverse) - { - os << "void " << scope << "::" << endl - << "init (data_image_type& i," << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "index_type* j," << endl; - break; - } - case ck_map: - case ck_multimap: - { - os << "const key_type* k," << endl; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "const value_type& v"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_insert);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl; - - if (generate_grow) - os << "bool grew (false);" - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl - << "if (j != 0)"; - - instance im ( - "index_", "*j", *it, ict, "index_type", "index"); - im->traverse (m); - } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl - << "if (k != 0)"; - - instance im ( - "key_", "*k", *kt, kct, "key_type", "key"); - im->traverse (m); - - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "// value" << endl - << "//" << endl; - { - instance im ( - "value_", "v", vt, vct, "value_type", "value"); - im->traverse (m); - } - - if (generate_grow) - os << "if (grew)" << endl - << "i.version++;"; - - os << "}"; - } - - // init (cond_image) - // - if (smart) - { - os << "void " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (cond_image_type& i, index_type j)" - << "{" - << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_select);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl; - - instance im ( - "index_", "j", *it, ict, "index_type", "index"); - im->traverse (m); - - os << "}"; - break; - } - case ck_map: - case ck_multimap: - { - // Need to handle growth. - // - // os << "init (data_image_type&, const key_type&);"; - break; - } - case ck_set: - case ck_multiset: - { - // Need to handle growth. - // - // os << "init (data_image_type&, const value_type&);"; - break; - } - } - - os << endl; - } - - // init (data) - // - os << "void " << scope << "::" << endl - << "init ("; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "index_type& j," << endl; - break; - } - case ck_map: - case ck_multimap: - { - os << "key_type& k," << endl; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "value_type& v," << endl; - os << "const data_image_type& i," << endl - << "database* db"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << endl; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - { - os << "// index" << endl - << "//" << endl; - - instance im ( - "index_", "j", *it, ict, "index_type", "index"); - im->traverse (m); - } - - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - - instance im ( - "key_", "k", *kt, kct, "key_type", "key"); - im->traverse (m); - - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "// value" << endl - << "//" << endl; - { - // If the value is an object pointer, pass the id type as a - // type override. - // - instance im ( - "value_", "v", vt, vct, "value_type", "value"); - im->traverse (m); - } - os << "}"; - - // insert - // - { - string ia, ka, va, da; - - if (!inverse) - { - ia = ordered ? " i" : ""; - ka = " k"; - va = " v"; - da = " d"; - } - - os << "void " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "insert (index_type" << ia << ", " << - "const value_type&" << va << ", " << - "void*" << da << ")"; - break; - } - case ck_map: - case ck_multimap: - { - os << "insert (const key_type&" << ka << ", " << - "const value_type&" << va << ", " << - "void*" << da << ")"; - break; - } - case ck_set: - case ck_multiset: - { - os << "insert (const value_type&" << va << ", " << - "void*" << da << ")"; - break; - } - } - - os << "{"; - - if (!inverse) - { - os << "using namespace " << db << ";" - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "data_image_type& di (sts.data_image ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration ());"; - - os << endl - << "init (di, "; - - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "&i, "; - break; - } - case ck_map: - case ck_multimap: - { - os << "&k, "; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "v" << (versioned ? ", svm" : "") << ");"; - - os << endl - << "if (sts.data_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.data_bind (), id.bind, id.count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "}" - << "if (!sts.insert_statement ().execute ())" << endl - << "throw object_already_persistent ();"; - } - - os << "}"; - } - - // update - // - if (smart) - { - os << "void " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "update (index_type i, const value_type& v, void* d)"; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << "{"; - - os << "using namespace " << db << ";" - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "cond_image_type& ci (sts.cond_image ());" - << "data_image_type& di (sts.data_image ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration ());"; - - os << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (ci, i);"; - os << "init (di, 0, v" << (versioned ? ", svm" : "") << ");"; - break; - } - case ck_map: - case ck_multimap: - { - //os << "init (di, 0, v);"; - break; - } - case ck_set: - case ck_multiset: - { - //os << "init (di, v);"; - break; - } - } - - os << endl - << "if (sts.update_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.update_bind (), id.bind, id.count, ci, di" << - (versioned ? ", svm" : "") << ");" - << "sts.update_binding_update_version ();" - << "}"; - - os << "if (sts.update_statement ().execute () == 0)" << endl - << "throw object_not_persistent ();" - << "}"; - } - - // select - // - os << "bool " << scope << "::" << endl; - - switch (ck) - { - case ck_ordered: - { - os << "select (index_type&" << (ordered ? " i" : "") << - ", value_type& v, void* d)"; - break; - } - case ck_map: - case ck_multimap: - { - os << "select (key_type& k, value_type& v, void* d)"; - break; - } - case ck_set: - case ck_multiset: - { - os << "select (value_type& v, void* d)"; - break; - } - } - - os << "{" - << "using namespace " << db << ";" - << "using " << db << "::select_statement;" // Conflicts. - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "data_image_type& di (sts.data_image ());"; - - if (versioned) - os << "const schema_version_migration& svm (" << - "sts.version_migration ());"; - - os << endl - << "init ("; - - // Extract current element. - // - switch (ck) - { - case ck_ordered: - { - if (ordered) - os << "i, "; - break; - } - case ck_map: - case ck_multimap: - { - os << "k, "; - break; - } - case ck_set: - case ck_multiset: - break; - } - - os << "v, di, &sts.connection ().database ()" << - (versioned ? ", svm" : "") << ");" - << endl; - - init_value_extra (); - - // If we are loading an eager pointer, then the call to init - // above executes other statements which potentially could - // change the image, including the id. - // - if (eager_ptr) - { - os << "if (sts.data_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.data_bind (), id.bind, id.count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "}"; - } - - // Fetch next. - // - os << "select_statement& st (sts.select_statement ());" - << "select_statement::result r (st.fetch ());"; - - if (grow) - os << endl - << "if (r == select_statement::truncated)" - << "{" - << "grow (di, sts.select_image_truncated ()" << - (versioned ? ", svm" : "") << ");" - << endl - << "if (sts.data_binding_test_version ())" - << "{" - // Id cannot change. - // - << "bind (sts.data_bind (), 0, sts.id_binding ().count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "st.refetch ();" - << "}" - << "}"; - - os << "return r != select_statement::no_data;" - << "}"; - - // delete_ - // - os << "void " << scope << "::" << endl - << "delete_ ("; - - if (smart) - { - switch (ck) - { - case ck_ordered: - { - os << "index_type i, "; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - } - - os << "void*" << (inverse ? "" : " d") << ")" - << "{"; - - if (!inverse) - { - os << "using namespace " << db << ";" - << endl - << "statements_type& sts (*static_cast< statements_type* > (d));"; - - if (smart) - { - os << "cond_image_type& ci (sts.cond_image ());" - << endl; - - switch (ck) - { - case ck_ordered: - { - os << "init (ci, i);"; - break; - } - case ck_map: - case ck_multimap: - { - break; - } - case ck_set: - case ck_multiset: - { - break; - } - } - - os << endl - << "if (sts.cond_binding_test_version ())" - << "{" - << "const binding& id (sts.id_binding ());" - << "bind (sts.cond_bind (), id.bind, id.count, ci);" - << "sts.cond_binding_update_version ();" - << "}"; - } - - os << "sts.delete_statement ().execute ();"; - } - - os << "}"; - - // persist - // - if (!inverse) - { - os << "void " << scope << "::" << endl - << "persist (const container_type& c," << endl - << "statements_type& sts"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - << "functions_type& fs (sts.functions ());"; - - if (versioned) - os << "sts.version_migration (svm);"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::persist (c, fs);" - << "}"; - } - - // load - // - os << "void " << scope << "::" << endl - << "load (container_type& c," << endl - << "statements_type& sts"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << "using " << db << "::select_statement;" // Conflicts. - << endl - << "const binding& id (sts.id_binding ());" - << endl - << "if (sts.data_binding_test_version ())" - << "{" - << "bind (sts.data_bind (), id.bind, id.count, sts.data_image ()" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "}" - // We use the id binding directly so no need to check cond binding. - // - << "select_statement& st (sts.select_statement ());" - << "st.execute ();" - << "auto_result ar (st);"; - - // If we are loading eager object pointers, we may need to cache - // the result since we will be loading other objects. - // - if (eager_ptr) - cache_result ("st"); - - os << "select_statement::result r (st.fetch ());"; - - if (grow) - os << endl - << "if (r == select_statement::truncated)" - << "{" - << "data_image_type& di (sts.data_image ());" - << "grow (di, sts.select_image_truncated ()" << - (versioned ? ", svm" : "") << ");" - << endl - << "if (sts.data_binding_test_version ())" - << "{" - // Id cannot change. - // - << "bind (sts.data_bind (), 0, id.count, di" << - (versioned ? ", svm" : "") << ");" - << "sts.data_binding_update_version ();" - << "st.refetch ();" - << "}" - << "}"; - - os << "bool more (r != select_statement::no_data);" - << endl - << "functions_type& fs (sts.functions ());"; - - if (versioned) - os << "sts.version_migration (svm);"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::load (c, more, fs);" - << "}"; - - // update - // - if (!(inverse || readonly (member_path_, member_scope_))) - { - os << "void " << scope << "::" << endl - << "update (const container_type& c," << endl - << "statements_type& sts"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "using namespace " << db << ";" - << endl - << "functions_type& fs (sts.functions ());"; - - if (versioned) - os << "sts.version_migration (svm);"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::update (c, fs);" - << "}"; - } - - // erase - // - if (!inverse) - { - os << "void " << scope << "::" << endl - << "erase ("; - - if (smart) - os << "const container_type* c, "; - - os << "statements_type& sts)" - << "{" - << "using namespace " << db << ";" - << endl - << "functions_type& fs (sts.functions ());"; - - if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << ordered << ";"; - - os << "container_traits_type::erase (" << (smart ? "c, " : "") << "fs);" - << "}"; - } - } - - protected: - string scope_; - semantics::class_& c_; - }; - - // Extra statement cache members for containers. - // - struct container_cache_members: object_members_base, virtual context - { - typedef container_cache_members base; - - container_cache_members () - : object_members_base (true, false, false) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& c) - { - bool smart (!context::inverse (m, "value") && - !unordered (m) && - container_smart (c)); - - string traits (flat_prefix_ + public_name (m) + "_traits"); - - os << db << "::" << (smart ? "smart_" : "") << - "container_statements_impl< " << traits << " > " << - flat_prefix_ << m.name () << ";"; - } - }; - - struct container_cache_init_members: object_members_base, virtual context - { - typedef container_cache_init_members base; - - container_cache_init_members () - : object_members_base (true, false, false), first_ (true) - { - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - if (first_) - { - os << endl - << ": "; - first_ = false; - } - else - os << "," << endl - << " "; - - os << flat_prefix_ << m.name () << " (c, id"; - extra_members (); - os << ")"; - } - - virtual void - extra_members () {} - - protected: - bool first_; - }; - - // Extra statement cache members for sections. - // - struct section_cache_members: virtual context - { - typedef section_cache_members base; - - virtual void - traverse (user_section& s) - { - string traits (public_name (*s.member) + "_traits"); - - os << db << "::" << "section_statements< " << - class_fq_name (*s.object) << ", " << traits << " > " << - s.member->name () << ";"; - } - }; - - struct section_cache_init_members: virtual context - { - typedef section_cache_init_members base; - - section_cache_init_members (bool first): first_ (first) {} - - virtual void - traverse (user_section& s) - { - if (first_) - { - os << endl - << ": "; - first_ = false; - } - else - os << "," << endl - << " "; - - os << s.member->name () << " (c, im, idim, id, idv"; - extra_members (); - os << ")"; - } - - virtual void - extra_members () {} - - protected: - bool first_; - }; - - // Calls for container members. - // - struct container_calls: object_members_base, virtual context - { - typedef container_calls base; - - enum call_type - { - persist_call, - load_call, - update_call, - erase_obj_call, - erase_id_call, - section_call - }; - - container_calls (call_type call, object_section* section = 0) - : object_members_base (true, false, true, false, section), - call_ (call), - obj_prefix_ ("obj"), - by_value_ (0) - { - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section for - // load calls. - // - return section_ == 0 || - *section_ == s || - (call_ == load_call && - *section_ == main_section && - !s.separate_load ()); - } - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&) - { - // We don't want to traverse composite id. - } - - virtual void - traverse_composite_wrapper (semantics::data_member* m, - semantics::class_& c, - semantics::type* w) - { - if (m == 0 || - call_ == erase_id_call || - (call_ == load_call && by_value_ != 0)) - { - object_members_base::traverse_composite (m, c); - return; - } - - // Get this member using the accessor expression. - // - member_access& ma ( - m->get (call_ == load_call ? "set" : "get")); - - // We don't support by-value modifiers for composite values - // with containers. However, at this point we don't know - // whether this composite value has any containers. So we - // are just going to set a flag that can be checked in - // traverse_container() below. - // - if (call_ == load_call && ma.placeholder ()) - { - by_value_ = &ma; - object_members_base::traverse_composite (m, c); - by_value_ = 0; - return; - } - - // We also don't support by-value accessors is there is a - // smart container inside (which, again, we don't know at - // this point). So keep track of such first instance. - // - member_access* old_by_value (by_value_); - if (call_ != load_call && ma.by_value && by_value_ == 0) - by_value_ = &ma; - - string old_op (obj_prefix_); - string old_f (from_); - obj_prefix_.clear (); - - // If this member is const and we have a synthesized direct - // access, then cast away constness. Otherwise, we assume - // that the user-provided expression handles this. - // - bool cast (call_ == load_call && ma.direct () && const_member (*m)); - if (cast) - obj_prefix_ = "const_cast< " + member_ref_type (*m, false) + - " > (\n"; - - obj_prefix_ += ma.translate (old_op); - - if (cast) - obj_prefix_ += ")"; - - // If this is not a synthesized expression, then store its - // location which we will output later for easier error - // tracking. - // - if (!ma.synthesized) - from_ += "// From " + location_string (ma.loc, true) + "\n"; - - // If this is a wrapped composite value, then we need to "unwrap" it. - // - if (w != 0) - { - semantics::names* hint; - semantics::type& t (utype (*m, hint)); - - // Because we cannot have nested containers, member type should - // be the same as w. - // - assert (&t == w); - - obj_prefix_ = "wrapper_traits< " + t.fq_name (hint) + " >::" + - (call_ == load_call ? "set_ref" : "get_ref") + - " (\n" + obj_prefix_ + ")"; - } - - object_members_base::traverse_composite (m, c); - from_ = old_f; - obj_prefix_ = old_op; - by_value_ = old_by_value; - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type& c) - { - using semantics::type; - - bool inverse (context::inverse (m, "value")); - bool smart (!inverse && !unordered (m) && container_smart (c)); - bool versioned (context::versioned (m)); - - // In certain cases we don't need to do anything. - // - if ((call_ != load_call && inverse) || - (call_ == section_call && !smart) || - (call_ == update_call && readonly (member_path_, member_scope_))) - return; - - string const& name (m.name ()); - string sts_name (flat_prefix_ + name); - string traits (flat_prefix_ + public_name (m) + "_traits"); - - os << "// " << member_prefix_ << m.name () << endl - << "//" << endl; - - // Get this member using the accessor expression. - // - string var; - member_access& ma ( - m.get (call_ == load_call ? "set" : "get")); - - // We don't support by-value modifiers for composite values - // with containers. - // - if (call_ == load_call && by_value_ != 0) - { - error (by_value_->loc) << "by-value modification of a composite " - << "value with container is not supported" - << endl; - info (m.location ()) << "container member is defined here" << endl; - throw operation_failed (); - } - - // We don't support by-value accessors for smart containers. - // - if (call_ != load_call && smart) - { - if (by_value_ != 0) - { - error (by_value_->loc) << "by-value access to a composite value " - << "with smart container is not supported" - << endl; - info (m.location ()) << "container member is defined here" << endl; - throw operation_failed (); - } - - if (ma.by_value) - { - error (ma.loc) << "by-value access to a smart container is not " - << "supported" << endl; - info (m.location ()) << "container member is defined here" << endl; - throw operation_failed (); - } - } - - // If the member is soft- added or deleted, check the version. - // - unsigned long long av (added (member_path_)); - unsigned long long dv (deleted (member_path_)); - - // If the addition/deletion version is the same as the section's, - // then we don't need the test. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0 || dv != 0) - { - os << "if ("; - - if (av != 0) - os << "svm >= schema_version_migration (" << av << "ULL, true)"; - - if (av != 0 && dv != 0) - os << " &&" << endl; - - if (dv != 0) - os << "svm <= schema_version_migration (" << dv << "ULL, true)"; - - os << ")" << endl; - } - - os << "{"; - - if (call_ != erase_id_call && (call_ != erase_obj_call || smart)) - { - // See if we are modifying via a reference or proper modifier. - // - if (call_ == load_call && ma.placeholder ()) - os << member_val_type (m, false, "v") << ";" - << endl; - else - { - // Note: this case is for both access and modification. - // - - // Output stored locations, if any. - // - os << from_; - - // If this is not a synthesized expression, then output its - // location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - // Note that here we don't decay arrays. - // - const string& ref_type ( - member_ref_type (m, call_ != load_call, "v", false /* decay */)); - - // VC++ cannot grok the constructor syntax. - // - os << ref_type << " =" << endl - << " "; - - // If this member is const and we have a synthesized direct - // access, then cast away constness. Otherwise, we assume - // that the user-provided expression handles this. - // - bool cast (call_ == load_call && ma.direct () && const_member (m)); - if (cast) - os << "const_cast< " << member_ref_type (m, false, "", false) << - " > (" << endl; - - os << ma.translate (obj_prefix_); - - if (cast) - os << ")"; - - os << ";" - << endl; - } - - var = "v"; - - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - // If this is a wrapped container, then we need to "unwrap" it. - // - if (wrapper (t)) - { - var = "wrapper_traits< " + t.fq_name (hint) + " >::" + - (call_ == load_call ? "set_ref" : "get_ref") + " (" + var + ")"; - } - } - - switch (call_) - { - case persist_call: - { - os << traits << "::persist (" << endl - << var << "," << endl - << "esc." << sts_name; - - if (versioned) - os << "," << endl - << "svm"; - - os << ");"; - break; - } - case load_call: - { - os << traits << "::load (" << endl - << var << "," << endl - << "esc." << sts_name; - - if (versioned) - os << "," << endl - << "svm"; - - os << ");"; - break; - } - case update_call: - { - os << traits << "::update (" << endl - << var << "," << endl - << "esc." << sts_name; - - if (versioned) - os << "," << endl - << "svm"; - - os << ");"; - break; - } - case erase_obj_call: - { - os << traits << "::erase (" << endl; - - if (smart) - os << "&" << var << "," << endl; - - os << "esc." << sts_name << ");" - << endl; - break; - } - case erase_id_call: - { - os << traits << "::erase (" << endl; - - if (smart) - os << "0," << endl; - - os << "esc." << sts_name << ");" - << endl; - break; - } - case section_call: - { - os << "if (" << traits << "::container_traits_type::changed (" << - var << "))" << endl - << "s.reset (true, true);"; // loaded, changed - break; - } - } - - if (call_ == load_call) - { - // Call the modifier if we are using a proper one. - // - if (ma.placeholder ()) - { - os << endl - << from_; - - // If this is not a synthesized expression, then output its - // location for easier error tracking. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << ma.translate ( - obj_prefix_, "v", "static_cast<" + db.string () + - "::database&> (db)") << ";"; - } - } - - os << "}"; - } - - protected: - call_type call_; - string obj_prefix_; - string from_; - member_access* by_value_; - }; - - // - // - struct section_traits: traversal::class_, virtual context - { - typedef section_traits base; - - section_traits (semantics::class_& c) - : c_ (c), - scope_ ("access::object_traits_impl< " + class_fq_name (c) + - ", id_" + db.string () + " >") - { - } - - // Additional code that need to be executed following the call to - // init_value(). - // - virtual void - init_value_extra () - { - } - - virtual void - process_statement_columns (statement_columns&, - statement_kind, - bool /*dynamic*/) - { - } - - virtual void - section_extra (user_section&) - { - } - - // Returning "1" means increment by one. - // - virtual string - optimistic_version_increment (semantics::data_member&) - { - return "1"; - } - - virtual string - update_statement_extra (user_section&) - { - return ""; - } - - virtual void - traverse (user_section& s) - { - using semantics::class_; - using semantics::data_member; - - data_member& m (*s.member); - - class_* poly_root (polymorphic (c_)); - bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c_); - class_* poly_base (poly_derived ? &polymorphic_base (c_) : 0); - - data_member* opt (optimistic (c_)); - - // Treat the special version update sections as abstract in reuse - // inheritance. - // - bool reuse_abst (!poly && - (abstract (c_) || - s.special == user_section::special_version)); - - bool load (s.total != 0 && s.separate_load ()); - bool load_con (s.containers && s.separate_load ()); - bool load_opt (s.optimistic () && s.separate_load ()); - - bool update (s.total != s.inverse + s.readonly); // Always separate. - bool update_con (s.readwrite_containers); - bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); - - // Don't generate anything for empty sections. - // - if (!(load || load_con || load_opt || - update || update_con || update_opt)) - return; - - // If we are adding a new section to a derived class in an optimistic - // polymorphic hierarchy, then pretend it inherits from the special - // version update section. - // - user_section* rs (0); - if (opt != 0) - { - // Skip overrides and get to the new section if polymorphic. - // - for (rs = &s; poly && rs->base != 0; rs = rs->base) ; - - if (rs != 0) - { - if (rs->object != &opt->scope ()) - rs->base = &(poly ? poly_root : &opt->scope ())-> - get ("user-sections").back (); - else - rs = 0; - } - } - - string name (public_name (m) + "_traits"); - string scope (scope_ + "::" + name); - - os << "// " << m.name () << endl - << "//" << endl - << endl; - - // bind (id, image_type) - // - if (load || load_opt || update || update_opt) - { - os << "std::size_t " << scope << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "const " << bind_vector << (reuse_abst ? "," : " id,") << endl - << "std::size_t" << (reuse_abst ? "," : " id_size,") << endl - << "image_type& i," << endl - << db << "::statement_kind sk"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl - << "std::size_t n (0);" - << endl; - - // Bind reuse base. It is always first and we never ask it - // to bind id(+ver). - // - if (s.base != 0 && !poly_derived) - { - user_section& b (*s.base); - - bool load (b.total != 0 && b.separate_load ()); - bool load_opt (b.optimistic () && b.separate_load ()); - - bool update (b.total != b.inverse + b.readonly); - - if (load || load_opt || update) - os << "// " << class_name (*b.object) << endl - << "//" << endl - << "n += object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::bind (" << endl - << "b, 0, 0, i, sk" << (b.versioned ? ", svm" : "") << ");" - << endl; - } - - // Bind members. - // - { - instance bm ("", "", &s); - traversal::names n (*bm); - names (c_, n); - } - - // Bind polymorphic image chain for the select statement. - // - if (s.base != 0 && poly_derived && s.separate_load ()) - { - // Find the next base that has something to load, if any. - // - user_section* b (s.base); - string acc (".base"); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != 0 || b->optimistic ()) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - if (b != 0) - os << "// " << class_name (*b->object) << endl - << "//" << endl - << "if (sk == statement_select)" << endl - << "n += object_traits_impl< " << class_fq_name (*b->object) << - ", id_" << db << " >::" << public_name (*b->member) << - "_traits::bind (" << endl - << "b + n, 0, 0, *i" << acc << ", sk" << - (b->versioned ? ", svm" : "") << ");" - << endl; - } - - if (!reuse_abst) - os << "// object_id" << endl - << "//" << endl - << "if (id != 0)" << endl - << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" - << "n += id_size;" // Not in if for "id unchanged" optimization. - << endl; - - os << "return n;" - << "}"; - } - - // grow () - // - if (generate_grow && (load || load_opt)) - { - os << "bool " << scope << "::" << endl - << "grow (image_type& i," << endl - << truncated_vector << " t"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "bool grew (false);" - << endl; - - size_t index (0); - - if (s.base != 0 && !poly_derived) - { - user_section& b (*s.base); - - bool load (b.total != 0); - bool load_opt (b.optimistic ()); - - if (load || load_opt) - { - os << "// " << class_name (*b.object) << endl - << "//" << endl - << "grew = object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::grow (i, t" << (b.versioned ? ", svm" : "") << ");" - << endl; - - index += b.total + (load_opt ? 1 : 0); - } - } - - { - user_section* ps (&s); - instance gm (index, "", ps); - traversal::names n (*gm); - names (c_, n); - } - - // Grow polymorphic image chain. - // - if (s.base != 0 && poly_derived) - { - // Find the next base that has something to load, if any. - // - user_section* b (s.base); - string acc (".base"); - size_t cols; - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - cols = b->total + (b->optimistic () ? 1 : 0); - if (cols != 0) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - if (b != 0) - os << "// " << class_name (*b->object) << endl - << "//" << endl - << "if (object_traits_impl< " << class_fq_name (*b->object) << - ", id_" << db << " >::" << public_name (*b->member) << - "_traits::grow (" << endl - << "*i" << acc << ", t + " << cols << "UL" << - (b->versioned ? ", svm" : "") << "))" << endl - << "i" << acc << "->version++;" - << endl; - } - - os << "return grew;" << endl - << "}"; - } - - // init (object, image) - // - if (load) - { - os << "void " << scope << "::" << endl - << "init (object_type& o," << endl - << "const image_type& i," << endl - << "database* db"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - if (s.base != 0) - { - if (!poly_derived) - { - user_section& b (*s.base); - - bool load (b.total != 0); - - if (load) - os << "// " << class_name (*b.object) << endl - << "//" << endl - << "object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::init (o, i, db" << - (b.versioned ? ", svm" : "") << ");" - << endl; - } - else - { - // Find the next base that has something to load, if any. - // - user_section* b (s.base); - string acc (".base"); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != 0) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - if (b != 0) - os << "// " << class_name (*b->object) << endl - << "//" << endl - << "object_traits_impl< " << class_fq_name (*b->object) << - ", id_" << db << " >::" << public_name (*b->member) << - "_traits::init (" << endl - << "o, *i" << acc << ", db" << - (b->versioned ? ", svm" : "") << ");" - << endl; - } - } - - { - instance iv ("", "", true, &s); - traversal::names n (*iv); - names (c_, n); - } - - os << "}"; - } - - // init (image, object) - // - if (update) - { - os << (generate_grow ? "bool " : "void ") << scope << "::" << endl - << "init (image_type& i," << endl - << "const object_type& o"; - - if (s.versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{"; - - if (s.versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);" - << endl; - - os << "using namespace " << db << ";" - << endl - << "statement_kind sk (statement_insert);" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl; - - // There is no call to init_image_pre() here (which calls the - // copy callback for some databases) since we are not going to - // touch any of the members that were loaded by query. - - if (generate_grow) - os << "bool grew (false);" - << endl; - - if (s.base != 0 && !poly_derived) - { - user_section& b (*s.base); - - bool update (b.total != b.inverse + b.readonly); - - if (update) - os << "// " << class_name (*b.object) << endl - << "//" << endl - << (generate_grow ? "grew = " : "") << - "object_traits_impl< " << class_fq_name (*b.object) << - ", id_" << db << " >::" << public_name (*b.member) << - "_traits::init (i, o" << (b.versioned ? ", svm" : "") << ");" - << endl; - } - - { - instance ii ("", "", &s); - traversal::names n (*ii); - names (c_, n); - } - - if (generate_grow) - os << "return grew;"; - - os << "}"; - } - - // The rest does not apply to reuse-abstract sections. - // - if (reuse_abst) - { - section_extra (s); - return; - } - - string sep (s.versioned ? "\n" : " "); - - // Schema name as a string literal or empty. - // - string schema_name (options.schema_name ()[db]); - if (!schema_name.empty ()) - schema_name = strlit (schema_name); - - // Statements. - // - qname table (table_name (c_)); - string qtable (quote_id (table)); - - instance id_cols; - id_cols->traverse (*id_member (c_)); - - // select_statement - // - if (load || load_opt) - { - size_t depth (poly_derived ? polymorphic_depth (c_) : 1); - - statement_columns sc; - { - statement_kind sk (statement_select); // Imperfect forwarding. - object_section* ps (&s); // Imperfect forwarding. - instance t (qtable, sk, sc, depth, ps); - t->traverse (c_); - process_statement_columns (sc, statement_select, s.versioned); - } - - os << "const char " << scope << "::" << endl - << "select_statement[] =" << endl - << strlit ("SELECT" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - os << strlit ("FROM " + qtable + sep) << endl; - - // Join polymorphic bases. - // - if (depth != 1 && s.base != 0) - { - bool f (false); //@@ (im)perfect forwarding - size_t d (depth - 1); //@@ (im)perfect forward. - instance j (c_, f, d, "", s.base); - j->traverse (*poly_base); - - for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) - os << strlit (*i + sep) << endl; - } - - // Join tables of inverse members belonging to this section. - // - { - bool f (false); // @@ (im)perfect forwarding - object_section* ps (&s); // @@ (im)perfect forwarding - instance j (c_, f, depth, ps); - j->traverse (c_); - - for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) - os << strlit (*i + sep) << endl; - } - - string where ("WHERE "); - instance qp (statement_select, table); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - os << strlit (where) << ";" - << endl; - } - - // update_statement - // - if (update || update_opt) - { - instance qp (statement_update, table); - - statement_columns sc; - { - query_parameters* p (qp.get ()); // Imperfect forwarding. - statement_kind sk (statement_update); // Imperfect forwarding. - object_section* ps (&s); // Imperfect forwarding. - instance t (sk, sc, p, ps); - t->traverse (c_); - process_statement_columns (sc, statement_update, s.versioned); - } - - os << "const char " << scope << "::" << endl - << "update_statement[] =" << endl - << strlit ("UPDATE " + qtable + sep) << endl - << strlit ("SET" + sep) << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "") + sep) << endl; - } - - // This didn't work out: cannot change the identity column. - // - //if (sc.empty ()) - //{ - // // We can end up with nothing to set if we need to "touch" a row - // // in order to increment its optimistic concurrency version. In - // // this case just do a dummy assignment based on the id column. - // // - // string const& c (quote_id (id_cols->begin ()->name)); - // os << strlit (c + "=" + c) << endl; - //} - - string extra (update_statement_extra (s)); - - if (!extra.empty ()) - os << strlit (extra + sep) << endl; - - string where ("WHERE "); - for (object_columns_list::iterator b (id_cols->begin ()), i (b); - i != id_cols->end (); ++i) - { - if (i != b) - where += " AND "; - - where += quote_id (i->name) + "=" + - convert_to (qp->next (*i), i->type, *i->member); - } - - if (s.optimistic ()) // Note: not update_opt. - { - string name (column_qname (*opt, column_prefix ())); - string type (column_type (*opt)); - - where += " AND " + name + "=" + - convert_to (qp->next (*opt, name, type), type, *opt); - } - - os << strlit (where) << ";" - << endl; - } - - // load () - // - if (load || load_opt || load_con) - { - os << "void " << scope << "::" << endl - << "load (extra_statement_cache_type& esc, object_type& obj" << - (poly ? ", bool top" : "") << ")" - << "{"; - - if (poly) - os << "ODB_POTENTIALLY_UNUSED (top);" - << endl; - - if (s.versioned || s.versioned_containers) - os << "const schema_version_migration& svm (" << endl - << "esc." << m.name () << ".version_migration (" << - schema_name << "));" - << endl; - - // Load values, if any. - // - if (load || load_opt) - { - // The SELECT statement for the top override loads all the - // values. - // - if (poly) - os << "if (top)" - << "{"; - - // Note that we don't use delayed load machinery here. While - // a section can definitely contain self-referencing pointers, - // loading such a pointer won't mess up the data members in the - // image that we care about. It also holds true for streaming - // result, since the bindings are different. - - os << "using namespace " << db << ";" - << "using " << db << "::select_statement;" // Conflicts. - << endl - << "statements_type& sts (esc." << m.name () << ");" - << endl - << "image_type& im (sts.image ());" - << "binding& imb (sts.select_image_binding ());" - << endl; - - // For the polymorphic case, instead of storing an array of - // versions as we do for objects, we will add all the versions - // up and use that as a cumulative image chain version. If you - // meditate a bit on that, you will realize that it will work - // (hint: versions can only increase). - // - string ver; - string ver_decl; - - if (s.base != 0 && poly_derived) - { - ver = "imv"; - ver_decl = "std::size_t imv (im.version"; - - user_section* b (s.base); - string acc ("im.base"); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != 0 || b->optimistic ()) - ver_decl += " +\n" + acc + "->version"; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - acc += "->base"; - } - - ver_decl += ")"; - - os << ver_decl << ";" - << endl; - } - else - ver = "im.version"; - - os << "if (" << ver << " != sts.select_image_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, 0, 0, im, statement_select" << - (s.versioned ? ", svm" : "") << ");" - << "sts.select_image_version (" << ver << ");" - << "imb.version++;" - << "}"; - - // Id binding is assumed initialized and bound. - // - os << "select_statement& st (sts.select_statement ());"; - - // The statement can be dynamically empty. - // - if (s.versioned) - os << "if (!st.empty ())" - << "{"; - - os << "st.execute ();" - << "auto_result ar (st);" - << "select_statement::result r (st.fetch ());" - << endl; - - os << "if (r == select_statement::no_data)" << endl - << "throw object_not_persistent ();" - << endl; - - if (grow (c_, &s)) - { - os << "if (r == select_statement::truncated)" - << "{" - << "if (grow (im, sts.select_image_truncated ()" << - (s.versioned ? ", svm" : "") << "))" << endl - << "im.version++;" - << endl; - - // The same logic as above. - // - if (s.base != 0 && poly_derived) - os << ver_decl << ";" - << endl; - - os << "if (" << ver << " != sts.select_image_version ())" - << "{" - << "bind (imb.bind, 0, 0, im, statement_select" << - (s.versioned ? ", svm" : "") << ");" - << "sts.select_image_version (" << ver << ");" - << "imb.version++;" - << "st.refetch ();" - << "}" - << "}"; - } - - if (opt != 0) // Not load_opt, we do it in poly-derived as well. - { - os << "if ("; - - if (poly_derived) - { - os << "root_traits::version (*im.base"; - for (class_* b (poly_base); - b != poly_root; - b = &polymorphic_base (*b)) - os << "->base"; - os << ")"; - } - else - os << "version (im)"; - - os << " != " << (poly_derived ? "root_traits::" : "") << - "version (obj))" << endl - << "throw object_changed ();" - << endl; - } - - if (load) - { - os << "init (obj, im, &sts.connection ().database ()" << - (s.versioned ? ", svm" : "") << ");"; - init_value_extra (); // Stream results, etc. - os << endl; - } - - if (s.versioned) - os << "}"; // if (!st.empty ()) - - if (poly) - os << "}"; // if (top) - } - - // Call base to load its containers, if this is an override. - // - if (poly_derived && s.base != 0) - { - user_section* b (s.base); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - // If we don't have any values of our own but out base - // does, then allow it to load them. - // - if (b->containers || - (!load && (b->total != 0 || b->optimistic ()))) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - } - - // This one is tricky: ideally we would do a direct call to - // the base's load() (which may not be our immediate base, - // BTW) but there is no easy way to resolve base's extra - // statements from ours. So, instead, we are going to go - // via the dispatch machinery which requires a connection - // rather than statements. Not the most efficient way but - // simple. - - // Find the "previous" override by starting the search from - // our base. - // - if (b != 0) - { - // Note that here we are using the base section index to - // handle the special version update base. - // - os << "info.base->find_section_load (" << b->index << "UL) (" << - "esc." << m.name () << ".connection (), obj, " << - // If we don't have any values of our own, then allow the - // base load its. - // - (load ? "false" : "top") << ");" - << endl; - } - } - - // Load our containers, if any. - // - if (s.containers) - { - instance t (container_calls::load_call, &s); - t->traverse (c_); - } - - os << "}"; - } - - // update () - // - if (update || update_opt || update_con) - { - os << "void " << scope << "::" << endl - << "update (extra_statement_cache_type& esc, " << - "const object_type& obj" << - (poly_derived && s.base != 0 ? ", bool base" : "") << ")" - << "{"; - - // Call base if this is an override. - // - if (poly_derived && s.base != 0) - { - user_section* b (s.base); - for (class_* bo (poly_base);; bo = &polymorphic_base (*bo)) - { - if (b->object == bo) - { - if (b->total != b->inverse + b->readonly || - b->readwrite_containers || - (poly && b->optimistic ())) - break; - - b = b->base; - if (b == 0 || !polymorphic (*b->object)) - { - b = 0; - break; - } - } - } - - // The same (tricky) logic as in load(). Note that here we are - // using the base section index to handle the special version - // update base. - // - if (b != 0) - os << "if (base)" << endl - << "info.base->find_section_update (" << b->index << - "UL) (esc." << m.name () << ".connection (), obj);" - << endl; - else - os << "ODB_POTENTIALLY_UNUSED (base);" - << endl; - } - - if (s.versioned || s.readwrite_versioned_containers) - os << "const schema_version_migration& svm (" << endl - << "esc." << m.name () << ".version_migration (" << - schema_name << "));" - << endl; - - // Update values, if any. - // - if (update || update_opt) - { - os << "using namespace " << db << ";" - << "using " << db << "::update_statement;" // Conflicts. - << endl - << "statements_type& sts (esc." << m.name () << ");" - << endl - << "image_type& im (sts.image ());" - << "const binding& id (sts.idv_binding ());" // id+version - << "binding& imb (sts.update_image_binding ());" - << endl; - - if (update) - { - if (generate_grow) - os << "if ("; - - os << "init (im, obj" << (s.versioned ? ", svm" : "") << ")"; - - if (generate_grow) - os << ")" << endl - << "im.version++"; - - os << ";" - << endl; - } - - os << "if (im.version != sts.update_image_version () ||" << endl - << "id.version != sts.update_id_binding_version () ||" << endl - << "imb.version == 0)" - << "{" - << "bind (imb.bind, id.bind, id.count, im, statement_update" << - (s.versioned ? ", svm" : "") << ");" - << "sts.update_image_version (im.version);" - << "sts.update_id_binding_version (id.version);" - << "imb.version++;" - << "}"; - - os << "update_statement& st (sts.update_statement ());" - << "if ("; - - if (s.versioned) - os << "!st.empty () && "; - - os << "st.execute () == 0)" << endl; - - if (opt == 0) - os << "throw object_not_persistent ();"; - else - os << "throw object_changed ();"; - - os << endl; - } - - // Update readwrite containers if any. - // - if (s.readwrite_containers) - { - instance t (container_calls::update_call, &s); - t->traverse (c_); - } - - // Update the optimistic concurrency version in the object member. - // Very similar code to object. - // - if (s.optimistic ()) // Note: not update_opt. - { - // Object is passed as const reference so we need to cast away - // constness. - // - const char* obj ("const_cast (obj)"); - string inc (optimistic_version_increment (*opt)); - - if (inc == "1") - inc_member (*opt, obj, "obj", "version_type"); - else - set_member (*opt, obj, inc, "", "version_type"); - } - - os << "}"; - } - - section_extra (s); - - if (rs != 0) - rs->base = 0; - } - - using class_::traverse; // Unhide. - - protected: - semantics::class_& c_; - string scope_; - }; - - // Output a list of parameters for the persist statement. - // - struct persist_statement_params: object_columns_base, virtual context - { - typedef persist_statement_params base; - - persist_statement_params (string& params, - query_parameters& qp, - const string& sep) - : params_ (params), qp_ (qp), sep_ (sep) - { - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - if (!inverse (m, key_prefix_)) - object_columns_base::traverse_pointer (m, c); - } - - virtual bool - traverse_column (semantics::data_member& m, - string const& name, - bool first) - { - string p; - - if (version (m)) - p = version_value (m); - else - { - const string& qname (quote_id (name)); - const string& type (column_type ()); - - p = auto_ (m) // Only simple, direct id can be auto. - ? qp_.auto_id (m, qname, type) - : qp_.next (m, qname, type); - } - - if (!p.empty ()) - { - if (!first) - { - params_ += ','; - params_ += sep_; - } - - params_ += (p != "DEFAULT" ? convert_to (p, column_type (), m) : p); - } - - return !p.empty (); - } - - virtual string - version_value (semantics::data_member&) - { - return "1"; - } - - private: - string& params_; - query_parameters& qp_; - const string& sep_; - }; - - // - // - struct class_: traversal::class_, virtual context - { - typedef class_ base; - - class_ () - : typedefs_ (false), - query_columns_type_ (false, false, false), - view_query_columns_type_ (false), - index_ (0), - grow_base_ (index_), - grow_member_ (index_), - grow_version_member_ (index_, "version_"), - grow_discriminator_member_ (index_, "discriminator_"), - bind_id_member_ ("id_"), - bind_version_member_ ("version_"), - bind_discriminator_member_ ("discriminator_"), - init_id_image_member_ ("id_", "id"), - init_version_image_member_ ("version_", "(*v)"), - init_view_pointer_member_pre_ (true, *init_value_member_), - init_view_pointer_member_post_ (false, *init_value_member_), - init_id_value_member_ ("id"), - init_id_value_member_id_image_ ("id", "id_"), - init_version_value_member_ ("v"), - init_named_version_value_member_ ("v", "version_"), - init_discriminator_value_member_ ("d", "", false), - init_named_discriminator_value_member_ ( - "d", "discriminator_", false) - { - init (); - } - - class_ (class_ const&) - : root_context (), //@@ -Wextra - context (), - typedefs_ (false), - query_columns_type_ (false, false, false), - view_query_columns_type_ (false), - index_ (0), - grow_base_ (index_), - grow_member_ (index_), - grow_version_member_ (index_, "version_"), - grow_discriminator_member_ (index_, "discriminator_"), - bind_id_member_ ("id_"), - bind_version_member_ ("version_"), - bind_discriminator_member_ ("discriminator_"), - init_id_image_member_ ("id_", "id"), - init_version_image_member_ ("version_", "(*v)"), - init_view_pointer_member_pre_ (true, *init_value_member_), - init_view_pointer_member_post_ (false, *init_value_member_), - init_id_value_member_ ("id"), - init_id_value_member_id_image_ ("id", "id_"), - init_version_value_member_ ("v"), - init_named_version_value_member_ ("v", "version_"), - init_discriminator_value_member_ ("d", "", false), - init_named_discriminator_value_member_ ( - "d", "discriminator_", false) - { - init (); - } - - void - init () - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - - if (generate_grow) - { - grow_base_inherits_ >> grow_base_; - grow_member_names_ >> grow_member_; - } - - bind_base_inherits_ >> bind_base_; - bind_member_names_ >> bind_member_; - - init_image_base_inherits_ >> init_image_base_; - init_image_member_names_ >> init_image_member_; - - init_value_base_inherits_ >> init_value_base_; - init_value_member_names_ >> init_value_member_; - - init_view_pointer_member_pre_names_ >> init_view_pointer_member_pre_; - init_view_pointer_member_post_names_ >> init_view_pointer_member_post_; - } - - virtual void - init_auto_id (semantics::data_member&, // id member - string const&) // image variable prefix - { - if (insert_send_auto_id) - assert (false); - } - - virtual void - init_image_pre (type&) - { - } - - virtual void - init_value_extra () - { - } - - virtual void - traverse (type& c) - { - class_kind_type ck (class_kind (c)); - - if (ck == class_other || - (!options.at_once () && class_file (c) != unit.file ())) - return; - - names (c); - - context::top_object = context::cur_object = &c; - - switch (ck) - { - case class_object: traverse_object (c); break; - case class_view: traverse_view (c); break; - case class_composite: traverse_composite (c); break; - default: break; - } - - context::top_object = context::cur_object = 0; - } - - // - // statements - // - - enum persist_position - { - persist_after_columns, - persist_after_values - }; - - virtual string - persist_statement_extra (type&, query_parameters&, persist_position) - { - return ""; - } - - virtual string - update_statement_extra (type&) - { - return ""; - } - - // - // common - // - - virtual void - post_query_ (type&, bool /*once_off*/) - { - } - - virtual void - process_statement_columns (statement_columns&, - statement_kind, - bool /*dynamic*/) - { - } - - // - // object - // - - virtual void - object_extra (type&) {} - - virtual void - extra_statement_cache_extra_args (bool /*containers*/, - bool /*sections*/) {} - - virtual void - object_query_statement_ctor_args (type&, - std::string const& q, - bool process, - bool /*prepared*/) - { - os << "conn," << endl - << "text," << endl - << process << "," << endl // Process. - << "true," << endl // Optimize. - << q << ".parameters_binding ()," << endl - << "imb"; - } - - virtual void - object_erase_query_statement_ctor_args (type&) - { - os << "conn," << endl - << "text," << endl - << "q.parameters_binding ()"; - } - - virtual string - optimistic_version_init (semantics::data_member&, bool /*index*/ = false) - { - return "1"; - } - - // Returning "1" means increment by one. - // - virtual string - optimistic_version_increment (semantics::data_member&, - bool /*index*/ = false) - { - return "1"; - } - - virtual bool - optimistic_insert_bind_version (semantics::data_member&) - { - return false; - } - - virtual void - traverse_object (type& c); - - // - // view - // - - virtual void - view_extra (type&) - { - } - - virtual void - view_query_statement_ctor_args (type&, - string const& q, - bool process, - bool /*prepared*/) - { - os << "conn," << endl - << q << ".clause ()," << endl - << process << "," << endl // Process. - << "true," << endl // Optimize. - << q << ".parameters_binding ()," << endl - << "imb"; - } - - virtual string - from_trailer (type&) { return "";} - - virtual string - select_trailer (type& c) - { - return c.get ("query").for_update ? "FOR UPDATE" : ""; - } - - virtual string - join_syntax (view_object const& vo) - { - const char* r (0); - - switch (vo.join) - { - case view_object::left: r = "LEFT JOIN"; break; - case view_object::right: r = "RIGHT JOIN"; break; - case view_object::full: r = "FULL JOIN"; break; - case view_object::inner: r = "INNER JOIN"; break; - case view_object::cross: r = "CROSS JOIN"; break; - } - - return r; - } - - virtual void - traverse_view (type& c); - - struct expression - { - explicit - expression (std::string const& v): kind (literal), value (v) {} - expression (view_object* vo): kind (pointer), vo (vo) {} - - enum kind_type {literal, pointer}; - - kind_type kind; - std::string value; - data_member_path member_path; - view_object* vo; - }; - - expression - translate_expression (type& c, - cxx_tokens const&, - semantics::scope& start_scope, - location_t loc, - string const& prag, - bool* placeholder = 0, - bool predicate = true); - // - // composite - // - - virtual void - traverse_composite (type& c) - { - bool versioned (context::versioned (c)); - - string const& type (class_fq_name (c)); - string traits ("access::composite_value_traits< " + type + ", id_" + - db.string () + " >"); - - os << "// " << class_name (c) << endl - << "//" << endl - << endl; - - // Containers. - // - { - instance t (c); - t->traverse (c); - } - - // grow () - // - if (generate_grow) - { - os << "bool " << traits << "::" << endl - << "grow (image_type& i," << endl - << truncated_vector << " t"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "bool grew (false);" - << endl; - - index_ = 0; - inherits (c, grow_base_inherits_); - names (c, grow_member_names_); - - os << "return grew;" - << "}"; - } - - // bind (image_type) - // - os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b," << endl - << "image_type& i," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (b);" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - if (readonly (c)) - os << "assert (sk != statement_update);" - << endl; - - os << "std::size_t n (0);" - << "ODB_POTENTIALLY_UNUSED (n);" - << endl; - - inherits (c, bind_base_inherits_); - names (c, bind_member_names_); - - os << "}"; - - // init (image, value) - // - os << (generate_grow ? "bool " : "void ") << traits << "::" << endl - << "init (image_type& i," << endl - << "const value_type& o," << endl - << db << "::statement_kind sk"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (sk);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl - << "using namespace " << db << ";" - << endl; - - if (readonly (c)) - os << "assert (sk != statement_update);" - << endl; - - if (generate_grow) - os << "bool grew (false);" - << endl; - - inherits (c, init_image_base_inherits_); - names (c, init_image_member_names_); - - if (generate_grow) - os << "return grew;"; - - os << "}"; - - // init (value, image) - // - os << "void " << traits << "::" << endl - << "init (value_type& o," << endl - << "const image_type& i," << endl - << "database* db"; - - if (versioned) - os << "," << endl - << "const schema_version_migration& svm"; - - os << ")" - << "{" - << "ODB_POTENTIALLY_UNUSED (o);" - << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (db);"; - - if (versioned) - os << "ODB_POTENTIALLY_UNUSED (svm);"; - - os << endl; - - inherits (c, init_value_base_inherits_); - names (c, init_value_member_names_); - - os << "}"; - } - - private: - traversal::defines defines_; - typedefs typedefs_; - - instance query_columns_type_; - instance view_query_columns_type_; - - size_t index_; - instance grow_base_; - traversal::inherits grow_base_inherits_; - instance grow_member_; - traversal::names grow_member_names_; - instance grow_version_member_; - instance grow_discriminator_member_; - - - instance bind_base_; - traversal::inherits bind_base_inherits_; - instance bind_member_; - traversal::names bind_member_names_; - instance bind_id_member_; - instance bind_version_member_; - instance bind_discriminator_member_; - - instance init_image_base_; - traversal::inherits init_image_base_inherits_; - instance init_image_member_; - traversal::names init_image_member_names_; - - instance init_id_image_member_; - instance init_version_image_member_; - - instance init_value_base_; - traversal::inherits init_value_base_inherits_; - instance init_value_member_; - traversal::names init_value_member_names_; - - instance init_view_pointer_member_pre_; - instance init_view_pointer_member_post_; - traversal::names init_view_pointer_member_pre_names_; - traversal::names init_view_pointer_member_post_names_; - - instance init_id_value_member_; - instance init_id_value_member_id_image_; - instance init_version_value_member_; - instance init_named_version_value_member_; - instance init_discriminator_value_member_; - instance init_named_discriminator_value_member_; - }; - - struct include: virtual context - { - typedef include base; - - virtual void - generate () - { - extra_pre (); - - os << "#include " << endl - << "#include // std::memcpy" << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - os << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - if (embedded_schema) - os << "#include " << endl; - - if (multi_dynamic) - os << "#include " << endl; - - os << endl; - - os << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl - << "#include " << endl; - - if (features.simple_object) - os << "#include " << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - if (features.no_id_object) - os << "#include " << endl; - - if (features.view) - os << "#include " << endl; - - if (features.section) - os << "#include " << endl; - - os << "#include " << endl - << "#include " << endl; - - if (options.generate_query ()) - { - if (options.generate_prepared ()) - os << "#include " << endl; - - if (features.simple_object) - os << "#include " << endl; - - if (features.polymorphic_object) - os << "#include " << endl; - - if (features.no_id_object) - os << "#include " << endl; - - if (features.view) - os << "#include " << endl; - } - - extra_post (); - - os << endl; - } - - virtual void - extra_pre () - { - } - - virtual void - extra_post () - { - } - }; - } -} - -#endif // ODB_RELATIONAL_SOURCE_HXX diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx deleted file mode 100644 index 03a3599..0000000 --- a/odb/relational/sqlite/common.cxx +++ /dev/null @@ -1,217 +0,0 @@ -// file : odb/relational/sqlite/common.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace relational -{ - namespace sqlite - { - // - // member_base - // - - sql_type const& member_base:: - member_sql_type (semantics::data_member& m) - { - return parse_sql_type (column_type (m, key_prefix_), m); - } - - void member_base:: - traverse_simple (member_info& mi) - { - switch (mi.st->type) - { - case sql_type::INTEGER: - { - traverse_integer (mi); - break; - } - case sql_type::REAL: - { - traverse_real (mi); - break; - } - case sql_type::TEXT: - { - if (mi.st->stream) - traverse_text_stream (mi); - else - traverse_text (mi); - break; - } - case sql_type::BLOB: - { - if (mi.st->stream) - traverse_blob_stream (mi); - else - traverse_blob (mi); - break; - } - case sql_type::invalid: - { - assert (false); - break; - } - } - } - - // - // member_image_type - // - - member_image_type:: - member_image_type (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_image_type:: - member_image_type () - : relational::member_base (0, 0, string (), string ()) {} - - member_image_type:: - member_image_type (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, ct, fq_type, key_prefix) {} - - string member_image_type:: - image_type (semantics::data_member& m) - { - type_.clear (); - member_base::traverse (m, true); - return type_; - } - - void member_image_type:: - traverse_composite (member_info& mi) - { - type_ = "composite_value_traits< " + mi.fq_type () + - ", id_sqlite >::image_type"; - } - - void member_image_type:: - traverse_integer (member_info&) - { - type_ = "long long"; - } - - void member_image_type:: - traverse_real (member_info&) - { - type_ = "double"; - } - - void member_image_type:: - traverse_string (member_info&) - { - type_ = "details::buffer"; - } - - void member_image_type:: - traverse_stream (member_info&) - { - type_ = "sqlite::stream_buffers"; - } - - entry member_image_type_; - - // - // member_database_type - // - - member_database_type_id:: - member_database_type_id (base const& x) - : member_base::base (x), // virtual base - base (x) {} - - member_database_type_id:: - member_database_type_id () - : member_base::base (0, 0, string (), string ()), // virtual base - base (0, 0, string (), string ()) {} - - member_database_type_id:: - member_database_type_id (semantics::type* type, - const custom_cxx_type* ct, - string const& fq_type, - string const& key_prefix) - : member_base::base (type, ct, fq_type, key_prefix), // virtual base - base (type, ct, fq_type, key_prefix) {} - - string member_database_type_id:: - database_type_id (type& m) - { - type_id_.clear (); - member_base::traverse (m, true); - return type_id_; - } - - void member_database_type_id:: - traverse_composite (member_info&) - { - assert (false); - } - - void member_database_type_id:: - traverse_integer (member_info&) - { - type_id_ = "sqlite::id_integer"; - } - - void member_database_type_id:: - traverse_real (member_info&) - { - type_id_ = "sqlite::id_real"; - } - - void member_database_type_id:: - traverse_text (member_info&) - { - type_id_ = "sqlite::id_text"; - } - - void member_database_type_id:: - traverse_blob (member_info&) - { - type_id_ = "sqlite::id_blob"; - } - - void member_database_type_id:: - traverse_text_stream (member_info&) - { - type_id_ = "sqlite::id_text_stream"; - } - - void member_database_type_id:: - traverse_blob_stream (member_info&) - { - type_id_ = "sqlite::id_blob_stream"; - } - - entry member_database_type_id_; - - // - // query_columns - // - - struct query_columns: relational::query_columns, context - { - query_columns (base const& x): base_impl (x) {} - - virtual string - database_type_id (semantics::data_member& m) - { - return member_database_type_id_.database_type_id (m); - } - - private: - member_database_type_id member_database_type_id_; - }; - entry query_columns_; - } -} diff --git a/odb/relational/sqlite/common.hxx b/odb/relational/sqlite/common.hxx deleted file mode 100644 index 4d6089e..0000000 --- a/odb/relational/sqlite/common.hxx +++ /dev/null @@ -1,147 +0,0 @@ -// file : odb/relational/sqlite/common.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SQLITE_COMMON_HXX -#define ODB_RELATIONAL_SQLITE_COMMON_HXX - -#include -#include - -namespace relational -{ - namespace sqlite - { - struct member_base: virtual relational::member_base_impl, context - { - member_base (base const& x): base (x), base_impl (x) {} - - // This c-tor is for the direct use inside the sqlite namespace. - // If you do use this c-tor, you should also explicitly call - // relational::member_base (aka base). - // - member_base () {} - - virtual sql_type const& - member_sql_type (semantics::data_member&); - - virtual void - traverse_simple (member_info&); - - virtual void - traverse_integer (member_info&) - { - } - - virtual void - traverse_real (member_info&) - { - } - - virtual void - traverse_text (member_info& m) - { - traverse_string (m); - } - - virtual void - traverse_blob (member_info& m) - { - traverse_string (m); - } - - // String covers both text and blob. - // - virtual void - traverse_string (member_info&) - { - } - - virtual void - traverse_text_stream (member_info& m) - { - traverse_stream (m); - } - - virtual void - traverse_blob_stream (member_info& m) - { - traverse_stream (m); - } - - virtual void - traverse_stream (member_info&) - { - } - }; - - struct member_image_type: relational::member_image_type, - member_base - { - member_image_type (base const&); - member_image_type (); - member_image_type (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - virtual string - image_type (semantics::data_member&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_real (member_info&); - - virtual void - traverse_string (member_info&); - - virtual void - traverse_stream (member_info&); - - private: - string type_; - }; - - struct member_database_type_id: relational::member_database_type_id, - member_base - { - member_database_type_id (base const&); - member_database_type_id (); - member_database_type_id (semantics::type* type, - const custom_cxx_type*, - string const& fq_type = string (), - string const& key_prefix = string ()); - - virtual string - database_type_id (type&); - - virtual void - traverse_composite (member_info&); - - virtual void - traverse_integer (member_info&); - - virtual void - traverse_real (member_info&); - - virtual void - traverse_text (member_info&); - - virtual void - traverse_blob (member_info&); - - virtual void - traverse_text_stream (member_info&); - - virtual void - traverse_blob_stream (member_info&); - - private: - string type_id_; - }; - } -} -#endif // ODB_RELATIONAL_SQLITE_COMMON_HXX diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx deleted file mode 100644 index 9a4369f..0000000 --- a/odb/relational/sqlite/context.cxx +++ /dev/null @@ -1,490 +0,0 @@ -// file : odb/relational/sqlite/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include -#include - -#include -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace - { - struct type_map_entry - { - char const* const cxx_type; - char const* const db_type; - char const* const db_id_type; - bool const null; - }; - - type_map_entry type_map[] = - { - {"bool", "INTEGER", 0, false}, - - {"char", "TEXT", 0, false}, - {"wchar_t", "TEXT", 0, false}, - {"signed char", "INTEGER", 0, false}, - {"unsigned char", "INTEGER", 0, false}, - - {"short int", "INTEGER", 0, false}, - {"short unsigned int", "INTEGER", 0, false}, - - {"int", "INTEGER", 0, false}, - {"unsigned int", "INTEGER", 0, false}, - - {"long int", "INTEGER", 0, false}, - {"long unsigned int", "INTEGER", 0, false}, - - {"long long int", "INTEGER", 0, false}, - {"long long unsigned int", "INTEGER", 0, false}, - - // SQLite stores NaN as NULL. - // - {"float", "REAL", 0, true}, - {"double", "REAL", 0, true}, - - {"::std::string", "TEXT", 0, false}, - {"::std::wstring", "TEXT", 0, false} - }; - } - - context* context::current_; - - context:: - ~context () - { - if (current_ == this) - current_ = 0; - } - - context:: - context (ostream& os, - semantics::unit& u, - options_type const& ops, - features_type& f, - sema_rel::model* m) - : root_context (os, u, ops, f, data_ptr (new (shared) data (os))), - base_context (static_cast (root_context::data_.get ()), m), - data_ (static_cast (base_context::data_)) - { - assert (current_ == 0); - current_ = this; - - generate_grow = true; - need_alias_as = true; - insert_send_auto_id = true; - delay_freeing_statement_result = false; - need_image_clone = false; - generate_bulk = false; - global_index = true; - global_fkey = false; - data_->bind_vector_ = "sqlite::bind*"; - data_->truncated_vector_ = "bool*"; - - // Populate the C++ type to DB type map. - // - for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i) - { - type_map_entry const& e (type_map[i]); - - type_map_type::value_type v ( - e.cxx_type, - db_type_type ( - e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null)); - - data_->type_map_.insert (v); - } - } - - context:: - context () - : data_ (current ().data_) - { - } - - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - - namespace - { - struct has_grow: traversal::class_ - { - has_grow (bool& r, user_section* s) - : r_ (r), section_ (s) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - // Ignore transient bases. - // - if (!(context::object (c) || context::composite (c))) - return; - - if (section_ == 0 && c.count ("sqlite-grow")) - r_ = c.get ("sqlite-grow"); - else - { - // r_ should be false. - // - inherits (c); - - if (!r_) - names (c); - - if (section_ == 0) - c.set ("sqlite-grow", r_); - } - } - - private: - bool& r_; - user_section* section_; - traversal::inherits inherits_; - }; - - struct has_grow_member: member_base - { - has_grow_member (bool& r, user_section* section = 0) - : relational::member_base (0, 0, string (), string (), section), - r_ (r) {} - - has_grow_member (bool& r, - user_section* section, - semantics::type* t, - const custom_cxx_type* ct, - string const& key_prefix = string ()) - : relational::member_base (t, ct, string (), key_prefix, section), - r_ (r) {} - - virtual bool - pre (member_info& mi) - { - // If we have a key prefix (container), then it can't be in a - // section (while mi.m can). The same for top-level -- if we got - // called, then we shouldn't ignore it. - // - return !key_prefix_.empty () || top_level_ || - (section_ == 0 && !separate_load (mi.m)) || - (section_ != 0 && *section_ == section (mi.m)); - } - - virtual void - traverse_composite (member_info& mi) - { - // By calling grow() instead of recursing, we reset any overrides. - // We also don't pass section since they don't apply inside - // composites. - // - r_ = r_ || context::grow (dynamic_cast (mi.t)); - } - - virtual void - traverse_string (member_info&) - { - r_ = true; - } - - private: - bool& r_; - }; - } - - bool context:: - grow_impl (semantics::class_& c, user_section* section) - { - if (section == 0 && c.count ("sqlite-grow")) - return c.get ("sqlite-grow"); - - bool r (false); - has_grow ct (r, section); - has_grow_member mt (r, section); - traversal::names names; - ct >> names >> mt; - ct.traverse (c); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m) - { - bool r (false); - has_grow_member mt (r); - mt.traverse (m, true); - return r; - } - - bool context:: - grow_impl (semantics::data_member& m, - semantics::type& t, - const custom_cxx_type* ct, - string const& kp) - { - bool r (false); - has_grow_member mt (r, 0, &t, ct, kp); - mt.traverse (m, true); - return r; - } - - string context:: - database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) - { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - - using semantics::array; - - // char[N] mapping. - // - if (array* a = dynamic_cast (&t)) - { - semantics::type& bt (a->base_type ()); - if (bt.is_a () || - bt.is_a ()) - { - if (a->size () != 0) - r = "TEXT"; - } - } - - return r; - } - - // - // SQL type parsing. - // - - namespace - { - struct sql_parser - { - typedef context::invalid_sql_type invalid_sql_type; - - sql_parser (custom_db_types const* ct): ct_ (ct) {} - - sql_type - parse (string sql) - { - sql_type r; - - // First run the type through the custom mapping, if requested. - // - if (ct_ != 0) - { - for (custom_db_types::const_iterator i (ct_->begin ()); - i != ct_->end (); ++i) - { - custom_db_type const& t (*i); - - if (t.type.match (sql)) - { - r.to = t.type.replace (sql, t.to); - r.from = t.type.replace (sql, t.from); - sql = t.type.replace (sql, t.as); - break; - } - } - } - - // Parse the type into a sequence of identifiers. - // - try - { - l_.lex (sql); - - for (sql_token t (l_.next ()); t.type () != sql_token::t_eos;) - { - sql_token::token_type tt (t.type ()); - - if (tt == sql_token::t_identifier) - { - ids_.push_back (context::upcase (t.identifier ())); - t = l_.next (); - - if (t.punctuation () == sql_token::p_lparen) - { - if (!parse_range ()) - return error (m_); - - t = l_.next (); - } - } - else - return error ("expected SQLite type name instead of '" + - t.string () + "'"); - } - } - catch (sql_lexer::invalid_input const& e) - { - return error ("invalid SQLite type declaration: " + e.message); - } - - if (ids_.empty ()) - return error ("expected SQLite type name"); - - // First check our own types. - // - if (ids_.size () == 2 && ids_[0] == "TEXT" && ids_[1] == "STREAM") - { - r.type = sql_type::TEXT; - r.stream = true; - } - if (ids_.size () == 2 && ids_[0] == "BLOB" && ids_[1] == "STREAM") - { - r.type = sql_type::BLOB; - r.stream = true; - } - // - // Apply the first four rules of the SQLite type to affinity - // conversion algorithm. - // - else if (find ("INT")) - r.type = sql_type::INTEGER; - else if (find ("TEXT") || find ("CHAR") || find ("CLOB")) - r.type = sql_type::TEXT; - else if (find ("BLOB")) - r.type = sql_type::BLOB; - else if (find ("REAL") || find ("FLOA") || find ("DOUB")) - r.type = sql_type::REAL; - else - { - // Instead of the fifth rule which maps everything else - // to NUMERICAL (which we don't have), map some commonly - // used type names to one of the above types. - // - string const& id (ids_[0]); - - if (id == "NUMERIC") - r.type = sql_type::REAL; - else if (id == "DECIMAL") - r.type = sql_type::TEXT; - else if (id == "BOOLEAN" || id == "BOOL") - r.type = sql_type::INTEGER; - else if (id == "DATE" || id == "TIME" || id == "DATETIME") - r.type = sql_type::TEXT; - else - return error ("unknown SQLite type '" + id + "'"); - } - - return r; - } - - bool - parse_range () - { - // Skip tokens until we get the closing paren. - // - for (sql_token t (l_.next ());; t = l_.next ()) - { - if (t.punctuation () == sql_token::p_rparen) - break; - - if (t.type () == sql_token::t_eos) - { - m_ = "missing ')' in SQLite type declaration"; - return false; - } - } - - return true; - } - - private: - sql_type - error (string const& m) - { - if (ct_ == 0) - return sql_type (); - else - throw invalid_sql_type (m); - } - - bool - find (string const& str) const - { - for (identifiers::const_iterator i (ids_.begin ()); - i != ids_.end (); ++i) - { - if (i->find (str) != string::npos) - return true; - } - - return false; - } - - private: - custom_db_types const* ct_; - sql_lexer l_; - string m_; // Error message. - - typedef vector identifiers; - identifiers ids_; - }; - } - - sql_type const& context:: - parse_sql_type (string const& t, semantics::data_member& m, bool custom) - { - // If this proves to be too expensive, we can maintain a cache of - // parsed types across contexts. - // - data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - - if (i != data_->sql_type_cache_.end () - && (custom ? i->second.custom_cached : i->second.straight_cached)) - { - return (custom ? i->second.custom : i->second.straight); - } - else - { - try - { - sql_type st ( - parse_sql_type ( - t, - custom ? &unit.get ("custom-db-types") : 0)); - - if (custom) - return data_->sql_type_cache_[t].cache_custom (st); - else - return data_->sql_type_cache_[t].cache_straight (st); - } - catch (invalid_sql_type const& e) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: " << e.message () << endl; - - throw operation_failed (); - } - } - } - - sql_type context:: - parse_sql_type (string const& sqlt, custom_db_types const* ct) - { - sql_parser p (ct); - return p.parse (sqlt); - } - } -} diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx deleted file mode 100644 index 777998b..0000000 --- a/odb/relational/sqlite/context.hxx +++ /dev/null @@ -1,146 +0,0 @@ -// file : odb/relational/sqlite/context.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_SQLITE_CONTEXT_HXX -#define ODB_RELATIONAL_SQLITE_CONTEXT_HXX - -#include - -#include - -namespace relational -{ - namespace sqlite - { - struct sql_type - { - // Keep the order in each block of types. - // - enum core_type - { - INTEGER, - REAL, - TEXT, - BLOB, - invalid - }; - - sql_type (): type (invalid), stream (false) {} - - core_type type; - bool stream; // TEXT or BLOB via sqlite3_blob_open(). - - // Conversion expressions for custom database types. - // - std::string to; - std::string from; - }; - - class context: public virtual relational::context - { - public: - sql_type const& - parse_sql_type (string const&, - semantics::data_member&, - bool custom = true); - public: - struct invalid_sql_type - { - invalid_sql_type (string const& message): message_ (message) {} - - string const& - message () const {return message_;} - - private: - string message_; - }; - - // If custom_db_types is NULL, then this function returns - // invalid type instead of throwing in case an unknown type - // is encountered. - // - static sql_type - parse_sql_type (string const&, custom_db_types const* = 0); - - protected: - virtual string const& - convert_expr (string const&, semantics::data_member&, bool); - - virtual bool - grow_impl (semantics::class_&, user_section*); - - virtual bool - grow_impl (semantics::data_member&); - - virtual bool - grow_impl (semantics::data_member&, - semantics::type&, - const custom_cxx_type*, - string const&); - - protected: - virtual string - database_type_impl (semantics::type&, semantics::names*, bool, bool*); - - public: - virtual - ~context (); - context (); - context (std::ostream&, - semantics::unit&, - options_type const&, - features_type& f, - sema_rel::model*); - - static context& - current () - { - return *current_; - } - - private: - static context* current_; - - private: - struct data: base_context::data - { - data (std::ostream& os): base_context::data (os) {} - - struct sql_type_cache_entry - { - sql_type_cache_entry () - : custom_cached (false), straight_cached (false) {} - - sql_type const& - cache_custom (sql_type const& t) - { - custom = t; - custom_cached = true; - return custom; - } - - sql_type const& - cache_straight (sql_type const& t) - { - straight = t; - straight_cached = true; - return straight; - } - - sql_type custom; // With custom mapping. - sql_type straight; // Without custom mapping. - - bool custom_cached; - bool straight_cached; - }; - - typedef std::map sql_type_cache; - sql_type_cache sql_type_cache_; - }; - - data* data_; - }; - } -} - -#endif // ODB_RELATIONAL_SQLITE_CONTEXT_HXX diff --git a/odb/relational/sqlite/header.cxx b/odb/relational/sqlite/header.cxx deleted file mode 100644 index 1aafe7a..0000000 --- a/odb/relational/sqlite/header.cxx +++ /dev/null @@ -1,63 +0,0 @@ -// file : odb/relational/sqlite/header.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -namespace relational -{ - namespace sqlite - { - namespace header - { - namespace relational = relational::header; - - struct image_member: relational::image_member_impl, - member_base - { - image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_real (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - - virtual void - traverse_stream (member_info& mi) - { - os << image_type << " " << mi.var << "value;" - << "std::size_t " << mi.var << "size;" - << "bool " << mi.var << "null;" - << endl; - } - }; - entry image_member_; - } - } -} diff --git a/odb/relational/sqlite/inline.cxx b/odb/relational/sqlite/inline.cxx deleted file mode 100644 index dd3274f..0000000 --- a/odb/relational/sqlite/inline.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/relational/sqlite/inline.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace inline_ - { - namespace relational = relational::inline_; - - struct null_member: relational::null_member_impl, - member_base - { - null_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_simple (member_info& mi) - { - if (get_) - os << "r = r && i." << mi.var << "null;"; - else - os << "i." << mi.var << "null = true;"; - } - }; - entry null_member_; - } - } -} diff --git a/odb/relational/sqlite/model.cxx b/odb/relational/sqlite/model.cxx deleted file mode 100644 index da16ded..0000000 --- a/odb/relational/sqlite/model.cxx +++ /dev/null @@ -1,91 +0,0 @@ -// file : odb/relational/sqlite/model.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace model - { - namespace relational = relational::model; - - struct object_columns: relational::object_columns, context - { - object_columns (base const& x): base (x) {} - - virtual string - type (semantics::data_member& m) - { - // Translate BLOB|TEXT STREAM to just BLOB|TEXT. - // - string r (relational::object_columns::type (m)); - - sql_type const& t (parse_sql_type (r, m, false)); - if (t.stream) - { - switch (t.type) - { - case sql_type::BLOB: r = "BLOB"; break; - case sql_type::TEXT: r = "TEXT"; break; - default: break; - } - } - - return r; - } - - virtual bool - null (semantics::data_member& m) - { - return options.sqlite_override_null () || base::null (m); - } - - virtual string - default_enum (semantics::data_member& m, tree en, string const&) - { - // Make sure the column is mapped to INTEGER. - // - sql_type const& t (parse_sql_type (column_type (), m, false)); - if (t.type != sql_type::INTEGER) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: column with default value specified as C++ " - << "enumerator must map to SQLite INTEGER" << endl; - - throw operation_failed (); - } - - using semantics::enumerator; - - enumerator& e (dynamic_cast (*unit.find (en))); - - ostringstream ostr; - - if (e.enum_ ().unsigned_ ()) - ostr << e.value (); - else - ostr << static_cast (e.value ()); - - return ostr.str (); - } - - virtual void - primary_key (sema_rel::primary_key& pk) - { - if (pk.auto_ () && options.sqlite_lax_auto_id ()) - pk.extra ()["lax"] = "true"; - } - }; - entry object_columns_; - } - } -} diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx deleted file mode 100644 index f5549b4..0000000 --- a/odb/relational/sqlite/schema.cxx +++ /dev/null @@ -1,455 +0,0 @@ -// file : odb/relational/sqlite/schema.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -namespace relational -{ - namespace sqlite - { - namespace schema - { - namespace relational = relational::schema; - - // - // Drop. - // - - struct drop_column: trav_rel::drop_column, relational::common - { - drop_column (relational::common const& c) - : relational::common (c), first_ (true) {} - - virtual void - traverse (sema_rel::drop_column& dc) - { - // SQLite does not support dropping columns. If this column is - // not NULLable, then there is nothing we can do. Otherwise, do - // a logical DROP by setting all the values to NULL. - // - sema_rel::column& c (find (dc)); - - if (!c.null ()) - { - cerr << "error: SQLite does not support dropping of columns" << - endl; - cerr << "info: first dropped column is '" << dc.name () << - "' in table '" << dc.table ().name () << "'" << endl; - cerr << "info: could have performed logical drop if the column " << - "allowed NULL values" << endl; - throw operation_failed (); - } - - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - os << quote_id (dc.name ()) << " = NULL"; - } - - private: - bool first_; - }; - // Not registered as an override. - - struct drop_index: relational::drop_index, context - { - drop_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In SQLite, index names can be qualified with the database. - // - sema_rel::table& t (static_cast (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - return quote_id (n); - } - }; - entry drop_index_; - - struct drop_table: relational::drop_table, context - { - drop_table (base const& x): base (x) {} - - virtual void - traverse (sema_rel::table& t, bool migration) - { - // In SQLite there is no way to drop foreign keys except as part - // of the table. - // - if (pass_ != 2) - return; - - // Polymorphic base cleanup code. Because we cannot drop foreign - // keys, we will trigger cascade deletion. The only way to work - // around this problem is to delete from the root table and rely - // on the cascade to clean up the rest. - // - if (migration && t.extra ()["kind"] == "polymorphic derived object") - { - using sema_rel::model; - using sema_rel::table; - using sema_rel::primary_key; - using sema_rel::foreign_key; - - model& m (dynamic_cast (t.scope ())); - - table* p (&t); - do - { - // The polymorphic link is the first primary key. - // - for (table::names_iterator i (p->names_begin ()); - i != p->names_end (); ++i) - { - if (foreign_key* fk = dynamic_cast ( - &i->nameable ())) - { - p = m.find
(fk->referenced_table ()); - assert (p != 0); // Base table should be there. - break; - } - } - } - while (p->extra ()["kind"] != "polymorphic root object"); - - primary_key& rkey (*p->find ("")); - primary_key& dkey (*t.find ("")); - assert (rkey.contains_size () == dkey.contains_size ()); - delete_ (p->name (), t.name (), rkey, dkey); - } - - drop (t, migration); - } - }; - entry drop_table_; - - // - // Create. - // - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::add_column& ac) - { - using sema_rel::alter_table; - using sema_rel::add_column; - using sema_rel::add_foreign_key; - - alter_table& at (static_cast (ac.scope ())); - - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ADD COLUMN "; - - // In SQLite it is impossible to alter a column later, so unless - // it has a default value, we add it as NULL. Without this, it - // will be impossible to add a column to a table that contains - // some rows. - // - create (ac); - - // SQLite doesn't support adding foreign keys other than inline - // via a column definition. See if we can handle any. - // - add_foreign_key* afk (0); - - for (add_column::contained_iterator i (ac.contained_begin ()); - i != ac.contained_end (); - ++i) - { - if ((afk = dynamic_cast (&i->key ()))) - { - // Check that it is a single-column foreign key. Also make - // sure the column and foreign key are from the same changeset. - // - if (afk->contains_size () != 1 || &ac.scope () != &afk->scope ()) - afk = 0; - else - break; - } - } - - if (afk != 0) - { - os << " CONSTRAINT " << quote_id (afk->name ()) << " REFERENCES " << - quote_id (afk->referenced_table ().uname ()) << " (" << - quote_id (afk->referenced_columns ()[0]) << ")"; - - bool del (afk->on_delete () != sema_rel::foreign_key::no_action); - bool def (!afk->not_deferrable ()); - - if (del || def) - { - instance cfk (*this); - - if (del) - cfk->on_delete (afk->on_delete ()); - - if (def) - cfk->deferrable (afk->deferrable ()); - } - - afk->set ("sqlite-fk-defined", true); // Mark it as defined. - } - - os << endl; - post_statement (); - } - - virtual void - auto_ (sema_rel::primary_key& pk) - { - if (pk.extra ().count ("lax")) - os << " /*AUTOINCREMENT*/"; - else - os << " AUTOINCREMENT"; - } - }; - entry create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - virtual void - traverse (sema_rel::foreign_key& fk) - { - // In SQLite, all constraints are defined as part of a table. - // - os << "," << endl - << " CONSTRAINT "; - - create (fk); - } - - virtual string - table_name (sema_rel::foreign_key& fk) - { - // In SQLite, the referenced table cannot be qualified with the - // database name (it has to be in the same database anyway). - // - return quote_id (fk.referenced_table ().uname ()); - } - }; - entry create_foreign_key_; - - struct create_index: relational::create_index, context - { - create_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In SQLite, index names can be qualified with the database. - // - sema_rel::table& t (static_cast (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - return quote_id (n); - } - - virtual string - table_name (sema_rel::index& in) - { - // In SQLite, the index table cannot be qualified with the - // database name (it has to be in the same database). - // - return quote_id ( - static_cast (in.scope ()).name ().uname ()); - } - }; - entry create_index_; - - struct create_table: relational::create_table, context - { - create_table (base const& x): base (x) {} - - void - traverse (sema_rel::table& t) - { - // For SQLite we do everything in a single pass since there - // is no way to add constraints later. - // - if (pass_ == 1) - create (t); - } - }; - entry create_table_; - - // - // Alter. - // - - struct alter_table_pre: relational::alter_table_pre, context - { - alter_table_pre (base const& x): base (x) {} - - virtual void - alter (sema_rel::alter_table& at) - { - // SQLite can only add a single column per ALTER TABLE statement. - // - instance cc (*this); - trav_rel::unames n (*cc); - names (at, n); - - // SQLite does not support altering columns. - // - if (sema_rel::alter_column* ac = check (at)) - { - cerr << "error: SQLite does not support altering of columns" - << endl; - cerr << "info: first altered column is '" << ac->name () << - "' in table '" << at.name () << "'" << endl; - throw operation_failed (); - } - - // SQLite does not support dropping constraints. We are going to - // ignore this if the column is NULL'able since in most cases - // the constraint is going to be dropped as a result of the - // column drop (e.g., an object pointer member got deleted). - // If we were not to allow this, then it would be impossible - // to do logical drop for pointer columns. - // - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - using sema_rel::foreign_key; - using sema_rel::drop_foreign_key; - - drop_foreign_key* dfk ( - dynamic_cast (&i->nameable ())); - - if (dfk == 0) - continue; - - foreign_key& fk (find (*dfk)); - - for (foreign_key::contains_iterator j (fk.contains_begin ()); - j != fk.contains_end (); ++j) - { - if (j->column ().null ()) - continue; - - cerr << "error: SQLite does not support dropping of foreign " << - "keys" << endl; - cerr << "info: first dropped foreign key is '" << dfk->name () << - "' in table '" << at.name () << "'" << endl; - cerr << "info: could have ignored it if the contained " << - "column(s) allowed NULL values" << endl; - throw operation_failed (); - } - } - } - }; - entry alter_table_pre_; - - struct alter_table_post: relational::alter_table_post, context - { - alter_table_post (base const& x): base (x) {} - - virtual void - alter (sema_rel::alter_table& at) - { - // SQLite does not support altering columns (we have to do this - // in both alter_table_pre/post because of the - // check_alter_column_null() test in the common code). - // - if (sema_rel::alter_column* ac = check (at)) - { - cerr << "error: SQLite does not support altering of columns" - << endl; - cerr << "info: first altered column is '" << ac->name () << - "' in table '" << at.name () << "'" << endl; - throw operation_failed (); - } - - // Try to do logical column drop. - // - if (check (at)) - { - pre_statement (); - - os << "UPDATE " << quote_id (at.name ()) << endl - << " SET "; - - drop_column dc (*this); - trav_rel::unames n (dc); - names (at, n); - os << endl; - - post_statement (); - } - - // SQLite doesn't support adding foreign keys other than inline - // via a column definition. See if there are any that we couldn't - // handle that way. - // - for (sema_rel::alter_table::names_iterator i (at.names_begin ()); - i != at.names_end (); ++i) - { - sema_rel::add_foreign_key* afk ( - dynamic_cast (&i->nameable ())); - - if (afk == 0 || afk->count ("sqlite-fk-defined")) - continue; - - cerr << "error: SQLite does not support adding foreign keys" - << endl; - cerr << "info: first added foreign key is '" << afk->name () << - "' in table '" << at.name () << "'" << endl; - throw operation_failed (); - } - } - }; - entry alter_table_post_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x): base (x) {} - - virtual void - create_table () - { - pre_statement (); - - os << "CREATE TABLE IF NOT EXISTS " << qt_ << " (" << endl - << " " << qn_ << " TEXT NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " INTEGER NOT NULL," << endl - << " " << qm_ << " INTEGER NOT NULL)" << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - os << "INSERT OR IGNORE INTO " << qt_ << " (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", 0)" << endl; - - post_statement (); - } - }; - entry version_table_; - } - } -} diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx deleted file mode 100644 index 5a4b9d3..0000000 --- a/odb/relational/sqlite/source.cxx +++ /dev/null @@ -1,471 +0,0 @@ -// file : odb/relational/sqlite/source.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include - -using namespace std; - -namespace relational -{ - namespace sqlite - { - namespace source - { - namespace relational = relational::source; - - struct query_parameters: relational::query_parameters, context - { - query_parameters (base const& x): base (x) {} - - virtual string - next (semantics::data_member& m, - const string& column, - const string& sqlt) - { - // Handle stream columns. Specifically, we somehow need to - // pass the column name to the code that runs in the - // statement. So what we are going to do is encode it - // in the parameter name. - // - if (sk_ == statement_insert || sk_ == statement_update) - { - const sql_type& t (parse_sql_type (sqlt, m, false)); - if (t.stream) - { - // The column name is quoted. - // - string r (column); - r[0] = '$'; // Replace leading '"'. - r.resize (r.size () - 1); // Remove trailing '"'. - - // Verify it only contains allowed characters. - // - for (size_t i (1); i != r.size (); ++i) - { - char c (r[i]); - if (c != '_' && - (c < '0' || c > '9') && - (c < 'a' || c > 'z') && - (c < 'A' || c > 'Z')) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": error: unsupported character '" << c << "' in " - << sqlt << " column name " << column << endl; - - cerr << m.file () << ":" << m.line () << ":" << m.column () - << ": info: STREAM column can contain alpha-numeric " - << "characters plus '_'" << endl; - - throw operation_failed (); - } - } - - // For TEXT columns, since we use the *_bind_zeroblob() - // function (there is no *_bind_zerotext()), the value - // that will be stored is BLOB, not TEXT, unless we - // explicitly CAST it. The user better make sure the - // encoding of raw TEXT data they are going to write - // matches the database encoding. - // - if (t.type == sql_type::TEXT) - r = "CAST(" + r + " AS TEXT)"; - - return r; - } - } - - return "?"; - } - }; - entry query_parameters_; - - // - // bind - // - - struct bind_member: relational::bind_member_impl, - member_base - { - bind_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - traverse_integer (member_info& mi) - { - os << b << ".type = sqlite::bind::integer;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_real (member_info& mi) - { - os << b << ".type = sqlite::bind::real;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_text (member_info& mi) - { - os << b << ".type = sqlite::image_traits<" << endl - << " " << mi.fq_type () << "," << endl - << " sqlite::id_text>::bind_value;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_blob (member_info& mi) - { - os << b << ".type = sqlite::bind::blob;" - << b << ".buffer = " << arg << "." << mi.var << "value.data ();" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".capacity = " << arg << "." << mi.var << - "value.capacity ();" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - - virtual void - traverse_stream (member_info& mi) - { - os << b << ".type = sqlite::bind::stream;" - << b << ".buffer = &" << arg << "." << mi.var << "value;" - << b << ".size = &" << arg << "." << mi.var << "size;" - << b << ".is_null = &" << arg << "." << mi.var << "null;"; - } - }; - entry bind_member_; - - // - // grow - // - - struct grow_member: relational::grow_member_impl, - member_base - { - grow_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) {} - - virtual void - traverse_integer (member_info&) - { - os << e << " = false;" - << endl; - } - - virtual void - traverse_real (member_info&) - { - os << e << " = false;" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << "if (" << e << ")" << endl - << "{" - << "i." << mi.var << "value.capacity (i." << mi.var << "size);" - << "grew = true;" - << "}"; - } - - virtual void - traverse_stream (member_info&) - { - os << e << " = false;" - << endl; - } - }; - entry grow_member_; - - // - // init image - // - - struct init_image_member: relational::init_image_member_impl, - member_base - { - init_image_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - set_null (member_info& mi) - { - os << "i." << mi.var << "null = true;"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_real (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;"; - } - - virtual void - traverse_string (member_info& mi) - { - os << "std::size_t cap (i." << mi.var << "value.capacity ());" - << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;" - << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; - } - - virtual void - traverse_stream (member_info& mi) - { - os << traits << "::set_image (" << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "is_null," << endl - << member << ");" - << "i." << mi.var << "null = is_null;"; - } - }; - entry init_image_member_; - - // - // init value - // - - struct init_value_member: relational::init_value_member_impl, - member_base - { - init_value_member (base const& x) - : member_base::base (x), // virtual base - member_base::base_impl (x), // virtual base - base_impl (x), - member_base (x) - { - } - - virtual void - get_null (string const& var) const - { - os << "i." << var << "null"; - } - - virtual void - traverse_integer (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_real (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_string (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - - virtual void - traverse_stream (member_info& mi) - { - os << traits << "::set_value (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "i." << mi.var << "size," << endl - << "i." << mi.var << "null);" - << endl; - } - }; - entry init_value_member_; - - struct statement_columns_common: context - { - void - process (relational::statement_columns& cs, statement_kind sk) - { - using relational::statement_columns; - - // For SELECT statements, add _ROWID_ "follow-up" column to - // each stream column. The reason we need both, and not just - // ROWID is the NULL value. Let's hope that SELECT'ing a BLOB - // but not actually reading it with sqlite3_result_blob() is - // as fast as not SELECT'ing it. - // - if (sk != statement_select) - return; - - for (statement_columns::iterator i (cs.begin ()); - i != cs.end (); ++i) - { - if (parse_sql_type (i->type, *i->member).stream) - { - // Column is already table-qualified and quoted. Do some - // surgery to replace it with _ROWID_. That is, we want to - // transform "table"."column" to "table"."_ROWID_". - // - string c (i->column); - string::size_type n (c.size ()), p (c.rfind ('"', n - 2)); - assert (p != string::npos); - string as (c, p + 1, n - p - 2); - c.resize (p); - c += "\"_ROWID_\""; - - // We are going to pack this "tightly", without any newlines, - // so that the statement processing code treats them as a - // single column. - // - i->column += ','; - i->column += c; - } - } - } - }; - - struct container_traits: relational::container_traits, - statement_columns_common - { - container_traits (base const& x): base (x) {} - - virtual void - cache_result (string const&) - { - // Caching is not necessary since SQLite can execute several - // interleaving statements. - // - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool) - { - statement_columns_common::process (cols, sk); - } - }; - entry container_traits_; - - struct section_traits: relational::section_traits, - statement_columns_common - { - section_traits (base const& x): base (x) {} - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool) - { - statement_columns_common::process (cols, sk); - } - }; - entry section_traits_; - - struct class_: relational::class_, statement_columns_common - { - class_ (base const& x): base (x) {} - - virtual void - init_auto_id (semantics::data_member& m, string const& im) - { - // Don't set the id value to NULL if this is a nullable wrapper. - // This will allow the user to control whether the value is auto or - // manually assigned by using something like this: - // - // #pragma db auto - // odb::nullable id; - // - semantics::type& t (utype (m)); - if (wrapper (t) && t.template get ("wrapper-null-handler")) - return; - - os << im << "null = true;" - << endl; - } - - virtual string - select_trailer (type&) - { - // SQLite has not support for FOR UPDATE and since this is an - // optimization, we simply ignore it. - // - return ""; - } - - virtual string - join_syntax (view_object const& vo) - { - const char* n (0); - - if (vo.join == view_object::full) - n = "FULL OUTER JOIN"; - else if (vo.join == view_object::right) - n = "RIGHT OUTER JOIN"; - - if (n != 0) - { - error (vo.loc) << n << " is not supported by SQLite" << endl; - throw operation_failed (); - } - - return base::join_syntax (vo); - } - - virtual void - process_statement_columns (relational::statement_columns& cols, - statement_kind sk, - bool) - { - statement_columns_common::process (cols, sk); - } - }; - entry class_entry_; - } - } -} diff --git a/odb/relational/validator.cxx b/odb/relational/validator.cxx deleted file mode 100644 index 50c887e..0000000 --- a/odb/relational/validator.cxx +++ /dev/null @@ -1,638 +0,0 @@ -// file : odb/relational/validator.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; - -namespace relational -{ - namespace - { - // - // Pass 2. - // - - struct data_member2: traversal::data_member, context - { - data_member2 (bool& valid) - : valid_ (valid) - { - } - - virtual void - traverse (type& m) - { - if (transient (m)) - return; - - if (null (m)) - { - if (semantics::class_* c = composite_wrapper (utype (m))) - { - if (has_a (*c, test_container)) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: composite member containing containers cannot " - << "be null" << endl; - - os << c->file () << ":" << c->line () << ":" << c->column () - << ": info: composite value type is defined here" << endl; - - valid_ = false; - } - } - } - - // Check on-delete. - // - if (m.count ("on-delete")) - { - const char* kp (container (m) ? "value" : ""); - location l (m.location ()); - - // Make sure it is a pointer or a member with points_to pragma. - // - if (!object_pointer (utype (m, kp)) && !points_to (m)) - { - error (l) << "on_delete specified for non-object pointer" << endl; - valid_ = false; - } - - // Make sure it is not inverse. - // - if (inverse (m, kp)) - { - error (l) << "on_delete specified for inverse object " << - "pointer" << endl; - valid_ = false; - } - - // Make sure the pointer is nullable if asked to set it to NULL. - // - using sema_rel::foreign_key; - - if (m.get ("on-delete") == - foreign_key::set_null && - !null (m, kp)) - { - error (l) << "set_null specified for non-nullable object " - "pointer" << endl; - valid_ = false; - } - } - } - - bool& valid_; - }; - - struct object_no_id_members: object_members_base - { - object_no_id_members (bool& valid) - : object_members_base (false, false, true), valid_ (valid), dm_ (0) - { - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_&) - { - if (inverse (m)) - { - semantics::data_member& dm (dm_ != 0 ? *dm_ : m); - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << " error: inverse object pointer member '" << member_prefix_ - << m.name () << "' in an object without an object id" << endl; - - valid_ = false; - } - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - semantics::data_member& dm (dm_ != 0 ? *dm_ : m); - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << " error: container member '" << member_prefix_ << m.name () - << "' in an object without an object id" << endl; - - valid_ = false; - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - semantics::data_member* old_dm (dm_); - - if (dm_ == 0) - dm_ = m; - - object_members_base::traverse_composite (m, c); - - dm_ = old_dm; - } - - private: - bool& valid_; - semantics::data_member* dm_; // Direct object data member. - }; - - struct composite_id_members: object_members_base - { - composite_id_members (bool& valid) - : object_members_base (false, false, true), valid_ (valid), dm_ (0) - { - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_&) - { - semantics::data_member& dm (dm_ != 0 ? *dm_ : m); - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << " error: object pointer member '" << member_prefix_ << m.name () - << "' in a composite value type that is used as an object id" - << endl; - - valid_ = false; - } - - virtual void - traverse_simple (semantics::data_member& m) - { - if (readonly (member_path_, member_scope_)) - { - semantics::data_member& dm (dm_ != 0 ? *dm_ : m); - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << " error: readonly member '" << member_prefix_ << m.name () - << "' in a composite value type that is used as an object id" - << endl; - - valid_ = false; - } - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - semantics::data_member& dm (dm_ != 0 ? *dm_ : m); - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << " error: container member '" << member_prefix_ << m.name () - << "' in a composite value type that is used as an object id" - << endl; - - valid_ = false; - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - semantics::data_member* old_dm (dm_); - - if (dm_ == 0) - dm_ = m; - - object_members_base::traverse_composite (m, c); - - dm_ = old_dm; - } - - private: - bool& valid_; - semantics::data_member* dm_; // Direct composite member. - }; - - struct view_members: object_members_base - { - view_members (bool& valid) - : object_members_base (false, false, true), valid_ (valid), dm_ (0) - { - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_&) - { - if (dm_ != 0 && object_pointer (utype (m))) - { - location const& l (dm_->location ()); - - error (l) << "nested view data member '" << member_prefix_ - << m.name () << "' is an object pointer" << endl; - info (l) << "views can only contain direct object pointer members" - << endl; - - valid_ = false; - } - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - semantics::data_member& dm (dm_ != 0 ? *dm_ : m); - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << " error: view data member '" << member_prefix_ << m.name () - << "' is a container" << endl; - - os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" - << ": info: views cannot contain containers" << endl; - - valid_ = false; - } - - virtual void - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - semantics::data_member* old_dm (dm_); - - if (dm_ == 0) - dm_ = m; - - object_members_base::traverse_composite (m, c); - - dm_ = old_dm; - } - - private: - bool& valid_; - semantics::data_member* dm_; // Direct view data member. - }; - - struct class2: traversal::class_, context - { - class2 (bool& valid) - : valid_ (valid), - typedefs_ (true), - data_member_ (valid), - object_no_id_members_ (valid), - composite_id_members_ (valid), - view_members_ (valid) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - - data_member_names_ >> data_member_; - } - - virtual void - traverse (type& c) - { - class_kind_type ck (class_kind (c)); - switch (ck) - { - case class_object: - names (c); - traverse_object (c); - break; - case class_view: - names (c); - traverse_view (c); - break; - case class_composite: - names (c); - traverse_composite (c); - break; - case class_other: - break; - } - - // Make sure indexes are not defined for anything other than objects. - // - if (c.count ("index") && ck != class_object) - { - indexes& ins (c.get ("index")); - - for (indexes::iterator i (ins.begin ()); i != ins.end (); ++i) - { - error (i->loc) << "index definition on a non-persistent class" - << endl; - valid_ = false; - } - } - } - - virtual void - traverse_object (type& c) - { - data_member_path* id (id_member (c)); - - if (id != 0) - { - if (semantics::class_* cm = composite_wrapper (utype (*id))) - { - location idl (id->front ()->location ()); - - // Composite id cannot be auto. - // - if (auto_ (*id)) - { - error (idl) << "composite id cannot be automatically assigned" - << endl; - valid_ = false; - } - - // Make sure we don't have any containers or pointers in this - // composite value type. - // - if (valid_) - { - composite_id_members_.traverse (*cm); - - if (!valid_) - info (idl) << "composite id is defined here" << endl; - } - - // Check that the composite value type is default-constructible. - // - if (!cm->default_ctor ()) - { - os << cm->file () << ":" << cm->line () << ":" << cm->column () - << ": error: composite value type that is used as object id " - << "is not default-constructible" << endl; - - os << cm->file () << ":" << cm->line () << ":" << cm->column () - << ": info: provide default constructor for this value type" - << endl; - - info (idl) << "composite id is defined here" << endl; - - valid_ = false; - } - } - } - else - { - if (!abstract (c)) - { - // Make sure we don't have any containers or inverse pointers. - // - object_no_id_members_.traverse (c); - } - } - - names (c, data_member_names_); - - // Validate bulk operation support. - // - for (bool i (true); i && c.count ("bulk"); i = false) - { - location_t l (c.get ("bulk-location")); - - if (polymorphic (c)) - { - error (l) << "bulk operations on polymorphic objects are " - "not supported" << endl; - valid_ = false; - break; - } - - if (has_a (c, test_straight_container)) - { - error (l) << "bulk operations on objects with containers are " - "not supported" << endl; - valid_ = false; - break; - } - - bool update (true); - - // Unless we only have manually-updated sections, we cannot generate - // the bulk update operation. - // - user_sections& uss (c.get ("user-sections")); - - for (user_sections::iterator i (uss.begin ()); - update && i != uss.end (); - ++i) - { - const user_section& s (*i); - - // Skip special sections. - // - if (s.special != user_section::special_ordinary) - continue; - - // Always-updated section still needs a separate statement - // (since it may not be loaded). - // - if (!s.update_empty () && s.update != user_section::update_manual) - update = false; - } - - c.set ("bulk-persist", true); - if (update) c.set ("bulk-update", true); - c.set ("bulk-erase", true); - } - - // Validate indexes. - // - { - indexes& ins (c.get ("index")); - - // Make sure index members are not transient, inverse, or - // containers. - // - for (indexes::iterator i (ins.begin ()); i != ins.end (); ++i) - { - index& in (*i); - - for (index::members_type::iterator i (in.members.begin ()); - i != in.members.end (); ++i) - { - index::member& im (*i); - semantics::data_member& m (*im.path.back ()); - - if (transient (m)) - { - error (im.loc) << "index member is transient" << endl; - valid_ = false; - } - - if (inverse (m)) - { - error (im.loc) << "index member is an inverse object " << - "pointer" << endl; - valid_ = false; - } - - if (container (m)) - { - error (im.loc) << "index member is a container" << endl; - valid_ = false; - } - } - } - } - } - - virtual void - traverse_view (type& c) - { - const view_query& vq (c.get ("query")); - - // Make sure we don't have any containers or object pointers. - // - view_members_.traverse (c); - - names (c, data_member_names_); - - // Allow certain kinds of empty views. - // - if (vq.kind != view_query::runtime && - vq.kind != view_query::complete_execute) - { - // Allow all the members to be deleted. - // - column_count_type const& cc (column_count (c)); - - if (cc.total == 0) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - valid_ = false; - } - } - } - - virtual void - traverse_composite (type& c) - { - names (c, data_member_names_); - } - - public: - bool& valid_; - - traversal::defines defines_; - typedefs typedefs_; - - data_member2 data_member_; - traversal::names data_member_names_; - - object_no_id_members object_no_id_members_; - composite_id_members composite_id_members_; - view_members view_members_; - }; - } - - void - validate (options const&, - features&, - semantics::unit& u, - semantics::path const&, - unsigned short pass) - { - bool valid (true); - - // Validate custom type mapping. - // - if (pass == 1) - { - // Create an empty list if we don't have one. This makes the - // rest of the code simpler. - // - if (!u.count ("custom-db-types")) - u.set ("custom-db-types", custom_db_types ()); - - custom_db_types & cts (u.get ("custom-db-types")); - - for (custom_db_types::iterator i (cts.begin ()); i != cts.end (); ++i) - { - custom_db_type& ct (*i); - - if (ct.type.empty ()) - { - error (ct.loc) << "'type' clause expected in db pragma map" << endl; - valid = false; - } - - if (ct.as.empty ()) - { - error (ct.loc) << "'as' clause expected in db pragma map" << endl; - valid = false; - } - - if (ct.to.empty ()) - ct.to = "(?)"; - else - { - size_t p (ct.to.find ("(?)")); - - if (p == string::npos) - { - error (ct.loc) << "no '(?)' expression in the 'to' clause " - << "of db pragma map" << endl; - valid = false; - } - else if (ct.to.find ("(?)", p + 3) != string::npos) - { - error (ct.loc) << "multiple '(?)' expressions in the 'to' " - << "clause of db pragma map" << endl; - valid = false; - } - } - - if (ct.from.empty ()) - ct.from = "(?)"; - else - { - size_t p (ct.from.find ("(?)")); - - if (p == string::npos) - { - error (ct.loc) << "no '(?)' expression in the 'from' clause " - << "of db pragma map" << endl; - valid = false; - } - else if (ct.from.find ("(?)", p + 3) != string::npos) - { - error (ct.loc) << "multiple '(?)' expressions in the 'from' " - << "clause of db pragma map" << endl; - valid = false; - } - } - } - } - - if (!valid) - throw operation_failed (); - - if (pass == 1) - { - } - else - { - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (true); - traversal::namespace_ ns; - class2 c (valid); - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (true); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - unit.dispatch (u); - } - - if (!valid) - throw operation_failed (); - } -} diff --git a/odb/relational/validator.hxx b/odb/relational/validator.hxx deleted file mode 100644 index d6602f7..0000000 --- a/odb/relational/validator.hxx +++ /dev/null @@ -1,24 +0,0 @@ -// file : odb/relational/validator.hxx -// license : GNU GPL v3; see accompanying LICENSE file - -#ifndef ODB_RELATIONAL_VALIDATOR_HXX -#define ODB_RELATIONAL_VALIDATOR_HXX - -#include -#include -#include - -namespace relational -{ - // The first pass is performed before processing. The second -- after. - // Throws operation_failed to signal a failure. - // - void - validate (options const&, - features&, - semantics::unit&, - semantics::path const&, - unsigned short pass); -} - -#endif // ODB_RELATIONAL_VALIDATOR_HXX -- cgit v1.1