~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Monty Taylor
  • Date: 2011-02-13 17:26:39 UTC
  • mfrom: (2157.2.2 give-in-to-pkg-config)
  • mto: This revision was merged to the branch mainline in revision 2166.
  • Revision ID: mordred@inaugust.com-20110213172639-nhy7i72sfhoq13ms
Merged in pkg-config fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2009 Sun Microsystems
 
4
 *  Copyright (C) 2009 Sun Microsystems, Inc.
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
41
41
#include "drizzled/pthread_globals.h"
42
42
#include "drizzled/internal/my_sys.h"
43
43
#include "drizzled/internal/iocache.h"
 
44
#include "drizzled/plugin/storage_engine.h"
 
45
#include <drizzled/copy_field.h>
44
46
 
45
47
#include "drizzled/transaction_services.h"
46
48
 
66
68
                                    enum enum_enable_or_disable keys_onoff,
67
69
                                    bool error_if_not_empty);
68
70
 
69
 
static bool mysql_prepare_alter_table(Session *session,
 
71
static bool prepare_alter_table(Session *session,
70
72
                                      Table *table,
71
73
                                      HA_CREATE_INFO *create_info,
72
74
                                      const message::Table &original_proto,
73
75
                                      message::Table &table_message,
74
76
                                      AlterInfo *alter_info);
75
77
 
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);
 
78
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier);
 
79
 
 
80
namespace statement {
 
81
 
 
82
AlterTable::AlterTable(Session *in_session, Table_ident *ident, drizzled::ha_build_method build_arg) :
 
83
  CreateTable(in_session)
 
84
 
85
  in_session->lex->sql_command= SQLCOM_ALTER_TABLE;
 
86
  (void)ident;
 
87
  alter_info.build_method= build_arg;
 
88
}
 
89
 
 
90
} // namespace statement
83
91
 
84
92
bool statement::AlterTable::execute()
85
93
{
86
 
  TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
87
 
  TableList *all_tables= session->lex->query_tables;
 
94
  TableList *first_table= (TableList *) getSession()->lex->select_lex.table_list.first;
 
95
  TableList *all_tables= getSession()->lex->query_tables;
88
96
  assert(first_table == all_tables && first_table != 0);
89
 
  Select_Lex *select_lex= &session->lex->select_lex;
 
97
  Select_Lex *select_lex= &getSession()->lex->select_lex;
90
98
  bool need_start_waiting= false;
91
99
 
 
100
  is_engine_set= not createTableMessage().engine().name().empty();
 
101
 
92
102
  if (is_engine_set)
93
103
  {
94
 
    create_info.db_type= 
95
 
      plugin::StorageEngine::findByName(*session, create_table_message.engine().name());
 
104
    create_info().db_type= 
 
105
      plugin::StorageEngine::findByName(*getSession(), createTableMessage().engine().name());
96
106
 
97
 
    if (create_info.db_type == NULL)
 
107
    if (create_info().db_type == NULL)
98
108
    {
99
 
      my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), 
100
 
               create_table_message.engine().name().c_str());
 
109
      my_error(createTableMessage().engine().name(), ER_UNKNOWN_STORAGE_ENGINE, MYF(0));
101
110
 
102
111
      return true;
103
112
    }
107
116
  assert(select_lex->db);
108
117
 
