~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/create_table.cc

  • Committer: Monty Taylor
  • Date: 2009-09-22 23:50:12 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20090922235012-i0a3bs91f6krqduc
Fixed multi_malloc.h include guard.
Added include guard checking script.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include "config.h"
 
21
#include <drizzled/server_includes.h>
22
22
#include <drizzled/show.h>
23
23
#include <drizzled/lock.h>
24
24
#include <drizzled/session.h>
25
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
 
{
 
26
 
 
27
using namespace drizzled;
33
28
 
34
29
bool statement::CreateTable::execute()
35
30
{
41
36
  bool need_start_waiting= false;
42
37
  bool res= false;
43
38
  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
39
 
71
40
  /* If CREATE TABLE of non-temporary table, do implicit commit */
72
 
  if (not lex_identified_temp_table)
 
41
  if (! (session->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
73
42
  {
74
 
    if (not session->endActiveTransaction())
 
43
    if (! session->endActiveTransaction())
75
44
    {
76
45
      return true;
77
46
    }
79
48
  /* Skip first table, which is the table we are creating */
80
49
  TableList *create_table= session->lex->unlink_first_table(&link_to_local);
81
50
  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 (not check(new_table_identifier))
 
51
  /*
 
52
     Code below (especially in mysql_create_table() and select_create
 
53
     methods) may modify HA_CREATE_INFO structure in LEX, so we have to
 
54
     use a copy of this structure to make execution prepared statement-
 
55
     safe. A shallow copy is enough as this code won't modify any memory
 
56
     referenced from this structure.
 
57
   */
 
58
  HA_CREATE_INFO create_info(session->lex->create_info);
 
59
  /*
 
60
     We need to copy alter_info for the same reasons of re-execution
 
61
     safety, only in case of AlterInfo we have to do (almost) a deep
 
62
     copy.
 
63
   */
 
64
  AlterInfo alter_info(session->lex->alter_info, session->mem_root);
 
65
 
 
66
  if (session->is_fatal_error)
 
67
  {
 
68
    /* If out of memory when creating a copy of alter_info. */
 
69
    /* put tables back for PS rexecuting */
 
70
    session->lex->link_first_table_back(create_table, link_to_local);
 
71
    return true;
 
72
  }
 
73
 
 
74
  if (create_table_precheck(session, select_tables, create_table))
90
75
  {
91
76
    /* put tables back for PS rexecuting */
92
77
    session->lex->link_first_table_back(create_table, link_to_local);
109
94
     TABLE in the same way. That way we avoid that a new table is
110
95
     created during a gobal read lock.
111
96
   */
112
 
  if (! (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
 
97
  if (! (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
113
98
  {
114
99
    /* put tables back for PS rexecuting */
115
100
    session->lex->link_first_table_back(create_table, link_to_local);
116
101
    return true;
117
102
  }
118
 
 
119
103
  if (select_lex->item_list.elements)           // With select
120
104
  {
121
105
    select_result *result;
123
107
    select_lex->options|= SELECT_NO_UNLOCK;
124
108
    unit->set_limit(select_lex);
125
109
 
126
 
    if (not lex_identified_temp_table)
 
110
    if (! (create_info.options & HA_LEX_CREATE_TMP_TABLE))
127
111
    {
128
112
      session->lex->link_first_table_back(create_table, link_to_local);
129
 
      create_table->setCreate(true);
 
113
      create_table->create= true;
130
114
    }
131
115
 
132
 
    if (not (res= session->openTablesLock(session->lex->query_tables)))
 
116
    if (! (res= session->openTablesLock(session->lex->query_tables)))
133
117
    {
134
118
      /*
135
119
         Is table which we are changing used somewhere in other parts
136
120
         of query
137
121
       */
138
 
      if (not lex_identified_temp_table)
 
122
      if (! (create_info.options & HA_LEX_CREATE_TMP_TABLE))
139
123
      {
140
124
        TableList *duplicate= NULL;
141
125
        create_table= session->lex->unlink_first_table(&link_to_local);
142
 
        if ((duplicate= unique_table(create_table, select_tables)))
 
126
        if ((duplicate= unique_table(session, create_table, select_tables, 0)))
143
127
        {
144
128
          my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->alias);
145
129
          /*
146
130
             Release the protection against the global read lock and wake
147
131
             everyone, who might want to set a global read lock.
148
132
           */
149
 
          session->startWaitingGlobalReadLock();
 
133
          start_waiting_global_read_lock(session);
150
134
          /* put tables back for PS rexecuting */
151
135
          session->lex->link_first_table_back(create_table, link_to_local);
152
 
 
153
136
          return true;
154
137
        }
155
138
      }
159
142
         needs to be created for every execution of a PS/SP.
160
143
       */
161
144
      if ((result= new select_create(create_table,
162
 
                                     is_if_not_exists,
163
145
                                     &create_info,
164
 
                                     create_table_message,
 
146
                                     session->lex->create_table_proto,
165
147
                                     &alter_info,
166
148
                                     select_lex->item_list,
167
149
                                     session->lex->duplicates,
168
150
                                     session->lex->ignore,
169
 
                                     select_tables,
170
 
                                     new_table_identifier)))
 
151
                                     select_tables)))
171
152
      {
172
153
        /*
173
154
           CREATE from SELECT give its Select_Lex for SELECT,
177
158
        delete result;
178
159
      }
179
160
    }
180
 
    else if (not lex_identified_temp_table)
 
161
    else if (! (create_info.options & HA_LEX_CREATE_TMP_TABLE))
181
162
    {
182
163
      create_table= session->lex->unlink_first_table(&link_to_local);
183
164
    }
184
165
  }
185
166
  else
186
167
  {
 
168
    /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
 
169
    if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
 
170
      session->options|= OPTION_KEEP_LOG;
187
171
    /* regular create */
188
 
    if (is_create_table_like)
 
172
    if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
189
173
    {
190
174
      res= mysql_create_like_table(session, 
191
 
                                   new_table_identifier,
192
175
                                   create_table, 
193
176
                                   select_tables,
194
 
                                   create_table_message,
195
 
                                   is_if_not_exists,
196
 
                                   is_engine_set);
 
177
                                   &create_info);
197
178
    }
198
179
    else
199
180
    {
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
181
      res= mysql_create_table(session, 
209
 
                              new_table_identifier,
 
182
                              create_table->db,
 
183
                              create_table->table_name, 
210
184
                              &create_info,
211
 
                              create_table_message,
 
185
                              session->lex->create_table_proto,
212
186
                              &alter_info, 
213
 
                              false, 
214
 
                              0,
215
 
                              is_if_not_exists);
 
187
                              0, 
 
188
                              0);
216
189
    }
217
 
 
218
 
    if (not res)
 
190
    if (! res)
219
191
    {
220
192
      session->my_ok();
221
193
    }
225
197
     Release the protection against the global read lock and wake
226
198
     everyone, who might want to set a global read lock.
227
199
   */
228
 
  session->startWaitingGlobalReadLock();
 
200
  start_waiting_global_read_lock(session);
229
201
 
230
202
  return res;
231
203
}
232
 
 
233
 
bool statement::CreateTable::check(const TableIdentifier &identifier)
234
 
{
235
 
  // Check table name for validity
236
 
  if (not identifier.isValid())
237
 
    return false;
238
 
 
239
 
  // See if any storage engine objects to the name of the file
240
 
  if (not plugin::StorageEngine::canCreateTable(identifier))
241
 
  {
242
 
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", identifier.getSchemaName().c_str());
243
 
 
244
 
    return false;
245
 
  }
246
 
 
247
 
  // Make sure the schema exists, we will do this again during the actual
248
 
  // create for the table.
249
 
  if (not plugin::StorageEngine::doesSchemaExist(identifier))
250
 
  {
251
 
    my_error(ER_BAD_DB_ERROR, MYF(0), identifier.getSchemaName().c_str());
252
 
 
253
 
    return false;
254
 
  }
255
 
 
256
 
  return true;
257
 
}
258
 
 
259
 
bool statement::CreateTable::validateCreateTableOption()
260
 
{
261
 
  bool rc= true;
262
 
  size_t num_engine_options= create_table_message.engine().options_size();
263
 
 
264
 
  assert(create_info.db_type);
265
 
 
266
 
  for (size_t y= 0; y < num_engine_options; ++y)
267
 
  {
268
 
    bool valid= create_info.db_type->validateCreateTableOption(create_table_message.engine().options(y).name(),
269
 
                                                               create_table_message.engine().options(y).state());
270
 
 
271
 
    if (not valid)
272
 
    {
273
 
      my_error(ER_UNKNOWN_ENGINE_OPTION, MYF(0),
274
 
               create_table_message.engine().options(y).name().c_str(),
275
 
               create_table_message.engine().options(y).state().c_str());
276
 
 
277
 
      rc= false;
278
 
    }
279
 
  }
280
 
 
281
 
  return rc;
282
 
}
283
 
 
284
 
} /* namespace drizzled */
285