~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Monty Taylor
  • Date: 2009-09-30 07:01:32 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20090930070132-b1ol1xu1rpajdddy
Small namespace cleanup.

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