~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Brian Aker
  • Date: 2011-02-22 06:12:02 UTC
  • mfrom: (2190.1.6 drizzle-build)
  • Revision ID: brian@tangent.org-20110222061202-k03czxykqy4x9hjs
List update, header fixes, multiple symbols, and David deletes some code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2009 Sun Microsystems
 
4
 *  Copyright (C) 2009 Sun Microsystems, Inc.
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include "config.h"
 
21
#include <config.h>
22
22
 
23
23
#include <fcntl.h>
24
24
 
25
25
#include <sstream>
26
26
 
27
 
#include "drizzled/show.h"
28
 
#include "drizzled/lock.h"
29
 
#include "drizzled/session.h"
30
 
#include "drizzled/statement/alter_table.h"
31
 
#include "drizzled/global_charset_info.h"
32
 
 
33
 
 
34
 
#include "drizzled/gettext.h"
35
 
#include "drizzled/data_home.h"
36
 
#include "drizzled/sql_table.h"
37
 
#include "drizzled/table_proto.h"
38
 
#include "drizzled/optimizer/range.h"
39
 
#include "drizzled/time_functions.h"
40
 
#include "drizzled/records.h"
41
 
#include "drizzled/pthread_globals.h"
42
 
#include "drizzled/internal/my_sys.h"
43
 
#include "drizzled/internal/iocache.h"
44
 
 
45
 
#include "drizzled/transaction_services.h"
46
 
 
47
 
#include "drizzled/message.h"
 
27
#include <drizzled/show.h>
 
28
#include <drizzled/lock.h>
 
29
#include <drizzled/session.h>
 
30
#include <drizzled/statement/alter_table.h>
 
31
#include <drizzled/global_charset_info.h>
 
32
 
 
33
 
 
34
#include <drizzled/gettext.h>
 
35
#include <drizzled/data_home.h>
 
36
#include <drizzled/sql_table.h>
 
37
#include <drizzled/table_proto.h>
 
38
#include <drizzled/optimizer/range.h>
 
39
#include <drizzled/time_functions.h>
 
40
#include <drizzled/records.h>
 
41
#include <drizzled/pthread_globals.h>
 
42
#include <drizzled/internal/my_sys.h>
 
43
#include <drizzled/internal/iocache.h>
 
44
#include <drizzled/plugin/storage_engine.h>
 
45
#include <drizzled/copy_field.h>
 
46
 
 
47
#include <drizzled/transaction_services.h>
 
48
 
 
49
#include <drizzled/filesort.h>
 
50
 
 
51
#include <drizzled/message.h>
48
52
 
49
53
using namespace std;
50
54
 
64
68
                                    enum enum_enable_or_disable keys_onoff,
65
69
                                    bool error_if_not_empty);
66
70
 
67
 
static bool mysql_prepare_alter_table(Session *session,
 
71
static bool prepare_alter_table(Session *session,
68
72
                                      Table *table,
69
73
                                      HA_CREATE_INFO *create_info,
70
74
                                      const message::Table &original_proto,
71
75
                                      message::Table &table_message,
72
76
                                      AlterInfo *alter_info);
73
77
 
74
 
static int create_temporary_table(Session *session,
75
 
                                  TableIdentifier &identifier,
76
 
                                  HA_CREATE_INFO *create_info,
77
 
                                  message::Table &create_message,
78
 
                                  AlterInfo *alter_info);
79
 
 
80
 
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier);
 
78
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier);
 
79
 
 
80
namespace statement {
 
81
 
 
82
AlterTable::AlterTable(Session *in_session, Table_ident *ident, drizzled::ha_build_method build_arg) :
 
83
  CreateTable(in_session)
 
84
 
85
  in_session->getLex()->sql_command= SQLCOM_ALTER_TABLE;
 
86
  (void)ident;
 
87
  alter_info.build_method= build_arg;
 
88
}
 
89
 
 
90
} // namespace statement
81
91
 
82
92
bool statement::AlterTable::execute()
83
93
{
84
 
  TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
85
 
  TableList *all_tables= session->lex->query_tables;
 
94
  TableList *first_table= (TableList *) getSession()->getLex()->select_lex.table_list.first;
 
95
  TableList *all_tables= getSession()->getLex()->query_tables;
86
96
  assert(first_table == all_tables && first_table != 0);
87
 
  Select_Lex *select_lex= &session->lex->select_lex;
 
97
  Select_Lex *select_lex= &getSession()->getLex()->select_lex;
88
98
  bool need_start_waiting= false;
89
99
 
 
100
  is_engine_set= not createTableMessage().engine().name().empty();
 
101
 
90
102
  if (is_engine_set)
91
103
  {
92
 
    create_info.db_type= 
93
 
      plugin::StorageEngine::findByName(*session, create_table_message.engine().name());
 
104
    create_info().db_type= 
 
105
      plugin::StorageEngine::findByName(*getSession(), createTableMessage().engine().name());
94
106
 
95
 
    if (create_info.db_type == NULL)
 
107
    if (create_info().db_type == NULL)
96
108
    {
97
 
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
98
 
               create_table_message.engine().name().c_str());
 
109
      my_error(createTableMessage().engine().name(), ER_UNKNOWN_STORAGE_ENGINE, MYF(0));
99
110
 
100
111
      return true;
101
112
    }
105
116
  assert(select_lex->db);
106
117
 
107
118
  /* Chicken/Egg... we need to search for the table, to know if the table exists, so we can build a full identifier from it */
108
 
  message::Table original_table_message;
 
119
  message::table::shared_ptr original_table_message;
109
120
  {
110
 
    TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
111
 
    if (plugin::StorageEngine::getTableDefinition(*session, identifier, original_table_message) != EEXIST)
 
121
    identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
 
122
    if (not (original_table_message= plugin::StorageEngine::getTableMessage(*getSession(), identifier)))
112
123
    {
113
 
      my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
124
      my_error(ER_BAD_TABLE_ERROR, identifier);
114
125
      return true;
115
126
    }
116
127
 
117
 
    if (not  create_info.db_type)
 
128
    if (not  create_info().db_type)
118
129
    {
119
 
      create_info.db_type= 
120
 
        plugin::StorageEngine::findByName(*session, original_table_message.engine().name());
 
130
      create_info().db_type= 
 
131
        plugin::StorageEngine::findByName(*getSession(), original_table_message->engine().name());
121
132
 
122
 
      if (not create_info.db_type)
 
133
      if (not create_info().db_type)
123
134
      {
124
 
        my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
135
        my_error(ER_BAD_TABLE_ERROR, identifier);
125
136
        return true;
126
137
      }
127
138
    }
128
139
  }
129
140
 
130
141
  if (not validateCreateTableOption())
131
 
  {
132
 
    return true;
133
 
  }
134
 
 
135
 
  /* ALTER TABLE ends previous transaction */
136
 
  if (not session->endActiveTransaction())
137
 
  {
138
 
    return true;
139
 
  }
140
 
 
141
 
  if (not (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
142
 
  {
143
 
    return true;
144
 
  }
 
142
    return true;
 
143
 
 
144
  if (getSession()->inTransaction())
 
145
  {
 
146
    my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
 
147
    return true;
 
148
  }
 
149
 
 
150
  if (not (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
 
151
    return true;
145
152
 
146
153
  bool res;
147
 
  if (original_table_message.type() == message::Table::STANDARD )
 
154
  if (original_table_message->type() == message::Table::STANDARD )
148
155
  {
149
 
    TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
150
 
    TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
151
 
                                   session->lex->name.str ? session->lex->name.str : first_table->getTableName());
 
156
    identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
 
157
    identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
 
158
                                   getSession()->getLex()->name.str ? getSession()->getLex()->name.str : first_table->getTableName());
152
159
 
153
 
    res= alter_table(session, 
 
160
    res= alter_table(getSession(), 
154
161
                     identifier,
155
162
                     new_identifier,
156
 
                     &create_info,
157
 
                     original_table_message,
158
 
                     create_table_message,
 
163
                     &create_info(),
 
164
                     *original_table_message,
 
165
                     createTableMessage(),
159
166
                     first_table,
160
167
                     &alter_info,
161
168
                     select_lex->order_list.elements,
162
169
                     (Order *) select_lex->order_list.first,
163
 
                     session->lex->ignore);
 
170
                     getSession()->getLex()->ignore);
164
171
  }
165
172
  else
166
173
  {
167
 
    TableIdentifier catch22(first_table->getSchemaName(), first_table->getTableName());
168
 
    Table *table= session->find_temporary_table(catch22);
 
174
    identifier::Table catch22(first_table->getSchemaName(), first_table->getTableName());
 
175
    Table *table= getSession()->find_temporary_table(catch22);
169
176
    assert(table);
170
177
    {
171
 
      TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
172
 
      TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
173
 
                                     session->lex->name.str ? session->lex->name.str : first_table->getTableName(),
174
 
                                     table->getMutableShare()->getPath());
 
178
      identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
 
179
      identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
 
180
                                       getSession()->getLex()->name.str ? getSession()->getLex()->name.str : first_table->getTableName(),
 
181
                                       table->getMutableShare()->getPath());
175
182
 
176
 
      res= alter_table(session, 
 
183
      res= alter_table(getSession(), 
177
184
                       identifier,
178
185
                       new_identifier,
179
 
                       &create_info,
180
 
                       original_table_message,
181
 
                       create_table_message,
 
186
                       &create_info(),
 
187
                       *original_table_message,
 
188
                       createTableMessage(),
182
189
                       first_table,
183
190
                       &alter_info,
184
191
                       select_lex->order_list.elements,
185
192
                       (Order *) select_lex->order_list.first,
186
 
                       session->lex->ignore);
 
193
                       getSession()->getLex()->ignore);
187
194
    }
188
195
  }
189
196
 
191
198
     Release the protection against the global read lock and wake
192
199
     everyone, who might want to set a global read lock.
193
200
   */
194
 
  start_waiting_global_read_lock(session);
 
201
  getSession()->startWaitingGlobalReadLock();
 
202
 
195
203
  return res;
196
204
}
197
205
 
