~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2009 Sun Microsystems, Inc.
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
 
 
23
#include <drizzled/show.h>
 
24
#include <drizzled/lock.h>
 
25
#include <drizzled/session.h>
 
26
#include <drizzled/statement/create_table.h>
 
27
#include <drizzled/message.h>
 
28
#include <drizzled/identifier.h>
 
29
#include <drizzled/plugin/storage_engine.h>
 
30
#include <drizzled/select_create.h>
 
31
#include <drizzled/table_ident.h>
 
32
 
 
33
#include <iostream>
 
34
 
 
35
namespace drizzled
 
36
{
 
37
 
 
38
namespace statement {
 
39
 
 
40
CreateTable::CreateTable(Session *in_session, Table_ident *ident, bool is_temporary) :
 
41
  Statement(in_session),
 
42
  change(NULL),
 
43
  default_value(NULL),
 
44
  on_update_value(NULL),
 
45
  is_engine_set(false),
 
46
  is_create_table_like(false),
 
47
  lex_identified_temp_table(false),
 
48
  link_to_local(false),
 
49
  create_table_list(NULL)
 
50
{
 
51
  set_command(SQLCOM_CREATE_TABLE);
 
52
  createTableMessage().set_name(ident->table.str, ident->table.length);
 
53
#if 0
 
54
  createTableMessage().set_schema(ident->db.str, ident->db.length);
 
55
#endif
 
56
 
 
57
  if (is_temporary)
 
58
  {
 
59
    createTableMessage().set_type(message::Table::TEMPORARY);
 
60
  }
 
61
  else
 
62
  {
 
63
    createTableMessage().set_type(message::Table::STANDARD);
 
64
  }
 
65
}
 
66
 
 
67
CreateTable::CreateTable(Session *in_session) :
 
68
  Statement(in_session),
 
69
  change(NULL),
 
70
  default_value(NULL),
 
71
  on_update_value(NULL),
 
72
  is_engine_set(false),
 
73
  is_create_table_like(false),
 
74
  lex_identified_temp_table(false),
 
75
  link_to_local(false),
 
76
  create_table_list(NULL)
 
77
{
 
78
  set_command(SQLCOM_CREATE_TABLE);
 
79
}
 
80
 
 
81
} // namespace statement
 
82
 
 
83
bool statement::CreateTable::execute()
 
84
{
 
85
  TableList *first_table= (TableList *) lex().select_lex.table_list.first;
 
86
  TableList *all_tables= lex().query_tables;
 
87
  assert(first_table == all_tables && first_table != 0);
 
88
  lex_identified_temp_table= createTableMessage().type() == message::Table::TEMPORARY;
 
89
 
 
90
  is_engine_set= not createTableMessage().engine().name().empty();
 
91
 
 
92
  if (is_engine_set)
 
93
  {
 
94
    create_info().db_type= 
 
95
      plugin::StorageEngine::findByName(session(), createTableMessage().engine().name());
 
96
 
 
97
    if (create_info().db_type == NULL)
 
98
    {
 
99
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
 
100
               createTableMessage().engine().name().c_str());
 
101
 
 
102
      return true;
 
103
    }
 
104
  }
 
105
  else /* We now get the default, place it in create_info, and put the engine name in table proto */
 
106
  {
 
107
    create_info().db_type= session().getDefaultStorageEngine();
 
108
  }
 
109
 
 
110
  if (not validateCreateTableOption())
 
111
  {
 
112
    return true;
 
113
  }
 
114
 
 
115
  if (not lex_identified_temp_table)
 
116
  {
 
117
    if (session().inTransaction())
 
118
    {
 
119
      my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
 
120
      return true;
 
121
    }
 
122
  }
 
123
  /* Skip first table, which is the table we are creating */
 
124
  create_table_list= lex().unlink_first_table(&link_to_local);
 
125
 
 
126
  drizzled::message::table::init(createTableMessage(), createTableMessage().name(), create_table_list->getSchemaName(), create_info().db_type->getName());
 
127
 
 
128
  identifier::Table new_table_identifier(create_table_list->getSchemaName(),
 
129
                                       create_table_list->getTableName(),
 
130
                                       createTableMessage().type());
 
131
 
 
132
  if (not check(new_table_identifier))
 
133
  {
 
134
    /* put tables back for PS rexecuting */
 
135
    lex().link_first_table_back(create_table_list, link_to_local);
 
136
    return true;
 
137
  }
 
138
 
 
139
  /* Might have been updated in create_table_precheck */
 
140
  create_info().alias= create_table_list->alias;
 
141
 
 
142
  /*
 
143
     The create-select command will open and read-lock the select table
 
144
     and then create, open and write-lock the new table. If a global
 
145
     read lock steps in, we get a deadlock. The write lock waits for
 
146
     the global read lock, while the global read lock waits for the
 
147
     select table to be closed. So we wait until the global readlock is
 
148
     gone before starting both steps. Note that
 
149
     wait_if_global_read_lock() sets a protection against a new global
 
150
     read lock when it succeeds. This needs to be released by
 
151
     start_waiting_global_read_lock(). We protect the normal CREATE
 
152
     TABLE in the same way. That way we avoid that a new table is
 
153
     created during a gobal read lock.
 
154
   */
 
155
  if (session().wait_if_global_read_lock(0, 1))
 
156
  {
 
157
    /* put tables back for PS rexecuting */
 
158
    lex().link_first_table_back(create_table_list, link_to_local);
 
159
    return true;
 
160
  }
 
161
 
 
162
  bool res= executeInner(new_table_identifier);
 
163
 
 
164
  /*
 
165
    Release the protection against the global read lock and wake
 
166
    everyone, who might want to set a global read lock.
 
167
  */
 
168
  session().startWaitingGlobalReadLock();
 
169
 
 
170
  return res;
 
171
}
 
