00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 }
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
00126 assert(select_lex->db);
00127
00128
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
00209
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
00271
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
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
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();
00310
00311 List<CreateField> new_create_list;
00312 List<Key> new_key_list;
00313
00314 Field *field;
00315 for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
00316 {
00317
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
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
00342 field->setReadSet();
00343
00344 CreateField *def;
00345
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
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
00368
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++))
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
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++))
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);
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
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
00464
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;
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;
00508
00509 uint32_t key_part_length= key_part->length;
00510 if (cfield->field)
00511 {
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
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;
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
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++))
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
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
00705 static int discard_or_import_tablespace(Session *session,
00706 TableList *table_list,
00707 bool discard)
00708 {
00709
00710
00711
00712
00713 session->set_proc_info("discard_or_import_tablespace");
00714
00715
00716
00717
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
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
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
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
00965
00966
00967
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
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()))
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)
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
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
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
01068
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
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
01093 {
01094
01095 session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
01096 session->cuted_fields= 0L;
01097 session->set_proc_info("copy to tmp table");
01098 copied= deleted= 0;
01099
01100
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
01116 assert(session->count_cuted_fields == CHECK_FIELD_ERROR_FOR_NULL);
01117 }
01118
01119
01120
01121 if (error)
01122 {
01123
01124
01125
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
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
01152
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
01171 else if (original_table_identifier.isTmp())
01172 {
01173
01174 if (session->open_tables.lock)
01175 {
01176 session->unlockTables(session->open_tables.lock);
01177 session->open_tables.lock= 0;
01178 }
01179
01180
01181 session->open_tables.close_temporary_table(table);
01182
01183
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
01194 else
01195 {
01196 if (new_table)
01197 {
01198
01199
01200
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());
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
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
01243
01244
01245
01246
01247
01248
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
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
01283
01284
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
01302
01303
01304
01305 if (session->is_error())
01306 {
01307
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
01328
01329
01330
01331
01332
01333
01334
01335 {
01336 boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
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
01342 }
01343 else
01344 {
01345 {
01346 boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
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
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());
01367
01368
01369
01370
01371
01372
01373
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
01384
01385
01386 session->close_cached_table(table);
01387
01388
01389
01390
01391
01392
01393
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
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
01452
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
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
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
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
01533 alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(),
01534 alter_table_message);
01535
01536
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
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();
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
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
01686
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
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
01721 return session->openTable(&tbl, NULL, DRIZZLE_LOCK_IGNORE_FLUSH);
01722 }
01723 else
01724 {
01725
01726 return session->open_temporary_table(identifier, false);
01727 }
01728 }
01729
01730 }