Drizzled Public API Documentation

alter_table.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <config.h>
22 
23 #include <fcntl.h>
24 
25 #include <sstream>
26 
27 #include <drizzled/show.h>
28 #include <drizzled/lock.h>
29 #include <drizzled/session.h>
30 #include <drizzled/statement/alter_table.h>
31 #include <drizzled/charset.h>
32 #include <drizzled/gettext.h>
33 #include <drizzled/data_home.h>
34 #include <drizzled/sql_table.h>
35 #include <drizzled/table_proto.h>
36 #include <drizzled/optimizer/range.h>
37 #include <drizzled/time_functions.h>
38 #include <drizzled/records.h>
39 #include <drizzled/pthread_globals.h>
40 #include <drizzled/internal/my_sys.h>
41 #include <drizzled/internal/iocache.h>
42 #include <drizzled/plugin/storage_engine.h>
43 #include <drizzled/copy_field.h>
44 #include <drizzled/transaction_services.h>
45 #include <drizzled/filesort.h>
46 #include <drizzled/message.h>
47 #include <drizzled/message/alter_table.pb.h>
48 #include <drizzled/alter_column.h>
49 #include <drizzled/alter_info.h>
50 #include <drizzled/util/test.h>
51 #include <drizzled/open_tables_state.h>
52 #include <drizzled/table/cache.h>
53 #include <drizzled/create_field.h>
54 #include <drizzled/catalog/instance.h>
55 
56 using namespace std;
57 
58 namespace drizzled {
59 
60 extern pid_t current_pid;
61 
62 static int copy_data_between_tables(Session *session,
63  Table *from,Table *to,
64  List<CreateField> &create,
65  bool ignore,
66  uint32_t order_num,
67  Order *order,
68  ha_rows *copied,
69  ha_rows *deleted,
70  message::AlterTable &alter_table_message,
71  bool error_if_not_empty);
72 
73 static bool prepare_alter_table(Session *session,
74  Table *table,
75  HA_CREATE_INFO *create_info,
76  const message::Table &original_proto,
77  message::Table &table_message,
78  message::AlterTable &alter_table_message,
79  AlterInfo *alter_info);
80 
81 static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier);
82 
83 static int apply_online_alter_keys_onoff(Session *session,
84  Table* table,
85  const message::AlterTable::AlterKeysOnOff &op);
86 
87 static int apply_online_rename_table(Session *session,
88  Table *table,
89  plugin::StorageEngine *original_engine,
90  identifier::Table &original_table_identifier,
91  identifier::Table &new_table_identifier,
92  const message::AlterTable::RenameTable &alter_operation);
93 
94 namespace statement {
95 
96 AlterTable::AlterTable(Session *in_session, Table_ident *) :
97  CreateTable(in_session)
98 {
99  set_command(SQLCOM_ALTER_TABLE);
100 }
101 
102 } // namespace statement
103 
105 {
106  TableList *first_table= (TableList *) lex().select_lex.table_list.first;
107  TableList *all_tables= lex().query_tables;
108  assert(first_table == all_tables && first_table != 0);
109  Select_Lex *select_lex= &lex().select_lex;
110 
111  is_engine_set= not createTableMessage().engine().name().empty();
112 
113  if (is_engine_set)
114  {
115  create_info().db_type=
116  plugin::StorageEngine::findByName(session(), createTableMessage().engine().name());
117 
118  if (create_info().db_type == NULL)
119  {
120  my_error(createTableMessage().engine().name(), ER_UNKNOWN_STORAGE_ENGINE, MYF(0));
121 
122  return true;
123  }
124  }
125 
126  /* Must be set in the parser */
127  assert(select_lex->db);
128 
129  /* Chicken/Egg... we need to search for the table, to know if the table exists, so we can build a full identifier from it */
130  message::table::shared_ptr original_table_message;
131  {
132  identifier::Table identifier(session().catalog().identifier(),
133  first_table->getSchemaName(),
134  first_table->getTableName());
135  if (not (original_table_message= plugin::StorageEngine::getTableMessage(session(), identifier)))
136  {
137  my_error(ER_BAD_TABLE_ERROR, identifier);
138  return true;
139  }
140 
141  if (not create_info().db_type)
142  {
143  create_info().db_type=
144  plugin::StorageEngine::findByName(session(), original_table_message->engine().name());
145 
146  if (not create_info().db_type)
147  {
148  my_error(ER_BAD_TABLE_ERROR, identifier);
149  return true;
150  }
151  }
152  }
153 
154  if (not validateCreateTableOption())
155  return true;
156 
157  if (session().inTransaction())
158  {
159  my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
160  return true;
161  }
162 
163  if (session().wait_if_global_read_lock(0, 1))
164  return true;
165 
166  bool res;
167  if (original_table_message->type() == message::Table::STANDARD )
168  {
169  identifier::Table identifier(session().catalog().identifier(),
170  first_table->getSchemaName(),
171  first_table->getTableName());
172  identifier::Table new_identifier(session().catalog().identifier(),
173  select_lex->db ? select_lex->db : first_table->getSchemaName(),
174  lex().name.data() ? lex().name.data() : first_table->getTableName());
175 
176  res= alter_table(&session(),
177  identifier,
178  new_identifier,
179  &create_info(),
180  *original_table_message,
181  createTableMessage(),
182  first_table,
183  &alter_info,
184  select_lex->order_list.size(),
185  (Order *) select_lex->order_list.first,
186  lex().ignore);
187  }
188  else
189  {
190  identifier::Table catch22(session().catalog().identifier(),
191  first_table->getSchemaName(),
192  first_table->getTableName());
193  Table *table= session().open_tables.find_temporary_table(catch22);
194  assert(table);
195  {
196  identifier::Table identifier(session().catalog().identifier(),
197  first_table->getSchemaName(),
198  first_table->getTableName(),
199  table->getMutableShare()->getPath());
200 
201  identifier::Table new_identifier(session().catalog().identifier(),
202  select_lex->db ? select_lex->db : first_table->getSchemaName(),
203  lex().name.data() ? lex().name.data() : first_table->getTableName(),
204  table->getMutableShare()->getPath());
205 
206  res= alter_table(&session(),
207  identifier,
208  new_identifier,
209  &create_info(),
210  *original_table_message,
211  createTableMessage(),
212  first_table,
213  &alter_info,
214  select_lex->order_list.size(),
215  (Order *) select_lex->order_list.first,
216  lex().ignore);
217  }
218  }
219 
220  /*
221  Release the protection against the global read lock and wake
222  everyone, who might want to set a global read lock.
223  */
224  session().startWaitingGlobalReadLock();
225 
226  return res;
227 }
228 
229 
270 static bool prepare_alter_table(Session *session,
271  Table *table,
272  HA_CREATE_INFO *create_info,
273  const message::Table &original_proto,
274  message::Table &table_message,
275  message::AlterTable &alter_table_message,
276  AlterInfo *alter_info)
277 {
278  uint32_t used_fields= create_info->used_fields;
279  vector<string> drop_keys;
280  vector<string> drop_columns;
281  vector<string> drop_fkeys;
282 
283  /* we use drop_(keys|columns|fkey) below to check that we can do all
284  operations we've been asked to do */
285  for (int operationnr= 0; operationnr < alter_table_message.operations_size();
286  operationnr++)
287  {
289  alter_table_message.operations(operationnr);
290 
291  switch (operation.operation())
292  {
293  case message::AlterTable::AlterTableOperation::DROP_KEY:
294  drop_keys.push_back(operation.drop_name());
295  break;
296  case message::AlterTable::AlterTableOperation::DROP_COLUMN:
297  drop_columns.push_back(operation.drop_name());
298  break;
299  case message::AlterTable::AlterTableOperation::DROP_FOREIGN_KEY:
300  drop_fkeys.push_back(operation.drop_name());
301  break;
302  default:
303  break;
304  }
305  }
306 
307  /* Let new create options override the old ones */
308  message::Table::TableOptions *table_options= table_message.mutable_options();
309 
310  if (not (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
311  create_info->default_table_charset= table->getShare()->table_charset;
312 
313  if (not (used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
314  {
315  /* Table has an autoincrement, copy value to new table */
316  table->cursor->info(HA_STATUS_AUTO);
317  create_info->auto_increment_value= table->cursor->stats.auto_increment_value;
318  if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
319  table_options->set_has_user_set_auto_increment_value(false);
320  }
321 
322  table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
323 
324  List<CreateField> new_create_list;
325  List<Key> new_key_list;
326  /* First collect all fields from table which isn't in drop_list */
327  Field *field;
328  for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
329  {
330  /* Check if field should be dropped */
331  vector<string>::iterator it= drop_columns.begin();
332  while (it != drop_columns.end())
333  {
334  if (not system_charset_info->strcasecmp(field->field_name, it->c_str()))
335  {
336  /* Reset auto_increment value if it was dropped */
337  if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
338  not (used_fields & HA_CREATE_USED_AUTO))
339  {
340  create_info->auto_increment_value= 0;
341  create_info->used_fields|= HA_CREATE_USED_AUTO;
342  }
343  break;
344  }
345  it++;
346  }
347 
348  if (it != drop_columns.end())
349  {
350  drop_columns.erase(it);
351  continue;
352  }
353 
354  /* Mark that we will read the field */
355  field->setReadSet();
356 
357  CreateField *def;
358  /* Check if field is changed */
359  List<CreateField>::iterator def_it= alter_info->create_list.begin();
360  while ((def= def_it++))
361  {
362  if (def->change &&
363  ! system_charset_info->strcasecmp(field->field_name, def->change))
364  break;
365  }
366 
367  if (def)
368  {
369  /* Field is changed */
370  def->field= field;
371  if (! def->after)
372  {
373  new_create_list.push_back(def);
374  def_it.remove();
375  }
376  }
377  else
378  {
379  /*
380  This field was not dropped and not changed, add it to the list
381  for the new table.
382  */
383  def= new CreateField(field, field);
384  new_create_list.push_back(def);
385  AlterInfo::alter_list_t::iterator alter(alter_info->alter_list.begin());
386 
387  for (; alter != alter_info->alter_list.end(); alter++)
388  {
389  if (not system_charset_info->strcasecmp(field->field_name, alter->name))
390  break;
391  }
392 
393  if (alter != alter_info->alter_list.end())
394  {
395  def->setDefaultValue(alter->def, NULL);
396 
397  alter_info->alter_list.erase(alter);
398  }
399  }
400  }
401 
402  CreateField *def;
403  List<CreateField>::iterator def_it= alter_info->create_list.begin();
404  while ((def= def_it++)) /* Add new columns */
405  {
406  if (def->change && ! def->field)
407  {
408  my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
409  return true;
410  }
411  /*
412  If we have been given a field which has no default value, and is not null then we need to bail.
413  */
414  if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
415  {
416  alter_info->error_if_not_empty= true;
417  }
418  if (! def->after)
419  {
420  new_create_list.push_back(def);
421  }
422  else if (def->after == first_keyword)
423  {
424  new_create_list.push_front(def);
425  }
426  else
427  {
428  CreateField *find;
429  List<CreateField>::iterator find_it= new_create_list.begin();
430 
431  while ((find= find_it++)) /* Add new columns */
432  {
433  if (not system_charset_info->strcasecmp(def->after, find->field_name))
434  break;
435  }
436 
437  if (not find)
438  {
439  my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
440  return true;
441  }
442 
443  find_it.after(def); /* Put element after this */
444 
445  /*
446  XXX: hack for Bug#28427.
447  If column order has changed, force OFFLINE ALTER Table
448  without querying engine capabilities. If we ever have an
449  engine that supports online ALTER Table CHANGE COLUMN
450  <name> AFTER <name1> (Falcon?), this fix will effectively
451  disable the capability.
452  TODO: detect the situation in compare_tables, behave based
453  on engine capabilities.
454  */
455  if (alter_table_message.build_method() == message::AlterTable::BUILD_ONLINE)
456  {
457  my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
458  return true;
459  }
460  }
461  }
462 
463  if (not alter_info->alter_list.empty())
464  {
465  my_error(ER_BAD_FIELD_ERROR, MYF(0), alter_info->alter_list.front().name, table->getMutableShare()->getTableName());
466  return true;
467  }
468 
469  if (new_create_list.is_empty())
470  {
471  my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS), MYF(0));
472  return true;
473  }
474 
475  /*
476  Collect all keys which isn't in drop list. Add only those
477  for which some fields exists.
478  */
479  KeyInfo *key_info= table->key_info;
480  for (uint32_t i= 0; i < table->getShare()->sizeKeys(); i++, key_info++)
481  {
482  const char *key_name= key_info->name;
483 
484  vector<string>::iterator it= drop_keys.begin();
485  while (it != drop_keys.end())
486  {
487  if (not system_charset_info->strcasecmp(key_name, it->c_str()))
488  break;
489  it++;
490  }
491 
492  if (it != drop_keys.end())
493  {
494  drop_keys.erase(it);
495  continue;
496  }
497 
498  KeyPartInfo *key_part= key_info->key_part;
499  List<Key_part_spec> key_parts;
500  for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
501  {
502  if (not key_part->field)
503  continue; /* Wrong field (from UNIREG) */
504 
505  const char *key_part_name= key_part->field->field_name;
506  CreateField *cfield;
507  List<CreateField>::iterator field_it= new_create_list.begin();
508  while ((cfield= field_it++))
509  {
510  if (cfield->change)
511  {
512  if (not system_charset_info->strcasecmp(key_part_name, cfield->change))
513  break;
514  }
515  else if (not system_charset_info->strcasecmp(key_part_name, cfield->field_name))
516  break;
517  }
518 
519  if (not cfield)
520  continue; /* Field is removed */
521 
522  uint32_t key_part_length= key_part->length;
523  if (cfield->field) /* Not new field */
524  {
525  /*
526  If the field can't have only a part used in a key according to its
527  new type, or should not be used partially according to its
528  previous type, or the field length is less than the key part
529  length, unset the key part length.
530 
531  We also unset the key part length if it is the same as the
532  old field's length, so the whole new field will be used.
533 
534  BLOBs may have cfield->length == 0, which is why we test it before
535  checking whether cfield->length < key_part_length (in chars).
536  */
537  if (! Field::type_can_have_key_part(cfield->field->type()) ||
538  ! Field::type_can_have_key_part(cfield->sql_type) ||
539  (cfield->field->field_length == key_part_length) ||
540  (cfield->length &&
541  (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
542  key_part_length= 0; /* Use whole field */
543  }
544  key_part_length/= key_part->field->charset()->mbmaxlen;
545  key_parts.push_back(new Key_part_spec(str_ref(cfield->field_name), key_part_length));
546  }
547  if (key_parts.size())
548  {
549  KEY_CREATE_INFO key_create_info= default_key_create_info;
550  key_create_info.algorithm= key_info->algorithm;
551 
552  if (key_info->flags & HA_USES_BLOCK_SIZE)
553  key_create_info.block_size= key_info->block_size;
554 
555  if (key_info->flags & HA_USES_COMMENT)
556  key_create_info.comment= key_info->comment;
557 
558  Key::Keytype key_type= key_info->flags & HA_NOSAME
559  ? (is_primary_key(key_name) ? Key::PRIMARY : Key::UNIQUE)
560  : Key::MULTIPLE;
561  new_key_list.push_back(new Key(key_type, str_ref(key_name), &key_create_info, test(key_info->flags & HA_GENERATED_KEY), key_parts));
562  }
563  }
564 
565  /* Copy over existing foreign keys */
566  for (int32_t j= 0; j < original_proto.fk_constraint_size(); j++)
567  {
568  vector<string>::iterator it= drop_fkeys.begin();
569  while (it != drop_fkeys.end())
570  {
571  if (! system_charset_info->strcasecmp(original_proto.fk_constraint(j).name().c_str(), it->c_str()))
572  {
573  break;
574  }
575  it++;
576  }
577 
578  if (it != drop_fkeys.end())
579  {
580  drop_fkeys.erase(it);
581  continue;
582  }
583 
584  message::Table::ForeignKeyConstraint *pfkey= table_message.add_fk_constraint();
585  *pfkey= original_proto.fk_constraint(j);
586  }
587 
588  {
589  Key *key;
590  List<Key>::iterator key_it(alter_info->key_list.begin());
591  while ((key= key_it++)) /* Add new keys */
592  {
593  if (key->type == Key::FOREIGN_KEY)
594  {
595  if (((Foreign_key *)key)->validate(new_create_list))
596  {
597  return true;
598  }
599 
600  Foreign_key *fkey= (Foreign_key*)key;
601  add_foreign_key_to_table_message(&table_message,
602  fkey->name.data(),
603  fkey->columns,
604  fkey->ref_table,
605  fkey->ref_columns,
606  fkey->delete_opt,
607  fkey->update_opt,
608  fkey->match_opt);
609  }
610 
611  if (key->type != Key::FOREIGN_KEY)
612  new_key_list.push_back(key);
613 
614  if (key->name.data() && is_primary_key(key->name.data()))
615  {
616  my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.data());
617  return true;
618  }
619  }
620  }
621 
622  /* Fix names of foreign keys being added */
623  for (int j= 0; j < table_message.fk_constraint_size(); j++)
624  {
625  if (! table_message.fk_constraint(j).has_name())
626  {
627  std::string name(table->getMutableShare()->getTableName());
628  char number[20];
629 
630  name.append("_ibfk_");
631  snprintf(number, sizeof(number), "%d", j+1);
632  name.append(number);
633 
634  message::Table::ForeignKeyConstraint *pfkey= table_message.mutable_fk_constraint(j);
635  pfkey->set_name(name);
636  }
637  }
638 
639  if (drop_keys.size())
640  {
641  my_error(ER_CANT_DROP_FIELD_OR_KEY,
642  MYF(0),
643  drop_keys.front().c_str());
644  return true;
645  }
646 
647  if (drop_columns.size())
648  {
649  my_error(ER_CANT_DROP_FIELD_OR_KEY,
650  MYF(0),
651  drop_columns.front().c_str());
652  return true;
653  }
654 
655  if (drop_fkeys.size())
656  {
657  my_error(ER_CANT_DROP_FIELD_OR_KEY,
658  MYF(0),
659  drop_fkeys.front().c_str());
660  return true;
661  }
662 
663  if (not alter_info->alter_list.empty())
664  {
665  my_error(ER_CANT_DROP_FIELD_OR_KEY,
666  MYF(0),
667  alter_info->alter_list.front().name);
668  return true;
669  }
670 
671  if (not table_message.options().has_comment()
672  && table->getMutableShare()->hasComment())
673  {
674  table_options->set_comment(table->getMutableShare()->getComment());
675  }
676 
677  if (table->getShare()->getType())
678  {
679  table_message.set_type(message::Table::TEMPORARY);
680  }
681 
682  table_message.set_creation_timestamp(table->getShare()->getTableMessage()->creation_timestamp());
683  table_message.set_version(table->getShare()->getTableMessage()->version());
684  table_message.set_uuid(table->getShare()->getTableMessage()->uuid());
685 
686  alter_info->create_list.swap(new_create_list);
687  alter_info->key_list.swap(new_key_list);
688 
689  size_t num_engine_options= table_message.engine().options_size();
690  size_t original_num_engine_options= original_proto.engine().options_size();
691  for (size_t x= 0; x < original_num_engine_options; ++x)
692  {
693  bool found= false;
694 
695  for (size_t y= 0; y < num_engine_options; ++y)
696  {
697  found= not table_message.engine().options(y).name().compare(original_proto.engine().options(x).name());
698 
699  if (found)
700  break;
701  }
702 
703  if (not found)
704  {
705  message::Engine::Option *opt= table_message.mutable_engine()->add_options();
706 
707  opt->set_name(original_proto.engine().options(x).name());
708  opt->set_state(original_proto.engine().options(x).state());
709  }
710  }
711 
712  drizzled::message::update(table_message);
713 
714  return false;
715 }
716 
717 /* table_list should contain just one table */
718 static int discard_or_import_tablespace(Session *session,
719  TableList *table_list,
720  bool discard)
721 {
722  /*
723  Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
724  ALTER Table
725  */
726  session->set_proc_info("discard_or_import_tablespace");
727 
728  /*
729  We set this flag so that ha_innobase::open and ::external_lock() do
730  not complain when we lock the table
731  */
732  session->setDoingTablespaceOperation(true);
733  Table* table= session->openTableLock(table_list, TL_WRITE);
734  if (not table)
735  {
736  session->setDoingTablespaceOperation(false);
737  return -1;
738  }
739 
740  int error;
741  do {
742  error= table->cursor->ha_discard_or_import_tablespace(discard);
743 
744  session->set_proc_info("end");
745 
746  if (error)
747  break;
748 
749  /* The ALTER Table is always in its own transaction */
750  error= TransactionServices::autocommitOrRollback(*session, false);
751  if (not session->endActiveTransaction())
752  error= 1;
753 
754  if (error)
755  break;
756 
758  *session->getQueryString(),
759  *session->schema());
760 
761  } while(0);
762 
763  (void) TransactionServices::autocommitOrRollback(*session, error);
764  session->setDoingTablespaceOperation(false);
765 
766  if (error == 0)
767  {
768  session->my_ok();
769  return 0;
770  }
771 
772  table->print_error(error, MYF(0));
773 
774  return -1;
775 }
776 
791 static bool alter_table_manage_keys(Session *session,
792  Table *table, int indexes_were_disabled,
793  const message::AlterTable &alter_table_message)
794 {
795  int error= 0;
796  if (alter_table_message.has_alter_keys_onoff()
797  && alter_table_message.alter_keys_onoff().enable())
798  {
799  error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
800  }
801 
802  if ((! alter_table_message.has_alter_keys_onoff() && indexes_were_disabled)
803  || (alter_table_message.has_alter_keys_onoff()
804  && ! alter_table_message.alter_keys_onoff().enable()))
805  {
806  error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
807  }
808 
809  if (error == HA_ERR_WRONG_COMMAND)
810  {
811  push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
812  ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
813  table->getMutableShare()->getTableName());
814  error= 0;
815  }
816  else if (error)
817  {
818  table->print_error(error, MYF(0));
819  }
820 
821  return(error);
822 }
823 
824 static bool lockTableIfDifferent(Session &session,
825  identifier::Table &original_table_identifier,
826  identifier::Table &new_table_identifier,
827  Table *name_lock)
828 {
829  /* Check that we are not trying to rename to an existing table */
830  if (not (original_table_identifier == new_table_identifier))
831  {
832  if (original_table_identifier.isTmp())
833  {
834  if (session.open_tables.find_temporary_table(new_table_identifier))
835  {
836  my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
837  return false;
838  }
839  }
840  else
841  {
842  name_lock= session.lock_table_name_if_not_cached(new_table_identifier);
843  if (not name_lock)
844  {
845  my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
846  return false;
847  }
848 
849  if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
850  {
851  /* Table will be closed by Session::executeCommand() */
852  my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
853 
854  {
855  boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
856  session.unlink_open_table(name_lock);
857  }
858 
859  return false;
860  }
861  }
862  }
863 
864  return true;
865 }
866 
909 static bool internal_alter_table(Session *session,
910  Table *table,
911  identifier::Table &original_table_identifier,
912  identifier::Table &new_table_identifier,
913  HA_CREATE_INFO *create_info,
914  const message::Table &original_proto,
915  message::Table &create_proto,
916  message::AlterTable &alter_table_message,
917  TableList *table_list,
918  AlterInfo *alter_info,
919  uint32_t order_num,
920  Order *order,
921  bool ignore)
922 {
923  int error= 0;
924  char tmp_name[80];
925  char old_name[32];
926  ha_rows copied= 0;
927  ha_rows deleted= 0;
928 
929  if (not original_table_identifier.isValid())
930  return true;
931 
932  if (not new_table_identifier.isValid())
933  return true;
934 
935  session->set_proc_info("init");
936 
937  table->use_all_columns();
938 
939  plugin::StorageEngine *new_engine;
940  plugin::StorageEngine *original_engine;
941 
942  original_engine= table->getMutableShare()->getEngine();
943 
944  if (not create_info->db_type)
945  {
946  create_info->db_type= original_engine;
947  }
948  new_engine= create_info->db_type;
949 
950 
951  create_proto.set_schema(new_table_identifier.getSchemaName());
952  create_proto.set_type(new_table_identifier.getType());
953 
958  if (new_engine != original_engine &&
959  not table->cursor->can_switch_engines())
960  {
961  assert(0);
962  my_error(ER_ROW_IS_REFERENCED, MYF(0));
963 
964  return true;
965  }
966 
967  if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
968  new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
969  {
970  my_error(ER_ILLEGAL_HA, new_table_identifier);
971 
972  return true;
973  }
974 
975  session->set_proc_info("setup");
976 
977  /* First we try for operations that do not require a copying
978  ALTER TABLE.
979 
980  In future there should be more operations, currently it's just a couple.
981  */
982 
983  if ((alter_table_message.has_rename()
984  || alter_table_message.has_alter_keys_onoff())
985  && alter_table_message.operations_size() == 0)
986  {
987  /*
988  * test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
989  */
990  bitset<32> tmp;
991 
992  tmp.set();
993  tmp.reset(ALTER_RENAME);
994  tmp.reset(ALTER_KEYS_ONOFF);
995  tmp&= alter_info->flags;
996 
997  if((not (tmp.any()) && not table->getShare()->getType())) // no need to touch frm
998  {
999  if (alter_table_message.has_alter_keys_onoff())
1000  {
1001  error= apply_online_alter_keys_onoff(session, table,
1002  alter_table_message.alter_keys_onoff());
1003 
1004  if (error == HA_ERR_WRONG_COMMAND)
1005  {
1006  error= EE_OK;
1007  push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1008  ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1009  table->getAlias());
1010  }
1011  }
1012 
1013  if (alter_table_message.has_rename())
1014  {
1015  error= apply_online_rename_table(session,
1016  table,
1017  original_engine,
1018  original_table_identifier,
1019  new_table_identifier,
1020  alter_table_message.rename());
1021 
1022  if (error == HA_ERR_WRONG_COMMAND)
1023  {
1024  error= EE_OK;
1025  push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1026  ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1027  table->getAlias());
1028  }
1029  }
1030 
1031  if (not error)
1032  {
1033  TransactionServices::allocateNewTransactionId();
1035  *session->getQueryString(),
1036  *session->schema());
1037  session->my_ok();
1038  }
1039  else if (error > EE_OK) // If we have already set the error, we pass along -1
1040  {
1041  table->print_error(error, MYF(0));
1042  }
1043 
1044  table_list->table= NULL;
1045 
1046  return error;
1047  }
1048  }
1049 
1050  if (alter_table_message.build_method() == message::AlterTable::BUILD_ONLINE)
1051  {
1052  my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
1053  return true;
1054  }
1055 
1056  /* We have to do full alter table. */
1057  new_engine= create_info->db_type;
1058 
1059  if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_table_message, alter_info))
1060  {
1061  return true;
1062  }
1063 
1064  set_table_default_charset(session->catalog().identifier(), create_info, new_table_identifier.getSchemaName().c_str());
1065 
1066  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1067 
1068  /* Create a temporary table with the new format */
1074  identifier::Table new_table_as_temporary(session->catalog().identifier(),
1075  original_table_identifier.getSchemaName(),
1076  tmp_name,
1077  create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1078  message::Table::TEMPORARY);
1079 
1080  /*
1081  Create a table with a temporary name.
1082  We don't log the statement, it will be logged later.
1083  */
1084  create_proto.set_name(new_table_as_temporary.getTableName());
1085  create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1086 
1087  error= create_table(session,
1088  new_table_as_temporary,
1089  create_info, create_proto, alter_info, true, 0, false);
1090 
1091  if (error != 0)
1092  {
1093  return true;
1094  }
1095 
1096  /* Open the table so we need to copy the data to it. */
1097  Table *new_table= open_alter_table(session, table, new_table_as_temporary);
1098 
1099 
1100  if (not new_table)
1101  {
1102  plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1103  return true;
1104  }
1105 
1106  /* Copy the data if necessary. */
1107  {
1108  /* We must not ignore bad input! */
1109  session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; // calc cuted fields
1110  session->cuted_fields= 0L;
1111  session->set_proc_info("copy to tmp table");
1112  copied= deleted= 0;
1113 
1114  /* We don't want update TIMESTAMP fields during ALTER Table. */
1115  new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1116  new_table->next_number_field= new_table->found_next_number_field;
1117  error= copy_data_between_tables(session,
1118  table,
1119  new_table,
1120  alter_info->create_list,
1121  ignore,
1122  order_num,
1123  order,
1124  &copied,
1125  &deleted,
1126  alter_table_message,
1127  alter_info->error_if_not_empty);
1128 
1129  /* We must not ignore bad input! */
1130  assert(session->count_cuted_fields == CHECK_FIELD_ERROR_FOR_NULL);
1131  }
1132 
1133  /* Now we need to resolve what just happened with the data copy. */
1134 
1135  if (error)
1136  {
1137 
1138  /*
1139  No default value was provided for new fields.
1140  */
1141  if (alter_info->error_if_not_empty && session->row_count)
1142  {
1143  my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
1144  }
1145 
1146  if (original_table_identifier.isTmp())
1147  {
1148  if (new_table)
1149  {
1150  /* close_temporary_table() frees the new_table pointer. */
1151  session->open_tables.close_temporary_table(new_table);
1152  }
1153  else
1154  {
1155  plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1156  }
1157 
1158  return true;
1159  }
1160  else
1161  {
1162  if (new_table)
1163  {
1164  /*
1165  Close the intermediate table that will be the new table.
1166  Note that MERGE tables do not have their children attached here.
1167  */
1168  new_table->intern_close_table();
1169  if (new_table->hasShare())
1170  {
1171  delete new_table->getMutableShare();
1172  }
1173 
1174  delete new_table;
1175  }
1176 
1177  boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
1178 
1179  plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1180 
1181  return true;
1182  }
1183  }
1184  // Temporary table and success
1185  else if (original_table_identifier.isTmp())
1186  {
1187  /* Close lock if this is a transactional table */
1188  if (session->open_tables.lock)
1189  {
1190  session->unlockTables(session->open_tables.lock);
1191  session->open_tables.lock= 0;
1192  }
1193 
1194  /* Remove link to old table and rename the new one */
1195  session->open_tables.close_temporary_table(table);
1196 
1197  /* Should pass the 'new_name' as we store table name in the cache */
1198  new_table->getMutableShare()->setIdentifier(new_table_identifier);
1199 
1200  new_table_identifier.setPath(new_table_as_temporary.getPath());
1201 
1202  if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1203  {
1204  return true;
1205  }
1206  }
1207  // Normal table success
1208  else
1209  {
1210  if (new_table)
1211  {
1212  /*
1213  Close the intermediate table that will be the new table.
1214  Note that MERGE tables do not have their children attached here.
1215  */
1216  new_table->intern_close_table();
1217 
1218  if (new_table->hasShare())
1219  {
1220  delete new_table->getMutableShare();
1221  }
1222 
1223  delete new_table;
1224  }
1225 
1226  {
1227  boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* ALTER TABLE */
1228  /*
1229  Data is copied. Now we:
1230  1) Wait until all other threads close old version of table.
1231  2) Close instances of table open by this thread and replace them
1232  with exclusive name-locks.
1233  3) Rename the old table to a temp name, rename the new one to the
1234  old name.
1235  4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1236  we reopen new version of table.
1237  5) Write statement to the binary log.
1238  6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1239  remove name-locks from list of open tables and table cache.
1240  7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1241  call to remove name-locks from table cache and list of open table.
1242  */
1243 
1244  session->set_proc_info("rename result table");
1245 
1246  snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1247 
1248  files_charset_info->casedn_str(old_name);
1249 
1250  wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1251  session->close_data_files_and_morph_locks(original_table_identifier);
1252 
1253  assert(not error);
1254 
1255  /*
1256  This leads to the storage engine (SE) not being notified for renames in
1257  rename_table(), because we just juggle with the FRM and nothing
1258  more. If we have an intermediate table, then we notify the SE that
1259  it should become the actual table. Later, we will recycle the old table.
1260  However, in case of ALTER Table RENAME there might be no intermediate
1261  table. This is when the old and new tables are compatible, according to
1262  compare_table(). Then, we need one additional call to
1263  */
1264  identifier::Table original_table_to_drop(session->catalog().identifier(),
1265  original_table_identifier.getSchemaName(),
1266  old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1267  message::Table::TEMPORARY);
1268 
1269  drizzled::error_t rename_error= EE_OK;
1270  if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1271  {
1272  error= ER_ERROR_ON_RENAME;
1273  plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1274  }
1275  else
1276  {
1277  if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1278  {
1279  /* Try to get everything back. */
1280  rename_error= ER_ERROR_ON_RENAME;
1281 
1282  plugin::StorageEngine::dropTable(*session, new_table_identifier);
1283 
1284  plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1285 
1286  rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1287  }
1288  else
1289  {
1290  plugin::StorageEngine::dropTable(*session, original_table_to_drop);
1291  }
1292  }
1293 
1294  if (rename_error)
1295  {
1296  /*
1297  An error happened while we were holding exclusive name-lock on table
1298  being altered. To be safe under LOCK TABLES we should remove placeholders
1299  from list of open tables list and table cache.
1300  */
1301  session->unlink_open_table(table);
1302 
1303  return true;
1304  }
1305  }
1306 
1307  session->set_proc_info("end");
1308 
1310  *session->getQueryString(),
1311  *session->schema());
1312  table_list->table= NULL;
1313  }
1314 
1315  /*
1316  * Field::store() may have called my_error(). If this is
1317  * the case, we must not send an ok packet, since
1318  * Diagnostics_area::is_set() will fail an assert.
1319  */
1320  if (session->is_error())
1321  {
1322  /* my_error() was called. Return true (which means error...) */
1323  return true;
1324  }
1325 
1326  snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1327  (ulong) (copied + deleted), (ulong) deleted,
1328  (ulong) session->cuted_fields);
1329  session->my_ok(copied + deleted, 0, 0L, tmp_name);
1330  return false;
1331 }
1332 
1333 static int apply_online_alter_keys_onoff(Session *session,
1334  Table* table,
1335  const message::AlterTable::AlterKeysOnOff &op)
1336 {
1337  int error= 0;
1338 
1339  if (op.enable())
1340  {
1341  /*
1342  wait_while_table_is_used() ensures that table being altered is
1343  opened only by this thread and that Table::TableShare::version
1344  of Table object corresponding to this table is 0.
1345  The latter guarantees that no DML statement will open this table
1346  until ALTER Table finishes (i.e. until close_thread_tables())
1347  while the fact that the table is still open gives us protection
1348  from concurrent DDL statements.
1349  */
1350  {
1351  boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* DDL wait for/blocker */
1352  wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1353  }
1354  error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1355 
1356  /* COND_refresh will be signaled in close_thread_tables() */
1357  }
1358  else
1359  {
1360  {
1361  boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* DDL wait for/blocker */
1362  wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1363  }
1364  error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1365 
1366  /* COND_refresh will be signaled in close_thread_tables() */
1367  }
1368 
1369  return error;
1370 }
1371 
1372 static int apply_online_rename_table(Session *session,
1373  Table *table,
1374  plugin::StorageEngine *original_engine,
1375  identifier::Table &original_table_identifier,
1376  identifier::Table &new_table_identifier,
1377  const message::AlterTable::RenameTable &alter_operation)
1378 {
1379  int error= 0;
1380 
1381  boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* Lock to remove all instances of table from table cache before ALTER */
1382  /*
1383  Unlike to the above case close_cached_table() below will remove ALL
1384  instances of Table from table cache (it will also remove table lock
1385  held by this thread).
1386  */
1387 
1388  if (not (original_table_identifier == new_table_identifier))
1389  {
1390  assert(alter_operation.to_name() == new_table_identifier.getTableName());
1391  assert(alter_operation.to_schema() == new_table_identifier.getSchemaName());
1392 
1393  session->set_proc_info("rename");
1394  /*
1395  Then do a 'simple' rename of the table. First we need to close all
1396  instances of 'source' table.
1397  */
1398  session->close_cached_table(table);
1399  /*
1400  Then, we want check once again that target table does not exist.
1401  Actually the order of these two steps does not matter since
1402  earlier we took name-lock on the target table, so we do them
1403  in this particular order only to be consistent with 5.0, in which
1404  we don't take this name-lock and where this order really matters.
1405  @todo Investigate if we need this access() check at all.
1406  */
1407  if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1408  {
1409  my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
1410  error= -1;
1411  }
1412  else
1413  {
1414  if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1415  {
1416  error= -1;
1417  }
1418  }
1419  }
1420  return error;
1421 }
1422 
1423 bool alter_table(Session *session,
1424  identifier::Table &original_table_identifier,
1425  identifier::Table &new_table_identifier,
1426  HA_CREATE_INFO *create_info,
1427  const message::Table &original_proto,
1428  message::Table &create_proto,
1429  TableList *table_list,
1430  AlterInfo *alter_info,
1431  uint32_t order_num,
1432  Order *order,
1433  bool ignore)
1434 {
1435  bool error;
1436  Table *table;
1437  message::AlterTable *alter_table_message= session->lex().alter_table();
1438 
1439  alter_table_message->set_catalog(original_table_identifier.getCatalogName());
1440  alter_table_message->set_schema(original_table_identifier.getSchemaName());
1441  alter_table_message->set_name(original_table_identifier.getTableName());
1442 
1443  if (alter_table_message->operations_size()
1444  && (alter_table_message->operations(0).operation()
1445  == message::AlterTable::AlterTableOperation::DISCARD_TABLESPACE
1446  || alter_table_message->operations(0).operation()
1447  == message::AlterTable::AlterTableOperation::IMPORT_TABLESPACE))
1448  {
1449  bool discard= (alter_table_message->operations(0).operation() ==
1450  message::AlterTable::AlterTableOperation::DISCARD_TABLESPACE);
1451  /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1452  return discard_or_import_tablespace(session, table_list, discard);
1453  }
1454 
1455  session->set_proc_info("init");
1456 
1457  if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
1458  return true;
1459 
1460  session->set_proc_info("gained write lock on table");
1461 
1462  /*
1463  Check that we are not trying to rename to an existing table,
1464  if one existed we get a lock, if we can't we error.
1465  */
1466  {
1467  Table *name_lock= NULL;
1468 
1469  if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
1470  {
1471  return true;
1472  }
1473 
1474  error= internal_alter_table(session,
1475  table,
1476  original_table_identifier,
1477  new_table_identifier,
1478  create_info,
1479  original_proto,
1480  create_proto,
1481  *alter_table_message,
1482  table_list,
1483  alter_info,
1484  order_num,
1485  order,
1486  ignore);
1487 
1488  if (name_lock)
1489  {
1490  boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
1491  session->unlink_open_table(name_lock);
1492  }
1493  }
1494 
1495  return error;
1496 }
1497 /* alter_table */
1498 
1499 static int
1500 copy_data_between_tables(Session *session,
1501  Table *from, Table *to,
1502  List<CreateField> &create,
1503  bool ignore,
1504  uint32_t order_num, Order *order,
1505  ha_rows *copied,
1506  ha_rows *deleted,
1507  message::AlterTable &alter_table_message,
1508  bool error_if_not_empty)
1509 {
1510  int error= 0;
1511  CopyField *copy,*copy_end;
1512  ulong found_count,delete_count;
1513  uint32_t length= 0;
1514  SortField *sortorder;
1515  ReadRecord info;
1516  TableList tables;
1517  List<Item> fields;
1518  List<Item> all_fields;
1519  ha_rows examined_rows;
1520  bool auto_increment_field_copied= 0;
1521  uint64_t prev_insert_id;
1522 
1523  /*
1524  Turn off recovery logging since rollback of an alter table is to
1525  delete the new table so there is no need to log the changes to it.
1526 
1527  This needs to be done before external_lock
1528  */
1529 
1530  /*
1531  * LP Bug #552420
1532  *
1533  * Since open_temporary_table() doesn't invoke lockTables(), we
1534  * don't get the usual automatic call to StorageEngine::startStatement(), so
1535  * we manually call it here...
1536  */
1537  to->getMutableShare()->getEngine()->startStatement(session);
1538 
1539  copy= new CopyField[to->getShare()->sizeFields()];
1540 
1541  if (to->cursor->ha_external_lock(session, F_WRLCK))
1542  return -1;
1543 
1544  /* We need external lock before we can disable/enable keys */
1545  alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(),
1546  alter_table_message);
1547 
1548  /* We can abort alter table for any table type */
1549  session->setAbortOnWarning(not ignore);
1550 
1551  from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1552  to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1553 
1554  List<CreateField>::iterator it(create.begin());
1555  copy_end= copy;
1556  for (Field **ptr= to->getFields(); *ptr ; ptr++)
1557  {
1558  CreateField* def=it++;
1559  if (def->field)
1560  {
1561  if (*ptr == to->next_number_field)
1562  auto_increment_field_copied= true;
1563 
1564  (copy_end++)->set(*ptr,def->field,0);
1565  }
1566 
1567  }
1568 
1569  found_count=delete_count=0;
1570 
1571  do
1572  {
1573  if (order)
1574  {
1575  if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1576  {
1577  char warn_buff[DRIZZLE_ERRMSG_SIZE];
1578  snprintf(warn_buff, sizeof(warn_buff),
1579  _("order_st BY ignored because there is a user-defined clustered "
1580  "index in the table '%-.192s'"),
1581  from->getMutableShare()->getTableName());
1582  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1583  warn_buff);
1584  }
1585  else
1586  {
1587  FileSort filesort(*session);
1588  from->sort.io_cache= new internal::io_cache_st;
1589 
1590  tables.table= from;
1591  tables.setTableName(from->getMutableShare()->getTableName());
1592  tables.alias= tables.getTableName();
1593  tables.setSchemaName(from->getMutableShare()->getSchemaName());
1594  error= 1;
1595 
1596  session->lex().select_lex.setup_ref_array(session, order_num);
1597  if (setup_order(session, session->lex().select_lex.ref_pointer_array, &tables, fields, all_fields, order))
1598  break;
1599  sortorder= make_unireg_sortorder(order, &length, NULL);
1600  if ((from->sort.found_records= filesort.run(from, sortorder, length, (optimizer::SqlSelect *) 0, HA_POS_ERROR, 1, examined_rows)) == HA_POS_ERROR)
1601  break;
1602  }
1603  }
1604 
1605  /* Tell handler that we have values for all columns in the to table */
1606  to->use_all_columns();
1607 
1608  error= info.init_read_record(session, from, NULL, 1, true);
1609  if (error)
1610  {
1611  to->print_error(errno, MYF(0));
1612 
1613  break;
1614  }
1615 
1616  if (ignore)
1617  {
1618  to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1619  }
1620 
1621  session->row_count= 0;
1622  to->restoreRecordAsDefault(); // Create empty record
1623  while (not (error=info.read_record(&info)))
1624  {
1625  if (session->getKilled())
1626  {
1627  session->send_kill_message();
1628  error= 1;
1629  break;
1630  }
1631  session->row_count++;
1632  /* Return error if source table isn't empty. */
1633  if (error_if_not_empty)
1634  {
1635  error= 1;
1636  break;
1637  }
1638  if (to->next_number_field)
1639  {
1640  if (auto_increment_field_copied)
1641  to->auto_increment_field_not_null= true;
1642  else
1643  to->next_number_field->reset();
1644  }
1645 
1646  for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
1647  {
1648  if (not copy->to_field->hasDefault() and copy->from_null_ptr and *copy->from_null_ptr & copy->from_bit)
1649  {
1650  copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1651  ER_WARN_DATA_TRUNCATED, 1);
1652  copy->to_field->reset();
1653  error= 1;
1654  break;
1655  }
1656 
1657  copy_ptr->do_copy(copy_ptr);
1658  }
1659 
1660  if (error)
1661  {
1662  break;
1663  }
1664 
1665  prev_insert_id= to->cursor->next_insert_id;
1666  error= to->cursor->insertRecord(to->record[0]);
1667  to->auto_increment_field_not_null= false;
1668 
1669  if (error)
1670  {
1671  if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1672  {
1673  to->print_error(error, MYF(0));
1674  break;
1675  }
1676  to->cursor->restore_auto_increment(prev_insert_id);
1677  delete_count++;
1678  }
1679  else
1680  {
1681  found_count++;
1682  }
1683  }
1684 
1685  info.end_read_record();
1686  from->free_io_cache();
1687  delete[] copy;
1688 
1689  if (to->cursor->ha_end_bulk_insert() && error <= 0)
1690  {
1691  to->print_error(errno, MYF(0));
1692  error= 1;
1693  }
1694  to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1695 
1696  /*
1697  Ensure that the new table is saved properly to disk so that we
1698  can do a rename
1699  */
1700  if (TransactionServices::autocommitOrRollback(*session, false))
1701  error= 1;
1702 
1703  if (not session->endActiveTransaction())
1704  error= 1;
1705 
1706  } while (0);
1707 
1708  session->setAbortOnWarning(false);
1709  from->free_io_cache();
1710  *copied= found_count;
1711  *deleted=delete_count;
1712  to->cursor->ha_release_auto_increment();
1713 
1714  if (to->cursor->ha_external_lock(session, F_UNLCK))
1715  {
1716  error= 1;
1717  }
1718 
1719  return error > 0 ? -1 : 0;
1720 }
1721 
1722 static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
1723 {
1724  /* Open the table so we need to copy the data to it. */
1725  if (table->getShare()->getType())
1726  {
1727  TableList tbl;
1728  tbl.setSchemaName(identifier.getSchemaName().c_str());
1729  tbl.alias= identifier.getTableName().c_str();
1730  tbl.setTableName(identifier.getTableName().c_str());
1731 
1732  /* Table is in session->temporary_tables */
1733  return session->openTable(&tbl, NULL, DRIZZLE_LOCK_IGNORE_FLUSH);
1734  }
1735  else
1736  {
1737  /* Open our intermediate table */
1738  return session->open_temporary_table(identifier, false);
1739  }
1740 }
1741 
1742 } /* namespace drizzled */
void my_ok(ha_rows affected_rows=0, ha_rows found_rows_arg=0, uint64_t passed_id=0, const char *message=NULL)
Definition: session.cc:1877
uint32_t row_count
Definition: session.h:447
void set_proc_info(const char *info)
Definition: session.h:609
ha_rows cuted_fields
Definition: session.h:408
static void rawStatement(Session &, const std::string &query, const std::string &schema)
static bool internal_alter_table(Session *session, Table *table, identifier::Table &original_table_identifier, identifier::Table &new_table_identifier, HA_CREATE_INFO *create_info, const message::Table &original_proto, message::Table &create_proto, message::AlterTable &alter_table_message, TableList *table_list, AlterInfo *alter_info, uint32_t order_num, Order *order, bool ignore)
Definition: alter_table.cc:909
#define TMP_FILE_PREFIX
Definition: definitions.h:210
TODO: Rename this file - func.h is stupid.
void close_data_files_and_morph_locks(const identifier::Table &)
Definition: sql_base.cc:1125
Table * table
opened table
Definition: table_list.h:145
Field * found_next_number_field
Definition: table.h:143
virtual bool can_switch_engines(void)
Definition: cursor.h:433
uint64_t prev_insert_id(uint64_t nr, drizzle_system_variables *variables)
Definition: cursor.cc:341
void unlink_open_table(Table *find)
Definition: sql_base.cc:591
static bool prepare_alter_table(Session *session, Table *table, HA_CREATE_INFO *create_info, const message::Table &original_proto, message::Table &table_message, message::AlterTable &alter_table_message, AlterInfo *alter_info)
Definition: alter_table.cc:270
const char * field_name
Definition: create_field.h:35
KeyInfo * key_info
Definition: table.h:141
int setup_order(Session *session, Item **ref_pointer_array, TableList *tables, List< Item > &fields, List< Item > &all_fields, Order *order)
Definition: sql_select.cc:5908
Cursor * cursor
Definition: table.h:68
int ha_disable_indexes(uint32_t mode)
Definition: cursor.cc:694
static bool doesTableExist(Session &session, const drizzled::identifier::Table &identifier, bool include_temporary_tables=true)
static bool type_can_have_key_part(enum_field_types)
Definition: field.cc:859
static bool alter_table_manage_keys(Session *session, Table *table, int indexes_were_disabled, const message::AlterTable &alter_table_message)
Definition: alter_table.cc:791
const char * after
Definition: create_field.h:37
const char * change
Definition: create_field.h:36
int ha_enable_indexes(uint32_t mode)
Definition: cursor.cc:709
const char * field_name
Definition: field.h:102
static int autocommitOrRollback(Session &, int error)
bool is_error() const
Definition: session.cc:1871