109
118
  /* 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;
 
119
  message::table::shared_ptr original_table_message;
111
120
  {
112
 
    TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
113
 
    if (plugin::StorageEngine::getTableDefinition(*session, identifier, original_table_message) != EEXIST)
 
121
    identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
 
122
    if (plugin::StorageEngine::getTableDefinition(*getSession(), identifier, original_table_message) != EEXIST)
114
123
    {
115
 
      my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
124
      my_error(ER_BAD_TABLE_ERROR, identifier);
116
125
      return true;
117
126
    }
118
127
 
119
 
    if (not  create_info.db_type)
 
128
    if (not  create_info().db_type)
120
129
    {
121
 
      create_info.db_type= 
122
 
        plugin::StorageEngine::findByName(*session, original_table_message->engine().name());
 
130
      create_info().db_type= 
 
131
        plugin::StorageEngine::findByName(*getSession(), original_table_message->engine().name());
123
132
 
124
 
      if (not create_info.db_type)
 
133
      if (not create_info().db_type)
125
134
      {
126
 
        my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
135
        my_error(ER_BAD_TABLE_ERROR, identifier);
127
136
        return true;
128
137
      }
129
138
    }
130
139
  }
131
140
 
132
141
  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
 
  }
 
142
    return true;
 
143
 
 
144
  if (getSession()->inTransaction())
 
145
  {
 
146
    my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
 
147
    return true;
 
148
  }
 
149
 
 
150
  if (not (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
 
151
    return true;
147
152
 
148
153
  bool res;
149
154
  if (original_table_message->type() == message::Table::STANDARD )
150
155
  {
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());
 
156
    identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
 
157
    identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
 
158
                                   getSession()->lex->name.str ? getSession()->lex->name.str : first_table->getTableName());
154
159
 
155
 
    res= alter_table(session, 
 
160
    res= alter_table(getSession(), 
156
161
                     identifier,
157
162
                     new_identifier,
158
 
                     &create_info,
 
163
                     &create_info(),
159
164
                     *original_table_message,
160
 
                     create_table_message,
 
165
                     createTableMessage(),
161
166
                     first_table,
162
167
                     &alter_info,
163
168
                     select_lex->order_list.elements,
164
169
                     (Order *) select_lex->order_list.first,
165
 
                     session->lex->ignore);
 
170
                     getSession()->lex->ignore);
166
171
  }
167
172
  else
168
173
  {
169
 
    TableIdentifier catch22(first_table->getSchemaName(), first_table->getTableName());
170
 
    Table *table= session->find_temporary_table(catch22);
 
174
    identifier::Table catch22(first_table->getSchemaName(), first_table->getTableName());
 
175
    Table *table= getSession()->find_temporary_table(catch22);
171
176
    assert(table);
172
177
    {
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());
 
178
      identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
 
179
      identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
 
180
                                       getSession()->lex->name.str ? getSession()->lex->name.str : first_table->getTableName(),
 
181
                                       table->getMutableShare()->getPath());
177
182
 
178
 
      res= alter_table(session, 
 
183
      res= alter_table(getSession(), 
179
184
                       identifier,
180
185
                       new_identifier,
181
 
                       &create_info,
 
186
                       &create_info(),
182
187
                       *original_table_message,
183
 
                       create_table_message,
 
188
                       createTableMessage(),
184
189
                       first_table,
185
190
                       &alter_info,
186
191
                       select_lex->order_list.elements,
187
192
                       (Order *) select_lex->order_list.first,
188
 
                       session->lex->ignore);
 
193
                       getSession()->lex->ignore);
189
194
    }
190
195
  }
191
196
 
193
198
     Release the protection against the global read lock and wake
194
199
     everyone, who might want to set a global read lock.
195
200
   */
196
 
  session->startWaitingGlobalReadLock();
 
201
  getSession()->startWaitingGlobalReadLock();
197
202
 
198
203
  return res;
199
204
}
239
244
                 Table instructions
240
245
  @retval false  success
241
246
*/
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)
 
247
static bool prepare_alter_table(Session *session,
 
248
                                Table *table,
 
249
                                HA_CREATE_INFO *create_info,
 
250
                                const message::Table &original_proto,
 
251
                                message::Table &table_message,
 
252
                                AlterInfo *alter_info)
248
253
{
249
254
  /* New column definitions are added here */
250
255
  List<CreateField> new_create_list;
265
270
  message::Table::TableOptions *table_options;
266
271
  table_options= table_message.mutable_options();
267
272
 
268
 
  if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
 
273
  if (not (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
269
274
    create_info->default_table_charset= table->getShare()->table_charset;
270
 
  if (! (used_fields & HA_CREATE_USED_AUTO) &&
271
 
      table->found_next_number_field)
 
275
 
 
276
  if (not (used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
272
277
  {
273
278
    /* Table has an autoincrement, copy value to new table */
274
279
    table->cursor->info(HA_STATUS_AUTO);
276
281
    if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
277
282
      table_options->set_has_user_set_auto_increment_value(false);
278
283
  }
 
284
 
279
285
  table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
280
286
  CreateField *def;
281
287
 
282
288
  /* First collect all fields from table which isn't in drop_list */
283
 
  Field **f_ptr;
284
289
  Field *field;
285
 
  for (f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
 
290
  for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
286
291
  {
287
292
    /* Check if field should be dropped */
288
293
    AlterDrop *drop;
302
307
        break;
303
308
      }
304
309
    }
 
310
 
305
311
    if (drop)
306
312
    {
307
313
      drop_it.remove();
319
325
          ! my_strcasecmp(system_charset_info, field->field_name, def->change))
320
326
              break;
321
327
    }
 
328
 
322
329
    if (def)
323
330
    {
324
331
      /* Field is changed */
339
346
      new_create_list.push_back(def);
340
347
      alter_it.rewind(); /* Change default if ALTER */
341
348
      AlterColumn *alter;
 
349
 
342
350
      while ((alter= alter_it++))
343
351
      {
344
352
        if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
345
353
          break;
346
354
      }
 
355
 
347
356
      if (alter)
348
357
      {
349
358
        if (def->sql_type == DRIZZLE_TYPE_BLOB)
350
359
        {
351
360
          my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
352
 
                goto err;
 
361
          return true;
353
362
        }
 
363
 
354
364
        if ((def->def= alter->def))
355
365
        {
356
366
          /* Use new default */
357
367
          def->flags&= ~NO_DEFAULT_VALUE_FLAG;
358
368
        }
359
369
        else
 
370
        {
360
371
          def->flags|= NO_DEFAULT_VALUE_FLAG;
 
372
        }
361
373
        alter_it.remove();
362
374
      }
363
375
    }
364
376
  }
 
377
 
365
378
  def_it.rewind();
366
379
  while ((def= def_it++)) /* Add new columns */
367
380
  {
368
381
    if (def->change && ! def->field)
369
382
    {
370
383
      my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
371
 
      goto err;
 
384
      return true;
372
385
    }
373
386
    /*
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.
 
387
      If we have been given a field which has no default value, and is not null then we need to bail.
379
388
    */
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)))
 
389
    if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
384
390
    {
385
 
      alter_info->datetime_field= def;
386
391
      alter_info->error_if_not_empty= true;
387
392
    }
388
393
    if (! def->after)
 
394
    {
389
395
      new_create_list.push_back(def);
 
396
    }
390
397
    else if (def->after == first_keyword)
 
398
    {
391
399
      new_create_list.push_front(def);
 
400
    }
392
401
    else
393
402
    {
394
403
      CreateField *find;
395
404
      find_it.rewind();
 
405
 
396
406
      while ((find= find_it++)) /* Add new columns */
397
407
      {
398
 
        if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
 
408
        if (not my_strcasecmp(system_charset_info,def->after, find->field_name))
399
409
          break;
400
410
      }
401
 
      if (! find)
 
411
 
 
412
      if (not find)
402
413
      {
403
414
        my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
404
 
        goto err;
 
415
        return true;
405
416
      }
 
417
 
406
418
      find_it.after(def); /* Put element after this */
 
419
 
407
420
      /*
408
421
        XXX: hack for Bug#28427.
409
422
        If column order has changed, force OFFLINE ALTER Table
416
429
      */
417
430
      if (alter_info->build_method == HA_BUILD_ONLINE)
418
431
      {
419
 
        my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->getQueryString()->c_str());
420
 
        goto err;
 
432
        my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
 
433
        return true;
421
434
      }
 
435
 
422
436
      alter_info->build_method= HA_BUILD_OFFLINE;
423
437
    }
