~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Brian Aker
  • Date: 2011-02-22 06:12:02 UTC
  • mfrom: (2190.1.6 drizzle-build)
  • Revision ID: brian@tangent.org-20110222061202-k03czxykqy4x9hjs
List update, header fixes, multiple symbols, and David deletes some code.

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
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include "config.h"
 
21
#include <config.h>
22
22
 
23
23
#include <fcntl.h>
24
24
 
25
25
#include <sstream>
26
26
 
27
 
#include "drizzled/show.h"
28
 
#include "drizzled/lock.h"
29
 
#include "drizzled/session.h"
30
 
#include "drizzled/statement/alter_table.h"
31
 
#include "drizzled/global_charset_info.h"
32
 
 
33
 
 
34
 
#include "drizzled/gettext.h"
35
 
#include "drizzled/data_home.h"
36
 
#include "drizzled/sql_table.h"
37
 
#include "drizzled/table_proto.h"
38
 
#include "drizzled/optimizer/range.h"
39
 
#include "drizzled/time_functions.h"
40
 
#include "drizzled/records.h"
41
 
#include "drizzled/pthread_globals.h"
42
 
#include "drizzled/internal/my_sys.h"
43
 
#include "drizzled/internal/iocache.h"
44
 
 
45
 
#include "drizzled/transaction_services.h"
46
 
 
47
 
#include "drizzled/filesort.h"
48
 
 
49
 
#include "drizzled/message.h"
 
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
#include <drizzled/plugin/storage_engine.h>
 
45
#include <drizzled/copy_field.h>
 
46
 
 
47
#include <drizzled/transaction_services.h>
 
48
 
 
49
#include <drizzled/filesort.h>
 
50
 
 
51
#include <drizzled/message.h>
50
52
 
51
53
using namespace std;
52
54
 
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->getLex()->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()->getLex()->select_lex.table_list.first;
 
95
  TableList *all_tables= getSession()->getLex()->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()->getLex()->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
    }
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
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 (not (original_table_message= plugin::StorageEngine::getTableMessage(*getSession(), identifier)))
114
123
    {
115
 
      std::string path;
116
 
      identifier.getSQLPath(path);
117
 
      my_error(ER_BAD_TABLE_ERROR, MYF(0), path.c_str());
 
124
      my_error(ER_BAD_TABLE_ERROR, identifier);
118
125
      return true;
119
126
    }
120
127
 
121
 
    if (not  create_info.db_type)
 
128
    if (not  create_info().db_type)
122
129
    {
123
 
      create_info.db_type= 
124
 
        plugin::StorageEngine::findByName(*session, original_table_message->engine().name());
 
130
      create_info().db_type= 
 
131
        plugin::StorageEngine::findByName(*getSession(), original_table_message->engine().name());
125
132
 
126
 
      if (not create_info.db_type)
 
133
      if (not create_info().db_type)
127
134
      {
128
 
        std::string path;
129
 
        identifier.getSQLPath(path);
130
 
        my_error(ER_BAD_TABLE_ERROR, MYF(0), path.c_str());
 
135
        my_error(ER_BAD_TABLE_ERROR, identifier);
131
136
        return true;
132
137
      }
133
138
    }
136
141
  if (not validateCreateTableOption())
137
142
    return true;
138
143
 
139
 
  /* ALTER TABLE ends previous transaction */
140
 
  if (not session->endActiveTransaction())
 
144
  if (getSession()->inTransaction())
 
145
  {
 
146
    my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
141
147
    return true;
 
148
  }
142
149
 
143
 
  if (not (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
 
150
  if (not (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
144
151
    return true;
145
152
 
146
153
  bool res;
147
154
  if (original_table_message->type() == message::Table::STANDARD )
148
155
  {
149
 
    TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
150
 
    TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
151
 
                                   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()->getLex()->name.str ? getSession()->getLex()->name.str : first_table->getTableName());
152
159
 
153
 
    res= alter_table(session, 
 
160
    res= alter_table(getSession(), 
154
161
                     identifier,
155
162
                     new_identifier,
156
 
                     &create_info,
 
163
                     &create_info(),
157
164
                     *original_table_message,
158
 
                     create_table_message,
 
165
                     createTableMessage(),
159
166
                     first_table,
160
167
                     &alter_info,
161
168
                     select_lex->order_list.elements,
162
169
                     (Order *) select_lex->order_list.first,
163
 
                     session->lex->ignore);
 
170
                     getSession()->getLex()->ignore);
164
171
  }
165
172
  else
166
173
  {
167
 
    TableIdentifier catch22(first_table->getSchemaName(), first_table->getTableName());
168
 
    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);
169
176
    assert(table);
170
177
    {
171
 
      TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
172
 
      TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
173
 
                                     session->lex->name.str ? session->lex->name.str : first_table->getTableName(),
174
 
                                     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()->getLex()->name.str ? getSession()->getLex()->name.str : first_table->getTableName(),
 
181
                                       table->getMutableShare()->getPath());
175
182
 
176
 
      res= alter_table(session, 
 
183
      res= alter_table(getSession(), 
177
184
                       identifier,
178
185
                       new_identifier,
179
 
                       &create_info,
 
186
                       &create_info(),
180
187
                       *original_table_message,
181
 
                       create_table_message,
 
188
                       createTableMessage(),
182
189
                       first_table,
183
190
                       &alter_info,
184
191
                       select_lex->order_list.elements,
185
192
                       (Order *) select_lex->order_list.first,
186
 
                       session->lex->ignore);
 
193
                       getSession()->getLex()->ignore);
187
194
    }
188
195
  }
189
196
 
191
198
     Release the protection against the global read lock and wake
192
199
     everyone, who might want to set a global read lock.
193
200
   */
194
 
  session->startWaitingGlobalReadLock();
 
201
  getSession()->startWaitingGlobalReadLock();
195
202
 
196
203
  return res;
197
204
}
237
244
                 Table instructions
