~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Stewart Smith
  • Date: 2010-11-07 04:22:31 UTC
  • mto: (1911.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1912.
  • Revision ID: stewart@flamingspork.com-20101107042231-ola4sl7j0qvg58tz
fix ARCHIVE storage engine calling exit (lintian warning). Was because we were linking in libinternal into libazio, which links into archive plugin. Just link libinternal into the command line utilities.

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