424
438
  }
 
439
 
425
440
  if (alter_info->alter_list.elements)
426
441
  {
427
442
    my_error(ER_BAD_FIELD_ERROR,
428
443
             MYF(0),
429
444
             alter_info->alter_list.head()->name,
430
445
             table->getMutableShare()->getTableName());
431
 
    goto err;
 
446
    return true;
432
447
  }
433
 
  if (! new_create_list.elements)
 
448
 
 
449
  if (not new_create_list.elements)
434
450
  {
435
451
    my_message(ER_CANT_REMOVE_ALL_FIELDS,
436
452
               ER(ER_CANT_REMOVE_ALL_FIELDS),
437
453
               MYF(0));
438
 
    goto err;
 
454
    return true;
439
455
  }
440
456
 
441
457
  /*
446
462
  {
447
463
    char *key_name= key_info->name;
448
464
    AlterDrop *drop;
 
465
 
449
466
    drop_it.rewind();
450
467
    while ((drop= drop_it++))
451
468
    {
453
470
          ! my_strcasecmp(system_charset_info, key_name, drop->name))
454
471
        break;
455
472
    }
 
473
 
456
474
    if (drop)
457
475
    {
458
476
      drop_it.remove();
473
491
      {
474
492
        if (cfield->change)
475
493
        {
476
 
          if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
 
494
          if (not my_strcasecmp(system_charset_info, key_part_name, cfield->change))
477
495
            break;
478
496
        }
479
 
        else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
 
497
        else if (not my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
480
498
          break;
481
499
      }
482
 
      if (! cfield)
 
500
 
 
501
      if (not cfield)
483
502
              continue; /* Field is removed */
484
503
      
485
504
      uint32_t key_part_length= key_part->length;
511
530
    }
512
531
    if (key_parts.elements)
513
532
    {
514
 
      KEY_CREATE_INFO key_create_info;
 
533
      key_create_information_st key_create_info= default_key_create_info;
515
534
      Key *key;
516
 
      enum Key::Keytype key_type;
517
 
      memset(&key_create_info, 0, sizeof(key_create_info));
 
535
      Key::Keytype key_type;
518
536
 
519
537
      key_create_info.algorithm= key_info->algorithm;
 
538
 
520
539
      if (key_info->flags & HA_USES_BLOCK_SIZE)
521
540
        key_create_info.block_size= key_info->block_size;
 
541
 
522
542
      if (key_info->flags & HA_USES_COMMENT)
523
543
        key_create_info.comment= key_info->comment;
524
544
 
530
550
          key_type= Key::UNIQUE;
531
551
      }
532
552
      else
 
553
      {
533
554
        key_type= Key::MULTIPLE;
 
555
      }
534
556
 
535
557
      key= new Key(key_type,
536
558
                   key_name,
543
565
  }
544
566
 
545
567
  /* Copy over existing foreign keys */
546
 
  for (int j= 0; j < original_proto.fk_constraint_size(); j++)
 
568
  for (int32_t j= 0; j < original_proto.fk_constraint_size(); j++)