238
245
  @retval false  success
239
246
*/
240
 
static bool mysql_prepare_alter_table(Session *session,
241
 
                                      Table *table,
242
 
                                      HA_CREATE_INFO *create_info,
243
 
                                      const message::Table &original_proto,
244
 
                                      message::Table &table_message,
245
 
                                      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)
246
253
{
247
254
  /* New column definitions are added here */
248
255
  List<CreateField> new_create_list;
249
256
  /* New key definitions are added here */
250
257
  List<Key> new_key_list;
251
 
  List_iterator<AlterDrop> drop_it(alter_info->drop_list);
252
 
  List_iterator<CreateField> def_it(alter_info->create_list);
253
 
  List_iterator<AlterColumn> alter_it(alter_info->alter_list);
254
 
  List_iterator<Key> key_it(alter_info->key_list);
255
 
  List_iterator<CreateField> find_it(new_create_list);
256
 
  List_iterator<CreateField> field_it(new_create_list);
 
258
  List<AlterDrop>::iterator drop_it(alter_info->drop_list.begin());
 
259
  List<CreateField>::iterator def_it(alter_info->create_list.begin());
 
260
  List<AlterColumn>::iterator alter_it(alter_info->alter_list.begin());
 
261
  List<Key>::iterator key_it(alter_info->key_list.begin());
 
262
  List<CreateField>::iterator find_it(new_create_list.begin());
 
263
  List<CreateField>::iterator field_it(new_create_list.begin());
257
264
  List<Key_part_spec> key_parts;
258
265
  uint32_t used_fields= create_info->used_fields;
259
266
  KeyInfo *key_info= table->key_info;
263
270
  message::Table::TableOptions *table_options;
264
271
  table_options= table_message.mutable_options();
265
272
 
266
 
  if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
 
273
  if (not (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
267
274
    create_info->default_table_charset= table->getShare()->table_charset;
268
 
  if (! (used_fields & HA_CREATE_USED_AUTO) &&
269
 
      table->found_next_number_field)
 
275
 
 
276
  if (not (used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
270
277
  {
271
278
    /* Table has an autoincrement, copy value to new table */
272
279
    table->cursor->info(HA_STATUS_AUTO);
274
281
    if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
275
282
      table_options->set_has_user_set_auto_increment_value(false);
276
283
  }
 
284
 
277
285
  table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
278
286
  CreateField *def;
279
287
 
280
288
  /* First collect all fields from table which isn't in drop_list */
281
 
  Field **f_ptr;
282
289
  Field *field;
283
 
  for (f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
 
290
  for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
284
291
  {
285
292
    /* Check if field should be dropped */
286
293
    AlterDrop *drop;
287
 
    drop_it.rewind();
 
294
    drop_it= alter_info->drop_list.begin();
288
295
    while ((drop= drop_it++))
289
296
    {
290
297
      if (drop->type == AlterDrop::COLUMN &&
300
307
        break;
301
308
      }
302
309
    }
 
310
 
303
311
    if (drop)
304
312
    {
305
313
      drop_it.remove();
310
318
    field->setReadSet();
311
319
 
312
320
    /* Check if field is changed */
313
 
    def_it.rewind();
 
321
    def_it= alter_info->create_list.begin();
314
322
    while ((def= def_it++))
315
323
    {
316
324
      if (def->change &&
317
325
          ! my_strcasecmp(system_charset_info, field->field_name, def->change))
318
326
              break;
319
327
    }
 
328
 
320
329
    if (def)
321
330
    {
322
331
      /* Field is changed */
335
344
      */
336
345
      def= new CreateField(field, field);
337
346
      new_create_list.push_back(def);
338
 
      alter_it.rewind(); /* Change default if ALTER */
 
347
      alter_it= alter_info->alter_list.begin(); /* Change default if ALTER */
339
348
      AlterColumn *alter;
 
349
 
340
350
      while ((alter= alter_it++))
341
351
      {
342
352
        if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
343
353
          break;
344
354
      }
 
355
 
345
356
      if (alter)
346
357
      {
347
358
        if (def->sql_type == DRIZZLE_TYPE_BLOB)
349
360
          my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
350
361
          return true;
351
362
        }
 
363
 
352
364
        if ((def->def= alter->def))
353
365
        {
354
366
          /* Use new default */
362
374
      }
363
375
    }
364
376
  }
365
 
  def_it.rewind();
 
377
 
 
378
  def_it= alter_info->create_list.begin();
366
379
  while ((def= def_it++)) /* Add new columns */
367
380
  {
368
381
    if (def->change && ! def->field)
388
401
    else
389
402
    {
390
403
      CreateField *find;
391
 
      find_it.rewind();
 
404
      find_it= new_create_list.begin();
 
405
 
392
406
      while ((find= find_it++)) /* Add new columns */
393
407
      {
394
 
        if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
 
408
        if (not my_strcasecmp(system_charset_info,def->after, find->field_name))
395
409
          break;
396
410
      }
397
 
      if (! find)
 
411
 
 
412
      if (not find)
398
413
      {
399
414
        my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
400
415
        return true;
401
416
      }
 
417
 
402
418
      find_it.after(def); /* Put element after this */
 
419
 
403
420
      /*
404
421
        XXX: hack for Bug#28427.
405
422
        If column order has changed, force OFFLINE ALTER Table
412
429
      */
413
430
      if (alter_info->build_method == HA_BUILD_ONLINE)
414
431
      {
415
 
        my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->getQueryString()->c_str());
 
432
        my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
416
433
        return true;
417
434
      }
 
435
 
418
436
      alter_info->build_method= HA_BUILD_OFFLINE;
419
437
    }
420
438
  }
 
439
 
421
440
  if (alter_info->alter_list.elements)
422
441
  {
423
442
    my_error(ER_BAD_FIELD_ERROR,
426
445
             table->getMutableShare()->getTableName());
427
446
    return true;
428
447
  }
429
 
  if (! new_create_list.elements)
 
448
 
 
449
  if (not new_create_list.elements)
430
450
  {
431
451
    my_message(ER_CANT_REMOVE_ALL_FIELDS,
432
452
               ER(ER_CANT_REMOVE_ALL_FIELDS),
442
462
  {
443
463
    char *key_name= key_info->name;
444
464
    AlterDrop *drop;
445
 
    drop_it.rewind();
 
465
 
 
466
    drop_it= alter_info->drop_list.begin();
446
467
    while ((drop= drop_it++))
447
468
    {
448
469
      if (drop->type == AlterDrop::KEY &&
449
470
          ! my_strcasecmp(system_charset_info, key_name, drop->name))
450
471
        break;
451
472
    }
 
473
 
452
474
    if (drop)
453
475
    {
454
476
      drop_it.remove();
456
478
    }
457
479
 
458
480
    KeyPartInfo *key_part= key_info->key_part;
459
 
    key_parts.empty();
 
481
    key_parts.clear();
460
482
    for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
461
483
    {
462
484
      if (! key_part->field)
464
486
 
465
487
      const char *key_part_name= key_part->field->field_name;
466
488
      CreateField *cfield;
467
 
      field_it.rewind();
 
489
      field_it= new_create_list.begin();
468
490
      while ((cfield= field_it++))
469
491
      {
470
492
        if (cfield->change)
471
493
        {
472
 
          if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
 
494
          if (not my_strcasecmp(system_charset_info, key_part_name, cfield->change))
473
495
            break;
474
496
        }
475
 
        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))
476
498
          break;
477
499
      }
478
 
      if (! cfield)
 
500
 
 
501
      if (not cfield)
479
502
              continue; /* Field is removed */
480
503
      
481
504
      uint32_t key_part_length= key_part->length;
507
530
    }
508
531
    if (key_parts.elements)
509
532
    {
510
 
      KEY_CREATE_INFO key_create_info;
 
533
      key_create_information_st key_create_info= default_key_create_info;
511
534
      Key *key;
512
 
      enum Key::Keytype key_type;
513
 
      memset(&key_create_info, 0, sizeof(key_create_info));
 
535
      Key::Keytype key_type;
514
536
 
515
537
      key_create_info.algorithm= key_info->algorithm;
 
538
 
516
539
      if (key_info->flags & HA_USES_BLOCK_SIZE)
517
540
        key_create_info.block_size= key_info->block_size;
 
541
 
518
542
      if (key_info->flags & HA_USES_COMMENT)
519
543
        key_create_info.comment= key_info->comment;
520
544
 
526
550
          key_type= Key::UNIQUE;
527
551
      }
528
552
      else
 
553
      {
529
554
        key_type= Key::MULTIPLE;
 
555
      }
530
556
 
531
557
      key= new Key(key_type,
532
558
                   key_name,
539
565
  }
540
566
 
541
567
  /* Copy over existing foreign keys */
542
 
  for (int j= 0; j < original_proto.fk_constraint_size(); j++)
 
568
  for (int32_t j= 0; j < original_proto.fk_constraint_size(); j++)
543
569
  {
544
570
    AlterDrop *drop;
545
 
    drop_it.rewind();
 
571
    drop_it= alter_info->drop_list.begin();
546
572
    while ((drop= drop_it++))
547
573
    {
548
574
      if (drop->type == AlterDrop::FOREIGN_KEY &&
620
646
             alter_info->drop_list.head()->name);
621
647
    return true;
622
648
  }
 
649
 
623
650
  if (alter_info->alter_list.elements)
624
651
  {
625
652
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
630
657
 
631
658
  if (not table_message.options().has_comment()
632
659
      && table->getMutableShare()->hasComment())
 
660
  {
633
661
    table_options->set_comment(table->getMutableShare()->getComment());
 
662
  }
634
663
 
635
664
  if (table->getShare()->getType())
636
665
  {
637
666
    table_message.set_type(message::Table::TEMPORARY);
638
667
  }
639
668
 
640
 
  table_message.set_creation_timestamp(table->getShare()->getTableProto()->creation_timestamp());
641
 
  table_message.set_version(table->getShare()->getTableProto()->version());
642
 
  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());
643
672
 
644
673
  rc= false;
645
674
  alter_info->create_list.swap(new_create_list);
674
703
}
675
704
 
676
705
/* table_list should contain just one table */
677
 
static int mysql_discard_or_import_tablespace(Session *session,
 
706
static int discard_or_import_tablespace(Session *session,
678
707
                                              TableList *table_list,
679
708
                                              enum tablespace_op_type tablespace_op)
680
709
{
681
710
  Table *table;
682
711
  bool discard;
683
 
  int error;
684
712
 
685
713
  /*
686
714
    Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
687
715
    ALTER Table
688
716
  */
689
 
 
690
717
  TransactionServices &transaction_services= TransactionServices::singleton();
691
718
  session->set_proc_info("discard_or_import_tablespace");
692
719
 
696
723
   We set this flag so that ha_innobase::open and ::external_lock() do
697
724
   not complain when we lock the table
698
725
 */
699
 
  session->tablespace_op= true;
700
 
  if (!(table= session->openTableLock(table_list, TL_WRITE)))
 
726
  session->setDoingTablespaceOperation(true);
 
727
  if (not (table= session->openTableLock(table_list, TL_WRITE)))
701
728
  {
702
 
    session->tablespace_op= false;
 
729
    session->setDoingTablespaceOperation(false);
703
730
    return -1;
704
731
  }
705
732
 
706
 
  error= table->cursor->ha_discard_or_import_tablespace(discard);
707
 
 
708
 
  session->set_proc_info("end");
709
 
 
710
 
  if (error)
711
 
    goto err;
712
 
 
713
 
  /* The ALTER Table is always in its own transaction */
714
 
  error= transaction_services.autocommitOrRollback(session, false);
715
 
  if (not session->endActiveTransaction())
716
 
    error=1;
717
 
 
718
 
  if (error)
719
 
    goto err;
720
 
 
721
 
  write_bin_log(session, *session->getQueryString());
722
 
 
723
 
err:
724
 
  (void) transaction_services.autocommitOrRollback(session, error);
725
 
  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);
726
756
 
727
757
  if (error == 0)
728
758
  {
772
802
                        ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
773
803
                        table->getMutableShare()->getTableName());
774
804
    error= 0;
775
 
  } else if (error)
 
805
  }
 
806
  else if (error)
 
807
  {
776
808
    table->print_error(error, MYF(0));
 
809
  }
777
810
 
778
811
  return(error);
779
812
}
780
813
 
781
814
static bool lockTableIfDifferent(Session &session,
782
 
                                 TableIdentifier &original_table_identifier,
783
 
                                 TableIdentifier &new_table_identifier,
 
815
                                 identifier::Table &original_table_identifier,
 
816
                                 identifier::Table &new_table_identifier,
784
817
                                 Table *name_lock)
785
818
{
786
819
  /* Check that we are not trying to rename to an existing table */
791
824
 
792
825
      if (session.find_temporary_table(new_table_identifier))
793
826
      {
794
 
        std::string path;
795
 
        new_table_identifier.getSQLPath(path);
796
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
827
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
797
828
        return false;
798
829
      }
799
830
    }
806
837
 
807
838
      if (not name_lock)
808
839
      {
809
 
        std::string path;
810
 
        new_table_identifier.getSQLPath(path);
811
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
840
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
812
841
        return false;
813
842
      }
814
843
 
815
844
      if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
816
845
      {
817
 
        std::string path;
818
 
        new_table_identifier.getSQLPath(path);
819
 
 
820
846
        /* Table will be closed by Session::executeCommand() */
821
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
847
        my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
822
848
 
823
 
        table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
824
 
        session.unlink_open_table(name_lock);
825
 
        table::Cache::singleton().mutex().unlock();
 
849
        {
 
850
          boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
 
851
          session.unlink_open_table(name_lock);
 
852
        }
826
853
 
827
854
        return false;
828
855
      }
876
903
 
877
904
static bool internal_alter_table(Session *session,
878
905
                                 Table *table,
879
 
                                 TableIdentifier &original_table_identifier,
880
 
                                 TableIdentifier &new_table_identifier,
 
906
                                 identifier::Table &original_table_identifier,
 
907
                                 identifier::Table &new_table_identifier,
881
908
                                 HA_CREATE_INFO *create_info,
882
909
                                 const message::Table &original_proto,
883
910
                                 message::Table &create_proto,
934
961
  if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
935
962
      new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
936
963
  {
937
 
    std::string path;
938
 
    new_table_identifier.getSQLPath(path);
939
 
    my_error(ER_ILLEGAL_HA, MYF(0), path.c_str());
 
964
    my_error(ER_ILLEGAL_HA, new_table_identifier);
940
965
 
941
966
    return true;
942
967
  }
954
979
    tmp.reset(ALTER_KEYS_ONOFF);
955
980
    tmp&= alter_info->flags;
956
981
 
957
 
    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
958
983
    {
959
984
      switch (alter_info->keys_onoff)
960
985
      {
961
986
      case LEAVE_AS_IS:
962
987
        break;
 
988
 
963
989
      case ENABLE:
964
990
        /*
965
991
          wait_while_table_is_used() ensures that table being altered is
970
996
          while the fact that the table is still open gives us protection
971
997
          from concurrent DDL statements.
972
998
        */
973
 
        table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
974
 
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
975
 
        table::Cache::singleton().mutex().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
        }
976
1003
        error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
 
1004
 
977
1005
        /* COND_refresh will be signaled in close_thread_tables() */
978
1006
        break;
 
1007
 
979
1008
      case DISABLE:
980
 
        table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
981
 
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
982
 
        table::Cache::singleton().mutex().unlock();
983
 
        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
 
984
1015
        /* COND_refresh will be signaled in close_thread_tables() */
985
1016
        break;
986
 
      default:
987
 
        assert(false);
988
 
        error= 0;
989
 
        break;
990
1017
      }
991
1018
 
992
1019
      if (error == HA_ERR_WRONG_COMMAND)
993
1020
      {
994
 
        error= 0;
 
1021
        error= EE_OK;
995
1022
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
996
1023
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
997
1024
                            table->getAlias());
998
1025
      }
999
1026
 
1000
 
      table::Cache::singleton().mutex().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 */
1001
1028
      /*
1002
1029
        Unlike to the above case close_cached_table() below will remove ALL
1003
1030
        instances of Table from table cache (it will also remove table lock
1004
1031
        held by this thread). So to make actual table renaming and writing
1005
1032
        to binlog atomic we have to put them into the same critical section
1006
1033
        protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
1007
 
        access() and mysql_rename_table() calls.
 
1034
        access() and rename_table() calls.
1008
1035
      */
1009
1036
 
1010
 
      if (error == 0 &&  not (original_table_identifier == new_table_identifier))
 
1037
      if (not error &&  not (original_table_identifier == new_table_identifier))
1011
1038
      {
1012
1039
        session->set_proc_info("rename");
1013
1040
        /*
1025
1052
        */
1026
1053
        if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1027
1054
        {
1028
 
          std::string path;
1029
 
          new_table_identifier.getSQLPath(path);
1030
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
1055
          my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
1031
1056
          error= -1;
1032
1057
        }
1033
1058
        else
1034
1059
        {
1035
 
          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))
1036
1061
          {
1037
1062
            error= -1;
1038
1063
          }
1041
1066
 
1042
1067
      if (error == HA_ERR_WRONG_COMMAND)
1043
1068
      {
1044
 
        error= 0;
 
1069
        error= EE_OK;
1045
1070
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1046
1071
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1047
1072
                            table->getAlias());
1048
1073
      }
1049
1074
 
1050
 
      if (error == 0)
 
1075
      if (not error)
1051
1076
      {
1052
1077
        TransactionServices &transaction_services= TransactionServices::singleton();
1053
1078
        transaction_services.allocateNewTransactionId();
1054
1079
        write_bin_log(session, *session->getQueryString());
1055
1080
        session->my_ok();
1056
1081
      }
1057
 
      else if (error > 0)
 
1082
      else if (error > EE_OK) // If we have already set the error, we pass along -1
1058
1083
      {
1059
1084
        table->print_error(error, MYF(0));
1060
 
        error= -1;
1061
1085
      }
1062
1086
 
1063
 
      table::Cache::singleton().mutex().unlock();
1064
1087
      table_list->table= NULL;
1065
1088
 
1066
1089
      return error;
1070
1093
  /* We have to do full alter table. */
1071
1094
  new_engine= create_info->db_type;
1072
1095
 
1073
 
  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))
1074
1097
  {
1075
1098
    return true;
1076
1099
  }
1087
1110
    case we just use it as is. Neither of these tables require locks in order to  be
1088
1111
    filled.
1089
1112
  */
1090
 
  TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
 
1113
  identifier::Table new_table_as_temporary(original_table_identifier.getSchemaName(),
1091
1114
                                         tmp_name,
1092
1115
                                         create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1093
1116
                                         message::Table::TEMPORARY);
1094
1117
 
1095
 
  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);
1096
1128
 
1097
1129
  if (error != 0)
1098
1130
  {
1142
1174
  {
1143
1175
 
1144
1176
    /*
1145
 
      No default value was provided for a DATE/DATETIME field, the
1146
 
      current sql_mode doesn't allow the '0000-00-00' value and
1147
 
      the table to be altered isn't empty.
1148
 
      Report error here.
 
1177
      No default value was provided for new fields.
1149
1178
    */
1150
1179
    if (alter_info->error_if_not_empty && session->row_count)
1151
1180
    {
1183
1212
        delete new_table;
1184
1213
      }
1185
1214
 
1186
 
      table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
 
1215
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1187
1216
 
1188
1217
      plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1189
 
      table::Cache::singleton().mutex().unlock();
1190
1218
 
1191
1219
      return true;
1192
1220
    }
1209
1237
 
1210
1238
    new_table_identifier.setPath(new_table_as_temporary.getPath());
1211
1239
 
1212
 
    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)
1213
1241
    {
1214
1242
      return true;
1215
1243
    }
1233
1261
      delete new_table;
1234
1262
    }
