aboutsummaryrefslogtreecommitdiff
path: root/odb/relational/mysql/model.cxx
blob: 4d38a4ece20eb0bb20d305125f045365d5351d47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// file      : odb/relational/mysql/model.cxx
// copyright : Copyright (c) 2009-2017 Code Synthesis Tools CC
// license   : GNU GPL v3; see accompanying LICENSE file

#include <sstream>

#include <odb/relational/model.hxx>
#include <odb/relational/mysql/context.hxx>

using namespace std;

namespace relational
{
  namespace mysql
  {
    namespace model
    {
      namespace relational = relational::model;

      struct object_columns: relational::object_columns, context
      {
        object_columns (base const& x): base (x) {}

        virtual string
        default_bool (semantics::data_member&, bool v)
        {
          // MySQL has TRUE and FALSE as just aliases for 1 and 0. Still
          // use them for self-documentation.
          //
          return v ? "TRUE" : "FALSE";
        }

        virtual string
        default_enum (semantics::data_member& m, tree en, string const& name)
        {
          // Make sure the column is mapped to an ENUM or integer type.
          //
          sql_type const& t (parse_sql_type (column_type (), m, false));

          switch (t.type)
          {
          case sql_type::ENUM:
          case sql_type::TINYINT:
          case sql_type::SMALLINT:
          case sql_type::MEDIUMINT:
          case sql_type::INT:
          case sql_type::BIGINT:
            break;
          default:
            {
              cerr << m.file () << ":" << m.line () << ":" << m.column ()
                   << ": error: column with default value specified as C++ "
                   << "enumerator must map to MySQL ENUM or integer type"
                   << endl;

              throw operation_failed ();
            }
          }

          using semantics::enum_;
          using semantics::enumerator;

          enumerator& er (dynamic_cast<enumerator&> (*unit.find (en)));
          enum_& e (er.enum_ ());

          if (t.type == sql_type::ENUM)
          {
            // Assuming the enumerators in the C++ enum and MySQL ENUM are
            // in the same order, calculate the poistion of the C++
            // enumerator and use that as an index in the MySQL ENUM.
            //
            size_t pos (0);

            for (enum_::enumerates_iterator i (e.enumerates_begin ()),
                   end (e.enumerates_end ()); i != end; ++i)
            {
              if (&i->enumerator () == &er)
                break;

              pos++;
            }

            if (pos < t.enumerators.size ())
              return t.enumerators[pos];
            else
            {
              cerr << m.file () << ":" << m.line () << ":" << m.column ()
                   << ": error: unable to map C++ enumerator '" << name
                   << "' to MySQL ENUM value" << endl;

              throw operation_failed ();
            }
          }
          else
          {
            ostringstream ostr;

            if (e.unsigned_ ())
              ostr << er.value ();
            else
              ostr << static_cast<long long> (er.value ());

            return ostr.str ();
          }
        }
      };
      entry<object_columns> object_columns_;

      struct member_create: relational::member_create, context
      {
        member_create (base const& x): base (x) {}

        virtual string
        table_options (semantics::data_member&, semantics::type&)
        {
          string const& engine (options.mysql_engine ());
          return engine != "default" ? "ENGINE=" + engine : "";
        }
      };
      entry<member_create> member_create_;

      struct class_: relational::class_, context
      {
        class_ (base const& x): base (x) {}

        virtual string
        table_options (type&)
        {
          string const& engine (options.mysql_engine ());
          return engine != "default" ? "ENGINE=" + engine : "";
        }
      };
      entry<class_> class__;
    }
  }
}