1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2009 Sun Microsystems, Inc.
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.
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.
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
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
#include <drizzled/table_ident.h>
40
CreateTable::CreateTable(Session *in_session, Table_ident *ident, bool is_temporary) :
41
Statement(in_session),
44
on_update_value(NULL),
46
is_create_table_like(false),
47
lex_identified_temp_table(false),
49
create_table_list(NULL)
51
set_command(SQLCOM_CREATE_TABLE);
52
createTableMessage().set_name(ident->table.str, ident->table.length);
54
createTableMessage().set_schema(ident->db.str, ident->db.length);
59
createTableMessage().set_type(message::Table::TEMPORARY);
63
createTableMessage().set_type(message::Table::STANDARD);
67
CreateTable::CreateTable(Session *in_session) :
68
Statement(in_session),
71
on_update_value(NULL),
73
is_create_table_like(false),
74
lex_identified_temp_table(false),
76
create_table_list(NULL)
78
set_command(SQLCOM_CREATE_TABLE);
81
} // namespace statement
83
bool statement::CreateTable::execute()
85
TableList *first_table= (TableList *) lex().select_lex.table_list.first;
86
TableList *all_tables= lex().query_tables;
87
assert(first_table == all_tables && first_table != 0);
88
lex_identified_temp_table= createTableMessage().type() == message::Table::TEMPORARY;
90
is_engine_set= not createTableMessage().engine().name().empty();
94
create_info().db_type=
95
plugin::StorageEngine::findByName(session(), createTableMessage().engine().name());
97
if (create_info().db_type == NULL)
99
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0),
100
createTableMessage().engine().name().c_str());
105
else /* We now get the default, place it in create_info, and put the engine name in table proto */
107
create_info().db_type= session().getDefaultStorageEngine();
110
if (not validateCreateTableOption())
115
if (not lex_identified_temp_table)
117
if (session().inTransaction())
119
my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
123
/* Skip first table, which is the table we are creating */
124
create_table_list= lex().unlink_first_table(&link_to_local);
126
drizzled::message::table::init(createTableMessage(), createTableMessage().name(), create_table_list->getSchemaName(), create_info().db_type->getName());
128
identifier::Table new_table_identifier(create_table_list->getSchemaName(),
129
create_table_list->getTableName(),
130
createTableMessage().type());
132
if (not check(new_table_identifier))
134
/* put tables back for PS rexecuting */
135
lex().link_first_table_back(create_table_list, link_to_local);
139
/* Might have been updated in create_table_precheck */
140
create_info().alias= create_table_list->alias;
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.
155
if (session().wait_if_global_read_lock(0, 1))
157
/* put tables back for PS rexecuting */
158
lex().link_first_table_back(create_table_list, link_to_local);
162
bool res= executeInner(new_table_identifier);
165
Release the protection against the global read lock and wake
166
everyone, who might want to set a global read lock.
168
session().startWaitingGlobalReadLock();
173
bool statement::CreateTable::executeInner(const identifier::Table& new_table_identifier)
176
Select_Lex *select_lex= &lex().select_lex;
177
TableList *select_tables= lex().query_tables;
181
if (select_lex->item_list.size()) // With select
183
Select_Lex_Unit *unit= &lex().unit;
184
select_result *result;
186
select_lex->options|= SELECT_NO_UNLOCK;
187
unit->set_limit(select_lex);
189
if (not lex_identified_temp_table)
191
lex().link_first_table_back(create_table_list, link_to_local);
192
create_table_list->setCreate(true);
195
if (not (res= session().openTablesLock(lex().query_tables)))
198
Is table which we are changing used somewhere in other parts
201
if (not lex_identified_temp_table)
203
create_table_list= lex().unlink_first_table(&link_to_local);
205
if (unique_table(create_table_list, select_tables))
207
my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table_list->alias);
208
/* put tables back for PS rexecuting */
209
lex().link_first_table_back(create_table_list, link_to_local);
217
select_create is currently not re-execution friendly and
218
needs to be created for every execution of a PS/SP.
220
if ((result= new select_create(create_table_list,
223
createTableMessage(),
225
select_lex->item_list,
229
new_table_identifier)))
232
CREATE from SELECT give its Select_Lex for SELECT,
233
and item_list belong to SELECT
235
res= handle_select(&session(), &lex(), result, 0);
239
else if (not lex_identified_temp_table)
241
create_table_list= lex().unlink_first_table(&link_to_local);
247
if (is_create_table_like)
249
res= create_like_table(&session(),
250
new_table_identifier,
251
identifier::Table(select_tables->getSchemaName(),
252
select_tables->getTableName()),
253
createTableMessage(),
260
for (int32_t x= 0; x < alter_info.added_fields_proto.added_field_size(); x++)
262
message::Table::Field *field= createTableMessage().add_field();
264
*field= alter_info.added_fields_proto.added_field(x);
267
res= create_table(&session(),
268
new_table_identifier,
270
createTableMessage(),
287
bool statement::CreateTable::check(const identifier::Table &identifier)
289
// Check table name for validity
290
if (not identifier.isValid())
293
// See if any storage engine objects to the name of the file
294
if (not plugin::StorageEngine::canCreateTable(identifier))
296
identifier::Schema schema_identifier= identifier;
297
error::access(*session().user(), schema_identifier);
302
// Make sure the schema exists, we will do this again during the actual
303
// create for the table.
304
if (not plugin::StorageEngine::doesSchemaExist(identifier))
306
identifier::Schema schema_identifier= identifier;
307
my_error(ER_BAD_DB_ERROR, schema_identifier);
315
bool statement::CreateTable::validateCreateTableOption()
318
size_t num_engine_options= createTableMessage().engine().options_size();
320
assert(create_info().db_type);
322
for (size_t y= 0; y < num_engine_options; ++y)
324
bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
325
createTableMessage().engine().options(y).state());
329
my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
330
createTableMessage().engine().options(y).name().c_str(),
331
createTableMessage().engine().options(y).state().c_str());
340
} /* namespace drizzled */