~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 00:53:34 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913005334-6wio2sbjugskfbm3
Added calls to the connection start/end dtrace probes.

Show diffs side-by-side

added added

removed removed

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