547
569
  {
548
570
    AlterDrop *drop;
549
571
    drop_it.rewind();
572
594
      if (key->type == Key::FOREIGN_KEY)
573
595
      {
574
596
        if (((Foreign_key *)key)->validate(new_create_list))
575
 
          goto err;
 
597
        {
 
598
          return true;
 
599
        }
576
600
 
577
601
        Foreign_key *fkey= (Foreign_key*)key;
578
602
        add_foreign_key_to_table_message(&table_message,
593
617
        my_error(ER_WRONG_NAME_FOR_INDEX,
594
618
                 MYF(0),
595
619
                 key->name.str);
596
 
        goto err;
 
620
        return true;
597
621
      }
598
622
    }
599
623
  }
620
644
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
621
645
             MYF(0),
622
646
             alter_info->drop_list.head()->name);
623
 
    goto err;
 
647
    return true;
624
648
  }
 
649
 
625
650
  if (alter_info->alter_list.elements)
626
651
  {
627
652
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
628
653
             MYF(0),
629
654
             alter_info->alter_list.head()->name);
630
 
    goto err;
 
655
    return true;
631
656
  }
632
657
 
633
658
  if (not table_message.options().has_comment()
634
659
      && table->getMutableShare()->hasComment())
 
660
  {
635
661
    table_options->set_comment(table->getMutableShare()->getComment());
 
662
  }
636
663
 
637
664
  if (table->getShare()->getType())
638
665
  {
639
666
    table_message.set_type(message::Table::TEMPORARY);
640
667
  }
641
668
 
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());
 
669
  table_message.set_creation_timestamp(table->getShare()->getTableMessage()->creation_timestamp());
 
670
  table_message.set_version(table->getShare()->getTableMessage()->version());
 
671
  table_message.set_uuid(table->getShare()->getTableMessage()->uuid());
645
672
 
646
673
  rc= false;
647
674
  alter_info->create_list.swap(new_create_list);
648
675
  alter_info->key_list.swap(new_key_list);
649
 
err:
650
676
 
651
677
  size_t num_engine_options= table_message.engine().options_size();
652
678
  size_t original_num_engine_options= original_proto.engine().options_size();
673
699
 
674
700
  drizzled::message::update(table_message);
675
701
 
676
 
  return rc;
 
702
  return false;
677
703
}
678
704
 
679
705
/* table_list should contain just one table */
680
 
static int mysql_discard_or_import_tablespace(Session *session,
 
706
static int discard_or_import_tablespace(Session *session,
681
707
                                              TableList *table_list,
682
708
                                              enum tablespace_op_type tablespace_op)
683
709
{
684
710
  Table *table;
685
711
  bool discard;
686
 
  int error;
687
712
 
688
713
  /*
689
714
    Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
690
715
    ALTER Table
691
716
  */
692
 
 
693
717
  TransactionServices &transaction_services= TransactionServices::singleton();
694
718
  session->set_proc_info("discard_or_import_tablespace");
695
719
 
699
723
   We set this flag so that ha_innobase::open and ::external_lock() do
700
724
   not complain when we lock the table
701
725
 */
702
 
  session->tablespace_op= true;
703
 
  if (!(table= session->openTableLock(table_list, TL_WRITE)))
 
726
  session->setDoingTablespaceOperation(true);
 
727
  if (not (table= session->openTableLock(table_list, TL_WRITE)))
704
728
  {
705
 
    session->tablespace_op= false;
 
729
    session->setDoingTablespaceOperation(false);
706
730
    return -1;
707
731
  }
708
732
 
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;
 
733
  int error;
 
734
  do {
 
735
    error= table->cursor->ha_discard_or_import_tablespace(discard);
 
736
 
 
737
    session->set_proc_info("end");
 
738
 
 
739
    if (error)
 
740
      break;
 
741
 
 
742
    /* The ALTER Table is always in its own transaction */
 
743
    error= transaction_services.autocommitOrRollback(*session, false);
 
744
    if (not session->endActiveTransaction())
 
745
      error= 1;
 
746
 
 
747
    if (error)
 
748
      break;
 
749
 
 
750
    write_bin_log(session, *session->getQueryString());
 
751
 
 
752
  } while(0);
 
753
 
 
754
  (void) transaction_services.autocommitOrRollback(*session, error);
 
755
  session->setDoingTablespaceOperation(false);
729
756
 
730
757
  if (error == 0)
731
758
  {
775
802
                        ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
776
803
                        table->getMutableShare()->getTableName());
777
804
    error= 0;
778
 
  } else if (error)
 
805
  }
 
806
  else if (error)
 
807
  {
779
808
    table->print_error(error, MYF(0));
 
809
  }
780
810
 
781
811
  return(error);
782
812
}
783
813
 
784
814
static bool lockTableIfDifferent(Session &session,
785
 
                                 TableIdentifier &original_table_identifier,
786
 
                                 TableIdentifier &new_table_identifier,
 
815
                                 identifier::Table &original_table_identifier,
 
816
                                 identifier::Table &new_table_identifier,
787
817
                                 Table *name_lock)