236
244
                 Table instructions
237
245
  @retval false  success
238
246
*/
239
 
static bool mysql_prepare_alter_table(Session *session,
240
 
                                      Table *table,
241
 
                                      HA_CREATE_INFO *create_info,
242
 
                                      const message::Table &original_proto,
243
 
                                      message::Table &table_message,
244
 
                                      AlterInfo *alter_info)
 
247
static bool prepare_alter_table(Session *session,
 
248
                                Table *table,
 
249
                                HA_CREATE_INFO *create_info,
 
250
                                const message::Table &original_proto,
 
251
                                message::Table &table_message,
 
252
                                AlterInfo *alter_info)
245
253
{
246
254
  /* New column definitions are added here */
247
255
  List<CreateField> new_create_list;
248
256
  /* New key definitions are added here */
249
257
  List<Key> new_key_list;
250
 
  List_iterator<AlterDrop> drop_it(alter_info->drop_list);
251
 
  List_iterator<CreateField> def_it(alter_info->create_list);
252
 
  List_iterator<AlterColumn> alter_it(alter_info->alter_list);
253
 
  List_iterator<Key> key_it(alter_info->key_list);
254
 
  List_iterator<CreateField> find_it(new_create_list);
255
 
  List_iterator<CreateField> field_it(new_create_list);
 
258
  List<AlterDrop>::iterator drop_it(alter_info->drop_list.begin());
 
259
  List<CreateField>::iterator def_it(alter_info->create_list.begin());
 
260
  List<AlterColumn>::iterator alter_it(alter_info->alter_list.begin());
 
261
  List<Key>::iterator key_it(alter_info->key_list.begin());
 
262
  List<CreateField>::iterator find_it(new_create_list.begin());
 
263
  List<CreateField>::iterator field_it(new_create_list.begin());
256
264
  List<Key_part_spec> key_parts;
257
265
  uint32_t used_fields= create_info->used_fields;
258
266
  KeyInfo *key_info= table->key_info;
262
270
  message::Table::TableOptions *table_options;
263
271
  table_options= table_message.mutable_options();
264
272
 
265
 
  if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
 
273
  if (not (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
266
274
    create_info->default_table_charset= table->getShare()->table_charset;
267
 
  if (! (used_fields & HA_CREATE_USED_AUTO) &&
268
 
      table->found_next_number_field)
 
275
 
 
276
  if (not (used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
269
277
  {
270
278
    /* Table has an autoincrement, copy value to new table */
271
279
    table->cursor->info(HA_STATUS_AUTO);
273
281
    if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
274
282
      table_options->set_has_user_set_auto_increment_value(false);
275
283
  }
 
284
 
276
285
  table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
277
286
  CreateField *def;
278
287
 
279
288
  /* First collect all fields from table which isn't in drop_list */
280
 
  Field **f_ptr;
281
289
  Field *field;
282
 
  for (f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
 
290
  for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
283
291
  {
284
292
    /* Check if field should be dropped */
285
293
    AlterDrop *drop;
286
 
    drop_it.rewind();
 
294
    drop_it= alter_info->drop_list.begin();
287
295
    while ((drop= drop_it++))
288
296
    {
289
297
      if (drop->type == AlterDrop::COLUMN &&
299
307
        break;
300
308
      }
301
309
    }
 
310
 
302
311
    if (drop)
303
312
    {
304
313
      drop_it.remove();
309
318
    field->setReadSet();
310
319
 
311
320
    /* Check if field is changed */
312
 
    def_it.rewind();
 
321
    def_it= alter_info->create_list.begin();
313
322
    while ((def= def_it++))
314
323
    {
315
324
      if (def->change &&
316
325
          ! my_strcasecmp(system_charset_info, field->field_name, def->change))
317
326
              break;
318
327
    }
 
328
 
319
329
    if (def)
320
330
    {
321
331
      /* Field is changed */
334
344
      */
335
345
      def= new CreateField(field, field);
336
346
      new_create_list.push_back(def);
337
 
      alter_it.rewind(); /* Change default if ALTER */
 
347
      alter_it= alter_info->alter_list.begin(); /* Change default if ALTER */
338
348
      AlterColumn *alter;
 
349
 
339
350
      while ((alter= alter_it++))
340
351
      {
341
352
        if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
342
353
          break;
343
354
      }
 
355
 
344
356
      if (alter)
345
357
      {
346
358
        if (def->sql_type == DRIZZLE_TYPE_BLOB)
347
359
        {
348
360
          my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
349
 
                goto err;
 
361
          return true;
350
362
        }
 
363
 
351
364
        if ((def->def= alter->def))
352
365
        {
353
366
          /* Use new default */
354
367
          def->flags&= ~NO_DEFAULT_VALUE_FLAG;
355
368
        }
356
369
        else
 
370
        {
357
371
          def->flags|= NO_DEFAULT_VALUE_FLAG;
 
372
        }
358
373
        alter_it.remove();
359
374
      }
360
375
    }
361
376
  }
362
 
  def_it.rewind();
 
377
 
 
378
  def_it= alter_info->create_list.begin();
363
379
  while ((def= def_it++)) /* Add new columns */
364
380
  {
365
381
    if (def->change && ! def->field)
366
382
    {
367
383
      my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
368
 
      goto err;
 
384
      return true;
369
385
    }
370
386
    /*
371
 
      Check that the DATE/DATETIME not null field we are going to add is
372
 
      either has a default value or the '0000-00-00' is allowed by the
373
 
      set sql mode.
374
 
      If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
375
 
      flag to allow ALTER Table only if the table to be altered is empty.
 
387
      If we have been given a field which has no default value, and is not null then we need to bail.
376
388
    */
377
 
    if ((def->sql_type == DRIZZLE_TYPE_DATE ||
378
 
         def->sql_type == DRIZZLE_TYPE_DATETIME) &&
379
 
        ! alter_info->datetime_field &&
380
 
        ! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)))
 
389
    if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
381
390
    {
382
 
      alter_info->datetime_field= def;
383
391
      alter_info->error_if_not_empty= true;
384
392
    }
385
393
    if (! def->after)
 
394
    {
386
395
      new_create_list.push_back(def);
 
396
    }
387
397
    else if (def->after == first_keyword)
 
398
    {
388
399
      new_create_list.push_front(def);
 
400
    }
389
401
    else
390
402
    {
391
403
      CreateField *find;
392
 
      find_it.rewind();
 
404
      find_it= new_create_list.begin();
 
405
 
393
406
      while ((find= find_it++)) /* Add new columns */
394
407
      {
395
 
        if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
 
408
        if (not my_strcasecmp(system_charset_info,def->after, find->field_name))
396
409
          break;
397
410
      }
398
 
      if (! find)
 
411
 
 
412
      if (not find)
399
413
      {
400
414
        my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
401
 
        goto err;
 
415
        return true;
402
416
      }
 
417
 
403
418
      find_it.after(def); /* Put element after this */
 
419
 
404
420
      /*
405
421
        XXX: hack for Bug#28427.
406
422
        If column order has changed, force OFFLINE ALTER Table
413
429
      */
414
430
      if (alter_info->build_method == HA_BUILD_ONLINE)
415
431
      {
416
 
        my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query.c_str());
417
 
        goto err;
 
432
        my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
 
433
        return true;
418
434
      }
 
435
 
419
436
      alter_info->build_method= HA_BUILD_OFFLINE;
420
437
    }
421
438
  }
 
439
 
422
440
  if (alter_info->alter_list.elements)
423
441
  {
424
442
    my_error(ER_BAD_FIELD_ERROR,
425
443
             MYF(0),
426
444
             alter_info->alter_list.head()->name,
427
445
             table->getMutableShare()->getTableName());
428
 
    goto err;
 
446
    return true;
429
447
  }
430
 
  if (! new_create_list.elements)
 
448
 
 
449
  if (not new_create_list.elements)
431
450
  {
432
451
    my_message(ER_CANT_REMOVE_ALL_FIELDS,
433
452
               ER(ER_CANT_REMOVE_ALL_FIELDS),
434
453
               MYF(0));
435
 
    goto err;
 
454
    return true;
436
455
  }
437
456
 
438
457
  /*
443
462
  {
444
463
    char *key_name= key_info->name;
445
464
    AlterDrop *drop;
446
 
    drop_it.rewind();
 
465
 
 
466
    drop_it= alter_info->drop_list.begin();
447
467
    while ((drop= drop_it++))
448
468
    {
449
469
      if (drop->type == AlterDrop::KEY &&
450
470
          ! my_strcasecmp(system_charset_info, key_name, drop->name))
451
471
        break;
452
472
    }
 
473
 
453
474
    if (drop)
454
475
    {
455
476
      drop_it.remove();
457
478
    }
458
479
 
459
480
    KeyPartInfo *key_part= key_info->key_part;
460
 
    key_parts.empty();
 
481
    key_parts.clear();
461
482
    for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
462
483
    {
463
484
      if (! key_part->field)
465
486
 
466
487
      const char *key_part_name= key_part->field->field_name;
467
488
      CreateField *cfield;
468
 
      field_it.rewind();
 
489
      field_it= new_create_list.begin();
469
490
      while ((cfield= field_it++))
470
491
      {
471
492
        if (cfield->change)
472
493
        {
473
 
          if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
 
494
          if (not my_strcasecmp(system_charset_info, key_part_name, cfield->change))
474
495
            break;
475
496
        }
476
 
        else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
 
497
        else if (not my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
477
498
          break;
478
499
      }
479
 
      if (! cfield)
 
500
 
 
501
      if (not cfield)
480
502
              continue; /* Field is removed */
481
503
      
482
504
      uint32_t key_part_length= key_part->length;
508
530
    }
509
531
    if (key_parts.elements)
510
532
    {
511
 
      KEY_CREATE_INFO key_create_info;
 
533
      key_create_information_st key_create_info= default_key_create_info;
512
534
      Key *key;
513
 
      enum Key::Keytype key_type;
514
 
      memset(&key_create_info, 0, sizeof(key_create_info));
 
535
      Key::Keytype key_type;
515
536
 
516
537
      key_create_info.algorithm= key_info->algorithm;
 
538
 
517
539
      if (key_info->flags & HA_USES_BLOCK_SIZE)
518
540
        key_create_info.block_size= key_info->block_size;
 
541
 
519
542
      if (key_info->flags & HA_USES_COMMENT)
520
543
        key_create_info.comment= key_info->comment;
521
544
 
527
550
          key_type= Key::UNIQUE;
528
551
      }
529
552
      else
 
553
      {
530
554
        key_type= Key::MULTIPLE;
 
555
      }
531
556
 
532
557
      key= new Key(key_type,
533
558
                   key_name,
540
565
  }
541
566
 
542
567
  /* Copy over existing foreign keys */
543
 
  for (int j= 0; j < original_proto.fk_constraint_size(); j++)
 
568
  for (int32_t j= 0; j < original_proto.fk_constraint_size(); j++)
544
569
  {
545
570
    AlterDrop *drop;
546
 
    drop_it.rewind();
 
571
    drop_it= alter_info->drop_list.begin();
547
572
    while ((drop= drop_it++))
548
573
    {
549
574
      if (drop->type == AlterDrop::FOREIGN_KEY &&
569
594
      if (key->type == Key::FOREIGN_KEY)
570
595
      {
571
596
        if (((Foreign_key *)key)->validate(new_create_list))
572
 
          goto err;
 
597
        {
 
598
          return true;
 
599
        }
573
600
 
574
601
        Foreign_key *fkey= (Foreign_key*)key;
575
602
        add_foreign_key_to_table_message(&table_message,
590
617
        my_error(ER_WRONG_NAME_FOR_INDEX,
591
618
                 MYF(0),
592
619
                 key->name.str);
593
 
        goto err;
 
620
        return true;
594
621
      }
595
622
    }
596
623
  }
617
644
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
618
645
             MYF(0),
619
646
             alter_info->drop_list.head()->name);
620
 
    goto err;
 
647
    return true;
621
648
  }
 
649
 
622
650
  if (alter_info->alter_list.elements)
623
651
  {
624
652
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
625
653
             MYF(0),
626
654
             alter_info->alter_list.head()->name);
627
 
    goto err;
 
655
    return true;
628
656
  }
629
657
 
630
658
  if (not table_message.options().has_comment()
631
659
      && table->getMutableShare()->hasComment())
 
660
  {
632
661
    table_options->set_comment(table->getMutableShare()->getComment());
 
662
  }
633
663
 
634
664
  if (table->getShare()->getType())
635
665
  {
636
666
    table_message.set_type(message::Table::TEMPORARY);
637
667
  }
638
668
 
639
 
  table_message.set_creation_timestamp(table->getShare()->getTableProto()->creation_timestamp());
640
 
  table_message.set_version(table->getShare()->getTableProto()->version());
641
 
  table_message.set_uuid(table->getShare()->getTableProto()->uuid());
 
669
  table_message.set_creation_timestamp(table->getShare()->getTableMessage()->creation_timestamp());
 
670
  table_message.set_version(table->getShare()->getTableMessage()->version());
 
671
  table_message.set_uuid(table->getShare()->getTableMessage()->uuid());
642
672
 
643
673
  rc= false;
644
674
  alter_info->create_list.swap(new_create_list);
645
675
  alter_info->key_list.swap(new_key_list);
646
 
err:
647
676
 
648
677
  size_t num_engine_options= table_message.engine().options_size();
649
678
  size_t original_num_engine_options= original_proto.engine().options_size();
670
699
 
671
700
  drizzled::message::update(table_message);
672
701
 
673
 
  return rc;
 
702
  return false;
674
703
}
675
704
 
676
705
/* table_list should contain just one table */
677
 
static int mysql_discard_or_import_tablespace(Session *session,
 
706
static int discard_or_import_tablespace(Session *session,
678
707
                                              TableList *table_list,
679
708
                                              enum tablespace_op_type tablespace_op)
680
709
{
681
710
  Table *table;
682
711
  bool discard;
683
 
  int error;
684
712
 
685
713
  /*
686
714
    Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
687
715
    ALTER Table
688
716
  */
689
 
 
690
717
  TransactionServices &transaction_services= TransactionServices::singleton();
691
718
  session->set_proc_info("discard_or_import_tablespace");
692
719
 
696
723
   We set this flag so that ha_innobase::open and ::external_lock() do
697
724
   not complain when we lock the table
698
725
 */
699
 
  session->tablespace_op= true;
700
 
  if (!(table= session->openTableLock(table_list, TL_WRITE)))
 
726
  session->setDoingTablespaceOperation(true);
 
727
  if (not (table= session->openTableLock(table_list, TL_WRITE)))
701
728
  {
702
 
    session->tablespace_op= false;
 
729
    session->setDoingTablespaceOperation(false);
703
730
    return -1;
704
731
  }
705
732
 
706
 
  error= table->cursor->ha_discard_or_import_tablespace(discard);
707
 
 
708
 
  session->set_proc_info("end");
709
 
 
710
 
  if (error)
711
 
    goto err;
712
 
 
713
 
  /* The ALTER Table is always in its own transaction */
714
 
  error= transaction_services.autocommitOrRollback(session, false);
715
 
  if (! session->endActiveTransaction())
716
 
    error=1;
717
 
  if (error)
718
 
    goto err;
719
 
  write_bin_log(session, session->query.c_str());
720
 
 
721
 
err:
722
 
  (void) transaction_services.autocommitOrRollback(session, error);
723
 
  session->tablespace_op=false;
 
733
  int error;
 
734
  do {
 
735
    error= table->cursor->ha_discard_or_import_tablespace(discard);
 
736
 
 
737
    session->set_proc_info("end");
 
738
 
 
739
    if (error)
 
740
      break;
 
741
 
 
742
    /* The ALTER Table is always in its own transaction */
 
743
    error= transaction_services.autocommitOrRollback(*session, false);
 
744
    if (not session->endActiveTransaction())
 
745
      error= 1;
 
746
 
 
747
    if (error)
 
748
      break;
 
749
 
 
750
    write_bin_log(session, *session->getQueryString());
 
751
 
 
752
  } while(0);
 
753
 
 
754
  (void) transaction_services.autocommitOrRollback(*session, error);
 
755
  session->setDoingTablespaceOperation(false);
724
756
 
725
757
  if (error == 0)
726
758
  {
770
802
                        ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
771
803
                        table->getMutableShare()->getTableName());
772
804
    error= 0;
773
 
  } else if (error)
 
805
  }
 
806
  else if (error)
 
807
  {
774
808
    table->print_error(error, MYF(0));
 
809
  }
775
810
 
776
811
  return(error);
777
812
}
778
813
 
