~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Brian Aker
  • Date: 2009-08-17 22:19:53 UTC
  • mto: This revision was merged to the branch mainline in revision 1118.
  • Revision ID: brian@gaz-20090817221953-6qzdxpi8l9nd342y
More dead option removal.

Show diffs side-by-side

added added

removed removed

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