~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: Lee
  • Date: 2008-10-30 22:02:01 UTC
  • mto: (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 573.
  • Revision ID: lbieber@lbieber-desktop-20081030220201-elb6qprbzpn7c5a4
add my name to the AUTHORS file

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
 
#include <drizzled/show.h>
23
 
#include <drizzled/lock.h>
24
 
#include <drizzled/session.h>
25
 
#include <drizzled/statement/create_table.h>
26
 
#include <drizzled/message.h>
27
 
#include <drizzled/identifier.h>
28
 
#include <drizzled/plugin/storage_engine.h>
29
 
 
30
 
#include <iostream>
31
 
 
32
 
namespace drizzled
33
 
{
34
 
 
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
 
bool statement::CreateTable::execute()
81
 
{
82
 
  TableList *first_table= (TableList *) getSession()->lex->select_lex.table_list.first;
83
 
  TableList *all_tables= getSession()->lex->query_tables;
84
 
  assert(first_table == all_tables && first_table != 0);
85
 
  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();
89
 
 
90
 
  if (is_engine_set)
91
 
  {
92
 
    create_info().db_type= 
93
 
      plugin::StorageEngine::findByName(*getSession(), createTableMessage().engine().name());
94
 
 
95
 
    if (create_info().db_type == NULL)
96
 
    {
97
 
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
98
 
               createTableMessage().engine().name().c_str());
99
 
 
100
 
      return true;
101
 
    }
102
 
  }
103
 
  else /* We now get the default, place it in create_info, and put the engine name in table proto */
104
 
  {
105
 
    create_info().db_type= getSession()->getDefaultStorageEngine();
106
 
  }
107
 
 
108
 
  if (not validateCreateTableOption())
109
 
  {
110
 
    return true;
111
 
  }
112
 
 
113
 
  if (not lex_identified_temp_table)
114
 
  {
115
 
    if (getSession()->inTransaction())
116
 
    {
117
 
      my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
118
 
      return true;
119
 
    }
120
 
  }
121
 
  /* 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))
131
 
  {
132
 
    /* put tables back for PS rexecuting */
133
 
    getSession()->lex->link_first_table_back(create_table_list, link_to_local);
134
 
    return true;
135
 
  }
136
 
 
137
 
  /* Might have been updated in create_table_precheck */
138
 
  create_info().alias= create_table_list->alias;
139
 
 
140
 
  /*
141
 
     The create-select command will open and read-lock the select table
142
 
     and then create, open and write-lock the new table. If a global
143
 
     read lock steps in, we get a deadlock. The write lock waits for
144
 
     the global read lock, while the global read lock waits for the
145
 
     select table to be closed. So we wait until the global readlock is
146
 
     gone before starting both steps. Note that
147
 
     wait_if_global_read_lock() sets a protection against a new global
148
 
     read lock when it succeeds. This needs to be released by
149
 
     start_waiting_global_read_lock(). We protect the normal CREATE
150
 
     TABLE in the same way. That way we avoid that a new table is
151
 
     created during a gobal read lock.
152
 
   */
153
 
  if (! (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
154
 
  {
155
 
    /* put tables back for PS rexecuting */
156
 
    getSession()->lex->link_first_table_back(create_table_list, link_to_local);
157
 
    return true;
158
 
  }
159
 
 
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 
178
 
  {
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
 
 
187
 
      if (not lex_identified_temp_table)
188
 
      {
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
 
        {
230
 
          /*
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;
236
 
        }
237
 
      }
238
 
      else if (not lex_identified_temp_table)
239
 
      {
240
 
        create_table_list= getSession()->lex->unlink_first_table(&link_to_local);
241
 
      }
242
 
    }
243
 
    else
244
 
    {
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);
282
 
 
283
 
  return res;
284
 
}
285
 
 
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
 
bool statement::CreateTable::validateCreateTableOption()
313
 
{
314
 
  bool rc= true;
315
 
  size_t num_engine_options= createTableMessage().engine().options_size();
316
 
 
317
 
  assert(create_info().db_type);
318
 
 
319
 
  for (size_t y= 0; y < num_engine_options; ++y)
320
 
  {
321
 
    bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
322
 
                                                                 createTableMessage().engine().options(y).state());
323
 
 
324
 
    if (not valid)
325
 
    {
326
 
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
327
 
               createTableMessage().engine().options(y).name().c_str(),
328
 
               createTableMessage().engine().options(y).state().c_str());
329
 
 
330
 
      rc= false;
331
 
    }
332
 
  }
333
 
 
334
 
  return rc;
335
 
}
336
 
 
337
 
} /* namespace drizzled */
338