~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Monty Taylor
  • Date: 2010-11-08 18:26:08 UTC
  • mto: This revision was merged to the branch mainline in revision 1931.
  • Revision ID: mordred@inaugust.com-20101108182608-lci86acl7r53sbi3
Replaced auto_ptr with scoped_ptr.

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