~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Brian Aker
  • Date: 2010-03-25 01:22:58 UTC
  • mfrom: (1395.1.4 build)
  • Revision ID: brian@gaz-20100325012258-cg51yq2yiuldvgxw
Merge of ALTER TABLE code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
73
73
                                  message::Table &create_message,
74
74
                                  AlterInfo *alter_info);
75
75
 
76
 
static Table *open_alter_table(Session *session, Table *table, char *db, char *table_name);
 
76
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier);
77
77
 
78
78
bool statement::AlterTable::execute()
79
79
{
127
127
  if (original_table_message.type() == message::Table::STANDARD )
128
128
  {
129
129
    TableIdentifier identifier(first_table->db, first_table->table_name);
 
130
    TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->db,
 
131
                                   session->lex->name.str ? session->lex->name.str : first_table->table_name);
130
132
 
131
133
    res= alter_table(session, 
132
 
                     select_lex->db, 
133
 
                     session->lex->name.str,
134
134
                     identifier,
 
135
                     new_identifier,
135
136
                     &create_info,
136
137
                     create_table_message,
137
138
                     first_table,
146
147
    assert(table);
147
148
    {
148
149
      TableIdentifier identifier(first_table->db, first_table->table_name, table->s->path.str);
 
150
      TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->db,
 
151
                                     session->lex->name.str ? session->lex->name.str : first_table->table_name,
 
152
                                     table->s->path.str);
149
153
 
150
154
      res= alter_table(session, 
151
 
                       select_lex->db, 
152
 
                       session->lex->name.str,
153
155
                       identifier,
 
156
                       new_identifier,
154
157
                       &create_info,
155
158
                       create_table_message,
156
159
                       first_table,
680
683
  return(error);
681
684
}
682
685
 
 
686
static bool lockTableIfDifferent(Session &session,
 
687
                                 TableIdentifier &original_table_identifier,
 
688
                                 TableIdentifier &new_table_identifier,
 
689
                                 Table *name_lock)
 
690
{
 
691
  /* Check that we are not trying to rename to an existing table */
 
692
  if (not (original_table_identifier == new_table_identifier))
 
693
  {
 
694
    if (original_table_identifier.isTmp())
 
695
    {
 
696
 
 
697
      if (session.find_temporary_table(new_table_identifier))
 
698
      {
 
699
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
700
        return false;
 
701
      }
 
702
    }
 
703
    else
 
704
    {
 
705
      if (session.lock_table_name_if_not_cached(new_table_identifier, &name_lock))
 
706
      {
 
707
        return false;
 
708
      }
 
709
 
 
710
      if (not name_lock)
 
711
      {
 
712
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
713
        return false;
 
714
      }
 
715
 
 
716
      if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
 
717
      {
 
718
        /* Table will be closed by Session::executeCommand() */
 
719
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
 
720
 
 
721
        pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
 
722
        session.unlink_open_table(name_lock);
 
723
        pthread_mutex_unlock(&LOCK_open);
 
724
 
 
725
        return false;
 
726
      }
 
727
    }
 
728
  }
 
729
 
 
730
  return true;
 
731
}
 
732
 
683
733
/**
684
734
  Alter table
685
735
 
721
771
    false  OK
722
772
    true   Error
723
773
*/
724
 
bool alter_table(Session *session,
725
 
                 char *new_db,
726
 
                 char *new_name,
727
 
                 TableIdentifier &original_table_identifier,
728
 
                 HA_CREATE_INFO *create_info,
729
 
                 message::Table &create_proto,
730
 
                 TableList *table_list,
731
 
                 AlterInfo *alter_info,
732
 
                 uint32_t order_num,
733
 
                 order_st *order,
734
 
                 bool ignore)
 
774
 
 
775
static bool internal_alter_table(Session *session,
 
776
                                 Table *table,
 
777
                                 TableIdentifier &original_table_identifier,
 
778
                                 TableIdentifier &new_table_identifier,
 
779
                                 HA_CREATE_INFO *create_info,
 
780
                                 message::Table &create_proto,
 
781
                                 TableList *table_list,
 
782
                                 AlterInfo *alter_info,
 
783
                                 uint32_t order_num,
 
784
                                 order_st *order,
 
785
                                 bool ignore)
735
786
{
736
 
  Table *table;
737
787
  Table *new_table= NULL;
738
 
  Table *name_lock= NULL;
739
 
  string new_name_str;
740
788
  int error= 0;
741
789
  char tmp_name[80];
742
790
  char old_name[32];
743
 
  char *table_name;
744
 
  char *db;
745
 
  const char *new_alias;
746
791
  ha_rows copied= 0;
747
792
  ha_rows deleted= 0;
748
 
  plugin::StorageEngine *old_db_type;
749
 
  plugin::StorageEngine *new_db_type;
750
 
  plugin::StorageEngine *save_old_db_type;
751
 
  bitset<32> tmp;
 
793
 
 
794
  message::Table *original_table_definition= table->s->getTableProto();
752
795
 
753
796
  session->set_proc_info("init");
754
797
 
755
 
  /*
756
 
    Assign variables table_name, new_name, db, new_db, path
757
 
    to simplify further comparisons: we want to see if it's a RENAME
758
 
    later just by comparing the pointers, avoiding the need for strcmp.
759
 
  */
760
 
  table_name= table_list->table_name;
761
 
  db= table_list->db;
762
 
  if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
763
 
    new_db= db;
764
 
 
765
 
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
766
 
  {
767
 
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
768
 
    return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
769
 
  }
770
 
 
771
 
  /*
772
 
    If this is just a rename of a view, short cut to the
773
 
    following scenario: 1) lock LOCK_open 2) do a RENAME
774
 
    2) unlock LOCK_open.
775
 
    This is a copy-paste added to make sure
776
 
    ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
777
 
    as an independent branch in mysql_execute_command. The need
778
 
    for a copy-paste arose because the main code flow of ALTER Table
779
 
    ... RENAME tries to use openTableLock, which does not work for views
780
 
    (openTableLock was never modified to merge table lists of child tables
781
 
    into the main table list, like open_tables does).
782
 
    This code is wrong and will be removed, please do not copy.
783
 
  */
784
 
 
785
 
  if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
786
 
    return true;
787
 
  
788
798
  table->use_all_columns();
789
799
 
790
 
  bool error_on_rename= false;
791
 
 
792
 
  /* Check that we are not trying to rename to an existing table */
793
 
  if (new_name)
794
 
  {
795
 
    char new_alias_buff[FN_REFLEN];
796
 
    char lower_case_table_name[FN_REFLEN];
797
 
 
798
 
    strcpy(lower_case_table_name, new_name);
799
 
    strcpy(new_alias_buff, new_name);
800
 
    new_alias= new_alias_buff;
801
 
 
802
 
    my_casedn_str(files_charset_info, lower_case_table_name);
803
 
    new_alias= new_name; // Create lower case table name
804
 
    my_casedn_str(files_charset_info, new_name);
805
 
 
806
 
    if (new_db == db &&
807
 
        not my_strcasecmp(table_alias_charset, lower_case_table_name, table_name))
808
 
    {
809
 
      /*
810
 
        Source and destination table names are equal: make later check
811
 
        easier.
812
 
      */
813
 
      new_alias= new_name= table_name;
814
 
    }
815
 
    else
816
 
    {
817
 
      TableIdentifier identifier(new_db, lower_case_table_name);
818
 
 
819
 
      if (table->s->tmp_table != STANDARD_TABLE)
820
 
      {
821
 
 
822
 
        if (session->find_temporary_table(identifier))
823
 
        {
824
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), lower_case_table_name);
825
 
          return true;
826
 
        }
827
 
      }
828
 
      else
829
 
      {
830
 
        if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
831
 
          return true;
832
 
 
833
 
        if (not name_lock)
834
 
        {
835
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
836
 
          return true;
837
 
        }
838
 
 
839
 
        if (plugin::StorageEngine::doesTableExist(*session, identifier))
840
 
        {
841
 
          /* Table will be closed by Session::executeCommand() */
842
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
843
 
          error_on_rename= true;
844
 
        }
845
 
      }
846
 
    }
 
800
  plugin::StorageEngine *new_engine;
 
801
  plugin::StorageEngine *original_engine;
 
802
 
 
803
  original_engine= table->s->getEngine();
 
804
 
 
805
  if (not create_info->db_type)
 
806
  {
 
807
    create_info->db_type= original_engine;
 
808
  }
 
809
  new_engine= create_info->db_type;
 
810
 
 
811
 
 
812
  create_proto.set_schema(new_table_identifier.getSchemaName().c_str());
 
813
 
 
814
  if (new_table_identifier.isTmp())
 
815
  {
 
816
    create_proto.set_type(message::Table::TEMPORARY);
847
817
  }
848
818
  else
849
819
  {
850
 
    new_alias= table_name;
851
 
    new_name= table_name;
852
 
  }
853
 
 
854
 
  TableIdentifier new_table_as_replacement(new_db, new_alias);
855
 
 
856
 
  if (not error_on_rename)
857
 
  {
858
 
    old_db_type= table->s->db_type();
859
 
    if (not create_info->db_type)
860
 
    {
861
 
      create_info->db_type= old_db_type;
862
 
    }
863
 
 
864
 
    create_proto.set_schema(new_db);
865
 
 
866
 
    if (table->s->tmp_table != STANDARD_TABLE)
867
 
    {
868
 
      create_proto.set_type(message::Table::TEMPORARY);
869
 
    }
870
 
    else
871
 
    {
872
 
      create_proto.set_type(message::Table::STANDARD);
873
 
    }
874
 
 
875
 
    new_db_type= create_info->db_type;
876
 
 
877
 
    /**
878
 
      @todo Have a check on the table definition for FK in the future 
879
 
      to remove the need for the cursor. (aka can_switch_engines())
880
 
    */
881
 
    if (new_db_type != old_db_type &&
882
 
        not table->cursor->can_switch_engines())
883
 
    {
884
 
      assert(0);
885
 
      my_error(ER_ROW_IS_REFERENCED, MYF(0));
886
 
      goto err;
887
 
    }
888
 
 
889
 
    if (create_info->row_type == ROW_TYPE_NOT_USED)
890
 
    {
891
 
      message::Table::TableOptions *table_options;
892
 
      table_options= create_proto.mutable_options();
893
 
 
894
 
      create_info->row_type= table->s->row_type;
895
 
      table_options->set_row_type((message::Table_TableOptions_RowType)table->s->row_type);
896
 
    }
897
 
 
898
 
    if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
899
 
        new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
900
 
    {
901
 
      my_error(ER_ILLEGAL_HA, MYF(0), table_name);
902
 
      goto err;
903
 
    }
904
 
 
905
 
    session->set_proc_info("setup");
906
 
 
907
 
    /*
908
 
     * test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
909
 
   */
 
820
    create_proto.set_type(message::Table::STANDARD);
 
821
  }
 
822
 
 
823
  /**
 
824
    @todo Have a check on the table definition for FK in the future 
 
825
    to remove the need for the cursor. (aka can_switch_engines())
 
826
  */
 
827
  if (new_engine != original_engine &&
 
828
      not table->cursor->can_switch_engines())
 
829
  {
 
830
    assert(0);
 
831
    my_error(ER_ROW_IS_REFERENCED, MYF(0));
 
832
 
 
833
    return true;
 
834
  }
 
835
 
 
836
  if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
 
837
      new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
 
838
  {
 
839
    my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
 
840
 
 
841
    return true;
 
842
  }
 
843
 
 
844
  if (create_info->row_type == ROW_TYPE_NOT_USED)
 
845
  {
 
846
    message::Table::TableOptions *table_options;
 
847
    table_options= create_proto.mutable_options();
 
848
 
 
849
    create_info->row_type= table->s->row_type;
 
850
    table_options->set_row_type(original_table_definition->options().row_type());
 
851
  }
 
852
 
 
853
  session->set_proc_info("setup");
 
854
 
 
855
  /*
 
856
   * test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
 
857
 */
 
858
  {
 
859
    bitset<32> tmp;
 
860
 
910
861
    tmp.set();
911
862
    tmp.reset(ALTER_RENAME);
912
863
    tmp.reset(ALTER_KEYS_ONOFF);
913
864
    tmp&= alter_info->flags;
 
865
 
914
866
    if (! (tmp.any()) && ! table->s->tmp_table) // no need to touch frm
915
867
    {
916
868
      switch (alter_info->keys_onoff)
964
916
        access() and mysql_rename_table() calls.
965
917
      */
966
918
 
967
 
      if (error == 0 && 
968
 
          (new_name != table_name || new_db != db))
 
919
      if (error == 0 &&  not (original_table_identifier == new_table_identifier))
969
920
      {
970
921
        session->set_proc_info("rename");
971
922
        /*
981
932
          we don't take this name-lock and where this order really matters.
982
933
          @todo Investigate if we need this access() check at all.
983
934
        */
984
 
        TableIdentifier identifier(db, table_name);
985
 
        if (not plugin::StorageEngine::doesTableExist(*session, identifier))
 
935
        if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
986
936
        {
987
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
 
937
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
988
938
          error= -1;
989
939
        }
990
940
        else
991
941
        {
992
 
          *internal::fn_ext(new_name)= 0;
993
 
          if (mysql_rename_table(old_db_type, identifier, new_table_as_replacement, 0))
 
942
          if (mysql_rename_table(original_engine, original_table_identifier, new_table_identifier, 0))
994
943
          {
995
944
            error= -1;
996
945
          }
1016
965
        error= -1;
1017
966
      }
1018
967
 
1019
 
      if (name_lock)
1020
 
        session->unlink_open_table(name_lock);
1021
 
 
1022
968
      pthread_mutex_unlock(&LOCK_open);
1023
969
      table_list->table= NULL;
1024
970
 
1025
971
      return error;
1026
972
    }
1027
 
 
1028
 
    /* We have to do full alter table. */
1029
 
    new_db_type= create_info->db_type;
1030
 
 
1031
 
    if (mysql_prepare_alter_table(session, table, create_info, create_proto, alter_info))
1032
 
      goto err;
1033
 
 
1034
 
    set_table_default_charset(create_info, db);
1035
 
 
1036
 
    alter_info->build_method= HA_BUILD_OFFLINE;
1037
 
 
1038
 
    snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1039
 
 
1040
 
    /* Safety fix for innodb */
1041
 
    my_casedn_str(files_charset_info, tmp_name);
1042
 
 
1043
 
    /* Create a temporary table with the new format */
1044
 
    /**
1045
 
      @note we make an internal temporary table unless the table is a temporary table. In last
1046
 
      case we just use it as is. Neither of these tables require locks in order to  be
1047
 
      filled.
1048
 
    */
1049
 
    TableIdentifier new_table_as_temporary(new_db,
1050
 
                                           tmp_name,
1051
 
                                           create_proto.type() != message::Table::TEMPORARY ? INTERNAL_TMP_TABLE :
1052
 
                                           TEMP_TABLE);
1053
 
 
1054
 
    error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
1055
 
 
1056
 
    if (error != 0)
1057
 
      goto err;
1058
 
 
1059
 
    /* Open the table so we need to copy the data to it. */
1060
 
    new_table= open_alter_table(session, table, new_db, tmp_name);
1061
 
 
1062
 
    if (new_table == NULL)
1063
 
      goto err1;
1064
 
 
1065
 
    /* Copy the data if necessary. */
 
973
  }
 
974
 
 
975
  /* We have to do full alter table. */
 
976
  new_engine= create_info->db_type;
 
977
 
 
978
  if (mysql_prepare_alter_table(session, table, create_info, create_proto, alter_info))
 
979
  {
 
980
    return true;
 
981
  }
 
982
 
 
983
  set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
 
984
 
 
985
  alter_info->build_method= HA_BUILD_OFFLINE;
 
986
 
 
987
  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
988
 
 
989
  /* Create a temporary table with the new format */
 
990
  /**
 
991
    @note we make an internal temporary table unless the table is a temporary table. In last
 
992
    case we just use it as is. Neither of these tables require locks in order to  be
 
993
    filled.
 
994
  */
 
995
  TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
 
996
                                         tmp_name,
 
997
                                         create_proto.type() != message::Table::TEMPORARY ? INTERNAL_TMP_TABLE :
 
998
                                         TEMP_TABLE);
 
999
 
 
1000
  error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
 
1001
 
 
1002
  if (error != 0)
 
1003
  {
 
1004
    return true;
 
1005
  }
 
1006
 
 
1007
  /* Open the table so we need to copy the data to it. */
 
1008
  new_table= open_alter_table(session, table, new_table_as_temporary);
 
1009
 
 
1010
  if (not new_table)
 
1011
  {
 
1012
    quick_rm_table(*session, new_table_as_temporary);
 
1013
    return true;
 
1014
  }
 
1015
 
 
1016
  /* Copy the data if necessary. */
 
1017
  {
1066
1018
    session->count_cuted_fields= CHECK_FIELD_WARN;      // calc cuted fields
1067
1019
    session->cuted_fields= 0L;
1068
1020
    session->set_proc_info("copy to tmp table");
1069
1021
    copied= deleted= 0;
1070
1022
 
1071
 
    assert(new_table);
1072
 
 
1073
1023
    /* We don't want update TIMESTAMP fields during ALTER Table. */
1074
1024
    new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1075
1025
    new_table->next_number_field= new_table->found_next_number_field;
1086
1036
 
1087
1037
    /* We must not ignore bad input! */
1088
1038
    session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
1089
 
 
1090
 
    if (table->s->tmp_table != STANDARD_TABLE)
1091
 
    {
1092
 
      /* We changed a temporary table */
1093
 
      if (error)
1094
 
        goto err1;
1095
 
 
1096
 
      /* Close lock if this is a transactional table */
1097
 
      if (session->lock)
1098
 
      {
1099
 
        mysql_unlock_tables(session, session->lock);
1100
 
        session->lock= 0;
1101
 
      }
1102
 
 
1103
 
      /* Remove link to old table and rename the new one */
1104
 
      session->close_temporary_table(table);
1105
 
 
1106
 
      /* Should pass the 'new_name' as we store table name in the cache */
1107
 
      TableIdentifier alter_identifier(new_db, new_name);
1108
 
      if (new_table->renameAlterTemporaryTable(alter_identifier))
1109
 
        goto err1;
1110
 
    }
1111
 
    else
1112
 
    {
1113
 
      if (new_table)
1114
 
      {
1115
 
        /*
1116
 
          Close the intermediate table that will be the new table.
1117
 
          Note that MERGE tables do not have their children attached here.
1118
 
        */
1119
 
        new_table->intern_close_table();
1120
 
        free(new_table);
1121
 
      }
1122
 
 
1123
 
      pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1124
 
 
1125
 
      if (error)
1126
 
      {
1127
 
        TableIdentifier identifier(new_db, tmp_name, INTERNAL_TMP_TABLE);
1128
 
        quick_rm_table(*session, identifier);
1129
 
        pthread_mutex_unlock(&LOCK_open);
1130
 
        goto err;
1131
 
      }
1132
 
 
1133
 
      /*
1134
 
        Data is copied. Now we:
1135
 
        1) Wait until all other threads close old version of table.
1136
 
        2) Close instances of table open by this thread and replace them
1137
 
        with exclusive name-locks.
1138
 
        3) Rename the old table to a temp name, rename the new one to the
1139
 
        old name.
1140
 
        4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1141
 
        we reopen new version of table.
1142
 
        5) Write statement to the binary log.
1143
 
        6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1144
 
        remove name-locks from list of open tables and table cache.
1145
 
        7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1146
 
        call to remove name-locks from table cache and list of open table.
1147
 
      */
1148
 
 
1149
 
      session->set_proc_info("rename result table");
1150
 
 
1151
 
      snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1152
 
 
1153
 
      my_casedn_str(files_charset_info, old_name);
1154
 
 
1155
 
      wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1156
 
      session->close_data_files_and_morph_locks(db, table_name);
1157
 
 
1158
 
      error= 0;
1159
 
      save_old_db_type= old_db_type;
1160
 
 
1161
 
      /*
1162
 
        This leads to the storage engine (SE) not being notified for renames in
1163
 
        mysql_rename_table(), because we just juggle with the FRM and nothing
1164
 
        more. If we have an intermediate table, then we notify the SE that
1165
 
        it should become the actual table. Later, we will recycle the old table.
1166
 
        However, in case of ALTER Table RENAME there might be no intermediate
1167
 
        table. This is when the old and new tables are compatible, according to
1168
 
        compare_table(). Then, we need one additional call to
1169
 
      */
1170
 
      TableIdentifier original_table_to_drop(db, old_name, TEMP_TABLE);
1171
 
      if (mysql_rename_table(old_db_type, original_table_identifier, original_table_to_drop, FN_TO_IS_TMP))
1172
 
      {
1173
 
        error= 1;
1174
 
        TableIdentifier identifier(new_db, tmp_name, INTERNAL_TMP_TABLE);
1175
 
        quick_rm_table(*session, identifier);
1176
 
      }
1177
 
      else
1178
 
      {
1179
 
        if (mysql_rename_table(new_db_type, new_table_as_temporary, new_table_as_replacement, FN_FROM_IS_TMP) != 0)
1180
 
        {
1181
 
          /* Try to get everything back. */
1182
 
          error= 1;
1183
 
 
1184
 
          quick_rm_table(*session, new_table_as_replacement);
1185
 
 
1186
 
          quick_rm_table(*session, new_table_as_temporary);
1187
 
 
1188
 
          mysql_rename_table(old_db_type, original_table_to_drop, original_table_identifier, FN_FROM_IS_TMP);
1189
 
        }
1190
 
        else
1191
 
        {
1192
 
          quick_rm_table(*session, original_table_to_drop);
1193
 
        }
1194
 
      }
1195
 
 
1196
 
      if (error)
1197
 
      {
1198
 
        /*
1199
 
          An error happened while we were holding exclusive name-lock on table
1200
 
          being altered. To be safe under LOCK TABLES we should remove placeholders
1201
 
          from list of open tables list and table cache.
1202
 
        */
1203
 
        session->unlink_open_table(table);
1204
 
        if (name_lock)
1205
 
          session->unlink_open_table(name_lock);
1206
 
        pthread_mutex_unlock(&LOCK_open);
1207
 
        return true;
1208
 
      }
1209
 
 
1210
 
 
1211
 
      pthread_mutex_unlock(&LOCK_open);
1212
 
 
1213
 
      session->set_proc_info("end");
1214
 
 
1215
 
      write_bin_log(session, session->query.c_str());
1216
 
      table_list->table= NULL;
1217
 
    }
1218
 
 
1219
 
    /*
1220
 
     * Field::store() may have called my_error().  If this is 
1221
 
     * the case, we must not send an ok packet, since 
1222
 
     * Diagnostics_area::is_set() will fail an assert.
1223
 
   */
1224
 
    if (! session->is_error())
1225
 
    {
1226
 
      snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1227
 
               (ulong) (copied + deleted), (ulong) deleted,
1228
 
               (ulong) session->cuted_fields);
1229
 
      session->my_ok(copied + deleted, 0, 0L, tmp_name);
1230
 
      session->some_tables_deleted= 0;
1231
 
      return false;
1232
 
    }
1233
 
    else
1234
 
    {
1235
 
      /* my_error() was called.  Return true (which means error...) */
1236
 
      return true;
1237
 
    }
1238
 
 
1239
 
err1:
1240
 
    if (new_table)
1241
 
    {
1242
 
      /* close_temporary_table() frees the new_table pointer. */
1243
 
      session->close_temporary_table(new_table);
1244
 
    }
1245
 
    else
1246
 
    {
1247
 
      TableIdentifier tmp_identifier(new_db, tmp_name, INTERNAL_TMP_TABLE);
1248
 
      quick_rm_table(*session, tmp_identifier);
1249
 
    }
1250
1039
  }
1251
1040
 
1252
 
err:
1253
 
  /*
1254
 
    No default value was provided for a DATE/DATETIME field, the
1255
 
    current sql_mode doesn't allow the '0000-00-00' value and
1256
 
    the table to be altered isn't empty.
1257
 
    Report error here.
1258
 
  */
1259
 
  if (alter_info->error_if_not_empty && session->row_count)
 
1041
  /* Now we need to resolve what just happened with the data copy. */
 
1042
 
 
1043
  if (error)
1260
1044
  {
1261
 
    const char *f_val= 0;
1262
 
    enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1263
1045
 
1264
 
    switch (alter_info->datetime_field->sql_type)
 
1046
    /*
 
1047
      No default value was provided for a DATE/DATETIME field, the
 
1048
      current sql_mode doesn't allow the '0000-00-00' value and
 
1049
      the table to be altered isn't empty.
 
1050
      Report error here.
 
1051
    */
 
1052
    if (alter_info->error_if_not_empty && session->row_count)
1265
1053
    {
 
1054
      const char *f_val= 0;
 
1055
      enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
 
1056
 
 
1057
      switch (alter_info->datetime_field->sql_type)
 
1058
      {
1266
1059
      case DRIZZLE_TYPE_DATE:
1267
1060
        f_val= "0000-00-00";
1268
1061
        t_type= DRIZZLE_TIMESTAMP_DATE;
1274
1067
      default:
1275
1068
        /* Shouldn't get here. */
1276
1069
        assert(0);
1277
 
    }
1278
 
    bool save_abort_on_warning= session->abort_on_warning;
1279
 
    session->abort_on_warning= true;
1280
 
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1281
 
                                 f_val, internal::strlength(f_val), t_type,
1282
 
                                 alter_info->datetime_field->field_name);
1283
 
    session->abort_on_warning= save_abort_on_warning;
1284
 
  }
1285
 
 
1286
 
  if (name_lock)
1287
 
  {
1288
 
    pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1289
 
    session->unlink_open_table(name_lock);
 
1070
      }
 
1071
      bool save_abort_on_warning= session->abort_on_warning;
 
1072
      session->abort_on_warning= true;
 
1073
      make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1074
                                   f_val, internal::strlength(f_val), t_type,
 
1075
                                   alter_info->datetime_field->field_name);
 
