aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--doc/odb-epilogue.1105
-rw-r--r--doc/odb-epilogue.xhtml71
-rw-r--r--odb/common-query.cxx8
-rw-r--r--odb/common.cxx129
-rw-r--r--odb/common.hxx42
-rw-r--r--odb/context.cxx381
-rw-r--r--odb/context.hxx100
-rw-r--r--odb/option-types.cxx23
-rw-r--r--odb/option-types.hxx20
-rw-r--r--odb/options.cli112
-rw-r--r--odb/relational/common-query.cxx11
-rw-r--r--odb/relational/context.cxx42
-rw-r--r--odb/relational/context.hxx19
-rw-r--r--odb/relational/model.hxx54
-rw-r--r--odb/relational/mssql/context.cxx2
-rw-r--r--odb/relational/mssql/schema.cxx23
-rw-r--r--odb/relational/mssql/source.cxx10
-rw-r--r--odb/relational/mysql/context.cxx2
-rw-r--r--odb/relational/mysql/schema.cxx12
-rw-r--r--odb/relational/oracle/context.cxx19
-rw-r--r--odb/relational/oracle/context.hxx6
-rw-r--r--odb/relational/oracle/schema.cxx28
-rw-r--r--odb/relational/oracle/source.cxx11
-rw-r--r--odb/relational/pgsql/context.cxx2
-rw-r--r--odb/relational/pgsql/schema.cxx12
-rw-r--r--odb/relational/pgsql/source.cxx5
-rw-r--r--odb/relational/processor.cxx15
-rw-r--r--odb/relational/source.cxx21
-rw-r--r--odb/relational/source.hxx53
-rw-r--r--odb/relational/sqlite/context.cxx2
-rw-r--r--odb/relational/sqlite/schema.cxx11
32 files changed, 975 insertions, 385 deletions
diff --git a/NEWS b/NEWS
index e4fd9f3..b07df8b 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,15 @@ Version 2.2.0
refer to Section 4.5, "Prepared Queries" in the ODB manual as well as the
'prepared' example in the odb-examples package.
+ * Support for automatically-derived SQL name (table, column, index, etc.)
+ transformations. At the higher level, it is possible to assign prefixes
+ and suffixes (--table-prefix, --{index,fkey,sequence}--suffix options)
+ as well as to convert to upper or lower case (--sql-name-case option).
+ At the lower level, it is possible to specify transformations as regular
+ expressions (--{table,column,index,fkey,sequence,sql-name}-regex options).
+ For more information, refer to the SQL NAME TRANSFORMATIONS section in
+ the ODB compiler command line interface documentation (man pages).
+
* New options, --export-symbol and --extern-symbol, allow DLL exporting of
the generated database support code.
diff --git a/doc/odb-epilogue.1 b/doc/odb-epilogue.1
index 6bdc5c4..8755374 100644
--- a/doc/odb-epilogue.1
+++ b/doc/odb-epilogue.1
@@ -1,4 +1,109 @@
.\"
+.\" SQL NAME TRANSFORMATIONS
+.\"
+.SH SQL NAME TRANSFORMATIONS
+The ODB compiler provides a number of mechanisms for transforming
+automatically-derived SQL names, such as tables, columns, etc.,
+to match a specific naming convention. At the higher level, we can
+add a prefix to global names (tables and, for some databases,
+indexes and/or foreign keys) with the
+.B --table-prefix
+option. Similarly, we can specify custom suffixes for automatically-derived
+index
+.RB ( --index-suffix ;
+default is
+.BR _i ),
+foreign key
+.RB ( --fkey-suffix ;
+default is
+.BR _fk ),
+and sequence
+.RB ( --sequence-suffix ;
+default is
+.BR _seq )
+names. Finally, we can also convert all the names to upper or lower
+case with the
+.B --sql-name-case
+option (valid values are
+.B upper
+and
+.BR lower ).
+
+At the lower level we can specify a set of regular expressions to
+implement arbitrary transformations of the automatically-derived SQL
+names. If we want a particular regular expression only to apply to
+a specific name, for example, table or column, then we use one of the
+.B --\fIkind\fB-regex
+options, where
+.I kind
+can be
+.BR table ,
+.BR column ,
+.BR index ,
+.BR fkey ,
+or
+.BR sequence .
+On the other hand, if we want our regular expressions to apply to all SQL
+names, then we use the
+.B --sql-name-regex
+option.
+
+The interaction between the higher and lower level transformations
+is as follows. Prefixes and suffixes are added first. Then the
+regular expression transformations are applied. Finally, if requested,
+the name is converted to upper or lower case. Note also that all of
+these transformations except for
+.B --table-prefix
+only apply to automatically-derived names. In other words, if a table,
+column, etc., name was explicitly specified with a pragma, then it
+is used as is, without applying any (except for the table prefix)
+transformations.
+
+The value for the
+.B --*-regex
+options is a Perl-like regular expression in the form
+.BI / pattern / replacement /\fR.
+Any character can be used as a delimiter instead of
+.B /
+and the delimiter can be escaped inside
+.I pattern
+and
+.I replacement
+with a backslash
+.RB ( \e ).
+You can also specify multiple regular expressions by repeating these
+options.
+
+All the regular expressions are tried in the order specified with the
+name-specific expressions (for example,
+.BR --table-regex)
+tried first followed by the generic expressions
+.RB ( --sql-name-regex ).
+The first expression that matches is used.
+
+As an example, consider a regular expression that transforms a class
+name in the form
+.B CFoo
+to a table name in the form
+.BR FOO:
+
+.B --table-regex '/C(.+)/\eU$1/'
+
+As a more interesting example, consider the transformation of class
+names that follow the upper camel case convention (for example,
+.BR FooBar )
+to table names that follow the underscore-separated, all upper case
+convention (for example,
+.BR FOO_BAR ).
+For this case we have to use separate expressions to handle one-word,
+two-word, etc., names:
+
+.B --table-regex '/([A-z][a-z]+)/\eU$1/'
+
+.B --table-regex '/([A-z][a-z]+)([A-z][a-z]+)/\eU$1_$2/'
+
+See also the REGEX AND SHELL QUOTING section below.
+.\"
.\" REGEX AND SHELL QUOTING
.\"
.SH REGEX AND SHELL QUOTING
diff --git a/doc/odb-epilogue.xhtml b/doc/odb-epilogue.xhtml
index 8dd45e7..0309fc6 100644
--- a/doc/odb-epilogue.xhtml
+++ b/doc/odb-epilogue.xhtml
@@ -1,3 +1,74 @@
+ <h1>SQL NAME TRANSFORMATIONS</h1>
+
+ <p>The ODB compiler provides a number of mechanisms for transforming
+ automatically-derived SQL names, such as tables, columns, etc.,
+ to match a specific naming convention. At the higher level, we can
+ add a prefix to global names (tables and, for some databases,
+ indexes and/or foreign keys) with the <code><b>--table-prefix</b></code>
+ option. Similarly, we can specify custom suffixes for
+ automatically-derived
+ index (<code><b>--index-suffix</b></code>; default is <code><b>_i</b></code>),
+ foreign key (<code><b>--fkey-suffix</b></code>; default is <code><b>_fk</b></code>), and
+ sequence (<code><b>--sequence-suffix</b></code>; default is <code><b>_seq</b></code>)
+ names. Finally, we can also convert all the names to upper or lower
+ case with the <code><b>--sql-name-case</b></code> option (valid values
+ are <code><b>upper</b></code> and <code><b>lower</b></code>).</p>
+
+ <p>At the lower level we can specify a set of regular expressions to
+ implement arbitrary transformations of the automatically-derived SQL
+ names. If we want a particular regular expression only to apply to
+ a specific name, for example, table or column, then we use one of the
+ <code><b>--</b><i>kind</i><b>-regex</b></code> options, where
+ <code><i>kind</i></code> can be <code><b>table</b></code>,
+ <code><b>column</b></code>, <code><b>index</b></code>,
+ <code><b>fkey</b></code>, or <code><b>sequence</b></code>. On the
+ other hand, if we want our regular expressions to apply to all SQL
+ names, then we use the <code><b>--sql-name-regex</b></code> option.</p>
+
+ <p>The interaction between the higher and lower level transformations
+ is as follows. Prefixes and suffixes are added first. Then the
+ regular expression transformations are applied. Finally, if requested,
+ the name is converted to upper or lower case. Note also that all of
+ these transformations except for <code><b>--table-prefix</b></code>
+ only apply to automatically-derived names. In other words, if a table,
+ column, etc., name was explicitly specified with a pragma, then it
+ is used as is, without applying any (except for the table prefix)
+ transformations.</p>
+
+ <p>The value for the <code><b>--*-regex</b></code> options is a Perl-like
+ regular expression in the form
+ <code><b>/</b><i>pattern</i><b>/</b><i>replacement</i><b>/</b></code>.
+ Any character can be used as a delimiter instead of <code><b>/</b></code>
+ and the delimiter can be escaped inside <code><i>pattern</i></code> and
+ <code><i>replacement</i></code> with a backslash (<code><b>\</b></code>).
+ You can also specify multiple regular expressions by repeating these
+ options.</p>
+
+ <p>All the regular expressions are tried in the order specified with the
+ name-specific expressions (for example, <code><b>--table-regex</b></code>)
+ tried first followed by the generic expressions
+ (<code><b>--sql-name-regex</b></code>). The first expression that
+ matches is used.</p>
+
+ <p>As an example, consider a regular expression that transforms a class
+ name in the form <code><b>CFoo</b></code> to a table name in the
+ form <code><b>FOO</b></code>:</p>
+
+ <p><code><b>--table-regex '/C(.+)/\U$1/'</b></code></p>
+
+ <p>As a more interesting example, consider the transformation of class
+ names that follow the upper camel case convention (for example,
+ <code><b>FooBar</b></code>) to table names that follow the
+ underscore-separated, all upper case convention (for example,
+ <code><b>FOO_BAR</b></code>). For this case we have to use
+ separate expressions to handle one-word, two-word, etc.,
+ names:</p>
+
+ <p><code><b>--table-regex '/([A-z][a-z]+)/\U$1/'</b></code></p>
+ <p><code><b>--table-regex '/([A-z][a-z]+)([A-z][a-z]+)/\U$1_$2/'</b></code></p>
+
+ <p>See also the REGEX AND SHELL QUOTING section below.</p>
+
<h1>REGEX AND SHELL QUOTING</h1>
<p>When entering a regular expression argument in the shell
diff --git a/odb/common-query.cxx b/odb/common-query.cxx
index 67a2674..f7c4714 100644
--- a/odb/common-query.cxx
+++ b/odb/common-query.cxx
@@ -577,14 +577,12 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
// Simple id.
//
string type (t.fq_name (hint));
- string column (
- compose_name (
- column_prefix_, column_name (m, key_prefix_, default_name_)));
+ string col (column_name (m, key_prefix_, default_name_, column_prefix_));
// For pointer_query_columns generate normal column mapping.
//
if (ptr_)
- column_common (m, type, column);
+ column_common (m, type, col);
else
{
// If this is a non-inverse relationship, then make the column have
@@ -593,7 +591,7 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
// test in a natural way. For inverse relationships there is no
// column and so the column interface is not available.
//
- column_common (m, type, column, "_column_type_");
+ column_common (m, type, col, "_column_type_");
if (decl_)
{
diff --git a/odb/common.cxx b/odb/common.cxx
index 34d8372..9689d83 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -114,11 +114,7 @@ traverse (semantics::class_& c)
if (table_prefix_.level == 0)
{
- table_prefix_.ns_schema = schema (c.scope ());
- table_prefix_.ns_prefix = table_name_prefix (c.scope ());
- table_prefix_.prefix = table_name (c);
- table_prefix_.prefix += "_";
- table_prefix_.level = 1;
+ table_prefix_ = table_prefix (c);
tb = true;
}
@@ -128,12 +124,7 @@ traverse (semantics::class_& c)
traverse_view (c);
if (tb)
- {
- table_prefix_.level = 0;
- table_prefix_.prefix.clear ();
- table_prefix_.ns_prefix.clear ();
- table_prefix_.ns_schema.clear ();
- }
+ table_prefix_ = table_prefix ();
}
else
{
@@ -162,7 +153,7 @@ traverse_member (semantics::data_member& m, semantics::type& t)
member_scope_.push_back (class_inheritance_chain ());
member_scope_.back ().push_back (comp);
- qname old_table_prefix;
+ table_prefix old_table_prefix;
string old_flat_prefix, old_member_prefix;
if (build_flat_prefix_)
@@ -181,17 +172,14 @@ traverse_member (semantics::data_member& m, semantics::type& t)
if (build_table_prefix_)
{
- old_table_prefix = table_prefix_.prefix;
- append (m, table_prefix_);
+ old_table_prefix = table_prefix_;
+ table_prefix_.append (m);
}
traverse_composite_wrapper (&m, *comp, (wrapper (t) ? &t : 0));
if (build_table_prefix_)
- {
- table_prefix_.level--;
- table_prefix_.prefix = old_table_prefix;
- }
+ table_prefix_ = old_table_prefix;
if (build_flat_prefix_)
flat_prefix_ = old_flat_prefix;
@@ -225,57 +213,6 @@ traverse (semantics::data_member& m)
om_.member_path_.pop_back ();
}
-void object_members_base::
-append (semantics::data_member& m, table_prefix& tp)
-{
- context& ctx (context::current ());
-
- assert (tp.level > 0);
-
- // If a custom table prefix was specified, then ignore the top-level
- // table prefix (this corresponds to a container directly inside an
- // object) but keep the schema unless the alternative schema is fully
- // qualified.
- //
- if (m.count ("table"))
- {
- qname p, n (m.get<qname> ("table"));
-
- if (n.fully_qualified ())
- p = n.qualifier ();
- else
- {
- if (n.qualified ())
- {
- p = tp.ns_schema;
- p.append (n.qualifier ());
- }
- else
- p = tp.prefix.qualifier ();
- }
-
- p.append (tp.level == 1 ? tp.ns_prefix : tp.prefix.uname ());
- p += n.uname ();
-
- tp.prefix.swap (p);
- }
- // Otherwise use the member name and add an underscore unless it is
- // already there.
- //
- else
- {
- string name (ctx.public_name_db (m));
- size_t n (name.size ());
-
- tp.prefix += name;
-
- if (n != 0 && name[n - 1] != '_')
- tp.prefix += "_";
- }
-
- tp.level++;
-}
-
//
// object_columns_base
//
@@ -419,52 +356,6 @@ traverse (semantics::class_& c)
flush ();
}
-string object_columns_base::
-column_prefix (semantics::data_member& m, string const& kp, string const& dn)
-{
- bool custom;
- string r;
-
- if (kp.empty ())
- {
- custom = m.count ("column");
- r = context::current ().column_name (m);
- }
- else
- {
- custom = m.count (kp + "-column");
- r = context::current ().column_name (m, kp, dn);
- }
-
- // If the user provided the column prefix, then use it verbatime.
- // Otherwise, append the underscore, unless it is already there.
- //
- if (!custom)
- {
- size_t n (r.size ());
-
- if (n != 0 && r[n - 1] != '_')
- r += '_';
- }
-
- return r;
-}
-
-string object_columns_base::
-column_prefix (data_member_path const& mp)
-{
- if (mp.size () < 2)
- return "";
-
- string r;
-
- for (data_member_path::const_iterator i (mp.begin ()), e (mp.end () - 1);
- i != e; ++i)
- r += column_prefix (**i);
-
- return r;
-}
-
void object_columns_base::
traverse_member (semantics::data_member& m, semantics::type& t)
{
@@ -473,8 +364,8 @@ traverse_member (semantics::data_member& m, semantics::type& t)
member_scope_.push_back (class_inheritance_chain ());
member_scope_.back ().push_back (comp);
- string old_prefix (column_prefix_);
- column_prefix_ += column_prefix (m, key_prefix_, default_name_);
+ column_prefix old_prefix (column_prefix_);
+ column_prefix_.append (m, key_prefix_, default_name_);
// Save and clear the key prefix and default name.
//
@@ -492,9 +383,7 @@ traverse_member (semantics::data_member& m, semantics::type& t)
}
else
{
- string name (
- compose_name (
- column_prefix_, column_name (m, key_prefix_, default_name_)));
+ string name (column_name (m, key_prefix_, default_name_, column_prefix_));
if (traverse_column (m, name, first_))
{
diff --git a/odb/common.hxx b/odb/common.hxx
index 7ce59a5..80f91c4 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -100,12 +100,6 @@ public:
virtual void
traverse (semantics::class_&);
-public:
- // Append composite member prefix.
- //
- static void
- append (semantics::data_member&, table_prefix&);
-
protected:
string flat_prefix_;
table_prefix table_prefix_;
@@ -219,10 +213,19 @@ struct object_columns_base: traversal::class_, virtual context
public:
object_columns_base (bool first = true,
- string const& column_prefix = string (),
- bool traverse_poly_base = false)
- : column_prefix_ (column_prefix),
+ column_prefix const& cp = column_prefix ())
+ : column_prefix_ (cp),
root_ (0),
+ traverse_poly_base_ (false),
+ first_ (first),
+ top_level_ (true),
+ member_ (*this)
+ {
+ init ();
+ }
+
+ object_columns_base (bool first, bool traverse_poly_base)
+ : root_ (0),
traverse_poly_base_ (traverse_poly_base),
first_ (first),
top_level_ (true),
@@ -262,25 +265,11 @@ public:
string const& default_name,
semantics::class_* top_object = 0); // If not 0, switch top object.
-public:
- // Return column prefix for composite data member.
- //
- static string
- column_prefix (semantics::data_member&,
- string const& key_prefix = string (),
- string const& default_name = string ());
-
- // Return column prefix up to (but not including) the last member
- // in the path.
- //
- static string
- column_prefix (data_member_path const&);
-
protected:
string key_prefix_;
string default_name_;
- string column_prefix_;
+ column_prefix column_prefix_;
data_member_path member_path_;
data_member_scope member_scope_;
@@ -365,9 +354,8 @@ struct object_columns_list: object_columns_base
{
}
- object_columns_list (string const& column_prefix, bool ignore_inverse = true)
- : object_columns_base (true, column_prefix),
- ignore_inverse_ (ignore_inverse)
+ object_columns_list (column_prefix const& cp, bool ignore_inverse = true)
+ : object_columns_base (true, cp), ignore_inverse_ (ignore_inverse)
{
}
diff --git a/odb/context.cxx b/odb/context.cxx
index f5ff975..46116f6 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -472,6 +472,46 @@ context (ostream& os_,
for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i)
data_->keyword_set_.insert (keywords[i]);
+ // SQL name regex.
+ //
+ if (ops.table_regex ().count (db) != 0)
+ {
+ strings const& s (ops.table_regex ()[db]);
+ data_->sql_name_regex_[sql_name_table].assign (s.begin (), s.end ());
+ }
+
+ if (ops.column_regex ().count (db) != 0)
+ {
+ strings const& s (ops.column_regex ()[db]);
+ data_->sql_name_regex_[sql_name_column].assign (s.begin (), s.end ());
+ }
+
+ if (ops.index_regex ().count (db) != 0)
+ {
+ strings const& s (ops.index_regex ()[db]);
+ data_->sql_name_regex_[sql_name_index].assign (s.begin (), s.end ());
+ }
+
+ if (ops.fkey_regex ().count (db) != 0)
+ {
+ strings const& s (ops.fkey_regex ()[db]);
+ data_->sql_name_regex_[sql_name_fkey].assign (s.begin (), s.end ());
+ }
+
+ if (ops.sequence_regex ().count (db) != 0)
+ {
+ strings const& s (ops.sequence_regex ()[db]);
+ data_->sql_name_regex_[sql_name_sequence].assign (s.begin (), s.end ());
+ }
+
+ if (ops.sql_name_regex ().count (db) != 0)
+ {
+ strings const& s (ops.sql_name_regex ()[db]);
+ data_->sql_name_regex_[sql_name_all].assign (s.begin (), s.end ());
+ }
+
+ // Include regex.
+ //
for (strings::const_iterator i (ops.include_regex ().begin ());
i != ops.include_regex ().end (); ++i)
data_->include_regex_.push_back (regexsub (*i));
@@ -1088,6 +1128,79 @@ composite_ (semantics::class_& c)
return r;
}
+// context::table_prefix
+//
+context::table_prefix::
+table_prefix (semantics::class_& c)
+ : level (1)
+{
+ context& ctx (context::current ());
+
+ ns_schema = ctx.schema (c.scope ());
+ ns_prefix = ctx.table_name_prefix (c.scope ());
+ prefix = ctx.table_name (c, &derived);
+ prefix += "_";
+}
+
+void context::table_prefix::
+append (semantics::data_member& m)
+{
+ assert (level > 0);
+
+ context& ctx (context::current ());
+
+ // If a custom table prefix was specified, then ignore the top-level
+ // table prefix (this corresponds to a container directly inside an
+ // object) but keep the schema unless the alternative schema is fully
+ // qualified.
+ //
+ if (m.count ("table"))
+ {
+ qname p, n (m.get<qname> ("table"));
+
+ if (n.fully_qualified ())
+ p = n.qualifier ();
+ else
+ {
+ if (n.qualified ())
+ {
+ p = ns_schema;
+ p.append (n.qualifier ());
+ }
+ else
+ p = prefix.qualifier ();
+ }
+
+ if (level == 1)
+ {
+ p.append (ns_prefix);
+ derived = false;
+ }
+ else
+ p.append (prefix.uname ());
+
+ p += n.uname ();
+ prefix.swap (p);
+ }
+ // Otherwise use the member name and add an underscore unless it is
+ // already there.
+ //
+ else
+ {
+ string name (ctx.public_name_db (m));
+ size_t n (name.size ());
+
+ prefix += name;
+
+ if (n != 0 && name[n - 1] != '_')
+ prefix += "_";
+
+ derived = true;
+ }
+
+ level++;
+}
+
qname context::
schema (semantics::scope& s) const
{
@@ -1198,14 +1311,14 @@ table_name_prefix (semantics::scope& s) const
}
qname context::
-table_name (semantics::class_& c) const
+table_name (semantics::class_& c, bool* pd) const
{
if (c.count ("qualified-table"))
return c.get<qname> ("qualified-table");
qname r;
-
bool sf (c.count ("schema"));
+ bool derived;
if (c.count ("table"))
{
@@ -1221,9 +1334,14 @@ table_name (semantics::class_& c) const
c.get<location_t> ("table-location") <
c.get<location_t> ("schema-location");
}
+
+ derived = false;
}
else
+ {
r = class_name (c);
+ derived = true;
+ }
if (sf)
{
@@ -1247,16 +1365,21 @@ table_name (semantics::class_& c) const
//
r.uname () = table_name_prefix (c.scope ()) + r.uname ();
+ if (derived)
+ r.uname () = transform_name (r.uname (), sql_name_table);
+
c.set ("qualified-table", r);
+
+ if (pd != 0)
+ *pd = derived;
+
return r;
}
qname context::
table_name (semantics::class_& obj, data_member_path const& mp) const
{
- table_prefix tp (schema (obj.scope ()),
- table_name_prefix (obj.scope ()),
- table_name (obj) + "_");
+ table_prefix tp (obj);
if (mp.size () == 1)
{
@@ -1271,7 +1394,7 @@ table_name (semantics::class_& obj, data_member_path const& mp) const
// The last member is the container.
//
for (data_member_path::const_iterator e (mp.end () - 1); i != e; ++i)
- object_members_base::append (**i, tp);
+ tp.append (**i);
return table_name (**i, tp);
}
@@ -1285,12 +1408,14 @@ table_name (semantics::data_member& m, table_prefix const& p) const
{
assert (p.level > 0);
qname r;
+ string rn;
+ bool derived; // Any of the components in the table name is derived.
// If a custom table name was specified, then ignore the top-level
// table prefix (this corresponds to a container directly inside an
// object). If the container table is unqualifed, then we use the
// object schema. If it is fully qualified, then we use that name.
- // Finally, if it is qualified by not fully qualifed, then we
+ // Finally, if it is qualified but not fully qualifed, then we
// append the object's namespace schema.
//
if (m.count ("table"))
@@ -1310,59 +1435,111 @@ table_name (semantics::data_member& m, table_prefix const& p) const
r = p.prefix.qualifier ();
}
- r.append (p.level == 1 ? p.ns_prefix : p.prefix.uname ());
- r += n.uname ();
+ if (p.level == 1)
+ {
+ rn = p.ns_prefix;
+ derived = false;
+ }
+ else
+ {
+ rn = p.prefix.uname ();
+ derived = p.derived;
+ }
+
+ rn += n.uname ();
}
else
{
- r = p.prefix;
- r += public_name_db (m);
+ r = p.prefix.qualifier ();
+ rn = p.prefix.uname () + public_name_db (m);
+ derived = true;
}
+ if (derived)
+ r.append (transform_name (rn, sql_name_table));
+ else
+ r.append (rn);
+
return r;
}
-string context::
-column_name (semantics::data_member& m) const
+// context::column_prefix
+//
+context::column_prefix::
+column_prefix (data_member_path const& mp, bool l)
+ : derived (false)
{
- if (m.count ("column"))
- return m.get<table_column> ("column").column;
- else
- return public_name_db (m);
+ if (mp.size () < (l ? 1 : 2))
+ return;
+
+ for (data_member_path::const_iterator i (mp.begin ()),
+ e (mp.end () - (l ? 0 : 1)); i != e; ++i)
+ append (**i);
}
-string context::
-column_name (data_member_path const& mp) const
+void context::column_prefix::
+append (semantics::data_member& m, string const& kp, string const& dn)
{
- // The path can lead to a composite value member and column names for
- // such members are derived dynamically using the same derivation
- // process as when generating object columns (see object_columns_base).
- //
- string r;
+ bool d;
+ context& ctx (context::current ());
- for (data_member_path::const_iterator i (mp.begin ()); i != mp.end (); ++i)
+ if (kp.empty ())
+ prefix += ctx.column_name (m, d);
+ else
+ prefix += ctx.column_name (m, kp, dn, d);
+
+ // If the user provided the column prefix, then use it verbatime.
+ // Otherwise, append the underscore, unless it is already there.
+ //
+ if (d)
{
- semantics::data_member& m (**i);
+ size_t n (prefix.size ());
- if (composite_wrapper (utype (m)))
- r += object_columns_base::column_prefix (m);
- else
- r = compose_name (r, column_name (m));
+ if (n != 0 && prefix[n - 1] != '_')
+ prefix += '_';
}
- return r;
+ derived = derived || d;
+}
+
+string context::
+column_name (semantics::data_member& m, bool& derived) const
+{
+ derived = !m.count ("column");
+ return derived
+ ? public_name_db (m)
+ : m.get<table_column> ("column").column;
+}
+
+string context::
+column_name (semantics::data_member& m, column_prefix const& cp) const
+{
+ bool d;
+ string n (column_name (m, d));
+ n = compose_name (cp.prefix, n);
+
+ // If any component is derived, the run it through the SQL name regex.
+ //
+ if (d || cp.derived)
+ n = transform_name (n, sql_name_column);
+
+ return n;
}
string context::
-column_name (semantics::data_member& m, string const& p, string const& d) const
+column_name (semantics::data_member& m,
+ string const& p,
+ string const& d,
+ bool& derived) const
{
if (p.empty () && d.empty ())
- return column_name (m);
+ return column_name (m, derived);
// A container column name can be specified for the member or for the
// container type.
//
string key (p + "-column");
+ derived = false;
if (m.count (key))
return m.get<string> (key);
@@ -1374,35 +1551,32 @@ column_name (semantics::data_member& m, string const& p, string const& d) const
return t.get<string> (key);
}
+ derived = true;
return d;
}
string context::
-compose_name (string const& prefix, string const& name)
+column_name (semantics::data_member& m,
+ string const& kp,
+ string const& dn,
+ column_prefix const& cp) const
{
- string r (prefix);
- size_t n (r.size ());
+ bool d;
+ string n (column_name (m, kp, dn, d));
+ n = compose_name (cp.prefix, n);
- // Add an underscore unless one is already in the prefix or
- // the name is empty. Similarly, remove it if it is there but
- // the name is empty.
+ // If any component is derived, the run it through the SQL name regex.
//
- if (n != 0)
- {
- if (r[n - 1] != '_')
- {
- if (!name.empty ())
- r += '_';
- }
- else
- {
- if (name.empty ())
- r.resize (n - 1);
- }
- }
+ if (d || cp.derived)
+ n = transform_name (n, sql_name_column);
- r += name;
- return r;
+ return n;
+}
+
+string context::
+column_name (data_member_path const& mp) const
+{
+ return column_name (*mp.back (), column_prefix (mp));
}
string context::
@@ -1614,6 +1788,105 @@ public_name_db (semantics::data_member& m) const
}
string context::
+compose_name (string const& prefix, string const& name)
+{
+ string r (prefix);
+ size_t n (r.size ());
+
+ // Add an underscore unless one is already in the prefix or
+ // the name is empty. Similarly, remove it if it is there but
+ // the name is empty.
+ //
+ if (n != 0)
+ {
+ if (r[n - 1] != '_')
+ {
+ if (!name.empty ())
+ r += '_';
+ }
+ else
+ {
+ if (name.empty ())
+ r.resize (n - 1);
+ }
+ }
+
+ r += name;
+ return r;
+}
+
+string context::
+transform_name (string const& name, sql_name_type type) const
+{
+ string r;
+
+ if (!data_->sql_name_regex_[type].empty () ||
+ !data_->sql_name_regex_[sql_name_all].empty ())
+ {
+ bool t (options.sql_name_regex_trace ());
+
+ if (t)
+ cerr << "name: '" << name << "'" << endl;
+
+ bool found (false);
+
+ // First try the type-specific transformations, if that didn't work,
+ // try common transformations.
+ //
+ for (unsigned short j (0); !found && j < 2; ++j)
+ {
+ regex_mapping const& rm = data_->sql_name_regex_[
+ j == 0 ? type : sql_name_all];
+
+ for (regex_mapping::const_iterator i (rm.begin ()); i != rm.end (); ++i)
+ {
+ if (t)
+ cerr << "try: '" << i->regex () << "' : ";
+
+ if (i->match (name))
+ {
+ r = i->replace (name);
+ found = true;
+
+ if (t)
+ cerr << "'" << r << "' : ";
+ }
+
+ if (t)
+ cerr << (found ? '+' : '-') << endl;
+
+ if (found)
+ break;
+ }
+ }
+
+ if (!found)
+ r = name;
+ }
+ else
+ r = name;
+
+ if (options.sql_name_case ().count (db) != 0)
+ {
+ switch (options.sql_name_case ()[db])
+ {
+ case name_case::upper:
+ {
+ r = data_->sql_name_upper_.replace (r);
+ break;
+ }
+ case name_case::lower:
+ {
+ r = data_->sql_name_lower_.replace (r);
+ break;
+ }
+ }
+ }
+
+ return r;
+}
+
+string context::
public_name (semantics::data_member& m, bool e) const
{
return e ? escape (public_name_impl (m)) : public_name_impl (m);
diff --git a/odb/context.hxx b/odb/context.hxx
index 22750de..6b532fa 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -620,24 +620,27 @@ public:
//
//
- qname
- table_name (semantics::class_&) const;
-
- qname
- table_name (semantics::class_&, data_member_path const&) const;
-
struct table_prefix
{
- table_prefix (): level (0) {}
- table_prefix (qname const& ns_s, string const& ns_p, qname const& p)
- : ns_schema (ns_s), ns_prefix (ns_p), prefix (p), level (1) {}
+ table_prefix (): level (0), derived (false) {}
+ table_prefix (semantics::class_&);
+
+ void
+ append (semantics::data_member&);
qname ns_schema; // Object's namespace schema.
string ns_prefix; // Object's namespace table prefix.
qname prefix;
size_t level;
+ bool derived; // One of the components in the prefix was derived.
};
+ qname
+ table_name (semantics::class_&, bool* derived = 0) const;
+
+ qname
+ table_name (semantics::class_&, data_member_path const&) const;
+
// Table name for the container member. The table prefix passed as the
// second argument must include the table prefix specified with the
// --table-prefix option.
@@ -645,23 +648,58 @@ public:
qname
table_name (semantics::data_member&, table_prefix const&) const;
+ //
+ //
+ struct column_prefix
+ {
+ column_prefix (): derived (false) {}
+
+ column_prefix (semantics::data_member& m,
+ string const& key_prefix = string (),
+ string const& default_name = string ())
+ : derived (false)
+ {
+ append (m, key_prefix, default_name);
+ }
+
+ // If the last argument is true, the prefix will include the last member
+ // in the path.
+ //
+ column_prefix (data_member_path const&, bool last = false);
+
+ void
+ append (semantics::data_member&,
+ string const& key_prefix = string (),
+ string const& default_name = string ());
+
+ string prefix;
+ bool derived; // One of the components in the prefix was derived.
+ };
+
string
- column_name (semantics::data_member&) const;
+ column_name (semantics::data_member&, bool& derived) const;
string
- column_name (data_member_path const&) const;
+ column_name (semantics::data_member&, column_prefix const&) const;
string
column_name (semantics::data_member&,
string const& key_prefix,
- string const& default_name) const;
+ string const& default_name,
+ bool& derived) const;
- // Compose the name by inserting/removing an underscore, as necessary.
- //
- static string
- compose_name (string const& prefix, string const& name);
+ string
+ column_name (semantics::data_member&,
+ string const& key_prefix,
+ string const& default_name,
+ column_prefix const&) const;
string
+ column_name (data_member_path const&) const;
+
+ //
+ //
+ string
column_type (const data_member_path&,
string const& key_prefix = string (),
bool id = false); // Pass true if this type is object id other
@@ -680,6 +718,27 @@ public:
string
public_name_db (semantics::data_member&) const;
+ // Compose the name by inserting/removing an underscore, as necessary.
+ //
+ static string
+ compose_name (string const& prefix, string const& name);
+
+ // SQL name transformations.
+ //
+ enum sql_name_type
+ {
+ sql_name_all,
+ sql_name_table,
+ sql_name_column,
+ sql_name_index,
+ sql_name_fkey,
+ sql_name_sequence,
+ sql_name_count
+ };
+
+ string
+ transform_name (string const& name, sql_name_type) const;
+
// C++ names.
//
public:
@@ -959,8 +1018,11 @@ protected:
{
virtual
~data () {}
+
data (std::ostream& os)
- : os_ (os.rdbuf ()), top_object_ (0), cur_object_ (0)
+ : os_ (os.rdbuf ()), top_object_ (0), cur_object_ (0),
+ sql_name_upper_ ("(.+)", "\\U$1"),
+ sql_name_lower_ ("(.+)", "\\L$1")
{
}
@@ -977,6 +1039,10 @@ protected:
keyword_set_type keyword_set_;
type_map_type type_map_;
+ regex_mapping sql_name_regex_[sql_name_count];
+ regexsub sql_name_upper_;
+ regexsub sql_name_lower_;
+
regex_mapping include_regex_;
regex_mapping accessor_regex_;
regex_mapping modifier_regex_;
diff --git a/odb/option-types.cxx b/odb/option-types.cxx
index 8efb061..60fea73 100644
--- a/odb/option-types.cxx
+++ b/odb/option-types.cxx
@@ -195,6 +195,29 @@ operator<< (ostream& os, schema_format sf)
}
//
+// name_case
+//
+
+istream&
+operator>> (istream& is, name_case& v)
+{
+ string s;
+ is >> s;
+
+ if (!is.fail ())
+ {
+ if (s == "upper")
+ v = name_case::upper;
+ else if (s == "lower")
+ v = name_case::lower;
+ else
+ is.setstate (istream::failbit);
+ }
+
+ return is;
+}
+
+//
// oracle_version
//
diff --git a/odb/option-types.hxx b/odb/option-types.hxx
index 09be4ee..0b6d47a 100644
--- a/odb/option-types.hxx
+++ b/odb/option-types.hxx
@@ -151,6 +151,26 @@ operator<< (std::ostream&, schema_format);
//
//
+struct name_case
+{
+ enum value
+ {
+ upper,
+ lower
+ };
+
+ name_case (value v = value (0)) : v_ (v) {}
+ operator value () const {return v_;}
+
+private:
+ value v_;
+};
+
+std::istream&
+operator>> (std::istream&, name_case&);
+
+//
+//
struct oracle_version
{
oracle_version (unsigned short major, unsigned short minor)
diff --git a/odb/options.cli b/odb/options.cli
index d756494..5b67708 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -229,16 +229,6 @@ class options
\cb{--schema-name} option."
};
- database_map<std::string> --table-prefix
- {
- "<prefix>",
- "Add <prefix> to table and index names. The prefix is added to both
- names that were specified with the \cb{db table} pragma and those
- that were automatically derived from class names. If you require a
- separator, such as an underscore, between the prefix and the name,
- then you should include it into the prefix value."
- };
-
// Export control.
//
database_map<std::string> --export-symbol
@@ -529,6 +519,108 @@ class options
option)."
};
+ // SQL names.
+ //
+ database_map<std::string> --table-prefix
+ {
+ "<prefix>",
+ "Add <prefix> to table names and, for databases that have global index
+ and/or foreign key names, to those names as well. The prefix is added to
+ both names that were specified with the \cb{db table} and \cb{db index}
+ pragmas and those that were automatically derived from class and data
+ member names. If you require a separator, such as an underscore,
+ between the prefix and the name, then you should include it into the
+ prefix value."
+ };
+
+ database_map<std::string> --index-suffix
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{_i} to construct index names.
+ The suffix is only added to names that were automatically derived from
+ data member names. If you require a separator, such as an underscore,
+ between the name and the suffix, then you should include it into the
+ suffix value."
+ };
+
+ database_map<std::string> --fkey-suffix
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{_fk} to construct foreign key
+ names. If you require a separator, such as an underscore, between the
+ name and the suffix, then you should include it into the suffix value."
+ };
+
+ database_map<std::string> --sequence-suffix
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{_seq} to construct sequence
+ names. If you require a separator, such as an underscore, between the
+ name and the suffix, then you should include it into the suffix value."
+ };
+
+ database_map<name_case> --sql-name-case
+ {
+ "<case>",
+ "Convert all automatically-derived SQL names to upper or lower case.
+ Valid values for this option are \cb{upper} and \cb{lower}."
+ };
+
+ database_map<std::vector<std::string> > --table-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions that is used to
+ transform automatically-derived table names. See the SQL NAME
+ TRANSFORMATIONS section below for details."
+ };
+
+ database_map<std::vector<std::string> > --column-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions that is used to
+ transform automatically-derived column names. See the SQL NAME
+ TRANSFORMATIONS section below for details."
+ };
+
+ database_map<std::vector<std::string> > --index-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions that is used to
+ transform automatically-derived index names. See the SQL NAME
+ TRANSFORMATIONS section below for details."
+ };
+
+ database_map<std::vector<std::string> > --fkey-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions that is used to
+ transform automatically-derived foreign key names. See the SQL NAME
+ TRANSFORMATIONS section below for details."
+ };
+
+ database_map<std::vector<std::string> > --sequence-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions that is used to
+ transform automatically-derived sequence names. See the SQL NAME
+ TRANSFORMATIONS section below for details."
+ };
+
+ database_map<std::vector<std::string> > --sql-name-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions that is used to
+ transform all automatically-derived SQL names. See the SQL NAME
+ TRANSFORMATIONS section below for details."
+ };
+
+ bool --sql-name-regex-trace
+ {
+ "Trace the process of applying regular expressions specified with the
+ SQL name \cb{--*-regex} options. Use this option to find out why your
+ regular expressions don't do what you expected them to do."
+ };
+
// Accessor/modifier options.
//
std::vector<std::string> --accessor-regex
diff --git a/odb/relational/common-query.cxx b/odb/relational/common-query.cxx
index e49132f..40ed71b 100644
--- a/odb/relational/common-query.cxx
+++ b/odb/relational/common-query.cxx
@@ -34,17 +34,20 @@ namespace relational
if (composite_wrapper (utype (*id_member (c))))
{
- n = column_prefix (m, key_prefix_, default_name_);
+ n = column_prefix (m, key_prefix_, default_name_).prefix;
if (n.empty ())
n = public_name_db (m);
- else
+ else if (n[n.size () - 1] == '_')
n.resize (n.size () - 1); // Remove trailing underscore.
}
else
- n = column_name (m, key_prefix_, default_name_);
+ {
+ bool dummy;
+ n = column_name (m, key_prefix_, default_name_, dummy);
+ }
- alias = compose_name (column_prefix_, n);
+ alias = compose_name (column_prefix_.prefix, n);
}
generate_def (public_name (m), c, alias);
diff --git a/odb/relational/context.cxx b/odb/relational/context.cxx
index 08e68e5..b484ad9 100644
--- a/odb/relational/context.cxx
+++ b/odb/relational/context.cxx
@@ -28,6 +28,8 @@ namespace relational
insert_send_auto_id (current ().insert_send_auto_id),
delay_freeing_statement_result (current ().delay_freeing_statement_result),
need_image_clone (current ().need_image_clone),
+ global_index (current ().global_index),
+ global_fkey (current ().global_fkey),
bind_vector (data_->bind_vector_),
truncated_vector (data_->truncated_vector_)
{
@@ -45,6 +47,46 @@ namespace relational
}
string context::
+ index_name (qname const& table, string const& base)
+ {
+ string n;
+
+ if (options.index_suffix ().count (db) != 0)
+ n = base + options.index_suffix ()[db];
+ else
+ n = compose_name (base, "i");
+
+ // If this database has global index names, then add the table
+ // name as a prefix (the schema, if needed, will be added by
+ // database-specific create_index overrides).
+ //
+ if (global_index)
+ n = compose_name (table.uname (), n);
+
+ return transform_name (n, sql_name_index);
+ }
+
+ string context::
+ fkey_name (qname const& table, string const& base)
+ {
+ string n;
+
+ if (options.fkey_suffix ().count (db) != 0)
+ n = base + options.fkey_suffix ()[db];
+ else
+ n = compose_name (base, "fk");
+
+ // If this database has global index names, then add the table
+ // name as a prefix (the schema, if needed, will be added by
+ // database-specific create_foreign_key overrides).
+ //
+ if (global_fkey)
+ n = compose_name (table.uname (), n);
+
+ return transform_name (n, sql_name_fkey);
+ }
+
+ string context::
convert (string const& e, string const& c)
{
size_t p (c.find ("(?)"));
diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx
index 990e0aa..55c9a23 100644
--- a/odb/relational/context.hxx
+++ b/odb/relational/context.hxx
@@ -105,9 +105,9 @@ namespace relational
// Quoted column and table names.
//
string
- column_qname (semantics::data_member& m) const
+ column_qname (semantics::data_member& m, column_prefix const& cp) const
{
- return quote_id (column_name (m));
+ return quote_id (column_name (m, cp));
}
string
@@ -119,9 +119,10 @@ namespace relational
string
column_qname (semantics::data_member& m,
string const& key_prefix,
- string const& default_name) const
+ string const& default_name,
+ column_prefix const& cp) const
{
- return quote_id (column_name (m, key_prefix, default_name));
+ return quote_id (column_name (m, key_prefix, default_name, cp));
}
string
@@ -142,6 +143,13 @@ namespace relational
return quote_id (table_name (m, p));
}
+ public:
+ string
+ index_name (qname const& table, string const& base);
+
+ string
+ fkey_name (qname const& table, string const& base);
+
// Custom database type conversion.
//
public:
@@ -261,6 +269,9 @@ namespace relational
bool delay_freeing_statement_result;
bool need_image_clone;
+ bool global_index;
+ bool global_fkey;
+
string const& bind_vector;
string const& truncated_vector;
};
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index 4245c91..2835a3a 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -298,16 +298,18 @@ namespace relational
name = fk.contains_begin ()->column ().name ();
else
{
- string p (column_prefix (m, key_prefix_, default_name_));
+ string p (column_prefix (m, key_prefix_, default_name_).prefix);
if (p.empty ())
p = public_name_db (m);
+ else if (p[p.size () - 1] == '_')
+ p.resize (p.size () - 1); // Remove trailing underscore.
- name = compose_name (column_prefix_, p);
+ name = compose_name (column_prefix_.prefix, p);
}
model_.new_edge<sema_rel::unames> (
- table_, fk, compose_name (name, "fk"));
+ table_, fk, fkey_name (table_.name (), name));
}
protected:
@@ -371,10 +373,11 @@ namespace relational
if (type* comp = composite_wrapper (utype (*im.path.back ())))
{
- // Composite value. Get the list of the columns. Here
- // column_name() returns the column prefix.
+ // Composite value. Get the list of the columns. Note that
+ // the column prefix needs to contain all the components.
//
- instance<object_columns_list> ocl (column_name (im.path));
+ instance<object_columns_list> ocl (
+ column_prefix (im.path, true));
ocl->traverse (*comp);
for (object_columns_list::iterator i (ocl->begin ());
@@ -504,7 +507,11 @@ namespace relational
// composite), in which case it can be empty. In this case
// we just fallback on the default name.
//
- string id_name (column_name (m, "id", "object_id"));
+ // Finally, this is a top-level column, so there is no column
+ // prefix.
+ //
+ string id_name (
+ column_name (m, "id", "object_id", column_prefix ()));
if (id_name.empty ())
id_name = "object_id";
@@ -519,7 +526,7 @@ namespace relational
sema_rel::foreign_key::cascade));
fk.set ("cxx-location", m.location ());
model_.new_edge<sema_rel::unames> (
- t, fk, compose_name (id_name, "fk"));
+ t, fk, fkey_name (t.name (), id_name));
// Get referenced columns.
//
@@ -555,19 +562,20 @@ namespace relational
in = &model_.new_node<sema_rel::index> (
id + ".id", sin->type, sin->method, sin->options);
in->set ("cxx-location", sin->loc);
- model_.new_edge<sema_rel::unames> (
- t,
- *in,
- (sin->name.empty () ? compose_name (id_name, "i") : sin->name));
}
else
{
in = &model_.new_node<sema_rel::index> (id + ".id");
in->set ("cxx-location", m.location ());
- model_.new_edge<sema_rel::unames> (
- t, *in, compose_name (id_name, "i"));
}
+ model_.new_edge<sema_rel::unames> (
+ t,
+ *in,
+ sin != 0 && !sin->name.empty ()
+ ? sin->name
+ : index_name (name, id_name));
+
// All the columns we have in this table so far are for the
// object id. Add them to the index.
//
@@ -591,9 +599,10 @@ namespace relational
instance<object_columns> oc (model_, t);
oc->traverse (m, container_it (ct), "index", "index");
- // This is a simple value so the name cannot be empty.
+ // This is a simple value so the name cannot be empty. It is
+ // also a top-level column, so there is no column prefix.
//
- string col (column_name (m, "index", "index"));
+ string col (column_name (m, "index", "index", column_prefix ()));
// Index. See if we have a custom index.
//
@@ -607,19 +616,20 @@ namespace relational
in = &model_.new_node<sema_rel::index> (
id + ".index", sin->type, sin->method, sin->options);
in->set ("cxx-location", sin->loc);
- model_.new_edge<sema_rel::unames> (
- t,
- *in,
- (sin->name.empty () ? compose_name (col, "i") : sin->name));
}
else
{
in = &model_.new_node<sema_rel::index> (id + ".index");
in->set ("cxx-location", m.location ());
- model_.new_edge<sema_rel::unames> (
- t, *in, compose_name (col, "i"));
}
+ model_.new_edge<sema_rel::unames> (
+ t,
+ *in,
+ sin != 0 && !sin->name.empty ()
+ ? sin->name
+ : index_name (name, col));
+
model_.new_edge<sema_rel::contains> (
*in,
dynamic_cast<column&> (t.find (col)->nameable ()),
diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx
index 7e11564..c64ae57 100644
--- a/odb/relational/mssql/context.cxx
+++ b/odb/relational/mssql/context.cxx
@@ -88,6 +88,8 @@ namespace relational
insert_send_auto_id = false;
delay_freeing_statement_result = true;
need_image_clone = true;
+ global_index = false;
+ global_fkey = true;
data_->bind_vector_ = "mssql::bind*";
// Populate the C++ type to DB type map.
diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx
index 47cb250..20f9faf 100644
--- a/odb/relational/mssql/schema.cxx
+++ b/odb/relational/mssql/schema.cxx
@@ -80,18 +80,11 @@ namespace relational
if (dt_.tables_.find (rt) != dt_.tables_.end () ||
m.find (rt) == m.names_end ())
{
-
- // In SQL Server, foreign key names are schema-global. Make them
- // unique by prefixing the key name with table name. Note, however,
- // that they cannot have a schema.
- //
- string n (t.name ().uname () + "_" + fk.name ());
-
pre_statement ();
- os << "IF OBJECT_ID(" << quote_string (n) << ", " <<
+ os << "IF OBJECT_ID(" << quote_string (fk.name ()) << ", " <<
quote_string ("F") << ") IS NOT NULL" << endl
<< " ALTER TABLE " << quote_id (t.name ()) << " DROP" << endl
- << " CONSTRAINT " << quote_id (n) << endl;
+ << " CONSTRAINT " << quote_id (fk.name ()) << endl;
post_statement ();
}
}
@@ -208,18 +201,6 @@ namespace relational
}
}
- 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. Note, however,
- // that they cannot have a schema.
- //
- return quote_id (
- static_cast<sema_rel::table&> (fk.scope ()).name ().uname ()
- + "_" + fk.name ());
- }
-
virtual void
deferred ()
{
diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx
index 7fce155..5d0c594 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/relational/mssql/source.cxx
@@ -909,8 +909,14 @@ namespace relational
}
if (p == persist_after_columns)
- os << strlit (" OUTPUT " + convert_from (
- "INSERTED." + column_qname (*id), *id)) << endl;
+ {
+ // Top-level auto id.
+ //
+ os << strlit (
+ " OUTPUT " + convert_from (
+ "INSERTED." + column_qname (
+ *id, column_prefix ()), *id)) << endl;
+ }
}
virtual void
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index 8bf700e..ba22733 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -84,6 +84,8 @@ namespace relational
insert_send_auto_id = true;
delay_freeing_statement_result = false;
need_image_clone = false;
+ global_index = false;
+ global_fkey = true;
data_->bind_vector_ = "MYSQL_BIND*";
data_->truncated_vector_ = "my_bool*";
diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx
index 8068fc4..5b34cfa 100644
--- a/odb/relational/mysql/schema.cxx
+++ b/odb/relational/mysql/schema.cxx
@@ -86,18 +86,6 @@ namespace relational
base::traverse (fk);
}
- virtual string
- name (sema_rel::foreign_key& fk)
- {
- // In MySQL, foreign key names are database-global. Make them
- // unique by prefixing the key name with table name. Note,
- // however, that they cannot be prefixed with the database name.
- //
- return quote_id (
- static_cast<sema_rel::table&> (fk.scope ()).name ().uname ()
- + "_" + fk.name ());
- }
-
virtual void
deferred ()
{
diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx
index 4ba8659..df62ce8 100644
--- a/odb/relational/oracle/context.cxx
+++ b/odb/relational/oracle/context.cxx
@@ -85,6 +85,8 @@ namespace relational
insert_send_auto_id = false;
delay_freeing_statement_result = false;
need_image_clone = true;
+ global_index = true;
+ global_fkey = true;
data_->bind_vector_ = "oracle::bind*";
// Populate the C++ type to DB type map.
@@ -168,6 +170,23 @@ namespace relational
s == "long long unsigned int";
}
+ qname context::
+ sequence_name (qname const& table)
+ {
+ string n;
+
+ if (options.sequence_suffix ().count (db) != 0)
+ n = table.uname () + options.sequence_suffix ()[db];
+ else
+ n = compose_name (table.uname (), "seq");
+
+ n = transform_name (n, sql_name_sequence);
+
+ qname r (table.qualifier ());
+ r.append (n);
+ return r;
+ }
+
//
// SQL type parsing.
//
diff --git a/odb/relational/oracle/context.hxx b/odb/relational/oracle/context.hxx
index 6b07a5f..0008724 100644
--- a/odb/relational/oracle/context.hxx
+++ b/odb/relational/oracle/context.hxx
@@ -106,6 +106,12 @@ namespace relational
static bool
unsigned_integer (semantics::type&);
+ public:
+ // Construct sequence name from a given table name.
+ //
+ qname
+ sequence_name (qname const& table);
+
protected:
virtual string const&
convert_expr (string const&, semantics::data_member&, bool);
diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx
index f07e0d6..ffe4b31 100644
--- a/odb/relational/oracle/schema.cxx
+++ b/odb/relational/oracle/schema.cxx
@@ -127,7 +127,7 @@ namespace relational
{
os << " BEGIN" << endl
<< " EXECUTE IMMEDIATE 'DROP SEQUENCE " <<
- quote_id (table + "_seq") << "';" << endl
+ quote_id (sequence_name (table)) << "';" << endl
<< " EXCEPTION" << endl
<< " WHEN OTHERS THEN" << endl
<< " IF SQLCODE != -2289 THEN RAISE; END IF;" << endl
@@ -184,18 +184,6 @@ namespace relational
fk.set ("oracle-fk-defined", true); // Mark it as defined.
}
}
-
- virtual string
- name (sema_rel::foreign_key& fk)
- {
- // In Oracle, foreign key names are schema-global. Make them
- // unique by prefixing the key name with table name. Note,
- // however, that they cannot have a schema.
- //
- return quote_id (
- static_cast<sema_rel::table&> (fk.scope ()).name ().uname ()
- + "_" + fk.name ());
- }
};
entry<create_foreign_key> create_foreign_key_;
@@ -244,7 +232,8 @@ namespace relational
if (pk != 0 && pk->auto_ ())
{
pre_statement ();
- os_ << "CREATE SEQUENCE " << quote_id (t.name () + "_seq") << endl
+ os_ << "CREATE SEQUENCE " <<
+ quote_id (sequence_name (t.name ())) << endl
<< " START WITH 1 INCREMENT BY 1" << endl;
post_statement ();
}
@@ -266,14 +255,11 @@ namespace relational
virtual string
name (sema_rel::index& in)
{
- // In Oracle, index names are database-global. Make them unique
- // by prefixing the index name with table name (preserving the
- // schema).
+ // In Oracle, index names can be qualified with the schema.
//
- sema_rel::qname n (
- static_cast<sema_rel::table&> (in.scope ()).name ());
-
- n.uname () += "_" + in.name ();
+ 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);
}
};
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index 85be6cc..f6cdfcd 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -17,7 +17,7 @@ namespace relational
{
namespace relational = relational::source;
- struct query_parameters: relational::query_parameters
+ struct query_parameters: relational::query_parameters, context
{
query_parameters (base const& x): base (x), i_ (0) {}
@@ -33,9 +33,7 @@ namespace relational
virtual string
auto_id ()
{
- // The same sequence name as used in schema.cxx.
- //
- return quote_id (table_ + "_seq") + ".nextval";
+ return quote_id (sequence_name (table_)) + ".nextval";
}
private:
@@ -600,9 +598,12 @@ namespace relational
if (id != 0 && !poly_derived && id->count ("auto"))
{
+ // Top-level auto id.
+ //
os << endl
<< strlit (" RETURNING " +
- convert_from (column_qname (*id), *id) +
+ convert_from (column_qname (*id, column_prefix ()),
+ *id) +
" INTO " +
qp.next ());
}
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index 391c65e..0f68281 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -84,6 +84,8 @@ namespace relational
insert_send_auto_id = false;
delay_freeing_statement_result = false;
need_image_clone = false;
+ global_index = true;
+ global_fkey = false;
data_->bind_vector_ = "pgsql::bind*";
data_->truncated_vector_ = "bool*";
diff --git a/odb/relational/pgsql/schema.cxx b/odb/relational/pgsql/schema.cxx
index 5574bdb..b0d4f50 100644
--- a/odb/relational/pgsql/schema.cxx
+++ b/odb/relational/pgsql/schema.cxx
@@ -170,18 +170,6 @@ namespace relational
{
create_index (base const& x): base (x) {}
- virtual string
- name (sema_rel::index& in)
- {
- // In PostgreSQL, index names are database-global. Make them unique
- // by prefixing the index name with table name. Note, however, that
- // they cannot be qualified with the schema name.
- //
- return quote_id (
- static_cast<sema_rel::table&> (in.scope ()).name ().uname ()
- + "_" + in.name ());
- }
-
virtual void
create (sema_rel::index& in)
{
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index 332e25b..e106758 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -618,9 +618,12 @@ namespace relational
if (id != 0 && !poly_derived && id->count ("auto"))
{
+ // Top-level auto id.
+ //
os << endl
<< strlit (" RETURNING " +
- convert_from (column_qname (*id), *id));
+ convert_from (column_qname (*id, column_prefix ()),
+ *id));
}
}
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index 88e86fc..3e969be 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -1106,6 +1106,11 @@ namespace relational
}
}
+ // Add the table prefix if this database has global index names.
+ //
+ if (!in.name.empty () && global_index)
+ in.name = table_name_prefix (c.scope ()) + in.name;
+
// Handle container indexes.
//
if (j != in.members.end ())
@@ -1164,12 +1169,14 @@ namespace relational
// be empty, in which case we will just fall back on the
// member's public name.
//
- in.name = column_name (in.members.front ().path);
+ string n (column_prefix (in.members.front ().path, true).prefix);
- if (in.name.empty ())
- in.name = public_name_db (*in.members.front ().path.back ());
+ if (n.empty ())
+ n = public_name_db (*in.members.front ().path.back ());
+ else if (n[n.size () - 1] == '_')
+ n.resize (n.size () - 1); // Remove trailing underscore.
- in.name = compose_name (in.name, "i");
+ in.name = index_name (table_name (c), n);
}
++i;
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 74690d6..f133750 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -699,9 +699,14 @@ traverse_object (type& c)
}
if (opt != 0 && !poly_derived)
+ {
+ // Top-level version column.
+ //
os << endl
- << strlit (" AND " + column_qname (*opt) + "=" +
+ << strlit (" AND " + column_qname (*opt, column_prefix ()) + "=" +
convert_to (qp->next (), *opt));
+ }
+
os << ";"
<< endl;
}
@@ -744,8 +749,10 @@ traverse_object (type& c)
convert_to (qp->next (), i->type, *i->member));
}
+ // Top-level version column.
+ //
os << endl
- << strlit (" AND " + column_qname (*opt) + "=" +
+ << strlit (" AND " + column_qname (*opt, column_prefix ()) + "=" +
convert_to (qp->next (), *opt)) << ";"
<< endl;
}
@@ -3339,11 +3346,7 @@ traverse_view (type& c)
// function would have to return a member path instead
// of just a single member.
//
- table_prefix tp (
- context::schema (vo->obj->scope ()),
- context::table_name_prefix (vo->obj->scope ()),
- table_name (*vo->obj) + "_");
- ct = table_qname (*im, tp);
+ ct = table_qname (*im, table_prefix (*vo->obj));
}
else
ct = table_qname (*e.vo->obj, e.member_path);
@@ -3516,10 +3519,10 @@ traverse_view (type& c)
}
else
{
- string col_prefix;
+ column_prefix col_prefix;
if (im == 0)
- col_prefix = object_columns_base::column_prefix (e.member_path);
+ col_prefix = column_prefix (e.member_path);
instance<object_columns_list> l_cols (col_prefix);
instance<object_columns_list> r_cols;
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 610c545..1e223af 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -80,7 +80,7 @@ namespace relational
object_columns (statement_kind sk,
statement_columns& sc,
query_parameters* param = 0)
- : object_columns_base (true, "", true),
+ : object_columns_base (true, true),
sk_ (sk), sc_ (sc), param_ (param), depth_ (1)
{
}
@@ -89,7 +89,7 @@ namespace relational
statement_kind sk,
statement_columns& sc,
size_t depth = 1)
- : object_columns_base (true, "", true),
+ : object_columns_base (true, true),
sk_ (sk),
sc_ (sc),
param_ (0),
@@ -158,12 +158,7 @@ namespace relational
string table;
if (!table_name_.empty ())
- {
- table_prefix tp (schema (c.scope ()),
- table_name_prefix (c.scope ()),
- table_name (c) + "_");
- table = table_qname (*im, tp);
- }
+ table = table_qname (*im, table_prefix (c));
instance<object_columns> oc (table, sk_, sc_);
oc->traverse (*im, idt, "id", "object_id", &c);
@@ -190,17 +185,20 @@ namespace relational
if (composite_wrapper (idt))
{
- n = column_prefix (m, key_prefix_, default_name_);
+ n = column_prefix (m, key_prefix_, default_name_).prefix;
if (n.empty ())
n = public_name_db (m);
- else
+ else if (n[n.size () - 1] == '_')
n.resize (n.size () - 1); // Remove trailing underscore.
}
else
- n = column_name (m, key_prefix_, default_name_);
+ {
+ bool dummy;
+ n = column_name (m, key_prefix_, default_name_, dummy);
+ }
- table = quote_id (compose_name (column_prefix_, n));
+ table = quote_id (compose_name (column_prefix_.prefix, n));
}
instance<object_columns> oc (table, sk_, sc_);
@@ -461,7 +459,7 @@ namespace relational
string const& alias = "",
string const prefix = "",
string const& suffix = "\n")
- : object_columns_base (true, "", true),
+ : object_columns_base (true, true),
obj_ (obj),
depth_ (depth),
alias_ (alias),
@@ -537,7 +535,7 @@ namespace relational
//@@ context::{cur,top}_object; might have to be created every time.
//
object_joins (semantics::class_& scope, bool query, size_t depth = 1)
- : object_columns_base (true, "", true),
+ : object_columns_base (true, true),
query_ (query),
depth_ (depth),
table_ (table_qname (scope)),
@@ -595,17 +593,20 @@ namespace relational
if (composite_wrapper (utype (*id_member (c))))
{
- n = column_prefix (m, key_prefix_, default_name_);
+ n = column_prefix (m, key_prefix_, default_name_).prefix;
if (n.empty ())
n = public_name_db (m);
- else
+ else if (n[n.size () - 1] == '_')
n.resize (n.size () - 1); // Remove trailing underscore.
}
else
- n = column_name (m, key_prefix_, default_name_);
+ {
+ bool dummy;
+ n = column_name (m, key_prefix_, default_name_, dummy);
+ }
- alias = compose_name (column_prefix_, n);
+ alias = compose_name (column_prefix_.prefix, n);
}
semantics::class_* poly_root (polymorphic (c));
@@ -621,11 +622,7 @@ namespace relational
// This container is a direct member of the class so the table
// prefix is just the class table name.
//
- qname const& ct (table_name (c));
- table_prefix tp (schema (c.scope ()),
- table_name_prefix (c.scope ()),
- ct + "_");
- t = table_qname (*im, tp);
+ t = table_qname (*im, table_prefix (c));
// Container's value is our id.
//
@@ -1952,10 +1949,7 @@ namespace relational
// This other container is a direct member of the class so the
// table prefix is just the class table name.
//
- table_prefix tp (schema (c->scope ()),
- table_name_prefix (c->scope ()),
- table_name (*c) + "_");
- inv_table = table_name (*im, tp);
+ inv_table = table_name (*im, table_prefix (*c));
inv_qtable = quote_id (inv_table);
inv_id_cols->traverse (*im, utype (inv_id), "id", "object_id", c);
@@ -2077,7 +2071,10 @@ namespace relational
if (ordered)
{
- string const& col (column_qname (m, "index", "index"));
+ // Top-level column.
+ //
+ string const& col (
+ column_qname (m, "index", "index", column_prefix ()));
os << endl
<< strlit (" ORDER BY " + qtable + "." + col);
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index 5dc3fa8..5e46c77 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -85,6 +85,8 @@ namespace relational
insert_send_auto_id = true;
delay_freeing_statement_result = false;
need_image_clone = false;
+ global_index = true;
+ global_fkey = false;
data_->bind_vector_ = "sqlite::bind*";
data_->truncated_vector_ = "bool*";
diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx
index 8efef66..1d4b1d2 100644
--- a/odb/relational/sqlite/schema.cxx
+++ b/odb/relational/sqlite/schema.cxx
@@ -56,14 +56,11 @@ namespace relational
virtual string
name (sema_rel::index& in)
{
- // In SQLite, index names are database-global. Make them unique
- // by prefixing the index name with table name (preserving the
- // database).
+ // In SQLite, index names can be qualified with the database.
//
- sema_rel::qname n (
- static_cast<sema_rel::table&> (in.scope ()).name ());
-
- n.uname () += "_" + in.name ();
+ 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);
}