1235
1263
 
1236
 
    table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
1237
 
 
1238
 
    /*
1239
 
      Data is copied. Now we:
1240
 
      1) Wait until all other threads close old version of table.
1241
 
      2) Close instances of table open by this thread and replace them
1242
 
      with exclusive name-locks.
1243
 
      3) Rename the old table to a temp name, rename the new one to the
1244
 
      old name.
1245
 
      4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1246
 
      we reopen new version of table.
1247
 
      5) Write statement to the binary log.
1248
 
      6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1249
 
      remove name-locks from list of open tables and table cache.
1250
 
      7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1251
 
      call to remove name-locks from table cache and list of open table.
1252
 
    */
1253
 
 
1254
 
    session->set_proc_info("rename result table");
1255
 
 
1256
 
    snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1257
 
 
1258
 
    my_casedn_str(files_charset_info, old_name);
1259
 
 
1260
 
    wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1261
 
    session->close_data_files_and_morph_locks(original_table_identifier);
1262
 
 
1263
 
    error= 0;
1264
 
 
1265
 
    /*
1266
 
      This leads to the storage engine (SE) not being notified for renames in
1267
 
      mysql_rename_table(), because we just juggle with the FRM and nothing
1268
 
      more. If we have an intermediate table, then we notify the SE that
1269
 
      it should become the actual table. Later, we will recycle the old table.
1270
 
      However, in case of ALTER Table RENAME there might be no intermediate
1271
 
      table. This is when the old and new tables are compatible, according to
1272
 
      compare_table(). Then, we need one additional call to
1273
 
    */
