summaryrefslogtreecommitdiff
path: root/odb/relational
diff options
context:
space:
mode:
Diffstat (limited to 'odb/relational')
-rw-r--r--odb/relational/changelog.cxx1239
-rw-r--r--odb/relational/common-query.cxx169
-rw-r--r--odb/relational/common-query.hxx63
-rw-r--r--odb/relational/common.cxx27
-rw-r--r--odb/relational/common.hxx273
-rw-r--r--odb/relational/common.txx125
-rw-r--r--odb/relational/context.cxx169
-rw-r--r--odb/relational/context.hxx289
-rw-r--r--odb/relational/context.ixx44
-rw-r--r--odb/relational/generate.hxx81
-rw-r--r--odb/relational/header.cxx1146
-rw-r--r--odb/relational/header.hxx1464
-rw-r--r--odb/relational/inline.cxx47
-rw-r--r--odb/relational/inline.hxx689
-rw-r--r--odb/relational/model.cxx121
-rw-r--r--odb/relational/model.hxx868
-rw-r--r--odb/relational/mssql/common.cxx603
-rw-r--r--odb/relational/mssql/common.hxx293
-rw-r--r--odb/relational/mssql/context.cxx766
-rw-r--r--odb/relational/mssql/context.hxx194
-rw-r--r--odb/relational/mssql/header.cxx312
-rw-r--r--odb/relational/mssql/inline.cxx42
-rw-r--r--odb/relational/mssql/model.cxx66
-rw-r--r--odb/relational/mssql/schema.cxx651
-rw-r--r--odb/relational/mssql/source.cxx1201
-rw-r--r--odb/relational/mysql/common.cxx400
-rw-r--r--odb/relational/mysql/common.hxx171
-rw-r--r--odb/relational/mysql/context.cxx868
-rw-r--r--odb/relational/mysql/context.hxx194
-rw-r--r--odb/relational/mysql/header.cxx136
-rw-r--r--odb/relational/mysql/inline.cxx42
-rw-r--r--odb/relational/mysql/model.cxx135
-rw-r--r--odb/relational/mysql/schema.cxx489
-rw-r--r--odb/relational/mysql/source.cxx724
-rw-r--r--odb/relational/oracle/common.cxx522
-rw-r--r--odb/relational/oracle/common.hxx203
-rw-r--r--odb/relational/oracle/context.cxx795
-rw-r--r--odb/relational/oracle/context.hxx188
-rw-r--r--odb/relational/oracle/header.cxx230
-rw-r--r--odb/relational/oracle/inline.cxx42
-rw-r--r--odb/relational/oracle/model.cxx64
-rw-r--r--odb/relational/oracle/schema.cxx696
-rw-r--r--odb/relational/oracle/source.cxx646
-rw-r--r--odb/relational/pgsql/common.cxx351
-rw-r--r--odb/relational/pgsql/common.hxx159
-rw-r--r--odb/relational/pgsql/context.cxx786
-rw-r--r--odb/relational/pgsql/context.hxx192
-rw-r--r--odb/relational/pgsql/header.cxx271
-rw-r--r--odb/relational/pgsql/inline.cxx42
-rw-r--r--odb/relational/pgsql/model.cxx101
-rw-r--r--odb/relational/pgsql/schema.cxx266
-rw-r--r--odb/relational/pgsql/source.cxx1140
-rw-r--r--odb/relational/processor.cxx1562
-rw-r--r--odb/relational/processor.hxx15
-rw-r--r--odb/relational/schema-source.cxx281
-rw-r--r--odb/relational/schema-source.hxx126
-rw-r--r--odb/relational/schema.cxx174
-rw-r--r--odb/relational/schema.hxx1603
-rw-r--r--odb/relational/source.cxx6324
-rw-r--r--odb/relational/source.hxx7142
-rw-r--r--odb/relational/sqlite/common.cxx217
-rw-r--r--odb/relational/sqlite/common.hxx147
-rw-r--r--odb/relational/sqlite/context.cxx490
-rw-r--r--odb/relational/sqlite/context.hxx146
-rw-r--r--odb/relational/sqlite/header.cxx63
-rw-r--r--odb/relational/sqlite/inline.cxx42
-rw-r--r--odb/relational/sqlite/model.cxx91
-rw-r--r--odb/relational/sqlite/schema.cxx455
-rw-r--r--odb/relational/sqlite/source.cxx470
-rw-r--r--odb/relational/validator.cxx638
-rw-r--r--odb/relational/validator.hxx24
71 files changed, 0 insertions, 40805 deletions
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 <map>
-
-#include <odb/diagnostics.hxx>
-
-#include <odb/semantics/relational.hxx>
-#include <odb/traversal/relational.hxx>
-
-#include <odb/relational/context.hxx>
-#include <odb/relational/generate.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace changelog
- {
- using namespace sema_rel;
- using sema_rel::model;
- using sema_rel::changelog;
-
- typedef map<qname, semantics::node*> deleted_table_map;
- typedef map<uname, semantics::data_member*> 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<column> (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<alter_column> (c.id ()));
-
- // Set the alters edge.
- //
- column* b (at.lookup<column, drop_column> (c.name ()));
- assert (b != 0);
- g.new_edge<alters> (ac, *b);
-
- ac.null (c.null ());
- g.new_edge<unames> (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<data_member_path> ("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<location_t> ("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<semantics::class_&> (
- 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<add_column> (c, at, g));
- g.new_edge<unames> (at, ac, c.name ());
- }
- }
- else
- {
- if (other.find<column> (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_column_map> ("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<location_t> ("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<semantics::class_*> ("class", 0))
- {
- warn (s->location ()) << "column '" << c.name () << "' " <<
- "in class '" << s->name () << "' is hard-deleted" << endl;
- }
- else
- {
- data_member_path const& mp (
- other.get<data_member_path> ("member-path"));
-
- warn (mp.back ()->location ()) << "column '" <<
- c.name () << "' in container '" <<
- mp.back ()->name () << "' is hard-deleted" << endl;
- }
- }
- }
-
- drop_column& dc (g.new_node<drop_column> (c.id ()));
- g.new_edge<unames> (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<primary_key> (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<location> ("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<primary_key> (pk.name ()) == 0)
- {
- location const& l (other.get<location> ("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<foreign_key> (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<add_foreign_key> (fk, at, g));
- g.new_edge<unames> (at, afk, fk.name ());
- }
- }
- else
- {
- if (other.find<foreign_key> (fk.name ()) == 0)
- {
- drop_foreign_key& dfk (g.new_node<drop_foreign_key> (fk.id ()));
- g.new_edge<unames> (at, dfk, fk.name ());
- }
- }
- }
-
- virtual void
- traverse (sema_rel::index& i)
- {
- using sema_rel::index;
-
- if (mode == mode_add)
- {
- if (index* oi = other.find<index> (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<add_index> (i, at, g));
- g.new_edge<unames> (at, ai, i.name ());
- }
- }
- else
- {
- if (other.find<index> (i.name ()) == 0)
- {
- drop_index& di (g.new_node<drop_index> (i.id ()));
- g.new_edge<unames> (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<location> ("cxx-location"));
- location const& cl (c.get<location> ("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<location> ("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<foreign_key> ()))
- {
- location const& l (t.get<location> ("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<location> ("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<location> ("cxx-location"));
- location const& il (i.get<location> ("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<table> (t.name ()))
- {
- // See if there are any changes to the table.
- //
- alter_table& at (g.new_node<alter_table> (t.id ()));
-
- // Set the alters edge for lookup.
- //
- table* bt (cs.lookup<table, drop_table> (t.name ()));
- assert (bt != 0);
- alters& ae (g.new_edge<alters> (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<qnames> (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<data_member_path> ("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<location_t> ("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<semantics::class_&> (
- 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<add_table> (t, cs, g));
- g.new_edge<qnames> (cs, at, t.name ());
- }
- }
- else
- {
- if (other.find<table> (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_table_map> ("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<semantics::class_*> (i->second));
- if (c != 0 && context::deleted (*c) != version->current)
- {
- location l (c->get<location_t> ("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<semantics::data_member*> (i->second));
- if (m != 0 && context::deleted (*m) != version->current)
- {
- location l (m->get<location_t> ("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<drop_table> (t.id ()));
- g.new_edge<qnames> (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<location> ("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<changeset> (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<alters> (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<alters> (r, m);
- }
- else
- {
- changeset& c (l.contains_changeset_back ().changeset ());
- assert (o.version () == c.version ());
- l.new_edge<alters> (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<column> (ac, t, g));
- g.new_edge<unames> (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<column> ())
- {
- 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<column> (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<index> (ai, t, g));
- g.new_edge<unames> (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<index> ())
- {
- 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<foreign_key> (afk, t, g));
- g.new_edge<unames> (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<foreign_key> ())
- {
- 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<table> (at, m, g));
- g.new_edge<qnames> (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<table> ())
- {
- 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<table> (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<model> (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<changelog>
- 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<changelog> 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<contains_model> (*cl, g.new_node<model> (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<model> (mv.base));
- g.new_edge<contains_model> (*cl, nm);
- changeset& c (diff (nm, m, *cl, in_name, ops, &mv));
-
- if (!c.names_empty ())
- {
- g.new_edge<alters_model> (c, nm);
- g.new_edge<contains_changeset> (*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<model> (oldm, g));
- model* base (bver == mv.base && mv.base != mv.current ? last : 0);
- if (base != 0)
- g.new_edge<contains_model> (*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<contains_model> (*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<model> (mv.base);
- g.new_edge<contains_model> (*cl, *base);
-
- changeset& c (diff (*base, *last, *cl, in_name, ops, 0));
- if (!c.names_empty ())
- {
- g.new_edge<alters_model> (c, *base);
- g.new_edge<contains_changeset> (*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<changeset> (
- cs,
- cl->contains_changeset_empty ()
- ? static_cast<qscope&> (*base) // Cannot be NULL.
- : cl->contains_changeset_back ().changeset (),
- g));
-
- g.new_edge<alters_model> (c, prev);
- g.new_edge<contains_changeset> (*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<model> (m, g);
- else
- {
- // Fast-forward the latest model to the new base.
- //
- base = last;
- base->version (mv.base);
- }
-
- g.new_edge<contains_model> (*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<alters_model> (c, *last);
- g.new_edge<contains_changeset> (*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 <odb/relational/common-query.hxx>
-
-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_alias_traits_;
-
-
- // query_columns_base
- //
-
- entry<query_columns_base> 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 <typename A>" << 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 <odb/relational/common.hxx>
-
-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 <odb/relational/common.hxx>
-
-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 <set>
-#include <cassert>
-
-#include <odb/common.hxx>
-#include <odb/relational/context.hxx>
-
-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 <typename T>
- 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<semantics::names*> ("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 <odb/relational/common.txx>
-
-// Other common parts.
-//
-#include <odb/relational/common-query.hxx>
-
-#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 <typename T>
- void member_base_impl<T>::
- 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 <typename T>
- void member_base_impl<T>::
- 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 <cassert>
-
-#include <odb/relational/context.hxx>
-
-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 <odb/context.hxx>
-
-#include <odb/semantics/relational.hxx>
-#include <odb/traversal/relational.hxx>
-
-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<member> members_type;
-
- members_type members;
- };
-
- typedef std::vector<index> 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_type> 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 <odb/relational/context.ixx>
-
-#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 c3d19c7..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 <string>
-#include <cutl/shared-ptr.hxx>
-
-#include <odb/context.hxx>
-#include <odb/semantics/relational/model.hxx>
-#include <odb/semantics/relational/changeset.hxx>
-#include <odb/semantics/relational/changelog.hxx>
-
-namespace relational
-{
- namespace header
- {
- void
- generate ();
- }
-
- namespace inline_
- {
- void
- generate ();
- }
-
- namespace source
- {
- void
- generate ();
- }
-
- namespace model
- {
- cutl::shared_ptr<semantics::relational::model>
- generate ();
- }
-
- namespace changelog
- {
- // Returns NULL if the changelog is unchanged.
- //
- cutl::shared_ptr<semantics::relational::changelog>
- 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 <odb/relational/header.hxx>
-#include <odb/relational/generate.hxx>
-
-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> ("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<object_type, id_" << db <<
- "> entry_type;";
-
- os << "typedef object_traits_impl<root_type, id_" << db << "> " <<
- "root_traits;";
-
- if (poly_derived)
- {
- os << "typedef object_traits_impl<base_type, id_" << db << "> " <<
- "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<semantics::class_&> (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<container_traits> t (c);
- t->traverse (c);
- }
-
- //
- // Sections (abstract and concrete).
- //
-
- for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
- {
- instance<section_traits> 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<object_type>::id;"
- << endl;
-
- if (opt != 0)
- os << "using object_traits<object_type>::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" <<
- "<object_type>" << endl
- << "statements_type;"
- << endl
- << "typedef" << endl
- << db << "::polymorphic_root_object_statements<root_type>" << endl
- << "root_statements_type;"
- << endl;
- else
- os << "typedef" << endl
- << db << "::polymorphic_root_object_statements<object_type>" << endl
- << "statements_type;"
- << endl
- << "typedef statements_type root_statements_type;"
- << endl;
- }
- else
- {
- if (id != 0)
- os << "typedef " << db << "::object_statements<object_type> " <<
- "statements_type;"
- << endl;
- else
- os << "typedef " << db << "::no_id_object_statements<object_type> " <<
- "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<object_type>" << endl
- << "query (database&, const query_base_type&);"
- << endl;
-
- if (multi_dynamic)
- os << "static result<object_type>" << 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<prepared_query_impl>" << endl
- << "prepare_query (connection&, const char*, const query_base_type&);"
- << endl;
-
- if (multi_dynamic)
- os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
- << "prepare_query (connection&, const char*, " <<
- "const odb::query_base&);"
- << endl;
-
- os << "static odb::details::shared_ptr<result_impl>" << 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<size_t> ("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<view_type> 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<view_query> ("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<view_type>" << endl
- << "query (database&, const query_base_type&);"
- << endl;
-
- if (multi_dynamic)
- os << "static result<view_type>" << endl
- << "query (database&, const odb::query_base&);"
- << endl;
- }
-
- if (options.generate_prepared ())
- {
- os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
- << "prepare_query (connection&, const char*, const query_base_type&);"
- << endl;
-
- if (multi_dynamic)
- os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
- << "prepare_query (connection&, const char*, " <<
- "const odb::query_base&);"
- << endl;
-
- os << "static odb::details::shared_ptr<result_impl>" << endl
- << "execute_query (prepared_query_impl&);"
- << endl;
- }
-
- view_public_extra_post (c);
-
- os << "};";
-
- // view_traits_impl< , id_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<container_traits> 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<include> i;
- i->generate ();
-
- os << "namespace odb"
- << "{";
-
- {
- traversal::unit unit;
- traversal::defines unit_defines;
- typedefs unit_typedefs (false);
- traversal::namespace_ ns;
- instance<class1> 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<class2> 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 30a61ea..0000000
--- a/odb/relational/header.hxx
+++ /dev/null
@@ -1,1464 +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 <odb/relational/context.hxx>
-#include <odb/relational/common.hxx>
-
-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 <typename T>
- struct image_member_impl: image_member, virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- 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<T>::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> 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<image_base> 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<image_member> 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<type&> (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<semantics::class_&> (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<semantics::names*> ("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<container_type>" << 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<index_type, value_type> functions_type;";
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "typedef map_functions<key_type, value_type> " <<
- "functions_type;";
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "typedef set_functions<value_type> 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<image_member> im (
- "index_", *it, ict, "index_type", "index");
- im->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<image_member> im ("key_", *kt, kct, "key_type", "key");
- im->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "// value" << endl
- << "//" << endl;
- instance<image_member> 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<image_member> im (
- "index_", *it, ict, "index_type", "index");
- im->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<image_member> im ("key_", *kt, kct, "key_type", "key");
- im->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- break;
- }
- }
-
- os << "// value" << endl
- << "//" << endl;
- instance<image_member> 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> ("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<object_type, id_" << db <<
- ">::image_type image_type;"
- << "typedef object_traits_impl<object_type, id_" << db <<
- ">::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> image_type_;
- instance<image_member> id_image_member_;
- instance<image_member> version_image_member_;
- instance<image_member> discriminator_image_member_;
-
- instance<query_columns_type> query_columns_type_;
- instance<query_columns_type> 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<size_t> ("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> query_columns_type_;
- instance<query_columns_type> query_columns_type_inst_;
- instance<view_query_columns_type> view_query_columns_type_;
- };
-
- struct include: virtual context
- {
- typedef include base;
-
- virtual void
- generate ()
- {
- os << "#include <odb/details/buffer.hxx>" << endl
- << endl;
-
- os << "#include <odb/" << db << "/version.hxx>" << endl
- << "#include <odb/" << db << "/forward.hxx>" << endl
- << "#include <odb/" << db << "/binding.hxx>" << endl
- << "#include <odb/" << db << "/" << db << "-types.hxx>" << endl;
-
- if (options.generate_query ())
- {
- os << "#include <odb/" << db << "/query.hxx>" << endl;
-
- if (multi_dynamic)
- os << "#include <odb/" << db << "/query-dynamic.hxx>" << 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 <odb/relational/inline.hxx>
-#include <odb/relational/generate.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace inline_
- {
- void
- generate ()
- {
- context ctx;
- ostream& os (ctx.os);
-
- instance<include> 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 48ababf..0000000
--- a/odb/relational/inline.hxx
+++ /dev/null
@@ -1,689 +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 <odb/diagnostics.hxx>
-#include <odb/relational/context.hxx>
-#include <odb/relational/common.hxx>
-
-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 <typename T>
- struct null_member_impl: null_member, virtual member_base_impl<T>
- {
- typedef null_member_impl base_impl;
-
- null_member_impl (base const& x): base (x) {}
-
- typedef typename member_base_impl<T>::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<type*> (&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> ("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<member_access> ("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<base_traits::image_type> 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<null_base> get_null_base_;
- traversal::inherits get_null_base_inherits_;
- instance<null_member> get_null_member_;
- traversal::names get_null_member_names_;
-
- instance<null_base> set_null_base_;
- traversal::inherits set_null_base_inherits_;
- instance<null_member> set_null_member_;
- traversal::names set_null_member_names_;
- };
-
- struct include: virtual context
- {
- typedef include base;
-
- virtual void
- generate ()
- {
- if (features.polymorphic_object && options.generate_query ())
- os << "#include <odb/details/unique-ptr.hxx>" << 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 <odb/diagnostics.hxx>
-
-#include <odb/relational/model.hxx>
-#include <odb/relational/generate.hxx>
-
-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_value> ("default");
- else if (t.count ("default"))
- dv = &t.get<default_value> ("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<sema_rel::model>
- generate ()
- {
- context ctx;
- cutl::shared_ptr<sema_rel::model> 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<class_> 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<location> ("cxx-location"));
- location const& d (e.dup.get<location> ("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 b7a07ea..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 <map>
-#include <set>
-#include <cassert>
-#include <sstream>
-
-#include <odb/semantics/relational.hxx>
-
-#include <odb/relational/common.hxx>
-#include <odb/relational/context.hxx>
-
-namespace relational
-{
- namespace model
- {
- typedef std::set<qname> tables;
- typedef std::map<qname, semantics::node*> deleted_table_map;
- typedef std::map<uname, semantics::data_member*> 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_column_map> ("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<sema_rel::column> (col_id, type (m), null (m)));
- c.set ("cxx-location", m.location ());
- c.set ("member-path", member_path_);
- model_.new_edge<sema_rel::unames> (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<sema_rel::primary_key> (
- 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<sema_rel::unames> (table_, *pkey_, "");
- primary_key (*pkey_);
- }
-
- model_.new_edge<sema_rel::contains> (*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<sema_rel::column> ())
- 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<sema_rel::column> ())
- 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> ("deferrable",
- options.fkeys_deferrable_mode ()[db]));
-
- foreign_key::action_type on_delete (
- m.get<foreign_key::action_type> (
- "on-delete", foreign_key::no_action));
-
- foreign_key& fk (
- model_.new_node<foreign_key> (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<object_columns_list> 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<column*> (&i->nameable ()))
- model_.new_edge<sema_rel::contains> (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<sema_rel::unames> (
- 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<indexes> ("index"));
-
- for (indexes::iterator i (ins.begin ()); i != ins.end (); ++i)
- {
- // Using index name as its id.
- //
- sema_rel::index& in (
- model_.new_node<sema_rel::index> (
- i->name, i->type, i->method, i->options));
- in.set ("cxx-location", location (i->loc));
- model_.new_edge<sema_rel::unames> (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<object_columns_list> 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<column> (i->name));
- assert (c != 0);
- model_.new_edge<sema_rel::contains> (in, *c, im.options);
- }
- }
- else
- {
- // Simple value. Get the column name and look it up in the
- // table.
- //
- column* c (table_.find<column> (column_name (im.path)));
- assert (c != 0);
- model_.new_edge<sema_rel::contains> (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&, semantics::type&)
- {
- return "";
- }
-
- 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_table_map> ("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<sema_rel::table> (id));
- t.set ("cxx-location", m.location ());
- t.set ("member-path", member_path_);
- t.set ("deleted-map", deleted_column_map ());
- model_.new_edge<sema_rel::qnames> (model_, t, name);
-
- t.options (table_options (m, ct));
- t.extra ()["kind"] = "container";
-
- // object_id
- //
- {
- bool f (false); //@@ (im)persfect forwarding.
- instance<object_columns> 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<sema_rel::foreign_key> (
- 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<sema_rel::unames> (
- t, fk, fkey_name (t.name (), id_name));
-
- // Get referenced columns.
- //
- {
- data_member_path& id (*id_member (*context::top_object));
-
- instance<object_columns_list> 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<column*> (&i->nameable ()))
- model_.new_edge<sema_rel::contains> (fk, *c);
- }
-
- // Index. See if we have a custom index.
- //
- index* sin (m.count ("id-index") ? &m.get<index> ("id-index") : 0);
- sema_rel::index* in (0);
-
- if (sin != 0)
- {
- in = &model_.new_node<sema_rel::index> (
- id + ".id", sin->type, sin->method, sin->options);
- in->set ("cxx-location", location (sin->loc));
- }
- else
- {
- in = &model_.new_node<sema_rel::index> (id + ".id");
- in->set ("cxx-location", m.location ());
- }
-
- model_.new_edge<sema_rel::unames> (
- 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<column*> (&i->nameable ()))
- model_.new_edge<sema_rel::contains> (
- *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<object_columns> 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-index")
- : 0);
- sema_rel::index* in (0);
-
- if (sin != 0)
- {
- in = &model_.new_node<sema_rel::index> (
- id + ".index", sin->type, sin->method, sin->options);
- in->set ("cxx-location", location (sin->loc));
- }
- else
- {
- in = &model_.new_node<sema_rel::index> (id + ".index");
- in->set ("cxx-location", m.location ());
- }
-
- model_.new_edge<sema_rel::unames> (
- t,
- *in,
- sin != 0 && !sin->name.empty ()
- ? sin->name
- : index_name (name, col));
-
- column* c (t.find<column> (col));
- assert (c != 0);
-
- model_.new_edge<sema_rel::contains> (
- *in,
- *c,
- (sin != 0 ? sin->members.back ().options : ""));
- }
-
- // key
- //
- if (ck == ck_map || ck == ck_multimap)
- {
- bool f (false); //@@ (im)persfect forwarding.
- instance<object_columns> oc (model_, t, f);
- oc->traverse (m, container_kt (m), "key", "key");
- }
-
- // value
- //
- {
- bool f (false); //@@ (im)persfect forwarding.
- instance<object_columns> 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&)
- {
- return "";
- }
-
- 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_table_map> ("deleted-map")[name] = &c;
- return;
- }
-
- string id (class_fq_name (c), 2); // Remove leading '::'.
-
- sema_rel::table& t (model_.new_node<sema_rel::table> (id));
- t.set ("cxx-location", c.location ());
- t.set ("class", &c);
- t.set ("deleted-map", deleted_column_map ());
- model_.new_edge<sema_rel::qnames> (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<object_columns> oc (model_, t, tr);
- oc->traverse (c);
- }
-
- // Add indexes.
- //
- {
- instance<object_indexes> oi (model_, t);
- oi->traverse (c);
- }
-
- tables_.insert (name);
-
- // Create tables for members.
- //
- {
- instance<member_create> 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 <cassert>
-
-#include <odb/relational/mssql/common.hxx>
-
-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_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> 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> 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 <odb/relational/common.hxx>
-#include <odb/relational/mssql/context.hxx>
-
-namespace relational
-{
- namespace mssql
- {
- struct member_base: virtual relational::member_base_impl<sql_type>, 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 <cassert>
-#include <sstream>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/relational/mssql/context.hxx>
-
-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<data*> (root_context::data_.get ()), m),
- data_ (static_cast<data*> (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<array*> (&t))
- {
- semantics::type& bt (a->base_type ());
- bool c (bt.is_a<semantics::fund_char> ());
-
- if (c || bt.is_a<semantics::fund_wchar> ())
- {
- 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> ("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 <map>
-
-#include <odb/relational/context.hxx>
-
-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<string, sql_type_cache_entry> 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 <odb/relational/header.hxx>
-
-#include <odb/relational/mssql/common.hxx>
-#include <odb/relational/mssql/context.hxx>
-
-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<unsigned long long> ("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> 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> 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> image_type_;
-
- struct image_member: relational::image_member_impl<sql_type>,
- 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> 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 <odb/relational/inline.hxx>
-
-#include <odb/relational/mssql/common.hxx>
-#include <odb/relational/mssql/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace mssql
- {
- namespace inline_
- {
- namespace relational = relational::inline_;
-
- struct null_member: relational::null_member_impl<sql_type>,
- 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> 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 <sstream>
-
-#include <odb/relational/model.hxx>
-
-#include <odb/relational/mssql/common.hxx>
-#include <odb/relational/mssql/context.hxx>
-
-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<enumerator&> (*unit.find (en)));
-
- ostringstream ostr;
-
- if (e.enum_ ().unsigned_ ())
- ostr << e.value ();
- else
- ostr << static_cast<long long> (e.value ());
-
- return ostr.str ();
- }
- };
- entry<object_columns> 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 <odb/relational/schema.hxx>
-
-#include <odb/relational/mssql/common.hxx>
-#include <odb/relational/mssql/context.hxx>
-
-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> 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> 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> 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<sema_rel::foreign_key> (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> 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<sema_rel::table&> (in.scope ()));
-
- os << "DROP INDEX " << name (in) << " ON " <<
- quote_id (t.name ()) << endl;
- }
- };
- entry<drop_index> 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> 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> 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> 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<foreign_key*> (&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<create_foreign_key> 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> 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<table&> (c.scope ()));
-
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ()) << endl
- << " ALTER COLUMN ";
- alter (c);
- os << endl;
-
- post_statement ();
- }
- };
- entry<alter_column> 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<drop_foreign_key*> (&i->nameable ()))
- {
- foreign_key& fk (find<foreign_key> (*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<sema_rel::drop_foreign_key> (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<drop_foreign_key> 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<sema_rel::add_column> (at))
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ()) << endl
- << " ADD ";
-
- instance<create_column> 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<alter_column> ac (*this, tl);
- trav_rel::unames n (*ac);
- names (at, n);
- }
- }
- };
- entry<alter_table_pre> 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<add_foreign_key*> (&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<sema_rel::drop_column> (at))
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ()) << endl
- << " DROP COLUMN ";
-
- instance<drop_column> 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<alter_column> ac (*this, fl);
- trav_rel::unames n (*ac);
- names (at, n);
- }
-
- if (check<sema_rel::add_foreign_key> (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<create_foreign_key> 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> 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> 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 <odb/relational/source.hxx>
-
-#include <odb/relational/mssql/common.hxx>
-#include <odb/relational/mssql/context.hxx>
-
-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> 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> 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> 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<sql_type>,
- 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<SQLLEN> (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<SQLLEN> (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<SQLLEN> (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> bind_member_;
-
- //
- // init image
- //
-
- struct init_image_member: relational::init_image_member_impl<sql_type>,
- 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<SQLLEN> (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<SQLLEN> (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<SQLLEN> (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<SQLLEN> (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<SQLLEN> (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_image_member_;
-
- //
- // init value
- //
-
- struct init_value_member: relational::init_value_member_impl<sql_type>,
- 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<std::size_t> (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<std::size_t> (" <<
- "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<std::size_t> (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> 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> 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> 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<bool> ("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<view_query> ("query").for_update
- ? " WITH (UPDLOCK)"
- : "";
- }
-
- virtual string
- select_trailer (type&) {return "";}
-
- private:
- // Go via the dynamic creation to get access to the constructor.
- //
- instance<relational::init_value_member>
- init_version_value_member_id_image_;
- };
- entry<class_> 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 <cassert>
-
-#include <odb/relational/mysql/common.hxx>
-
-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_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> 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> 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 <odb/relational/common.hxx>
-#include <odb/relational/mysql/context.hxx>
-
-namespace relational
-{
- namespace mysql
- {
- struct member_base: virtual relational::member_base_impl<sql_type>, 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 <cassert>
-#include <sstream>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/relational/mysql/context.hxx>
-#include <odb/relational/mysql/common.hxx>
-
-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<data*> (root_context::data_.get ()), m),
- data_ (static_cast<data*> (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<bool> ("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<semantics::class_&> (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<bool> ("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<enum_*> (&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<array*> (&t))
- {
- semantics::type& bt (a->base_type ());
- if (bt.is_a<semantics::fund_char> ())
- {
- 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> ("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 <map>
-#include <vector>
-
-#include <odb/relational/context.hxx>
-
-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<std::string> 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<string, sql_type_cache_entry> 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 <odb/relational/header.hxx>
-
-#include <odb/relational/mysql/common.hxx>
-#include <odb/relational/mysql/context.hxx>
-
-namespace relational
-{
- namespace mysql
- {
- namespace header
- {
- namespace relational = relational::header;
-
- struct image_member: relational::image_member_impl<sql_type>,
- 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> 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 <odb/relational/inline.hxx>
-
-#include <odb/relational/mysql/common.hxx>
-#include <odb/relational/mysql/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace mysql
- {
- namespace inline_
- {
- namespace relational = relational::inline_;
-
- struct null_member: relational::null_member_impl<sql_type>,
- 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> null_member_;
- }
- }
-}
diff --git a/odb/relational/mysql/model.cxx b/odb/relational/mysql/model.cxx
deleted file mode 100644
index 2ec9d8b..0000000
--- a/odb/relational/mysql/model.cxx
+++ /dev/null
@@ -1,135 +0,0 @@
-// file : odb/relational/mysql/model.cxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <sstream>
-
-#include <odb/relational/model.hxx>
-#include <odb/relational/mysql/context.hxx>
-
-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<enumerator&> (*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<long long> (er.value ());
-
- return ostr.str ();
- }
- }
- };
- entry<object_columns> object_columns_;
-
- struct member_create: relational::member_create, context
- {
- member_create (base const& x): base (x) {}
-
- virtual string
- table_options (semantics::data_member&, semantics::type&)
- {
- string const& engine (options.mysql_engine ());
- return engine != "default" ? "ENGINE=" + engine : "";
- }
- };
- entry<member_create> member_create_;
-
- struct class_: relational::class_, context
- {
- class_ (base const& x): base (x) {}
-
- virtual string
- table_options (type&)
- {
- string const& engine (options.mysql_engine ());
- return engine != "default" ? "ENGINE=" + engine : "";
- }
- };
- entry<class_> 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 <odb/relational/schema.hxx>
-
-#include <odb/relational/mysql/common.hxx>
-#include <odb/relational/mysql/context.hxx>
-
-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<sema_rel::foreign_key> (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> 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<sema_rel::table&> (in.scope ()));
-
- os << "DROP INDEX " << name (in) << " ON " <<
- quote_id (t.name ()) << endl;
- }
- };
- entry<drop_index> 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> 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> 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> 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<foreign_key*> (&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<create_foreign_key> 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> 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> 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<sema_rel::add_column> (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<drop_foreign_key*> (&i->nameable ()))
- {
- foreign_key& fk (find<foreign_key> (*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<drop_foreign_key> 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> 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<sema_rel::drop_column> (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<add_foreign_key*> (&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<create_foreign_key> 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> 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> 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 <odb/relational/source.hxx>
-
-#include <odb/relational/mysql/common.hxx>
-#include <odb/relational/mysql/context.hxx>
-
-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<type>::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> 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> view_columns_;
-
- //
- // bind
- //
-
- struct bind_member: relational::bind_member_impl<sql_type>,
- 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<unsigned long> (" << 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<unsigned long> (" << 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<unsigned long> (" << 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<unsigned long> (" << 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<unsigned long> (" << endl
- << arg << "." << mi.var << "value.capacity ());"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
- };
- entry<bind_member> bind_member_;
-
- //
- // grow
- //
-
- struct grow_member: relational::grow_member_impl<sql_type>,
- 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> grow_member_;
-
- //
- // init image
- //
-
- struct init_image_member: relational::init_image_member_impl<sql_type>,
- 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<unsigned long> (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<unsigned long> (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<unsigned long> (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<unsigned long> (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<unsigned long> (size);"
- << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
- }
- };
- entry<init_image_member> init_image_member_;
-
- //
- // init value
- //
-
- struct init_value_member: relational::init_value_member_impl<sql_type>,
- 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> 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<int64_t> id;
- //
- semantics::type& t (utype (m));
- if (wrapper (t) && t.template get<bool> ("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_> class_entry_;
-
- struct include: relational::include, context
- {
- include (base const& x): base (x) {}
-
- virtual void
- extra_post ()
- {
- os << "#include <odb/mysql/enum.hxx>" << endl;
- }
- };
- entry<include> 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 <cassert>
-
-#include <odb/relational/oracle/common.hxx>
-
-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_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> 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> 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 <odb/relational/common.hxx>
-#include <odb/relational/oracle/context.hxx>
-
-namespace relational
-{
- namespace oracle
- {
- struct member_base: virtual relational::member_base_impl<sql_type>, 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 <cassert>
-#include <sstream>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/relational/oracle/context.hxx>
-
-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<data*> (root_context::data_.get ()), m),
- data_ (static_cast<data*> (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<array*> (&t))
- {
- semantics::type& bt (a->base_type ());
- if (bt.is_a<semantics::fund_char> ())
- {
- 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> ("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<short> (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 <map>
-
-#include <odb/relational/context.hxx>
-
-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<string, sql_type_cache_entry> 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 <odb/relational/header.hxx>
-
-#include <odb/relational/oracle/common.hxx>
-#include <odb/relational/oracle/context.hxx>
-
-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> image_type_;
-
- struct image_member: relational::image_member_impl<sql_type>,
- 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> 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<unsigned long long> ("bulk")
- : 1);
-
- os << "static const std::size_t batch = " << b << "UL;"
- << endl;
- }
- }
- };
- entry<class1> 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 <odb/relational/inline.hxx>
-
-#include <odb/relational/oracle/common.hxx>
-#include <odb/relational/oracle/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace oracle
- {
- namespace inline_
- {
- namespace relational = relational::inline_;
-
- struct null_member: relational::null_member_impl<sql_type>,
- 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> 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 <sstream>
-
-#include <odb/relational/model.hxx>
-
-#include <odb/relational/oracle/common.hxx>
-#include <odb/relational/oracle/context.hxx>
-
-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<enumerator&> (*unit.find (en)));
-
- ostringstream ostr;
-
- if (e.enum_ ().unsigned_ ())
- ostr << e.value ();
- else
- ostr << static_cast<long long> (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> 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 <map>
-#include <utility> // pair
-
-#include <odb/diagnostics.hxx>
-
-#include <odb/relational/schema.hxx>
-
-#include <odb/relational/oracle/common.hxx>
-#include <odb/relational/oracle/context.hxx>
-
-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> 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> 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> 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> 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<sema_rel::table&> (in.scope ()));
- sema_rel::qname n (t.name ().qualifier ());
- n.append (in.name ());
- return quote_id (n);
- }
- };
- entry<drop_index> 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<primary_key&> (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> 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 <typename N>
- struct scope
- {
- typedef std::map<N, pair<N, location> > 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<typename map::iterator, bool> 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<sema_rel::qname> tables;
- scope<sema_rel::uname> fkeys; // Global but can't have schema.
- scope<sema_rel::qname> indexes;
- scope<sema_rel::qname> sequences;
- scope<sema_rel::uname> 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<scopes*> (context::extra))
- s->columns.check (c.get<location> ("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> 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<scopes*> (context::extra))
- s->fkeys.check (fk.get<location> ("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<scopes*> (context::extra))
- s->fkeys.check (fk.get<location> ("cxx-location"), fk.name ());
-
- os << endl
- << " ADD CONSTRAINT ";
- create (fk);
- }
- };
- entry<create_foreign_key> 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<sema_rel::table&> (in.scope ()));
- sema_rel::qname n (t.name ().qualifier ());
- n.append (in.name ());
-
- // Check name trunction and conflicts.
- //
- if (scopes* s = static_cast<scopes*> (context::extra))
- s->indexes.check (in.get<location> ("cxx-location"), n);
-
- return quote_id (n);
- }
- };
- entry<create_index> 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<scopes*> (context::extra))
- {
- if (pass_ == 1)
- {
- s->tables.check (t.get<location> ("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<primary_key&> (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<scopes*> (context::extra))
- s->sequences.check (pk->get<location> ("cxx-location"), n);
-
- pre_statement ();
- os_ << "CREATE SEQUENCE " << quote_id (n) << endl
- << " START WITH 1 INCREMENT BY 1" << endl;
- post_statement ();
- }
- }
- }
- };
- entry<create_table> 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> 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> 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<sema_rel::drop_foreign_key> (at))
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ());
-
- instance<drop_foreign_key> dfc (*this);
- trav_rel::unames n (*dfc);
- names (at, n);
- os << endl;
-
- post_statement ();
- }
-
- if (check<sema_rel::add_column> (at))
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ()) << endl
- << " ADD (";
-
- instance<create_column> 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<alter_column> ac (*this, tl);
- trav_rel::unames n (*ac);
- names (at, n);
- os << ")" << endl;
-
- post_statement ();
- }
- }
- };
- entry<alter_table_pre> 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<sema_rel::drop_column> (at))
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ()) << endl
- << " DROP (";
-
- instance<drop_column> 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<alter_column> ac (*this, fl);
- trav_rel::unames n (*ac);
- names (at, n);
- os << ")" << endl;
-
- post_statement ();
- }
-
- if (check<sema_rel::add_foreign_key> (at))
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (at.name ());
-
- instance<create_foreign_key> cfc (*this);
- trav_rel::unames n (*cfc);
- names (at, n);
- os << endl;
-
- post_statement ();
- }
- }
- };
- entry<alter_table_post> 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> 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 <odb/relational/source.hxx>
-
-#include <odb/relational/oracle/common.hxx>
-#include <odb/relational/oracle/context.hxx>
-
-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> 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<sql_type>,
- 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<ub4> (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<ub4> (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<ub4> (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<ub4> (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> bind_member_;
-
- //
- // init image
- //
-
- struct init_image_member: relational::init_image_member_impl<sql_type>,
- 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<ub2> (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<ub2> (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<ub2> (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_image_member_;
-
- //
- // init value
- //
-
- struct init_value_member: relational::init_value_member_impl<sql_type>,
- 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> 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> 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> 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<view_query> ("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_> 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 <cassert>
-
-#include <odb/relational/pgsql/common.hxx>
-
-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_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> 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> 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 <odb/relational/common.hxx>
-#include <odb/relational/pgsql/context.hxx>
-
-namespace relational
-{
- namespace pgsql
- {
- struct member_base: virtual relational::member_base_impl<sql_type>, 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 a9f34dd..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 <cassert>
-#include <sstream>
-
-#include <odb/diagnostics.hxx>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/relational/pgsql/context.hxx>
-#include <odb/relational/pgsql/common.hxx>
-
-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<data*> (root_context::data_.get ()), m),
- data_ (static_cast<data*> (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 = false;
- 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<bool> ("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<semantics::class_&> (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<bool> ("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<array*> (&t))
- {
- semantics::type& bt (a->base_type ());
- if (bt.is_a<semantics::fund_char> ())
- {
- 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> ("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 <map>
-
-#include <odb/relational/context.hxx>
-
-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<string, sql_type_cache_entry> 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 ff00eaa..0000000
--- a/odb/relational/pgsql/header.cxx
+++ /dev/null
@@ -1,271 +0,0 @@
-// file : odb/relational/pgsql/header.cxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <odb/relational/header.hxx>
-
-#include <odb/relational/pgsql/common.hxx>
-#include <odb/relational/pgsql/context.hxx>
-
-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;
- }
-
- virtual void
- view_public_extra_post (type&)
- {
- // Statement names.
- //
- os << "static const char query_statement_name[];"
- << endl;
- }
- };
- entry<class1> 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> 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> section_traits_;
-
- struct image_member: relational::image_member_impl<sql_type>,
- 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> 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 <odb/relational/inline.hxx>
-
-#include <odb/relational/pgsql/common.hxx>
-#include <odb/relational/pgsql/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace pgsql
- {
- namespace inline_
- {
- namespace relational = relational::inline_;
-
- struct null_member: relational::null_member_impl<sql_type>,
- 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> 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 <sstream>
-
-#include <odb/diagnostics.hxx>
-
-#include <odb/relational/model.hxx>
-
-#include <odb/relational/pgsql/common.hxx>
-#include <odb/relational/pgsql/context.hxx>
-
-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<location> ("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<enumerator&> (*unit.find (en)));
-
- ostringstream ostr;
-
- if (e.enum_ ().unsigned_ ())
- ostr << e.value ();
- else
- ostr << static_cast<long long> (e.value ());
-
- return ostr.str ();
- }
- };
- entry<object_columns> 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 <odb/relational/schema.hxx>
-
-#include <odb/relational/pgsql/common.hxx>
-#include <odb/relational/pgsql/context.hxx>
-
-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> 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> 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> 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> 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> 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> version_table_;
- }
- }
-}
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
deleted file mode 100644
index 580103d..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 <sstream>
-
-#include <odb/relational/source.hxx>
-
-#include <odb/relational/pgsql/common.hxx>
-#include <odb/relational/pgsql/context.hxx>
-
-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> 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<sql_type>,
- 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 ();"
- << 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 ();"
- << 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 ();"
- << 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> bind_member_;
-
- //
- // grow
- //
-
- struct grow_member: relational::grow_member_impl<sql_type>,
- 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> grow_member_;
-
- //
- // init image
- //
-
- struct init_image_member: relational::init_image_member_impl<sql_type>,
- 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_image_member_;
-
- //
- // init value
- //
-
- struct init_value_member: relational::init_value_member_impl<sql_type>,
- 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> 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_> 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> 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> 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> 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> section_cache_init_members_;
- }
- }
-}
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
deleted file mode 100644
index aac8d79..0000000
--- a/odb/relational/processor.cxx
+++ /dev/null
@@ -1,1562 +0,0 @@
-// file : odb/relational/processor.cxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <odb/gcc.hxx>
-
-#include <vector>
-#include <algorithm>
-
-#include <odb/diagnostics.hxx>
-#include <odb/lookup.hxx>
-#include <odb/cxx-lexer.hxx>
-#include <odb/common.hxx>
-
-#include <odb/relational/context.hxx>
-#include <odb/relational/processor.hxx>
-
-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<string> ("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<string> ("id-type");
-
- if (m.count ("type"))
- {
- type = m.get<string> ("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<string> ("id-type");
-
- if (type.empty () && id.count ("type"))
- type = id.get<string> ("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<string> ("id-type");
-
- if (type.empty () && wt != 0 && wt->count ("id-type"))
- type = wt->get<string> ("id-type");
-
- if (type.empty () && idt.count ("type"))
- type = idt.get<string> ("type");
-
- if (type.empty () && wt != 0 && wt->count ("type"))
- type = wt->get<string> ("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<string> ("id-type");
-
- if (id_type.empty () && wt != 0 && wt->count ("id-type"))
- id_type = wt->get<string> ("id-type");
-
- if (type.empty () && t.count ("type"))
- type = t.get<string> ("type");
-
- if (type.empty () && wt != 0 && wt->count ("type"))
- type = wt->get<string> ("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<table_column> ("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<class_&> (m.scope ()));
-
- indexes& ins (c.count ("index")
- ? c.get<indexes> ("index")
- : c.set ("index", indexes ()));
-
- index in;
- in.loc = m.get<location_t> (
- 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<string> (prefix + "-type");
-
- if (type.empty () && ct.count (prefix + "-type"))
- type = ct.get<string> (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<string> ("id-type");
-
- if (type.empty () && id.count ("type"))
- type = id.get<string> ("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<string> ("id-type");
-
- if (type.empty () && wt != 0 && wt->count ("id-type"))
- type = wt->get<string> ("id-type");
-
- if (type.empty () && idt.count ("type"))
- type = idt.get<string> ("type");
-
- if (type.empty () && wt != 0 && wt->count ("type"))
- type = wt->get<string> ("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<string> ("type");
-
- if (type.empty () && wt != 0 && wt->count ("type"))
- type = wt->get<string> ("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 () ? "<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_type> ("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<view_query> ("query")),
- amap_ (c.get<view_alias_map> ("alias-map")),
- omap_ (c.get<view_object_map> ("object-map"))
- {
- }
-
- struct assoc_member
- {
- semantics::data_member* m;
- view_object* vo;
- };
-
- typedef vector<assoc_member> 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<location_t> ("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> ("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<data_member> (
- 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<data_member> (
- lex_, tt, tl, tn, ptt,
- dynamic_cast<scope&> (*unit.find (i->scope)),
- name,
- false,
- &s);
-
- view_object_map::iterator j (
- omap_.find (dynamic_cast<class_*> (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<class_&> (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<data_member> (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<view_objects> ("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<class_&> (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<string> ("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<string> ("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<indexes> ("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<relationship> 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<view_query> ("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<view_objects> ("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);
- }
-
- 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 <odb/relational/schema-source.hxx>
-#include <odb/relational/generate.hxx>
-
-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<cxx_emitter> 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<drop_model> dmodel (*emitter, emitter_os, format);
- instance<drop_table> 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<version_table> 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<create_model> cmodel (*emitter, emitter_os, format);
- instance<create_table> 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<version_table> 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_pre> changeset (*emitter, emitter_os, format);
- instance<create_table> ctable (*emitter, emitter_os, format);
- instance<alter_table_pre> 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<version_table> 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_post> changeset (*emitter, emitter_os, format);
- instance<drop_table> dtable (*emitter, emitter_os, format);
- instance<alter_table_post> 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<version_table> 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 <odb/diagnostics.hxx>
-
-#include <odb/emitter.hxx>
-#include <odb/relational/context.hxx>
-#include <odb/relational/schema.hxx>
-
-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 <cassert>
-#include <limits>
-#include <sstream>
-
-#include <odb/relational/schema.hxx>
-#include <odb/relational/generate.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace schema
- {
- void
- generate_prologue ()
- {
- instance<sql_file> file;
- file->prologue ();
- }
-
- void
- generate_epilogue ()
- {
- instance<sql_file> file;
- file->epilogue ();
- }
-
- void
- generate_drop ()
- {
- context ctx;
- instance<sql_emitter> em;
- emitter_ostream emos (*em);
-
- schema_format f (schema_format::sql);
-
- instance<drop_model> model (*em, emos, f);
- instance<drop_table> 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<version_table> vt (*em, emos, f);
- vt->create_table ();
- vt->drop ();
- }
- }
-
- void
- generate_create ()
- {
- context ctx;
- instance<sql_emitter> em;
- emitter_ostream emos (*em);
-
- schema_format f (schema_format::sql);
-
- instance<create_model> model (*em, emos, f);
- instance<create_table> 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<version_table> 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<sql_emitter> em;
- emitter_ostream emos (*em);
-
- schema_format f (schema_format::sql);
-
- instance<changeset_pre> changeset (*em, emos, f);
- instance<create_table> ctable (*em, emos, f);
- instance<alter_table_pre> 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<version_table> vt (*em, emos, f);
- vt->migrate_pre (cs.version ());
- }
- }
-
- void
- generate_migrate_post (sema_rel::changeset& cs)
- {
- context ctx;
- instance<sql_emitter> em;
- emitter_ostream emos (*em);
-
- schema_format f (schema_format::sql);
-
- instance<changeset_post> changeset (*em, emos, f);
- instance<drop_table> dtable (*em, emos, f);
- instance<alter_table_post> 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<version_table> vt (*em, emos, f);
- vt->migrate_post ();
- }
- }
- }
-}
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
deleted file mode 100644
index c5e16c6..0000000
--- a/odb/relational/schema.hxx
+++ /dev/null
@@ -1,1603 +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 <set>
-#include <vector>
-#include <cassert>
-
-#include <odb/emitter.hxx>
-#include <odb/relational/common.hxx>
-#include <odb/relational/context.hxx>
-
-namespace relational
-{
- namespace schema
- {
- typedef std::set<qname> 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 <typename T, typename D>
- 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<alter_table&> (d.scope ()));
- changeset& cs (dynamic_cast<changeset&> (at.scope ()));
- model& bm (cs.base_model ());
- table* bt (bm.find<table> (at.name ()));
- assert (bt != 0);
- T* b (bt->find<T> (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<sema_rel::table&> (fk.scope ()));
-
- if (dropped_ != 0)
- {
- sema_rel::qname const& rt (fk.referenced_table ());
- sema_rel::model& m (dynamic_cast<sema_rel::model&> (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<sema_rel::index> (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<drop_foreign_key> dfk (*this);
- trav_rel::unames n (*dfk);
- names (t, n);
- }
- else
- {
- dropped_.insert (t.name ()); // Add it before to cover self-refs.
-
- instance<drop_foreign_key> 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<model&> (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<foreign_key*> (
- &i->nameable ()))
- {
- p = m.find<table> (fk->referenced_table ());
- assert (p != 0); // Base table should be there.
- break;
- }
- }
-
- primary_key& rkey (*p->find<primary_key> (""));
- primary_key& dkey (*t.find<primary_key> (""));
- 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<changeset&> (dt.scope ()));
- model& bm (cs.base_model ());
- table* t (bm.find<table> (dt.name ()));
- assert (t != 0);
- traverse (*t, true);
- }
-
- 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<sema_rel::primary_key*> (&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<sema_rel::add_column> () &&
- !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<sema_rel::table&> (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<create_column> c (*this);
- instance<create_primary_key> 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<create_foreign_key> 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<create_index> 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<sema_rel::foreign_key> () &&
- !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<sema_rel::add_table> ())
- 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<create_foreign_key> 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<sema_rel::column&> (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<sema_rel::column&> (ac));
- }
-
- protected:
- bool pre_;
- bool& first_;
- bool first_data_;
- bool fl_; // (Im)perfect forwarding.
- instance<create_column> 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 <typename T>
- 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<T*> (&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<alter_column*> (&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<add_column*> (&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<sema_rel::drop_foreign_key> (at) ||
- check<sema_rel::add_column> (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<create_column> cc (*this, tl, pf);
- instance<alter_column> ac (*this, tl, pf);
- instance<drop_foreign_key> 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<drop_index> 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<create_index> 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<sema_rel::add_foreign_key> (at) ||
- check<sema_rel::drop_column> (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<drop_column> dc (*this, pf);
- instance<alter_column> ac (*this, fl, pf);
- instance<create_foreign_key> 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<drop_index> 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<create_index> 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 20c431a..0000000
--- a/odb/relational/source.cxx
+++ /dev/null
@@ -1,6324 +0,0 @@
-// file : odb/relational/source.cxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <map>
-
-#include <odb/gcc.hxx>
-
-#include <odb/lookup.hxx>
-#include <odb/cxx-lexer.hxx>
-
-#include <odb/relational/source.hxx>
-#include <odb/relational/generate.hxx>
-
-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"));
- user_sections* buss (poly_base != 0
- ? &poly_base->get<user_sections> ("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<container_cache_members> cm;
- cm->traverse (c);
-
- if (containers)
- os << endl;
-
- instance<section_cache_members> 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<container_cache_init_members> cim;
- cim->traverse (c);
-
- instance<section_cache_init_members> 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<container_traits> t (c);
- t->traverse (c);
- }
-
- //
- // Sections (abstract and concrete).
- //
-
- for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
- {
- instance<section_traits> 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<init_value_member> 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<size_t, user_section*> 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<size_t, user_section*>::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 << "&section_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<object_columns> 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<query_parameters> 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<persist_statement_params> 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<object_columns_list> id_cols;
- id_cols->traverse (*id);
-
- std::vector<size_t> 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<object_columns> 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<polymorphic_object_joins> 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<object_joins> 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<query_parameters> 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<size_t>::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<object_columns> 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<query_parameters> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<query_parameters> 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<polymorphic_object_joins> 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<object_joins> 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<object_columns> 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 << ")"
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);";
-
- if (poly)
- os << "ODB_POTENTIALLY_UNUSED (top);";
-
- os << endl
- << "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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<const object_type&> (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<object_type&> (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<container_calls> 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<member_access> ("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<const object_type&> (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)"
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
- << "using namespace " << db << ";"
- << endl;
-
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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
- //@@ assumption: insert_send_auto_id is false
- << "init (sts.image (i), obj, statement_insert" <<
- (versioned ? ", svm" : "") << ");"
- << "}";
-
- //@@ assumption: generate_grow is false
- 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 is false
- << "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<object_type&> (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<member_access> ("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<const object_type&> (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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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<member_access> ("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<container_calls> 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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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<container_calls> 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<object_type&> (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<member_access> ("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)"
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
- << "using namespace " << db << ";"
- << "using " << db << "::update_statement;"
- << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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 false
- << "init (sts.image (i), obj, statement_update);"
- << "}";
-
- // Update bindings.
- //
- os << "binding& idb (sts.id_image_binding ());"
- << "binding& imb (sts.update_image_binding ());"
- << endl;
-
- //@@ assumption: generate_grow false
- //
- 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 false
- //
- 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<object_type&> (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 << ";"
- << endl
- << "ODB_POTENTIALLY_UNUSED (db);";
-
- if (poly)
- os << "ODB_POTENTIALLY_UNUSED (top);";
-
- os << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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<container_calls> 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
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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 false
- << "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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<container_calls> 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<container_calls> 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
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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 false
- << "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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<object_type> " <<
- "(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<object_type, pointer_type>::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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<object_type> ());";
-
- 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<member_access> ("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<object_type> ());";
-
- 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<member_access> ("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<container_calls> 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<member_access> ("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<object_type&> (r));"
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());"
- << 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<object_type>";
- else if (id != 0)
- result_type = "object_result_impl<object_type>";
- else
- result_type = "no_id_object_result_impl<object_type>";
-
- string sep (versioned || query_optimize ? "\n" : " ");
-
- // Unprepared.
- //
- if (!options.omit_unprepared ())
- {
- // query ()
- //
- os << "result< " << traits << "::object_type >" << endl
- << traits << "::" << endl
- << "query (database&, const query_base_type& q)"
- << "{"
- << "using namespace " << db << ";"
- << "using odb::details::shared;"
- << "using odb::details::shared_ptr;"
- << endl;
-
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << endl
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<select_statement> 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<object_type> (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&, const query_base_type& q)"
- << "{"
- << "using namespace " << db << ";"
- << endl
- << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << 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<prepared_query_impl>" << endl
- << traits << "::" << endl
- << "prepare_query (connection& c, const char* n, " <<
- "const query_base_type& q)"
- << "{"
- << "using namespace " << db << ";"
- << "using odb::details::shared;"
- << "using odb::details::shared_ptr;"
- << endl;
-
- os << db << "::connection& conn (" << endl
- << "static_cast<" << db << "::connection&> (c));"
- << endl
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<prepared_query_impl>" << 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<result_impl>" << endl
- << traits << "::" << endl
- << "execute_query (prepared_query_impl& q)"
- << "{"
- << "using namespace " << db << ";"
- << "using odb::details::shared;"
- << "using odb::details::shared_ptr;"
- << endl
- << db << "::prepared_query_impl& pq (" << endl
- << "static_cast<" << db << "::prepared_query_impl&> (q));"
- << "shared_ptr<select_statement> st (" << endl
- << "odb::details::inc_ref (" << endl
- << "static_cast<select_statement*> (pq.stmt.get ())));"
- << endl;
-
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << endl
- << "// The connection used by the current transaction and the" << endl
- << "// one used to prepare this statement must be the same." << endl
- << "//" << endl
- << "assert (&conn == &st->connection ());"
- << endl
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
-
- 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<result_impl> (" << 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<view_query> ("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<view_objects> ("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<semantics::scope&> (*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<polymorphic_object_joins> 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<semantics::scope&> (*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<polymorphic_object_joins> 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<class_&> (
- 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<class_&> (e.member_path.front ()->scope ());
-
- if (!polymorphic (*c))
- c = root;
-
- t = table_name (*c, e.member_path);
- }
- else
- {
- c = &static_cast<class_&> (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<object_columns_list> c_cols; // Container columns.
- instance<object_columns_list> 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 = &lt;
- }
- 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 = &lt;
- }
- 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<object_columns_list> c_cols; // Container columns.
- instance<object_columns_list> 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 = &lt;
- }
- }
- 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 = &lt;
- }
- }
-
- 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<object_columns_list> l_cols;
- instance<object_columns_list> 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<polymorphic_object_joins> 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<view_objects> ("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<view_object_check> 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<size_t> ("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;
-
- if (has_a (c, test_pointer))
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << 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<semantics::scope&> (*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<view_columns> 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<semantics::scope&> (*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&, 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 ());"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_view<view_type> ());";
-
- 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<select_statement> 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<view_type> > r (" << endl
- << "new (shared) " << db << "::view_result_impl<view_type> (" << endl
- << "qs, st, sts, " << (versioned ? "&svm" : "0") << "));"
- << endl
- << "return result<view_type> (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<prepared_query_impl>" << endl
- << traits << "::" << endl
- << "prepare_query (connection& c, const char* n, " <<
- "const query_base_type& q)"
- << "{"
- << "using namespace " << db << ";"
- << "using odb::details::shared;"
- << "using odb::details::shared_ptr;"
- << endl;
-
- os << db << "::connection& conn (" << endl
- << "static_cast<" << db << "::connection&> (c));"
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_view<view_type> ());";
-
- 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<prepared_query_impl>" << 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<result_impl>" << endl
- << traits << "::" << endl
- << "execute_query (prepared_query_impl& q)"
- << "{"
- << "using namespace " << db << ";"
- << "using odb::details::shared;"
- << "using odb::details::shared_ptr;"
- << endl
- << db << "::prepared_query_impl& pq (" << endl
- << "static_cast<" << db << "::prepared_query_impl&> (q));"
- << "shared_ptr<select_statement> st (" << endl
- << "odb::details::inc_ref (" << endl
- << "static_cast<select_statement*> (pq.stmt.get ())));"
- << endl;
-
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
- << endl
- << "// The connection used by the current transaction and the" << endl
- << "// one used to prepare this statement must be the same." << endl
- << "//" << endl
- << "assert (&conn == &st->connection ());"
- << endl
- << "statements_type& sts (" << endl
- << "conn.statement_cache ().find_view<view_type> ());";
-
- 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<result_impl> (" << endl
- << "new (shared) " << db << "::view_result_impl<view_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::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<data_member> (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<data_member> (
- l, tt, tl, tn, ptt,
- start_scope,
- name,
- false,
- &s);
-
- view_object_map::const_iterator i (
- omap.find (dynamic_cast<semantics::class_*> (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<data_member> (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<view_alias_map> ("alias-map"));
- view_object_map const& omap (c.get<view_object_map> ("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<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;
-
- instance<include> 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 f82b5ad..0000000
--- a/odb/relational/source.hxx
+++ /dev/null
@@ -1,7142 +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 <map>
-#include <set>
-#include <list>
-#include <vector>
-#include <sstream>
-
-#include <odb/diagnostics.hxx>
-
-#include <odb/relational/context.hxx>
-#include <odb/relational/common.hxx>
-#include <odb/relational/schema.hxx>
-
-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_column> 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<semantics::class_&> (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<object_columns> 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<object_columns> 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*> ("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<iterator, iterator> 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<class_&> (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<class_&> (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<object_columns_list> l_cols; // Our id columns.
- instance<object_columns_list> 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*> ("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*> ("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<object_columns> 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<table_column> ("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> ("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<table_column> ("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> ("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<object_columns_list> 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<semantics::class_&> (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<object_columns_list> 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<object_columns_list> 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<object_columns_list> 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<object_columns_list> oid_cols (column_prefix_);
- oid_cols->traverse (m);
-
- instance<object_columns_list> 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<polymorphic_object_joins> 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<polymorphic_object_joins> 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<object_columns_list> 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<view_object_check> 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<view_object_check> 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<iterator, iterator> 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<semantics::class_&> (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 <typename T>
- struct bind_member_impl: bind_member, virtual member_base_impl<T>
- {
- typedef bind_member_impl base_impl;
-
- bind_member_impl (base const& x): base (x) {}
-
- typedef typename member_base_impl<T>::member_info member_info;
-
- 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<user_section*> (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<user_section*> (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<T>::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 <typename T>
- struct grow_member_impl: grow_member, virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- 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<user_section*> (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<user_section*> (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<T>::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 <typename T>
- struct init_image_member_impl: init_image_member,
- virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- 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<user_section*> (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<member_access> ("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<bool> ("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<bool> ("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<user_section*> (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> 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 <typename T>
- struct init_value_member_impl: init_value_member,
- virtual member_base_impl<T>
- {
- 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<T>::member_info member_info;
-
- 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<user_section*> (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<member_access> ("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<bool> ("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<bool> ("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<member_access> ("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<T>::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> 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<bool> // 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<bool> ("object-pointer-raw"));
- bool mp_raw (utype (mi.m).is_a<semantics::pointer> ());
-
- // 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<member_access> ("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<member_access> ("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<type&> (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<object_columns_list> id_cols;
- instance<object_columns_list> 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<semantics::class_&> (imf.scope ());
-
- data_member_path& inv_id (*id_member (*c));
-
- qname inv_table; // Other table name.
- string inv_qtable;
- instance<object_columns_list> inv_id_cols; // Other id column.
- instance<object_columns_list> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<query_parameters> 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<object_columns> 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<query_parameters> 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<bind_member> bm (
- "index_", "c", *it, ict, "index_type", "index");
- bm->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<bind_member> bm (
- "key_", "c", *kt, kct, "key_type", "key");
- bm->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "// value" << endl
- << "//" << endl;
- instance<bind_member> 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<bind_member> 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<bind_member> 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<bind_member> 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<bind_member> 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<bind_member> bm (
- "index_", "c", *it, ict, "index_type", "index");
- bm->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<bind_member> bm (
- "key_", "c", *kt, kct, "key_type", "key");
- bm->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- os << "// value" << endl
- << "//" << endl;
- instance<bind_member> 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<grow_member> gm (
- index, "index_", *it, ict, "index_type", "index");
- gm->traverse (m);
- }
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
- instance<grow_member> gm (
- index, "key_", *kt, kct, "key_type", "key");
- gm->traverse (m);
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- break;
- }
- }
-
- os << "// value" << endl
- << "//" << endl;
- instance<grow_member> 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<init_image_member> 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<init_image_member> im (
- "key_", "*k", *kt, kct, "key_type", "key");
- im->traverse (m);
-
- break;
- }
- case ck_set:
- case ck_multiset:
- {
- break;
- }
- }
-
- os << "// value" << endl
- << "//" << endl;
- {
- instance<init_image_member> 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<init_image_member> 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<init_value_member> im (
- "index_", "j", *it, ict, "index_type", "index");
- im->traverse (m);
- }
-
- break;
- }
- case ck_map:
- case ck_multimap:
- {
- os << "// key" << endl
- << "//" << endl;
-
- instance<init_value_member> 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<init_value_member> 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<member_access> (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<member_access> (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<user_section*> (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> ("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<bind_member> 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<grow_member> 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<init_value_member> 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<init_image_member> 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<object_columns_list> 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<object_columns> 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<polymorphic_object_joins> 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<object_joins> 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<query_parameters> 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<query_parameters> 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<object_columns> 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<container_calls> 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<container_calls> 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<object_type&> (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;
- }
-
- 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),
- 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),
- 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<view_query> ("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<container_traits> 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> query_columns_type_;
- instance<view_query_columns_type> view_query_columns_type_;
-
- size_t index_;
- instance<grow_base> grow_base_;
- traversal::inherits grow_base_inherits_;
- instance<grow_member> grow_member_;
- traversal::names grow_member_names_;
- instance<grow_member> grow_version_member_;
- instance<grow_member> grow_discriminator_member_;
-
-
- instance<bind_base> bind_base_;
- traversal::inherits bind_base_inherits_;
- instance<bind_member> bind_member_;
- traversal::names bind_member_names_;
- instance<bind_member> bind_id_member_;
- instance<bind_member> bind_version_member_;
- instance<bind_member> bind_discriminator_member_;
-
- instance<init_image_base> init_image_base_;
- traversal::inherits init_image_base_inherits_;
- instance<init_image_member> init_image_member_;
- traversal::names init_image_member_names_;
-
- instance<init_image_member> init_id_image_member_;
- instance<init_image_member> init_version_image_member_;
-
- instance<init_value_base> init_value_base_;
- traversal::inherits init_value_base_inherits_;
- instance<init_value_member> init_value_member_;
- traversal::names init_value_member_names_;
-
- instance<init_view_pointer_member> init_view_pointer_member_pre_;
- instance<init_view_pointer_member> init_view_pointer_member_post_;
- traversal::names init_view_pointer_member_pre_names_;
- traversal::names init_view_pointer_member_post_names_;
-
- instance<init_value_member> init_id_value_member_;
- instance<init_value_member> init_id_value_member_id_image_;
- instance<init_value_member> init_version_value_member_;
- instance<init_value_member> init_named_version_value_member_;
- instance<init_value_member> init_discriminator_value_member_;
- instance<init_value_member> init_named_discriminator_value_member_;
- };
-
- struct include: virtual context
- {
- typedef include base;
-
- virtual void
- generate ()
- {
- extra_pre ();
-
- os << "#include <cassert>" << endl
- << "#include <cstring> // std::memcpy" << endl;
-
- if (features.polymorphic_object)
- os << "#include <typeinfo>" << endl;
-
- os << endl;
-
- if (features.polymorphic_object)
- os << "#include <odb/polymorphic-map.hxx>" << endl;
-
- if (embedded_schema)
- os << "#include <odb/schema-catalog-impl.hxx>" << endl;
-
- if (multi_dynamic)
- os << "#include <odb/function-table.hxx>" << endl;
-
- os << endl;
-
- os << "#include <odb/" << db << "/traits.hxx>" << endl
- << "#include <odb/" << db << "/database.hxx>" << endl
- << "#include <odb/" << db << "/transaction.hxx>" << endl
- << "#include <odb/" << db << "/connection.hxx>" << endl
- << "#include <odb/" << db << "/statement.hxx>" << endl
- << "#include <odb/" << db << "/statement-cache.hxx>" << endl;
-
- if (features.simple_object)
- os << "#include <odb/" << db << "/simple-object-statements.hxx>" << endl;
-
- if (features.polymorphic_object)
- os << "#include <odb/" << db << "/polymorphic-object-statements.hxx>" << endl;
-
- if (features.no_id_object)
- os << "#include <odb/" << db << "/no-id-object-statements.hxx>" << endl;
-
- if (features.view)
- os << "#include <odb/" << db << "/view-statements.hxx>" << endl;
-
- if (features.section)
- os << "#include <odb/" << db << "/section-statements.hxx>" << endl;
-
- os << "#include <odb/" << db << "/container-statements.hxx>" << endl
- << "#include <odb/" << db << "/exceptions.hxx>" << endl;
-
- if (options.generate_query ())
- {
- if (options.generate_prepared ())
- os << "#include <odb/" << db << "/prepared-query.hxx>" << endl;
-
- if (features.simple_object)
- os << "#include <odb/" << db << "/simple-object-result.hxx>" << endl;
-
- if (features.polymorphic_object)
- os << "#include <odb/" << db << "/polymorphic-object-result.hxx>" << endl;
-
- if (features.no_id_object)
- os << "#include <odb/" << db << "/no-id-object-result.hxx>" << endl;
-
- if (features.view)
- os << "#include <odb/" << db << "/view-result.hxx>" << 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 <cassert>
-
-#include <odb/relational/sqlite/common.hxx>
-
-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_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> 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> 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 <odb/relational/common.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-namespace relational
-{
- namespace sqlite
- {
- struct member_base: virtual relational::member_base_impl<sql_type>, 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 <vector>
-#include <cassert>
-#include <sstream>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/relational/sqlite/context.hxx>
-#include <odb/relational/sqlite/common.hxx>
-
-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<data*> (root_context::data_.get ()), m),
- data_ (static_cast<data*> (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<bool> ("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<semantics::class_&> (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<bool> ("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<array*> (&t))
- {
- semantics::type& bt (a->base_type ());
- if (bt.is_a<semantics::fund_char> () ||
- bt.is_a<semantics::fund_wchar> ())
- {
- 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<string> 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> ("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 <map>
-
-#include <odb/relational/context.hxx>
-
-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<string, sql_type_cache_entry> 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 <odb/relational/header.hxx>
-
-#include <odb/relational/sqlite/common.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-namespace relational
-{
- namespace sqlite
- {
- namespace header
- {
- namespace relational = relational::header;
-
- struct image_member: relational::image_member_impl<sql_type>,
- 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> 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 <odb/relational/inline.hxx>
-
-#include <odb/relational/sqlite/common.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace sqlite
- {
- namespace inline_
- {
- namespace relational = relational::inline_;
-
- struct null_member: relational::null_member_impl<sql_type>,
- 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> 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 <sstream>
-
-#include <odb/relational/model.hxx>
-
-#include <odb/relational/sqlite/common.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-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<enumerator&> (*unit.find (en)));
-
- ostringstream ostr;
-
- if (e.enum_ ().unsigned_ ())
- ostr << e.value ();
- else
- ostr << static_cast<long long> (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> 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 <odb/relational/schema.hxx>
-
-#include <odb/relational/sqlite/common.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-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<sema_rel::column> (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<sema_rel::table&> (in.scope ()));
- sema_rel::qname n (t.name ().qualifier ());
- n.append (in.name ());
- return quote_id (n);
- }
- };
- entry<drop_index> 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<model&> (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<foreign_key*> (
- &i->nameable ()))
- {
- p = m.find<table> (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> (""));
- primary_key& dkey (*t.find<primary_key> (""));
- assert (rkey.contains_size () == dkey.contains_size ());
- delete_ (p->name (), t.name (), rkey, dkey);
- }
-
- drop (t, migration);
- }
- };
- entry<drop_table> 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<alter_table&> (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<add_foreign_key*> (&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<relational::create_foreign_key> 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> 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> 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<sema_rel::table&> (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<sema_rel::table&> (in.scope ()).name ().uname ());
- }
- };
- entry<create_index> 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> 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<create_column> cc (*this);
- trav_rel::unames n (*cc);
- names (at, n);
-
- // SQLite does not support altering columns.
- //
- if (sema_rel::alter_column* ac = check<sema_rel::alter_column> (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<drop_foreign_key*> (&i->nameable ()));
-
- if (dfk == 0)
- continue;
-
- foreign_key& fk (find<foreign_key> (*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> 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<sema_rel::alter_column> (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<sema_rel::drop_column> (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<sema_rel::add_foreign_key*> (&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> 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> version_table_;
- }
- }
-}
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
deleted file mode 100644
index 2624af2..0000000
--- a/odb/relational/sqlite/source.cxx
+++ /dev/null
@@ -1,470 +0,0 @@
-// file : odb/relational/sqlite/source.cxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <odb/relational/source.hxx>
-
-#include <odb/relational/sqlite/common.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-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> query_parameters_;
-
- //
- // bind
- //
-
- struct bind_member: relational::bind_member_impl<sql_type>,
- 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> bind_member_;
-
- //
- // grow
- //
-
- struct grow_member: relational::grow_member_impl<sql_type>,
- 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> grow_member_;
-
- //
- // init image
- //
-
- struct init_image_member: relational::init_image_member_impl<sql_type>,
- 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_image_member_;
-
- //
- // init value
- //
-
- struct init_value_member: relational::init_value_member_impl<sql_type>,
- 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> 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> 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)
- {
- statement_columns_common::process (cols, sk);
- }
- };
- entry<section_traits> 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<int64_t> id;
- //
- semantics::type& t (utype (m));
- if (wrapper (t) && t.template get<bool> ("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_> 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 <map>
-#include <iostream>
-
-#include <odb/diagnostics.hxx>
-#include <odb/traversal.hxx>
-#include <odb/relational/common.hxx>
-#include <odb/relational/context.hxx>
-#include <odb/relational/validator.hxx>
-
-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<foreign_key::action_type> ("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<indexes> ("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<location_t> ("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> ("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<indexes> ("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<view_query> ("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> ("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 <odb/options.hxx>
-#include <odb/features.hxx>
-#include <odb/semantics/unit.hxx>
-
-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