172
 
 
173
bool statement::CreateTable::executeInner(const identifier::Table& new_table_identifier)
 
174
{
 
175
  bool res= false;
 
176
  Select_Lex *select_lex= &lex().select_lex;
 
177
  TableList *select_tables= lex().query_tables;
 
178
 
 
179
  do 
 
180
  {
 
181
    if (select_lex->item_list.size())           // With select
 
182
    {
 
183
      Select_Lex_Unit *unit= &lex().unit;
 
184
      select_result *result;
 
185
 
 
186
      select_lex->options|= SELECT_NO_UNLOCK;
 
187
      unit->set_limit(select_lex);
 
188
 
 
189
      if (not lex_identified_temp_table)
 
190
      {
 
191
        lex().link_first_table_back(create_table_list, link_to_local);
 
192
        create_table_list->setCreate(true);
 
193
      }
 
194
 
 
195
      if (not (res= session().openTablesLock(lex().query_tables)))
 
196
      {
 
197
        /*
 
198
          Is table which we are changing used somewhere in other parts
 
199
          of query
 
200
        */
 
201
        if (not lex_identified_temp_table)
 
202
        {
 
203
          create_table_list= lex().unlink_first_table(&link_to_local);
 
204
 
 
205
          if (unique_table(create_table_list, select_tables))
 
206
          {
 
207
            my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table_list->alias);
 
208
            /* put tables back for PS rexecuting */
 
209
            lex().link_first_table_back(create_table_list, link_to_local);
 
210
 
 
211
            res= true;
 
212
            break;
 
213
          }
 
214
        }
 
215
 
 
216
        /*
 
217
          select_create is currently not re-execution friendly and
 
218
          needs to be created for every execution of a PS/SP.
 
219
        */
 
220
        if ((result= new select_create(create_table_list,
 
221
                                       lex().exists(),
 
222
                                       &create_info(),
 
223
                                       createTableMessage(),
 
224
                                       &alter_info,
 
225
                                       select_lex->item_list,
 
226
                                       lex().duplicates,
 
227
                                       lex().ignore,
 
228
                                       select_tables,
 
229
                                       new_table_identifier)))
 
230
        {
 
231
          /*
 
232
            CREATE from SELECT give its Select_Lex for SELECT,
 
233
            and item_list belong to SELECT
 
234
          */
 
235
          res= handle_select(&session(), &lex(), result, 0);
 
236
          delete result;
 
237
        }
 
238
      }
 
239
      else if (not lex_identified_temp_table)
 
240
      {
 
241
        create_table_list= lex().unlink_first_table(&link_to_local);
 
242
      }
 
243
    }
 
244
    else
 
245
    {
 
246
      /* regular create */
 
247
      if (is_create_table_like)
 
248
      {
 
249
        res= create_like_table(&session(), 
 
250
                               new_table_identifier,
 
251
                               identifier::Table(select_tables->getSchemaName(),
 
252
                                                 select_tables->getTableName()),
 
253
                               createTableMessage(),
 
254
                               lex().exists(),
 
255
                               is_engine_set);
 
256
      }
 
257
      else
 
258
      {
 
259
 
 
260
        for (int32_t x= 0; x < alter_info.added_fields_proto.added_field_size(); x++)
 
261
        {
 
262
          message::Table::Field *field= createTableMessage().add_field();
 
263
 
 
264
          *field= alter_info.added_fields_proto.added_field(x);
 
265
        }
 
266
 
 
267
        res= create_table(&session(), 
 
268
                          new_table_identifier,
 
269
                          &create_info(),
 
270
                          createTableMessage(),
 
271
                          &alter_info, 
 
272
                          false, 
 
273
                          0,
 
274
                          lex().exists());
 
275
      }
 
276
 
 
277
      if (not res)
 
278
      {
 
279
        session().my_ok();
 
280
      }
 
281
    }
 
282
  } while (0);
 
