~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

Merge Revision revid:marko.makela@oracle.com-20100505101406-u4low2x26q6itck0 from MySQL InnoDB

Original revid:marko.makela@oracle.com-20100505101406-u4low2x26q6itck0

Original Authors: Marko Mäkelä <marko.makela@oracle.com>
Original commit message:
Merge from mysql-5.1-innodb:

  ------------------------------------------------------------
  revno: 3446
  revision-id: marko.makela@oracle.com-20100505100507-6kcd2hf32hruxbv7
  parent: marko.makela@oracle.com-20100505095328-vetnl0flhmhao7p5
  committer: Marko Mäkelä <marko.makela@oracle.com>
  branch nick: 5.1-innodb
  timestamp: Wed 2010-05-05 13:05:07 +0300
  message:
    Add Valgrind diagnostics to track down Bug #38999.
  ------------------------------------------------------------

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