779
814
static bool lockTableIfDifferent(Session &session,
780
 
                                 TableIdentifier &original_table_identifier,
781
 
                                 TableIdentifier &new_table_identifier,
 
815
                                 identifier::Table &original_table_identifier,
 
816
                                 identifier::Table &new_table_identifier,
782
817
                                 Table *name_lock)
783
818
{
784
819
  /* Check that we are not trying to rename to an existing table */
789
824
 
790
825
      if (session.find_temporary_table(new_table_identifier))
791
826
      {
792
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
827
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
793
828
        return false;
794
829
      }
795
830
    }
802
837
 
803
838
      if (not name_lock)
804
839
      {
805
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
840
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
806
841
        return false;
807
842
      }
808
843
 
809
844
      if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
810
845
      {
811
846
        /* Table will be closed by Session::executeCommand() */
812
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
847
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
813
848
 
814
 
        LOCK_open.lock(); /* ALTER TABLe */
815
 
        session.unlink_open_table(name_lock);
816
 
        LOCK_open.unlock();
 
849
        {
 
850
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
 
851
          session.unlink_open_table(name_lock);
 
852
        }
817
853
 
818
854
        return false;
819
855
      }
867
903
 
868
904
static bool internal_alter_table(Session *session,
869
905
                                 Table *table,
870
 
                                 TableIdentifier &original_table_identifier,
871
 
                                 TableIdentifier &new_table_identifier,
 
906
                                 identifier::Table &original_table_identifier,
 
907
                                 identifier::Table &new_table_identifier,
872
908
                                 HA_CREATE_INFO *create_info,
873
909
                                 const message::Table &original_proto,
874
910
                                 message::Table &create_proto,
884
920
  ha_rows copied= 0;
885
921
  ha_rows deleted= 0;
886
922
 
 
923
  if (not original_table_identifier.isValid())
 
924
    return true;
 
925
 
 
926
  if (not new_table_identifier.isValid())
 
927
    return true;
 
928
 
887
929
  session->set_proc_info("init");
888
930
 
889
931
  table->use_all_columns();
919
961
  if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
920
962
      new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
921
963
  {
922
 
    my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
 
964
    my_error(ER_ILLEGAL_HA, new_table_identifier);
923
965
 
924
966
    return true;
925
967
  }
937
979
    tmp.reset(ALTER_KEYS_ONOFF);
938
980
    tmp&= alter_info->flags;
939
981
 
940
 
    if (! (tmp.any()) && ! table->getShare()->getType()) // no need to touch frm
 
982
    if (not (tmp.any()) && not table->getShare()->getType()) // no need to touch frm
941
983
    {
942
984
      switch (alter_info->keys_onoff)
943
985
      {
944
986
      case LEAVE_AS_IS:
945
987
        break;
 
988
 
946
989
      case ENABLE:
947
990
        /*
948
991
          wait_while_table_is_used() ensures that table being altered is
953
996
          while the fact that the table is still open gives us protection
954
997
          from concurrent DDL statements.
955
998
        */
956
 
        LOCK_open.lock(); /* DDL wait for/blocker */
957
 
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
958
 
        LOCK_open.unlock();
 
999
        {
 
1000
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
 
1001
          wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
 
1002
        }
959
1003
        error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
1004
 
960
1005
        /* COND_refresh will be signaled in close_thread_tables() */
961
1006
        break;
 
1007
 
962
1008
      case DISABLE:
963
 
        LOCK_open.lock(); /* DDL wait for/blocker */
964
 
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
965
 
        LOCK_open.unlock();
966
 
        error=table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
1009
        {
 
1010
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
 
1011
          wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
 
1012
        }
 
1013
        error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
1014
 
967
1015
        /* COND_refresh will be signaled in close_thread_tables() */
968
1016
        break;
969
 
      default:
970
 
        assert(false);
971
 
        error= 0;
972
 
        break;
973
1017
      }
974
1018
 
975
1019
      if (error == HA_ERR_WRONG_COMMAND)
976
1020
      {
977
 
        error= 0;
 
1021
        error= EE_OK;
978
1022
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
979
1023
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
980
1024
                            table->getAlias());
981
1025
      }
982
1026
 
983
 
      LOCK_open.lock(); /* Lock to remove all instances of table from table cache before ALTER */
 
1027
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* Lock to remove all instances of table from table cache before ALTER */
984
1028
      /*
985
1029
        Unlike to the above case close_cached_table() below will remove ALL
986
1030
        instances of Table from table cache (it will also remove table lock
987
1031
        held by this thread). So to make actual table renaming and writing
988
1032
        to binlog atomic we have to put them into the same critical section
989
 
        protected by LOCK_open mutex. This also removes gap for races between
990
 
        access() and mysql_rename_table() calls.
 
1033
        protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
 
1034
        access() and rename_table() calls.
991
1035
      */
992
1036
 
993
 
      if (error == 0 &&  not (original_table_identifier == new_table_identifier))
 
1037
      if (not error &&  not (original_table_identifier == new_table_identifier))
994
1038
      {
995
1039
        session->set_proc_info("rename");
996
1040
        /*
1008
1052
        */
1009
1053
        if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1010
1054
        {
1011
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
1055
          my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
1012
1056
          error= -1;
1013
1057
        }
1014
1058
        else
1015
1059
        {
1016
 
          if (mysql_rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
 
1060
          if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1017
1061
          {
1018
1062
            error= -1;
1019
1063
          }
1022
1066
 
1023
1067
      if (error == HA_ERR_WRONG_COMMAND)
1024
1068
      {
1025
 
        error= 0;
 
1069
        error= EE_OK;
1026
1070
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1027
1071
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1028
1072
                            table->getAlias());
1029
1073
      }
1030
1074
 
1031
 
      if (error == 0)
 
1075
      if (not error)
1032
1076
      {
1033
 
        write_bin_log(session, session->query.c_str());
 
1077
        TransactionServices &transaction_services= TransactionServices::singleton();
 
1078
        transaction_services.allocateNewTransactionId();
 
1079
        write_bin_log(session, *session->getQueryString());
1034
1080
        session->my_ok();
1035
1081
      }
1036
 
      else if (error > 0)
 
1082
      else if (error > EE_OK) // If we have already set the error, we pass along -1
1037
1083
      {
1038
1084
        table->print_error(error, MYF(0));
1039
 
        error= -1;
1040
1085
      }
1041
1086
 
1042
 
      LOCK_open.unlock();
1043
1087
      table_list->table= NULL;
1044
1088
 
1045
1089
      return error;
1049
1093
  /* We have to do full alter table. */
1050
1094
  new_engine= create_info->db_type;
1051
1095
 
1052
 
  if (mysql_prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
 
1096
  if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
1053
1097
  {
1054
1098
    return true;
1055
1099
  }
1066
1110
    case we just use it as is. Neither of these tables require locks in order to  be
1067
1111
    filled.
1068
1112
  */
1069
 
  TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
 
1113
  identifier::Table new_table_as_temporary(original_table_identifier.getSchemaName(),
1070
1114
                                         tmp_name,
1071
1115
                                         create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1072
1116
                                         message::Table::TEMPORARY);
1073
1117
 
1074
 
  error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
 
1118
  /*
 
1119
    Create a table with a temporary name.
 
1120
    We don't log the statement, it will be logged later.
 
1121
  */
 
1122
  create_proto.set_name(new_table_as_temporary.getTableName());
 
1123
  create_proto.mutable_engine()->set_name(create_info->db_type->getName());
 
1124
 
 
1125
  error= create_table(session,
 
1126
                      new_table_as_temporary,
 
1127
                      create_info, create_proto, alter_info, true, 0, false);
1075
1128
 
1076
1129
  if (error != 0)
1077
1130
  {
1084
1137
 
1085
1138
  if (not new_table)
1086
1139
  {
1087
 
    quick_rm_table(*session, new_table_as_temporary);
 
1140
    plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1088
1141
    return true;
1089
1142
  }
1090
1143
 
1121
1174
  {
1122
1175
 
1123
1176
    /*
1124
 
      No default value was provided for a DATE/DATETIME field, the
1125
 
      current sql_mode doesn't allow the '0000-00-00' value and
1126
 
      the table to be altered isn't empty.
1127
 
      Report error here.
 
1177
      No default value was provided for new fields.
1128
1178
    */
1129
1179
    if (alter_info->error_if_not_empty && session->row_count)
1130
1180
    {
1131
 
      const char *f_val= 0;
1132
 
      enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1133
 
 
1134
 
      switch (alter_info->datetime_field->sql_type)
1135
 
      {
1136
 
      case DRIZZLE_TYPE_DATE:
1137
 
        f_val= "0000-00-00";
1138
 
        t_type= DRIZZLE_TIMESTAMP_DATE;
1139
 
        break;
1140
 
      case DRIZZLE_TYPE_DATETIME:
1141
 
        f_val= "0000-00-00 00:00:00";
1142
 
        t_type= DRIZZLE_TIMESTAMP_DATETIME;
1143
 
        break;
1144
 
      default:
1145
 
        /* Shouldn't get here. */
1146
 
        assert(0);
1147
 
      }
1148
 
      bool save_abort_on_warning= session->abort_on_warning;
1149
 
      session->abort_on_warning= true;
1150
 
      make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1151
 
                                   f_val, internal::strlength(f_val), t_type,
1152
 
                                   alter_info->datetime_field->field_name);
1153
 
      session->abort_on_warning= save_abort_on_warning;
 
1181
      my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
1154
1182
    }
1155
1183
 
1156
1184
    if (original_table_identifier.isTmp())
1162
1190
      }
1163
1191
      else
1164
1192
      {
1165
 
        quick_rm_table(*session, new_table_as_temporary);
 
1193
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1166
1194
      }
1167
1195
 
1168
1196
      return true;
1184
1212
        delete new_table;
1185
1213
      }
1186
1214
 
1187
 
      LOCK_open.lock(); /* ALTER TABLE */
 
1215
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1188
1216
 
1189
 
      quick_rm_table(*session, new_table_as_temporary);
1190
 
      LOCK_open.unlock();
 
1217
      plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1191
1218
 
1192
1219
      return true;
1193
1220
    }
1198
1225
    /* Close lock if this is a transactional table */
1199
1226
    if (session->lock)
1200
1227
    {
1201
 
      mysql_unlock_tables(session, session->lock);
 
1228
      session->unlockTables(session->lock);
1202
1229
      session->lock= 0;
1203
1230
    }
1204
1231
 
1210
1237
 
1211
1238
    new_table_identifier.setPath(new_table_as_temporary.getPath());
1212
1239
 
1213
 
    if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
 
1240
    if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1214
1241
    {
1215
1242
      return true;
1216
1243
    }
1234
1261
      delete new_table;
1235
1262
    }
1236
1263
 
1237
 
    LOCK_open.lock(); /* ALTER TABLE */
1238
 
 
1239
 
    /*
1240
 
      Data is copied. Now we:
1241
 
      1) Wait until all other threads close old version of table.
1242
 
      2) Close instances of table open by this thread and replace them
1243
 
      with exclusive name-locks.
1244
 
      3) Rename the old table to a temp name, rename the new one to the
1245
 
      old name.
1246
 
      4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1247
 
      we reopen new version of table.
1248
 
      5) Write statement to the binary log.
1249
 
      6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1250
 
      remove name-locks from list of open tables and table cache.
1251
 
      7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1252
 
      call to remove name-locks from table cache and list of open table.
1253
 
    */
1254
 
 
1255
 
    session->set_proc_info("rename result table");
1256
 
 
1257
 
    snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1258
 
 
1259
 
    my_casedn_str(files_charset_info, old_name);
1260
 
 
1261
 
    wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1262
 
    session->close_data_files_and_morph_locks(original_table_identifier);
1263
 
 
1264
 
    error= 0;
1265
 
 
1266
 
    /*
1267
 
      This leads to the storage engine (SE) not being notified for renames in
1268
 
      mysql_rename_table(), because we just juggle with the FRM and nothing
1269
 
      more. If we have an intermediate table, then we notify the SE that
1270
 
      it should become the actual table. Later, we will recycle the old table.
1271
 
      However, in case of ALTER Table RENAME there might be no intermediate
1272
 
      table. This is when the old and new tables are compatible, according to
1273
 
      compare_table(). Then, we need one additional call to
1274
 
    */
1275
 
    TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1276
 
                                           old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1277
 
                                         message::Table::TEMPORARY);
