~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Mark Atwood
  • Date: 2008-10-16 11:33:16 UTC
  • mto: (520.1.13 drizzle)
  • mto: This revision was merged to the branch mainline in revision 530.
  • Revision ID: mark@fallenpegasus.com-20081016113316-ff6jdt31ck90sjdh
an implemention of the errmsg plugin

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