~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: Monty Taylor
  • Date: 2009-03-03 07:39:39 UTC
  • mto: This revision was merged to the branch mainline in revision 910.
  • Revision ID: mordred@inaugust.com-20090303073939-rfswfdo68klfcp1o
Updated comment version indicators to handle drizzle versions.

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
 
 
32
 
#include <iostream>
33
 
 
34
 
namespace drizzled
35
 
{
36
 
 
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
 
bool statement::CreateTable::execute()
83
 
{
84
 
  TableList *first_table= (TableList *) getSession()->getLex()->select_lex.table_list.first;
85
 
  TableList *all_tables= getSession()->getLex()->query_tables;
86
 
  assert(first_table == all_tables && first_table != 0);
87
 
  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();
91
 
 
92
 
  if (is_engine_set)
93
 
  {
94
 
    create_info().db_type= 
95
 
      plugin::StorageEngine::findByName(*getSession(), 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= getSession()->getDefaultStorageEngine();
108
 
  }
109
 
 
110
 
  if (not validateCreateTableOption())
111
 
  {
112
 
    return true;
113
 
  }
114
 
 
115
 
  if (not lex_identified_temp_table)
116
 
  {
117
 
    if (getSession()->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= 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))
133
 
  {
134
 
    /* put tables back for PS rexecuting */
135
 
    getSession()->getLex()->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 (! (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
156
 
  {
157
 
    /* put tables back for PS rexecuting */
158
 
    getSession()->getLex()->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
 
  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 
180
 
  {
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
 
 
189
 
      if (not lex_identified_temp_table)
190
 
      {
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
 
        {
232
 
          /*
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;
238
 
        }
239
 
      }
240
 
      else if (not lex_identified_temp_table)
241
 
      {
242
 
        create_table_list= getSession()->getLex()->unlink_first_table(&link_to_local);
243
 
      }
244
 
    }
245
 
    else
246
 
    {
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);
284
 
 
285
 
  return res;
286
 
}
287
 
 
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
 
bool statement::CreateTable::validateCreateTableOption()
317
 
{
318
 
  bool rc= true;
319
 
  size_t num_engine_options= createTableMessage().engine().options_size();
320
 
 
321
 
  assert(create_info().db_type);
322
 
 
323
 
  for (size_t y= 0; y < num_engine_options; ++y)
324
 
  {
325
 
    bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
326
 
                                                                 createTableMessage().engine().options(y).state());
327
 
 
328
 
    if (not valid)
329
 
    {
330
 
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
331
 
               createTableMessage().engine().options(y).name().c_str(),
332
 
               createTableMessage().engine().options(y).state().c_str());
333
 
 
334
 
      rc= false;
335
 
    }
336
 
  }
337
 
 
338
 
  return rc;
339
 
}
340
 
 
341
 
} /* namespace drizzled */
342