Drizzled Public API Documentation

alter_table.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <fcntl.h>
00024 
00025 #include <sstream>
00026 
00027 #include <drizzled/show.h>
00028 #include <drizzled/lock.h>
00029 #include <drizzled/session.h>
00030 #include <drizzled/statement/alter_table.h>
00031 #include <drizzled/charset.h>
00032 #include <drizzled/gettext.h>
00033 #include <drizzled/data_home.h>
00034 #include <drizzled/sql_table.h>
00035 #include <drizzled/table_proto.h>
00036 #include <drizzled/optimizer/range.h>
00037 #include <drizzled/time_functions.h>
00038 #include <drizzled/records.h>
00039 #include <drizzled/pthread_globals.h>
00040 #include <drizzled/internal/my_sys.h>
00041 #include <drizzled/internal/iocache.h>
00042 #include <drizzled/plugin/storage_engine.h>
00043 #include <drizzled/copy_field.h>
00044 #include <drizzled/transaction_services.h>
00045 #include <drizzled/filesort.h>
00046 #include <drizzled/message.h>
00047 #include <drizzled/message/alter_table.pb.h>
00048 #include <drizzled/alter_column.h>
00049 #include <drizzled/alter_info.h>
00050 #include <drizzled/util/test.h>
00051 #include <drizzled/open_tables_state.h>
00052 #include <drizzled/table/cache.h>
00053 #include <drizzled/create_field.h>
00054 
00055 using namespace std;
00056 
00057 namespace drizzled {
00058 
00059 extern pid_t current_pid;
00060 
00061 static int copy_data_between_tables(Session *session,
00062                                     Table *from,Table *to,
00063                                     List<CreateField> &create,
00064                                     bool ignore,
00065                                     uint32_t order_num,
00066                                     Order *order,
00067                                     ha_rows *copied,
00068                                     ha_rows *deleted,
00069                                     message::AlterTable &alter_table_message,
00070                                     bool error_if_not_empty);
00071 
00072 static bool prepare_alter_table(Session *session,
00073                                 Table *table,
00074                                 HA_CREATE_INFO *create_info,
00075                                 const message::Table &original_proto,
00076                                 message::Table &table_message,
00077                                 message::AlterTable &alter_table_message,
00078                                 AlterInfo *alter_info);
00079 
00080 static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier);
00081 
00082 static int apply_online_alter_keys_onoff(Session *session,
00083                                          Table* table,
00084                                          const message::AlterTable::AlterKeysOnOff &op);
00085 
00086 static int apply_online_rename_table(Session *session,
00087                                      Table *table,
00088                                      plugin::StorageEngine *original_engine,
00089                                      identifier::Table &original_table_identifier,
00090                                      identifier::Table &new_table_identifier,
00091                                      const message::AlterTable::RenameTable &alter_operation);
00092 
00093 namespace statement {
00094 
00095 AlterTable::AlterTable(Session *in_session, Table_ident *) :
00096   CreateTable(in_session)
00097 {
00098   set_command(SQLCOM_ALTER_TABLE);
00099 }
00100 
00101 } // namespace statement
00102 
00103 bool statement::AlterTable::execute()
00104 {
00105   TableList *first_table= (TableList *) lex().select_lex.table_list.first;
00106   TableList *all_tables= lex().query_tables;
00107   assert(first_table == all_tables && first_table != 0);
00108   Select_Lex *select_lex= &lex().select_lex;
00109 
00110   is_engine_set= not createTableMessage().engine().name().empty();
00111 
00112   if (is_engine_set)
00113   {
00114     create_info().db_type=
00115       plugin::StorageEngine::findByName(session(), createTableMessage().engine().name());
00116 
00117     if (create_info().db_type == NULL)
00118     {
00119       my_error(createTableMessage().engine().name(), ER_UNKNOWN_STORAGE_ENGINE, MYF(0));
00120 
00121       return true;
00122     }
00123   }
00124 
00125   /* Must be set in the parser */
00126   assert(select_lex->db);
00127 
00128   /* Chicken/Egg... we need to search for the table, to know if the table exists, so we can build a full identifier from it */
00129   message::table::shared_ptr original_table_message;
00130   {
00131     identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
00132     if (not (original_table_message= plugin::StorageEngine::getTableMessage(session(), identifier)))
00133     {
00134       my_error(ER_BAD_TABLE_ERROR, identifier);
00135       return true;
00136     }
00137 
00138     if (not  create_info().db_type)
00139     {
00140       create_info().db_type=
00141         plugin::StorageEngine::findByName(session(), original_table_message->engine().name());
00142 
00143       if (not create_info().db_type)
00144       {
00145         my_error(ER_BAD_TABLE_ERROR, identifier);
00146         return true;
00147       }
00148     }
00149   }
00150 
00151   if (not validateCreateTableOption())
00152     return true;
00153 
00154   if (session().inTransaction())
00155   {
00156     my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
00157     return true;
00158   }
00159 
00160   if (session().wait_if_global_read_lock(0, 1))
00161     return true;
00162 
00163   bool res;
00164   if (original_table_message->type() == message::Table::STANDARD )
00165   {
00166     identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
00167     identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
00168                                    lex().name.data() ? lex().name.data() : first_table->getTableName());
00169 
00170     res= alter_table(&session(),
00171                      identifier,
00172                      new_identifier,
00173                      &create_info(),
00174                      *original_table_message,
00175                      createTableMessage(),
00176                      first_table,
00177                      &alter_info,
00178                      select_lex->order_list.size(),
00179                      (Order *) select_lex->order_list.first,
00180                      lex().ignore);
00181   }
00182   else
00183   {
00184     identifier::Table catch22(first_table->getSchemaName(), first_table->getTableName());
00185     Table *table= session().open_tables.find_temporary_table(catch22);
00186     assert(table);
00187     {
00188       identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
00189       identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
00190                                        lex().name.data() ? lex().name.data() : first_table->getTableName(),
00191                                        table->getMutableShare()->getPath());
00192 
00193       res= alter_table(&session(),
00194                        identifier,
00195                        new_identifier,
00196                        &create_info(),
00197                        *original_table_message,
00198                        createTableMessage(),
00199                        first_table,
00200                        &alter_info,
00201                        select_lex->order_list.size(),
00202                        (Order *) select_lex->order_list.first,
00203                        lex().ignore);
00204     }
00205   }
00206 
00207   /*
00208      Release the protection against the global read lock and wake
00209      everyone, who might want to set a global read lock.
00210    */
00211   session().startWaitingGlobalReadLock();
00212 
00213   return res;
00214 }
00215 
00216 
00257 static bool prepare_alter_table(Session *session,
00258                                 Table *table,
00259                                 HA_CREATE_INFO *create_info,
00260                                 const message::Table &original_proto,
00261                                 message::Table &table_message,
00262                                 message::AlterTable &alter_table_message,
00263                                 AlterInfo *alter_info)
00264 {
00265   uint32_t used_fields= create_info->used_fields;
00266   vector<string> drop_keys;
00267   vector<string> drop_columns;
00268   vector<string> drop_fkeys;
00269 
00270   /* we use drop_(keys|columns|fkey) below to check that we can do all
00271      operations we've been asked to do */
00272   for (int operationnr= 0; operationnr < alter_table_message.operations_size();
00273        operationnr++)
00274   {
00275     const message::AlterTable::AlterTableOperation &operation=
00276       alter_table_message.operations(operationnr);
00277 
00278     switch (operation.operation())
00279     {
00280     case message::AlterTable::AlterTableOperation::DROP_KEY:
00281       drop_keys.push_back(operation.drop_name());
00282       break;
00283     case message::AlterTable::AlterTableOperation::DROP_COLUMN:
00284       drop_columns.push_back(operation.drop_name());
00285       break;
00286     case message::AlterTable::AlterTableOperation::DROP_FOREIGN_KEY:
00287       drop_fkeys.push_back(operation.drop_name());
00288       break;
00289     default:
00290       break;
00291     }
00292   }
00293 
00294   /* Let new create options override the old ones */
00295   message::Table::TableOptions *table_options= table_message.mutable_options();
00296 
00297   if (not (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
00298     create_info->default_table_charset= table->getShare()->table_charset;
00299 
00300   if (not (used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
00301   {
00302     /* Table has an autoincrement, copy value to new table */
00303     table->cursor->info(HA_STATUS_AUTO);
00304     create_info->auto_increment_value= table->cursor->stats.auto_increment_value;
00305     if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
00306       table_options->set_has_user_set_auto_increment_value(false);
00307   }
00308 
00309   table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
00310 
00311   List<CreateField> new_create_list;
00312   List<Key> new_key_list;
00313   /* First collect all fields from table which isn't in drop_list */
00314   Field *field;
00315   for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
00316   {
00317     /* Check if field should be dropped */
00318     vector<string>::iterator it= drop_columns.begin();
00319     while (it != drop_columns.end())
00320     {
00321       if (not system_charset_info->strcasecmp(field->field_name, it->c_str()))
00322       {
00323         /* Reset auto_increment value if it was dropped */
00324         if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
00325             not (used_fields & HA_CREATE_USED_AUTO))
00326         {
00327           create_info->auto_increment_value= 0;
00328           create_info->used_fields|= HA_CREATE_USED_AUTO;
00329         }
00330         break;
00331       }
00332       it++;
00333     }
00334 
00335     if (it != drop_columns.end())
00336     {
00337       drop_columns.erase(it);
00338       continue;
00339     }
00340 
00341     /* Mark that we will read the field */
00342     field->setReadSet();
00343 
00344     CreateField *def;
00345     /* Check if field is changed */
00346     List<CreateField>::iterator def_it= alter_info->create_list.begin();
00347     while ((def= def_it++))
00348     {
00349       if (def->change &&
00350           ! system_charset_info->strcasecmp(field->field_name, def->change))
00351         break;
00352     }
00353 
00354     if (def)
00355     {
00356       /* Field is changed */
00357       def->field= field;
00358       if (! def->after)
00359       {
00360         new_create_list.push_back(def);
00361         def_it.remove();
00362       }
00363     }
00364     else
00365     {
00366       /*
00367         This field was not dropped and not changed, add it to the list
00368         for the new table.
00369       */
00370       def= new CreateField(field, field);
00371       new_create_list.push_back(def);
00372       AlterInfo::alter_list_t::iterator alter(alter_info->alter_list.begin());
00373 
00374       for (; alter != alter_info->alter_list.end(); alter++)
00375       {
00376         if (not system_charset_info->strcasecmp(field->field_name, alter->name))
00377           break;
00378       }
00379 
00380       if (alter != alter_info->alter_list.end())
00381       {
00382         def->setDefaultValue(alter->def, NULL);
00383 
00384         alter_info->alter_list.erase(alter);
00385       }
00386     }
00387   }
00388 
00389   CreateField *def;
00390   List<CreateField>::iterator def_it= alter_info->create_list.begin();
00391   while ((def= def_it++)) /* Add new columns */
00392   {
00393     if (def->change && ! def->field)
00394     {
00395       my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
00396       return true;
00397     }
00398     /*
00399       If we have been given a field which has no default value, and is not null then we need to bail.
00400     */
00401     if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
00402     {
00403       alter_info->error_if_not_empty= true;
00404     }
00405     if (! def->after)
00406     {
00407       new_create_list.push_back(def);
00408     }
00409     else if (def->after == first_keyword)
00410     {
00411       new_create_list.push_front(def);
00412     }
00413     else
00414     {
00415       CreateField *find;
00416       List<CreateField>::iterator find_it= new_create_list.begin();
00417 
00418       while ((find= find_it++)) /* Add new columns */
00419       {
00420         if (not system_charset_info->strcasecmp(def->after, find->field_name))
00421           break;
00422       }
00423 
00424       if (not find)
00425       {
00426         my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
00427         return true;
00428       }
00429 
00430       find_it.after(def); /* Put element after this */
00431 
00432       /*
00433         XXX: hack for Bug#28427.
00434         If column order has changed, force OFFLINE ALTER Table
00435         without querying engine capabilities.  If we ever have an
00436         engine that supports online ALTER Table CHANGE COLUMN
00437         <name> AFTER <name1> (Falcon?), this fix will effectively
00438         disable the capability.
00439         TODO: detect the situation in compare_tables, behave based
00440         on engine capabilities.
00441       */
00442       if (alter_table_message.build_method() == message::AlterTable::BUILD_ONLINE)
00443       {
00444         my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
00445         return true;
00446       }
00447     }
00448   }
00449 
00450   if (not alter_info->alter_list.empty())
00451   {
00452     my_error(ER_BAD_FIELD_ERROR, MYF(0), alter_info->alter_list.front().name, table->getMutableShare()->getTableName());
00453     return true;
00454   }
00455 
00456   if (new_create_list.is_empty())
00457   {
00458     my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS), MYF(0));
00459     return true;
00460   }
00461 
00462   /*
00463     Collect all keys which isn't in drop list. Add only those
00464     for which some fields exists.
00465   */
00466   KeyInfo *key_info= table->key_info;
00467   for (uint32_t i= 0; i < table->getShare()->sizeKeys(); i++, key_info++)
00468   {
00469     const char *key_name= key_info->name;
00470 
00471     vector<string>::iterator it= drop_keys.begin();
00472     while (it != drop_keys.end())
00473     {
00474       if (not system_charset_info->strcasecmp(key_name, it->c_str()))
00475         break;
00476       it++;
00477     }
00478 
00479     if (it != drop_keys.end())
00480     {
00481       drop_keys.erase(it);
00482       continue;
00483     }
00484 
00485     KeyPartInfo *key_part= key_info->key_part;
00486     List<Key_part_spec> key_parts;
00487     for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
00488     {
00489       if (not key_part->field)
00490         continue; /* Wrong field (from UNIREG) */
00491 
00492       const char *key_part_name= key_part->field->field_name;
00493       CreateField *cfield;
00494       List<CreateField>::iterator field_it= new_create_list.begin();
00495       while ((cfield= field_it++))
00496       {
00497         if (cfield->change)
00498         {
00499           if (not system_charset_info->strcasecmp(key_part_name, cfield->change))
00500             break;
00501         }
00502         else if (not system_charset_info->strcasecmp(key_part_name, cfield->field_name))
00503           break;
00504       }
00505 
00506       if (not cfield)
00507         continue; /* Field is removed */
00508 
00509       uint32_t key_part_length= key_part->length;
00510       if (cfield->field) /* Not new field */
00511       {
00512         /*
00513           If the field can't have only a part used in a key according to its
00514           new type, or should not be used partially according to its
00515           previous type, or the field length is less than the key part
00516           length, unset the key part length.
00517 
00518           We also unset the key part length if it is the same as the
00519           old field's length, so the whole new field will be used.
00520 
00521           BLOBs may have cfield->length == 0, which is why we test it before
00522           checking whether cfield->length < key_part_length (in chars).
00523          */
00524         if (! Field::type_can_have_key_part(cfield->field->type()) ||
00525             ! Field::type_can_have_key_part(cfield->sql_type) ||
00526             (cfield->field->field_length == key_part_length) ||
00527             (cfield->length &&
00528              (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
00529           key_part_length= 0; /* Use whole field */
00530       }
00531       key_part_length/= key_part->field->charset()->mbmaxlen;
00532       key_parts.push_back(new Key_part_spec(str_ref(cfield->field_name), key_part_length));
00533     }
00534     if (key_parts.size())
00535     {
00536       KEY_CREATE_INFO key_create_info= default_key_create_info;
00537       key_create_info.algorithm= key_info->algorithm;
00538 
00539       if (key_info->flags & HA_USES_BLOCK_SIZE)
00540         key_create_info.block_size= key_info->block_size;
00541 
00542       if (key_info->flags & HA_USES_COMMENT)
00543         key_create_info.comment= key_info->comment;
00544 
00545       Key::Keytype key_type= key_info->flags & HA_NOSAME
00546         ? (is_primary_key(key_name) ? Key::PRIMARY : Key::UNIQUE)
00547         : Key::MULTIPLE;
00548       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));
00549     }
00550   }
00551 
00552   /* Copy over existing foreign keys */
00553   for (int32_t j= 0; j < original_proto.fk_constraint_size(); j++)
00554   {
00555     vector<string>::iterator it= drop_fkeys.begin();
00556     while (it != drop_fkeys.end())
00557     {
00558       if (! system_charset_info->strcasecmp(original_proto.fk_constraint(j).name().c_str(), it->c_str()))
00559       {
00560         break;
00561       }
00562       it++;
00563     }
00564 
00565     if (it != drop_fkeys.end())
00566     {
00567       drop_fkeys.erase(it);
00568       continue;
00569     }
00570 
00571     message::Table::ForeignKeyConstraint *pfkey= table_message.add_fk_constraint();
00572     *pfkey= original_proto.fk_constraint(j);
00573   }
00574 
00575   {
00576     Key *key;
00577     List<Key>::iterator key_it(alter_info->key_list.begin());
00578     while ((key= key_it++)) /* Add new keys */
00579     {
00580       if (key->type == Key::FOREIGN_KEY)
00581       {
00582         if (((Foreign_key *)key)->validate(new_create_list))
00583         {
00584           return true;
00585         }
00586 
00587         Foreign_key *fkey= (Foreign_key*)key;
00588         add_foreign_key_to_table_message(&table_message,
00589                                          fkey->name.data(),
00590                                          fkey->columns,
00591                                          fkey->ref_table,
00592                                          fkey->ref_columns,
00593                                          fkey->delete_opt,
00594                                          fkey->update_opt,
00595                                          fkey->match_opt);
00596       }
00597 
00598       if (key->type != Key::FOREIGN_KEY)
00599         new_key_list.push_back(key);
00600 
00601       if (key->name.data() && is_primary_key(key->name.data()))
00602       {
00603         my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.data());
00604         return true;
00605       }
00606     }
00607   }
00608 
00609   /* Fix names of foreign keys being added */
00610   for (int j= 0; j < table_message.fk_constraint_size(); j++)
00611   {
00612     if (! table_message.fk_constraint(j).has_name())
00613     {
00614       std::string name(table->getMutableShare()->getTableName());
00615       char number[20];
00616 
00617       name.append("_ibfk_");
00618       snprintf(number, sizeof(number), "%d", j+1);
00619       name.append(number);
00620 
00621       message::Table::ForeignKeyConstraint *pfkey= table_message.mutable_fk_constraint(j);
00622       pfkey->set_name(name);
00623     }
00624   }
00625 
00626   if (drop_keys.size())
00627   {
00628     my_error(ER_CANT_DROP_FIELD_OR_KEY,
00629              MYF(0),
00630              drop_keys.front().c_str());
00631     return true;
00632   }
00633 
00634   if (drop_columns.size())
00635   {
00636     my_error(ER_CANT_DROP_FIELD_OR_KEY,
00637              MYF(0),
00638              drop_columns.front().c_str());
00639     return true;
00640   }
00641 
00642   if (drop_fkeys.size())
00643   {
00644     my_error(ER_CANT_DROP_FIELD_OR_KEY,
00645              MYF(0),
00646              drop_fkeys.front().c_str());
00647     return true;
00648   }
00649 
00650   if (not alter_info->alter_list.empty())
00651   {
00652     my_error(ER_CANT_DROP_FIELD_OR_KEY,
00653              MYF(0),
00654              alter_info->alter_list.front().name);
00655     return true;
00656   }
00657 
00658   if (not table_message.options().has_comment()
00659       && table->getMutableShare()->hasComment())
00660   {
00661     table_options->set_comment(table->getMutableShare()->getComment());
00662   }
00663 
00664   if (table->getShare()->getType())
00665   {
00666     table_message.set_type(message::Table::TEMPORARY);
00667   }
00668 
00669   table_message.set_creation_timestamp(table->getShare()->getTableMessage()->creation_timestamp());
00670   table_message.set_version(table->getShare()->getTableMessage()->version());
00671   table_message.set_uuid(table->getShare()->getTableMessage()->uuid());
00672 
00673   alter_info->create_list.swap(new_create_list);
00674   alter_info->key_list.swap(new_key_list);
00675 
00676   size_t num_engine_options= table_message.engine().options_size();
00677   size_t original_num_engine_options= original_proto.engine().options_size();
00678   for (size_t x= 0; x < original_num_engine_options; ++x)
00679   {
00680     bool found= false;
00681 
00682     for (size_t y= 0; y < num_engine_options; ++y)
00683     {
00684       found= not table_message.engine().options(y).name().compare(original_proto.engine().options(x).name());
00685 
00686       if (found)
00687         break;
00688     }
00689 
00690     if (not found)
00691     {
00692       message::Engine::Option *opt= table_message.mutable_engine()->add_options();
00693 
00694       opt->set_name(original_proto.engine().options(x).name());
00695       opt->set_state(original_proto.engine().options(x).state());
00696     }
00697   }
00698 
00699   drizzled::message::update(table_message);
00700 
00701   return false;
00702 }
00703 
00704 /* table_list should contain just one table */
00705 static int discard_or_import_tablespace(Session *session,
00706                                         TableList *table_list,
00707                                         bool discard)
00708 {
00709   /*
00710     Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
00711     ALTER Table
00712   */
00713   session->set_proc_info("discard_or_import_tablespace");
00714 
00715  /*
00716    We set this flag so that ha_innobase::open and ::external_lock() do
00717    not complain when we lock the table
00718  */
00719   session->setDoingTablespaceOperation(true);
00720   Table* table= session->openTableLock(table_list, TL_WRITE);
00721   if (not table)
00722   {
00723     session->setDoingTablespaceOperation(false);
00724     return -1;
00725   }
00726 
00727   int error;
00728   do {
00729     error= table->cursor->ha_discard_or_import_tablespace(discard);
00730 
00731     session->set_proc_info("end");
00732 
00733     if (error)
00734       break;
00735 
00736     /* The ALTER Table is always in its own transaction */
00737     error= TransactionServices::autocommitOrRollback(*session, false);
00738     if (not session->endActiveTransaction())
00739       error= 1;
00740 
00741     if (error)
00742       break;
00743 
00744     TransactionServices::rawStatement(*session,
00745                                       *session->getQueryString(),
00746                                       *session->schema());
00747 
00748   } while(0);
00749 
00750   (void) TransactionServices::autocommitOrRollback(*session, error);
00751   session->setDoingTablespaceOperation(false);
00752 
00753   if (error == 0)
00754   {
00755     session->my_ok();
00756     return 0;
00757   }
00758 
00759   table->print_error(error, MYF(0));
00760 
00761   return -1;
00762 }
00763 
00778 static bool alter_table_manage_keys(Session *session,
00779                                     Table *table, int indexes_were_disabled,
00780                                     const message::AlterTable &alter_table_message)
00781 {
00782   int error= 0;
00783   if (alter_table_message.has_alter_keys_onoff()
00784       && alter_table_message.alter_keys_onoff().enable())
00785   {
00786     error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
00787   }
00788 
00789   if ((! alter_table_message.has_alter_keys_onoff() && indexes_were_disabled)
00790       || (alter_table_message.has_alter_keys_onoff()
00791           && ! alter_table_message.alter_keys_onoff().enable()))
00792   {
00793     error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
00794   }
00795 
00796   if (error == HA_ERR_WRONG_COMMAND)
00797   {
00798     push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
00799                         ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
00800                         table->getMutableShare()->getTableName());
00801     error= 0;
00802   }
00803   else if (error)
00804   {
00805     table->print_error(error, MYF(0));
00806   }
00807 
00808   return(error);
00809 }
00810 
00811 static bool lockTableIfDifferent(Session &session,
00812                                  identifier::Table &original_table_identifier,
00813                                  identifier::Table &new_table_identifier,
00814                                  Table *name_lock)
00815 {
00816   /* Check that we are not trying to rename to an existing table */
00817   if (not (original_table_identifier == new_table_identifier))
00818   {
00819     if (original_table_identifier.isTmp())
00820     {
00821       if (session.open_tables.find_temporary_table(new_table_identifier))
00822       {
00823         my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
00824         return false;
00825       }
00826     }
00827     else
00828     {
00829       name_lock= session.lock_table_name_if_not_cached(new_table_identifier);
00830       if (not name_lock)
00831       {
00832         my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
00833         return false;
00834       }
00835 
00836       if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
00837       {
00838         /* Table will be closed by Session::executeCommand() */
00839         my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
00840 
00841         {
00842           boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
00843           session.unlink_open_table(name_lock);
00844         }
00845 
00846         return false;
00847       }
00848     }
00849   }
00850 
00851   return true;
00852 }
00853 
00896 static bool internal_alter_table(Session *session,
00897                                  Table *table,
00898                                  identifier::Table &original_table_identifier,
00899                                  identifier::Table &new_table_identifier,
00900                                  HA_CREATE_INFO *create_info,
00901                                  const message::Table &original_proto,
00902                                  message::Table &create_proto,
00903                                  message::AlterTable &alter_table_message,
00904                                  TableList *table_list,
00905                                  AlterInfo *alter_info,
00906                                  uint32_t order_num,
00907                                  Order *order,
00908                                  bool ignore)
00909 {
00910   int error= 0;
00911   char tmp_name[80];
00912   char old_name[32];
00913   ha_rows copied= 0;
00914   ha_rows deleted= 0;
00915 
00916   if (not original_table_identifier.isValid())
00917     return true;
00918 
00919   if (not new_table_identifier.isValid())
00920     return true;
00921 
00922   session->set_proc_info("init");
00923 
00924   table->use_all_columns();
00925 
00926   plugin::StorageEngine *new_engine;
00927   plugin::StorageEngine *original_engine;
00928 
00929   original_engine= table->getMutableShare()->getEngine();
00930 
00931   if (not create_info->db_type)
00932   {
00933     create_info->db_type= original_engine;
00934   }
00935   new_engine= create_info->db_type;
00936 
00937 
00938   create_proto.set_schema(new_table_identifier.getSchemaName());
00939   create_proto.set_type(new_table_identifier.getType());
00940 
00945   if (new_engine != original_engine &&
00946       not table->cursor->can_switch_engines())
00947   {
00948     assert(0);
00949     my_error(ER_ROW_IS_REFERENCED, MYF(0));
00950 
00951     return true;
00952   }
00953 
00954   if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
00955       new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
00956   {
00957     my_error(ER_ILLEGAL_HA, new_table_identifier);
00958 
00959     return true;
00960   }
00961 
00962   session->set_proc_info("setup");
00963 
00964   /* First we try for operations that do not require a copying
00965      ALTER TABLE.
00966 
00967      In future there should be more operations, currently it's just a couple.
00968   */
00969 
00970   if ((alter_table_message.has_rename()
00971        || alter_table_message.has_alter_keys_onoff())
00972       && alter_table_message.operations_size() == 0)
00973   {
00974     /*
00975      * test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
00976      */
00977     bitset<32> tmp;
00978 
00979     tmp.set();
00980     tmp.reset(ALTER_RENAME);
00981     tmp.reset(ALTER_KEYS_ONOFF);
00982     tmp&= alter_info->flags;
00983 
00984     if((not (tmp.any()) && not table->getShare()->getType())) // no need to touch frm
00985     {
00986       if (alter_table_message.has_alter_keys_onoff())
00987       {
00988         error= apply_online_alter_keys_onoff(session, table,
00989                                        alter_table_message.alter_keys_onoff());
00990 
00991         if (error == HA_ERR_WRONG_COMMAND)
00992         {
00993           error= EE_OK;
00994           push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
00995                               ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
00996                               table->getAlias());
00997         }
00998       }
00999 
01000       if (alter_table_message.has_rename())
01001       {
01002         error= apply_online_rename_table(session,
01003                                          table,
01004                                          original_engine,
01005                                          original_table_identifier,
01006                                          new_table_identifier,
01007                                          alter_table_message.rename());
01008 
01009         if (error == HA_ERR_WRONG_COMMAND)
01010         {
01011           error= EE_OK;
01012           push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
01013                               ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
01014                               table->getAlias());
01015         }
01016       }
01017 
01018       if (not error)
01019       {
01020         TransactionServices::allocateNewTransactionId();
01021         TransactionServices::rawStatement(*session,
01022                                           *session->getQueryString(),
01023                                           *session->schema());
01024         session->my_ok();
01025       }
01026       else if (error > EE_OK) // If we have already set the error, we pass along -1
01027       {
01028         table->print_error(error, MYF(0));
01029       }
01030 
01031       table_list->table= NULL;
01032 
01033       return error;
01034     }
01035   }
01036 
01037   if (alter_table_message.build_method() == message::AlterTable::BUILD_ONLINE)
01038   {
01039     my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
01040     return true;
01041   }
01042 
01043   /* We have to do full alter table. */
01044   new_engine= create_info->db_type;
01045 
01046   if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_table_message, alter_info))
01047   {
01048     return true;
01049   }
01050 
01051   set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
01052 
01053   snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
01054 
01055   /* Create a temporary table with the new format */
01061   identifier::Table new_table_as_temporary(original_table_identifier.getSchemaName(),
01062                                          tmp_name,
01063                                          create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
01064                                          message::Table::TEMPORARY);
01065 
01066   /*
01067     Create a table with a temporary name.
01068     We don't log the statement, it will be logged later.
01069   */
01070   create_proto.set_name(new_table_as_temporary.getTableName());
01071   create_proto.mutable_engine()->set_name(create_info->db_type->getName());
01072 
01073   error= create_table(session,
01074                       new_table_as_temporary,
01075                       create_info, create_proto, alter_info, true, 0, false);
01076 
01077   if (error != 0)
01078   {
01079     return true;
01080   }
01081 
01082   /* Open the table so we need to copy the data to it. */
01083   Table *new_table= open_alter_table(session, table, new_table_as_temporary);
01084 
01085 
01086   if (not new_table)
01087   {
01088     plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
01089     return true;
01090   }
01091 
01092   /* Copy the data if necessary. */
01093   {
01094     /* We must not ignore bad input! */
01095     session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;  // calc cuted fields
01096     session->cuted_fields= 0L;
01097     session->set_proc_info("copy to tmp table");
01098     copied= deleted= 0;
01099 
01100     /* We don't want update TIMESTAMP fields during ALTER Table. */
01101     new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
01102     new_table->next_number_field= new_table->found_next_number_field;
01103     error= copy_data_between_tables(session,
01104                                     table,
01105                                     new_table,
01106                                     alter_info->create_list,
01107                                     ignore,
01108                                     order_num,
01109                                     order,
01110                                     &copied,
01111                                     &deleted,
01112                                     alter_table_message,
01113                                     alter_info->error_if_not_empty);
01114 
01115     /* We must not ignore bad input! */
01116     assert(session->count_cuted_fields == CHECK_FIELD_ERROR_FOR_NULL);
01117   }
01118 
01119   /* Now we need to resolve what just happened with the data copy. */
01120 
01121   if (error)
01122   {
01123 
01124     /*
01125       No default value was provided for new fields.
01126     */
01127     if (alter_info->error_if_not_empty && session->row_count)
01128     {
01129       my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
01130     }
01131 
01132     if (original_table_identifier.isTmp())
01133     {
01134       if (new_table)
01135       {
01136         /* close_temporary_table() frees the new_table pointer. */
01137         session->open_tables.close_temporary_table(new_table);
01138       }
01139       else
01140       {
01141         plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
01142       }
01143 
01144       return true;
01145     }
01146     else
01147     {
01148       if (new_table)
01149       {
01150         /*
01151           Close the intermediate table that will be the new table.
01152           Note that MERGE tables do not have their children attached here.
01153         */
01154         new_table->intern_close_table();
01155         if (new_table->hasShare())
01156         {
01157           delete new_table->getMutableShare();
01158         }
01159 
01160         delete new_table;
01161       }
01162 
01163       boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
01164 
01165       plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
01166 
01167       return true;
01168     }
01169   }
01170   // Temporary table and success
01171   else if (original_table_identifier.isTmp())
01172   {
01173     /* Close lock if this is a transactional table */
01174     if (session->open_tables.lock)
01175     {
01176       session->unlockTables(session->open_tables.lock);
01177       session->open_tables.lock= 0;
01178     }
01179 
01180     /* Remove link to old table and rename the new one */
01181     session->open_tables.close_temporary_table(table);
01182 
01183     /* Should pass the 'new_name' as we store table name in the cache */
01184     new_table->getMutableShare()->setIdentifier(new_table_identifier);
01185 
01186     new_table_identifier.setPath(new_table_as_temporary.getPath());
01187 
01188     if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
01189     {
01190       return true;
01191     }
01192   }
01193   // Normal table success
01194   else
01195   {
01196     if (new_table)
01197     {
01198       /*
01199         Close the intermediate table that will be the new table.
01200         Note that MERGE tables do not have their children attached here.
01201       */
01202       new_table->intern_close_table();
01203 
01204       if (new_table->hasShare())
01205       {
01206         delete new_table->getMutableShare();
01207       }
01208 
01209       delete new_table;
01210     }
01211 
01212     {
01213       boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* ALTER TABLE */
01214       /*
01215         Data is copied. Now we:
01216         1) Wait until all other threads close old version of table.
01217         2) Close instances of table open by this thread and replace them
01218         with exclusive name-locks.
01219         3) Rename the old table to a temp name, rename the new one to the
01220         old name.
01221         4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
01222         we reopen new version of table.
01223         5) Write statement to the binary log.
01224         6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
01225         remove name-locks from list of open tables and table cache.
01226         7) If we are not not under LOCK TABLES we rely on close_thread_tables()
01227         call to remove name-locks from table cache and list of open table.
01228       */
01229 
01230       session->set_proc_info("rename result table");
01231 
01232       snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
01233 
01234       files_charset_info->casedn_str(old_name);
01235 
01236       wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
01237       session->close_data_files_and_morph_locks(original_table_identifier);
01238 
01239       assert(not error);
01240 
01241       /*
01242         This leads to the storage engine (SE) not being notified for renames in
01243         rename_table(), because we just juggle with the FRM and nothing
01244         more. If we have an intermediate table, then we notify the SE that
01245         it should become the actual table. Later, we will recycle the old table.
01246         However, in case of ALTER Table RENAME there might be no intermediate
01247         table. This is when the old and new tables are compatible, according to
01248         compare_table(). Then, we need one additional call to
01249       */
01250       identifier::Table original_table_to_drop(original_table_identifier.getSchemaName(),
01251                                              old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
01252                                              message::Table::TEMPORARY);
01253 
01254       drizzled::error_t rename_error= EE_OK;
01255       if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
01256       {
01257         error= ER_ERROR_ON_RENAME;
01258         plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
01259       }
01260       else
01261       {
01262         if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
01263         {
01264           /* Try to get everything back. */
01265           rename_error= ER_ERROR_ON_RENAME;
01266 
01267           plugin::StorageEngine::dropTable(*session, new_table_identifier);
01268 
01269           plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
01270 
01271           rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
01272         }
01273         else
01274         {
01275           plugin::StorageEngine::dropTable(*session, original_table_to_drop);
01276         }
01277       }
01278 
01279       if (rename_error)
01280       {
01281         /*
01282           An error happened while we were holding exclusive name-lock on table
01283           being altered. To be safe under LOCK TABLES we should remove placeholders
01284           from list of open tables list and table cache.
01285         */
01286         session->unlink_open_table(table);
01287 
01288         return true;
01289       }
01290     }
01291 
01292     session->set_proc_info("end");
01293 
01294     TransactionServices::rawStatement(*session,
01295                                       *session->getQueryString(),
01296                                       *session->schema());
01297     table_list->table= NULL;
01298   }
01299 
01300   /*
01301    * Field::store() may have called my_error().  If this is
01302    * the case, we must not send an ok packet, since
01303    * Diagnostics_area::is_set() will fail an assert.
01304  */
01305   if (session->is_error())
01306   {
01307     /* my_error() was called.  Return true (which means error...) */
01308     return true;
01309   }
01310 
01311   snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
01312            (ulong) (copied + deleted), (ulong) deleted,
01313            (ulong) session->cuted_fields);
01314   session->my_ok(copied + deleted, 0, 0L, tmp_name);
01315   return false;
01316 }
01317 
01318 static int apply_online_alter_keys_onoff(Session *session,
01319                                          Table* table,
01320                                          const message::AlterTable::AlterKeysOnOff &op)
01321 {
01322   int error= 0;
01323 
01324   if (op.enable())
01325   {
01326     /*
01327       wait_while_table_is_used() ensures that table being altered is
01328       opened only by this thread and that Table::TableShare::version
01329       of Table object corresponding to this table is 0.
01330       The latter guarantees that no DML statement will open this table
01331       until ALTER Table finishes (i.e. until close_thread_tables())
01332       while the fact that the table is still open gives us protection
01333       from concurrent DDL statements.
01334     */
01335     {
01336       boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* DDL wait for/blocker */
01337       wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
01338     }
01339     error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
01340 
01341     /* COND_refresh will be signaled in close_thread_tables() */
01342   }
01343   else
01344   {
01345     {
01346       boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* DDL wait for/blocker */
01347       wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
01348     }
01349     error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
01350 
01351     /* COND_refresh will be signaled in close_thread_tables() */
01352   }
01353 
01354   return error;
01355 }
01356 
01357 static int apply_online_rename_table(Session *session,
01358                                      Table *table,
01359                                      plugin::StorageEngine *original_engine,
01360                                      identifier::Table &original_table_identifier,
01361                                      identifier::Table &new_table_identifier,
01362                                      const message::AlterTable::RenameTable &alter_operation)
01363 {
01364   int error= 0;
01365 
01366   boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* Lock to remove all instances of table from table cache before ALTER */
01367   /*
01368     Unlike to the above case close_cached_table() below will remove ALL
01369     instances of Table from table cache (it will also remove table lock
01370     held by this thread). So to make actual table renaming and writing
01371     to binlog atomic we have to put them into the same critical section
01372     protected by table::Cache::mutex() mutex. This also removes gap for races between
01373     access() and rename_table() calls.
01374   */
01375 
01376   if (not (original_table_identifier == new_table_identifier))
01377   {
01378     assert(alter_operation.to_name() == new_table_identifier.getTableName());
01379     assert(alter_operation.to_schema() == new_table_identifier.getSchemaName());
01380 
01381     session->set_proc_info("rename");
01382     /*
01383       Then do a 'simple' rename of the table. First we need to close all
01384       instances of 'source' table.
01385     */
01386     session->close_cached_table(table);
01387     /*
01388       Then, we want check once again that target table does not exist.
01389       Actually the order of these two steps does not matter since
01390       earlier we took name-lock on the target table, so we do them
01391       in this particular order only to be consistent with 5.0, in which
01392       we don't take this name-lock and where this order really matters.
01393       @todo Investigate if we need this access() check at all.
01394     */
01395     if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
01396     {
01397       my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
01398       error= -1;
01399     }
01400     else
01401     {
01402       if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
01403       {
01404         error= -1;
01405       }
01406     }
01407   }
01408   return error;
01409 }
01410 
01411 bool alter_table(Session *session,
01412                  identifier::Table &original_table_identifier,
01413                  identifier::Table &new_table_identifier,
01414                  HA_CREATE_INFO *create_info,
01415                  const message::Table &original_proto,
01416                  message::Table &create_proto,
01417                  TableList *table_list,
01418                  AlterInfo *alter_info,
01419                  uint32_t order_num,
01420                  Order *order,
01421                  bool ignore)
01422 {
01423   bool error;
01424   Table *table;
01425   message::AlterTable *alter_table_message= session->lex().alter_table();
01426 
01427   alter_table_message->set_catalog(original_table_identifier.getCatalogName());
01428   alter_table_message->set_schema(original_table_identifier.getSchemaName());
01429   alter_table_message->set_name(original_table_identifier.getTableName());
01430 
01431   if (alter_table_message->operations_size()
01432       && (alter_table_message->operations(0).operation()
01433           == message::AlterTable::AlterTableOperation::DISCARD_TABLESPACE
01434           || alter_table_message->operations(0).operation()
01435           == message::AlterTable::AlterTableOperation::IMPORT_TABLESPACE))
01436   {
01437     bool discard= (alter_table_message->operations(0).operation() ==
01438                    message::AlterTable::AlterTableOperation::DISCARD_TABLESPACE);
01439     /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
01440     return discard_or_import_tablespace(session, table_list, discard);
01441   }
01442 
01443   session->set_proc_info("init");
01444 
01445   if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
01446     return true;
01447 
01448   session->set_proc_info("gained write lock on table");
01449 
01450   /*
01451     Check that we are not trying to rename to an existing table,
01452     if one existed we get a lock, if we can't we error.
01453   */
01454   {
01455     Table *name_lock= NULL;
01456 
01457     if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
01458     {
01459       return true;
01460     }
01461 
01462     error= internal_alter_table(session,
01463                                 table,
01464                                 original_table_identifier,
01465                                 new_table_identifier,
01466                                 create_info,
01467                                 original_proto,
01468                                 create_proto,
01469                                 *alter_table_message,
01470                                 table_list,
01471                                 alter_info,
01472                                 order_num,
01473                                 order,
01474                                 ignore);
01475 
01476     if (name_lock)
01477     {
01478       boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
01479       session->unlink_open_table(name_lock);
01480     }
01481   }
01482 
01483   return error;
01484 }
01485 /* alter_table */
01486 
01487 static int
01488 copy_data_between_tables(Session *session,
01489                          Table *from, Table *to,
01490                          List<CreateField> &create,
01491                          bool ignore,
01492                          uint32_t order_num, Order *order,
01493                          ha_rows *copied,
01494                          ha_rows *deleted,
01495                          message::AlterTable &alter_table_message,
01496                          bool error_if_not_empty)
01497 {
01498   int error= 0;
01499   CopyField *copy,*copy_end;
01500   ulong found_count,delete_count;
01501   uint32_t length= 0;
01502   SortField *sortorder;
01503   ReadRecord info;
01504   TableList   tables;
01505   List<Item>   fields;
01506   List<Item>   all_fields;
01507   ha_rows examined_rows;
01508   bool auto_increment_field_copied= 0;
01509   uint64_t prev_insert_id;
01510 
01511   /*
01512     Turn off recovery logging since rollback of an alter table is to
01513     delete the new table so there is no need to log the changes to it.
01514 
01515     This needs to be done before external_lock
01516   */
01517 
01518   /*
01519    * LP Bug #552420
01520    *
01521    * Since open_temporary_table() doesn't invoke lockTables(), we
01522    * don't get the usual automatic call to StorageEngine::startStatement(), so
01523    * we manually call it here...
01524    */
01525   to->getMutableShare()->getEngine()->startStatement(session);
01526 
01527   copy= new CopyField[to->getShare()->sizeFields()];
01528 
01529   if (to->cursor->ha_external_lock(session, F_WRLCK))
01530     return -1;
01531 
01532   /* We need external lock before we can disable/enable keys */
01533   alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(),
01534                           alter_table_message);
01535 
01536   /* We can abort alter table for any table type */
01537   session->setAbortOnWarning(not ignore);
01538 
01539   from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
01540   to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
01541 
01542   List<CreateField>::iterator it(create.begin());
01543   copy_end= copy;
01544   for (Field **ptr= to->getFields(); *ptr ; ptr++)
01545   {
01546     CreateField* def=it++;
01547     if (def->field)
01548     {
01549       if (*ptr == to->next_number_field)
01550         auto_increment_field_copied= true;
01551 
01552       (copy_end++)->set(*ptr,def->field,0);
01553     }
01554 
01555   }
01556 
01557   found_count=delete_count=0;
01558 
01559   do
01560   {
01561     if (order)
01562     {
01563       if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
01564       {
01565         char warn_buff[DRIZZLE_ERRMSG_SIZE];
01566         snprintf(warn_buff, sizeof(warn_buff),
01567                  _("order_st BY ignored because there is a user-defined clustered "
01568                    "index in the table '%-.192s'"),
01569                  from->getMutableShare()->getTableName());
01570         push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
01571                      warn_buff);
01572       }
01573       else
01574       {
01575         FileSort filesort(*session);
01576         from->sort.io_cache= new internal::io_cache_st;
01577 
01578         tables.table= from;
01579         tables.setTableName(from->getMutableShare()->getTableName());
01580         tables.alias= tables.getTableName();
01581         tables.setSchemaName(from->getMutableShare()->getSchemaName());
01582         error= 1;
01583 
01584         session->lex().select_lex.setup_ref_array(session, order_num);
01585         if (setup_order(session, session->lex().select_lex.ref_pointer_array, &tables, fields, all_fields, order))
01586           break;
01587         sortorder= make_unireg_sortorder(order, &length, NULL);
01588         if ((from->sort.found_records= filesort.run(from, sortorder, length, (optimizer::SqlSelect *) 0, HA_POS_ERROR, 1, examined_rows)) == HA_POS_ERROR)
01589           break;
01590       }
01591     }
01592 
01593     /* Tell handler that we have values for all columns in the to table */
01594     to->use_all_columns();
01595 
01596     error= info.init_read_record(session, from, NULL, 1, true);
01597     if (error)
01598     {
01599       to->print_error(errno, MYF(0));
01600 
01601       break;
01602     }
01603 
01604     if (ignore)
01605     {
01606       to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
01607     }
01608 
01609     session->row_count= 0;
01610     to->restoreRecordAsDefault();        // Create empty record
01611     while (not (error=info.read_record(&info)))
01612     {
01613       if (session->getKilled())
01614       {
01615         session->send_kill_message();
01616         error= 1;
01617         break;
01618       }
01619       session->row_count++;
01620       /* Return error if source table isn't empty. */
01621       if (error_if_not_empty)
01622       {
01623         error= 1;
01624         break;
01625       }
01626       if (to->next_number_field)
01627       {
01628         if (auto_increment_field_copied)
01629           to->auto_increment_field_not_null= true;
01630         else
01631           to->next_number_field->reset();
01632       }
01633 
01634       for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
01635       {
01636         if (not copy->to_field->hasDefault() and copy->from_null_ptr and  *copy->from_null_ptr & copy->from_bit)
01637         {
01638           copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
01639                                       ER_WARN_DATA_TRUNCATED, 1);
01640           copy->to_field->reset();
01641           error= 1;
01642           break;
01643         }
01644 
01645         copy_ptr->do_copy(copy_ptr);
01646       }
01647 
01648       if (error)
01649       {
01650         break;
01651       }
01652 
01653       prev_insert_id= to->cursor->next_insert_id;
01654       error= to->cursor->insertRecord(to->record[0]);
01655       to->auto_increment_field_not_null= false;
01656 
01657       if (error)
01658       {
01659         if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
01660         {
01661           to->print_error(error, MYF(0));
01662           break;
01663         }
01664         to->cursor->restore_auto_increment(prev_insert_id);
01665         delete_count++;
01666       }
01667       else
01668       {
01669         found_count++;
01670       }
01671     }
01672 
01673     info.end_read_record();
01674     from->free_io_cache();
01675     delete[] copy;
01676 
01677     if (to->cursor->ha_end_bulk_insert() && error <= 0)
01678     {
01679       to->print_error(errno, MYF(0));
01680       error= 1;
01681     }
01682     to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
01683 
01684     /*
01685       Ensure that the new table is saved properly to disk so that we
01686       can do a rename
01687     */
01688     if (TransactionServices::autocommitOrRollback(*session, false))
01689       error= 1;
01690 
01691     if (not session->endActiveTransaction())
01692       error= 1;
01693 
01694   } while (0);
01695 
01696   session->setAbortOnWarning(false);
01697   from->free_io_cache();
01698   *copied= found_count;
01699   *deleted=delete_count;
01700   to->cursor->ha_release_auto_increment();
01701 
01702   if (to->cursor->ha_external_lock(session, F_UNLCK))
01703   {
01704     error= 1;
01705   }
01706 
01707   return error > 0 ? -1 : 0;
01708 }
01709 
01710 static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
01711 {
01712   /* Open the table so we need to copy the data to it. */
01713   if (table->getShare()->getType())
01714   {
01715     TableList tbl;
01716     tbl.setSchemaName(identifier.getSchemaName().c_str());
01717     tbl.alias= identifier.getTableName().c_str();
01718     tbl.setTableName(identifier.getTableName().c_str());
01719 
01720     /* Table is in session->temporary_tables */
01721     return session->openTable(&tbl, NULL, DRIZZLE_LOCK_IGNORE_FLUSH);
01722   }
01723   else
01724   {
01725     /* Open our intermediate table */
01726     return session->open_temporary_table(identifier, false);
01727   }
01728 }
01729 
01730 } /* namespace drizzled */