summaryrefslogtreecommitdiff
path: root/odb/relational/oracle/context.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/relational/oracle/context.cxx')
-rw-r--r--odb/relational/oracle/context.cxx796
1 files changed, 0 insertions, 796 deletions
diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx
deleted file mode 100644
index 36d1343..0000000
--- a/odb/relational/oracle/context.cxx
+++ /dev/null
@@ -1,796 +0,0 @@
-// file : odb/relational/oracle/context.cxx
-// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <cassert>
-#include <sstream>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/relational/oracle/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace oracle
- {
- namespace
- {
- struct type_map_entry
- {
- char const* const cxx_type;
- char const* const db_type;
- char const* const db_id_type;
- bool const null;
- };
-
- type_map_entry type_map[] =
- {
- {"bool", "NUMBER(1)", 0, false},
-
- {"char", "CHAR(1)", 0, false},
- {"signed char", "NUMBER(3)", 0, false},
- {"unsigned char", "NUMBER(3)", 0, false},
-
- {"short int", "NUMBER(5)", 0, false},
- {"short unsigned int", "NUMBER(5)", 0, false},
-
- {"int", "NUMBER(10)", 0, false},
- {"unsigned int", "NUMBER(10)", 0, false},
-
- {"long int", "NUMBER(19)", 0, false},
- {"long unsigned int", "NUMBER(20)", 0, false},
-
- {"long long int", "NUMBER(19)", 0, false},
- {"long long unsigned int", "NUMBER(20)", 0, false},
-
- {"float", "BINARY_FLOAT", 0, false},
- {"double", "BINARY_DOUBLE", 0, false},
-
- // Oracle treats empty VARCHAR2 (and NVARCHAR2) strings as NULL.
- //
- {"::std::string", "VARCHAR2(512)", 0, true},
-
- {"::size_t", "NUMBER(20)", 0, false},
- {"::std::size_t", "NUMBER(20)", 0, false}
- };
- }
-
- context* context::current_;
-
- context::
- ~context ()
- {
- if (current_ == this)
- current_ = 0;
- }
-
- context::
- context (ostream& os,
- semantics::unit& u,
- options_type const& ops,
- features_type& f,
- sema_rel::model* m)
- : root_context (os, u, ops, f, data_ptr (new (shared) data (os))),
- base_context (static_cast<data*> (root_context::data_.get ()), m),
- data_ (static_cast<data*> (base_context::data_))
- {
- assert (current_ == 0);
- current_ = this;
-
- generate_grow = false;
- need_alias_as = false;
- insert_send_auto_id = false;
- delay_freeing_statement_result = false;
- need_image_clone = true;
- generate_bulk = true;
- global_index = true;
- global_fkey = true;
- data_->bind_vector_ = "oracle::bind*";
-
- // Populate the C++ type to DB type map.
- //
- for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i)
- {
- type_map_entry const& e (type_map[i]);
-
- type_map_type::value_type v (
- e.cxx_type,
- db_type_type (
- e.db_type, e.db_id_type ? e.db_id_type : e.db_type, e.null));
-
- data_->type_map_.insert (v);
- }
- }
-
- context::
- context ()
- : data_ (current ().data_)
- {
- }
-
- string const& context::
- convert_expr (string const& sqlt, semantics::data_member& m, bool to)
- {
- sql_type const& t (parse_sql_type (sqlt, m));
- return to ? t.to : t.from;
- }
-
- string context::
- quote_id_impl (qname const& id) const
- {
- string r;
-
- bool f (true);
- for (qname::iterator i (id.begin ()); i < id.end (); ++i)
- {
- if (i->empty ())
- continue;
-
- if (f)
- f = false;
- else
- r += '.';
-
- r += '"';
- r.append (*i, 0, 30); // Max identifier length is 30.
- r += '"';
- }
-
- return r;
- }
-
- string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- bool id,
- bool* null)
- {
- string r (base_context::database_type_impl (t, hint, id, null));
-
- if (!r.empty ())
- return r;
-
- using semantics::array;
-
- // char[N] mapping.
- //
- if (array* a = dynamic_cast<array*> (&t))
- {
- semantics::type& bt (a->base_type ());
- if (bt.is_a<semantics::fund_char> ())
- {
- unsigned long long n (a->size ());
-
- if (n == 0)
- return r;
- else if (n == 1)
- r = "CHAR";
- else
- {
- r = "VARCHAR2";
- n--;
- }
-
- // Oracle VARCHAR2 limit is 4000 bytes. Since there are no good
- // alternatives (CLOB?), let the user specify the mapping.
- //
- if (n > 4000)
- return "";
-
- // Allow empty VARCHAR2 values.
- //
- if (null != 0 && r == "VARCHAR2")
- *null = true;
-
- ostringstream ostr;
- ostr << n;
- r += '(';
- r += ostr.str ();
- r += ')';
- }
- }
-
- return r;
- }
-
- bool context::
- unsigned_integer (semantics::type& t)
- {
- semantics::type* wt (wrapper (t));
- const string& s ((wt == 0 ? t : utype (*wt)).name ());
-
- return s == "bool" ||
- s == "unsigned char" ||
- s == "short unsigned int" ||
- s == "unsigned int" ||
- s == "long unsigned int" ||
- 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.
- //
-
- sql_type const& context::
- parse_sql_type (string const& t, semantics::data_member& m, bool custom)
- {
- // If this proves to be too expensive, we can maintain a cache of
- // parsed types across contexts.
- //
- data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t));
-
- if (i != data_->sql_type_cache_.end ()
- && (custom ? i->second.custom_cached : i->second.straight_cached))
- {
- return (custom ? i->second.custom : i->second.straight);
- }
- else
- {
- try
- {
- sql_type st (
- parse_sql_type (
- t,
- custom ? &unit.get<custom_db_types> ("custom-db-types") : 0));
-
- if (custom)
- return data_->sql_type_cache_[t].cache_custom (st);
- else
- return data_->sql_type_cache_[t].cache_straight (st);
- }
- catch (invalid_sql_type const& e)
- {
- cerr << m.file () << ":" << m.line () << ":" << m.column ()
- << ": error: " << e.message () << endl;
-
- throw operation_failed ();
- }
- }
- }
-
- inline sql_type
- error (bool fail, string const& m)
- {
- if (!fail)
- return sql_type ();
- else
- throw context::invalid_sql_type (m);
- }
-
- sql_type context::
- parse_sql_type (string sqlt, custom_db_types const* ct)
- {
- try
- {
- sql_type r;
-
- // First run the type through the custom mapping, if requested.
- //
- if (ct != 0)
- {
- for (custom_db_types::const_iterator i (ct->begin ());
- i != ct->end (); ++i)
- {
- custom_db_type const& t (*i);
-
- if (t.type.match (sqlt))
- {
- r.to = t.type.replace (sqlt, t.to);
- r.from = t.type.replace (sqlt, t.from);
- sqlt = t.type.replace (sqlt, t.as);
- break;
- }
- }
- }
-
- sql_lexer l (sqlt);
-
- // While most type names use single identifier, there are
- // a couple of exceptions to this rule:
- //
- // CHARACTER VARYING (VARCHAR2)
- // CHAR VARYING (VARCHAR2)
- // NATIONAL CHARACTER (NCHAR)
- // NATIONAL CHAR (NCHAR)
- // NCHAR VARYING (NVARCHAR2)
- // NATIONAL CHARACTER VARYING (NVARCHAR2)
- // NATIONAL CHAR VARYING (NVARCHAR2)
- // NCHAR VARYING (NVARCHAR2)
- // DOUBLE PRECISION (FLOAT(126))
- // INTERVAL YEAR TO MONTH
- // INTERVAL DAY TO SECOND
- //
- enum state
- {
- parse_identifier,
- parse_prec,
- parse_done
- };
-
- state s (parse_identifier);
- string prefix;
- sql_token t (l.next ());
-
- while (t.type () != sql_token::t_eos)
- {
- sql_token::token_type tt (t.type ());
-
- switch (s)
- {
- case parse_identifier:
- {
- if (tt == sql_token::t_identifier)
- {
- string const& id (context::upcase (t.identifier ()));
-
- //
- // Numeric types.
- //
- if ((id == "NUMBER") && prefix.empty ())
- {
- // If NUMBER has no precision/scale, then it is a floating-
- // point number. We indicate this by having no precision.
- //
- r.type = sql_type::NUMBER;
- s = parse_prec;
- }
- else if ((id == "DEC" || id == "DECIMAL" || id == "NUMERIC")
- && prefix.empty ())
- {
- // DEC, DECIMAL, and NUMERIC are equivalent to NUMBER in
- // all ways except that they may not represent a floating
- // point number. The scale defaults to zero.
- //
- r.type = sql_type::NUMBER;
- s = parse_prec;
- }
- else if ((id == "INT" || id == "INTEGER" || id == "SMALLINT")
- && prefix.empty ())
- {
- // INT, INTEGER, and SMALLINT map to NUMBER(38). They may not
- // have precision or scale explicitly specified.
- //
- r.type = sql_type::NUMBER;
- r.prec = true;
- r.prec_value = 38;
-
- s = parse_done;
- }
- //
- // Floating point types.
- //
- else if (id == "FLOAT" && prefix.empty ())
- {
- r.type = sql_type::FLOAT;
- r.prec = true;
- r.prec_value = 126;
-
- s = parse_prec;
- }
- else if (id == "DOUBLE" && prefix.empty ())
- {
- prefix = id;
- }
- else if (id == "PRECISION" && prefix == "DOUBLE")
- {
- r.type = sql_type::FLOAT;
- r.prec = true;
- r.prec_value = 126;
-
- s = parse_done;
- }
- else if (id == "REAL" && prefix.empty ())
- {
- r.type = sql_type::FLOAT;
- r.prec = true;
- r.prec_value = 63;
-
- s = parse_done;
- }
- else if (id == "BINARY_FLOAT" && prefix.empty ())
- {
- r.type = sql_type::BINARY_FLOAT;
- s = parse_done;
- }
- else if (id == "BINARY_DOUBLE" && prefix.empty ())
- {
- r.type = sql_type::BINARY_DOUBLE;
- s = parse_done;
- }
- //
- // Date-time types.
- //
- else if (id == "DATE" && prefix.empty ())
- {
- r.type = sql_type::DATE;
- s = parse_done;
- }
- else if (id == "TIMESTAMP" && prefix.empty ())
- {
- prefix = id;
- }
- else if (id == "INTERVAL" && prefix.empty ())
- {
- prefix = id;
- }
- else if (id == "YEAR" && prefix == "INTERVAL")
- {
- prefix += " ";
- prefix += id;
-
- r.prec = true;
- r.prec_value = 2;
- s = parse_prec;
- }
- else if (id == "DAY" && prefix == "INTERVAL")
- {
- prefix += " ";
- prefix += id;
-
- r.prec = true;
- r.prec_value = 2;
- s = parse_prec;
- }
- else if (id == "TO" &&
- (prefix == "INTERVAL YEAR" ||
- prefix == "INTERVAL DAY"))
- {
- prefix += " ";
- prefix += id;
- }
- else if (id == "MONTH" && prefix == "INTERVAL YEAR TO")
- {
- r.type = sql_type::INTERVAL_YM;
- s = parse_done;
- }
- else if (id == "SECOND" && prefix == "INTERVAL DAY TO")
- {
- r.type = sql_type::INTERVAL_DS;
-
- // Store seconds precision in scale since prec holds
- // the days precision.
- //
- r.scale = true;
- r.scale_value = 6;
- s = parse_prec;
- }
- //
- // Timestamp with time zone (not supported).
- //
- else if (id == "WITH" && prefix == "TIMESTAMP")
- {
- prefix += " ";
- prefix += id;
- }
- else if (id == "TIME" &&
- (prefix == "TIMESTAMP WITH" ||
- prefix == "TIMESTAMP WITH LOCAL"))
- {
- prefix += " ";
- prefix += id;
- }
- else if (id == "LOCAL" && prefix == "TIMESTAMP WITH")
- {
- prefix += " ";
- prefix += id;
- }
- else if (id == "ZONE" &&
- (prefix == "TIMESTAMP WITH LOCAL TIME" ||
- prefix == "TIMESTAMP WITH TIME"))
- {
- return error (ct, "Oracle timestamps with time zones are "
- "not currently supported");
- }
- //
- // String and binary types.
- //
- else if (id == "CHAR")
- {
- prefix += prefix.empty () ? "" : " ";
- prefix += id;
- }
- else if (id == "CHARACTER")
- {
- prefix += prefix.empty () ? "" : " ";
- prefix += id;
- }
- else if (id == "NCHAR")
- {
- prefix += prefix.empty () ? "" : " ";
- prefix += id;
- }
- else if (id == "VARCHAR" || id == "VARCHAR2")
- {
- // VARCHAR is currently mapped to VARCHAR2 in Oracle server.
- // However, this may change in future versions.
- //
- r.type = sql_type::VARCHAR2;
- r.byte_semantics = true;
- s = parse_prec;
- }
- else if (id == "NVARCHAR2")
- {
- r.type = sql_type::NVARCHAR2;
- r.byte_semantics = false;
- s = parse_prec;
- }
- else if (id == "VARYING")
- {
- // VARYING always appears at the end of an identifier.
- //
- if (prefix == "CHAR" || prefix == "CHARACTER")
- {
- r.type = sql_type::VARCHAR2;
- r.byte_semantics = true;
- }
- else if (prefix == "NCHAR" ||
- prefix == "NATIONAL CHAR" ||
- prefix == "NATIONAL CHARACTER")
- {
- r.type = sql_type::NVARCHAR2;
- r.byte_semantics = false;
- }
-
- s = parse_prec;
- }
- else if (id == "NATIONAL" && prefix.empty ())
- {
- prefix = id;
- }
- else if (id == "RAW" && prefix.empty ())
- {
- r.type = sql_type::RAW;
- s = parse_prec;
- }
- //
- // LOB types.
- //
- else if (id == "BLOB" && prefix.empty ())
- {
- r.type = sql_type::BLOB;
- s = parse_done;
- }
- else if (id == "CLOB" && prefix.empty ())
- {
- r.type = sql_type::CLOB;
- s = parse_done;
- }
- else if (id == "NCLOB" && prefix.empty ())
- {
- r.type = sql_type::NCLOB;
- s = parse_done;
- }
- //
- // LONG types.
- //
- else if (id == "LONG")
- return error (ct, "Oracle LONG types are not supported");
- else
- return error (ct, "unknown Oracle type '" +
- t.identifier () + "'");
-
- t = l.next ();
- continue;
- }
- else if (!prefix.empty ())
- {
- // Some prefixes can also be type names if not followed
- // by the actual type name.
- //
-
- if (prefix == "CHAR" || prefix == "CHARACTER")
- {
- r.type = sql_type::CHAR;
- r.byte_semantics = true;
- r.prec = true;
- r.prec_value = 1;
- }
- else if (prefix == "NCHAR" ||
- prefix == "NATIONAL CHAR" ||
- prefix == "NATIONAL CHARACTER")
- {
- r.type = sql_type::NCHAR;
- r.byte_semantics = false;
- r.prec = true;
- r.prec_value = 1;
- }
- else if (prefix == "TIMESTAMP")
- {
- r.type = sql_type::TIMESTAMP;
- r.prec = true;
- r.prec_value = 6;
- }
- else
- return error (ct, "incomplete Oracle type declaration: '" +
- prefix + "'");
-
- // All of the possible types handled in this block can take
- // an optional precision specifier. Set the state and fall
- // through to the parse_prec handler.
- //
- s = parse_prec;
- }
- else
- {
- assert (r.type == sql_type::invalid);
- return error (ct, "unexepected '" + t.literal () +
- "' in Oracle type declaration");
- }
- }
- // Fall through.
- case parse_prec:
- {
- if (t.punctuation () == sql_token::p_lparen)
- {
- t = l.next ();
-
- if (t.type () != sql_token::t_int_lit)
- {
- return error (ct, "integer size/precision expected in "
- "Oracle type declaration");
- }
-
- // Parse the precision.
- //
- {
- unsigned short v;
- istringstream is (t.literal ());
-
- if (!(is >> v && is.eof ()))
- {
- return error (ct, "invalid prec value '" + t.literal () +
- "' in Oracle type declaration");
- }
-
- // Store seconds precision in scale since prec holds
- // the days precision for INTERVAL DAY TO SECOND.
- //
- if (r.type == sql_type::INTERVAL_DS)
- {
- r.scale = true;
- r.scale_value = static_cast<short> (v);
- }
- else
- {
- r.prec = true;
- r.prec_value = v;
- }
-
- t = l.next ();
- }
-
- // Parse the scale if present.
- //
- if (t.punctuation () == sql_token::p_comma)
- {
- // Scale can only be specified for NUMBER.
- //
- if (r.type != sql_type::NUMBER)
- {
- return error (ct, "invalid scale in Oracle type "
- "declaration");
- }
-
- t = l.next ();
-
- if (t.type () != sql_token::t_int_lit)
- {
- return error (ct, "integer scale expected in Oracle type "
- "declaration");
- }
-
- short v;
- istringstream is (t.literal ());
-
- if (!(is >> v && is.eof ()))
- {
- return error (ct, "invalid scale value '" + t.literal () +
- "' in Oracle type declaration");
- }
-
- r.scale = true;
- r.scale_value = v;
-
- t = l.next ();
- }
- else if (t.type () == sql_token::t_identifier)
- {
- const string& id (context::upcase (t.identifier ()));
-
- if (id == "CHAR")
- r.byte_semantics = false;
- else if (id != "BYTE")
- {
- return error (ct, "invalid keyword '" + t.literal () +
- "' in Oracle type declaration");
- }
-
- t = l.next ();
- }
-
- if (t.punctuation () != sql_token::p_rparen)
- {
- return error (ct, "expected ')' in Oracle type declaration");
- }
- else
- t = l.next ();
- }
-
- s = r.type == sql_type::invalid ? parse_identifier : parse_done;
- continue;
- }
- case parse_done:
- {
- return error (ct, "unexepected '" + t.literal () + "' in Oracle "
- "type declaration");
- break;
- }
- }
- }
-
- // Some prefixes can also be type names if not followed by the actual
- // type name.
- //
- if (r.type == sql_type::invalid)
- {
- if (!prefix.empty ())
- {
- if (prefix == "CHAR" || prefix == "CHARACTER")
- {
- r.type = sql_type::CHAR;
- r.byte_semantics = true;
- r.prec = true;
- r.prec_value = 1;
- }
- else if (prefix == "NCHAR" ||
- prefix == "NATIONAL CHAR" ||
- prefix == "NATIONAL CHARACTER")
- {
- r.type = sql_type::NCHAR;
- r.byte_semantics = false;
- r.prec = true;
- r.prec_value = 1;
- }
- else if (prefix == "TIMESTAMP")
- {
- r.type = sql_type::TIMESTAMP;
- r.prec = true;
- r.prec_value = 6;
- }
- else
- return error (ct, "incomplete Oracle type declaration: '" +
- prefix + "'");
- }
- else
- return error (ct, "invalid Oracle type declaration");
- }
-
- return r;
- }
- catch (sql_lexer::invalid_input const& e)
- {
- return error (ct, "invalid Oracle type declaration: " + e.message);
- }
- }
- }
-}