1076
      session->abort_on_warning= save_abort_on_warning;
 
1077
    }
 
1078
 
 
1079
    if (original_table_identifier.isTmp())
 
1080
    {
 
1081
      if (new_table)
 
1082
      {
 
1083
        /* close_temporary_table() frees the new_table pointer. */
 
1084
        session->close_temporary_table(new_table);
 
1085
      }
 
1086
      else
 
1087
      {
 
1088
        quick_rm_table(*session, new_table_as_temporary);
 
1089
      }
 
1090
 
 
1091
      return true;
 
1092
    }
 
1093
    else
 
1094
    {
 
1095
      if (new_table)
 
1096
      {
 
1097
        /*
 
1098
          Close the intermediate table that will be the new table.
 
1099
          Note that MERGE tables do not have their children attached here.
 
1100
        */
 
1101
        new_table->intern_close_table();
 
1102
        free(new_table);
 
1103
      }
 
1104
 
 
1105
      pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
 
1106
 
 
1107
      quick_rm_table(*session, new_table_as_temporary);
 
1108
      pthread_mutex_unlock(&LOCK_open);
 
1109
 
 
1110
      return true;
 
1111
    }
 
1112
  }
 
1113
  // Temporary table and success
 
1114
  else if (original_table_identifier.isTmp())
 
