~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: Brian Aker
  • Date: 2010-05-27 01:25:56 UTC
  • mfrom: (1567.1.4 new-staging)
  • Revision ID: brian@gaz-20100527012556-5zgkirkl7swbigd6
Merge of Brian, Paul. PBXT compile issue, and test framework cleanup. 

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/table_identifier.h>
 
27
 
 
28
#include <iostream>
 
29
 
 
30
namespace drizzled
 
31
{
 
32
 
 
33
bool statement::CreateTable::execute()
 
34
{
 
35
  TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
 
36
  TableList *all_tables= session->lex->query_tables;
 
37
  assert(first_table == all_tables && first_table != 0);
 
38
  Select_Lex *select_lex= &session->lex->select_lex;
 
39
  Select_Lex_Unit *unit= &session->lex->unit;
 
40
  bool need_start_waiting= false;
 
41
  bool res= false;
 
42
  bool link_to_local= false;
 
43
  bool lex_identified_temp_table= 
 
44
    create_table_message.type() == message::Table::TEMPORARY;
 
45
 
 
46
  if (is_engine_set)
 
47
  {
 
48
    create_info.db_type= 
 
49
      plugin::StorageEngine::findByName(*session, create_table_message.engine().name());
 
50
 
 
51
    if (create_info.db_type == NULL)
 
52
    {
 
53
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
 
54
               create_table_message.name().c_str());
 
55
 
 
56
      return true;
 
57
    }
 
58
  }
 
59
  else /* We now get the default, place it in create_info, and put the engine name in table proto */
 
60
  {
 
61
    create_info.db_type= session->getDefaultStorageEngine();
 
62
  }
 
63
 
 
64
  if (not validateCreateTableOption())
 
65
  {
 
66
    return true;
 
67
  }
 
68
 
 
69
  /* 
 
70
    Now we set the name in our Table proto so that it will match 
 
71
    create_info.db_type.
 
72
  */
 
73
  {
 
74
    create_table_message.mutable_engine()->set_name(create_info.db_type->getName());
 
75
  }
 
76
 
 
77
 
 
78
  /* If CREATE TABLE of non-temporary table, do implicit commit */
 
79
  if (not lex_identified_temp_table)
 
80
  {
 
81
    if (not session->endActiveTransaction())
 
82
    {
 
83
      return true;
 
84
    }
 
85
  }
 
86
  /* Skip first table, which is the table we are creating */
 
87
  TableList *create_table= session->lex->unlink_first_table(&link_to_local);
 
88
  TableList *select_tables= session->lex->query_tables;
 
89
 
 
90
 
 
91
  /*
 
92
    Now that we have the engine, we can figure out the table identifier. We need the engine in order
 
93
    to determine if the table is transactional or not if it is temp.
 
94
  */
 
95
 
 
96
  create_table_message.set_schema(create_table->db);
 
97
 
 
98
  TableIdentifier new_table_identifier(create_table->db,
 
99
                                       create_table->table_name,
 
100
                                       create_table_message.type());
 
101
 
 
102
  if (create_table_precheck(new_table_identifier))
 
103
  {
 
104
    /* put tables back for PS rexecuting */
 
105
    session->lex->link_first_table_back(create_table, link_to_local);
 
106
    return true;
 
107
  }
 
108
 
 
109
  /* Might have been updated in create_table_precheck */
 
110
  create_info.alias= create_table->alias;
 
111
 
 
112
  /*
 
113
     The create-select command will open and read-lock the select table
 
114
     and then create, open and write-lock the new table. If a global
 
115
     read lock steps in, we get a deadlock. The write lock waits for
 
116
     the global read lock, while the global read lock waits for the
 
117
     select table to be closed. So we wait until the global readlock is
 
118
     gone before starting both steps. Note that
 
119
     wait_if_global_read_lock() sets a protection against a new global
 
120
     read lock when it succeeds. This needs to be released by
 
121
     start_waiting_global_read_lock(). We protect the normal CREATE
 
122
     TABLE in the same way. That way we avoid that a new table is
 
123
     created during a gobal read lock.
 
124
   */
 
125
  if (! (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
 
126
  {
 
127
    /* put tables back for PS rexecuting */
 
128
    session->lex->link_first_table_back(create_table, link_to_local);
 
129
    return true;
 
130
  }
 
131
 
 
132
  if (select_lex->item_list.elements)           // With select
 
133
  {
 
134
    select_result *result;
 
135
 
 
136
    select_lex->options|= SELECT_NO_UNLOCK;
 
137
    unit->set_limit(select_lex);
 
138
 
 
139
    if (not lex_identified_temp_table)
 
140
    {
 
141
      session->lex->link_first_table_back(create_table, link_to_local);
 
142
      create_table->create= true;
 
143
    }
 
144
 
 
145
    if (not (res= session->openTablesLock(session->lex->query_tables)))
 
146
    {
 
147
      /*
 
148
         Is table which we are changing used somewhere in other parts
 
149
         of query
 
150
       */
 
151
      if (not lex_identified_temp_table)
 
152
      {
 
153
        TableList *duplicate= NULL;
 
154
        create_table= session->lex->unlink_first_table(&link_to_local);
 
155
        if ((duplicate= unique_table(create_table, select_tables)))
 
156
        {
 
157
          my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->alias);
 
158
          /*
 
159
             Release the protection against the global read lock and wake
 
160
             everyone, who might want to set a global read lock.
 
161
           */
 
162
          start_waiting_global_read_lock(session);
 
163
          /* put tables back for PS rexecuting */
 
164
          session->lex->link_first_table_back(create_table, link_to_local);
 
165
          return true;
 
166
        }
 
167
      }
 
168
 
 
169
      /*
 
170
         select_create is currently not re-execution friendly and
 
171
         needs to be created for every execution of a PS/SP.
 
172
       */
 
173
      if ((result= new select_create(create_table,
 
174
                                     is_if_not_exists,
 
175
                                     &create_info,
 
176
                                     create_table_message,
 
177
                                     &alter_info,
 
178
                                     select_lex->item_list,
 
179
                                     session->lex->duplicates,
 
180
                                     session->lex->ignore,
 
181
                                     select_tables,
 
182
                                     new_table_identifier)))
 
183
      {
 
184
        /*
 
185
           CREATE from SELECT give its Select_Lex for SELECT,
 
186
           and item_list belong to SELECT
 
187
         */
 
188
        res= handle_select(session, session->lex, result, 0);
 
189
        delete result;
 
190
      }
 
191
    }
 
192
    else if (not lex_identified_temp_table)
 
193
    {
 
194
      create_table= session->lex->unlink_first_table(&link_to_local);
 
195
    }
 
196
  }
 
197
  else
 
198
  {
 
199
    /* regular create */
 
200
    if (is_create_table_like)
 
201
    {
 
202
      res= mysql_create_like_table(session, 
 
203
                                   new_table_identifier,
 
204
                                   create_table, 
 
205
                                   select_tables,
 
206
                                   create_table_message,
 
207
                                   is_if_not_exists,
 
208
                                   is_engine_set);
 
209
    }
 
210
    else
 
211
    {
 
212
 
 
213
      for (int32_t x= 0; x < alter_info.alter_proto.added_field_size(); x++)
 
214
      {
 
215
        message::Table::Field *field= create_table_message.add_field();
 
216
 
 
217
        *field= alter_info.alter_proto.added_field(x);
 
218
      }
 
219
 
 
220
      res= mysql_create_table(session, 
 
221
                              new_table_identifier,
 
222
                              &create_info,
 
223
                              create_table_message,
 
224
                              &alter_info, 
 
225
                              false, 
 
226
                              0,
 
227
                              is_if_not_exists);
 
228
    }
 
229
 
 
230
    if (not res)
 
231
    {
 
232
      session->my_ok();
 
233
    }
 
234
  }
 
235
 
 
236
  /*
 
237
     Release the protection against the global read lock and wake
 
238
     everyone, who might want to set a global read lock.
 
239
   */
 
240
  start_waiting_global_read_lock(session);
 
241
 
 
242
  return res;
 
243
}
 
244
 
 
245
bool statement::CreateTable::validateCreateTableOption()
 
246
{
 
247
  bool rc= true;
 
248
  size_t num_engine_options= create_table_message.engine().options_size();
 
249
 
 
250
  assert(create_info.db_type);
 
251
 
 
252
  for (size_t y= 0; y < num_engine_options; ++y)
 
253
  {
 
254
    bool valid= create_info.db_type->validateCreateTableOption(create_table_message.engine().options(y).name(),
 
255
                                                               create_table_message.engine().options(y).state());
 
256
 
 
257
    if (not valid)
 
258
    {
 
259
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
 
260
               create_table_message.engine().options(y).name().c_str(),
 
261
               create_table_message.engine().options(y).state().c_str());
 
262
 
 
263
      rc= false;
 
264
    }
 
265
  }
 
266
 
 
267
  return rc;
 
268
}
 
269
 
 
270
} /* namespace drizzled */
 
271