summaryrefslogtreecommitdiff
path: root/odb/relational/sqlite/schema.cxx
blob: 6d3cba4f816852d8ae2d332074ec6f53e1bc6476 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// file      : odb/relational/sqlite/schema.cxx
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license   : GNU GPL v3; see accompanying LICENSE file

#include <odb/relational/schema.hxx>

#include <odb/relational/sqlite/common.hxx>
#include <odb/relational/sqlite/context.hxx>

namespace relational
{
  namespace sqlite
  {
    namespace schema
    {
      namespace relational = relational::schema;

      //
      // Create.
      //

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

        virtual void
        traverse (sema_rel::add_column& ac)
        {
          using sema_rel::alter_table;
          alter_table& at (static_cast<alter_table&> (ac.scope ()));

          pre_statement ();

          os << "ALTER TABLE " << quote_id (at.name ()) << endl
             << "  ADD COLUMN ";
          create (ac);
          os << endl;

          post_statement ();
        }

        virtual void
        auto_ (sema_rel::column&)
        {
          if (options.sqlite_lax_auto_id ())
            os << " /*AUTOINCREMENT*/";
          else
            os << " AUTOINCREMENT";
        }
      };
      entry<create_column> create_column_;

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

        virtual string
        table_name (sema_rel::foreign_key& fk)
        {
          // In SQLite, the referenced table cannot be qualified with the
          // database name (it has to be in the same database anyway).
          //
          return quote_id (fk.referenced_table ().uname ());
        }
      };
      entry<create_foreign_key> create_foreign_key_;

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

        virtual string
        name (sema_rel::index& in)
        {
          // In SQLite, index names can be qualified with the database.
          //
          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);
        }

        virtual string
        table_name (sema_rel::index& in)
        {
          // In SQLite, the index table cannot be qualified with the
          // database name (it has to be in the same database).
          //
          return quote_id (
            static_cast<sema_rel::table&> (in.scope ()).name ().uname ());
        }
      };
      entry<create_index> create_index_;

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

        virtual string
        name (sema_rel::index& in)
        {
          // In SQLite, index names can be qualified with the database.
          //
          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);
        }
      };
      entry<drop_index> drop_index_;

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

        virtual void
        alter (sema_rel::alter_table& at)
        {
          // SQLite can only add a single column per ALTER TABLE statement.
          //
          instance<create_column> c (emitter (), stream (), format_);
          trav_rel::unames n;
          n >> c;
          names (at, n);

          // SQLite does not support altering columns.
          //
          if (sema_rel::alter_column* ac = check<sema_rel::alter_column> (at))
          {
            cerr << "error: SQLite does not support altering of columns"
                 << endl;
            cerr << "info: first altered column is '" << ac->name () <<
              "' in table '" << at.name () << "'" << endl;
            throw operation_failed ();
          }
        }
      };
      entry<alter_table_pre> alter_table_pre_;

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

        virtual void
        alter (sema_rel::alter_table& at)
        {
          // SQLite does not support dropping columns.
          //
          if (sema_rel::drop_column* dc = check<sema_rel::drop_column> (at))
          {
            cerr << "error: SQLite does not support dropping of columns"
                 << endl;
            cerr << "info: first dropped column is '" << dc->name () <<
              "' in table '" << at.name () << "'" << endl;
            throw operation_failed ();
          }
        }
      };
      entry<alter_table_post> alter_table_post_;
    }
  }
}