1115
  {
 
1116
    /* Close lock if this is a transactional table */
 
1117
    if (session->lock)
 
1118
    {
 
1119
      mysql_unlock_tables(session, session->lock);
 
1120
      session->lock= 0;
 
1121
    }
 
1122
 
 
1123
    /* Remove link to old table and rename the new one */
 
1124
    session->close_temporary_table(table);
 
1125
 
 
1126
    /* Should pass the 'new_name' as we store table name in the cache */
 
1127
    if (new_table->renameAlterTemporaryTable(new_table_identifier))
 
1128
    {
 
1129
      if (new_table)
 
1130
      {
 
1131
        /* close_temporary_table() frees the new_table pointer. */
 
1132
        session->close_temporary_table(new_table);
 
1133
      }
 
1134
      else
 
1135
      {
 
1136
        quick_rm_table(*session, new_table_as_temporary);
 
1137
      }
 
1138
 
 
1139
      return true;
 
1140
    }
 
1141
  }
 
1142
  // Normal table success
 
1143
  else
 
1144
  {
 
1145
    if (new_table)
 
1146
    {
 
1147
      /*
 
1148
        Close the intermediate table that will be the new table.
 
1149
        Note that MERGE tables do not have their children attached here.
 
1150
      */
 
1151
      new_table->intern_close_table();
 
1152
      free(new_table);
 
1153
    }
 
1154
 
 
1155
    pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
 
1156
 
 
1157
    /*
 
1158
      Data is copied. Now we:
 
1159
      1) Wait until all other threads close old version of table.
 
1160
      2) Close instances of table open by this thread and replace them
 
1161
      with exclusive name-locks.
 
1162
      3) Rename the old table to a temp name, rename the new one to the
 
1163
      old name.
 
1164
      4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
 
1165
      we reopen new version of table.
 
1166
      5) Write statement to the binary log.
 
1167
      6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
 
1168
      remove name-locks from list of open tables and table cache.
 
1169
      7) If we are not not under LOCK TABLES we rely on close_thread_tables()
 
1170
      call to remove name-locks from table cache and list of open table.
 
1171
    */
 
1172
 
 
1173
    session->set_proc_info("rename result table");
 
1174
 
 
1175
    snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
1176
 
 
1177
    my_casedn_str(files_charset_info, old_name);
 
1178
 
 
1179
    wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
 
1180
    session->close_data_files_and_morph_locks(original_table_identifier);
 
1181
 
 
1182
    error= 0;
 
1183
 
 
1184
    /*
 
1185
      This leads to the storage engine (SE) not being notified for renames in
 
1186
      mysql_rename_table(), because we just juggle with the FRM and nothing
 
1187
      more. If we have an intermediate table, then we notify the SE that
 
1188
      it should become the actual table. Later, we will recycle the old table.
 
1189
      However, in case of ALTER Table RENAME there might be no intermediate
 
1190
      table. This is when the old and new tables are compatible, according to
 
1191
      compare_table(). Then, we need one additional call to
 
1192
    */
 
1193
    TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
 
1194
                                           old_name, TEMP_TABLE);
 
