From 853d76b58e96aab4e6182cc1234652dfcdd74c14 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 5 Apr 2013 10:16:48 +0200 Subject: Generate alter column migration statements --- odb/relational/mssql/schema.cxx | 53 ++++++++++++- odb/relational/mysql/schema.cxx | 12 +++ odb/relational/oracle/schema.cxx | 65 ++++++++++++++-- odb/relational/pgsql/schema.cxx | 13 ++++ odb/relational/schema.hxx | 160 ++++++++++++++++++++++++++++++++++++--- odb/relational/sqlite/schema.cxx | 11 +++ 6 files changed, 292 insertions(+), 22 deletions(-) diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx index 03406ce..2db0c12 100644 --- a/odb/relational/mssql/schema.cxx +++ b/odb/relational/mssql/schema.cxx @@ -336,6 +336,35 @@ namespace relational }; entry drop_index_; + struct alter_column: relational::alter_column, context + { + alter_column (base const& x): base (x) {} + + virtual void + traverse (sema_rel::alter_column& ac) + { + assert (ac.null_altered ()); + + // Relax (NULL) in pre and tighten (NOT NULL) in post. + // + if (pre_ != ac.null ()) + return; + + using sema_rel::alter_table; + alter_table& at (static_cast (ac.scope ())); + + pre_statement (); + + os << "ALTER TABLE " << quote_id (at.name ()) << endl + << " ALTER COLUMN "; + alter (ac); + os << endl; + + post_statement (); + } + }; + entry alter_column_; + struct alter_table_pre: relational::alter_table_pre, context { alter_table_pre (base const& x): base (x) {} @@ -352,13 +381,21 @@ namespace relational os << " ADD "; instance c (emitter (), stream (), format_); - trav_rel::unames n; - n >> c; + trav_rel::unames n (*c); names (at, n); os << endl; post_statement (); } + + // For ALTER COLUMN, SQL Server can only have one per ALTER TABLE. + // + { + bool tl (true); // (Im)perfect forwarding. + instance ac (emitter (), stream (), format_, tl); + trav_rel::unames n (*ac); + names (at, n); + } } }; entry alter_table_pre_; @@ -379,13 +416,21 @@ namespace relational os << " DROP COLUMN "; instance c (emitter (), stream (), format_); - trav_rel::unames n; - n >> c; + trav_rel::unames n (*c); names (at, n); os << endl; post_statement (); } + + // For ALTER COLUMN, SQL Server can only have one per ALTER TABLE. + // + { + bool fl (false); // (Im)perfect forwarding. + instance ac (emitter (), stream (), format_, fl); + trav_rel::unames n (*ac); + names (at, n); + } } }; entry alter_table_post_; diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx index c3f7571..6ce619b 100644 --- a/odb/relational/mysql/schema.cxx +++ b/odb/relational/mysql/schema.cxx @@ -367,6 +367,18 @@ namespace relational } }; entry drop_index_; + + struct alter_column: relational::alter_column, context + { + alter_column (base const& x): base (x) {} + + virtual void + alter_header () + { + os << "MODIFY COLUMN "; + } + }; + entry alter_column_; } } } diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx index 34ede1c..024701c 100644 --- a/odb/relational/oracle/schema.cxx +++ b/odb/relational/oracle/schema.cxx @@ -344,6 +344,31 @@ namespace relational }; entry drop_index_; + struct alter_column: relational::alter_column, context + { + alter_column (base const& x): base (x) {} + + virtual void + traverse (sema_rel::alter_column& ac) + { + assert (ac.null_altered ()); + + // Relax (NULL) in pre and tighten (NOT NULL) in post. + // + if (pre_ != ac.null ()) + return; + + if (first_) + first_ = false; + else + os << "," << endl + << " "; + + os << quote_id (ac.name ()) << (ac.null () ? " NULL" : " NOT NULL"); + } + }; + entry alter_column_; + struct alter_table_pre: relational::alter_table_pre, context { alter_table_pre (base const& x): base (x) {} @@ -360,9 +385,23 @@ namespace relational alter_header (at.name ()); os << " ADD ("; - instance c (emitter (), stream (), format_); - trav_rel::unames n; - n >> c; + instance cc (emitter (), stream (), format_); + trav_rel::unames n (*cc); + names (at, n); + os << ")" << endl; + + post_statement (); + } + + if (check_alter_null (at, true)) + { + pre_statement (); + alter_header (at.name ()); + os << " MODIFY ("; + + bool tl (true); // (Im)perfect forwarding. + instance ac (emitter (), stream (), format_, tl); + trav_rel::unames n (*ac); names (at, n); os << ")" << endl; @@ -388,9 +427,23 @@ namespace relational alter_header (at.name ()); os << " DROP ("; - instance c (emitter (), stream (), format_); - trav_rel::unames n; - n >> c; + instance dc (emitter (), stream (), format_); + trav_rel::unames n (*dc); + names (at, n); + os << ")" << endl; + + post_statement (); + } + + if (check_alter_null (at, false)) + { + pre_statement (); + alter_header (at.name ()); + os << " MODIFY ("; + + bool fl (false); // (Im)perfect forwarding. + instance ac (emitter (), stream (), format_, fl); + trav_rel::unames n (*ac); names (at, n); os << ")" << endl; diff --git a/odb/relational/pgsql/schema.cxx b/odb/relational/pgsql/schema.cxx index efe9b40..7e0b7a5 100644 --- a/odb/relational/pgsql/schema.cxx +++ b/odb/relational/pgsql/schema.cxx @@ -209,6 +209,19 @@ namespace relational } }; entry create_index_; + + struct alter_column: relational::alter_column, context + { + alter_column (base const& x): base (x) {} + + virtual void + alter (sema_rel::alter_column& ac) + { + os << quote_id (ac.name ()) << " " << + (ac.null () ? "DROP" : "SET") << " NOT NULL"; + } + }; + entry alter_column_; } } } diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx index b0d70df..69e8089 100644 --- a/odb/relational/schema.hxx +++ b/odb/relational/schema.hxx @@ -64,8 +64,24 @@ namespace relational { typedef drop_column base; - drop_column (emitter_type& e, ostream& os, schema_format f) - : common (e, os), format_ (f), first_ (true) + drop_column (emitter_type& e, + ostream& os, + schema_format f, + bool* first = 0) + : common (e, os), + format_ (f), + first_ (first != 0 ? *first : first_data_), + first_data_ (true) + { + } + + drop_column (drop_column const& c) + : root_context (), // @@ -Wextra + context (), + common (c), + format_ (c.format_), + first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), + first_data_ (c.first_data_) { } @@ -92,7 +108,8 @@ namespace relational protected: schema_format format_; - bool first_; + bool& first_; + bool first_data_; }; // Currently only used in migration. @@ -292,8 +309,24 @@ namespace relational { typedef create_column base; - create_column (emitter_type& e, ostream& os, schema_format f) - : common (e, os), format_ (f), first_ (true) + create_column (emitter_type& e, + ostream& os, + schema_format f, + bool* first = 0) + : common (e, os), + format_ (f), + first_ (first != 0 ? *first : first_data_), + first_data_ (true) + { + } + + create_column (create_column const& c) + : root_context (), // @@ -Wextra + context (), + common (c), + format_ (c.format_), + first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), + first_data_ (c.first_data_) { } @@ -394,7 +427,8 @@ namespace relational protected: schema_format format_; - bool first_; + bool& first_; + bool first_data_; }; struct create_primary_key: trav_rel::primary_key, virtual context @@ -775,6 +809,78 @@ namespace relational // Migration. // + struct alter_column: trav_rel::alter_column, common + { + typedef alter_column base; + + alter_column (emitter_type& e, + ostream& os, + schema_format f, + bool pre, + bool* first = 0) + : common (e, os), + format_ (f), + pre_ (pre), + first_ (first != 0 ? *first : first_data_), + first_data_ (true), + def_ (e, os, f) + { + } + + alter_column (alter_column const& c) + : root_context (), // @@ -Wextra + context (), + common (c), + format_ (c.format_), + pre_ (c.pre_), + first_ (&c.first_ != &c.first_data_ ? c.first_ : first_data_), + first_data_ (c.first_data_), + def_ (common::e_, common::os_, c.format_) + { + } + + virtual void + alter_header () + { + os << "ALTER COLUMN "; + } + + virtual void + alter (sema_rel::alter_column& ac) + { + // By default use the whole definition. + // + def_->create (ac); + } + + virtual void + traverse (sema_rel::alter_column& ac) + { + assert (ac.null_altered ()); + + // Relax (NULL) in pre and tighten (NOT NULL) in post. + // + if (pre_ != ac.null ()) + return; + + if (first_) + first_ = false; + else + os << "," << endl; + + os << " "; + alter_header (); + alter (ac); + } + + protected: + schema_format format_; + bool pre_; + bool& first_; + bool first_data_; + instance def_; + }; + struct alter_table_common: trav_rel::alter_table, common { alter_table_common (emitter_type& e, ostream& os, schema_format f) @@ -796,6 +902,24 @@ namespace relational return 0; } + sema_rel::alter_column* + check_alter_null (sema_rel::alter_table& at, bool v) + { + using sema_rel::alter_column; + + for (sema_rel::alter_table::names_iterator i (at.names_begin ()); + i != at.names_end (); ++i) + { + if (alter_column* ac = dynamic_cast (&i->nameable ())) + { + if (ac->null_altered () && ac->null () == v) + return ac; + } + } + + return 0; + } + virtual void alter_header (sema_rel::qname const& table) { @@ -829,7 +953,8 @@ namespace relational virtual bool check (sema_rel::alter_table& at) { - return check (at); + return check (at) || + check_alter_null (at, true); } virtual void @@ -841,9 +966,14 @@ namespace relational pre_statement (); alter_header (at.name ()); - instance c (emitter (), stream (), format_); + bool f (true); // Shared first flag. + bool* pf (&f); // (Im)perfect forwarding. + bool tl (true); // (Im)perfect forwarding. + instance cc (emitter (), stream (), format_, pf); + instance ac (emitter (), stream (), format_, tl, pf); trav_rel::unames n; - n >> c; + n >> cc; + n >> ac; names (at, n); os << endl; @@ -933,7 +1063,8 @@ namespace relational virtual bool check (sema_rel::alter_table& at) { - return check (at); + return check (at) || + check_alter_null (at, false); } virtual void @@ -945,9 +1076,14 @@ namespace relational pre_statement (); alter_header (at.name ()); - instance c (emitter (), stream (), format_); + bool f (true); // Shared first flag. + bool* pf (&f); // (Im)perfect forwarding. + bool fl (false); // (Im)perfect forwarding. + instance dc (emitter (), stream (), format_, pf); + instance ac (emitter (), stream (), format_, fl, pf); trav_rel::unames n; - n >> c; + n >> dc; + n >> ac; names (at, n); os << endl; diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx index ac19328..6d3cba4 100644 --- a/odb/relational/sqlite/schema.cxx +++ b/odb/relational/sqlite/schema.cxx @@ -122,6 +122,17 @@ namespace relational trav_rel::unames n; n >> c; names (at, n); + + // SQLite does not support altering columns. + // + if (sema_rel::alter_column* ac = check (at)) + { + cerr << "error: SQLite does not support altering of columns" + << endl; + cerr << "info: first altered column is '" << ac->name () << + "' in table '" << at.name () << "'" << endl; + throw operation_failed (); + } } }; entry alter_table_pre_; -- cgit v1.1