diff options
Diffstat (limited to 'odb/relational/oracle/schema.cxx')
-rw-r--r-- | odb/relational/oracle/schema.cxx | 697 |
1 files changed, 0 insertions, 697 deletions
diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx deleted file mode 100644 index 4c0d483..0000000 --- a/odb/relational/oracle/schema.cxx +++ /dev/null @@ -1,697 +0,0 @@ -// file : odb/relational/oracle/schema.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC -// license : GNU GPL v3; see accompanying LICENSE file - -#include <map> -#include <utility> // pair - -#include <odb/diagnostics.hxx> - -#include <odb/relational/schema.hxx> - -#include <odb/relational/oracle/common.hxx> -#include <odb/relational/oracle/context.hxx> - -using namespace std; - -namespace relational -{ - namespace oracle - { - namespace schema - { - namespace relational = relational::schema; - using relational::table_set; - - struct sql_emitter: relational::sql_emitter - { - sql_emitter (const base& x): base (x) {} - - virtual void - line (const std::string& l) - { - // SQLPlus doesn't like empty line in the middle of a statement. - // - if (!l.empty ()) - { - base::line (l); - last_ = l; - } - } - - virtual void - post () - { - if (!first_) // Ignore empty statements. - { - if (last_ == "END;") - os << endl - << '/' << endl - << endl; - - else - os << ';' << endl - << endl; - } - } - - private: - string last_; - }; - entry<sql_emitter> sql_emitter_; - - // - // File. - // - - struct sql_file: relational::sql_file, context - { - sql_file (const base& x): base (x) {} - - virtual void - prologue () - { - // Quiet down SQLPlus and make sure it exits with an error - // code if there is an error. - // - os << "SET FEEDBACK OFF;" << endl - << "WHENEVER SQLERROR EXIT FAILURE;" << endl - << "WHENEVER OSERROR EXIT FAILURE;" << endl - << endl; - } - - virtual void - epilogue () - { - os << "EXIT;" << endl; - } - }; - entry<sql_file> sql_file_; - - // - // 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_foreign_key: relational::drop_foreign_key, context - { - drop_foreign_key (base const& x): base (x) {} - - virtual void - traverse (sema_rel::drop_foreign_key& dfk) - { - os << endl; - drop (dfk); - } - }; - entry<drop_foreign_key> drop_foreign_key_; - - struct drop_index: relational::drop_index, context - { - drop_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In Oracle, index names can be qualified with the schema. - // - sema_rel::table& t (static_cast<sema_rel::table&> (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - return quote_id (n); - } - }; - entry<drop_index> drop_index_; - - struct drop_table: relational::drop_table, context - { - drop_table (base const& x): base (x) {} - - virtual void - drop (sema_rel::table& t, bool migration) - { - using sema_rel::primary_key; - - sema_rel::table::names_iterator i (t.find ("")); // Special name. - primary_key* pk (i != t.names_end () - ? &dynamic_cast<primary_key&> (i->nameable ()) - : 0); - - string qt (quote_id (t.name ())); - string qs (pk != 0 && pk->auto_ () - ? quote_id (qname::from_string (pk->extra ()["sequence"])) - : ""); - - if (migration) - { - pre_statement (); - os << "DROP TABLE " << qt << endl; - post_statement (); - - // Drop the sequence if we have auto primary key. - // - if (!qs.empty ()) - { - pre_statement (); - os << "DROP SEQUENCE " << qs << endl; - post_statement (); - } - } - else - { - // Oracle has no IF EXISTS conditional for dropping objects. The - // PL/SQL approach below seems to be the least error-prone and the - // most widely used of the alternatives. - // - pre_statement (); - os << "BEGIN" << endl - << " BEGIN" << endl - << " EXECUTE IMMEDIATE 'DROP TABLE " << qt << " CASCADE " << - "CONSTRAINTS';" << endl - << " EXCEPTION" << endl - << " WHEN OTHERS THEN" << endl - << " IF SQLCODE != -942 THEN RAISE; END IF;" << endl - << " END;" << endl; - - // Drop the sequence if we have auto primary key. - // - if (!qs.empty ()) - { - os << " BEGIN" << endl - << " EXECUTE IMMEDIATE 'DROP SEQUENCE " << qs << - "';" << endl - << " EXCEPTION" << endl - << " WHEN OTHERS THEN" << endl - << " IF SQLCODE != -2289 THEN RAISE; END IF;" << endl - << " END;" << endl; - } - - os << "END;" << endl; - post_statement (); - } - } - - virtual void - traverse (sema_rel::table& t, bool migration) - { - // For migration drop foreign keys explicitly in pre-migration. - // - if (migration) - { - base::traverse (t, migration); - return; - } - - // For schema creation we use the CASCADE clause to drop foreign - // keys. - // - if (pass_ != 2) - return; - - drop (t, migration); - } - }; - entry<drop_table> drop_table_; - - // - // Create. - // - static sema_rel::uname - truncate (location const& l, const char* kind, sema_rel::uname n, bool w) - { - if (n.size () > 30) - { - if (w) - warn (l) << kind << " name '" << n << "' is longer than 30 " - << "characters and will be truncated" << endl; - - n.resize (30); - } - - return n; - } - - static sema_rel::qname - truncate (location const& l, - const char* kind, - sema_rel::qname const& n, - bool w) - { - // Don't bother verifying the schema name since that is - // specified explicitly and in a single place. - // - qname r (n.qualifier ()); - r.append (truncate (l, kind, n.uname (), w)); - return r; - } - - template <typename N> - struct scope - { - typedef std::map<N, pair<N, location> > map; - - scope (const char* k, const char* p, bool w) - : kind_ (k), prag_ (p), warn_ (w) {} - - void - check (location const& l, N const& n) - { - N tn (truncate (l, kind_, n, warn_)); - - pair<typename map::iterator, bool> r ( - map_.insert (make_pair (tn, make_pair (n, l)))); - - if (r.second) - return; - - error (l) << kind_ << " name '" << tn << "' conflicts with an " - << "already defined " << kind_ << " name" << endl; - - if (tn != n) - info (l) << kind_ << " name '" << tn << "' is truncated '" - << n << "'" << endl; - - N const& n1 (r.first->second.first); - location const& l1 (r.first->second.second); - - info (l1) << "conflicting " << kind_ << " is defined here" << endl; - - if (tn != n) - info (l1) << "conflicting " << kind_ << " name '" << tn - << "' is truncated '" << n1 << "'" << endl; - - info (l) << "use #pragma db " << prag_ << " to change one of " - << "the names" << endl; - - throw operation_failed (); - } - - void - clear () {map_.clear ();} - - const char* kind_; - const char* prag_; - bool warn_; - map map_; - }; - - struct scopes - { - scopes (bool warn) - : tables ("table", "table", warn), - fkeys ("foreign key", "column", warn), // Change column name. - indexes ("index", "index", warn), - sequences ("sequence", "table", warn), // Change table name. - columns ("column", "column", warn) {} - - // In Oracle, all these entities are in their own name spaces, - // as in an index and a foreign key with the same name do not - // conflict. - // - scope<sema_rel::qname> tables; - scope<sema_rel::uname> fkeys; // Global but can't have schema. - scope<sema_rel::qname> indexes; - scope<sema_rel::qname> sequences; - scope<sema_rel::uname> columns; - }; - - struct create_column: relational::create_column, context - { - create_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::column& c) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast<scopes*> (context::extra)) - s->columns.check (c.get<location> ("cxx-location"), c.name ()); - - base::traverse (c); - } - - virtual void - traverse (sema_rel::add_column& ac) - { - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - create (ac); - } - - virtual void - constraints (sema_rel::column& c, sema_rel::primary_key* pk) - { - // Oracle wants DEFAULT before NULL even though we can end - // up with mouthfulls like DEFAULT NULL NULL. - // - if (!c.default_ ().empty ()) - os << " DEFAULT " << c.default_ (); - - null (c); - - // If this is a single-column primary key, generate it inline. - // - if (pk != 0 && pk->contains_size () == 1) - primary_key (); - - if (pk != 0 && pk->auto_ ()) - auto_ (*pk); - } - }; - entry<create_column> create_column_; - - struct create_foreign_key: relational::create_foreign_key, context - { - create_foreign_key (base const& x): base (x) {} - - virtual void - traverse_create (sema_rel::foreign_key& fk) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast<scopes*> (context::extra)) - s->fkeys.check (fk.get<location> ("cxx-location"), fk.name ()); - - base::traverse_create (fk); - } - - virtual void - traverse_add (sema_rel::foreign_key& fk) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast<scopes*> (context::extra)) - s->fkeys.check (fk.get<location> ("cxx-location"), fk.name ()); - - os << endl - << " ADD CONSTRAINT "; - create (fk); - } - }; - entry<create_foreign_key> create_foreign_key_; - - struct create_index: relational::create_index, context - { - create_index (base const& x): base (x) {} - - virtual string - name (sema_rel::index& in) - { - // In Oracle, index names can be qualified with the schema. - // - sema_rel::table& t (static_cast<sema_rel::table&> (in.scope ())); - sema_rel::qname n (t.name ().qualifier ()); - n.append (in.name ()); - - // Check name trunction and conflicts. - // - if (scopes* s = static_cast<scopes*> (context::extra)) - s->indexes.check (in.get<location> ("cxx-location"), n); - - return quote_id (n); - } - }; - entry<create_index> create_index_; - - struct create_table: relational::create_table, context - { - create_table (base const& x): base (x) {} - - void - traverse (sema_rel::table& t) - { - // Check name trunction and conflicts. - // - if (scopes* s = static_cast<scopes*> (context::extra)) - { - if (pass_ == 1) - { - s->tables.check (t.get<location> ("cxx-location"), t.name ()); - s->columns.clear (); - } - } - - base::traverse (t); - - if (pass_ == 1) - { - // Create the sequence if we have auto primary key. - // - using sema_rel::primary_key; - - sema_rel::table::names_iterator i (t.find ("")); // Special name. - primary_key* pk (i != t.names_end () - ? &dynamic_cast<primary_key&> (i->nameable ()) - : 0); - - if (pk != 0 && pk->auto_ ()) - { - // Already qualified with the table's schema, if any. - // - sema_rel::qname n ( - qname::from_string (pk->extra ()["sequence"])); - - if (scopes* s = static_cast<scopes*> (context::extra)) - s->sequences.check (pk->get<location> ("cxx-location"), n); - - pre_statement (); - os_ << "CREATE SEQUENCE " << quote_id (n) << endl - << " START WITH 1 INCREMENT BY 1" << endl; - post_statement (); - } - } - } - }; - entry<create_table> create_table_; - - struct create_model: relational::create_model, context - { - create_model (base const& x): base (x) {} - - void - traverse (sema_rel::model& m) - { - scopes s (options.oracle_warn_truncation ()); - context::extra = &s; - base::traverse (m); - context::extra = 0; - } - }; - entry<create_model> create_model_; - - // - // Alter. - // - - struct alter_column: relational::alter_column, context - { - alter_column (base const& x): base (x) {} - - virtual void - traverse (sema_rel::column& c) - { - // Relax (NULL) in pre and tighten (NOT NULL) in post. - // - if (pre_ != c.null ()) - return; - - if (first_) - first_ = false; - else - os << "," << endl - << " "; - - os << quote_id (c.name ()) << (c.null () ? " NULL" : " NOT NULL"); - } - }; - entry<alter_column> alter_column_; - - 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::drop_foreign_key> (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()); - - instance<drop_foreign_key> dfc (*this); - trav_rel::unames n (*dfc); - names (at, n); - os << endl; - - post_statement (); - } - - if (check<sema_rel::add_column> (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " ADD ("; - - instance<create_column> cc (*this); - trav_rel::unames n (*cc); - names (at, n); - os << ")" << endl; - - post_statement (); - } - - if (check_alter_column_null (at, true)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " MODIFY ("; - - bool tl (true); // (Im)perfect forwarding. - instance<alter_column> ac (*this, tl); - trav_rel::unames n (*ac); - 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 (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " DROP ("; - - instance<drop_column> dc (*this); - trav_rel::unames n (*dc); - names (at, n); - os << ")" << endl; - - post_statement (); - } - - if (check_alter_column_null (at, false)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()) << endl - << " MODIFY ("; - - bool fl (false); // (Im)perfect forwarding. - instance<alter_column> ac (*this, fl); - trav_rel::unames n (*ac); - names (at, n); - os << ")" << endl; - - post_statement (); - } - - if (check<sema_rel::add_foreign_key> (at)) - { - pre_statement (); - - os << "ALTER TABLE " << quote_id (at.name ()); - - instance<create_foreign_key> cfc (*this); - trav_rel::unames n (*cfc); - names (at, n); - os << endl; - - post_statement (); - } - } - }; - entry<alter_table_post> alter_table_post_; - - // - // Schema version table. - // - - struct version_table: relational::version_table, context - { - version_table (base const& x) - : base (x) - { - // If the schema name is empty, replace it with a single space - // to workaround the VARCHAR2 empty/NULL issue. - // - if (qs_ == "''") - qs_ = "' '"; - } - - virtual void - create_table () - { - pre_statement (); - - os << "BEGIN" << endl - << " EXECUTE IMMEDIATE 'CREATE TABLE " << qt_ << " (" << endl - << " " << qn_ << " VARCHAR2(512) NOT NULL PRIMARY KEY," << endl - << " " << qv_ << " NUMBER(20) NOT NULL," << endl - << " " << qm_ << " NUMBER(1) NOT NULL)';" << endl - << "EXCEPTION" << endl - << " WHEN OTHERS THEN" << endl - << " IF SQLCODE != -955 THEN RAISE; END IF;" << endl - << "END;" << endl; - - post_statement (); - } - - virtual void - create (sema_rel::version v) - { - pre_statement (); - - os << "MERGE INTO " << qt_ << " USING DUAL ON (" << qn_ << " = " << - qs_ << ")" << endl - << " WHEN NOT MATCHED THEN INSERT (" << endl - << " " << qn_ << ", " << qv_ << ", " << qm_ << ")" << endl - << " VALUES (" << qs_ << ", " << v << ", 0)" << endl; - - post_statement (); - } - }; - entry<version_table> version_table_; - } - } -} |