1195
 
 
1196
    if (mysql_rename_table(original_engine, original_table_identifier, original_table_to_drop, FN_TO_IS_TMP))
 
1197
    {
 
1198
      error= 1;
 
1199
      quick_rm_table(*session, new_table_as_temporary);
 
1200
    }
 
1201
    else
 
1202
    {
 
1203
      if (mysql_rename_table(new_engine, new_table_as_temporary, new_table_identifier, FN_FROM_IS_TMP) != 0)
 
1204
      {
 
1205
        /* Try to get everything back. */
 
1206
        error= 1;
 
1207
 
 
1208
        quick_rm_table(*session, new_table_identifier);
 
1209
 
 
1210
        quick_rm_table(*session, new_table_as_temporary);
 
1211
 
 
1212
        mysql_rename_table(original_engine, original_table_to_drop, original_table_identifier, FN_FROM_IS_TMP);
 
1213
      }
 
1214
      else
 
1215
      {
 
1216
        quick_rm_table(*session, original_table_to_drop);
 
1217
      }
 
1218
    }
 
1219
 
 
1220
    if (error)
 
1221
    {
 
1222
      /*
 
1223
        An error happened while we were holding exclusive name-lock on table
 
1224
        being altered. To be safe under LOCK TABLES we should remove placeholders
 
1225
        from list of open tables list and table cache.
 
1226
      */
 
1227
      session->unlink_open_table(table);
 
1228
      pthread_mutex_unlock(&LOCK_open);
 
1229
 
 
1230
      return true;
 
1231
    }
 
