~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Brian Aker
  • Date: 2009-09-16 21:56:01 UTC
  • mfrom: (1126.2.5 merge)
  • Revision ID: brian@gaz-20090916215601-o8gy2wmwt0pgfp86
Merge Jay Alter table + Brian dead code

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
#include <drizzled/session.h>
25
25
#include <drizzled/statement/alter_table.h>
26
26
 
 
27
#include "drizzled/gettext.h"
 
28
#include "drizzled/data_home.h"
 
29
#include "drizzled/sql_table.h"
 
30
#include "drizzled/table_proto.h"
 
31
 
27
32
using namespace drizzled;
28
33
 
 
34
static int copy_data_between_tables(Table *from,Table *to,
 
35
                                    List<CreateField> &create,
 
36
                                    bool ignore,
 
37
                                    uint32_t order_num,
 
38
                                    order_st *order,
 
39
                                    ha_rows *copied,
 
40
                                    ha_rows *deleted,
 
41
                                    enum enum_enable_or_disable keys_onoff,
 
42
                                    bool error_if_not_empty);
 
43
static bool mysql_prepare_alter_table(Session *session,
 
44
                                      Table *table,
 
45
                                      HA_CREATE_INFO *create_info,
 
46
                                      message::Table *table_proto,
 
47
                                      AlterInfo *alter_info);
 
48
static int create_temporary_table(Session *session,
 
49
                                  Table *table,
 
50
                                  char *new_db,
 
51
                                  char *tmp_name,
 
52
                                  HA_CREATE_INFO *create_info,
 
53
                                  message::Table *create_proto,
 
54
                                  AlterInfo *alter_info);
 
55
 
