summaryrefslogtreecommitdiff
path: root/odb/relational/mssql/schema.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/relational/mssql/schema.cxx')
-rw-r--r--odb/relational/mssql/schema.cxx224
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);
+ }
+ }
+ }
+}