From a141e3ca1ec78989de58e4498aaaca0da966bd03 Mon Sep 17 00:00:00 2001 From: Constantin Michael Date: Fri, 8 Jul 2011 13:53:58 +0200 Subject: Add foreign keys to PostgreSQL schema generation --- odb/relational/pgsql/schema.cxx | 129 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/odb/relational/pgsql/schema.cxx b/odb/relational/pgsql/schema.cxx index de4d507..68c0e4c 100644 --- a/odb/relational/pgsql/schema.cxx +++ b/odb/relational/pgsql/schema.cxx @@ -75,8 +75,137 @@ namespace relational base::type (m); } } + + virtual void + reference (semantics::data_member&) + { + } }; entry object_columns_; + + struct object_columns_references: + object_columns_base, relational::common, context + { + object_columns_references (emitter& e, + ostream& os, + string const& table, + string const& prefix = string ()) + : relational::common (e, os), + table_ (table), + prefix_ (prefix) + { + } + + virtual bool + column (semantics::data_member& m, string const& name, bool) + { + semantics::class_* c (object_pointer (member_type (m, prefix_))); + + if (c != 0 && !inverse (m)) + { + pre_statement (); + + os << "ALTER TABLE " << quote_id (table_) << endl + << " ADD FOREIGN KEY (" << quote_id (name) << ")" << + endl + << " REFERENCES " << quote_id (table_name (*c)) << endl + << " INITIALLY DEFERRED" << endl; + + post_statement (); + } + + return true; + } + + private: + string table_; + string prefix_; + }; + + struct member_create: object_members_base, context + { + member_create (emitter& e, ostream& os, relational::tables& tables) + : object_members_base (false, true), + e_ (e), + os_ (os), + tables_ (tables) + { + } + + virtual void + container (semantics::data_member& m) + { + using semantics::type; + using semantics::data_member; + + // Ignore inverse containers of object pointers. + // + if (inverse (m, "value")) + return; + + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + type& t (m.type ()); + type& vt (container_vt (t)); + + if (semantics::class_* cvt = comp_value (vt)) + { + object_columns_references ocr (e_, os_, name); + ocr.traverse_composite (m, *cvt, "value", "value"); + } + else + { + object_columns_references ocr (e_, os_, name, "value"); + string const& name (column_name (m, "value", "value")); + ocr.column (m, name, true); + } + + tables_.insert (name); + } + + private: + emitter& e_; + ostream& os_; + relational::tables& tables_; + }; + + struct class_create: relational::class_create + { + class_create (base const& x): base (x) {} + + virtual void + traverse (type& c) + { + if (pass_ != 2) + { + base::traverse (c); + return; + } + + if (c.file () != unit.file ()) + return; + + if (!c.count ("object") || abstract (c)) + return; + + string const& name (table_name (c)); + + if (tables_[pass_].count (name)) + return; + + object_columns_references ocr (e_, os_, name); + ocr.traverse (c); + + tables_[pass_].insert (name); + + member_create mc (e_, os_, tables_[pass_]); + mc.traverse (c); + } + }; + entry class_create_; } } } -- cgit v1.1