~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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
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
 
 
29
 
#include <iostream>
30
 
 
31
 
namespace drizzled
32
 
{
33
 
 
34
 
bool statement::CreateTable::execute()
35
 
{
36
 
  TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
37
 
  TableList *all_tables= session->lex->query_tables;
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;
41
 
  bool need_start_waiting= false;
42
 
  bool res= false;
43
 
  bool link_to_local= false;
44
 
  bool lex_identified_temp_table= 
45
 
    create_table_message.type() == message::Table::TEMPORARY;
46
 
 
47
 
  if (is_engine_set)
48
 
  {
49
 
    create_info.db_type= 
50
 
      plugin::StorageEngine::findByName(*session, create_table_message.engine().name());
51
 
 
52
 
    if (create_info.db_type == NULL)
53
 
    {
54
 
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
55
 
               create_table_message.engine().name().c_str());
56
 
 
57
 
      return true;
58
 
    }
59
 
  }
60
 
  else /* We now get the default, place it in create_info, and put the engine name in table proto */
61
 
  {
62
 
    create_info.db_type= session->getDefaultStorageEngine();
63
 
  }
64
 
 
65
 
  if (not validateCreateTableOption())
66
 
  {
67
 
    return true;
68
 
  }
69
 
 
70
 
 
71
 
  /* If CREATE TABLE of non-temporary table, do implicit commit */
72
 
  if (not lex_identified_temp_table)
73
 
  {
74
 
    if (not session->endActiveTransaction())
75
 
    {
76
 
      return true;
77
 
    }
78
 
  }
79
 
  /* Skip first table, which is the table we are creating */
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 (not check(new_table_identifier))
90
 
  {
91
 
    /* put tables back for PS rexecuting */
92
 
    session->lex->link_first_table_back(create_table, link_to_local);
93
 
    return true;
94
 
  }
95
 
 
96
 
  /* Might have been updated in create_table_precheck */
97
 
  create_info.alias= create_table->alias;
98
 
 
99
 
  /*
100
 
     The create-select command will open and read-lock the select table
101
 
     and then create, open and write-lock the new table. If a global
102
 
     read lock steps in, we get a deadlock. The write lock waits for
103
 
     the global read lock, while the global read lock waits for the
104
 
     select table to be closed. So we wait until the global readlock is
105
 
     gone before starting both steps. Note that
106
 
     wait_if_global_read_lock() sets a protection against a new global
107
 
     read lock when it succeeds. This needs to be released by
108
 
     start_waiting_global_read_lock(). We protect the normal CREATE
109
 
     TABLE in the same way. That way we avoid that a new table is
110
 
     created during a gobal read lock.
111
 
   */
112
 
  if (! (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
113
 
  {
114
 
    /* put tables back for PS rexecuting */
115
 
    session->lex->link_first_table_back(create_table, link_to_local);
116
 
    return true;
117
 
  }
118
 
 
119
 
  if (select_lex->item_list.elements)           // With select
120
 
  {
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
 
       */
138
 
      if (not lex_identified_temp_table)
139
 
      {
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);
145
 
          /*
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;
154
 
        }
155
 
      }
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)))
171
 
      {
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;
178
 
      }
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
 
    }
198
 
    else
199
 
    {
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();
229
 
 
230
 
  return res;
231
 
}
232
 
 
233
 
bool statement::CreateTable::check(const TableIdentifier &identifier)
234
 
{
235
 
  // Check table name for validity
236
 
  if (not identifier.isValid())
237
 
    return false;
238
 
 
239
 
  // See if any storage engine objects to the name of the file
240
 
  if (not plugin::StorageEngine::canCreateTable(identifier))
241
 
  {
242
 
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", identifier.getSchemaName().c_str());
243
 
 
244
 
    return false;
245
 
  }
246
 
 
247
 
  // Make sure the schema exists, we will do this again during the actual
248
 
  // create for the table.
249
 
  if (not plugin::StorageEngine::doesSchemaExist(identifier))
250
 
  {
251
 
    my_error(ER_BAD_DB_ERROR, MYF(0), identifier.getSchemaName().c_str());
252
 
 
253
 
    return false;
254
 
  }
255
 
 
256
 
  return true;
257
 
}
258
 
 
259
 
bool statement::CreateTable::validateCreateTableOption()
260
 
{
261
 
  bool rc= true;
262
 
  size_t num_engine_options= create_table_message.engine().options_size();
263
 
 
264
 
  assert(create_info.db_type);
265
 
 
266
 
  for (size_t y= 0; y < num_engine_options; ++y)
267
 
  {
268
 
    bool valid= create_info.db_type->validateCreateTableOption(create_table_message.engine().options(y).name(),
269
 
                                                               create_table_message.engine().options(y).state());
270
 
 
271
 
    if (not valid)
272
 
    {
273
 
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
274
 
               create_table_message.engine().options(y).name().c_str(),
275
 
               create_table_message.engine().options(y).state().c_str());
276
 
 
277
 
      rc= false;
278
 
    }
279
 
  }
280
 
 
281
 
  return rc;
282
 
}
283
 
 
284
 
} /* namespace drizzled */
285