aboutsummaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-01-22 14:37:10 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-01-22 14:37:10 +0200
commit36863f5f31c202e45c8a406a321deb8d237cbc14 (patch)
tree73ddb6aa8d7d5c5ae3a4d0b47a7e9415b6787359 /odb
parent823ec53170fa7092bb0b88db13a3c5e64bf14159 (diff)
Add support for warning about SQL name truncations in Oracle
Also detect and issue diagnostics when such truncations lead to name conflicts.
Diffstat (limited to 'odb')
-rw-r--r--odb/context.cxx2
-rw-r--r--odb/context.hxx7
-rw-r--r--odb/options.cli9
-rw-r--r--odb/relational/model.cxx9
-rw-r--r--odb/relational/model.hxx4
-rw-r--r--odb/relational/oracle/schema.cxx173
6 files changed, 192 insertions, 12 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index dfd75f6..4af13b7 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -617,6 +617,7 @@ context (ostream& os_,
features_type& f,
data_ptr d)
: data_ (d ? d : data_ptr (new (shared) data (os_))),
+ extra (data_->extra_),
os (data_->os_),
unit (u),
options (ops),
@@ -727,6 +728,7 @@ context (ostream& os_,
context::
context ()
: data_ (current ().data_),
+ extra (current ().extra),
os (current ().os),
unit (current ().unit),
options (current ().options),
diff --git a/odb/context.hxx b/odb/context.hxx
index 0af3b3c..805691f 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -1512,7 +1512,8 @@ protected:
~data () {}
data (std::ostream& os)
- : os_ (os.rdbuf ()),
+ : extra_ (0),
+ os_ (os.rdbuf ()),
in_comment_ (false),
top_object_ (0),
cur_object_ (0),
@@ -1522,6 +1523,8 @@ protected:
}
public:
+ void* extra_;
+
std::ostream os_;
std::stack<std::streambuf*> os_stack_;
@@ -1551,6 +1554,8 @@ protected:
public:
typedef ::features features_type;
+ void*& extra; // Extra data that may need to be shared by a sub-system.
+
std::ostream& os;
semantics::unit& unit;
options_type const& options;
diff --git a/odb/options.cli b/odb/options.cli
index 6d67ca7..350bbfc 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -1027,6 +1027,15 @@ class options
\cb{10.1} or later is assumed."
};
+ bool --oracle-warn-truncation
+ {
+ "Warn about SQL names that are longer than 30 characters and are
+ therefore truncated. Note that during database schema generation
+ (\cb{--generate-schema}) ODB detects when such truncations lead
+ to name conflicts and issues diagnostics even without this option
+ specified."
+ };
+
//
// SQL Server-specific options.
//
diff --git a/odb/relational/model.cxx b/odb/relational/model.cxx
index 6a65803..d7c2bd8 100644
--- a/odb/relational/model.cxx
+++ b/odb/relational/model.cxx
@@ -107,14 +107,11 @@ namespace relational
<< endl;
if (e.dup.kind () == "index")
- error (d) << "use #pragma db index to change one of the names"
- << endl;
+ info (d) << "use #pragma db index to change its name" << endl;
else if (e.dup.kind () == "table")
- error (d) << "use #pragma db table to change one of the names"
- << endl;
+ info (d) << "use #pragma db table to change its name" << endl;
else
- error (d) << "use #pragma db column to change its name"
- << endl;
+ info (d) << "use #pragma db column to change its name" << endl;
throw operation_failed ();
}
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index bb83e02..9b53104 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -618,7 +618,7 @@ namespace relational
{
in = &model_.new_node<sema_rel::index> (
id + ".id", sin->type, sin->method, sin->options);
- in->set ("cxx-location", sin->loc);
+ in->set ("cxx-location", location (sin->loc));
}
else
{
@@ -675,7 +675,7 @@ namespace relational
{
in = &model_.new_node<sema_rel::index> (
id + ".index", sin->type, sin->method, sin->options);
- in->set ("cxx-location", sin->loc);
+ in->set ("cxx-location", location (sin->loc));
}
else
{
diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx
index 829a37a..a775529 100644
--- a/odb/relational/oracle/schema.cxx
+++ b/odb/relational/oracle/schema.cxx
@@ -2,6 +2,11 @@
// copyright : Copyright (c) 2009-2013 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>
@@ -228,12 +233,121 @@ namespace relational
//
// 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_)
@@ -272,8 +386,24 @@ namespace relational
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);
@@ -293,6 +423,12 @@ namespace relational
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);
}
};
@@ -305,6 +441,17 @@ namespace relational
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)
@@ -320,11 +467,16 @@ namespace relational
if (pk != 0 && pk->auto_ ())
{
- string qs (
- quote_id (qname::from_string (pk->extra ()["sequence"])));
+ // 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 " << qs << endl
+ os_ << "CREATE SEQUENCE " << quote_id (n) << endl
<< " START WITH 1 INCREMENT BY 1" << endl;
post_statement ();
}
@@ -333,6 +485,21 @@ namespace relational
};
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.
//