788
818
{
789
819
  /* Check that we are not trying to rename to an existing table */
794
824
 
795
825
      if (session.find_temporary_table(new_table_identifier))
796
826
      {
797
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
827
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
798
828
        return false;
799
829
      }
800
830
    }
807
837
 
808
838
      if (not name_lock)
809
839
      {
810
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
840
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
811
841
        return false;
812
842
      }
813
843
 
814
844
      if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
815
845
      {
816
846
        /* Table will be closed by Session::executeCommand() */
817
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
847
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
818
848
 
819
 
        LOCK_open.lock(); /* ALTER TABLe */
820
 
        session.unlink_open_table(name_lock);
821
 
        LOCK_open.unlock();
 
849
        {
 
850
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
 
851
          session.unlink_open_table(name_lock);
 
852
        }
822
853
 
823
854
        return false;
824
855
      }
872
903
 
873
904
static bool internal_alter_table(Session *session,
874
905
                                 Table *table,
875
 
                                 TableIdentifier &original_table_identifier,
876
 
                                 TableIdentifier &new_table_identifier,
 
906
                                 identifier::Table &original_table_identifier,
 
907
                                 identifier::Table &new_table_identifier,
877
908
                                 HA_CREATE_INFO *create_info,
878
909
                                 const message::Table &original_proto,
879
910
                                 message::Table &create_proto,
889
920
  ha_rows copied= 0;
890
921
  ha_rows deleted= 0;
891
922
 
 
923
  if (not original_table_identifier.isValid())
 
924
    return true;
 
925
 
 
926
  if (not new_table_identifier.isValid())
 
927
    return true;
 
928
 
892
929
  session->set_proc_info("init");
893
930
 
894
931
  table->use_all_columns();
924
961
  if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
925
962
      new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
926
963
  {
927
 
    my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
 
964
    my_error(ER_ILLEGAL_HA, new_table_identifier);
928
965
 
929
966
    return true;
930
967
  }
942
979
    tmp.reset(ALTER_KEYS_ONOFF);
943
980
    tmp&= alter_info->flags;
944
981
 
945
 
    if (! (tmp.any()) && ! table->getShare()->getType()) // no need to touch frm
 
982
    if (not (tmp.any()) && not table->getShare()->getType()) // no need to touch frm
946
983
    {
947
984
      switch (alter_info->keys_onoff)
948
985
      {
949
986
      case LEAVE_AS_IS:
950
987
        break;
 
988
 
951
989
      case ENABLE:
952
990
        /*
953
991
          wait_while_table_is_used() ensures that table being altered is
958
996
          while the fact that the table is still open gives us protection
959
997
          from concurrent DDL statements.
960
998
        */
961
 
        LOCK_open.lock(); /* DDL wait for/blocker */
962
 
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
963
 
        LOCK_open.unlock();
 
999
        {
 
1000
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
 
1001
          wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
 
1002
        }
964
1003
        error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
1004
 
965
1005
        /* COND_refresh will be signaled in close_thread_tables() */
966
1006
        break;
 
1007
 
967
1008
      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);
 
1009
        {
 
1010
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
 
1011
          wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
 
1012
        }
 
1013
        error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
1014
 
972
1015
        /* COND_refresh will be signaled in close_thread_tables() */
973
1016
        break;
974
 
      default:
975
 
        assert(false);
976
 
        error= 0;
977
 
        break;
978
1017
      }
979
1018
 
980
1019
      if (error == HA_ERR_WRONG_COMMAND)
981
1020
      {
982
 
        error= 0;
 
1021
        error= EE_OK;
983
1022
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
984
1023
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
985
1024
                            table->getAlias());
986
1025
      }
987
1026
 
988
 
      LOCK_open.lock(); /* Lock to remove all instances of table from table cache before ALTER */
 
1027
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* Lock to remove all instances of table from table cache before ALTER */
989
1028
      /*
990
1029
        Unlike to the above case close_cached_table() below will remove ALL
991
1030
        instances of Table from table cache (it will also remove table lock
992
1031
        held by this thread). So to make actual table renaming and writing
993
1032
        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.
 
1033
        protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
 
1034
        access() and rename_table() calls.
996
1035
      */
997
1036
 
998
 
      if (error == 0 &&  not (original_table_identifier == new_table_identifier))
 
1037
      if (not error &&  not (original_table_identifier == new_table_identifier))