1232
 
 
1233
 
1290
1234
    pthread_mutex_unlock(&LOCK_open);
1291
 
  }
1292
 
 
1293
 
  return true;
 
1235
 
 
1236
    session->set_proc_info("end");
 
1237
 
 
1238
    write_bin_log(session, session->query.c_str());
 
1239
    table_list->table= NULL;
 
1240
  }
 
1241
 
 
1242
  /*
 
1243
   * Field::store() may have called my_error().  If this is 
 
1244
   * the case, we must not send an ok packet, since 
 
1245
   * Diagnostics_area::is_set() will fail an assert.
 
1246
 */
 
1247
  if (session->is_error())
 
1248
  {
 
1249
    /* my_error() was called.  Return true (which means error...) */
 
1250
    return true;
 
1251
  }
 
1252
 
 
1253
  snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
 
1254
           (ulong) (copied + deleted), (ulong) deleted,
 
1255
           (ulong) session->cuted_fields);
 
1256
  session->my_ok(copied + deleted, 0, 0L, tmp_name);
 
1257
  session->some_tables_deleted= 0;
 
1258
 
 
1259
  return false;
 
1260
}
 
1261
 
 
1262
bool alter_table(Session *session,
 
1263
                 TableIdentifier &original_table_identifier,
 
1264
                 TableIdentifier &new_table_identifier,
 
1265
                 HA_CREATE_INFO *create_info,
 
1266
                 message::Table &create_proto,
 
1267
                 TableList *table_list,
 
1268
                 AlterInfo *alter_info,
 
1269
                 uint32_t order_num,
 
1270
                 order_st *order,
 
1271
                 bool ignore)
 