1278
 
 
1279
 
    if (mysql_rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1280
 
    {
1281
 
      error= 1;
1282
 
      quick_rm_table(*session, new_table_as_temporary);
1283
 
    }
1284
 
    else
1285
 
    {
1286
 
      if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
 
1264
    {
 
1265
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* ALTER TABLE */
 
1266
      /*
 
1267
        Data is copied. Now we:
 
1268
        1) Wait until all other threads close old version of table.
 
1269
        2) Close instances of table open by this thread and replace them
 
1270
        with exclusive name-locks.
 
1271
        3) Rename the old table to a temp name, rename the new one to the
 
1272
        old name.
 
1273
        4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
 
1274
        we reopen new version of table.
 
1275
        5) Write statement to the binary log.
 
1276
        6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
 
1277
        remove name-locks from list of open tables and table cache.
 
1278
        7) If we are not not under LOCK TABLES we rely on close_thread_tables()
 
1279
        call to remove name-locks from table cache and list of open table.
 
1280
      */
 
1281
 
 
1282
      session->set_proc_info("rename result table");
 
1283
 
 
1284
      snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
1285
 
 
1286
      my_casedn_str(files_charset_info, old_name);
 
1287
 
 
1288
      wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
 
1289
      session->close_data_files_and_morph_locks(original_table_identifier);
 
1290
 
 
1291
      assert(not error);
 
1292
 
 
1293
      /*
 
1294
        This leads to the storage engine (SE) not being notified for renames in
 
1295
        rename_table(), because we just juggle with the FRM and nothing
 
1296
        more. If we have an intermediate table, then we notify the SE that
 
1297
        it should become the actual table. Later, we will recycle the old table.
 
1298
        However, in case of ALTER Table RENAME there might be no intermediate
 
1299
        table. This is when the old and new tables are compatible, according to
 
1300
        compare_table(). Then, we need one additional call to
 
1301
      */
 
1302
      identifier::Table original_table_to_drop(original_table_identifier.getSchemaName(),
 
1303
                                             old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
 
1304
                                             message::Table::TEMPORARY);
 
1305
 
 
1306
      drizzled::error_t rename_error= EE_OK;
 
1307
      if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1287
1308
      {
1288
 
        /* Try to get everything back. */
1289
 
        error= 1;
1290
 
 
1291
 
        quick_rm_table(*session, new_table_identifier);
1292
 
 
1293
 
        quick_rm_table(*session, new_table_as_temporary);
1294
 
 
1295
 
        mysql_rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
 
1309
        error= ER_ERROR_ON_RENAME;
 
1310
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1296
1311
      }
1297
1312
      else
1298
1313
      {
1299
 
        quick_rm_table(*session, original_table_to_drop);
1300
 
      }
1301
 
    }
1302
 
 
1303
 
    if (error)
1304
 
    {
1305
 
      /*
1306
 
        An error happened while we were holding exclusive name-lock on table
1307
 
        being altered. To be safe under LOCK TABLES we should remove placeholders
1308
 
        from list of open tables list and table cache.
1309
 
      */
1310
 
      session->unlink_open_table(table);
1311
 
      LOCK_open.unlock();
1312
 
 
1313
 
      return true;
1314
 
    }
1315
 
 
1316
 
    LOCK_open.unlock();
 
1314
        if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
 
1315
        {
 
1316
          /* Try to get everything back. */
 
1317
          rename_error= ER_ERROR_ON_RENAME;
 
1318
 
 
1319
          plugin::StorageEngine::dropTable(*session, new_table_identifier);
 
1320
 
 
1321
          plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
 
1322
 
 
1323
          rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
 
1324
        }
 
1325
        else
 
1326
        {
 
1327
          plugin::StorageEngine::dropTable(*session, original_table_to_drop);
 
1328
        }
 
1329
      }
 
1330
 
 
1331
      if (rename_error)
 
1332
      {
 
1333
        /*
 
1334
          An error happened while we were holding exclusive name-lock on table
 
1335
          being altered. To be safe under LOCK TABLES we should remove placeholders
 
1336
          from list of open tables list and table cache.
 
1337
        */
 
1338
        session->unlink_open_table(table);
 
1339
 
 
1340
        return true;
 
1341
      }
 
1342
    }