999
1038
      {
1000
1039
        session->set_proc_info("rename");
1001
1040
        /*
1013
1052
        */
1014
1053
        if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1015
1054
        {
1016
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
1055
          my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
1017
1056
          error= -1;
1018
1057
        }
1019
1058
        else
1020
1059
        {
1021
 
          if (mysql_rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
 
1060
          if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1022
1061
          {
1023
1062
            error= -1;
1024
1063
          }
1027
1066
 
1028
1067
      if (error == HA_ERR_WRONG_COMMAND)
1029
1068
      {
1030
 
        error= 0;
 
1069
        error= EE_OK;
1031
1070
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1032
1071
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1033
1072
                            table->getAlias());
1034
1073
      }
1035
1074
 
1036
 
      if (error == 0)
 
1075
      if (not error)
1037
1076
      {
1038
1077
        TransactionServices &transaction_services= TransactionServices::singleton();
1039
1078
        transaction_services.allocateNewTransactionId();
1040
1079
        write_bin_log(session, *session->getQueryString());
1041
1080
        session->my_ok();
1042
1081
      }
1043
 
      else if (error > 0)
 
1082
      else if (error > EE_OK) // If we have already set the error, we pass along -1
1044
1083
      {
1045
1084
        table->print_error(error, MYF(0));
1046
 
        error= -1;
1047
1085
      }
1048
1086
 
1049
 
      LOCK_open.unlock();
1050
1087
      table_list->table= NULL;
1051
1088
 
1052
1089
      return error;
1056
1093
  /* We have to do full alter table. */
1057
1094
  new_engine= create_info->db_type;
1058
1095
 
1059
 
  if (mysql_prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
 
1096
  if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
1060
1097
  {
1061
1098
    return true;
1062
1099
  }
1073
1110
    case we just use it as is. Neither of these tables require locks in order to  be
1074
1111
    filled.
1075
1112
  */
1076
 
  TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
 
1113
  identifier::Table new_table_as_temporary(original_table_identifier.getSchemaName(),
1077
1114
                                         tmp_name,
1078
1115
                                         create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1079
1116
                                         message::Table::TEMPORARY);
1080
1117
 
1081
 
  error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
 
1118
  /*
 
1119
    Create a table with a temporary name.
 
1120
    We don't log the statement, it will be logged later.
 
1121
  */
 
1122
  create_proto.set_name(new_table_as_temporary.getTableName());
 
1123
  create_proto.mutable_engine()->set_name(create_info->db_type->getName());
 
1124
 
 
1125
  error= create_table(session,
 
1126
                      new_table_as_temporary,
 
1127
                      create_info, create_proto, alter_info, true, 0, false);
1082
1128
 
1083
1129
  if (error != 0)
1084
1130
  {
1091
1137
 
1092
1138
  if (not new_table)
1093
1139
  {
1094
 
    quick_rm_table(*session, new_table_as_temporary);
 
1140
    plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1095
1141
    return true;
1096
1142
  }
1097
1143
 
1128
1174
  {
1129
1175
 
1130
1176
    /*
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.
 
1177
      No default value was provided for new fields.
1135
1178
    */
1136
1179
    if (alter_info->error_if_not_empty && session->row_count)
1137
1180
    {
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;
 
1181
      my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
1161
1182
    }
1162
1183
 
1163
1184
    if (original_table_identifier.isTmp())
1169
1190
      }
1170
1191
      else
1171
1192
      {
1172
 
        quick_rm_table(*session, new_table_as_temporary);
 
1193
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1173
1194
      }
1174
1195
 
1175
1196
      return true;
1191
1212
        delete new_table;
1192
1213
      }
1193
1214
 
1194
 
      LOCK_open.lock(); /* ALTER TABLE */
 
1215
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1195
1216
 
1196
 
      quick_rm_table(*session, new_table_as_temporary);
1197
 
      LOCK_open.unlock();
 
1217
      plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1198
1218
 
1199
1219
      return true;
1200
1220
    }
1217
1237
 
1218
1238
    new_table_identifier.setPath(new_table_as_temporary.getPath());
1219
1239
 
1220
 
    if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
 
1240
    if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1221
1241
    {
1222
1242
      return true;
1223
1243
    }
1241
1261
      delete new_table;
1242
1262
    }
1243
1263
 
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)
 
1264
    {
 
1265
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* ALTER TABLE */
 
1266
      /*
 
1267
        Data is copied. Now we:
 
1268
        1) Wait until all other threads close old version of table.
 
1269
        2) Close instances of table open by this thread and replace them
 
1270
        with exclusive name-locks.
 
1271
        3) Rename the old table to a temp name, rename the new one to the
 
1272
        old name.
 
1273
        4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
 
1274
        we reopen new version of table.
 
1275
        5) Write statement to the binary log.
 
1276
        6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
 
1277
        remove name-locks from list of open tables and table cache.
 
1278
        7) If we are not not under LOCK TABLES we rely on close_thread_tables()
 
1279
        call to remove name-locks from table cache and list of open table.
 
1280
      */
 
1281
 
 
1282
      session->set_proc_info("rename result table");
 
1283
 
 
1284
      snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
1285
 
 
1286
      my_casedn_str(files_charset_info, old_name);
 
1287
 
 
1288
      wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
 
1289
      session->close_data_files_and_morph_locks(original_table_identifier);
 
1290
 
 
1291
      assert(not error);
 
1292
 
 
1293
      /*
 
1294
        This leads to the storage engine (SE) not being notified for renames in
 
1295
        rename_table(), because we just juggle with the FRM and nothing
 
1296
        more. If we have an intermediate table, then we notify the SE that
 
1297
        it should become the actual table. Later, we will recycle the old table.
 
1298
        However, in case of ALTER Table RENAME there might be no intermediate
 
1299
        table. This is when the old and new tables are compatible, according to
 
1300
        compare_table(). Then, we need one additional call to
 
1301
      */
 
1302
      identifier::Table original_table_to_drop(original_table_identifier.getSchemaName(),
 
1303
                                             old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
 
1304
                                             message::Table::TEMPORARY);
 
1305
 
 
1306
      drizzled::error_t rename_error= EE_OK;
 
1307
      if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1294
1308
      {
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);
 
1309
        error= ER_ERROR_ON_RENAME;
 
1310
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1303
1311
      }
