aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-04-05 07:30:19 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-04-10 18:46:44 +0200
commitc9dbc099d74d92b17724a24823aafe1fcc8ca7e7 (patch)
tree1c536796f06386209cb2331df1d245ed93497ca9
parent6d4b471afd63780b8a8a6c2d3fb8cc529ab5b15d (diff)
Generate add/drop column migration statements
-rw-r--r--odb/relational/mssql/schema.cxx84
-rw-r--r--odb/relational/oracle/schema.cxx92
-rw-r--r--odb/relational/schema.hxx202
-rw-r--r--odb/relational/sqlite/schema.cxx54
4 files changed, 402 insertions, 30 deletions
diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx
index 58c0206..03406ce 100644
--- a/odb/relational/mssql/schema.cxx
+++ b/odb/relational/mssql/schema.cxx
@@ -40,6 +40,24 @@ namespace relational
// 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_table: relational::drop_table, context
{
drop_table (base const& x): base (x) {}
@@ -148,6 +166,18 @@ namespace relational
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::column&)
{
os << " IDENTITY";
@@ -305,6 +335,60 @@ namespace relational
}
};
entry<drop_index> drop_index_;
+
+ 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)
+ {
+ // SQL Server can only alter one kind of thing at a time.
+ //
+ if (check<sema_rel::add_column> (at))
+ {
+ pre_statement ();
+ alter_header (at.name ());
+ os << " ADD ";
+
+ instance<create_column> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ 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)
+ {
+ // SQL Server can only alter one kind of thing at a time.
+ //
+ if (check<sema_rel::drop_column> (at))
+ {
+ pre_statement ();
+ alter_header (at.name ());
+ os << " DROP COLUMN ";
+
+ instance<drop_column> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ names (at, n);
+ os << endl;
+
+ post_statement ();
+ }
+ }
+ };
+ entry<alter_table_post> alter_table_post_;
}
}
}
diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx
index a76e25a..34ede1c 100644
--- a/odb/relational/oracle/schema.cxx
+++ b/odb/relational/oracle/schema.cxx
@@ -88,6 +88,24 @@ namespace relational
// 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_table: relational::drop_table, context
{
drop_table (base const& x): base (x) {}
@@ -167,6 +185,24 @@ namespace relational
// 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);
+ }
+ };
+ entry<create_column> create_column_;
+
struct create_foreign_key;
struct create_table: relational::create_table, context
@@ -307,6 +343,62 @@ namespace relational
}
};
entry<drop_index> drop_index_;
+
+ 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::add_column> (at))
+ {
+ pre_statement ();
+ alter_header (at.name ());
+ os << " ADD (";
+
+ instance<create_column> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ 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 ();
+ alter_header (at.name ());
+ os << " DROP (";
+
+ instance<drop_column> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ names (at, n);
+ os << ")" << endl;
+
+ post_statement ();
+ }
+ }
+ };
+ entry<alter_table_post> alter_table_post_;
}
}
}
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index 5d3d91f..b0d70df 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -58,6 +58,43 @@ namespace relational
// Drop.
//
+ // Only used in migration.
+ //
+ struct drop_column: trav_rel::drop_column, common
+ {
+ typedef drop_column base;
+
+ drop_column (emitter_type& e, ostream& os, schema_format f)
+ : common (e, os), format_ (f), first_ (true)
+ {
+ }
+
+ 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 << "," << endl;
+
+ os << " ";
+ drop_header ();
+ os << quote_id (dc.name ());
+ }
+
+ protected:
+ schema_format format_;
+ bool first_;
+ };
+
// Currently only used in migration.
//
struct drop_index: trav_rel::drop_index, common
@@ -249,12 +286,14 @@ namespace relational
//
struct create_table;
- struct create_column: trav_rel::column, virtual context
+ struct create_column: trav_rel::column,
+ trav_rel::add_column,
+ common
{
typedef create_column base;
- create_column (schema_format f, create_table& ct)
- : format_ (f), create_table_ (ct), first_ (true)
+ create_column (emitter_type& e, ostream& os, schema_format f)
+ : common (e, os), format_ (f), first_ (true)
{
}
@@ -266,10 +305,32 @@ namespace relational
else
os << "," << endl;
+ os << " ";
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 << "," << endl;
+
+ os << " ";
+ add_header ();
+ create (ac);
+ }
+
+ virtual void
create (sema_rel::column& c)
{
using sema_rel::column;
@@ -286,7 +347,7 @@ namespace relational
break;
}
- os << " " << quote_id (c.name ()) << " ";
+ os << quote_id (c.name ()) << " ";
type (c, pk != 0 && pk->auto_ ());
@@ -333,7 +394,6 @@ namespace relational
protected:
schema_format format_;
- create_table& create_table_;
bool first_;
};
@@ -641,7 +701,7 @@ namespace relational
pre_statement ();
create_pre (t.name ());
- instance<create_column> c (format_, *this);
+ instance<create_column> c (emitter (), stream (), format_);
instance<create_primary_key> pk (format_, *this);
instance<create_foreign_key> fk (format_, *this);
trav_rel::unames n;
@@ -711,15 +771,83 @@ namespace relational
unsigned short pass_;
};
+ //
// Migration.
//
- struct alter_table_pre: trav_rel::alter_table, common
+
+ struct alter_table_common: trav_rel::alter_table, common
+ {
+ alter_table_common (emitter_type& e, ostream& os, schema_format f)
+ : common (e, os), format_ (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;
+ }
+
+ virtual void
+ alter_header (sema_rel::qname const& table)
+ {
+ os << "ALTER TABLE " << quote_id (table) << endl;
+ }
+
+ void
+ pass (unsigned short p)
+ {
+ pass_ = p;
+ }
+
+ protected:
+ schema_format format_;
+ 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)
- : common (e, os), 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)
{
+ return check<sema_rel::add_column> (at);
+ }
+
+ 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 ();
+ alter_header (at.name ());
+
+ instance<create_column> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ names (at, n);
+ os << endl;
+
+ post_statement ();
}
virtual void
@@ -735,6 +863,9 @@ namespace relational
trav_rel::unames n (*in);
names (at, n);
}
+
+ if (check (at))
+ alter (at);
}
else
{
@@ -748,16 +879,6 @@ namespace relational
}
}
}
-
- void
- pass (unsigned short p)
- {
- pass_ = p;
- }
-
- protected:
- schema_format format_;
- unsigned short pass_;
};
struct changeset_pre: trav_rel::changeset, common
@@ -796,13 +917,41 @@ namespace relational
unsigned short pass_;
};
- struct alter_table_post: trav_rel::alter_table, common
+ struct alter_table_post: alter_table_common
{
typedef alter_table_post base;
alter_table_post (emitter_type& e, ostream& os, schema_format f)
- : common (e, os), 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)
{
+ return check<sema_rel::drop_column> (at);
+ }
+
+ 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 ();
+ alter_header (at.name ());
+
+ instance<drop_column> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ names (at, n);
+ os << endl;
+
+ post_statement ();
}
virtual void
@@ -821,6 +970,9 @@ namespace relational
}
else
{
+ if (check (at))
+ alter (at);
+
// Add unique indexes.
//
{
@@ -831,16 +983,6 @@ namespace relational
}
}
}
-
- void
- pass (unsigned short p)
- {
- pass_ = p;
- }
-
- protected:
- schema_format format_;
- unsigned short pass_;
};
struct changeset_post: trav_rel::changeset, common
diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx
index bd694e7..ac19328 100644
--- a/odb/relational/sqlite/schema.cxx
+++ b/odb/relational/sqlite/schema.cxx
@@ -24,6 +24,22 @@ namespace relational
create_column (base const& x): base (x) {}
virtual void
+ traverse (sema_rel::add_column& ac)
+ {
+ using sema_rel::alter_table;
+ alter_table& at (static_cast<alter_table&> (ac.scope ()));
+
+ pre_statement ();
+
+ os << "ALTER TABLE " << quote_id (at.name ()) << endl
+ << " ADD COLUMN ";
+ create (ac);
+ os << endl;
+
+ post_statement ();
+ }
+
+ virtual void
auto_ (sema_rel::column&)
{
if (options.sqlite_lax_auto_id ())
@@ -92,6 +108,44 @@ namespace relational
}
};
entry<drop_index> drop_index_;
+
+ 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> c (emitter (), stream (), format_);
+ trav_rel::unames n;
+ n >> c;
+ 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) {}
+
+ virtual void
+ alter (sema_rel::alter_table& at)
+ {
+ // SQLite does not support dropping columns.
+ //
+ if (sema_rel::drop_column* dc = check<sema_rel::drop_column> (at))
+ {
+ cerr << "error: SQLite does not support dropping of columns"
+ << endl;
+ cerr << "info: first dropped column is '" << dc->name () <<
+ "' in table '" << at.name () << "'" << endl;
+ throw operation_failed ();
+ }
+ }
+ };
+ entry<alter_table_post> alter_table_post_;
}
}
}