1274
 
    TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1275
 
                                           old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1276
 
                                         message::Table::TEMPORARY);
1277
 
 
1278
 
    if (mysql_rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1279
 
    {
1280
 
      error= 1;
1281
 
      plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1282
 
    }
1283
 
    else
1284
 
    {
1285
 
      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))
1286
1308
      {
1287
 
        /* Try to get everything back. */
1288
 
        error= 1;
1289
 
 
1290
 
        plugin::StorageEngine::dropTable(*session, new_table_identifier);
1291
 
 
 
1309
        error= ER_ERROR_ON_RENAME;
1292
1310
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1293
 
 
1294
 
        mysql_rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1295
1311
      }
1296
1312
      else
1297
1313
      {
1298
 
        plugin::StorageEngine::dropTable(*session, original_table_to_drop);
1299
 
      }
1300
 
    }
1301
 
 
1302
 
    if (error)
1303
 
    {
1304
 
      /*
1305
 
        An error happened while we were holding exclusive name-lock on table
1306
 
        being altered. To be safe under LOCK TABLES we should remove placeholders
1307
 
        from list of open tables list and table cache.
1308
 
      */
1309
 
      session->unlink_open_table(table);
1310
 
      table::Cache::singleton().mutex().unlock();
1311
 
 
1312
 
      return true;
1313
 
    }