1317
1343
 
1318
1344
    session->set_proc_info("end");
1319
1345
 
1320
 
    write_bin_log(session, session->query.c_str());
 
1346
    write_bin_log(session, *session->getQueryString());
1321
1347
    table_list->table= NULL;
1322
1348
  }
1323
1349
 
1336
1362
           (ulong) (copied + deleted), (ulong) deleted,
1337
1363
           (ulong) session->cuted_fields);
1338
1364
  session->my_ok(copied + deleted, 0, 0L, tmp_name);
1339
 
  session->some_tables_deleted= 0;
 
1365
  session->some_tables_deleted= false;
1340
1366
 
1341
1367
  return false;
1342
1368
}
1343
1369
 
1344
1370
bool alter_table(Session *session,
1345
 
                 TableIdentifier &original_table_identifier,
1346
 
                 TableIdentifier &new_table_identifier,
 
1371
                 identifier::Table &original_table_identifier,
 
1372
                 identifier::Table &new_table_identifier,
1347
1373
                 HA_CREATE_INFO *create_info,
1348
1374
                 const message::Table &original_proto,
1349
1375
                 message::Table &create_proto,
1359
1385
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1360
1386
  {
1361
1387
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1362
 
    return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
 
1388
    return discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1363
1389
  }
1364
1390
 
1365
1391
  session->set_proc_info("init");
1396
1422
 
1397
1423
    if (name_lock)
1398
1424
    {
1399
 
      LOCK_open.lock(); /* ALTER TABLe */
 
1425
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1400
1426
      session->unlink_open_table(name_lock);
1401
 
      LOCK_open.unlock();
1402
1427
    }
1403
1428
  }