1272
{
 
1273
  bool error;
 
1274
  Table *table;
 
1275
 
 
1276
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
 
1277
  {
 
1278
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
 
1279
    return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
 
1280
  }
 
1281
 
 
1282
  session->set_proc_info("init");
 
1283
 
 
1284
  if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
 
1285
    return true;
 
1286
 
 
1287
  session->set_proc_info("gained write lock on table");
 
1288
 
 
1289
  /* 
 
1290
    Check that we are not trying to rename to an existing table,
 
1291
    if one existed we get a lock, if we can't we error.
 
1292
  */
 
1293
  {
 
1294
    Table *name_lock= NULL;
 
1295
 
 
1296
    if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
 
1297
    {
 
1298
      return true;
 
1299
    }
 
1300
 
 
1301
    error= internal_alter_table(session,
 
1302
                                table,
 
1303
                                original_table_identifier,
 
1304
                                new_table_identifier,
 
1305
                                create_info,
 
1306
                                create_proto,
 
1307
                                table_list,
 
1308
                                alter_info,
 
1309
                                order_num,
 
1310
                                order,
 
1311
                                ignore);
 
1312
 
 
1313
    if (name_lock)
 
1314
    {
 
1315
      pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
 
1316
      session->unlink_open_table(name_lock);
 
1317
      pthread_mutex_unlock(&LOCK_open);
 
1318
    }
 
1319
  }
 
1320
 
 
1321
  return error;
1294
1322
}
1295
1323
/* alter_table */
1296
1324
 