29
56
bool statement::AlterTable::execute()
30
57
{
31
58
  TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
41
68
     referenced from this structure will be modified.
42
69
   */
43
70
  HA_CREATE_INFO create_info(session->lex->create_info);
44
 
  Alter_info alter_info(session->lex->alter_info, session->mem_root);
 
71
  AlterInfo alter_info(session->lex->alter_info, session->mem_root);
45
72
 
46
73
  if (session->is_fatal_error) /* out of memory creating a copy of alter_info */
47
74
  {
51
78
  /* Must be set in the parser */
52
79
  assert(select_lex->db);
53
80
 
54
 
  { // Rename of table
55
 
    TableList tmp_table;
56
 
    memset(&tmp_table, 0, sizeof(tmp_table));
57
 
    tmp_table.table_name= session->lex->name.str;
58
 
    tmp_table.db= select_lex->db;
59
 
  }
60
 
 
61
81
  /* ALTER TABLE ends previous transaction */
62
82
  if (! session->endActiveTransaction())
63
83
  {
86
106
  start_waiting_global_read_lock(session);
87
107
  return res;
88
108
}
 
109
 
 
110
/**
 
111
  Prepare column and key definitions for CREATE TABLE in ALTER Table.
 
112
 
 
113
  This function transforms parse output of ALTER Table - lists of
 
114
  columns and keys to add, drop or modify into, essentially,
 
115
  CREATE TABLE definition - a list of columns and keys of the new
 
116
  table. While doing so, it also performs some (bug not all)
 
117
  semantic checks.
 
118
 
 
119
  This function is invoked when we know that we're going to
 
120
  perform ALTER Table via a temporary table -- i.e. fast ALTER Table
 
121
  is not possible, perhaps because the ALTER statement contains
 
122
  instructions that require change in table data, not only in
 
123
  table definition or indexes.
 
124
 
 
125
  @param[in,out]  session         thread handle. Used as a memory pool
 
126
                              and source of environment information.
 
127
  @param[in]      table       the source table, open and locked
 
128
                              Used as an interface to the storage engine
 
129
                              to acquire additional information about
 
130
                              the original table.
 
131
  @param[in,out]  create_info A blob with CREATE/ALTER Table
 
132
                              parameters
 
133
  @param[in,out]  alter_info  Another blob with ALTER/CREATE parameters.
 
134
                              Originally create_info was used only in
 
135
                              CREATE TABLE and alter_info only in ALTER Table.
 
136
                              But since ALTER might end-up doing CREATE,
 
137
                              this distinction is gone and we just carry
 
138
                              around two structures.
 
139
 
 
140
  @return
 
141
    Fills various create_info members based on information retrieved
 
142
    from the storage engine.
 
143
    Sets create_info->varchar if the table has a VARCHAR column.
 
144
    Prepares alter_info->create_list and alter_info->key_list with
 
145
    columns and keys of the new table.
 
146
  @retval true   error, out of memory or a semantical error in ALTER
 
147
                 Table instructions
 
148
  @retval false  success
 
149
*/
 
150
static bool mysql_prepare_alter_table(Session *session,
 
151
                                      Table *table,
 
152
                                      HA_CREATE_INFO *create_info,
 
153
                                      message::Table *table_proto,
 
154
                                      AlterInfo *alter_info)
 
155
{
 
156
  /* New column definitions are added here */
 
157
  List<CreateField> new_create_list;
 
158
  /* New key definitions are added here */
 
159
  List<Key> new_key_list;
 
160
  List_iterator<AlterDrop> drop_it(alter_info->drop_list);
 
161
  List_iterator<CreateField> def_it(alter_info->create_list);
 
162
  List_iterator<AlterColumn> alter_it(alter_info->alter_list);
 
163
  List_iterator<Key> key_it(alter_info->key_list);
 
164
  List_iterator<CreateField> find_it(new_create_list);
 
165
  List_iterator<CreateField> field_it(new_create_list);
 
166
  List<Key_part_spec> key_parts;
 
167
  uint32_t used_fields= create_info->used_fields;
 
168
  KEY *key_info= table->key_info;
 
169
  bool rc= true;
 
170
 
 
171
  /* Let new create options override the old ones */
 
172
  message::Table::TableOptions *table_options;
 
173
  table_options= table_proto->mutable_options();
 
174
 
 
175
  if (! (used_fields & HA_CREATE_USED_BLOCK_SIZE))
 
176
    table_options->set_block_size(table->s->block_size);
 
177
  if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
 
178
    create_info->default_table_charset= table->s->table_charset;
 
179
  if (! (used_fields & HA_CREATE_USED_AUTO) &&
 
180
      table->found_next_number_field)
 
181
  {
 
182
    /* Table has an autoincrement, copy value to new table */
 
183
    table->file->info(HA_STATUS_AUTO);
 
184
    create_info->auto_increment_value= table->file->stats.auto_increment_value;
 
185
  }
 
186
  if (! (used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
 
187
    create_info->key_block_size= table->s->key_block_size;
 
188
 
 
189
  table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
 
190
  CreateField *def;
 
191
 
 
192
  /* First collect all fields from table which isn't in drop_list */
 
193
  Field **f_ptr;
 
194
  Field *field;
 
195
  for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
 
196
  {
 
197
    /* Check if field should be dropped */
 
198
    AlterDrop *drop;
 
199
    drop_it.rewind();
 
200
    while ((drop= drop_it++))
 
201
    {
 
202
      if (drop->type == AlterDrop::COLUMN &&
 
203
          ! my_strcasecmp(system_charset_info, field->field_name, drop->name))
 
204
      {
 
205
        /* Reset auto_increment value if it was dropped */
 
206
        if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
 
207
            ! (used_fields & HA_CREATE_USED_AUTO))
 
208
        {
 
209
          create_info->auto_increment_value= 0;
 
210
          create_info->used_fields|= HA_CREATE_USED_AUTO;
 
211
        }
 
212
        break;
 
213
      }
 
214
    }
 
215
    if (drop)
 
216
    {
 
217
      drop_it.remove();
 
218
      continue;
 
219
    }
 
220
    
 
221
    /* Mark that we will read the field */
 
222
    field->setReadSet();
 
223
 
 
224
    /* Check if field is changed */
 
225
    def_it.rewind();
 
226
    while ((def= def_it++))
 
227
    {
 
228
      if (def->change &&
 
229
          ! my_strcasecmp(system_charset_info, field->field_name, def->change))
 
230
              break;
 
231
    }
 
232
    if (def)
 
233
    {
 
234
      /* Field is changed */
 
235
      def->field= field;
 
236
      if (! def->after)
 
237
      {
 
238
        new_create_list.push_back(def);
 
239
        def_it.remove();
 
240
      }
 
241
    }
 
242
    else
 
243
    {
 
244
      /*
 
245
        This field was not dropped and not changed, add it to the list
 
246
        for the new table.
 
247
      */
 
248
      def= new CreateField(field, field);
 
249
      new_create_list.push_back(def);
 
250
      alter_it.rewind(); /* Change default if ALTER */
 
251
      AlterColumn *alter;
 
252
      while ((alter= alter_it++))
 
253
      {
 
254
        if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
 
255
          break;
 
256
      }
 
257
      if (alter)
 
258
      {
 
259
        if (def->sql_type == DRIZZLE_TYPE_BLOB)
 
260
        {
 
261
          my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
 
262
                goto err;
 
263
        }
 
264
        if ((def->def= alter->def))
 
265
        {
 
266
          /* Use new default */
 
267
          def->flags&= ~NO_DEFAULT_VALUE_FLAG;
 
268
        }
 
269
        else
 
270
          def->flags|= NO_DEFAULT_VALUE_FLAG;
 
271
        alter_it.remove();
 
272
      }
 
273
    }
 
274
  }
 
275
  def_it.rewind();
 
276
  while ((def= def_it++)) /* Add new columns */
 
277
  {
 
278
    if (def->change && ! def->field)
 
279
    {
 
280
      my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
 
281
      goto err;
 
282
    }
 
283
    /*
 
284
      Check that the DATE/DATETIME not null field we are going to add is
 
285
      either has a default value or the '0000-00-00' is allowed by the
 
286
      set sql mode.
 
287
      If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
 
288
      flag to allow ALTER Table only if the table to be altered is empty.
 
289
    */
 
290
    if ((def->sql_type == DRIZZLE_TYPE_DATE ||
 
291
         def->sql_type == DRIZZLE_TYPE_DATETIME) &&
 
292
        ! alter_info->datetime_field &&
 
293
        ! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
 
294
        session->variables.sql_mode & MODE_NO_ZERO_DATE)
 
295
    {
 
296
      alter_info->datetime_field= def;
 
297
      alter_info->error_if_not_empty= true;
 
298
    }
 
299
    if (! def->after)
 
300
      new_create_list.push_back(def);
 
301
    else if (def->after == first_keyword)
 
302
      new_create_list.push_front(def);
 
303
    else
 
304
    {
 
305
      CreateField *find;
 
306
      find_it.rewind();
 
307
      while ((find= find_it++)) /* Add new columns */
 
308
      {
 
309
        if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
 
310
          break;
 
311
      }
 
312
      if (! find)
 
313
      {
 
314
        my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
 
315
        goto err;
 
316
      }
 
317
      find_it.after(def); /* Put element after this */
 
318
      /*
 
319
        XXX: hack for Bug#28427.
 
320
        If column order has changed, force OFFLINE ALTER Table
 
321
        without querying engine capabilities.  If we ever have an
 
322
        engine that supports online ALTER Table CHANGE COLUMN
 
323
        <name> AFTER <name1> (Falcon?), this fix will effectively
 
324
        disable the capability.
 
325
        TODO: detect the situation in compare_tables, behave based
 
326
        on engine capabilities.
 
327
      */
 
328
      if (alter_info->build_method == HA_BUILD_ONLINE)
 
329
      {
 
330
        my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
 
331
        goto err;
 
332
      }
 
333
      alter_info->build_method= HA_BUILD_OFFLINE;
 
334
    }
 
335
  }
 
336
  if (alter_info->alter_list.elements)
 
337
  {
 
338
    my_error(ER_BAD_FIELD_ERROR,
 
339
             MYF(0),
 
340
             alter_info->alter_list.head()->name,
 
341
             table->s->table_name.str);
 
342
    goto err;
 
343
  }
 
344
  if (! new_create_list.elements)
 
345
  {
 
346
    my_message(ER_CANT_REMOVE_ALL_FIELDS,
 
347
               ER(ER_CANT_REMOVE_ALL_FIELDS),
 
348
               MYF(0));
 
349
    goto err;
 
350
  }
 
351
 
 
352
  /*
 
353
    Collect all keys which isn't in drop list. Add only those
 
354
    for which some fields exists.
 
355
  */
 
356
  for (uint32_t i= 0; i < table->s->keys; i++, key_info++)
 
357
  {
 
358
    char *key_name= key_info->name;
 
359
    AlterDrop *drop;
 
360
    drop_it.rewind();
 
361
    while ((drop= drop_it++))
 
362
    {
 
363
      if (drop->type == AlterDrop::KEY &&
 
364
          ! my_strcasecmp(system_charset_info, key_name, drop->name))
 
365
        break;
 
366
    }
 
367
    if (drop)
 
368
    {
 
369
      drop_it.remove();
 
370
      continue;
 
371
    }
 
372
 
 
373
    KEY_PART_INFO *key_part= key_info->key_part;
 
374
    key_parts.empty();
 
375
    for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
 
376
    {
 
377
      if (! key_part->field)
 
378
              continue; /* Wrong field (from UNIREG) */
 
379
 
 
380
      const char *key_part_name= key_part->field->field_name;
 
381
      CreateField *cfield;
 
382
      field_it.rewind();
 
383
      while ((cfield= field_it++))
 
384
      {
 
385
        if (cfield->change)
 
386
        {
 
387
          if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
 
388
            break;
 
389
        }
 
390
        else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
 
391
          break;
 
392
      }
 
393
      if (! cfield)
 
394
              continue; /* Field is removed */
 
395
      
 
396
      uint32_t key_part_length= key_part->length;
 
397
      if (cfield->field) /* Not new field */
 
398
      {
 
399
        /*
 
400
          If the field can't have only a part used in a key according to its
 
401
          new type, or should not be used partially according to its
 
402
          previous type, or the field length is less than the key part
 
403
          length, unset the key part length.
 
404
 
 
405
          We also unset the key part length if it is the same as the
 
406
          old field's length, so the whole new field will be used.
 
407
 
 
408
          BLOBs may have cfield->length == 0, which is why we test it before
 
409
          checking whether cfield->length < key_part_length (in chars).
 
410
         */
 
411
        if (! Field::type_can_have_key_part(cfield->field->type()) ||
 
412
            ! Field::type_can_have_key_part(cfield->sql_type) ||
 
413
            (cfield->field->field_length == key_part_length &&
 
414
             ! f_is_blob(key_part->key_type)) ||
 
415
            (cfield->length &&
 
416
             (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
 
417
          key_part_length= 0; /* Use whole field */
 
418
      }
 
419
      key_part_length/= key_part->field->charset()->mbmaxlen;
 
420
      key_parts.push_back(new Key_part_spec(cfield->field_name,
 
421
                                            strlen(cfield->field_name),
 
422
                                            key_part_length));
 
423
    }
 
424
    if (key_parts.elements)
 
425
    {
 
426
      KEY_CREATE_INFO key_create_info;
 
427
      Key *key;
 
428
      enum Key::Keytype key_type;
 
429
      memset(&key_create_info, 0, sizeof(key_create_info));
 
430
 
 
431
      key_create_info.algorithm= key_info->algorithm;
 
432
      if (key_info->flags & HA_USES_BLOCK_SIZE)
 
433
        key_create_info.block_size= key_info->block_size;
 
434
      if (key_info->flags & HA_USES_COMMENT)
 
435
        key_create_info.comment= key_info->comment;
 
436
 
 
437
      if (key_info->flags & HA_NOSAME)
 
438
      {
 
439
        if (is_primary_key_name(key_name))
 
440
          key_type= Key::PRIMARY;
 
441
        else
 
442
          key_type= Key::UNIQUE;
 
443
      }
 
444
      else
 
445
        key_type= Key::MULTIPLE;
 
446
 
 
447
      key= new Key(key_type,
 
448
                   key_name,
 
449
                   strlen(key_name),
 
450
                   &key_create_info,
 
451
                   test(key_info->flags & HA_GENERATED_KEY),
 
452
                   key_parts);
 
453
      new_key_list.push_back(key);
 
454
    }
 
455
  }
 
456
  {
 
457
    Key *key;
 
458
    while ((key= key_it++)) /* Add new keys */
 
459
    {
 
460
      if (key->type == Key::FOREIGN_KEY &&
 
461
          ((Foreign_key *)key)->validate(new_create_list))
 
462
        goto err;
 
463
      if (key->type != Key::FOREIGN_KEY)
 
464
        new_key_list.push_back(key);
 
465
      if (key->name.str && is_primary_key_name(key->name.str))
 
466
      {
 
467
        my_error(ER_WRONG_NAME_FOR_INDEX,
 
468
                 MYF(0),
 
469
                 key->name.str);
 
470
        goto err;
 
471
      }
 
472
    }
 
473
  }
 
474
 
 
475
  if (alter_info->drop_list.elements)
 
476
  {
 
477
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
 
478
             MYF(0),
 
479
             alter_info->drop_list.head()->name);
 
480
    goto err;
 
481
  }
 
482
  if (alter_info->alter_list.elements)
 
483
  {
 
484
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
 
485
             MYF(0),
 
486
             alter_info->alter_list.head()->name);
 
487
    goto err;
 
488
  }
 
489
 
 
490
  if (! table_proto->options().has_comment()
 
491
      && table->s->hasComment())
 
492
    table_options->set_comment(table->s->getComment());
 
493
 
 
494
  if (table->s->tmp_table)
 
495
    create_info->options|= HA_LEX_CREATE_TMP_TABLE;
 
496
 
 
497
  rc= false;
 
498
  alter_info->create_list.swap(new_create_list);
 
499
  alter_info->key_list.swap(new_key_list);
 
500
err:
 
501
  return rc;
 
502
}
 
503
 
 
504
/* table_list should contain just one table */
 
505
static int mysql_discard_or_import_tablespace(Session *session,
 
506
                                              TableList *table_list,
 
507
                                              enum tablespace_op_type tablespace_op)
 
508
{
 
509
  Table *table;
 
510
  bool discard;
 
511
  int error;
 
512
 
 
513
  /*
 
514
    Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
 
515
    ALTER Table
 
516
  */
 
517
 
 
518
  session->set_proc_info("discard_or_import_tablespace");
 
519
 
 
520
  discard= test(tablespace_op == DISCARD_TABLESPACE);
 
521
 
 
522
 /*
 
523
   We set this flag so that ha_innobase::open and ::external_lock() do
 
524
   not complain when we lock the table
 
525
 */
 
526
  session->tablespace_op= true;
 
527
  if (!(table= session->openTableLock(table_list, TL_WRITE)))
 
528
  {
 
529
    session->tablespace_op= false;
 
530
    return -1;
 
531
  }
 
532
 
 
533
  error= table->file->ha_discard_or_import_tablespace(discard);
 
534
 
 
535
  session->set_proc_info("end");
 
536
 
 
537
  if (error)
 
538
    goto err;
 
539
 
 
540
  /* The ALTER Table is always in its own transaction */
 
541
  error = ha_autocommit_or_rollback(session, 0);
 
542
  if (! session->endActiveTransaction())
 
543
    error=1;
 
544
  if (error)
 
545
    goto err;
 
546
  write_bin_log(session, false, session->query, session->query_length);
 
547
 
 
548
err:
 
549
  ha_autocommit_or_rollback(session, error);
 
550
  session->tablespace_op=false;
 
551
 
 
552
  if (error == 0)
 
553
  {
 
554
    session->my_ok();
 
555
    return 0;
 
556
  }
 
557
 
 
558
  table->file->print_error(error, MYF(0));
 
559
 
 
560
  return -1;
 
561
}
 
562
 
 
563
/**
 
564
  Manages enabling/disabling of indexes for ALTER Table
 
565
 
 
566
  SYNOPSIS
 
567
    alter_table_manage_keys()
 
568
      table                  Target table
 
569
      indexes_were_disabled  Whether the indexes of the from table
 
570
                             were disabled
 
571
      keys_onoff             ENABLE | DISABLE | LEAVE_AS_IS
 
572
 
 
573
  RETURN VALUES
 
574
    false  OK
 
575
    true   Error
 
576
*/
 
577
static bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
 
578
                             enum enum_enable_or_disable keys_onoff)
 
579
{
 
580
  int error= 0;
 
581
  switch (keys_onoff) {
 
582
  case ENABLE:
 
583
    error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
584
    break;
 
585
  case LEAVE_AS_IS:
 
586
    if (!indexes_were_disabled)
 
587
      break;
 
588
    /* fall-through: disabled indexes */
 
589
  case DISABLE:
 
590
    error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
591
  }
 
592
 
 
593
  if (error == HA_ERR_WRONG_COMMAND)
 
594
  {
 
595
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
596
                        ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
 
597
                        table->s->table_name.str);
 
598
    error= 0;
 
599
  } else if (error)
 
600
    table->file->print_error(error, MYF(0));
 
601
 
 
602
  return(error);
 
603
}
 
604
 
 
605
/**
 
606
  Alter table
 
607
 
 
608
  SYNOPSIS
 
609
    mysql_alter_table()
 
610
      session              Thread handle
 
611
      new_db           If there is a RENAME clause
 
612
      new_name         If there is a RENAME clause
 
613
      create_info      Information from the parsing phase about new
 
614
                       table properties.
 
615
      table_list       The table to change.
 
616
      alter_info       Lists of fields, keys to be changed, added
 
617
                       or dropped.
 
618
      order_num        How many order_st BY fields has been specified.
 
619
      order            List of fields to order_st BY.
 
620
      ignore           Whether we have ALTER IGNORE Table
 
621
 
 
622
  DESCRIPTION
 
623
    This is a veery long function and is everything but the kitchen sink :)
 
624
    It is used to alter a table and not only by ALTER Table but also
 
625
    CREATE|DROP INDEX are mapped on this function.
 
626
 
 
627
    When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
 
628
    or both, then this function short cuts its operation by renaming
 
629
    the table and/or enabling/disabling the keys. In this case, the FRM is
 
630
    not changed, directly by mysql_alter_table. However, if there is a
 
631
    RENAME + change of a field, or an index, the short cut is not used.
 
632
    See how `create_list` is used to generate the new FRM regarding the
 
633
    structure of the fields. The same is done for the indices of the table.
 
634
 
 
635
    Important is the fact, that this function tries to do as little work as
 
636
    possible, by finding out whether a intermediate table is needed to copy
 
637
    data into and when finishing the altering to use it as the original table.
 
638
    For this reason the function compare_tables() is called, which decides
 
639
    based on all kind of data how similar are the new and the original
 
640
    tables.
 
641
 
 
642
  RETURN VALUES
 
643
    false  OK
 
644
    true   Error
 
645
*/
 
646
bool mysql_alter_table(Session *session,
 
647
                       char *new_db,
 
648
                       char *new_name,
 
649
                       HA_CREATE_INFO *create_info,
 
650
                       message::Table *create_proto,
 
651
                       TableList *table_list,
 
652
                       AlterInfo *alter_info,
 
653
                       uint32_t order_num,
 
654
                       order_st *order,
 
655
                       bool ignore)
 
656
{
 
657
  Table *table;
 
658
  Table *new_table= NULL;
 
659
  Table *name_lock= NULL;
 
660
  string new_name_str;
 
661
  int error= 0;
 
662
  char tmp_name[80];
 
663
  char old_name[32];
 
664
  char new_name_buff[FN_REFLEN];
 
665
  char new_alias_buff[FN_REFLEN];
 
666
  char *table_name;
 
667
  char *db;
 
668
  const char *new_alias;
 
669
  char path[FN_REFLEN];
 
670
  ha_rows copied= 0;
 
671
  ha_rows deleted= 0;
 
672
  StorageEngine *old_db_type;
 
673
  StorageEngine *new_db_type;
 
674
  StorageEngine *save_old_db_type;
 
675
  bitset<32> tmp;
 
676
 
 
677
  new_name_buff[0]= '\0';
 
678
 
 
679
  if (table_list && table_list->schema_table)
 
680
  {
 
681
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
 
682
    return true;
 
683
  }
 
684
 
 
685
  session->set_proc_info("init");
 
686
 
 
687
  /*
 
688
    Assign variables table_name, new_name, db, new_db, path
 
689
    to simplify further comparisons: we want to see if it's a RENAME
 
690
    later just by comparing the pointers, avoiding the need for strcmp.
 
691
  */
 
692
  table_name= table_list->table_name;
 
693
  db= table_list->db;
 
694
  if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
 
695
    new_db= db;
 
696
 
 
697
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
 
698
  {
 
699
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
 
700
    return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
 
701
  }
 
702
 
 
703
  build_table_filename(path, sizeof(path), db, table_name, false);
 
704
 
 
705
  ostringstream oss;
 
706
  oss << drizzle_data_home << "/" << db << "/" << table_name;
 
707
 
 
708
  (void) unpack_filename(new_name_buff, oss.str().c_str());
 
709
 
 
710
  /*
 
711
    If this is just a rename of a view, short cut to the
 
712
    following scenario: 1) lock LOCK_open 2) do a RENAME
 
713
    2) unlock LOCK_open.
 
714
    This is a copy-paste added to make sure
 
715
    ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
 
716
    as an independent branch in mysql_execute_command. The need
 
717
    for a copy-paste arose because the main code flow of ALTER Table
 
718
    ... RENAME tries to use openTableLock, which does not work for views
 
719
    (openTableLock was never modified to merge table lists of child tables
 
720
    into the main table list, like open_tables does).
 
721
    This code is wrong and will be removed, please do not copy.
 
722
  */
 
723
 
 
724
  if (!(table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
 
725
    return true;
 
726
  
 
727
  table->use_all_columns();
 
728
 
 
729
  /* Check that we are not trying to rename to an existing table */
 
730
  if (new_name)
 
731
  {
 
732
    strcpy(new_name_buff, new_name);
 
733
    strcpy(new_alias_buff, new_name);
 
734
    new_alias= new_alias_buff;
 
735
 
 
736
    my_casedn_str(files_charset_info, new_name_buff);
 
737
    new_alias= new_name; // Create lower case table name
 
738
    my_casedn_str(files_charset_info, new_name);
 
739
 
 
740
    if (new_db == db &&
 
741
        ! my_strcasecmp(table_alias_charset, new_name_buff, table_name))
 
742
    {
 
743
      /*
 
744
        Source and destination table names are equal: make later check
 
745
        easier.
 
746
      */
 
747
      new_alias= new_name= table_name;
 
748
    }
 
749
    else
 
750
    {
 
751
      if (table->s->tmp_table != NO_TMP_TABLE)
 
752
      {
 
753
        if (session->find_temporary_table(new_db, new_name_buff))
 
754
        {
 
755
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
 
756
          return true;
 
757
        }
 
758
      }
 
759
      else
 
760
      {
 
761
        if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
 
762
          return true;
 
763
 
 
764
        if (! name_lock)
 
765
        {
 
766
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
 
767
          return true;
 
768
        }
 
769
 
 
770
        build_table_filename(new_name_buff, sizeof(new_name_buff), new_db, new_name_buff, false);
 
771
 
 
772
        if (StorageEngine::getTableProto(new_name_buff, NULL) == EEXIST)
 
773
        {
 
774
          /* Table will be closed by Session::executeCommand() */
 
775
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
 
776
          goto err;
 
777
        }
 
778
      }
 
779
    }
 
780
  }
 
781
  else
 
782
  {
 
783
    new_alias= table_name;
 
784
    new_name= table_name;
 
785
  }
 
786
 
 
787
  old_db_type= table->s->db_type();
 
788
  if (! create_info->db_type)
 
789
  {
 
790
    create_info->db_type= old_db_type;
 
791
  }
 
792
 
 
793
  if (table->s->tmp_table != NO_TMP_TABLE)
 
794
    create_info->options|= HA_LEX_CREATE_TMP_TABLE;
 
795
 
 
796
  if (check_engine(session, new_name, create_info))
 
797
    goto err;
 
798
 
 
799
  new_db_type= create_info->db_type;
 
800
 
 
801
  if (new_db_type != old_db_type &&
 
802
      !table->file->can_switch_engines())
 
803
  {
 
804
    assert(0);
 
805
    my_error(ER_ROW_IS_REFERENCED, MYF(0));
 
806
    goto err;
 
807
  }
 
808
 
 
809
  if (create_info->row_type == ROW_TYPE_NOT_USED)
 
810
    create_info->row_type= table->s->row_type;
 
811
 
 
812
  if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
 
813
      new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
 
814
  {
 
815
    my_error(ER_ILLEGAL_HA, MYF(0), table_name);
 
816
    goto err;
 
817
  }
 
818
 
 
819
  session->set_proc_info("setup");
 
820
  
 
821
  /*
 
822
   * test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
 
823
   */
 
824
  tmp.set();
 
825
  tmp.reset(ALTER_RENAME);
 
826
  tmp.reset(ALTER_KEYS_ONOFF);
 
827
  tmp&= alter_info->flags;
 
828
  if (! (tmp.any()) &&
 
829
      ! table->s->tmp_table) // no need to touch frm
 
830
  {
 
831
    switch (alter_info->keys_onoff)
 
832
    {
 
833
    case LEAVE_AS_IS:
 
834
      break;
 
835
    case ENABLE:
 
836
      /*
 
837
        wait_while_table_is_used() ensures that table being altered is
 
838
        opened only by this thread and that Table::TableShare::version
 
839
        of Table object corresponding to this table is 0.
 
840
        The latter guarantees that no DML statement will open this table
 
841
        until ALTER Table finishes (i.e. until close_thread_tables())
 
842
        while the fact that the table is still open gives us protection
 
843
        from concurrent DDL statements.
 
844
      */
 
845
      pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
 
846
      wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
 
847
      pthread_mutex_unlock(&LOCK_open);
 
848
      error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
849
      /* COND_refresh will be signaled in close_thread_tables() */
 
850
      break;
 
851
    case DISABLE:
 
852
      pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
 
853
      wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
 
854
      pthread_mutex_unlock(&LOCK_open);
 
855
      error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
856
      /* COND_refresh will be signaled in close_thread_tables() */
 
857
      break;
 
858
    default:
 
859
      assert(false);
 
860
      error= 0;
 
861
      break;
 
862
    }
 
863
 
 
864
    if (error == HA_ERR_WRONG_COMMAND)
 
865
    {
 
866
      error= 0;
 
867
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
868
                          ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
 
869
                          table->alias);
 
870
    }
 
871
 
 
872
    pthread_mutex_lock(&LOCK_open); /* Lock to remove all instances of table from table cache before ALTER */
 
873
    /*
 
874
      Unlike to the above case close_cached_table() below will remove ALL
 
875
      instances of Table from table cache (it will also remove table lock
 
876
      held by this thread). So to make actual table renaming and writing
 
877
      to binlog atomic we have to put them into the same critical section
 
878
      protected by LOCK_open mutex. This also removes gap for races between
 
879
      access() and mysql_rename_table() calls.
 
880
    */
 
881
 
 
882
    if (error == 0 && 
 
883
        (new_name != table_name || new_db != db))
 
884
    {
 
885
      session->set_proc_info("rename");
 
886
      /*
 
887
        Then do a 'simple' rename of the table. First we need to close all
 
888
        instances of 'source' table.
 
889
      */
 
890
      session->close_cached_table(table);
 
891
      /*
 
892
        Then, we want check once again that target table does not exist.
 
893
        Actually the order of these two steps does not matter since
 
894
        earlier we took name-lock on the target table, so we do them
 
895
        in this particular order only to be consistent with 5.0, in which
 
896
        we don't take this name-lock and where this order really matters.
 
897
        TODO: Investigate if we need this access() check at all.
 
898
      */
 
899
      if (StorageEngine::getTableProto(new_name, NULL) == EEXIST)
 
900
      {
 
901
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
 
902
        error= -1;
 
903
      }
 
904
      else
 
905
      {
 
906
        *fn_ext(new_name)= 0;
 
907
        if (mysql_rename_table(old_db_type, db, table_name, new_db, new_alias, 0))
 
908
          error= -1;
 
909
      }
 
910
    }
 
911
 
 
912
    if (error == HA_ERR_WRONG_COMMAND)
 
913
    {
 
914
      error= 0;
 
915
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
916
                          ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
 
917
                          table->alias);
 
918
    }
 
919
 
 
920
    if (error == 0)
 
921
    {
 
922
      write_bin_log(session, true, session->query, session->query_length);
 
923
      session->my_ok();
 
924
    }
 
925
    else if (error > 0)
 
926
    {
 
927
      table->file->print_error(error, MYF(0));
 
928
      error= -1;
 
929
    }
 
930
 
 
931
    if (name_lock)
 
932
      session->unlink_open_table(name_lock);
 
933
 
 
934
    pthread_mutex_unlock(&LOCK_open);
 
935
    table_list->table= NULL;
 
936
    return error;
 
937
  }
 
938
 
 
939
  /* We have to do full alter table. */
 
940
 
 
941
  /*
 
942
    If the old table had partitions and we are doing ALTER Table ...
 
943
    engine= <new_engine>, the new table must preserve the original
 
944
    partitioning. That means that the new engine is still the
 
945
    partitioning engine, not the engine specified in the parser.
 
946
    This is discovered  in prep_alter_part_table, which in such case
 
947
    updates create_info->db_type.
 
948
    Now we need to update the stack copy of create_info->db_type,
 
949
    as otherwise we won't be able to correctly move the files of the
 
950
    temporary table to the result table files.
 
951
  */
 
952
  new_db_type= create_info->db_type;
 
953
 
 
954
  if (mysql_prepare_alter_table(session, table, create_info, create_proto,
 
955
                                alter_info))
 
956
      goto err;
 
957
 
 
958
  set_table_default_charset(create_info, db);
 
959
 
 
960
  alter_info->build_method= HA_BUILD_OFFLINE;
 
961
 
 
962
  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
963
  
 
964
  /* Safety fix for innodb */
 
965
  my_casedn_str(files_charset_info, tmp_name);
 
966
 
 
967
  /* Create a temporary table with the new format */
 
968
  error= create_temporary_table(session, table, new_db, tmp_name, create_info, create_proto, alter_info);
 
969
  if (error != 0)
 
970
    goto err;
 
971
 
 
972
  /* Open the table so we need to copy the data to it. */
 
973
  if (table->s->tmp_table)
 
974
  {
 
975
    TableList tbl;
 
976
    tbl.db= new_db;
 
977
    tbl.alias= tmp_name;
 
978
    tbl.table_name= tmp_name;
 
979
 
 
980
    /* Table is in session->temporary_tables */
 
981
    new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
 
982
  }
 
983
  else
 
984
  {
 
985
    char tmp_path[FN_REFLEN];
 
986
    /* table is a normal table: Create temporary table in same directory */
 
987
    build_table_filename(tmp_path, sizeof(tmp_path), new_db, tmp_name, true);
 
988
    /* Open our intermediate table */
 
989
    new_table= session->open_temporary_table(tmp_path, new_db, tmp_name, 0, OTM_OPEN);
 
990
  }
 
991
 
 
992
  if (new_table == NULL)
 
993
    goto err1;
 
994
 
 
995
  /* Copy the data if necessary. */
 
996
  session->count_cuted_fields= CHECK_FIELD_WARN;        // calc cuted fields
 
997
  session->cuted_fields= 0L;
 
998
  session->set_proc_info("copy to tmp table");
 
999
  copied= deleted= 0;
 
1000
 
 
1001
  assert(new_table);
 
1002
 
 
1003
  /* We don't want update TIMESTAMP fields during ALTER Table. */
 
1004
  new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
1005
  new_table->next_number_field= new_table->found_next_number_field;
 
1006
  error= copy_data_between_tables(table, 
 
1007
                                  new_table,
 
1008
                                  alter_info->create_list, 
 
1009
                                  ignore,
 
1010
                                  order_num, 
 
1011
                                  order, 
 
1012
                                  &copied, 
 
1013
                                  &deleted,
 
1014
                                  alter_info->keys_onoff,
 
1015
                                  alter_info->error_if_not_empty);
 
1016
 
 
1017
  /* We must not ignore bad input! */
 
1018
  session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
 
1019
 
 
1020
  if (table->s->tmp_table != NO_TMP_TABLE)
 
1021
  {
 
1022
    /* We changed a temporary table */
 
1023
    if (error)
 
1024
      goto err1;
 
1025
 
 
1026
    /* Close lock if this is a transactional table */
 
1027
    if (session->lock)
 
1028
    {
 
1029
      mysql_unlock_tables(session, session->lock);
 
1030
      session->lock= 0;
 
1031
    }
 
1032
 
 
1033
    /* Remove link to old table and rename the new one */
 
1034
    session->close_temporary_table(table, true, true);
 
1035
 
 
1036
    /* Should pass the 'new_name' as we store table name in the cache */
 
1037
    if (new_table->rename_temporary_table(new_db, new_name))
 
1038
      goto err1;
 
1039
    
 
1040
    goto end_temporary;
 
1041
  }
 
1042
 
 
1043
  if (new_table)
 
1044
  {
 
1045
    /*
 
1046
      Close the intermediate table that will be the new table.
 
1047
      Note that MERGE tables do not have their children attached here.
 
1048
    */
 
1049
    new_table->intern_close_table();
 
1050
    free(new_table);
 
1051
  }
 
1052
 
 
1053
  pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
 
1054
  
 
1055
  if (error)
 
1056
  {
 
1057
    quick_rm_table(new_db_type, new_db, tmp_name, true);
 
1058
    pthread_mutex_unlock(&LOCK_open);
 
1059
    goto err;
 
1060
  }
 
1061
 
 
1062
  /*
 
1063
    Data is copied. Now we:
 
1064
    1) Wait until all other threads close old version of table.
 
1065
    2) Close instances of table open by this thread and replace them
 
1066
       with exclusive name-locks.
 
1067
    3) Rename the old table to a temp name, rename the new one to the
 
1068
       old name.
 
1069
    4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
 
1070
       we reopen new version of table.
 
1071
    5) Write statement to the binary log.
 
1072
    6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
 
1073
       remove name-locks from list of open tables and table cache.
 
1074
    7) If we are not not under LOCK TABLES we rely on close_thread_tables()
 
1075
       call to remove name-locks from table cache and list of open table.
 
1076
  */
 
1077
 
 
1078
  session->set_proc_info("rename result table");
 
1079
 
 
1080
  snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
1081
 
 
1082
  my_casedn_str(files_charset_info, old_name);
 
1083
 
 
1084
  wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
 
1085
  session->close_data_files_and_morph_locks(db, table_name);
 
1086
 
 
1087
  error= 0;
 
1088
  save_old_db_type= old_db_type;
 
1089
 
 
1090
  /*
 
1091
    This leads to the storage engine (SE) not being notified for renames in
 
1092
    mysql_rename_table(), because we just juggle with the FRM and nothing
 
1093
    more. If we have an intermediate table, then we notify the SE that
 
1094
    it should become the actual table. Later, we will recycle the old table.
 
1095
    However, in case of ALTER Table RENAME there might be no intermediate
 
1096
    table. This is when the old and new tables are compatible, according to
 
1097
    compare_table(). Then, we need one additional call to
 
1098
    mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
 
1099
    actual rename in the SE and the FRM is not touched. Note that, if the
 
1100
    table is renamed and the SE is also changed, then an intermediate table
 
1101
    is created and the additional call will not take place.
 
1102
  */
 
1103
  if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
 
1104
  {
 
1105
    error= 1;
 
1106
    quick_rm_table(new_db_type, new_db, tmp_name, true);
 
1107
  }
 
1108
  else
 
1109
  {
 
1110
    if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
 
1111
    {
 
1112
      /* Try to get everything back. */
 
1113
      error= 1;
 
1114
      quick_rm_table(new_db_type, new_db, new_alias, false);
 
1115
      quick_rm_table(new_db_type, new_db, tmp_name, true);
 
1116
      mysql_rename_table(old_db_type, db, old_name, db, table_name, FN_FROM_IS_TMP);
 
1117
    }
 
1118
  }
 
1119
 
 
1120
  if (error)
 
1121
  {
 
1122
    /* This shouldn't happen. But let us play it safe. */
 
1123
    goto err_with_placeholders;
 
1124
  }
 
1125
 
 
1126
  quick_rm_table(old_db_type, db, old_name, true);
 
1127
 
 
1128
  pthread_mutex_unlock(&LOCK_open);
 
1129
 
 
1130
  session->set_proc_info("end");
 
1131
 
 
1132
  write_bin_log(session, true, session->query, session->query_length);
 
1133
 
 
1134
  if (old_db_type->check_flag(HTON_BIT_FLUSH_AFTER_RENAME))
 
1135
  {
 
1136
    /*
 
1137
      For the alter table to be properly flushed to the logs, we
 
1138
      have to open the new table.  If not, we get a problem on server
 
1139
      shutdown. But we do not need to attach MERGE children.
 
1140
    */
 
1141
    char table_path[FN_REFLEN];
 
1142
    Table *t_table;
 
1143
    build_table_filename(table_path, sizeof(table_path), new_db, table_name, false);
 
1144
    t_table= session->open_temporary_table(table_path, new_db, tmp_name, false, OTM_OPEN);
 
1145
    if (t_table)
 
1146
    {
 
1147
      t_table->intern_close_table();
 
1148
      free(t_table);
 
1149
    }
 
1150
    else
 
1151
      errmsg_printf(ERRMSG_LVL_WARN, _("Could not open table %s.%s after rename\n"), new_db, table_name);
 
1152
 
 
1153
    ha_flush_logs(old_db_type);
 
1154
  }
 
1155
  table_list->table= NULL;
 
1156
 
 
1157
end_temporary:
 
1158
  /*
 
1159
   * Field::store() may have called my_error().  If this is 
 
1160
   * the case, we must not send an ok packet, since 
 
1161
   * Diagnostics_area::is_set() will fail an assert.
 
1162
   */
 
1163
  if (! session->is_error())
 
1164
  {
 
1165
    snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
 
1166
            (ulong) (copied + deleted), (ulong) deleted,
 
1167
            (ulong) session->cuted_fields);
 
1168
    session->my_ok(copied + deleted, 0, 0L, tmp_name);
 
1169
    session->some_tables_deleted=0;
 
1170
    return false;
 
1171
  }
 
1172
  else
 
1173
  {
 
1174
    /* my_error() was called.  Return true (which means error...) */
 
1175
    return true;
 
1176
  }
 
1177
 
 
1178
err1:
 
1179
  if (new_table)
 
1180
  {
 
1181
    /* close_temporary_table() frees the new_table pointer. */
 
1182
    session->close_temporary_table(new_table, true, true);
 
1183
  }
 
1184
  else
 
1185
    quick_rm_table(new_db_type, new_db, tmp_name, true);
 
1186
 
 
1187
err:
 
1188
  /*
 
1189
    No default value was provided for a DATE/DATETIME field, the
 
1190
    current sql_mode doesn't allow the '0000-00-00' value and
 
1191
    the table to be altered isn't empty.
 
1192
    Report error here.
 
1193
  */
 
1194
  if (alter_info->error_if_not_empty && session->row_count)
 
1195
  {
 
1196
    const char *f_val= 0;
 
1197
    enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
 
1198
    switch (alter_info->datetime_field->sql_type)
 
1199
    {
 
1200
      case DRIZZLE_TYPE_DATE:
 
1201
        f_val= "0000-00-00";
 
1202
        t_type= DRIZZLE_TIMESTAMP_DATE;
 
1203
        break;
 
1204
      case DRIZZLE_TYPE_DATETIME:
 
1205
        f_val= "0000-00-00 00:00:00";
 
1206
        t_type= DRIZZLE_TIMESTAMP_DATETIME;
 
1207
        break;
 
1208
      default:
 
1209
        /* Shouldn't get here. */
 
1210
        assert(0);
 
1211
    }
 
1212
    bool save_abort_on_warning= session->abort_on_warning;
 
1213
    session->abort_on_warning= true;
 
1214
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1215
                                 f_val, strlength(f_val), t_type,
 
1216
                                 alter_info->datetime_field->field_name);
 
1217
    session->abort_on_warning= save_abort_on_warning;
 
1218
  }
 
1219
  if (name_lock)
 
1220
  {
 
1221
    pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
 
1222
    session->unlink_open_table(name_lock);
 
1223
    pthread_mutex_unlock(&LOCK_open);
 
1224
  }
 
1225
  return true;
 
1226
 
 
1227
err_with_placeholders:
 
1228
  /*
 
1229
    An error happened while we were holding exclusive name-lock on table
 
1230
    being altered. To be safe under LOCK TABLES we should remove placeholders
 
1231
    from list of open tables list and table cache.
 
1232
  */
 
1233
  session->unlink_open_table(table);
 
1234
  if (name_lock)
 
1235
    session->unlink_open_table(name_lock);
 
1236
  pthread_mutex_unlock(&LOCK_open);
 
1237
  return true;
 
1238
}
 
