diff options
Diffstat (limited to 'odb/relational/mssql/schema.cxx')
-rw-r--r-- | odb/relational/mssql/schema.cxx | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx new file mode 100644 index 0000000..2cbeb5f --- /dev/null +++ b/odb/relational/mssql/schema.cxx @@ -0,0 +1,224 @@ +// file : odb/relational/mssql/schema.cxx +// author : Constantin Michael <constantin@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include <set> + +#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; + + struct schema_emitter: relational::schema_emitter + { + schema_emitter (const base& x): base (x) {} + + virtual void + post () + { + if (!first_) // Ignore empty statements. + { + os << ';' << endl + << "GO" << endl + << endl; + } + } + }; + entry<schema_emitter> schema_emitter_; + + // + // Drop. + // + + struct drop_table: relational::drop_table, context + { + drop_table (base const& x): base (x) {} + + virtual void + drop (string const& table) + { + // SQL Server has no IF EXISTS conditional for dropping table. + // The following approach appears to be the recommended way to + // drop a table if it exists. + // + string const& qt (); + + os << "IF OBJECT_ID(" << quote_string (table) << + ", " << quote_string ("U") << ") IS NOT NULL" << endl + << " DROP TABLE " << quote_id (table) << endl; + } + }; + entry<drop_table> drop_table_; + + // + // Create. + // + + struct create_column: relational::create_column, context + { + create_column (base const& x): base (x) {} + + virtual void + auto_ (sema_rel::column&) + { + os << " IDENTITY"; + } + }; + entry<create_column> create_column_; + + struct create_foreign_key; + + struct create_table: relational::create_table, context + { + create_table (base const& x): base (x) {} + + void + traverse (sema_rel::table&); + + private: + friend class create_foreign_key; + set<string> tables_; // Set of tables we have already defined. + }; + entry<create_table> create_table_; + + struct create_foreign_key: relational::create_foreign_key, context + { + create_foreign_key (schema_format f, relational::create_table& ct) + : base (f, ct) + { + } + + create_foreign_key (base const& x): base (x) {} + + 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). + // + create_table& ct (static_cast<create_table&> (create_table_)); + + if (ct.tables_.find (fk.referenced_table ()) != ct.tables_.end ()) + { + // SQL Server does not support deferred constraint checking. + // Output such foreign keys as comments, for documentation, + // unless we are generating embedded schema. + // + if (fk.deferred ()) + { + // Don't bloat C++ code with comment strings if we are + // generating embedded schema. + // + if (format_ != schema_format::embedded) + { + os << endl + << endl + << " /*" << endl; + + base::create (fk); + + os << endl + << " */"; + } + } + else + base::traverse (fk); + + fk.set ("mssql-fk-defined", true); // Mark it as defined. + } + } + + virtual string + name (sema_rel::foreign_key& fk) + { + // In SQL Server, foreign key names are schema-global. Make them + // unique by prefixing the key name with table name. + // + return static_cast<sema_rel::table&> (fk.scope ()).name () + + '_' + fk.name (); + } + + virtual void + deferred () + { + // SQL Server doesn't support deferred. + } + }; + entry<create_foreign_key> create_foreign_key_; + + struct add_foreign_key: create_foreign_key, relational::common + { + add_foreign_key (schema_format f, relational::create_table& ct) + : create_foreign_key (f, ct), common (ct.emitter (), ct.stream ()) + { + } + + virtual void + traverse (sema_rel::foreign_key& fk) + { + if (!fk.count ("mssql-fk-defined")) + { + sema_rel::table& t (dynamic_cast<sema_rel::table&> (fk.scope ())); + + // SQL Server has no deferred constraints. + // + if (fk.deferred ()) + { + if (format_ != schema_format::embedded) + { + os << "/*" << endl; + + os << "ALTER TABLE " << quote_id (t.name ()) << " ADD" << endl; + base::create (fk); + + os << endl + << "*/" << endl + << endl; + } + } + else + { + pre_statement (); + + os << "ALTER TABLE " << quote_id (t.name ()) << " ADD" << endl; + base::create (fk); + os << endl; + + post_statement (); + } + } + } + }; + + void create_table:: + traverse (sema_rel::table& t) + { + if (pass_ == 1) + { + tables_.insert (t.name ()); // Add it before to cover self-refs. + base::traverse (t); + return; + } + + // Add foreign keys. + // + instance<add_foreign_key> fk (format_, *this); + trav_rel::names n (*fk); + names (t, n); + } + } + } +} |