1390
1418
                                              (optimizer::SqlSelect *) 0, HA_POS_ERROR,
1391
1419
                                              1, &examined_rows)) ==
1392
1420
          HA_POS_ERROR)
 
1421
      {
1393
1422
        goto err;
 
1423
      }
1394
1424
    }
1395
 
  };
 
1425
  }
1396
1426
 
1397
1427
  /* Tell handler that we have values for all columns in the to table */
1398
1428
  to->use_all_columns();
1502
1532
  return error;
1503
1533
}
1504
1534
 
1505
 
static Table *open_alter_table(Session *session, Table *table, char *db, char *table_name)
 
1535
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
1506
1536
{
1507
1537
  Table *new_table;
1508
1538
 
1510
1540
  if (table->s->tmp_table)
1511
1541
  {
1512
1542
    TableList tbl;
1513
 
    tbl.db= db;
1514
 
    tbl.alias= table_name;
1515
 
    tbl.table_name= table_name;
 
1543
    tbl.db= const_cast<char *>(identifier.getSchemaName().c_str());
 
1544
    tbl.alias= const_cast<char *>(identifier.getTableName().c_str());
 
1545
    tbl.table_name= const_cast<char *>(identifier.getTableName().c_str());
1516
1546
 
1517
1547
    /* Table is in session->temporary_tables */
1518
1548
    new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
1519
1549
  }
1520
1550
  else
1521
1551
  {
1522
 
    TableIdentifier new_identifier(db, table_name, INTERNAL_TMP_TABLE);
1523
 
 
1524
1552
    /* Open our intermediate table */
1525
 
    new_table= session->open_temporary_table(new_identifier, false);
 
1553
    new_table= session->open_temporary_table(identifier, false);
1526
1554
  }
1527
1555
 
1528
1556
  return new_table;