Drizzled Public API Documentation

create_table.cc
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 
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>
32 #include <drizzled/catalog/instance.h>
33 
34 #include <iostream>
35 
36 namespace drizzled {
37 namespace statement {
38 
39 CreateTable::CreateTable(Session *in_session, Table_ident *ident, bool is_temporary) :
40  Statement(in_session),
41  change(NULL),
42  default_value(NULL),
43  on_update_value(NULL),
44  is_engine_set(false),
45  is_create_table_like(false),
46  lex_identified_temp_table(false),
47  link_to_local(false),
48  create_table_list(NULL)
49 {
50  set_command(SQLCOM_CREATE_TABLE);
51  createTableMessage().set_name(ident->table.data(), ident->table.size());
52 #if 0
53  createTableMessage().set_schema(ident->db.data(), ident->db.size());
54 #endif
55 
56  createTableMessage().set_type(is_temporary ? message::Table::TEMPORARY : message::Table::STANDARD);
57 }
58 
59 CreateTable::CreateTable(Session *in_session) :
60  Statement(in_session),
61  change(NULL),
62  default_value(NULL),
63  on_update_value(NULL),
64  is_engine_set(false),
65  is_create_table_like(false),
66  lex_identified_temp_table(false),
67  link_to_local(false),
68  create_table_list(NULL)
69 {
70  set_command(SQLCOM_CREATE_TABLE);
71 }
72 
73 } // namespace statement
74 
76 {
77  TableList *first_table= (TableList *) lex().select_lex.table_list.first;
78  TableList *all_tables= lex().query_tables;
79  assert(first_table == all_tables && first_table != 0);
80  lex_identified_temp_table= createTableMessage().type() == message::Table::TEMPORARY;
81 
82  is_engine_set= not createTableMessage().engine().name().empty();
83 
84  if (is_engine_set)
85  {
86  create_info().db_type=
87  plugin::StorageEngine::findByName(session(), createTableMessage().engine().name());
88 
89  if (create_info().db_type == NULL)
90  {
91  my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0),
92  createTableMessage().engine().name().c_str());
93 
94  return true;
95  }
96  }
97  else /* We now get the default, place it in create_info, and put the engine name in table proto */
98  {
99  create_info().db_type= session().getDefaultStorageEngine();
100  }
101 
102  if (not validateCreateTableOption())
103  {
104  return true;
105  }
106 
107  if (not lex_identified_temp_table)
108  {
109  if (session().inTransaction())
110  {
111  my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
112  return true;
113  }
114  }
115  /* Skip first table, which is the table we are creating */
116  create_table_list= lex().unlink_first_table(&link_to_local);
117 
118  drizzled::message::table::init(createTableMessage(), createTableMessage().name(), create_table_list->getSchemaName(), create_info().db_type->getName());
119 
120  identifier::Table new_table_identifier(session().catalog().identifier(),
121  create_table_list->getSchemaName(),
122  create_table_list->getTableName(),
123  createTableMessage().type());
124 
125  if (not check(new_table_identifier))
126  {
127  /* put tables back for PS rexecuting */
128  lex().link_first_table_back(create_table_list, link_to_local);
129  return true;
130  }
131 
132  /* Might have been updated in create_table_precheck */
133  create_info().alias= create_table_list->alias;
134 
135  /*
136  The create-select command will open and read-lock the select table
137  and then create, open and write-lock the new table. If a global
138  read lock steps in, we get a deadlock. The write lock waits for
139  the global read lock, while the global read lock waits for the
140  select table to be closed. So we wait until the global readlock is
141  gone before starting both steps. Note that
142  wait_if_global_read_lock() sets a protection against a new global
143  read lock when it succeeds. This needs to be released by
144  start_waiting_global_read_lock(). We protect the normal CREATE
145  TABLE in the same way. That way we avoid that a new table is
146  created during a gobal read lock.
147  */
148  if (session().wait_if_global_read_lock(0, 1))
149  {
150  /* put tables back for PS rexecuting */
151  lex().link_first_table_back(create_table_list, link_to_local);
152  return true;
153  }
154 
155  bool res= executeInner(new_table_identifier);
156 
157  /*
158  Release the protection against the global read lock and wake
159  everyone, who might want to set a global read lock.
160  */
161  session().startWaitingGlobalReadLock();
162 
163  return res;
164 }
165 
166 bool statement::CreateTable::executeInner(const identifier::Table& new_table_identifier)
167 {
168  bool res= false;
169  Select_Lex *select_lex= &lex().select_lex;
170  TableList *select_tables= lex().query_tables;
171 
172  do
173  {
174  if (select_lex->item_list.size()) // With select
175  {
176  Select_Lex_Unit *unit= &lex().unit;
177  select_result *result;
178 
179  select_lex->options|= SELECT_NO_UNLOCK;
180  unit->set_limit(select_lex);
181 
182  if (not lex_identified_temp_table)
183  {
184  lex().link_first_table_back(create_table_list, link_to_local);
185  create_table_list->setCreate(true);
186  }
187 
188  if (not (res= session().openTablesLock(lex().query_tables)))
189  {
190  /*
191  Is table which we are changing used somewhere in other parts
192  of query
193  */
194  if (not lex_identified_temp_table)
195  {
196  create_table_list= lex().unlink_first_table(&link_to_local);
197 
198  if (unique_table(create_table_list, select_tables))
199  {
200  my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table_list->alias);
201  /* put tables back for PS rexecuting */
202  lex().link_first_table_back(create_table_list, link_to_local);
203 
204  res= true;
205  break;
206  }
207  }
208 
209  /*
210  select_create is currently not re-execution friendly and
211  needs to be created for every execution of a PS/SP.
212  */
213  if ((result= new select_create(create_table_list,
214  lex().exists(),
215  &create_info(),
216  createTableMessage(),
217  &alter_info,
218  select_lex->item_list,
219  lex().duplicates,
220  lex().ignore,
221  select_tables,
222  new_table_identifier)))
223  {
224  /*
225  CREATE from SELECT give its Select_Lex for SELECT,
226  and item_list belong to SELECT
227  */
228  res= handle_select(&session(), &lex(), result, 0);
229  delete result;
230  }
231  }
232  else if (not lex_identified_temp_table)
233  {
234  create_table_list= lex().unlink_first_table(&link_to_local);
235  }
236  }
237  else
238  {
239  /* regular create */
240  if (is_create_table_like)
241  {
242  res= create_like_table(&session(),
243  new_table_identifier,
244  identifier::Table(session().catalog().identifier(),
245  select_tables->getSchemaName(),
246  select_tables->getTableName()),
247  createTableMessage(),
248  lex().exists(),
249  is_engine_set);
250  }
251  else
252  {
253 
254  for (int32_t x= 0; x < alter_info.added_fields_proto.added_field_size(); x++)
255  {
256  message::Table::Field *field= createTableMessage().add_field();
257 
258  *field= alter_info.added_fields_proto.added_field(x);
259  }
260 
261  res= create_table(&session(),
262  new_table_identifier,
263  &create_info(),
264  createTableMessage(),
265  &alter_info,
266  false,
267  0,
268  lex().exists());
269  }
270 
271  if (not res)
272  {
273  session().my_ok();
274  }
275  }
276  } while (0);
277 
278  return res;
279 }
280 
281 bool statement::CreateTable::check(const identifier::Table &identifier)
282 {
283  // Check table name for validity
284  if (not identifier.isValid())
285  return false;
286 
287  // See if any storage engine objects to the name of the file
288  if (not plugin::StorageEngine::canCreateTable(identifier))
289  {
290  identifier::Schema schema_identifier= identifier;
291  error::access(*session().user(), schema_identifier);
292 
293  return false;
294  }
295 
296  // Make sure the schema exists, we will do this again during the actual
297  // create for the table.
298  if (not plugin::StorageEngine::doesSchemaExist(identifier))
299  {
300  identifier::Schema schema_identifier= identifier;
301  my_error(ER_BAD_DB_ERROR, schema_identifier);
302 
303  return false;
304  }
305 
306  return true;
307 }
308 
309 bool statement::CreateTable::validateCreateTableOption()
310 {
311  bool rc= true;
312  size_t num_engine_options= createTableMessage().engine().options_size();
313 
314  assert(create_info().db_type);
315 
316  for (size_t y= 0; y < num_engine_options; ++y)
317  {
318  bool valid= create_info().db_type->validateCreateTableOption(createTableMessage().engine().options(y).name(),
319  createTableMessage().engine().options(y).state());
320 
321  if (not valid)
322  {
323  my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
324  createTableMessage().engine().options(y).name().c_str(),
325  createTableMessage().engine().options(y).state().c_str());
326 
327  rc= false;
328  }
329  }
330 
331  return rc;
332 }
333 
334 } /* namespace drizzled */
void my_ok(ha_rows affected_rows=0, ha_rows found_rows_arg=0, uint64_t passed_id=0, const char *message=NULL)
Definition: session.cc:1877
static bool canCreateTable(const drizzled::identifier::Table &identifier)
bool handle_select(Session *session, LEX *lex, select_result *result, uint64_t setup_tables_done_option)
Definition: sql_select.cc:118
plugin::StorageEngine * getDefaultStorageEngine()
Definition: session.cc:1889