1304
1312
      else
1305
1313
      {
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();
 
1314
        if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
 
1315
        {
 
1316
          /* Try to get everything back. */
 
1317
          rename_error= ER_ERROR_ON_RENAME;
 
1318
 
 
1319
          plugin::StorageEngine::dropTable(*session, new_table_identifier);
 
1320
 
 
1321
          plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
 
1322
 
 
1323
          rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
 
1324
        }
 
1325
        else
 
1326
        {
 
1327
          plugin::StorageEngine::dropTable(*session, original_table_to_drop);
 
1328
        }
 
1329
      }
 
1330
 
 
1331
      if (rename_error)
 
1332
      {
 
1333
        /*
 
1334
          An error happened while we were holding exclusive name-lock on table
 
1335
          being altered. To be safe under LOCK TABLES we should remove placeholders
 
1336
          from list of open tables list and table cache.
 
1337
        */
 
1338
        session->unlink_open_table(table);
 
1339
 
 
1340
        return true;
 
1341
      }
 
1342
    }
1324
1343
 
1325
1344
    session->set_proc_info("end");
1326
1345
 
1343
1362
           (ulong) (copied + deleted), (ulong) deleted,
1344
1363
           (ulong) session->cuted_fields);
1345
1364
  session->my_ok(copied + deleted, 0, 0L, tmp_name);
1346
 
  session->some_tables_deleted= 0;
 
1365
  session->some_tables_deleted= false;
1347
1366
 
1348
1367
  return false;
1349
1368
}
1350
1369
 
1351
1370
bool alter_table(Session *session,
1352
 
                 TableIdentifier &original_table_identifier,
1353
 
                 TableIdentifier &new_table_identifier,
 
1371
                 identifier::Table &original_table_identifier,
 
1372
                 identifier::Table &new_table_identifier,
1354
1373
                 HA_CREATE_INFO *create_info,
1355
1374
                 const message::Table &original_proto,
1356
1375
                 message::Table &create_proto,
1366
1385
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1367
1386
  {
1368
1387
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1369
 
    return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
 
1388
    return discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1370
1389
  }
1371
1390
 
1372
1391
  session->set_proc_info("init");
1403
1422
 
1404
1423
    if (name_lock)
1405
1424
    {
1406
 
      LOCK_open.lock(); /* ALTER TABLe */
 
1425
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1407
1426
      session->unlink_open_table(name_lock);
1408
 
      LOCK_open.unlock();
1409
1427
    }
1410
1428
  }
1411
1429
 
1464
1482
  alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(), keys_onoff);
1465
1483
 
1466
1484
  /* We can abort alter table for any table type */
1467
 
  session->abort_on_warning= !ignore;
 
1485
  session->setAbortOnWarning(not ignore);
1468
1486
 
1469
1487
  from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1470
1488
  to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1471
1489
 
1472
1490
  List_iterator<CreateField> it(create);
1473
1491
  CreateField *def;
1474
 
  copy_end=copy;
 
1492
  copy_end= copy;
1475
1493
  for (Field **ptr= to->getFields(); *ptr ; ptr++)
