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