1239
/* mysql_alter_table */
 
1240
 
 
1241
static int
 
1242
copy_data_between_tables(Table *from,Table *to,
 
1243
                         List<CreateField> &create,
 
1244
                         bool ignore,
 
1245
                         uint32_t order_num, order_st *order,
 
1246
                         ha_rows *copied,
 
1247
                         ha_rows *deleted,
 
1248
                         enum enum_enable_or_disable keys_onoff,
 
1249
                         bool error_if_not_empty)
 
1250
{
 
1251
  int error;
 
1252
  CopyField *copy,*copy_end;
 
1253
  ulong found_count,delete_count;
 
1254
  Session *session= current_session;
 
1255
  uint32_t length= 0;
 
1256
  SORT_FIELD *sortorder;
 
1257
  READ_RECORD info;
 
1258
  TableList   tables;
 
1259
  List<Item>   fields;
 
1260
  List<Item>   all_fields;
 
1261
  ha_rows examined_rows;
 
1262
  bool auto_increment_field_copied= 0;
 
1263
  uint64_t prev_insert_id;
 
1264
 
 
1265
  /*
 
1266
    Turn off recovery logging since rollback of an alter table is to
 
1267
    delete the new table so there is no need to log the changes to it.
 
1268
 
 
1269
    This needs to be done before external_lock
 
1270
  */
 
1271
  error= ha_enable_transaction(session, false);
 
1272
  if (error)
 
1273
    return -1;
 
1274
 
 
1275
  if (!(copy= new CopyField[to->s->fields]))
 
1276
    return -1;                          /* purecov: inspected */
 
1277
 
 
1278
  if (to->file->ha_external_lock(session, F_WRLCK))
 
1279
    return -1;
 
1280
 
 
1281
  /* We need external lock before we can disable/enable keys */
 
1282
  alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
 
1283
 
 
1284
  /* We can abort alter table for any table type */
 
1285
  session->abort_on_warning= !ignore;
 
1286
 
 
1287
  from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
1288
  to->file->ha_start_bulk_insert(from->file->stats.records);
 
1289
 
 
1290
  List_iterator<CreateField> it(create);
 
1291
  CreateField *def;
 
1292
  copy_end=copy;
 
1293
  for (Field **ptr=to->field ; *ptr ; ptr++)
 
1294
  {
 
1295
    def=it++;
 
1296
    if (def->field)
 
1297
    {
 
1298
      if (*ptr == to->next_number_field)
 
1299
        auto_increment_field_copied= true;
 
1300
 
 
1301
      (copy_end++)->set(*ptr,def->field,0);
 
1302
    }
 
1303
 
 
1304
  }
 
1305
 
 
1306
  found_count=delete_count=0;
 
1307
 
 
1308
  if (order)
 
1309
  {
 
1310
    if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
 
1311
    {
 
1312
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
 
1313
      snprintf(warn_buff, sizeof(warn_buff),
 
1314
               _("order_st BY ignored because there is a user-defined clustered "
 
1315
                 "index in the table '%-.192s'"),
 
1316
               from->s->table_name.str);
 
1317
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
 
1318
                   warn_buff);
 
1319
    }
 
1320
    else
 
1321
    {
 
1322
      from->sort.io_cache= new IO_CACHE;
 
1323
      memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
 
1324
 
 
1325
      memset(&tables, 0, sizeof(tables));
 
1326
      tables.table= from;
 
1327
      tables.alias= tables.table_name= from->s->table_name.str;
 
1328
      tables.db= from->s->db.str;
 
1329
      error= 1;
 
1330
 
 
1331
      if (session->lex->select_lex.setup_ref_array(session, order_num) ||
 
1332
          setup_order(session, session->lex->select_lex.ref_pointer_array,
 
1333
                      &tables, fields, all_fields, order) ||
 
1334
          !(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
 
1335
          (from->sort.found_records= filesort(session, from, sortorder, length,
 
1336
                                              (SQL_SELECT *) 0, HA_POS_ERROR,
 
1337
                                              1, &examined_rows)) ==
 
1338
          HA_POS_ERROR)
 
1339
        goto err;
 
1340
    }
 
1341
  };
 
1342
 
 
1343
  /* Tell handler that we have values for all columns in the to table */
 
1344
  to->use_all_columns();
 
1345
  init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
 
1346
  if (ignore)
 
1347
    to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
 
1348
  session->row_count= 0;
 
1349
  to->restoreRecordAsDefault();        // Create empty record
 
1350
  while (!(error=info.read_record(&info)))
 
1351
  {
 
1352
    if (session->killed)
 
1353
    {
 
1354
      session->send_kill_message();
 
1355
      error= 1;
 
1356
      break;
 
1357
    }
 
1358
    session->row_count++;
 
1359
    /* Return error if source table isn't empty. */
 
1360
    if (error_if_not_empty)
 
1361
    {
 
1362
      error= 1;
 
1363
      break;
 
1364
    }
 
1365
    if (to->next_number_field)
 
1366
    {
 
1367
      if (auto_increment_field_copied)
 
1368
        to->auto_increment_field_not_null= true;
 
1369
      else
 
1370
        to->next_number_field->reset();
 
1371
    }
 
1372
 
 
1373
    for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
 
1374
    {
 
1375
      copy_ptr->do_copy(copy_ptr);
 
1376
    }
 
1377
    prev_insert_id= to->file->next_insert_id;
 
1378
    error=to->file->ha_write_row(to->record[0]);
 
1379
    to->auto_increment_field_not_null= false;
 
1380
    if (error)
 
1381
    {
 
1382
      if (!ignore ||
 
1383
          to->file->is_fatal_error(error, HA_CHECK_DUP))
 
1384
      {
 
1385
         if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
 
1386
         {
 
1387
           uint32_t key_nr= to->file->get_dup_key(error);
 
1388
           if ((int) key_nr >= 0)
 
1389
           {
 
1390
             const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
 
1391
             if (key_nr == 0 &&
 
1392
                 (to->key_info[0].key_part[0].field->flags &
 
1393
                  AUTO_INCREMENT_FLAG))
 
1394
               err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
 
1395
             to->file->print_keydup_error(key_nr, err_msg);
 
1396
             break;
 
1397
           }
 
1398
         }
 
1399
 
 
1400
        to->file->print_error(error,MYF(0));
 
1401
        break;
 
1402
      }
 
1403
      to->file->restore_auto_increment(prev_insert_id);
 
1404
      delete_count++;
 
1405
    }
 
1406
    else
 
1407
      found_count++;
 
1408
  }
 
1409
  end_read_record(&info);
 
1410
  from->free_io_cache();
 
1411
  delete [] copy;                               // This is never 0
 
1412
 
 
1413
  if (to->file->ha_end_bulk_insert() && error <= 0)
 
1414
  {
 
1415
    to->file->print_error(my_errno,MYF(0));
 
1416
    error=1;
 
1417
  }
 
1418
  to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
 
1419
 
 
1420
  if (ha_enable_transaction(session, true))
 
1421
  {
 
1422
    error= 1;
 
1423
    goto err;
 
1424
  }
 
1425
 
 
1426
  /*
 
1427
    Ensure that the new table is saved properly to disk so that we
 
1428
    can do a rename
 
1429
  */
 
1430
  if (ha_autocommit_or_rollback(session, 0))
 
1431
    error=1;
 
1432
  if (! session->endActiveTransaction())
 
1433
    error=1;
 
1434
 
 
1435
 err:
 
1436
  session->abort_on_warning= 0;
 
1437
  from->free_io_cache();
 
1438
  *copied= found_count;
 
1439
  *deleted=delete_count;
 
1440
  to->file->ha_release_auto_increment();
 
1441
  if (to->file->ha_external_lock(session,F_UNLCK))
 
1442
    error=1;
 
1443
  return(error > 0 ? -1 : 0);
 
1444
}
 
