summaryrefslogtreecommitdiff
path: root/odb/relational/mssql/context.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/relational/mssql/context.cxx')
-rw-r--r--odb/relational/mssql/context.cxx767
1 files changed, 0 insertions, 767 deletions
diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx
deleted file mode 100644
index 997e322..0000000
--- a/odb/relational/mssql/context.cxx
+++ /dev/null
@@ -1,767 +0,0 @@
-// file : odb/relational/mssql/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/mssql/context.hxx>
-
-using namespace std;
-
-namespace relational
-{
- namespace mssql
- {
- 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", "BIT", 0, false},
-
- {"char", "CHAR(1)", 0, false},
- {"wchar_t", "NCHAR(1)", 0, false},
- {"signed char", "TINYINT", 0, false},
- {"unsigned char", "TINYINT", 0, false},
-
- {"short int", "SMALLINT", 0, false},
- {"short unsigned int", "SMALLINT", 0, false},
-
- {"int", "INT", 0, false},
- {"unsigned int", "INT", 0, false},
-
- {"long int", "BIGINT", 0, false},
- {"long unsigned int", "BIGINT", 0, false},
-
- {"long long int", "BIGINT", 0, false},
- {"long long unsigned int", "BIGINT", 0, false},
-
- {"float", "REAL", 0, false},
- {"double", "FLOAT", 0, false},
-
- {"::std::string", "VARCHAR(512)", "VARCHAR(256)", false},
- {"::std::wstring", "NVARCHAR(512)", "NVARCHAR(256)", false},
-
- {"::size_t", "BIGINT", 0, false},
- {"::std::size_t", "BIGINT", 0, false},
-
- // Windows GUID/UUID (typedef struct _GUID {...} GUID, UUID;).
- //
- {"::_GUID", "UNIQUEIDENTIFIER", 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 = true;
- insert_send_auto_id = false;
- delay_freeing_statement_result = true;
- need_image_clone = true;
- generate_bulk = true;
- global_index = false;
- global_fkey = true;
- data_->bind_vector_ = "mssql::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;
-
- // Warn if the name is greater than the 128 limit.
- //
- if (i->size () > 128)
- {
- cerr << "warning: SQL name '" << *i << "' is longer than the "
- << "SQL Server name limit of 128 characters and will be "
- << "truncated" << endl;
-
- cerr << "info: consider shortening it using #pragma db "
- << "table/column/index or --*-regex options" << endl;
- }
-
- if (f)
- f = false;
- else
- r += '.';
-
- r += '[';
- r.append (*i, 0, 128); // Max identifier length is 128.
- 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 ());
- bool c (bt.is_a<semantics::fund_char> ());
-
- if (c || bt.is_a<semantics::fund_wchar> ())
- {
- unsigned long long n (a->size ());
-
- if (n == 0)
- return r;
- if (n == 1)
- r = c ? "CHAR(" : "NCHAR(";
- else
- {
- r = c ? "VARCHAR(" : "NVARCHAR(";
- n--;
- }
-
- if (n > (c ? 8000 : 4000))
- r += "max)";
- else
- {
- ostringstream ostr;
- ostr << n;
- r += ostr.str ();
- r += ')';
- }
- }
- }
-
- return r;
- }
-
- bool context::
- long_data (sql_type const& st)
- {
- bool r (false);
-
- // The same test as in common.cxx:traverse_simple().
- //
- switch (st.type)
- {
- case sql_type::CHAR:
- case sql_type::VARCHAR:
- case sql_type::BINARY:
- case sql_type::VARBINARY:
- {
- // Zero precision means max in VARCHAR(max).
- //
- if (st.prec == 0 || st.prec > options.mssql_short_limit ())
- r = true;
-
- break;
- }
- case sql_type::NCHAR:
- case sql_type::NVARCHAR:
- {
- // Zero precision means max in NVARCHAR(max). Note that
- // the precision is in 2-byte UCS-2 characters, not bytes.
- //
- if (st.prec == 0 || st.prec * 2 > options.mssql_short_limit ())
- r = true;
-
- break;
- }
- case sql_type::TEXT:
- case sql_type::NTEXT:
- case sql_type::IMAGE:
- {
- r = true;
- break;
- }
- default:
- break;
- }
-
- return r;
- }
-
- //
- // SQL type parsing.
- //
-
- namespace
- {
- struct sql_parser
- {
- typedef context::invalid_sql_type invalid_sql_type;
-
- sql_parser (custom_db_types const* ct): ct_ (ct) {}
-
- sql_type
- parse (std::string sql)
- {
- r_ = sql_type ();
- m_.clear ();
-
- // 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 (sql))
- {
- r_.to = t.type.replace (sql, t.to);
- r_.from = t.type.replace (sql, t.from);
- sql = t.type.replace (sql, t.as);
- break;
- }
- }
- }
-
- l_.lex (sql);
-
- bool ok (true);
-
- try
- {
- ok = parse_name ();
- }
- catch (sql_lexer::invalid_input const& e)
- {
- ok = false;
- m_ = "invalid SQL Server type declaration: " + e.message;
- }
-
- if (!ok)
- {
- if (ct_ == 0)
- return sql_type ();
- else
- throw invalid_sql_type (m_);
- }
-
- return r_;
- }
-
- bool
- parse_name ()
- {
- sql_token t (l_.next ());
-
- if (t.type () != sql_token::t_identifier)
- {
- m_ = "expected SQL Server type name instead of '" +
- t.string () + "'";
- return false;
- }
-
- string id (upcase (t.identifier ()));
-
- if (id == "BIT")
- {
- r_.type = sql_type::BIT;
- }
- else if (id == "TINYINT")
- {
- r_.type = sql_type::TINYINT;
- }
- else if (id == "SMALLINT")
- {
- r_.type = sql_type::SMALLINT;
- }
- else if (id == "INT" ||
- id == "INTEGER")
- {
- r_.type = sql_type::INT;
- }
- else if (id == "BIGINT")
- {
- r_.type = sql_type::BIGINT;
- }
- else if (id == "DECIMAL" ||
- id == "NUMERIC" ||
- id == "DEC")
- {
- r_.type = sql_type::DECIMAL;
-
- r_.has_prec = true;
- r_.prec = 18;
-
- r_.has_scale = true;
- r_.scale = 0;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "SMALLMONEY")
- {
- r_.type = sql_type::SMALLMONEY;
- }
- else if (id == "MONEY")
- {
- r_.type = sql_type::MONEY;
- }
- else if (id == "REAL")
- {
- r_.type = sql_type::FLOAT;
-
- r_.has_prec = true;
- r_.prec = 24;
- }
- else if (id == "FLOAT")
- {
- r_.type = sql_type::FLOAT;
-
- r_.has_prec = true;
- r_.prec = 53;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "DOUBLE")
- {
- t = l_.next ();
-
- if (t.type () != sql_token::t_identifier ||
- upcase (t.identifier ()) != "PRECISION")
- {
- m_ = "expected 'PRECISION' instead of '" + t.string () + "'";
- return false;
- }
-
- r_.type = sql_type::FLOAT;
-
- r_.has_prec = true;
- r_.prec = 53;
-
- // It appears that DOUBLE PRECISION can be followed by the
- // precision specification.
- //
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "CHAR" ||
- id == "CHARACTER")
- {
- if (!parse_char_trailer (false))
- return false;
- }
- else if (id == "VARCHAR")
- {
- r_.type = sql_type::VARCHAR;
-
- r_.has_prec = true;
- r_.prec = 1;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "TEXT")
- {
- r_.type = sql_type::TEXT;
- r_.has_prec = true;
- r_.prec = 0;
- }
- else if (id == "NCHAR")
- {
- r_.type = sql_type::NCHAR;
-
- r_.has_prec = true;
- r_.prec = 1;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "NVARCHAR")
- {
- r_.type = sql_type::NVARCHAR;
-
- r_.has_prec = true;
- r_.prec = 1;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "NTEXT")
- {
- r_.type = sql_type::NTEXT;
- r_.has_prec = true;
- r_.prec = 0;
- }
- else if (id == "NATIONAL")
- {
- t = l_.next ();
-
- if (t.type () == sql_token::t_identifier)
- id = upcase (t.identifier ());
-
- if (id == "TEXT")
- {
- r_.type = sql_type::NTEXT;
- r_.has_prec = true;
- r_.prec = 0;
- }
- else if (id == "CHAR" ||
- id == "CHARACTER")
- {
- if (!parse_char_trailer (true))
- return false;
- }
- else
- {
- m_ = "expected 'CHAR', 'CHARACTER', or 'TEXT' instead of '"
- + t.string () + "'";
- return false;
- }
- }
- else if (id == "BINARY")
- {
- // Can be just BINARY or BINARY VARYING.
- //
- t = l_.next ();
-
- if (t.type () == sql_token::t_identifier)
- id = upcase (t.identifier ());
-
- if (id == "VARYING")
- {
- r_.type = sql_type::VARBINARY;
- t = l_.next ();
- }
- else
- r_.type = sql_type::BINARY;
-
- r_.has_prec = true;
- r_.prec = 1;
-
- if (!parse_precision (t))
- return false;
- }
- else if (id == "VARBINARY")
- {
- r_.type = sql_type::VARBINARY;
-
- r_.has_prec = true;
- r_.prec = 1;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "IMAGE")
- {
- r_.type = sql_type::IMAGE;
- r_.has_prec = true;
- r_.prec = 0;
- }
- else if (id == "DATE")
- {
- r_.type = sql_type::DATE;
- }
- else if (id == "TIME")
- {
- r_.type = sql_type::TIME;
-
- r_.has_scale = true;
- r_.scale = 7;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "DATETIME")
- {
- r_.type = sql_type::DATETIME;
- }
- else if (id == "DATETIME2")
- {
- r_.type = sql_type::DATETIME2;
-
- r_.has_scale = true;
- r_.scale = 7;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "SMALLDATETIME")
- {
- r_.type = sql_type::SMALLDATETIME;
- }
- else if (id == "DATETIMEOFFSET")
- {
- r_.type = sql_type::DATETIMEOFFSET;
-
- r_.has_scale = true;
- r_.scale = 7;
-
- if (!parse_precision (l_.next ()))
- return false;
- }
- else if (id == "UNIQUEIDENTIFIER")
- {
- r_.type = sql_type::UNIQUEIDENTIFIER;
- }
- else if (id == "ROWVERSION" ||
- id == "TIMESTAMP")
- {
- r_.type = sql_type::ROWVERSION;
- }
- else
- {
- m_ = "unexpected SQL Server type name '" + t.identifier () + "'";
- return false;
- }
-
- return true;
- }
-
- bool
- parse_precision (sql_token t)
- {
- if (t.punctuation () == sql_token::p_lparen)
- {
- // Parse the precision.
- //
- t = l_.next ();
-
- if (t.type () == sql_token::t_identifier &&
- upcase (t.identifier ()) == "MAX")
- {
- r_.prec = 0;
- r_.has_prec = true;
- }
- else if (t.type () == sql_token::t_int_lit)
- {
- unsigned short v;
- istringstream is (t.literal ());
-
- if (!(is >> v && is.eof ()))
- {
- m_ = "invalid precision value '" + t.literal () + "' in SQL "
- "Server type declaration";
- return false;
- }
-
- switch (r_.type)
- {
- case sql_type::TIME:
- case sql_type::DATETIME2:
- case sql_type::DATETIMEOFFSET:
- {
- r_.scale = v;
- r_.has_scale = true;
- break;
- }
- default:
- {
- r_.prec = v;
- r_.has_prec = true;
- break;
- }
- }
- }
- else
- {
- m_ = "integer precision expected in SQL Server type declaration";
- return false;
- }
-
- // Parse the scale if present.
- //
- t = l_.next ();
-
- if (t.punctuation () == sql_token::p_comma)
- {
- // Scale can only be specified for the DECIMAL type.
- //
- if (r_.type != sql_type::DECIMAL)
- {
- m_ = "unexpected scale in SQL Server type declaration";
- return false;
- }
-
- t = l_.next ();
-
- if (t.type () != sql_token::t_int_lit)
- {
- m_ = "integer scale expected in SQL Server type declaration";
- return false;
- }
-
- istringstream is (t.literal ());
-
- if (!(is >> r_.scale && is.eof ()))
- {
- m_ = "invalid scale value '" + t.literal () + "' in SQL "
- "Server type declaration";
- return false;
- }
-
- r_.has_scale = true;
- t = l_.next ();
- }
-
- if (t.punctuation () != sql_token::p_rparen)
- {
- m_ = "expected ')' in SQL Server type declaration";
- return false;
- }
- }
-
- return true;
- }
-
- bool
- parse_char_trailer (bool nat)
- {
- sql_token t (l_.next ());
-
- string id;
-
- if (t.type () == sql_token::t_identifier)
- id = upcase (t.identifier ());
-
- if (id == "VARYING")
- {
- r_.type = nat ? sql_type::NVARCHAR : sql_type::VARCHAR;
- t = l_.next ();
- }
- else
- r_.type = nat ? sql_type::NCHAR : sql_type::CHAR;
-
- r_.has_prec = true;
- r_.prec = 1;
-
- return parse_precision (t);
- }
-
- private:
- string
- upcase (string const& s)
- {
- return context::upcase (s);
- }
-
- private:
- custom_db_types const* ct_;
- sql_lexer l_;
- sql_type r_;
- string m_; // Error message.
- };
- }
-
- 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 ();
- }
- }
- }
-
- sql_type context::
- parse_sql_type (string const& sqlt, custom_db_types const* ct)
- {
- sql_parser p (ct);
- return p.parse (sqlt);
- }
- }
-}