aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-04-08 14:22:00 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-04-10 18:46:44 +0200
commita9da959e71ce02b7e8b0457edcae303043b2799a (patch)
tree6ad504022ce8b6e841891b40820519d1c1311205
parent104cdccab69dd0b68a756f5d54126a6b74914408 (diff)
Use single ALTER TABLE to add foreign keys on pass 2
-rw-r--r--odb/relational/mssql/schema.cxx87
-rw-r--r--odb/relational/mysql/schema.cxx96
-rw-r--r--odb/relational/oracle/schema.cxx4
-rw-r--r--odb/relational/schema.hxx145
4 files changed, 200 insertions, 132 deletions
diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx
index 61e7e68..649ab13 100644
--- a/odb/relational/mssql/schema.cxx
+++ b/odb/relational/mssql/schema.cxx
@@ -199,14 +199,14 @@ namespace relational
create_foreign_key (base const& x): base (x) {}
virtual void
- generate (sema_rel::foreign_key& fk)
+ 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::generate (fk);
+ base::traverse_create (fk);
else
{
// Don't bloat C++ code with comment strings if we are
@@ -225,9 +225,9 @@ namespace relational
}
virtual void
- traverse (sema_rel::add_foreign_key& afk)
+ traverse_add (sema_rel::foreign_key& fk)
{
- bool c (!afk.not_deferrable () && !in_comment);
+ bool c (!fk.not_deferrable () && !in_comment);
if (c && format_ != schema_format::sql)
return;
@@ -241,7 +241,7 @@ namespace relational
<< " ";
os << "CONSTRAINT ";
- create (afk);
+ create (fk);
if (c)
os << endl
@@ -268,33 +268,76 @@ namespace relational
};
entry<create_foreign_key> create_foreign_key_;
- struct add_foreign_key: relational::add_foreign_key, context
+ struct create_table: relational::create_table, context
{
- add_foreign_key (base const& x): base (x) {}
+ 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
- generate (sema_rel::table& t, sema_rel::foreign_key& fk)
+ traverse (sema_rel::table& t)
{
- // SQL Server has no deferrable constraints.
- //
- if (fk.not_deferrable ())
- base::generate (t, fk);
+ if (pass_ == 1)
+ base::traverse (t);
else
{
- if (format_ != schema_format::sql)
- return;
+ // Add undefined foreign keys.
+ //
+ if (check_undefined_fk (t))
+ {
+ bool deferrable (check_undefined_fk_deferrable_only (t));
- os << "/*" << endl;
- os << "ALTER TABLE " << quote_id (t.name ()) << endl
- << " ADD CONSTRAINT ";
- def_->create (fk);
- os << endl
- << "*/" << endl
- << endl;
+ 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<add_foreign_key> add_foreign_key_;
+ entry<create_table> create_table_;
struct drop_index: relational::drop_index, context
{
diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx
index be058ce..d1721fa 100644
--- a/odb/relational/mysql/schema.cxx
+++ b/odb/relational/mysql/schema.cxx
@@ -130,14 +130,14 @@ namespace relational
create_foreign_key (base const& x): base (x) {}
virtual void
- generate (sema_rel::foreign_key& fk)
+ 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::generate (fk);
+ base::traverse_create (fk);
else
{
// Don't bloat C++ code with comment strings if we are
@@ -149,17 +149,17 @@ namespace relational
os << endl
<< " /*" << endl
<< " CONSTRAINT ";
- base::create (fk);
+ create (fk);
os << endl
<< " */";
}
}
virtual void
- traverse (sema_rel::add_foreign_key& afk)
+ traverse_add (sema_rel::foreign_key& fk)
{
- if (afk.not_deferrable () || in_comment)
- base::traverse (afk);
+ if (fk.not_deferrable () || in_comment)
+ base::traverse_add (fk);
else
{
if (format_ != schema_format::sql)
@@ -169,7 +169,7 @@ namespace relational
<< " /*"
<< endl;
- add (afk);
+ add (fk);
os << endl
<< " */";
@@ -184,37 +184,73 @@ namespace relational
};
entry<create_foreign_key> create_foreign_key_;
- struct add_foreign_key: relational::add_foreign_key, context
+ struct create_table: relational::create_table, context
{
- add_foreign_key (base const& x): base (x) {}
+ create_table (base const& x): base (x) {}
- virtual void
- generate (sema_rel::table& t, sema_rel::foreign_key& fk)
+ // See if there are any undefined foreign keys that are not
+ // deferrable.
+ //
+ bool
+ check_undefined_fk_deferrable_only (sema_rel::table& t)
{
- // MySQL has no deferrable constraints.
- //
- if (fk.not_deferrable ())
- base::generate (t, fk);
- else
+ for (sema_rel::table::names_iterator i (t.names_begin ());
+ i != t.names_end (); ++i)
{
- if (format_ != schema_format::sql)
- return;
+ using sema_rel::foreign_key;
- os << "/*" << endl;
- os << "ALTER TABLE " << quote_id (t.name ()) << endl
- << " ADD CONSTRAINT ";
- def_->create (fk);
- os << endl
- << "*/" << endl
- << endl;
+ if (foreign_key* fk = dynamic_cast<foreign_key*> (&i->nameable ()))
+ {
+ if (!fk->count ("mysql-fk-defined") &&
+ fk->not_deferrable ())
+ return false;
+ }
}
+ return true;
}
- };
- entry<add_foreign_key> add_foreign_key_;
- struct create_table: relational::create_table, context
- {
- create_table (base const& x): base (x) {}
+ 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 ();
+ }
+ }
+ }
+ }
virtual void
create_post ()
diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx
index 5d0c107..3348d7d 100644
--- a/odb/relational/oracle/schema.cxx
+++ b/odb/relational/oracle/schema.cxx
@@ -242,11 +242,11 @@ namespace relational
create_foreign_key (base const& x): base (x) {}
virtual void
- traverse (sema_rel::add_foreign_key& afk)
+ traverse_add (sema_rel::foreign_key& fk)
{
os << endl
<< " ADD CONSTRAINT ";
- create (afk);
+ create (fk);
}
};
entry<create_foreign_key> create_foreign_key_;
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index 146e526..7f1e1a0 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -634,7 +634,7 @@ namespace relational
{
typedef create_foreign_key base;
- // Schema constructor.
+ // Schema constructor, pass 1.
//
create_foreign_key (common const& c, table_set& created, bool* first = 0)
: common (c),
@@ -644,7 +644,7 @@ namespace relational
{
}
- // Migration constructor.
+ // Schema constructor, pass 2 and migration constructor.
//
create_foreign_key (common const& c, bool* first = 0)
: common (c),
@@ -667,20 +667,31 @@ namespace relational
virtual void
traverse (sema_rel::foreign_key& fk)
{
- // 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
- // (see add_foreign_key below).
- //
- if (created_->find (fk.referenced_table ()) != created_->end ())
+ if (created_ != 0)
{
- generate (fk);
- fk.set (db.string () + "-fk-defined", true); // Mark it as defined.
+ // 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
- generate (sema_rel::foreign_key& fk)
+ traverse_create (sema_rel::foreign_key& fk)
{
if (first_)
first_ = false;
@@ -693,13 +704,7 @@ namespace relational
}
virtual void
- add_header ()
- {
- os << "ADD CONSTRAINT ";
- }
-
- virtual void
- traverse (sema_rel::add_foreign_key& afk)
+ traverse_add (sema_rel::foreign_key& fk)
{
if (first_)
first_ = false;
@@ -707,15 +712,27 @@ namespace relational
os << ",";
os << endl;
- add (afk);
+ add (fk);
}
virtual void
- add (sema_rel::add_foreign_key& afk)
+ 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 (afk);
+ create (fk);
}
virtual void
@@ -807,59 +824,6 @@ namespace relational
bool first_data_;
};
- // Add foreign key via ALTER TABLE.
- //
- struct add_foreign_key: trav_rel::foreign_key, common
- {
- typedef add_foreign_key base;
-
- add_foreign_key (common const& c, table_set& created, bool* first = 0)
- : common (c),
- created_ (created),
- first_ (first != 0 ? *first : first_data_),
- first_data_ (true),
- def_ (c, created_)
- {
- }
-
- add_foreign_key (add_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_),
- def_ (c, created_)
- {
- }
-
- virtual void
- traverse (sema_rel::foreign_key& fk)
- {
- if (!fk.count (db.string () + "-fk-defined"))
- generate (dynamic_cast<sema_rel::table&> (fk.scope ()), fk);
- }
-
- virtual void
- generate (sema_rel::table& t, sema_rel::foreign_key& fk)
- {
- pre_statement ();
-
- os << "ALTER TABLE " << quote_id (t.name ()) << endl
- << " ADD CONSTRAINT ";
- def_->create (fk);
- os << endl;
-
- post_statement ();
- }
-
- protected:
- table_set& created_;
- bool& first_;
- bool first_data_;
- instance<create_foreign_key> def_;
- };
-
struct create_index: trav_rel::index, common
{
typedef create_index base;
@@ -1006,6 +970,22 @@ namespace relational
}
}
+ // 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)
{
@@ -1023,11 +1003,20 @@ namespace relational
}
else
{
- // Add foreign keys.
+ // Add undefined foreign keys.
//
- instance<add_foreign_key> fk (*this, created_);
- trav_rel::unames n (*fk);
- names (t, n);
+ 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 ();
+ }
}
}