1445
 
 
1446
static int
 
1447
create_temporary_table(Session *session,
 
1448
                       Table *table,
 
1449
                       char *new_db,
 
1450
                       char *tmp_name,
 
1451
                       HA_CREATE_INFO *create_info,
 
1452
                       message::Table *create_proto,
 
1453
                       AlterInfo *alter_info)
 
1454
{
 
1455
  int error;
 
1456
  StorageEngine *old_db_type, *new_db_type;
 
1457
  old_db_type= table->s->db_type();
 
1458
  new_db_type= create_info->db_type;
 
1459
  /*
 
1460
    Create a table with a temporary name.
 
1461
    We don't log the statement, it will be logged later.
 
1462
  */
 
1463
  create_proto->set_name(tmp_name);
 
1464
  create_proto->set_type(message::Table::TEMPORARY);
 
1465
 
 
1466
  message::Table::StorageEngine *protoengine;
 
1467
  protoengine= create_proto->mutable_engine();
 
1468
  protoengine->set_name(new_db_type->getName());
 
1469
 
 
1470
  error= mysql_create_table(session, new_db, tmp_name,
 
1471
                            create_info, create_proto, alter_info, 1, 0);
 
1472
 
 
1473
  return(error);
 
1474
}
 
1475
 
 
1476
/** @TODO This will soon die. */
 