283
 
 
284
  return res;
 
285
}
 
286
 
 
287
bool statement::CreateTable::check(const identifier::Table &identifier)
 
288
{
 
289
  // Check table name for validity
 
290
  if (not identifier.isValid())
 
291
    return false;
 
292
 
 
293
  // See if any storage engine objects to the name of the file
 
294
  if (not plugin::StorageEngine::canCreateTable(identifier))
 
295
  {
 
296
    identifier::Schema schema_identifier= identifier;
 
297
    error::access(*session().user(), schema_identifier);
 
298
 
 
299
    return false;
 
300
  }
 
301
 
 
302
  // Make sure the schema exists, we will do this again during the actual
 
303
  // create for the table.
 
304
  if (not plugin::StorageEngine::doesSchemaExist(identifier))
 
305
  {
 
306
    identifier::Schema schema_identifier= identifier;
 
307
    my_error(ER_BAD_DB_ERROR, schema_identifier);
 
308
 
 
309
    return false;
 
310
  }
 
311
 
 
312
  return true;
 
313
}
 
314
 
 
315
bool statement::CreateTable::validateCreateTableOption()
 
316
{
 
317
  bool rc= true;
 
318
  size_t num_engine_options= createTableMessage().engine().options_size();
 
319
 
 
320
  assert(create_info().db_type);
 
321
 
 
322
  for (size_t y= 0; y < num_engine_options; ++y)
 
323
  {
 
324
    bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
 
325
                                                                 createTableMessage().engine().options(y).state());
 
326
 
 
327
    if (not valid)
 
328
    {
 
329
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
 
330
               createTableMessage().engine().options(y).name().c_str(),
 
331
               createTableMessage().engine().options(y).state().c_str());
 
332
 
 
333
      rc= false;
 
334
    }
 
335
  }
 
336
 
 
337
  return rc;
 
338
}
 
339
 
 
340
} /* namespace drizzled */
 
341