1314
 
 
1315
 
    table::Cache::singleton().mutex().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
    }
1316
1343
 
1317
1344
    session->set_proc_info("end");
1318
1345
 
1335
1362
           (ulong) (copied + deleted), (ulong) deleted,
1336
1363
           (ulong) session->cuted_fields);
1337
1364
  session->my_ok(copied + deleted, 0, 0L, tmp_name);
1338
 
  session->some_tables_deleted= 0;
 
1365
  session->some_tables_deleted= false;
1339
1366
 
1340
1367
  return false;
1341
1368
}
1342
1369
 
1343
1370
bool alter_table(Session *session,
1344
 
                 TableIdentifier &original_table_identifier,
1345
 
                 TableIdentifier &new_table_identifier,
 
1371
                 identifier::Table &original_table_identifier,
 
1372
                 identifier::Table &new_table_identifier,
1346
1373
                 HA_CREATE_INFO *create_info,
1347
1374
                 const message::Table &original_proto,
1348
1375
                 message::Table &create_proto,
1358
1385
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1359
1386
  {
1360
1387
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1361
 
    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);
1362
1389
  }
1363
1390
 
1364
1391
  session->set_proc_info("init");
1395
1422
 
1396
1423
    if (name_lock)
1397
1424
    {
1398
 
      table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
 
1425
      boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1399
1426
      session->unlink_open_table(name_lock);
1400
 
      table::Cache::singleton().mutex().unlock();
1401
1427
    }