1404
1429
 
1441
1466
  /* 
1442
1467
   * LP Bug #552420 
1443
1468
   *
1444
 
   * Since open_temporary_table() doesn't invoke mysql_lock_tables(), we
 
1469
   * Since open_temporary_table() doesn't invoke lockTables(), we
1445
1470
   * don't get the usual automatic call to StorageEngine::startStatement(), so
1446
1471
   * we manually call it here...
1447
1472
   */
1457
1482
  alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(), keys_onoff);
1458
1483
 
1459
1484
  /* We can abort alter table for any table type */
1460
 
  session->abort_on_warning= !ignore;
 
1485
  session->setAbortOnWarning(not ignore);
1461
1486
 
1462
1487
  from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1463
1488
  to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1464
1489
 
1465
 
  List_iterator<CreateField> it(create);
 
1490
  List<CreateField>::iterator it(create.begin());
1466
1491
  CreateField *def;
1467
 
  copy_end=copy;
 
1492
  copy_end= copy;
1468
1493
  for (Field **ptr= to->getFields(); *ptr ; ptr++)
1469
1494
  {
1470
1495
    def=it++;
1480
1505
 
1481
1506
  found_count=delete_count=0;
1482
1507
 
1483
 
  if (order)
 
1508
  do
1484
1509
  {
1485
 
    if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1486
 
    {
1487
 
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
1488
 
      snprintf(warn_buff, sizeof(warn_buff),
1489
 
               _("order_st BY ignored because there is a user-defined clustered "
1490
 
                 "index in the table '%-.192s'"),
1491
 
               from->getMutableShare()->getTableName());
1492
 
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1493
 
                   warn_buff);
1494
 
    }
1495
 
    else
1496
 
    {
1497
 
      from->sort.io_cache= new internal::IO_CACHE;
1498
 
 
1499
 
      memset(&tables, 0, sizeof(tables));
1500
 
      tables.table= from;
1501
 
      tables.setTableName(const_cast<char *>(from->getMutableShare()->getTableName()));
1502
 
      tables.alias= const_cast<char *>(tables.getTableName());
1503
 
      tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1504
 
      error= 1;
1505
 
 
1506
 
      if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1507
 
          setup_order(session, session->lex->select_lex.ref_pointer_array,
1508
 
                      &tables, fields, all_fields, order) ||
1509
 
          !(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1510
 
          (from->sort.found_records= filesort(session, from, sortorder, length,
1511
 
                                              (optimizer::SqlSelect *) 0, HA_POS_ERROR,
1512
 
                                              1, &examined_rows)) ==
1513
 
          HA_POS_ERROR)
 
1510
    if (order)
 
1511
    {
 
1512
      if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1514
1513
      {
1515
 
        goto err;
 
1514
        char warn_buff[DRIZZLE_ERRMSG_SIZE];
 
1515
        snprintf(warn_buff, sizeof(warn_buff),
 
1516
                 _("order_st BY ignored because there is a user-defined clustered "
 
1517
                   "index in the table '%-.192s'"),
 
1518
                 from->getMutableShare()->getTableName());
 
1519
        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
 
1520
                     warn_buff);
1516
1521
      }
1517
 
    }
1518
 
  }
