~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

retrieve data from the local cache

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
 
#include <drizzled/message.h>
28
 
#include <drizzled/identifier.h>
29
 
#include <drizzled/plugin/storage_engine.h>
30
 
#include <drizzled/select_create.h>
 
26
#include <drizzled/table_identifier.h>
31
27
 
32
28
#include <iostream>
33
29
 
34
30
namespace drizzled
35
31
{
36
32
 
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
33
bool statement::CreateTable::execute()
83
34
{
84
 
  TableList *first_table= (TableList *) getSession()->getLex()->select_lex.table_list.first;
85
 
  TableList *all_tables= getSession()->getLex()->query_tables;
 
35
  TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
 
36
  TableList *all_tables= session->lex->query_tables;
86
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;
87
40
  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();
 
41
  bool res= false;
 
42
  bool link_to_local= false;
 
43
  bool lex_identified_temp_table= 
 
44
    create_table_message.type() == message::Table::TEMPORARY;
91
45
 
92
46
  if (is_engine_set)
93
47
  {
94
 
    create_info().db_type= 
95
 
      plugin::StorageEngine::findByName(*getSession(), createTableMessage().engine().name());
 
48
    create_info.db_type= 
 
49
      plugin::StorageEngine::findByName(*session, create_table_message.engine().name());
96
50
 
97
 
    if (create_info().db_type == NULL)
 
51
    if (create_info.db_type == NULL)
98
52
    {
99
53
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
100
 
               createTableMessage().engine().name().c_str());
 
54
               create_table_message.name().c_str());
101
55
 
102
56
      return true;
103
57
    }
104
58
  }
105
59
  else /* We now get the default, place it in create_info, and put the engine name in table proto */
106
60
  {
107
 
    create_info().db_type= getSession()->getDefaultStorageEngine();
 
61
    create_info.db_type= session->getDefaultStorageEngine();
108
62
  }
109
63
 
110
64
  if (not validateCreateTableOption())
112
66
    return true;
113
67
  }
114
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 */
115
79
  if (not lex_identified_temp_table)
116
80
  {
117
 
    if (getSession()->inTransaction())
 
81
    if (not session->endActiveTransaction())
118
82
    {
119
 
      my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
120
83
      return true;
121
84
    }
122
85
  }
123
86
  /* 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))
 
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))
133
103
  {
134
104
    /* put tables back for PS rexecuting */
135
 
    getSession()->getLex()->link_first_table_back(create_table_list, link_to_local);
 
105
    session->lex->link_first_table_back(create_table, link_to_local);
136
106
    return true;
137
107
  }
138
108
 
139
109
  /* Might have been updated in create_table_precheck */
140
 
  create_info().alias= create_table_list->alias;
 
110
  create_info.alias= create_table->alias;
141
111
 
142
112
  /*
143
113
     The create-select command will open and read-lock the select table
152
122
     TABLE in the same way. That way we avoid that a new table is
153
123
     created during a gobal read lock.
154
124
   */
155
 
  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)))
156
126
  {
157
127
    /* put tables back for PS rexecuting */
158
 
    getSession()->getLex()->link_first_table_back(create_table_list, link_to_local);
 
128
    session->lex->link_first_table_back(create_table, link_to_local);
159
129
    return true;
160
130
  }
161
131
 
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 
 
132
  if (select_lex->item_list.elements)           // With select
180
133
  {
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
 
 
 
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
       */
189
151
      if (not lex_identified_temp_table)
190
152
      {
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
 
        {
 
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);
232
158
          /*
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;
 
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;
238
166
        }
239
167
      }
240
 
      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)))
241
183
      {
242
 
        create_table_list= getSession()->getLex()->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;
243
190
      }
244
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
    }
245
210
    else
246
211
    {
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);
 
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);
284
241
 
285
242
  return res;
286
243
}
287
244
 
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
245
bool statement::CreateTable::validateCreateTableOption()
317
246
{
318
247
  bool rc= true;
319
 
  size_t num_engine_options= createTableMessage().engine().options_size();
 
248
  size_t num_engine_options= create_table_message.engine().options_size();
320
249
 
321
 
  assert(create_info().db_type);
 
250
  assert(create_info.db_type);
322
251
 
323
252
  for (size_t y= 0; y < num_engine_options; ++y)
324
253
  {
325
 
    bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
326
 
                                                                 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());
327
256
 
328
257
    if (not valid)
329
258
    {
330
259
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
331
 
               createTableMessage().engine().options(y).name().c_str(),
332
 
               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());
333
262
 
334
263
      rc= false;
335
264
    }