1477
bool mysql_create_like_schema_frm(Session* session,
 
1478
                                  TableList* schema_table,
 
1479
                                  HA_CREATE_INFO *create_info,
 
1480
                                  message::Table* table_proto)
 
1481
{
 
1482
  HA_CREATE_INFO local_create_info;
 
1483
  AlterInfo alter_info;
 
1484
  bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
 
1485
  uint32_t keys= schema_table->table->s->keys;
 
1486
  uint32_t db_options= 0;
 
1487
 
 
1488
  memset(&local_create_info, 0, sizeof(local_create_info));
 
1489
  local_create_info.db_type= schema_table->table->s->db_type();
 
1490
  local_create_info.row_type= schema_table->table->s->row_type;
 
1491
  local_create_info.default_table_charset=default_charset_info;
 
1492
  alter_info.flags.set(ALTER_CHANGE_COLUMN);
 
1493
  alter_info.flags.set(ALTER_RECREATE);
 
1494
  schema_table->table->use_all_columns();
 
1495
  if (mysql_prepare_alter_table(session, schema_table->table,
 
1496
                                &local_create_info, table_proto, &alter_info))
 
1497
    return true;
 
1498
 
 
1499
  /* I_S tables are created with MAX_ROWS for some efficiency drive.
 
1500
     When CREATE LIKE, we don't want to keep it coming across */
 
1501
  message::Table::TableOptions *table_options;
 
1502
  table_options= table_proto->mutable_options();
 
1503
  table_options->clear_max_rows();
 
1504
 
 
1505
  if (mysql_prepare_create_table(session, &local_create_info, &alter_info,
 
1506
                                 tmp_table, &db_options,
 
1507
                                 schema_table->table->file,
 
1508
                                 &schema_table->table->s->key_info, &keys, 0))
 
1509
    return true;
 
1510
 
 
1511
  table_proto->set_name("system_stupid_i_s_fix_nonsense");
 
1512
  if(tmp_table)
 
1513
    table_proto->set_type(message::Table::TEMPORARY);
 
1514
  else
 
1515
    table_proto->set_type(message::Table::STANDARD);
 
1516
 
 
1517
  {
 
1518
    message::Table::StorageEngine *protoengine;
 
1519
    protoengine= table_proto->mutable_engine();
 
1520
 
 
1521
    StorageEngine *engine= local_create_info.db_type;
 
1522
 
 
1523
    protoengine->set_name(engine->getName());
 
1524
  }
 
1525
 
 
1526
  if (fill_table_proto(table_proto, "system_stupid_i_s_fix_nonsense",
 
1527
                       alter_info.create_list, &local_create_info,
 
1528
                       keys, schema_table->table->s->key_info))
 
1529
    return true;
 
1530
 
 
1531
  return false;
 
1532
}