1402
1428
  }
1403
1429
 
1456
1482
  alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(), keys_onoff);
1457
1483
 
1458
1484
  /* We can abort alter table for any table type */
1459
 
  session->abort_on_warning= !ignore;
 
1485
  session->setAbortOnWarning(not ignore);
1460
1486
 
1461
1487
  from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1462
1488
  to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1463
1489
 
1464
 
  List_iterator<CreateField> it(create);
 
1490
  List<CreateField>::iterator it(create.begin());
1465
1491
  CreateField *def;
1466
 
  copy_end=copy;
 
1492
  copy_end= copy;
1467
1493
  for (Field **ptr= to->getFields(); *ptr ; ptr++)
1468
1494
  {
1469
1495
    def=it++;
1479
1505
 
1480
1506
  found_count=delete_count=0;
1481
1507
 
1482
 
  if (order)
 
1508
  do
1483
1509
  {
1484
 
    if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1485
 
    {
1486
 
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
1487
 
      snprintf(warn_buff, sizeof(warn_buff),
1488
 
               _("order_st BY ignored because there is a user-defined clustered "
1489
 
                 "index in the table '%-.192s'"),
1490
 
               from->getMutableShare()->getTableName());
1491
 
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1492
 
                   warn_buff);
1493
 
    }
1494
 
    else
1495
 
    {
1496
 
      FileSort filesort(*session);
1497
 
      from->sort.io_cache= new internal::IO_CACHE;
1498
 
 
1499
 
      memset(&tables, 0, sizeof(tables));
1500
 
      tables.table= from;
1501
 
      tables.setTableName(const_cast<char *>(from->getMutableShare()->getTableName()));
1502
 
      tables.alias= const_cast<char *>(tables.getTableName());
1503
 
      tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1504
 
      error= 1;
1505
 
 
1506
 
      if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1507
 
          setup_order(session, session->lex->select_lex.ref_pointer_array,
1508
 
                      &tables, fields, all_fields, order) ||
1509
 
          !(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1510
 
          (from->sort.found_records= filesort.run(from, sortorder, length,
1511
 
                                                  (optimizer::SqlSelect *) 0, HA_POS_ERROR,
1512
 
                                                  1, examined_rows)) == HA_POS_ERROR)
 
1510
    if (order)
 
1511
    {
 
1512
      if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1513
1513
      {
1514
 
        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);
1515
1521
      }
1516
 
    }
1517
 
  }