1519
 
 
1520
 
  /* Tell handler that we have values for all columns in the to table */
1521
 
  to->use_all_columns();
1522
 
  info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1523
 
  if (ignore)
1524
 
    to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1525
 
  session->row_count= 0;
1526
 
  to->restoreRecordAsDefault();        // Create empty record
1527
 
  while (!(error=info.read_record(&info)))
1528
 
  {
1529
 
    if (session->killed)
1530
 
    {
1531
 
      session->send_kill_message();
1532
 
      error= 1;
1533
 
      break;
1534
 
    }
1535
 
    session->row_count++;
1536
 
    /* Return error if source table isn't empty. */
1537
 
    if (error_if_not_empty)
1538
 
    {
1539
 
      error= 1;
1540
 
      break;
1541
 
    }
1542
 
    if (to->next_number_field)
1543
 
    {
1544
 
      if (auto_increment_field_copied)
1545
 
        to->auto_increment_field_not_null= true;
1546
1522
      else
1547
 
        to->next_number_field->reset();
1548
 
    }
1549
 
 
1550
 
    for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1551
 
    {
1552
 
      copy_ptr->do_copy(copy_ptr);
1553
 
    }
1554
 
    prev_insert_id= to->cursor->next_insert_id;
1555
 
    error= to->cursor->insertRecord(to->record[0]);
1556
 
    to->auto_increment_field_not_null= false;
1557
 
 
 
1523
      {
 
1524
        FileSort filesort(*session);
 
1525
        from->sort.io_cache= new internal::IO_CACHE;
 
1526
 
 
1527
        tables.table= from;
 
1528
        tables.setTableName(from->getMutableShare()->getTableName());
 
1529
        tables.alias= tables.getTableName();
 
1530
        tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
 
1531
        error= 1;
 
1532
 
 
1533
        if (session->getLex()->select_lex.setup_ref_array(session, order_num) ||
 
1534
            setup_order(session, session->getLex()->select_lex.ref_pointer_array,
 
1535
                        &tables, fields, all_fields, order) ||
 
1536
            !(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
 
1537
            (from->sort.found_records= filesort.run(from, sortorder, length,
 
1538
                                                    (optimizer::SqlSelect *) 0, HA_POS_ERROR,
 
1539
                                                    1, examined_rows)) == HA_POS_ERROR)
 
1540
        {
 
1541
          break;
 
1542
        }
 
1543
      }
 
1544
    }
 
1545
 
 
1546
    /* Tell handler that we have values for all columns in the to table */
 
1547
    to->use_all_columns();
 
1548
 
 
1549
    error= info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1558
1550
    if (error)
1559
 
    { 
1560
 
      if (!ignore ||
1561
 
          to->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
1551
    {
 
1552
      to->print_error(errno, MYF(0));
 
1553
 
 
1554
      break;
 
1555
    }
 
1556
 
 
1557
    if (ignore)
 
1558
    {
 
1559
      to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
 
1560
    }
 
1561
 
 
1562
    session->row_count= 0;
 
1563
    to->restoreRecordAsDefault();        // Create empty record
 
1564
    while (not (error=info.read_record(&info)))
 
1565
    {
 
1566
      if (session->getKilled())
 
1567
      {
 
1568
        session->send_kill_message();
 
1569
        error= 1;
 
1570
        break;
 
1571
      }
 
1572
      session->row_count++;
 
1573
      /* Return error if source table isn't empty. */
 
1574
      if (error_if_not_empty)
 
1575
      {
 
1576
        error= 1;
 
1577
        break;
 
1578
      }
 
1579
      if (to->next_number_field)
 
1580
      {
 
1581
        if (auto_increment_field_copied)
 
1582
          to->auto_increment_field_not_null= true;
 
1583
        else
 
1584
          to->next_number_field->reset();
 
1585
      }
 
1586
 
 
1587
      for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
 
1588
      {
 
1589
        if (not copy->to_field->hasDefault() and copy->from_null_ptr and  *copy->from_null_ptr & copy->from_bit)
 
1590
        {
 
1591
          copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1592
                                      ER_WARN_DATA_TRUNCATED, 1);
 
1593
          copy->to_field->reset();
 
1594
          error= 1;
 
1595
          break;
 
1596
        }
 
1597
 
 
1598
        copy_ptr->do_copy(copy_ptr);
 
1599
      }
 
1600
 
 
1601
      if (error)
 
1602
      {
 
1603
        break;
 
1604
      }
 
1605
 
 
1606
      prev_insert_id= to->cursor->next_insert_id;
 
1607
      error= to->cursor->insertRecord(to->record[0]);
 
1608
      to->auto_increment_field_not_null= false;
 
1609
 
 
1610
      if (error)
1562
1611
      { 
1563
 
        to->print_error(error, MYF(0));
1564
 
        break;
1565
 
      }
1566
 
      to->cursor->restore_auto_increment(prev_insert_id);
1567
 
      delete_count++;
 
1612
        if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
1613
        { 
 
1614
          to->print_error(error, MYF(0));
 
1615
          break;
 
1616
        }
 
1617
        to->cursor->restore_auto_increment(prev_insert_id);
 
1618
        delete_count++;
 
1619
      }
 
1620
      else
 
1621
      {
 
1622
        found_count++;
 
1623
      }
1568
1624
    }
1569
 
    else
 
1625
 
 
1626
    info.end_read_record();
 
1627
    from->free_io_cache();
 
1628
    delete [] copy;                             // This is never 0
 
1629
 
 
1630
    if (to->cursor->ha_end_bulk_insert() && error <= 0)
1570
1631
    {
1571
 
      found_count++;
 
1632
      to->print_error(errno, MYF(0));
 
1633
      error= 1;
1572
1634
    }
1573
 
  }
