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>
39
CreateTable::CreateTable(Session *in_session, Table_ident *ident, bool is_temporary) :
40
Statement(in_session),
43
on_update_value(NULL),
45
is_create_table_like(false),
46
lex_identified_temp_table(false),
48
create_table_list(NULL)
50
getSession()->getLex()->sql_command= SQLCOM_CREATE_TABLE;
51
createTableMessage().set_name(ident->table.str, ident->table.length);
53
createTableMessage().set_schema(ident->db.str, ident->db.length);
58
createTableMessage().set_type(message::Table::TEMPORARY);
62
createTableMessage().set_type(message::Table::STANDARD);
66
CreateTable::CreateTable(Session *in_session) :
67
Statement(in_session),
70
on_update_value(NULL),
72
is_create_table_like(false),
73
lex_identified_temp_table(false),
75
create_table_list(NULL)
77
getSession()->getLex()->sql_command= SQLCOM_CREATE_TABLE;
80
} // namespace statement
82
bool statement::CreateTable::execute()
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;
90
is_engine_set= not createTableMessage().engine().name().empty();
94
create_info().db_type=
95
plugin::StorageEngine::findByName(*getSession(), 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= getSession()->getDefaultStorageEngine();
110
if (not validateCreateTableOption())
115
if (not lex_identified_temp_table)
117
if (getSession()->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= getSession()->getLex()->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
getSession()->getLex()->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 (! (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
157
/* put tables back for PS rexecuting */
158
getSession()->getLex()->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
getSession()->startWaitingGlobalReadLock();
173
bool statement::CreateTable::executeInner(identifier::Table::const_reference new_table_identifier)
176
Select_Lex *select_lex= &getSession()->getLex()->select_lex;
177
TableList *select_tables= getSession()->getLex()->query_tables;
181
if (select_lex->item_list.elements) // With select
183
Select_Lex_Unit *unit= &getSession()->getLex()->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
getSession()->getLex()->link_first_table_back(create_table_list, link_to_local);
192
create_table_list->setCreate(true);
195
if (not (res= getSession()->openTablesLock(getSession()->getLex()->query_tables)))
198
Is table which we are changing used somewhere in other parts
201
if (not lex_identified_temp_table)
203
TableList *duplicate= NULL;
204
create_table_list= getSession()->getLex()->unlink_first_table(&link_to_local);
206
if ((duplicate= unique_table(create_table_list, select_tables)))
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);
218
select_create is currently not re-execution friendly and
219
needs to be created for every execution of a PS/SP.
221
if ((result= new select_create(create_table_list,
222
getSession()->getLex()->exists(),
224
createTableMessage(),
226
select_lex->item_list,
227
getSession()->getLex()->duplicates,
228
getSession()->getLex()->ignore,
230
new_table_identifier)))
233
CREATE from SELECT give its Select_Lex for SELECT,
234
and item_list belong to SELECT
236
res= handle_select(getSession(), getSession()->getLex(), result, 0);
240
else if (not lex_identified_temp_table)
242
create_table_list= getSession()->getLex()->unlink_first_table(&link_to_local);
248
if (is_create_table_like)
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(),
261
for (int32_t x= 0; x < alter_info.alter_proto.added_field_size(); x++)
263
message::Table::Field *field= createTableMessage().add_field();
265
*field= alter_info.alter_proto.added_field(x);
268
res= create_table(getSession(),
269
new_table_identifier,
271
createTableMessage(),
275
getSession()->getLex()->exists());
280
getSession()->my_ok();
288
bool statement::CreateTable::check(const identifier::Table &identifier)
290
// Check table name for validity
291
if (not identifier.isValid())
294
// See if any storage engine objects to the name of the file
295
if (not plugin::StorageEngine::canCreateTable(identifier))
297
identifier::Schema schema_identifier= identifier;
298
error::access(*getSession()->user(), schema_identifier);
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))
307
identifier::Schema schema_identifier= identifier;
308
my_error(ER_BAD_DB_ERROR, schema_identifier);
316
bool statement::CreateTable::validateCreateTableOption()
319
size_t num_engine_options= createTableMessage().engine().options_size();
321
assert(create_info().db_type);
323
for (size_t y= 0; y < num_engine_options; ++y)
325
bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
326
createTableMessage().engine().options(y).state());
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());
341
} /* namespace drizzled */