1518
 
 
1519
 
  /* Tell handler that we have values for all columns in the to table */
1520
 
  to->use_all_columns();
1521
 
  info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1522
 
  if (ignore)
1523
 
    to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1524
 
  session->row_count= 0;
1525
 
  to->restoreRecordAsDefault();        // Create empty record
1526
 
  while (!(error=info.read_record(&info)))
1527
 
  {
1528
 
    if (session->getKilled())
1529
 
    {
1530
 
      session->send_kill_message();
1531
 
      error= 1;
1532
 
      break;
1533
 
    }
1534
 
    session->row_count++;
1535
 
    /* Return error if source table isn't empty. */
1536
 
    if (error_if_not_empty)
1537
 
    {
1538
 
      error= 1;
1539
 
      break;
1540
 
    }
1541
 
    if (to->next_number_field)
1542
 
    {
1543
 
      if (auto_increment_field_copied)
1544
 
        to->auto_increment_field_not_null= true;
1545
1522
      else
1546
 
        to->next_number_field->reset();
1547
 
    }
1548
 
 
1549
 
    for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
1550
 
    {
1551
 
      if (not copy->to_field->hasDefault() and copy->from_null_ptr and  *copy->from_null_ptr & copy->from_bit)
1552
1523
      {
1553
 
        copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1554
 
                                    ER_WARN_DATA_TRUNCATED, 1);
1555
 
        copy->to_field->reset();
 
1524
        FileSort filesort(*session);
 
1525
        from->sort.io_cache= new internal::IO_CACHE;
 
1526
 
 
1527
        tables.table= from;
 
1528
        tables.setTableName(from->getMutableShare()->getTableName());
 
1529
        tables.alias= tables.getTableName();
 
1530
        tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1556
1531
        error= 1;
1557
 
        break;
 
1532
 
 
1533
        if (session->getLex()->select_lex.setup_ref_array(session, order_num) ||
 
1534
            setup_order(session, session->getLex()->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
        }
1558
1543
      }
1559
 
 
1560
 
      copy_ptr->do_copy(copy_ptr);
1561
1544
    }
1562
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);
1563
1550
    if (error)