1476
1494
  {
1477
1495
    def=it++;
1487
1505
 
1488
1506
  found_count=delete_count=0;
1489
1507
 
1490
 
  if (order)
 
1508
  do
1491
1509
  {
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)
 
1510
    if (order)
 
1511
    {
 
1512
      if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1521
1513
      {
1522
 
        goto err;
 
1514
        char warn_buff[DRIZZLE_ERRMSG_SIZE];
 
1515
        snprintf(warn_buff, sizeof(warn_buff),
 
1516
                 _("order_st BY ignored because there is a user-defined clustered "
 
1517
                   "index in the table '%-.192s'"),
 
1518
                 from->getMutableShare()->getTableName());
 
1519
        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
 
1520
                     warn_buff);
1523
1521
      }
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
1522
      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
 
 
 
1523
      {
 
1524
        FileSort filesort(*session);
 
1525
        from->sort.io_cache= new internal::IO_CACHE;
 
1526
 
 
1527
        tables.table= from;
 
1528
        tables.setTableName(const_cast<char *>(from->getMutableShare()->getTableName()));
 
1529
        tables.alias= const_cast<char *>(tables.getTableName());
 
1530
        tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
 
1531
        error= 1;
 
1532
 
 
1533
        if (session->lex->select_lex.setup_ref_array(session, order_num) ||
 
1534
            setup_order(session, session->lex->select_lex.ref_pointer_array,
 
1535
                        &tables, fields, all_fields, order) ||
 
1536
            !(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
 
1537
            (from->sort.found_records= filesort.run(from, sortorder, length,
 
1538
                                                    (optimizer::SqlSelect *) 0, HA_POS_ERROR,
 
1539
                                                    1, examined_rows)) == HA_POS_ERROR)
 
1540
        {
 
1541
          break;
 
1542
        }
 
1543
      }
 
1544
    }
 
1545
 
 
1546
    /* Tell handler that we have values for all columns in the to table */
 
1547
    to->use_all_columns();
 
1548
 
 
1549
    error= info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1565
1550
    if (error)
1566
 
    { 
1567
 
      if (!ignore ||
1568
 
          to->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
1551
    {
 
1552
      to->print_error(errno, MYF(0));
 
1553
 
 
1554
      break;
 
1555
    }
 
1556
 
 
1557
    if (ignore)
 
1558
    {
 
1559
      to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
 
1560
    }
 
1561
 
 
1562
    session->row_count= 0;
 
1563
    to->restoreRecordAsDefault();        // Create empty record
 
1564
    while (not (error=info.read_record(&info)))
 
1565
    {
 
1566
      if (session->getKilled())
 
1567
      {
 
1568
        session->send_kill_message();
 
1569
        error= 1;
 
1570
        break;
 
1571
      }
 
1572
      session->row_count++;
 
1573
      /* Return error if source table isn't empty. */
 
1574
      if (error_if_not_empty)
 
1575
      {
 
1576
        error= 1;
 
1577
        break;
 
1578
      }
 
1579
      if (to->next_number_field)
 
1580
      {
 
1581
        if (auto_increment_field_copied)
 
1582
          to->auto_increment_field_not_null= true;
 
1583
        else
 
1584
          to->next_number_field->reset();
 
1585
      }
 
1586
 
 
1587
      for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
 
1588
      {
 
1589
        if (not copy->to_field->hasDefault() and copy->from_null_ptr and  *copy->from_null_ptr & copy->from_bit)
 
1590
        {
 
1591
          copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1592
                                      ER_WARN_DATA_TRUNCATED, 1);
 
1593
          copy->to_field->reset();
 
1594
          error= 1;
 
1595
          break;
 
1596
        }
 
1597
 
 
1598
        copy_ptr->do_copy(copy_ptr);
 
1599
      }
 
1600
 
 
1601
      if (error)
 
1602
      {
 
1603
        break;
 
1604
      }
 
1605
 
 
1606
      prev_insert_id= to->cursor->next_insert_id;
 
1607
      error= to->cursor->insertRecord(to->record[0]);
 
1608
      to->auto_increment_field_not_null= false;
 
1609
 
 
1610
      if (error)
1569
1611
      { 
1570
 
        to->print_error(error, MYF(0));
1571
 
        break;
1572
 
      }
1573
 
      to->cursor->restore_auto_increment(prev_insert_id);
1574
 
      delete_count++;
 
1612
        if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
1613
        { 
 
1614
          to->print_error(error, MYF(0));
 
1615
          break;
 
1616
        }
 
1617
        to->cursor->restore_auto_increment(prev_insert_id);
 
1618
        delete_count++;
 
1619
      }
 
1620
      else
 
1621
      {
 
1622
        found_count++;
 
1623
      }
1575
1624
    }
1576
 
    else
 
1625
 
 
1626
    info.end_read_record();
 
1627
    from->free_io_cache();
 
1628
    delete [] copy;                             // This is never 0
 
1629
 
 
1630
    if (to->cursor->ha_end_bulk_insert() && error <= 0)
1577
1631
    {
1578
 
      found_count++;
 
1632
      to->print_error(errno, MYF(0));
 
1633
      error= 1;
1579
1634
    }
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;
 
1635
    to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
 
1636
 
 
1637
    /*
 
1638
      Ensure that the new table is saved properly to disk so that we
 
1639
      can do a rename
 
1640
    */
 
1641
    if (transaction_services.autocommitOrRollback(*session, false))
 
1642
      error= 1;
 
1643
 
 
1644
    if (not session->endActiveTransaction())
 
1645
      error= 1;
 
1646
 
 
1647
  } while (0);
 
1648
 
 
1649
  session->setAbortOnWarning(false);
1604
1650
  from->free_io_cache();
1605
1651
  *copied= found_count;
1606
1652
  *deleted=delete_count;
1607
1653
  to->cursor->ha_release_auto_increment();
1608
 
  if (to->cursor->ha_external_lock(session,F_UNLCK))
 
1654
 
 
1655
  if (to->cursor->ha_external_lock(session, F_UNLCK))
 
1656
  {
1609
1657
    error=1;
 
1658
  }
1610
1659
 
1611
1660
  return(error > 0 ? -1 : 0);
1612
1661
}
1613
1662
 
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)
 
1663
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
1639
1664
{
1640
1665
  Table *new_table;
1641
1666