~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

few updates and modifications to admin commands

Show diffs side-by-side

added added

removed removed

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