1564
1551
    {
 
1552
      to->print_error(errno, MYF(0));
 
1553
 
1565
1554
      break;
1566
1555
    }
1567
1556
 
1568
 
    prev_insert_id= to->cursor->next_insert_id;
1569
 
    error= to->cursor->insertRecord(to->record[0]);
1570
 
    to->auto_increment_field_not_null= false;
1571
 
 
1572
 
    if (error)
1573
 
    { 
1574
 
      if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
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)
1575
1611
      { 
1576
 
        to->print_error(error, MYF(0));
1577
 
        break;
1578
 
      }
1579
 
      to->cursor->restore_auto_increment(prev_insert_id);
1580
 
      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
      }
1581
1624
    }
1582
 
    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)
1583
1631
    {
1584
 
      found_count++;
 
1632
      to->print_error(errno, MYF(0));
 
1633
      error= 1;
1585
1634
    }
1586
 
  }
1587
 
 
1588
 
  info.end_read_record();
1589
 
  from->free_io_cache();
1590
 
  delete [] copy;                               // This is never 0
1591
 
 
1592
 
  if (to->cursor->ha_end_bulk_insert() && error <= 0)
1593
 
  {
1594
 
    to->print_error(errno, MYF(0));
1595
 
    error=1;
1596
 
  }
1597
 
  to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1598
 
 
1599
 
  /*
1600
 
    Ensure that the new table is saved properly to disk so that we
1601
 
    can do a rename
1602
 
  */
1603
 
  if (transaction_services.autocommitOrRollback(session, false))
1604
 
    error=1;
1605
 
  if (! session->endActiveTransaction())
1606
 
    error=1;
1607
 
 
1608
 
 err:
1609
 
  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);
1610
1650
  from->free_io_cache();
1611
1651
  *copied= found_count;
1612
1652
  *deleted=delete_count;
1613
1653
  to->cursor->ha_release_auto_increment();
1614
 
  if (to->cursor->ha_external_lock(session,F_UNLCK))
 
1654
 
 
1655
  if (to->cursor->ha_external_lock(session, F_UNLCK))
 
1656
  {
1615
1657
    error=1;
 
1658
  }
1616
1659
 
1617
1660
  return(error > 0 ? -1 : 0);
1618
1661
}
1619
1662
 
1620
 
static int
1621
 
create_temporary_table(Session *session,
1622
 
                       TableIdentifier &identifier,
1623
 
                       HA_CREATE_INFO *create_info,
1624
 
                       message::Table &create_proto,
1625
 
                       AlterInfo *alter_info)
1626
 
{
1627
 
  int error;
1628
 
 
1629
 
  /*
1630
 
    Create a table with a temporary name.
1631
 
    We don't log the statement, it will be logged later.
1632
 
  */
1633
 
  create_proto.set_name(identifier.getTableName());
1634
 
 
1635
 
  create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1636
 
 
1637
 
  error= mysql_create_table(session,
1638
 
                            identifier,
1639
 
                            create_info, create_proto, alter_info, true, 0, false);
1640
 
 
1641
 
  return error;
1642
 
}
1643
 
 
1644
 
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
 
1663
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
1645
1664
{
1646
1665
  Table *new_table;
1647
1666