1574
 
 
1575
 
  info.end_read_record();
1576
 
  from->free_io_cache();
1577
 
  delete [] copy;                               // This is never 0
1578
 
 
1579
 
  if (to->cursor->ha_end_bulk_insert() && error <= 0)
1580
 
  {
1581
 
    to->print_error(errno, MYF(0));
1582
 
    error=1;
1583
 
  }
1584
 
  to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1585
 
 
1586
 
  /*
1587
 
    Ensure that the new table is saved properly to disk so that we
1588
 
    can do a rename
1589
 
  */
1590
 
  if (transaction_services.autocommitOrRollback(session, false))
1591
 
    error=1;
1592
 
  if (! session->endActiveTransaction())
1593
 
    error=1;
1594
 
 
1595
 
 err:
1596
 
  session->abort_on_warning= 0;
 
1635
    to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
 
1636
 
 
1637
    /*
 
1638
      Ensure that the new table is saved properly to disk so that we
 
1639
      can do a rename
 
1640
    */
 
1641
    if (transaction_services.autocommitOrRollback(*session, false))
 
1642
      error= 1;
 
1643
 
 
1644
    if (not session->endActiveTransaction())
 
1645
      error= 1;
 
1646
 
 
1647
  } while (0);
 
1648
 
 
1649
  session->setAbortOnWarning(false);
1597
1650
  from->free_io_cache();
1598
1651
  *copied= found_count;
1599
1652
  *deleted=delete_count;
1600
1653
  to->cursor->ha_release_auto_increment();
1601
 
  if (to->cursor->ha_external_lock(session,F_UNLCK))
 
1654
 
 
1655
  if (to->cursor->ha_external_lock(session, F_UNLCK))
 
1656
  {
1602
1657
    error=1;
 
1658
  }
1603
1659
 
1604
1660
  return(error > 0 ? -1 : 0);
1605
1661
}
1606
1662
 
1607
 
static int
1608
 
create_temporary_table(Session *session,
1609
 
                       TableIdentifier &identifier,
1610
 
                       HA_CREATE_INFO *create_info,
1611
 
                       message::Table &create_proto,
1612
 
                       AlterInfo *alter_info)
1613
 
{
1614
 
  int error;
1615
 
 
1616
 
  /*
1617
 
    Create a table with a temporary name.
1618
 
    We don't log the statement, it will be logged later.
1619
 
  */
1620
 
  create_proto.set_name(identifier.getTableName());
1621
 
 
1622
 
  create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1623
 
 
1624
 
  error= mysql_create_table(session,
1625
 
                            identifier,
1626
 
                            create_info, create_proto, alter_info, true, 0, false);
1627
 
 
1628
 
  return error;
1629
 
}
1630
 
 
1631
 
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
 
1663
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
1632
1664
{
1633
1665
  Table *new_table;
1634
1666