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
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>
37
CreateTable::CreateTable(Session *in_session, Table_ident *ident, bool is_temporary) :
38
Statement(in_session),
41
on_update_value(NULL),
43
is_create_table_like(false),
44
lex_identified_temp_table(false),
46
create_table_list(NULL)
48
getSession()->getLex()->sql_command= SQLCOM_CREATE_TABLE;
49
createTableMessage().set_name(ident->table.str, ident->table.length);
51
createTableMessage().set_schema(ident->db.str, ident->db.length);
56
createTableMessage().set_type(message::Table::TEMPORARY);
60
createTableMessage().set_type(message::Table::STANDARD);
64
CreateTable::CreateTable(Session *in_session) :
65
Statement(in_session),
68
on_update_value(NULL),
70
is_create_table_like(false),
71
lex_identified_temp_table(false),
73
create_table_list(NULL)
75
getSession()->getLex()->sql_command= SQLCOM_CREATE_TABLE;
78
} // namespace statement
80
bool statement::CreateTable::execute()
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;
88
is_engine_set= not createTableMessage().engine().name().empty();
92
create_info().db_type=
93
plugin::StorageEngine::findByName(*getSession(), createTableMessage().engine().name());
95
if (create_info().db_type == NULL)
97
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0),
98
createTableMessage().engine().name().c_str());
103
else /* We now get the default, place it in create_info, and put the engine name in table proto */
105
create_info().db_type= getSession()->getDefaultStorageEngine();
108
if (not validateCreateTableOption())
113
if (not lex_identified_temp_table)
115
if (getSession()->inTransaction())
117
my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
121
/* Skip first table, which is the table we are creating */
122
create_table_list= getSession()->lex->unlink_first_table(&link_to_local);
124
drizzled::message::table::init(createTableMessage(), createTableMessage().name(), create_table_list->getSchemaName(), create_info().db_type->getName());
126
identifier::Table new_table_identifier(create_table_list->getSchemaName(),
127
create_table_list->getTableName(),
128
createTableMessage().type());
130
if (not check(new_table_identifier))
132
/* put tables back for PS rexecuting */
133
getSession()->lex->link_first_table_back(create_table_list, link_to_local);
137
/* Might have been updated in create_table_precheck */
138
create_info().alias= create_table_list->alias;
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.
153
if (! (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
155
/* put tables back for PS rexecuting */
156
getSession()->lex->link_first_table_back(create_table_list, link_to_local);
160
bool res= executeInner(new_table_identifier);
163
Release the protection against the global read lock and wake
164
everyone, who might want to set a global read lock.
166
getSession()->startWaitingGlobalReadLock();
171
bool statement::CreateTable::executeInner(identifier::Table::const_reference new_table_identifier)
174
Select_Lex *select_lex= &getSession()->lex->select_lex;
175
TableList *select_tables= getSession()->lex->query_tables;
179
if (select_lex->item_list.elements) // With select
181
Select_Lex_Unit *unit= &getSession()->lex->unit;
182
select_result *result;
184
select_lex->options|= SELECT_NO_UNLOCK;
185
unit->set_limit(select_lex);
187
if (not lex_identified_temp_table)
189
getSession()->lex->link_first_table_back(create_table_list, link_to_local);
190
create_table_list->setCreate(true);
193
if (not (res= getSession()->openTablesLock(getSession()->lex->query_tables)))
196
Is table which we are changing used somewhere in other parts
199
if (not lex_identified_temp_table)
201
TableList *duplicate= NULL;
202
create_table_list= getSession()->lex->unlink_first_table(&link_to_local);
204
if ((duplicate= unique_table(create_table_list, select_tables)))
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);
216
select_create is currently not re-execution friendly and
217
needs to be created for every execution of a PS/SP.
219
if ((result= new select_create(create_table_list,
220
getSession()->getLex()->exists(),
222
createTableMessage(),
224
select_lex->item_list,
225
getSession()->lex->duplicates,
226
getSession()->lex->ignore,
228
new_table_identifier)))
231
CREATE from SELECT give its Select_Lex for SELECT,
232
and item_list belong to SELECT
234
res= handle_select(getSession(), getSession()->lex, result, 0);
238
else if (not lex_identified_temp_table)
240
create_table_list= getSession()->lex->unlink_first_table(&link_to_local);
246
if (is_create_table_like)
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(),
259
for (int32_t x= 0; x < alter_info.alter_proto.added_field_size(); x++)
261
message::Table::Field *field= createTableMessage().add_field();
263
*field= alter_info.alter_proto.added_field(x);
266
res= create_table(getSession(),
267
new_table_identifier,
269
createTableMessage(),
273
getSession()->getLex()->exists());
278
getSession()->my_ok();
286
bool statement::CreateTable::check(const identifier::Table &identifier)
288
// Check table name for validity
289
if (not identifier.isValid())
292
// See if any storage engine objects to the name of the file
293
if (not plugin::StorageEngine::canCreateTable(identifier))
295
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", identifier.getSchemaName().c_str());
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))
304
my_error(ER_BAD_DB_ERROR, MYF(0), identifier.getSchemaName().c_str());
312
bool statement::CreateTable::validateCreateTableOption()
315
size_t num_engine_options= createTableMessage().engine().options_size();
317
assert(create_info().db_type);
319
for (size_t y= 0; y < num_engine_options; ++y)
321
bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
322
createTableMessage().engine().options(y).state());
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());
337
} /* namespace drizzled */