~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: lbieber
  • Date: 2010-10-01 12:16:18 UTC
  • mfrom: (1802.1.1 fix-bug-651256)
  • Revision ID: lbieber@orisndriz08-20101001121618-uqcboygpjwbiglem
Merge Vijay - fix bug 651256 - Remove --help-extended

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