00001 /* Copyright (C) 2000-2004 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* drop and alter of tables */ 00018 00019 #include "mysql_priv.h" 00020 #include <hash.h> 00021 #include <myisam.h> 00022 #include <my_dir.h> 00023 #include "sp_head.h" 00024 #include "sql_trigger.h" 00025 #include "sql_show.h" 00026 00027 #ifdef __WIN__ 00028 #include <io.h> 00029 #endif 00030 00031 int creating_table= 0; // How many mysql_create_table are running 00032 00033 const char *primary_key_name="PRIMARY"; 00034 00035 static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end); 00036 static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end); 00037 static int copy_data_between_tables(TABLE *from,TABLE *to, 00038 List<create_field> &create, bool ignore, 00039 uint order_num, ORDER *order, 00040 ha_rows *copied,ha_rows *deleted); 00041 static bool prepare_blob_field(THD *thd, create_field *sql_field); 00042 static bool check_engine(THD *thd, const char *table_name, 00043 HA_CREATE_INFO *create_info); 00044 static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, 00045 List<create_field> *fields, 00046 List<Key> *keys, bool tmp_table, 00047 uint *db_options, 00048 handler *file, KEY **key_info_buffer, 00049 uint *key_count, int select_field_count); 00050 00051 #define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" 00052 #define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9 00053 00054 00055 /* 00056 Translate a file name to a table name (WL #1324). 00057 00058 SYNOPSIS 00059 filename_to_tablename() 00060 from The file name in my_charset_filename. 00061 to OUT The table name in system_charset_info. 00062 to_length The size of the table name buffer. 00063 00064 RETURN 00065 Table name length. 00066 */ 00067 00068 uint filename_to_tablename(const char *from, char *to, uint to_length) 00069 { 00070 uint errors; 00071 uint res; 00072 DBUG_ENTER("filename_to_tablename"); 00073 DBUG_PRINT("enter", ("from '%s'", from)); 00074 00075 if (!memcmp(from, tmp_file_prefix, tmp_file_prefix_length)) 00076 { 00077 /* Temporary table name. */ 00078 res= (strnmov(to, from, to_length) - to); 00079 } 00080 else 00081 { 00082 res= strconvert(&my_charset_filename, from, 00083 system_charset_info, to, to_length, &errors); 00084 if (errors) // Old 5.0 name 00085 { 00086 res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) - 00087 to); 00088 sql_print_error("Invalid (old?) table or database name '%s'", from); 00089 /* 00090 TODO: add a stored procedure for fix table and database names, 00091 and mention its name in error log. 00092 */ 00093 } 00094 } 00095 00096 DBUG_PRINT("exit", ("to '%s'", to)); 00097 DBUG_RETURN(res); 00098 } 00099 00100 00101 /* 00102 Translate a table name to a file name (WL #1324). 00103 00104 SYNOPSIS 00105 tablename_to_filename() 00106 from The table name in system_charset_info. 00107 to OUT The file name in my_charset_filename. 00108 to_length The size of the file name buffer. 00109 00110 RETURN 00111 File name length. 00112 */ 00113 00114 uint tablename_to_filename(const char *from, char *to, uint to_length) 00115 { 00116 uint errors, length; 00117 DBUG_ENTER("tablename_to_filename"); 00118 DBUG_PRINT("enter", ("from '%s'", from)); 00119 00120 if (from[0] == '#' && !strncmp(from, MYSQL50_TABLE_NAME_PREFIX, 00121 MYSQL50_TABLE_NAME_PREFIX_LENGTH)) 00122 DBUG_RETURN((uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH, 00123 to_length-1) - 00124 (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH))); 00125 length= strconvert(system_charset_info, from, 00126 &my_charset_filename, to, to_length, &errors); 00127 if (check_if_legal_tablename(to) && 00128 length + 4 < to_length) 00129 { 00130 memcpy(to + length, "@@@", 4); 00131 length+= 3; 00132 } 00133 DBUG_PRINT("exit", ("to '%s'", to)); 00134 DBUG_RETURN(length); 00135 } 00136 00137 00138 /* 00139 Creates path to a file: mysql_data_dir/db/table.ext 00140 00141 SYNOPSIS 00142 build_table_filename() 00143 buff Where to write result in my_charset_filename. 00144 bufflen buff size 00145 db Database name in system_charset_info. 00146 table_name Table name in system_charset_info. 00147 ext File extension. 00148 flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP 00149 table_name is temporary, do not change. 00150 00151 NOTES 00152 00153 Uses database and table name, and extension to create 00154 a file name in mysql_data_dir. Database and table 00155 names are converted from system_charset_info into "fscs". 00156 Unless flags indicate a temporary table name. 00157 'db' is always converted. 00158 'ext' is not converted. 00159 00160 The conversion suppression is required for ALTER TABLE. This 00161 statement creates intermediate tables. These are regular 00162 (non-temporary) tables with a temporary name. Their path names must 00163 be derivable from the table name. So we cannot use 00164 build_tmptable_filename() for them. 00165 00166 RETURN 00167 path length 00168 */ 00169 00170 uint build_table_filename(char *buff, size_t bufflen, const char *db, 00171 const char *table_name, const char *ext, uint flags) 00172 { 00173 uint length; 00174 char dbbuff[FN_REFLEN]; 00175 char tbbuff[FN_REFLEN]; 00176 DBUG_ENTER("build_table_filename"); 00177 00178 if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP 00179 strnmov(tbbuff, table_name, sizeof(tbbuff)); 00180 else 00181 VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff))); 00182 00183 VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff))); 00184 length= strxnmov(buff, bufflen, mysql_data_home, "/", dbbuff, 00185 "/", tbbuff, ext, NullS) - buff; 00186 DBUG_PRINT("exit", ("buff: '%s'", buff)); 00187 DBUG_RETURN(length); 00188 } 00189 00190 00191 /* 00192 Creates path to a file: mysql_tmpdir/#sql1234_12_1.ext 00193 00194 SYNOPSIS 00195 build_tmptable_filename() 00196 thd The thread handle. 00197 buff Where to write result in my_charset_filename. 00198 bufflen buff size 00199 00200 NOTES 00201 00202 Uses current_pid, thread_id, and tmp_table counter to create 00203 a file name in mysql_tmpdir. 00204 00205 RETURN 00206 path length 00207 */ 00208 00209 uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen) 00210 { 00211 uint length; 00212 char tmp_table_name[tmp_file_prefix_length+22+22+22+3]; 00213 DBUG_ENTER("build_tmptable_filename"); 00214 00215 my_snprintf(tmp_table_name, sizeof(tmp_table_name), 00216 "%s%lx_%lx_%x", 00217 tmp_file_prefix, current_pid, 00218 thd->thread_id, thd->tmp_table++); 00219 00220 strxnmov(buff, bufflen, mysql_tmpdir, "/", tmp_table_name, reg_ext, NullS); 00221 length= unpack_filename(buff, buff); 00222 DBUG_PRINT("exit", ("buff: '%s'", buff)); 00223 DBUG_RETURN(length); 00224 } 00225 00226 /* 00227 Return values for compare_tables(). 00228 If you make compare_tables() non-static, move them to a header file. 00229 */ 00230 #define ALTER_TABLE_DATA_CHANGED 1 00231 #define ALTER_TABLE_INDEX_CHANGED 2 00232 00233 00234 /* 00235 SYNOPSIS 00236 mysql_copy_create_list() 00237 orig_create_list Original list of created fields 00238 inout::new_create_list Copy of original list 00239 00240 RETURN VALUES 00241 FALSE Success 00242 TRUE Memory allocation error 00243 00244 DESCRIPTION 00245 mysql_prepare_table destroys the create_list and in some cases we need 00246 this lists for more purposes. Thus we copy it specifically for use 00247 by mysql_prepare_table 00248 */ 00249 00250 static int mysql_copy_create_list(List<create_field> *orig_create_list, 00251 List<create_field> *new_create_list) 00252 { 00253 List_iterator<create_field> prep_field_it(*orig_create_list); 00254 create_field *prep_field; 00255 DBUG_ENTER("mysql_copy_create_list"); 00256 00257 while ((prep_field= prep_field_it++)) 00258 { 00259 create_field *field= new create_field(*prep_field); 00260 if (!field || new_create_list->push_back(field)) 00261 { 00262 mem_alloc_error(2); 00263 DBUG_RETURN(TRUE); 00264 } 00265 } 00266 DBUG_RETURN(FALSE); 00267 } 00268 00269 00270 /* 00271 SYNOPSIS 00272 mysql_copy_key_list() 00273 orig_key Original list of keys 00274 inout::new_key Copy of original list 00275 00276 RETURN VALUES 00277 FALSE Success 00278 TRUE Memory allocation error 00279 00280 DESCRIPTION 00281 mysql_prepare_table destroys the key list and in some cases we need 00282 this lists for more purposes. Thus we copy it specifically for use 00283 by mysql_prepare_table 00284 */ 00285 00286 static int mysql_copy_key_list(List<Key> *orig_key, 00287 List<Key> *new_key) 00288 { 00289 List_iterator<Key> prep_key_it(*orig_key); 00290 Key *prep_key; 00291 DBUG_ENTER("mysql_copy_key_list"); 00292 00293 while ((prep_key= prep_key_it++)) 00294 { 00295 List<key_part_spec> prep_columns; 00296 List_iterator<key_part_spec> prep_col_it(prep_key->columns); 00297 key_part_spec *prep_col; 00298 Key *temp_key; 00299 00300 while ((prep_col= prep_col_it++)) 00301 { 00302 key_part_spec *prep_key_part; 00303 00304 if (!(prep_key_part= new key_part_spec(*prep_col))) 00305 { 00306 mem_alloc_error(sizeof(key_part_spec)); 00307 DBUG_RETURN(TRUE); 00308 } 00309 if (prep_columns.push_back(prep_key_part)) 00310 { 00311 mem_alloc_error(2); 00312 DBUG_RETURN(TRUE); 00313 } 00314 } 00315 if (!(temp_key= new Key(prep_key->type, prep_key->name, 00316 &prep_key->key_create_info, 00317 prep_key->generated, 00318 prep_columns))) 00319 { 00320 mem_alloc_error(sizeof(Key)); 00321 DBUG_RETURN(TRUE); 00322 } 00323 if (new_key->push_back(temp_key)) 00324 { 00325 mem_alloc_error(2); 00326 DBUG_RETURN(TRUE); 00327 } 00328 } 00329 DBUG_RETURN(FALSE); 00330 } 00331 00332 /* 00333 -------------------------------------------------------------------------- 00334 00335 MODULE: DDL log 00336 ----------------- 00337 00338 This module is used to ensure that we can recover from crashes that occur 00339 in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2; 00340 We need to ensure that both t1 and t2 are dropped and not only t1 and 00341 also that each table drop is entirely done and not "half-baked". 00342 00343 To support this we create log entries for each meta-data statement in the 00344 ddl log while we are executing. These entries are dropped when the 00345 operation is completed. 00346 00347 At recovery those entries that were not completed will be executed. 00348 00349 There is only one ddl log in the system and it is protected by a mutex 00350 and there is a global struct that contains information about its current 00351 state. 00352 00353 History: 00354 First version written in 2006 by Mikael Ronstrom 00355 -------------------------------------------------------------------------- 00356 */ 00357 00358 00359 typedef struct st_global_ddl_log 00360 { 00361 /* 00362 We need to adjust buffer size to be able to handle downgrades/upgrades 00363 where IO_SIZE has changed. We'll set the buffer size such that we can 00364 handle that the buffer size was upto 4 times bigger in the version 00365 that wrote the DDL log. 00366 */ 00367 char file_entry_buf[4*IO_SIZE]; 00368 char file_name_str[FN_REFLEN]; 00369 char *file_name; 00370 DDL_LOG_MEMORY_ENTRY *first_free; 00371 DDL_LOG_MEMORY_ENTRY *first_used; 00372 uint num_entries; 00373 File file_id; 00374 uint name_len; 00375 uint io_size; 00376 bool inited; 00377 bool recovery_phase; 00378 } GLOBAL_DDL_LOG; 00379 00380 GLOBAL_DDL_LOG global_ddl_log; 00381 00382 pthread_mutex_t LOCK_gdl; 00383 00384 #define DDL_LOG_ENTRY_TYPE_POS 0 00385 #define DDL_LOG_ACTION_TYPE_POS 1 00386 #define DDL_LOG_PHASE_POS 2 00387 #define DDL_LOG_NEXT_ENTRY_POS 4 00388 #define DDL_LOG_NAME_POS 8 00389 00390 #define DDL_LOG_NUM_ENTRY_POS 0 00391 #define DDL_LOG_NAME_LEN_POS 4 00392 #define DDL_LOG_IO_SIZE_POS 8 00393 00394 /* 00395 Read one entry from ddl log file 00396 SYNOPSIS 00397 read_ddl_log_file_entry() 00398 entry_no Entry number to read 00399 RETURN VALUES 00400 TRUE Error 00401 FALSE Success 00402 */ 00403 00404 static bool read_ddl_log_file_entry(uint entry_no) 00405 { 00406 bool error= FALSE; 00407 File file_id= global_ddl_log.file_id; 00408 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; 00409 uint io_size= global_ddl_log.io_size; 00410 DBUG_ENTER("read_ddl_log_file_entry"); 00411 00412 if (my_pread(file_id, (byte*)file_entry_buf, io_size, io_size * entry_no, 00413 MYF(MY_WME)) != io_size) 00414 error= TRUE; 00415 DBUG_RETURN(error); 00416 } 00417 00418 00419 /* 00420 Write one entry from ddl log file 00421 SYNOPSIS 00422 write_ddl_log_file_entry() 00423 entry_no Entry number to read 00424 RETURN VALUES 00425 TRUE Error 00426 FALSE Success 00427 */ 00428 00429 static bool write_ddl_log_file_entry(uint entry_no) 00430 { 00431 bool error= FALSE; 00432 File file_id= global_ddl_log.file_id; 00433 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; 00434 DBUG_ENTER("write_ddl_log_file_entry"); 00435 00436 if (my_pwrite(file_id, (byte*)file_entry_buf, 00437 IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) 00438 error= TRUE; 00439 DBUG_RETURN(error); 00440 } 00441 00442 00443 /* 00444 Write ddl log header 00445 SYNOPSIS 00446 write_ddl_log_header() 00447 RETURN VALUES 00448 TRUE Error 00449 FALSE Success 00450 */ 00451 00452 static bool write_ddl_log_header() 00453 { 00454 uint16 const_var; 00455 bool error= FALSE; 00456 DBUG_ENTER("write_ddl_log_header"); 00457 00458 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS], 00459 global_ddl_log.num_entries); 00460 const_var= FN_LEN; 00461 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], 00462 const_var); 00463 const_var= IO_SIZE; 00464 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], 00465 const_var); 00466 if (write_ddl_log_file_entry(0UL)) 00467 { 00468 sql_print_error("Error writing ddl log header"); 00469 DBUG_RETURN(TRUE); 00470 } 00471 VOID(sync_ddl_log()); 00472 DBUG_RETURN(error); 00473 } 00474 00475 00476 /* 00477 Create ddl log file name 00478 SYNOPSIS 00479 create_ddl_log_file_name() 00480 file_name Filename setup 00481 RETURN VALUES 00482 NONE 00483 */ 00484 00485 static inline void create_ddl_log_file_name(char *file_name) 00486 { 00487 strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS); 00488 } 00489 00490 00491 /* 00492 Read header of ddl log file 00493 SYNOPSIS 00494 read_ddl_log_header() 00495 RETURN VALUES 00496 > 0 Last entry in ddl log 00497 0 No entries in ddl log 00498 DESCRIPTION 00499 When we read the ddl log header we get information about maximum sizes 00500 of names in the ddl log and we also get information about the number 00501 of entries in the ddl log. 00502 */ 00503 00504 static uint read_ddl_log_header() 00505 { 00506 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; 00507 char file_name[FN_REFLEN]; 00508 uint entry_no; 00509 bool successful_open= FALSE; 00510 DBUG_ENTER("read_ddl_log_header"); 00511 00512 create_ddl_log_file_name(file_name); 00513 if ((global_ddl_log.file_id= my_open(file_name, 00514 O_RDWR | O_BINARY, MYF(MY_WME))) >= 0) 00515 { 00516 if (read_ddl_log_file_entry(0UL)) 00517 { 00518 /* Write message into error log */ 00519 sql_print_error("Failed to read ddl log file in recovery"); 00520 } 00521 else 00522 successful_open= TRUE; 00523 } 00524 entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); 00525 global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); 00526 if (successful_open) 00527 { 00528 global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); 00529 DBUG_ASSERT(global_ddl_log.io_size <= 00530 sizeof(global_ddl_log.file_entry_buf)); 00531 } 00532 else 00533 { 00534 entry_no= 0; 00535 } 00536 global_ddl_log.first_free= NULL; 00537 global_ddl_log.first_used= NULL; 00538 global_ddl_log.num_entries= 0; 00539 VOID(pthread_mutex_init(&LOCK_gdl, MY_MUTEX_INIT_FAST)); 00540 DBUG_RETURN(entry_no); 00541 } 00542 00543 00544 /* 00545 Read a ddl log entry 00546 SYNOPSIS 00547 read_ddl_log_entry() 00548 read_entry Number of entry to read 00549 out:entry_info Information from entry 00550 RETURN VALUES 00551 TRUE Error 00552 FALSE Success 00553 DESCRIPTION 00554 Read a specified entry in the ddl log 00555 */ 00556 00557 bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) 00558 { 00559 char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; 00560 uint inx; 00561 uchar single_char; 00562 DBUG_ENTER("read_ddl_log_entry"); 00563 00564 if (read_ddl_log_file_entry(read_entry)) 00565 { 00566 DBUG_RETURN(TRUE); 00567 } 00568 ddl_log_entry->entry_pos= read_entry; 00569 single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; 00570 ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char; 00571 single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; 00572 ddl_log_entry->action_type= (enum ddl_log_action_code)single_char; 00573 ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; 00574 ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); 00575 ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; 00576 inx= DDL_LOG_NAME_POS + global_ddl_log.name_len; 00577 ddl_log_entry->from_name= &file_entry_buf[inx]; 00578 inx+= global_ddl_log.name_len; 00579 ddl_log_entry->handler_name= &file_entry_buf[inx]; 00580 DBUG_RETURN(FALSE); 00581 } 00582 00583 00584 /* 00585 Initialise ddl log 00586 SYNOPSIS 00587 init_ddl_log() 00588 00589 DESCRIPTION 00590 Write the header of the ddl log file and length of names. Also set 00591 number of entries to zero. 00592 00593 RETURN VALUES 00594 TRUE Error 00595 FALSE Success 00596 */ 00597 00598 static bool init_ddl_log() 00599 { 00600 bool error= FALSE; 00601 char file_name[FN_REFLEN]; 00602 DBUG_ENTER("init_ddl_log"); 00603 00604 if (global_ddl_log.inited) 00605 goto end; 00606 00607 global_ddl_log.io_size= IO_SIZE; 00608 create_ddl_log_file_name(file_name); 00609 if ((global_ddl_log.file_id= my_create(file_name, 00610 CREATE_MODE, 00611 O_RDWR | O_TRUNC | O_BINARY, 00612 MYF(MY_WME))) < 0) 00613 { 00614 /* Couldn't create ddl log file, this is serious error */ 00615 sql_print_error("Failed to open ddl log file"); 00616 DBUG_RETURN(TRUE); 00617 } 00618 global_ddl_log.inited= TRUE; 00619 if (write_ddl_log_header()) 00620 { 00621 VOID(my_close(global_ddl_log.file_id, MYF(MY_WME))); 00622 global_ddl_log.inited= FALSE; 00623 DBUG_RETURN(TRUE); 00624 } 00625 00626 end: 00627 DBUG_RETURN(FALSE); 00628 } 00629 00630 00631 /* 00632 Execute one action in a ddl log entry 00633 SYNOPSIS 00634 execute_ddl_log_action() 00635 ddl_log_entry Information in action entry to execute 00636 RETURN VALUES 00637 TRUE Error 00638 FALSE Success 00639 */ 00640 00641 static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) 00642 { 00643 bool frm_action= FALSE; 00644 LEX_STRING handler_name; 00645 handler *file= NULL; 00646 MEM_ROOT mem_root; 00647 int error= TRUE; 00648 char to_path[FN_REFLEN]; 00649 char from_path[FN_REFLEN]; 00650 char *par_ext= (char*)".par"; 00651 handlerton *hton; 00652 DBUG_ENTER("execute_ddl_log_action"); 00653 00654 if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE) 00655 { 00656 DBUG_RETURN(FALSE); 00657 } 00658 handler_name.str= (char*)ddl_log_entry->handler_name; 00659 handler_name.length= strlen(ddl_log_entry->handler_name); 00660 init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); 00661 if (!strcmp(ddl_log_entry->handler_name, reg_ext)) 00662 frm_action= TRUE; 00663 else 00664 { 00665 TABLE_SHARE dummy; 00666 00667 hton= ha_resolve_by_name(thd, &handler_name); 00668 if (!hton) 00669 { 00670 my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); 00671 goto error; 00672 } 00673 bzero(&dummy, sizeof(TABLE_SHARE)); 00674 file= get_new_handler(&dummy, &mem_root, hton); 00675 if (!file) 00676 { 00677 mem_alloc_error(sizeof(handler)); 00678 goto error; 00679 } 00680 } 00681 switch (ddl_log_entry->action_type) 00682 { 00683 case DDL_LOG_REPLACE_ACTION: 00684 case DDL_LOG_DELETE_ACTION: 00685 { 00686 if (ddl_log_entry->phase == 0) 00687 { 00688 if (frm_action) 00689 { 00690 strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); 00691 if ((error= my_delete(to_path, MYF(MY_WME)))) 00692 { 00693 if (my_errno != ENOENT) 00694 break; 00695 } 00696 #ifdef WITH_PARTITION_STORAGE_ENGINE 00697 strxmov(to_path, ddl_log_entry->name, par_ext, NullS); 00698 VOID(my_delete(to_path, MYF(MY_WME))); 00699 #endif 00700 } 00701 else 00702 { 00703 if ((error= file->delete_table(ddl_log_entry->name))) 00704 { 00705 if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE) 00706 break; 00707 } 00708 } 00709 if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) 00710 break; 00711 VOID(sync_ddl_log()); 00712 error= FALSE; 00713 if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) 00714 break; 00715 } 00716 DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION); 00717 /* 00718 Fall through and perform the rename action of the replace 00719 action. We have already indicated the success of the delete 00720 action in the log entry by stepping up the phase. 00721 */ 00722 } 00723 case DDL_LOG_RENAME_ACTION: 00724 { 00725 error= TRUE; 00726 if (frm_action) 00727 { 00728 strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); 00729 strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); 00730 if (my_rename(from_path, to_path, MYF(MY_WME))) 00731 break; 00732 #ifdef WITH_PARTITION_STORAGE_ENGINE 00733 strxmov(to_path, ddl_log_entry->name, par_ext, NullS); 00734 strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); 00735 VOID(my_rename(from_path, to_path, MYF(MY_WME))); 00736 #endif 00737 } 00738 else 00739 { 00740 if (file->rename_table(ddl_log_entry->from_name, 00741 ddl_log_entry->name)) 00742 break; 00743 } 00744 if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) 00745 break; 00746 VOID(sync_ddl_log()); 00747 error= FALSE; 00748 break; 00749 } 00750 default: 00751 DBUG_ASSERT(0); 00752 break; 00753 } 00754 delete file; 00755 error: 00756 free_root(&mem_root, MYF(0)); 00757 DBUG_RETURN(error); 00758 } 00759 00760 00761 /* 00762 Get a free entry in the ddl log 00763 SYNOPSIS 00764 get_free_ddl_log_entry() 00765 out:active_entry A ddl log memory entry returned 00766 RETURN VALUES 00767 TRUE Error 00768 FALSE Success 00769 */ 00770 00771 static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, 00772 bool *write_header) 00773 { 00774 DDL_LOG_MEMORY_ENTRY *used_entry; 00775 DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; 00776 DBUG_ENTER("get_free_ddl_log_entry"); 00777 00778 if (global_ddl_log.first_free == NULL) 00779 { 00780 if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( 00781 sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) 00782 { 00783 sql_print_error("Failed to allocate memory for ddl log free list"); 00784 DBUG_RETURN(TRUE); 00785 } 00786 global_ddl_log.num_entries++; 00787 used_entry->entry_pos= global_ddl_log.num_entries; 00788 *write_header= TRUE; 00789 } 00790 else 00791 { 00792 used_entry= global_ddl_log.first_free; 00793 global_ddl_log.first_free= used_entry->next_log_entry; 00794 *write_header= FALSE; 00795 } 00796 /* 00797 Move from free list to used list 00798 */ 00799 used_entry->next_log_entry= first_used; 00800 used_entry->prev_log_entry= NULL; 00801 global_ddl_log.first_used= used_entry; 00802 if (first_used) 00803 first_used->prev_log_entry= used_entry; 00804 00805 *active_entry= used_entry; 00806 DBUG_RETURN(FALSE); 00807 } 00808 00809 00810 /* 00811 External interface methods for the DDL log Module 00812 --------------------------------------------------- 00813 */ 00814 00815 /* 00816 SYNOPSIS 00817 write_ddl_log_entry() 00818 ddl_log_entry Information about log entry 00819 out:entry_written Entry information written into 00820 00821 RETURN VALUES 00822 TRUE Error 00823 FALSE Success 00824 00825 DESCRIPTION 00826 A careful write of the ddl log is performed to ensure that we can 00827 handle crashes occurring during CREATE and ALTER TABLE processing. 00828 */ 00829 00830 bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, 00831 DDL_LOG_MEMORY_ENTRY **active_entry) 00832 { 00833 bool error, write_header; 00834 DBUG_ENTER("write_ddl_log_entry"); 00835 00836 if (init_ddl_log()) 00837 { 00838 DBUG_RETURN(TRUE); 00839 } 00840 global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= 00841 (char)DDL_LOG_ENTRY_CODE; 00842 global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 00843 (char)ddl_log_entry->action_type; 00844 global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; 00845 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], 00846 ddl_log_entry->next_entry); 00847 DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN); 00848 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], 00849 ddl_log_entry->name, FN_LEN - 1); 00850 if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION || 00851 ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION) 00852 { 00853 DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN); 00854 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], 00855 ddl_log_entry->from_name, FN_LEN - 1); 00856 } 00857 else 00858 global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; 00859 DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN); 00860 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], 00861 ddl_log_entry->handler_name, FN_LEN - 1); 00862 if (get_free_ddl_log_entry(active_entry, &write_header)) 00863 { 00864 DBUG_RETURN(TRUE); 00865 } 00866 error= FALSE; 00867 if (write_ddl_log_file_entry((*active_entry)->entry_pos)) 00868 { 00869 error= TRUE; 00870 sql_print_error("Failed to write entry_no = %u", 00871 (*active_entry)->entry_pos); 00872 } 00873 if (write_header && !error) 00874 { 00875 VOID(sync_ddl_log()); 00876 if (write_ddl_log_header()) 00877 error= TRUE; 00878 } 00879 if (error) 00880 release_ddl_log_memory_entry(*active_entry); 00881 DBUG_RETURN(error); 00882 } 00883 00884 00885 /* 00886 Write final entry in the ddl log 00887 SYNOPSIS 00888 write_execute_ddl_log_entry() 00889 first_entry First entry in linked list of entries 00890 to execute, if 0 = NULL it means that 00891 the entry is removed and the entries 00892 are put into the free list. 00893 complete Flag indicating we are simply writing 00894 info about that entry has been completed 00895 in:out:active_entry Entry to execute, 0 = NULL if the entry 00896 is written first time and needs to be 00897 returned. In this case the entry written 00898 is returned in this parameter 00899 RETURN VALUES 00900 TRUE Error 00901 FALSE Success 00902 00903 DESCRIPTION 00904 This is the last write in the ddl log. The previous log entries have 00905 already been written but not yet synched to disk. 00906 We write a couple of log entries that describes action to perform. 00907 This entries are set-up in a linked list, however only when a first 00908 execute entry is put as the first entry these will be executed. 00909 This routine writes this first 00910 */ 00911 00912 bool write_execute_ddl_log_entry(uint first_entry, 00913 bool complete, 00914 DDL_LOG_MEMORY_ENTRY **active_entry) 00915 { 00916 bool write_header= FALSE; 00917 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; 00918 DBUG_ENTER("write_execute_ddl_log_entry"); 00919 00920 if (init_ddl_log()) 00921 { 00922 DBUG_RETURN(TRUE); 00923 } 00924 if (!complete) 00925 { 00926 /* 00927 We haven't synched the log entries yet, we synch them now before 00928 writing the execute entry. If complete is true we haven't written 00929 any log entries before, we are only here to write the execute 00930 entry to indicate it is done. 00931 */ 00932 VOID(sync_ddl_log()); 00933 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE; 00934 } 00935 else 00936 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE; 00937 file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ 00938 file_entry_buf[DDL_LOG_PHASE_POS]= 0; 00939 int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); 00940 file_entry_buf[DDL_LOG_NAME_POS]= 0; 00941 file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; 00942 file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0; 00943 if (!(*active_entry)) 00944 { 00945 if (get_free_ddl_log_entry(active_entry, &write_header)) 00946 { 00947 DBUG_RETURN(TRUE); 00948 } 00949 } 00950 if (write_ddl_log_file_entry((*active_entry)->entry_pos)) 00951 { 00952 sql_print_error("Error writing execute entry in ddl log"); 00953 release_ddl_log_memory_entry(*active_entry); 00954 DBUG_RETURN(TRUE); 00955 } 00956 VOID(sync_ddl_log()); 00957 if (write_header) 00958 { 00959 if (write_ddl_log_header()) 00960 { 00961 release_ddl_log_memory_entry(*active_entry); 00962 DBUG_RETURN(TRUE); 00963 } 00964 } 00965 DBUG_RETURN(FALSE); 00966 } 00967 00968 00969 /* 00970 For complex rename operations we need to deactivate individual entries. 00971 SYNOPSIS 00972 deactivate_ddl_log_entry() 00973 entry_no Entry position of record to change 00974 RETURN VALUES 00975 TRUE Error 00976 FALSE Success 00977 DESCRIPTION 00978 During replace operations where we start with an existing table called 00979 t1 and a replacement table called t1#temp or something else and where 00980 we want to delete t1 and rename t1#temp to t1 this is not possible to 00981 do in a safe manner unless the ddl log is informed of the phases in 00982 the change. 00983 00984 Delete actions are 1-phase actions that can be ignored immediately after 00985 being executed. 00986 Rename actions from x to y is also a 1-phase action since there is no 00987 interaction with any other handlers named x and y. 00988 Replace action where drop y and x -> y happens needs to be a two-phase 00989 action. Thus the first phase will drop y and the second phase will 00990 rename x -> y. 00991 */ 00992 00993 bool deactivate_ddl_log_entry(uint entry_no) 00994 { 00995 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; 00996 DBUG_ENTER("deactivate_ddl_log_entry"); 00997 00998 if (!read_ddl_log_file_entry(entry_no)) 00999 { 01000 if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE) 01001 { 01002 if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION || 01003 file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION || 01004 (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION && 01005 file_entry_buf[DDL_LOG_PHASE_POS] == 1)) 01006 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; 01007 else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION) 01008 { 01009 DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0); 01010 file_entry_buf[DDL_LOG_PHASE_POS]= 1; 01011 } 01012 else 01013 { 01014 DBUG_ASSERT(0); 01015 } 01016 if (write_ddl_log_file_entry(entry_no)) 01017 { 01018 sql_print_error("Error in deactivating log entry. Position = %u", 01019 entry_no); 01020 DBUG_RETURN(TRUE); 01021 } 01022 } 01023 } 01024 else 01025 { 01026 sql_print_error("Failed in reading entry before deactivating it"); 01027 DBUG_RETURN(TRUE); 01028 } 01029 DBUG_RETURN(FALSE); 01030 } 01031 01032 01033 /* 01034 Sync ddl log file 01035 SYNOPSIS 01036 sync_ddl_log() 01037 RETURN VALUES 01038 TRUE Error 01039 FALSE Success 01040 */ 01041 01042 bool sync_ddl_log() 01043 { 01044 bool error= FALSE; 01045 DBUG_ENTER("sync_ddl_log"); 01046 01047 if ((!global_ddl_log.recovery_phase) && 01048 init_ddl_log()) 01049 { 01050 DBUG_RETURN(TRUE); 01051 } 01052 if (my_sync(global_ddl_log.file_id, MYF(0))) 01053 { 01054 /* Write to error log */ 01055 sql_print_error("Failed to sync ddl log"); 01056 error= TRUE; 01057 } 01058 DBUG_RETURN(error); 01059 } 01060 01061 01062 /* 01063 Release a log memory entry 01064 SYNOPSIS 01065 release_ddl_log_memory_entry() 01066 log_memory_entry Log memory entry to release 01067 RETURN VALUES 01068 NONE 01069 */ 01070 01071 void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) 01072 { 01073 DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free; 01074 DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; 01075 DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; 01076 DBUG_ENTER("release_ddl_log_memory_entry"); 01077 01078 global_ddl_log.first_free= log_entry; 01079 log_entry->next_log_entry= first_free; 01080 01081 if (prev_log_entry) 01082 prev_log_entry->next_log_entry= next_log_entry; 01083 else 01084 global_ddl_log.first_used= next_log_entry; 01085 if (next_log_entry) 01086 next_log_entry->prev_log_entry= prev_log_entry; 01087 DBUG_VOID_RETURN; 01088 } 01089 01090 01091 /* 01092 Execute one entry in the ddl log. Executing an entry means executing 01093 a linked list of actions. 01094 SYNOPSIS 01095 execute_ddl_log_entry() 01096 first_entry Reference to first action in entry 01097 RETURN VALUES 01098 TRUE Error 01099 FALSE Success 01100 */ 01101 01102 bool execute_ddl_log_entry(THD *thd, uint first_entry) 01103 { 01104 DDL_LOG_ENTRY ddl_log_entry; 01105 uint read_entry= first_entry; 01106 DBUG_ENTER("execute_ddl_log_entry"); 01107 01108 pthread_mutex_lock(&LOCK_gdl); 01109 do 01110 { 01111 if (read_ddl_log_entry(read_entry, &ddl_log_entry)) 01112 { 01113 /* Write to error log and continue with next log entry */ 01114 sql_print_error("Failed to read entry = %u from ddl log", 01115 read_entry); 01116 break; 01117 } 01118 DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || 01119 ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); 01120 01121 if (execute_ddl_log_action(thd, &ddl_log_entry)) 01122 { 01123 /* Write to error log and continue with next log entry */ 01124 sql_print_error("Failed to execute action for entry = %u from ddl log", 01125 read_entry); 01126 break; 01127 } 01128 read_entry= ddl_log_entry.next_entry; 01129 } while (read_entry); 01130 pthread_mutex_unlock(&LOCK_gdl); 01131 DBUG_RETURN(FALSE); 01132 } 01133 01134 01135 /* 01136 Execute the ddl log at recovery of MySQL Server 01137 SYNOPSIS 01138 execute_ddl_log_recovery() 01139 RETURN VALUES 01140 NONE 01141 */ 01142 01143 void execute_ddl_log_recovery() 01144 { 01145 uint num_entries, i; 01146 THD *thd; 01147 DDL_LOG_ENTRY ddl_log_entry; 01148 char file_name[FN_REFLEN]; 01149 DBUG_ENTER("execute_ddl_log_recovery"); 01150 01151 /* 01152 Initialise global_ddl_log struct 01153 */ 01154 bzero(global_ddl_log.file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); 01155 global_ddl_log.inited= FALSE; 01156 global_ddl_log.recovery_phase= TRUE; 01157 global_ddl_log.io_size= IO_SIZE; 01158 global_ddl_log.file_id= (File) -1; 01159 01160 /* 01161 To be able to run this from boot, we allocate a temporary THD 01162 */ 01163 if (!(thd=new THD)) 01164 DBUG_VOID_RETURN; 01165 thd->thread_stack= (char*) &thd; 01166 thd->store_globals(); 01167 01168 num_entries= read_ddl_log_header(); 01169 for (i= 1; i < num_entries + 1; i++) 01170 { 01171 if (read_ddl_log_entry(i, &ddl_log_entry)) 01172 { 01173 sql_print_error("Failed to read entry no = %u from ddl log", 01174 i); 01175 continue; 01176 } 01177 if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) 01178 { 01179 if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) 01180 { 01181 /* Real unpleasant scenario but we continue anyways. */ 01182 continue; 01183 } 01184 } 01185 } 01186 create_ddl_log_file_name(file_name); 01187 VOID(my_delete(file_name, MYF(0))); 01188 global_ddl_log.recovery_phase= FALSE; 01189 delete thd; 01190 /* Remember that we don't have a THD */ 01191 my_pthread_setspecific_ptr(THR_THD, 0); 01192 DBUG_VOID_RETURN; 01193 } 01194 01195 01196 /* 01197 Release all memory allocated to the ddl log 01198 SYNOPSIS 01199 release_ddl_log() 01200 RETURN VALUES 01201 NONE 01202 */ 01203 01204 void release_ddl_log() 01205 { 01206 DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free; 01207 DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; 01208 DBUG_ENTER("release_ddl_log"); 01209 01210 pthread_mutex_lock(&LOCK_gdl); 01211 while (used_list) 01212 { 01213 DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; 01214 my_free((char*)used_list, MYF(0)); 01215 used_list= tmp; 01216 } 01217 while (free_list) 01218 { 01219 DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; 01220 my_free((char*)free_list, MYF(0)); 01221 free_list= tmp; 01222 } 01223 if (global_ddl_log.file_id >= 0) 01224 { 01225 VOID(my_close(global_ddl_log.file_id, MYF(MY_WME))); 01226 global_ddl_log.file_id= (File) -1; 01227 } 01228 global_ddl_log.inited= 0; 01229 pthread_mutex_unlock(&LOCK_gdl); 01230 VOID(pthread_mutex_destroy(&LOCK_gdl)); 01231 DBUG_VOID_RETURN; 01232 } 01233 01234 01235 /* 01236 --------------------------------------------------------------------------- 01237 01238 END MODULE DDL log 01239 -------------------- 01240 01241 --------------------------------------------------------------------------- 01242 */ 01243 01244 01245 /* 01246 SYNOPSIS 01247 mysql_write_frm() 01248 lpt Struct carrying many parameters needed for this 01249 method 01250 flags Flags as defined below 01251 WFRM_INITIAL_WRITE If set we need to prepare table before 01252 creating the frm file 01253 WFRM_CREATE_HANDLER_FILES If set we need to create the handler file as 01254 part of the creation of the frm file 01255 WFRM_PACK_FRM If set we should pack the frm file and delete 01256 the frm file 01257 01258 RETURN VALUES 01259 TRUE Error 01260 FALSE Success 01261 01262 DESCRIPTION 01263 A support method that creates a new frm file and in this process it 01264 regenerates the partition data. It works fine also for non-partitioned 01265 tables since it only handles partitioned data if it exists. 01266 */ 01267 01268 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) 01269 { 01270 /* 01271 Prepare table to prepare for writing a new frm file where the 01272 partitions in add/drop state have temporarily changed their state 01273 We set tmp_table to avoid get errors on naming of primary key index. 01274 */ 01275 int error= 0; 01276 char path[FN_REFLEN+1]; 01277 char shadow_path[FN_REFLEN+1]; 01278 char shadow_frm_name[FN_REFLEN+1]; 01279 char frm_name[FN_REFLEN+1]; 01280 DBUG_ENTER("mysql_write_frm"); 01281 01282 /* 01283 Build shadow frm file name 01284 */ 01285 build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, 01286 lpt->table_name, "#", 0); 01287 strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); 01288 if (flags & WFRM_WRITE_SHADOW) 01289 { 01290 if (mysql_copy_create_list(lpt->create_list, 01291 &lpt->new_create_list) || 01292 mysql_copy_key_list(lpt->key_list, 01293 &lpt->new_key_list) || 01294 mysql_prepare_table(lpt->thd, lpt->create_info, 01295 &lpt->new_create_list, 01296 &lpt->new_key_list, 01297 /*tmp_table*/ 1, 01298 &lpt->db_options, 01299 lpt->table->file, 01300 &lpt->key_info_buffer, 01301 &lpt->key_count, 01302 /*select_field_count*/ 0)) 01303 { 01304 DBUG_RETURN(TRUE); 01305 } 01306 #ifdef WITH_PARTITION_STORAGE_ENGINE 01307 { 01308 partition_info *part_info= lpt->table->part_info; 01309 char *part_syntax_buf; 01310 uint syntax_len; 01311 01312 if (part_info) 01313 { 01314 if (!(part_syntax_buf= generate_partition_syntax(part_info, 01315 &syntax_len, 01316 TRUE, TRUE))) 01317 { 01318 DBUG_RETURN(TRUE); 01319 } 01320 part_info->part_info_string= part_syntax_buf; 01321 part_info->part_info_len= syntax_len; 01322 } 01323 } 01324 #endif 01325 /* Write shadow frm file */ 01326 lpt->create_info->table_options= lpt->db_options; 01327 if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db, 01328 lpt->table_name, lpt->create_info, 01329 lpt->new_create_list, lpt->key_count, 01330 lpt->key_info_buffer, lpt->table->file)) || 01331 lpt->table->file->create_handler_files(shadow_path, NULL, 01332 CHF_CREATE_FLAG, 01333 lpt->create_info)) 01334 { 01335 my_delete(shadow_frm_name, MYF(0)); 01336 error= 1; 01337 goto end; 01338 } 01339 } 01340 if (flags & WFRM_PACK_FRM) 01341 { 01342 /* 01343 We need to pack the frm file and after packing it we delete the 01344 frm file to ensure it doesn't get used. This is only used for 01345 handlers that have the main version of the frm file stored in the 01346 handler. 01347 */ 01348 const void *data= 0; 01349 uint length= 0; 01350 if (readfrm(shadow_path, &data, &length) || 01351 packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len)) 01352 { 01353 my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); 01354 my_free((char*)lpt->pack_frm_data, MYF(MY_ALLOW_ZERO_PTR)); 01355 mem_alloc_error(length); 01356 error= 1; 01357 goto end; 01358 } 01359 error= my_delete(shadow_frm_name, MYF(MY_WME)); 01360 } 01361 if (flags & WFRM_INSTALL_SHADOW) 01362 { 01363 #ifdef WITH_PARTITION_STORAGE_ENGINE 01364 partition_info *part_info= lpt->part_info; 01365 #endif 01366 /* 01367 Build frm file name 01368 */ 01369 build_table_filename(path, sizeof(path), lpt->db, 01370 lpt->table_name, "", 0); 01371 strxmov(frm_name, path, reg_ext, NullS); 01372 /* 01373 When we are changing to use new frm file we need to ensure that we 01374 don't collide with another thread in process to open the frm file. 01375 We start by deleting the .frm file and possible .par file. Then we 01376 write to the DDL log that we have completed the delete phase by 01377 increasing the phase of the log entry. Next step is to rename the 01378 new .frm file and the new .par file to the real name. After 01379 completing this we write a new phase to the log entry that will 01380 deactivate it. 01381 */ 01382 VOID(pthread_mutex_lock(&LOCK_open)); 01383 if (my_delete(frm_name, MYF(MY_WME)) || 01384 #ifdef WITH_PARTITION_STORAGE_ENGINE 01385 lpt->table->file->create_handler_files(path, shadow_path, 01386 CHF_DELETE_FLAG, NULL) || 01387 deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || 01388 (sync_ddl_log(), FALSE) || 01389 #endif 01390 #ifdef WITH_PARTITION_STORAGE_ENGINE 01391 my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || 01392 lpt->table->file->create_handler_files(path, shadow_path, 01393 CHF_RENAME_FLAG, NULL)) 01394 #else 01395 my_rename(shadow_frm_name, frm_name, MYF(MY_WME))) 01396 #endif 01397 { 01398 error= 1; 01399 } 01400 VOID(pthread_mutex_unlock(&LOCK_open)); 01401 #ifdef WITH_PARTITION_STORAGE_ENGINE 01402 deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos); 01403 part_info->frm_log_entry= NULL; 01404 VOID(sync_ddl_log()); 01405 #endif 01406 } 01407 01408 end: 01409 DBUG_RETURN(error); 01410 } 01411 01412 01413 /* 01414 SYNOPSIS 01415 write_bin_log() 01416 thd Thread object 01417 clear_error is clear_error to be called 01418 query Query to log 01419 query_length Length of query 01420 01421 RETURN VALUES 01422 NONE 01423 01424 DESCRIPTION 01425 Write the binlog if open, routine used in multiple places in this 01426 file 01427 */ 01428 01429 void write_bin_log(THD *thd, bool clear_error, 01430 char const *query, ulong query_length) 01431 { 01432 if (mysql_bin_log.is_open()) 01433 { 01434 if (clear_error) 01435 thd->clear_error(); 01436 thd->binlog_query(THD::STMT_QUERY_TYPE, 01437 query, query_length, FALSE, FALSE); 01438 } 01439 } 01440 01441 01442 /* 01443 delete (drop) tables. 01444 01445 SYNOPSIS 01446 mysql_rm_table() 01447 thd Thread handle 01448 tables List of tables to delete 01449 if_exists If 1, don't give error if one table doesn't exists 01450 01451 NOTES 01452 Will delete all tables that can be deleted and give a compact error 01453 messages for tables that could not be deleted. 01454 If a table is in use, we will wait for all users to free the table 01455 before dropping it 01456 01457 Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set. 01458 01459 RETURN 01460 FALSE OK. In this case ok packet is sent to user 01461 TRUE Error 01462 01463 */ 01464 01465 bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, 01466 my_bool drop_temporary) 01467 { 01468 bool error= FALSE, need_start_waiters= FALSE; 01469 DBUG_ENTER("mysql_rm_table"); 01470 01471 /* mark for close and remove all cached entries */ 01472 01473 if (!drop_temporary) 01474 { 01475 if ((error= wait_if_global_read_lock(thd, 0, 1))) 01476 { 01477 my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name); 01478 DBUG_RETURN(TRUE); 01479 } 01480 else 01481 need_start_waiters= TRUE; 01482 } 01483 01484 /* 01485 Acquire LOCK_open after wait_if_global_read_lock(). If we would hold 01486 LOCK_open during wait_if_global_read_lock(), other threads could not 01487 close their tables. This would make a pretty deadlock. 01488 */ 01489 thd->mysys_var->current_mutex= &LOCK_open; 01490 thd->mysys_var->current_cond= &COND_refresh; 01491 VOID(pthread_mutex_lock(&LOCK_open)); 01492 01493 error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0); 01494 01495 pthread_mutex_unlock(&LOCK_open); 01496 01497 pthread_mutex_lock(&thd->mysys_var->mutex); 01498 thd->mysys_var->current_mutex= 0; 01499 thd->mysys_var->current_cond= 0; 01500 pthread_mutex_unlock(&thd->mysys_var->mutex); 01501 01502 if (need_start_waiters) 01503 start_waiting_global_read_lock(thd); 01504 01505 if (error) 01506 DBUG_RETURN(TRUE); 01507 send_ok(thd); 01508 DBUG_RETURN(FALSE); 01509 } 01510 01511 01512 /* 01513 delete (drop) tables. 01514 01515 SYNOPSIS 01516 mysql_rm_table_part2_with_lock() 01517 thd Thread handle 01518 tables List of tables to delete 01519 if_exists If 1, don't give error if one table doesn't exists 01520 dont_log_query Don't write query to log files. This will also not 01521 generate warnings if the handler files doesn't exists 01522 01523 NOTES 01524 Works like documented in mysql_rm_table(), but don't check 01525 global_read_lock and don't send_ok packet to server. 01526 01527 RETURN 01528 0 ok 01529 1 error 01530 */ 01531 01532 int mysql_rm_table_part2_with_lock(THD *thd, 01533 TABLE_LIST *tables, bool if_exists, 01534 bool drop_temporary, bool dont_log_query) 01535 { 01536 int error; 01537 thd->mysys_var->current_mutex= &LOCK_open; 01538 thd->mysys_var->current_cond= &COND_refresh; 01539 VOID(pthread_mutex_lock(&LOCK_open)); 01540 01541 error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 1, 01542 dont_log_query); 01543 01544 pthread_mutex_unlock(&LOCK_open); 01545 01546 pthread_mutex_lock(&thd->mysys_var->mutex); 01547 thd->mysys_var->current_mutex= 0; 01548 thd->mysys_var->current_cond= 0; 01549 pthread_mutex_unlock(&thd->mysys_var->mutex); 01550 return error; 01551 } 01552 01553 01554 /* 01555 Execute the drop of a normal or temporary table 01556 01557 SYNOPSIS 01558 mysql_rm_table_part2() 01559 thd Thread handler 01560 tables Tables to drop 01561 if_exists If set, don't give an error if table doesn't exists. 01562 In this case we give an warning of level 'NOTE' 01563 drop_temporary Only drop temporary tables 01564 drop_view Allow to delete VIEW .frm 01565 dont_log_query Don't write query to log files. This will also not 01566 generate warnings if the handler files doesn't exists 01567 01568 TODO: 01569 When logging to the binary log, we should log 01570 tmp_tables and transactional tables as separate statements if we 01571 are in a transaction; This is needed to get these tables into the 01572 cached binary log that is only written on COMMIT. 01573 01574 The current code only writes DROP statements that only uses temporary 01575 tables to the cache binary log. This should be ok on most cases, but 01576 not all. 01577 01578 RETURN 01579 0 ok 01580 1 Error 01581 -1 Thread was killed 01582 */ 01583 01584 int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, 01585 bool drop_temporary, bool drop_view, 01586 bool dont_log_query) 01587 { 01588 TABLE_LIST *table; 01589 char path[FN_REFLEN], *alias; 01590 uint path_length; 01591 String wrong_tables; 01592 int error; 01593 int non_temp_tables_count= 0; 01594 bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0; 01595 String built_query; 01596 DBUG_ENTER("mysql_rm_table_part2"); 01597 01598 LINT_INIT(alias); 01599 LINT_INIT(path_length); 01600 safe_mutex_assert_owner(&LOCK_open); 01601 01602 if (thd->current_stmt_binlog_row_based && !dont_log_query) 01603 { 01604 built_query.set_charset(system_charset_info); 01605 if (if_exists) 01606 built_query.append("DROP TABLE IF EXISTS "); 01607 else 01608 built_query.append("DROP TABLE "); 01609 } 01610 /* 01611 If we have the table in the definition cache, we don't have to check the 01612 .frm file to find if the table is a normal table (not view) and what 01613 engine to use. 01614 */ 01615 01616 for (table= tables; table; table= table->next_local) 01617 { 01618 TABLE_SHARE *share; 01619 table->db_type= NULL; 01620 if ((share= get_cached_table_share(table->db, table->table_name))) 01621 table->db_type= share->db_type; 01622 01623 /* Disable drop of enabled log tables */ 01624 if (share && share->log_table && 01625 ((!my_strcasecmp(system_charset_info, table->table_name, 01626 "general_log") && opt_log && 01627 logger.is_general_log_table_enabled()) || 01628 (!my_strcasecmp(system_charset_info, table->table_name, "slow_log") 01629 && opt_slow_log && logger.is_slow_log_table_enabled()))) 01630 { 01631 my_error(ER_CANT_DROP_LOG_TABLE, MYF(0)); 01632 DBUG_RETURN(1); 01633 } 01634 } 01635 01636 if (lock_table_names(thd, tables)) 01637 DBUG_RETURN(1); 01638 01639 /* Don't give warnings for not found errors, as we already generate notes */ 01640 thd->no_warnings_for_error= 1; 01641 01642 for (table= tables; table; table= table->next_local) 01643 { 01644 char *db=table->db; 01645 handlerton *table_type; 01646 enum legacy_db_type frm_db_type; 01647 01648 mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, TRUE); 01649 if (!close_temporary_table(thd, table)) 01650 { 01651 tmp_table_deleted=1; 01652 continue; // removed temporary table 01653 } 01654 01655 /* 01656 If row-based replication is used and the table is not a 01657 temporary table, we add the table name to the drop statement 01658 being built. The string always end in a comma and the comma 01659 will be chopped off before being written to the binary log. 01660 */ 01661 if (thd->current_stmt_binlog_row_based && !dont_log_query) 01662 { 01663 non_temp_tables_count++; 01664 /* 01665 Don't write the database name if it is the current one (or if 01666 thd->db is NULL). 01667 */ 01668 built_query.append("`"); 01669 if (thd->db == NULL || strcmp(db,thd->db) != 0) 01670 { 01671 built_query.append(db); 01672 built_query.append("`.`"); 01673 } 01674 01675 built_query.append(table->table_name); 01676 built_query.append("`,"); 01677 } 01678 01679 error=0; 01680 table_type= table->db_type; 01681 if (!drop_temporary) 01682 { 01683 TABLE *locked_table; 01684 abort_locked_tables(thd, db, table->table_name); 01685 remove_table_from_cache(thd, db, table->table_name, 01686 RTFC_WAIT_OTHER_THREAD_FLAG | 01687 RTFC_CHECK_KILLED_FLAG); 01688 /* 01689 If the table was used in lock tables, remember it so that 01690 unlock_table_names can free it 01691 */ 01692 if ((locked_table= drop_locked_tables(thd, db, table->table_name))) 01693 table->table= locked_table; 01694 01695 if (thd->killed) 01696 { 01697 thd->no_warnings_for_error= 0; 01698 DBUG_RETURN(-1); 01699 } 01700 alias= (lower_case_table_names == 2) ? table->alias : table->table_name; 01701 /* remove .frm file and engine files */ 01702 path_length= build_table_filename(path, sizeof(path), 01703 db, alias, reg_ext, 0); 01704 } 01705 if (drop_temporary || 01706 (table_type == NULL && 01707 (access(path, F_OK) && 01708 ha_create_table_from_engine(thd, db, alias)) || 01709 (!drop_view && 01710 mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) 01711 { 01712 // Table was not found on disk and table can't be created from engine 01713 if (if_exists) 01714 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 01715 ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), 01716 table->table_name); 01717 else 01718 error= 1; 01719 } 01720 else 01721 { 01722 char *end; 01723 if (table_type == NULL) 01724 { 01725 mysql_frm_type(thd, path, &frm_db_type); 01726 table_type= ha_resolve_by_legacy_type(thd, frm_db_type); 01727 } 01728 // Remove extension for delete 01729 *(end= path + path_length - reg_ext_length)= '\0'; 01730 error= ha_delete_table(thd, table_type, path, db, table->table_name, 01731 !dont_log_query); 01732 if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && 01733 (if_exists || table_type == NULL)) 01734 error= 0; 01735 if (error == HA_ERR_ROW_IS_REFERENCED) 01736 { 01737 /* the table is referenced by a foreign key constraint */ 01738 foreign_key_error=1; 01739 } 01740 if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) 01741 { 01742 int new_error; 01743 /* Delete the table definition file */ 01744 strmov(end,reg_ext); 01745 if (!(new_error=my_delete(path,MYF(MY_WME)))) 01746 { 01747 some_tables_deleted=1; 01748 new_error= Table_triggers_list::drop_all_triggers(thd, db, 01749 table->table_name); 01750 } 01751 error|= new_error; 01752 } 01753 } 01754 if (error) 01755 { 01756 if (wrong_tables.length()) 01757 wrong_tables.append(','); 01758 wrong_tables.append(String(table->table_name,system_charset_info)); 01759 } 01760 } 01761 thd->tmp_table_used= tmp_table_deleted; 01762 error= 0; 01763 if (wrong_tables.length()) 01764 { 01765 if (!foreign_key_error) 01766 my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0), 01767 wrong_tables.c_ptr()); 01768 else 01769 my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0)); 01770 error= 1; 01771 } 01772 01773 if (some_tables_deleted || tmp_table_deleted || !error) 01774 { 01775 query_cache_invalidate3(thd, tables, 0); 01776 if (!dont_log_query) 01777 { 01778 if (!thd->current_stmt_binlog_row_based || 01779 non_temp_tables_count > 0 && !tmp_table_deleted) 01780 { 01781 /* 01782 In this case, we are either using statement-based 01783 replication or using row-based replication but have only 01784 deleted one or more non-temporary tables (and no temporary 01785 tables). In this case, we can write the original query into 01786 the binary log. 01787 */ 01788 write_bin_log(thd, !error, thd->query, thd->query_length); 01789 } 01790 else if (thd->current_stmt_binlog_row_based && 01791 non_temp_tables_count > 0 && 01792 tmp_table_deleted) 01793 { 01794 /* 01795 In this case we have deleted both temporary and 01796 non-temporary tables, so: 01797 - since we have deleted a non-temporary table we have to 01798 binlog the statement, but 01799 - since we have deleted a temporary table we cannot binlog 01800 the statement (since the table has not been created on the 01801 slave, this might cause the slave to stop). 01802 01803 Instead, we write a built statement, only containing the 01804 non-temporary tables, to the binary log 01805 */ 01806 built_query.chop(); // Chop of the last comma 01807 built_query.append(" /* generated by server */"); 01808 write_bin_log(thd, !error, built_query.ptr(), built_query.length()); 01809 } 01810 /* 01811 The remaining cases are: 01812 - no tables where deleted and 01813 - only temporary tables where deleted and row-based 01814 replication is used. 01815 In both these cases, nothing should be written to the binary 01816 log. 01817 */ 01818 } 01819 } 01820 01821 unlock_table_names(thd, tables, (TABLE_LIST*) 0); 01822 thd->no_warnings_for_error= 0; 01823 DBUG_RETURN(error); 01824 } 01825 01826 01827 /* 01828 Quickly remove a table. 01829 01830 SYNOPSIS 01831 quick_rm_table() 01832 base The handlerton handle. 01833 db The database name. 01834 table_name The table name. 01835 flags flags for build_table_filename(). 01836 01837 RETURN 01838 0 OK 01839 != 0 Error 01840 */ 01841 01842 bool quick_rm_table(handlerton *base,const char *db, 01843 const char *table_name, uint flags) 01844 { 01845 char path[FN_REFLEN]; 01846 bool error= 0; 01847 DBUG_ENTER("quick_rm_table"); 01848 01849 uint path_length= build_table_filename(path, sizeof(path), 01850 db, table_name, reg_ext, flags); 01851 if (my_delete(path,MYF(0))) 01852 error= 1; /* purecov: inspected */ 01853 path[path_length - reg_ext_length]= '\0'; // Remove reg_ext 01854 DBUG_RETURN(ha_delete_table(current_thd, base, path, db, table_name, 0) || 01855 error); 01856 } 01857 01858 /* 01859 Sort keys in the following order: 01860 - PRIMARY KEY 01861 - UNIQUE keyws where all column are NOT NULL 01862 - Other UNIQUE keys 01863 - Normal keys 01864 - Fulltext keys 01865 01866 This will make checking for duplicated keys faster and ensure that 01867 PRIMARY keys are prioritized. 01868 */ 01869 01870 static int sort_keys(KEY *a, KEY *b) 01871 { 01872 if (a->flags & HA_NOSAME) 01873 { 01874 if (!(b->flags & HA_NOSAME)) 01875 return -1; 01876 if ((a->flags ^ b->flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) 01877 { 01878 /* Sort NOT NULL keys before other keys */ 01879 return (a->flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; 01880 } 01881 if (a->name == primary_key_name) 01882 return -1; 01883 if (b->name == primary_key_name) 01884 return 1; 01885 } 01886 else if (b->flags & HA_NOSAME) 01887 return 1; // Prefer b 01888 01889 if ((a->flags ^ b->flags) & HA_FULLTEXT) 01890 { 01891 return (a->flags & HA_FULLTEXT) ? 1 : -1; 01892 } 01893 /* 01894 Prefer original key order. usable_key_parts contains here 01895 the original key position. 01896 */ 01897 return ((a->usable_key_parts < b->usable_key_parts) ? -1 : 01898 (a->usable_key_parts > b->usable_key_parts) ? 1 : 01899 0); 01900 } 01901 01902 /* 01903 Check TYPELIB (set or enum) for duplicates 01904 01905 SYNOPSIS 01906 check_duplicates_in_interval() 01907 set_or_name "SET" or "ENUM" string for warning message 01908 name name of the checked column 01909 typelib list of values for the column 01910 01911 DESCRIPTION 01912 This function prints an warning for each value in list 01913 which has some duplicates on its right 01914 01915 RETURN VALUES 01916 void 01917 */ 01918 01919 void check_duplicates_in_interval(const char *set_or_name, 01920 const char *name, TYPELIB *typelib, 01921 CHARSET_INFO *cs) 01922 { 01923 TYPELIB tmp= *typelib; 01924 const char **cur_value= typelib->type_names; 01925 unsigned int *cur_length= typelib->type_lengths; 01926 01927 for ( ; tmp.count > 1; cur_value++, cur_length++) 01928 { 01929 tmp.type_names++; 01930 tmp.type_lengths++; 01931 tmp.count--; 01932 if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs)) 01933 { 01934 push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_NOTE, 01935 ER_DUPLICATED_VALUE_IN_TYPE, 01936 ER(ER_DUPLICATED_VALUE_IN_TYPE), 01937 name,*cur_value,set_or_name); 01938 } 01939 } 01940 } 01941 01942 01943 /* 01944 Check TYPELIB (set or enum) max and total lengths 01945 01946 SYNOPSIS 01947 calculate_interval_lengths() 01948 cs charset+collation pair of the interval 01949 typelib list of values for the column 01950 max_length length of the longest item 01951 tot_length sum of the item lengths 01952 01953 DESCRIPTION 01954 After this function call: 01955 - ENUM uses max_length 01956 - SET uses tot_length. 01957 01958 RETURN VALUES 01959 void 01960 */ 01961 void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval, 01962 uint32 *max_length, uint32 *tot_length) 01963 { 01964 const char **pos; 01965 uint *len; 01966 *max_length= *tot_length= 0; 01967 for (pos= interval->type_names, len= interval->type_lengths; 01968 *pos ; pos++, len++) 01969 { 01970 uint length= cs->cset->numchars(cs, *pos, *pos + *len); 01971 *tot_length+= length; 01972 set_if_bigger(*max_length, (uint32)length); 01973 } 01974 } 01975 01976 01977 /* 01978 Prepare a create_table instance for packing 01979 01980 SYNOPSIS 01981 prepare_create_field() 01982 sql_field field to prepare for packing 01983 blob_columns count for BLOBs 01984 timestamps count for timestamps 01985 table_flags table flags 01986 01987 DESCRIPTION 01988 This function prepares a create_field instance. 01989 Fields such as pack_flag are valid after this call. 01990 01991 RETURN VALUES 01992 0 ok 01993 1 Error 01994 */ 01995 01996 int prepare_create_field(create_field *sql_field, 01997 uint *blob_columns, 01998 int *timestamps, int *timestamps_with_niladic, 01999 uint table_flags) 02000 { 02001 DBUG_ENTER("prepare_field"); 02002 02003 /* 02004 This code came from mysql_prepare_table. 02005 Indent preserved to make patching easier 02006 */ 02007 DBUG_ASSERT(sql_field->charset); 02008 02009 switch (sql_field->sql_type) { 02010 case FIELD_TYPE_BLOB: 02011 case FIELD_TYPE_MEDIUM_BLOB: 02012 case FIELD_TYPE_TINY_BLOB: 02013 case FIELD_TYPE_LONG_BLOB: 02014 sql_field->pack_flag=FIELDFLAG_BLOB | 02015 pack_length_to_packflag(sql_field->pack_length - 02016 portable_sizeof_char_ptr); 02017 if (sql_field->charset->state & MY_CS_BINSORT) 02018 sql_field->pack_flag|=FIELDFLAG_BINARY; 02019 sql_field->length=8; // Unireg field length 02020 sql_field->unireg_check=Field::BLOB_FIELD; 02021 (*blob_columns)++; 02022 break; 02023 case FIELD_TYPE_GEOMETRY: 02024 #ifdef HAVE_SPATIAL 02025 if (!(table_flags & HA_CAN_GEOMETRY)) 02026 { 02027 my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED), 02028 MYF(0), "GEOMETRY"); 02029 DBUG_RETURN(1); 02030 } 02031 sql_field->pack_flag=FIELDFLAG_GEOM | 02032 pack_length_to_packflag(sql_field->pack_length - 02033 portable_sizeof_char_ptr); 02034 if (sql_field->charset->state & MY_CS_BINSORT) 02035 sql_field->pack_flag|=FIELDFLAG_BINARY; 02036 sql_field->length=8; // Unireg field length 02037 sql_field->unireg_check=Field::BLOB_FIELD; 02038 (*blob_columns)++; 02039 break; 02040 #else 02041 my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0), 02042 sym_group_geom.name, sym_group_geom.needed_define); 02043 DBUG_RETURN(1); 02044 #endif /*HAVE_SPATIAL*/ 02045 case MYSQL_TYPE_VARCHAR: 02046 #ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR 02047 if (table_flags & HA_NO_VARCHAR) 02048 { 02049 /* convert VARCHAR to CHAR because handler is not yet up to date */ 02050 sql_field->sql_type= MYSQL_TYPE_VAR_STRING; 02051 sql_field->pack_length= calc_pack_length(sql_field->sql_type, 02052 (uint) sql_field->length); 02053 if ((sql_field->length / sql_field->charset->mbmaxlen) > 02054 MAX_FIELD_CHARLENGTH) 02055 { 02056 my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH), 02057 MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH); 02058 DBUG_RETURN(1); 02059 } 02060 } 02061 #endif 02062 /* fall through */ 02063 case FIELD_TYPE_STRING: 02064 sql_field->pack_flag=0; 02065 if (sql_field->charset->state & MY_CS_BINSORT) 02066 sql_field->pack_flag|=FIELDFLAG_BINARY; 02067 break; 02068 case FIELD_TYPE_ENUM: 02069 sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | 02070 FIELDFLAG_INTERVAL; 02071 if (sql_field->charset->state & MY_CS_BINSORT) 02072 sql_field->pack_flag|=FIELDFLAG_BINARY; 02073 sql_field->unireg_check=Field::INTERVAL_FIELD; 02074 check_duplicates_in_interval("ENUM",sql_field->field_name, 02075 sql_field->interval, 02076 sql_field->charset); 02077 break; 02078 case FIELD_TYPE_SET: 02079 sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | 02080 FIELDFLAG_BITFIELD; 02081 if (sql_field->charset->state & MY_CS_BINSORT) 02082 sql_field->pack_flag|=FIELDFLAG_BINARY; 02083 sql_field->unireg_check=Field::BIT_FIELD; 02084 check_duplicates_in_interval("SET",sql_field->field_name, 02085 sql_field->interval, 02086 sql_field->charset); 02087 break; 02088 case FIELD_TYPE_DATE: // Rest of string types 02089 case FIELD_TYPE_NEWDATE: 02090 case FIELD_TYPE_TIME: 02091 case FIELD_TYPE_DATETIME: 02092 case FIELD_TYPE_NULL: 02093 sql_field->pack_flag=f_settype((uint) sql_field->sql_type); 02094 break; 02095 case FIELD_TYPE_BIT: 02096 /* 02097 We have sql_field->pack_flag already set here, see mysql_prepare_table(). 02098 */ 02099 break; 02100 case FIELD_TYPE_NEWDECIMAL: 02101 sql_field->pack_flag=(FIELDFLAG_NUMBER | 02102 (sql_field->flags & UNSIGNED_FLAG ? 0 : 02103 FIELDFLAG_DECIMAL) | 02104 (sql_field->flags & ZEROFILL_FLAG ? 02105 FIELDFLAG_ZEROFILL : 0) | 02106 (sql_field->decimals << FIELDFLAG_DEC_SHIFT)); 02107 break; 02108 case FIELD_TYPE_TIMESTAMP: 02109 /* We should replace old TIMESTAMP fields with their newer analogs */ 02110 if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD) 02111 { 02112 if (!*timestamps) 02113 { 02114 sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD; 02115 (*timestamps_with_niladic)++; 02116 } 02117 else 02118 sql_field->unireg_check= Field::NONE; 02119 } 02120 else if (sql_field->unireg_check != Field::NONE) 02121 (*timestamps_with_niladic)++; 02122 02123 (*timestamps)++; 02124 /* fall-through */ 02125 default: 02126 sql_field->pack_flag=(FIELDFLAG_NUMBER | 02127 (sql_field->flags & UNSIGNED_FLAG ? 0 : 02128 FIELDFLAG_DECIMAL) | 02129 (sql_field->flags & ZEROFILL_FLAG ? 02130 FIELDFLAG_ZEROFILL : 0) | 02131 f_settype((uint) sql_field->sql_type) | 02132 (sql_field->decimals << FIELDFLAG_DEC_SHIFT)); 02133 break; 02134 } 02135 if (!(sql_field->flags & NOT_NULL_FLAG)) 02136 sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL; 02137 if (sql_field->flags & NO_DEFAULT_VALUE_FLAG) 02138 sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT; 02139 DBUG_RETURN(0); 02140 } 02141 02142 /* 02143 Preparation for table creation 02144 02145 SYNOPSIS 02146 mysql_prepare_table() 02147 thd Thread object. 02148 create_info Create information (like MAX_ROWS). 02149 fields List of fields to create. 02150 keys List of keys to create. 02151 tmp_table If a temporary table is to be created. 02152 db_options INOUT Table options (like HA_OPTION_PACK_RECORD). 02153 file The handler for the new table. 02154 key_info_buffer OUT An array of KEY structs for the indexes. 02155 key_count OUT The number of elements in the array. 02156 select_field_count The number of fields coming from a select table. 02157 02158 DESCRIPTION 02159 Prepares the table and key structures for table creation. 02160 02161 NOTES 02162 sets create_info->varchar if the table has a varchar 02163 02164 RETURN VALUES 02165 0 ok 02166 -1 error 02167 */ 02168 02169 static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, 02170 List<create_field> *fields, 02171 List<Key> *keys, bool tmp_table, 02172 uint *db_options, 02173 handler *file, KEY **key_info_buffer, 02174 uint *key_count, int select_field_count) 02175 { 02176 const char *key_name; 02177 create_field *sql_field,*dup_field; 02178 uint field,null_fields,blob_columns,max_key_length; 02179 ulong record_offset= 0; 02180 KEY *key_info; 02181 KEY_PART_INFO *key_part_info; 02182 int timestamps= 0, timestamps_with_niladic= 0; 02183 int field_no,dup_no; 02184 int select_field_pos,auto_increment=0; 02185 List_iterator<create_field> it(*fields),it2(*fields); 02186 uint total_uneven_bit_length= 0; 02187 DBUG_ENTER("mysql_prepare_table"); 02188 02189 select_field_pos= fields->elements - select_field_count; 02190 null_fields=blob_columns=0; 02191 create_info->varchar= 0; 02192 max_key_length= file->max_key_length(); 02193 02194 for (field_no=0; (sql_field=it++) ; field_no++) 02195 { 02196 CHARSET_INFO *save_cs; 02197 02198 /* 02199 Initialize length from its original value (number of characters), 02200 which was set in the parser. This is necessary if we're 02201 executing a prepared statement for the second time. 02202 */ 02203 sql_field->length= sql_field->char_length; 02204 if (!sql_field->charset) 02205 sql_field->charset= create_info->default_table_charset; 02206 /* 02207 table_charset is set in ALTER TABLE if we want change character set 02208 for all varchar/char columns. 02209 But the table charset must not affect the BLOB fields, so don't 02210 allow to change my_charset_bin to somethig else. 02211 */ 02212 if (create_info->table_charset && sql_field->charset != &my_charset_bin) 02213 sql_field->charset= create_info->table_charset; 02214 02215 save_cs= sql_field->charset; 02216 if ((sql_field->flags & BINCMP_FLAG) && 02217 !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, 02218 MY_CS_BINSORT,MYF(0)))) 02219 { 02220 char tmp[64]; 02221 strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), 02222 STRING_WITH_LEN("_bin")); 02223 my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); 02224 DBUG_RETURN(-1); 02225 } 02226 02227 if (sql_field->sql_type == FIELD_TYPE_SET || 02228 sql_field->sql_type == FIELD_TYPE_ENUM) 02229 { 02230 uint32 dummy; 02231 CHARSET_INFO *cs= sql_field->charset; 02232 TYPELIB *interval= sql_field->interval; 02233 02234 /* 02235 Create typelib from interval_list, and if necessary 02236 convert strings from client character set to the 02237 column character set. 02238 */ 02239 if (!interval) 02240 { 02241 /* 02242 Create the typelib in prepared statement memory if we're 02243 executing one. 02244 */ 02245 MEM_ROOT *stmt_root= thd->stmt_arena->mem_root; 02246 02247 interval= sql_field->interval= typelib(stmt_root, 02248 sql_field->interval_list); 02249 List_iterator<String> it(sql_field->interval_list); 02250 String conv, *tmp; 02251 char comma_buf[2]; 02252 int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf, 02253 (uchar*) comma_buf + 02254 sizeof(comma_buf)); 02255 DBUG_ASSERT(comma_length > 0); 02256 for (uint i= 0; (tmp= it++); i++) 02257 { 02258 uint lengthsp; 02259 if (String::needs_conversion(tmp->length(), tmp->charset(), 02260 cs, &dummy)) 02261 { 02262 uint cnv_errs; 02263 conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs); 02264 interval->type_names[i]= strmake_root(stmt_root, conv.ptr(), 02265 conv.length()); 02266 interval->type_lengths[i]= conv.length(); 02267 } 02268 02269 // Strip trailing spaces. 02270 lengthsp= cs->cset->lengthsp(cs, interval->type_names[i], 02271 interval->type_lengths[i]); 02272 interval->type_lengths[i]= lengthsp; 02273 ((uchar *)interval->type_names[i])[lengthsp]= '\0'; 02274 if (sql_field->sql_type == FIELD_TYPE_SET) 02275 { 02276 if (cs->coll->instr(cs, interval->type_names[i], 02277 interval->type_lengths[i], 02278 comma_buf, comma_length, NULL, 0)) 02279 { 02280 my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", tmp->ptr()); 02281 DBUG_RETURN(-1); 02282 } 02283 } 02284 } 02285 sql_field->interval_list.empty(); // Don't need interval_list anymore 02286 } 02287 02288 /* 02289 Convert the default value from client character 02290 set into the column character set if necessary. 02291 */ 02292 if (sql_field->def && cs != sql_field->def->collation.collation) 02293 { 02294 Query_arena backup_arena; 02295 bool need_to_change_arena= !thd->stmt_arena->is_conventional(); 02296 if (need_to_change_arena) 02297 { 02298 /* Asser that we don't do that at every PS execute */ 02299 DBUG_ASSERT(thd->stmt_arena->is_first_stmt_execute() || 02300 thd->stmt_arena->is_first_sp_execute()); 02301 thd->set_n_backup_active_arena(thd->stmt_arena, &backup_arena); 02302 } 02303 02304 sql_field->def= sql_field->def->safe_charset_converter(cs); 02305 02306 if (need_to_change_arena) 02307 thd->restore_active_arena(thd->stmt_arena, &backup_arena); 02308 02309 if (sql_field->def == NULL) 02310 { 02311 /* Could not convert */ 02312 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); 02313 DBUG_RETURN(-1); 02314 } 02315 } 02316 02317 if (sql_field->sql_type == FIELD_TYPE_SET) 02318 { 02319 uint32 field_length; 02320 if (sql_field->def != NULL) 02321 { 02322 char *not_used; 02323 uint not_used2; 02324 bool not_found= 0; 02325 String str, *def= sql_field->def->val_str(&str); 02326 if (def == NULL) /* SQL "NULL" maps to NULL */ 02327 { 02328 if ((sql_field->flags & NOT_NULL_FLAG) != 0) 02329 { 02330 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); 02331 DBUG_RETURN(-1); 02332 } 02333 02334 /* else, NULL is an allowed value */ 02335 (void) find_set(interval, NULL, 0, 02336 cs, ¬_used, ¬_used2, ¬_found); 02337 } 02338 else /* not NULL */ 02339 { 02340 (void) find_set(interval, def->ptr(), def->length(), 02341 cs, ¬_used, ¬_used2, ¬_found); 02342 } 02343 02344 if (not_found) 02345 { 02346 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); 02347 DBUG_RETURN(-1); 02348 } 02349 } 02350 calculate_interval_lengths(cs, interval, &dummy, &field_length); 02351 sql_field->length= field_length + (interval->count - 1); 02352 } 02353 else /* FIELD_TYPE_ENUM */ 02354 { 02355 uint32 field_length; 02356 DBUG_ASSERT(sql_field->sql_type == FIELD_TYPE_ENUM); 02357 if (sql_field->def != NULL) 02358 { 02359 String str, *def= sql_field->def->val_str(&str); 02360 if (def == NULL) /* SQL "NULL" maps to NULL */ 02361 { 02362 if ((sql_field->flags & NOT_NULL_FLAG) != 0) 02363 { 02364 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); 02365 DBUG_RETURN(-1); 02366 } 02367 02368 /* else, the defaults yield the correct length for NULLs. */ 02369 } 02370 else /* not NULL */ 02371 { 02372 def->length(cs->cset->lengthsp(cs, def->ptr(), def->length())); 02373 if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */ 02374 { 02375 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); 02376 DBUG_RETURN(-1); 02377 } 02378 } 02379 } 02380 calculate_interval_lengths(cs, interval, &field_length, &dummy); 02381 sql_field->length= field_length; 02382 } 02383 set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1); 02384 } 02385 02386 if (sql_field->sql_type == FIELD_TYPE_BIT) 02387 { 02388 sql_field->pack_flag= FIELDFLAG_NUMBER; 02389 if (file->ha_table_flags() & HA_CAN_BIT_FIELD) 02390 total_uneven_bit_length+= sql_field->length & 7; 02391 else 02392 sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; 02393 } 02394 02395 sql_field->create_length_to_internal_length(); 02396 if (prepare_blob_field(thd, sql_field)) 02397 DBUG_RETURN(-1); 02398 02399 if (!(sql_field->flags & NOT_NULL_FLAG)) 02400 null_fields++; 02401 02402 if (check_column_name(sql_field->field_name)) 02403 { 02404 my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name); 02405 DBUG_RETURN(-1); 02406 } 02407 02408 /* Check if we have used the same field name before */ 02409 for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++) 02410 { 02411 if (my_strcasecmp(system_charset_info, 02412 sql_field->field_name, 02413 dup_field->field_name) == 0) 02414 { 02415 /* 02416 If this was a CREATE ... SELECT statement, accept a field 02417 redefinition if we are changing a field in the SELECT part 02418 */ 02419 if (field_no < select_field_pos || dup_no >= select_field_pos) 02420 { 02421 my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name); 02422 DBUG_RETURN(-1); 02423 } 02424 else 02425 { 02426 /* Field redefined */ 02427 sql_field->def= dup_field->def; 02428 sql_field->sql_type= dup_field->sql_type; 02429 sql_field->charset= (dup_field->charset ? 02430 dup_field->charset : 02431 create_info->default_table_charset); 02432 sql_field->length= dup_field->char_length; 02433 sql_field->pack_length= dup_field->pack_length; 02434 sql_field->key_length= dup_field->key_length; 02435 sql_field->create_length_to_internal_length(); 02436 sql_field->decimals= dup_field->decimals; 02437 sql_field->unireg_check= dup_field->unireg_check; 02438 /* 02439 We're making one field from two, the result field will have 02440 dup_field->flags as flags. If we've incremented null_fields 02441 because of sql_field->flags, decrement it back. 02442 */ 02443 if (!(sql_field->flags & NOT_NULL_FLAG)) 02444 null_fields--; 02445 sql_field->flags= dup_field->flags; 02446 sql_field->interval= dup_field->interval; 02447 it2.remove(); // Remove first (create) definition 02448 select_field_pos--; 02449 break; 02450 } 02451 } 02452 } 02453 /* Don't pack rows in old tables if the user has requested this */ 02454 if ((sql_field->flags & BLOB_FLAG) || 02455 sql_field->sql_type == MYSQL_TYPE_VARCHAR && 02456 create_info->row_type != ROW_TYPE_FIXED) 02457 (*db_options)|= HA_OPTION_PACK_RECORD; 02458 it2.rewind(); 02459 } 02460 02461 /* record_offset will be increased with 'length-of-null-bits' later */ 02462 record_offset= 0; 02463 null_fields+= total_uneven_bit_length; 02464 02465 it.rewind(); 02466 while ((sql_field=it++)) 02467 { 02468 DBUG_ASSERT(sql_field->charset != 0); 02469 02470 if (prepare_create_field(sql_field, &blob_columns, 02471 ×tamps, ×tamps_with_niladic, 02472 file->ha_table_flags())) 02473 DBUG_RETURN(-1); 02474 if (sql_field->sql_type == MYSQL_TYPE_VARCHAR) 02475 create_info->varchar= 1; 02476 sql_field->offset= record_offset; 02477 if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) 02478 auto_increment++; 02479 record_offset+= sql_field->pack_length; 02480 } 02481 if (timestamps_with_niladic > 1) 02482 { 02483 my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS, 02484 ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0)); 02485 DBUG_RETURN(-1); 02486 } 02487 if (auto_increment > 1) 02488 { 02489 my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0)); 02490 DBUG_RETURN(-1); 02491 } 02492 if (auto_increment && 02493 (file->ha_table_flags() & HA_NO_AUTO_INCREMENT)) 02494 { 02495 my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, 02496 ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0)); 02497 DBUG_RETURN(-1); 02498 } 02499 02500 if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS)) 02501 { 02502 my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB), 02503 MYF(0)); 02504 DBUG_RETURN(-1); 02505 } 02506 02507 /* Create keys */ 02508 02509 List_iterator<Key> key_iterator(*keys), key_iterator2(*keys); 02510 uint key_parts=0, fk_key_count=0; 02511 bool primary_key=0,unique_key=0; 02512 Key *key, *key2; 02513 uint tmp, key_number; 02514 /* special marker for keys to be ignored */ 02515 static char ignore_key[1]; 02516 02517 /* Calculate number of key segements */ 02518 *key_count= 0; 02519 02520 while ((key=key_iterator++)) 02521 { 02522 DBUG_PRINT("info", ("key name: '%s' type: %d", key->name ? key->name : 02523 "(none)" , key->type)); 02524 if (key->type == Key::FOREIGN_KEY) 02525 { 02526 fk_key_count++; 02527 foreign_key *fk_key= (foreign_key*) key; 02528 if (fk_key->ref_columns.elements && 02529 fk_key->ref_columns.elements != fk_key->columns.elements) 02530 { 02531 my_error(ER_WRONG_FK_DEF, MYF(0), 02532 (fk_key->name ? fk_key->name : "foreign key without name"), 02533 ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF)); 02534 DBUG_RETURN(-1); 02535 } 02536 continue; 02537 } 02538 (*key_count)++; 02539 tmp=file->max_key_parts(); 02540 if (key->columns.elements > tmp) 02541 { 02542 my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp); 02543 DBUG_RETURN(-1); 02544 } 02545 if (key->name && strlen(key->name) > NAME_LEN) 02546 { 02547 my_error(ER_TOO_LONG_IDENT, MYF(0), key->name); 02548 DBUG_RETURN(-1); 02549 } 02550 key_iterator2.rewind (); 02551 if (key->type != Key::FOREIGN_KEY) 02552 { 02553 while ((key2 = key_iterator2++) != key) 02554 { 02555 /* 02556 foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is 02557 'generated', and a generated key is a prefix of the other key. 02558 Then we do not need the generated shorter key. 02559 */ 02560 if ((key2->type != Key::FOREIGN_KEY && 02561 key2->name != ignore_key && 02562 !foreign_key_prefix(key, key2))) 02563 { 02564 /* TODO: issue warning message */ 02565 /* mark that the generated key should be ignored */ 02566 if (!key2->generated || 02567 (key->generated && key->columns.elements < 02568 key2->columns.elements)) 02569 key->name= ignore_key; 02570 else 02571 { 02572 key2->name= ignore_key; 02573 key_parts-= key2->columns.elements; 02574 (*key_count)--; 02575 } 02576 break; 02577 } 02578 } 02579 } 02580 if (key->name != ignore_key) 02581 key_parts+=key->columns.elements; 02582 else 02583 (*key_count)--; 02584 if (key->name && !tmp_table && (key->type != Key::PRIMARY) && 02585 !my_strcasecmp(system_charset_info,key->name,primary_key_name)) 02586 { 02587 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name); 02588 DBUG_RETURN(-1); 02589 } 02590 } 02591 tmp=file->max_keys(); 02592 if (*key_count > tmp) 02593 { 02594 my_error(ER_TOO_MANY_KEYS,MYF(0),tmp); 02595 DBUG_RETURN(-1); 02596 } 02597 02598 (*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count)); 02599 key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts); 02600 if (!*key_info_buffer || ! key_part_info) 02601 DBUG_RETURN(-1); // Out of memory 02602 02603 key_iterator.rewind(); 02604 key_number=0; 02605 for (; (key=key_iterator++) ; key_number++) 02606 { 02607 uint key_length=0; 02608 key_part_spec *column; 02609 02610 if (key->name == ignore_key) 02611 { 02612 /* ignore redundant keys */ 02613 do 02614 key=key_iterator++; 02615 while (key && key->name == ignore_key); 02616 if (!key) 02617 break; 02618 } 02619 02620 switch (key->type) { 02621 case Key::MULTIPLE: 02622 key_info->flags= 0; 02623 break; 02624 case Key::FULLTEXT: 02625 key_info->flags= HA_FULLTEXT; 02626 if ((key_info->parser_name= &key->key_create_info.parser_name)->str) 02627 key_info->flags|= HA_USES_PARSER; 02628 else 02629 key_info->parser_name= 0; 02630 break; 02631 case Key::SPATIAL: 02632 #ifdef HAVE_SPATIAL 02633 key_info->flags= HA_SPATIAL; 02634 break; 02635 #else 02636 my_error(ER_FEATURE_DISABLED, MYF(0), 02637 sym_group_geom.name, sym_group_geom.needed_define); 02638 DBUG_RETURN(-1); 02639 #endif 02640 case Key::FOREIGN_KEY: 02641 key_number--; // Skip this key 02642 continue; 02643 default: 02644 key_info->flags = HA_NOSAME; 02645 break; 02646 } 02647 if (key->generated) 02648 key_info->flags|= HA_GENERATED_KEY; 02649 02650 key_info->key_parts=(uint8) key->columns.elements; 02651 key_info->key_part=key_part_info; 02652 key_info->usable_key_parts= key_number; 02653 key_info->algorithm= key->key_create_info.algorithm; 02654 02655 if (key->type == Key::FULLTEXT) 02656 { 02657 if (!(file->ha_table_flags() & HA_CAN_FULLTEXT)) 02658 { 02659 my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT), 02660 MYF(0)); 02661 DBUG_RETURN(-1); 02662 } 02663 } 02664 /* 02665 Make SPATIAL to be RTREE by default 02666 SPATIAL only on BLOB or at least BINARY, this 02667 actually should be replaced by special GEOM type 02668 in near future when new frm file is ready 02669 checking for proper key parts number: 02670 */ 02671 02672 /* TODO: Add proper checks if handler supports key_type and algorithm */ 02673 if (key_info->flags & HA_SPATIAL) 02674 { 02675 if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS)) 02676 { 02677 my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS), 02678 MYF(0)); 02679 DBUG_RETURN(-1); 02680 } 02681 if (key_info->key_parts != 1) 02682 { 02683 my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX"); 02684 DBUG_RETURN(-1); 02685 } 02686 } 02687 else if (key_info->algorithm == HA_KEY_ALG_RTREE) 02688 { 02689 #ifdef HAVE_RTREE_KEYS 02690 if ((key_info->key_parts & 1) == 1) 02691 { 02692 my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX"); 02693 DBUG_RETURN(-1); 02694 } 02695 /* TODO: To be deleted */ 02696 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX"); 02697 DBUG_RETURN(-1); 02698 #else 02699 my_error(ER_FEATURE_DISABLED, MYF(0), 02700 sym_group_rtree.name, sym_group_rtree.needed_define); 02701 DBUG_RETURN(-1); 02702 #endif 02703 } 02704 02705 /* Take block size from key part or table part */ 02706 /* 02707 TODO: Add warning if block size changes. We can't do it here, as 02708 this may depend on the size of the key 02709 */ 02710 key_info->block_size= (key->key_create_info.block_size ? 02711 key->key_create_info.block_size : 02712 create_info->key_block_size); 02713 02714 if (key_info->block_size) 02715 key_info->flags|= HA_USES_BLOCK_SIZE; 02716 02717 List_iterator<key_part_spec> cols(key->columns), cols2(key->columns); 02718 CHARSET_INFO *ft_key_charset=0; // for FULLTEXT 02719 for (uint column_nr=0 ; (column=cols++) ; column_nr++) 02720 { 02721 uint length; 02722 key_part_spec *dup_column; 02723 02724 it.rewind(); 02725 field=0; 02726 while ((sql_field=it++) && 02727 my_strcasecmp(system_charset_info, 02728 column->field_name, 02729 sql_field->field_name)) 02730 field++; 02731 if (!sql_field) 02732 { 02733 my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name); 02734 DBUG_RETURN(-1); 02735 } 02736 while ((dup_column= cols2++) != column) 02737 { 02738 if (!my_strcasecmp(system_charset_info, 02739 column->field_name, dup_column->field_name)) 02740 { 02741 my_printf_error(ER_DUP_FIELDNAME, 02742 ER(ER_DUP_FIELDNAME),MYF(0), 02743 column->field_name); 02744 DBUG_RETURN(-1); 02745 } 02746 } 02747 cols2.rewind(); 02748 if (key->type == Key::FULLTEXT) 02749 { 02750 if ((sql_field->sql_type != MYSQL_TYPE_STRING && 02751 sql_field->sql_type != MYSQL_TYPE_VARCHAR && 02752 !f_is_blob(sql_field->pack_flag)) || 02753 sql_field->charset == &my_charset_bin || 02754 sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet 02755 (ft_key_charset && sql_field->charset != ft_key_charset)) 02756 { 02757 my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name); 02758 DBUG_RETURN(-1); 02759 } 02760 ft_key_charset=sql_field->charset; 02761 /* 02762 for fulltext keys keyseg length is 1 for blobs (it's ignored in ft 02763 code anyway, and 0 (set to column width later) for char's. it has 02764 to be correct col width for char's, as char data are not prefixed 02765 with length (unlike blobs, where ft code takes data length from a 02766 data prefix, ignoring column->length). 02767 */ 02768 column->length=test(f_is_blob(sql_field->pack_flag)); 02769 } 02770 else 02771 { 02772 column->length*= sql_field->charset->mbmaxlen; 02773 02774 if (f_is_blob(sql_field->pack_flag) || 02775 (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL)) 02776 { 02777 if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS)) 02778 { 02779 my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name); 02780 DBUG_RETURN(-1); 02781 } 02782 if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type == 02783 Field::GEOM_POINT) 02784 column->length= 21; 02785 if (!column->length) 02786 { 02787 my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name); 02788 DBUG_RETURN(-1); 02789 } 02790 } 02791 #ifdef HAVE_SPATIAL 02792 if (key->type == Key::SPATIAL) 02793 { 02794 if (!column->length) 02795 { 02796 /* 02797 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case 02798 Lately we'll extend this code to support more dimensions 02799 */ 02800 column->length= 4*sizeof(double); 02801 } 02802 } 02803 #endif 02804 if (!(sql_field->flags & NOT_NULL_FLAG)) 02805 { 02806 if (key->type == Key::PRIMARY) 02807 { 02808 /* Implicitly set primary key fields to NOT NULL for ISO conf. */ 02809 sql_field->flags|= NOT_NULL_FLAG; 02810 sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; 02811 null_fields--; 02812 } 02813 else 02814 { 02815 key_info->flags|= HA_NULL_PART_KEY; 02816 if (!(file->ha_table_flags() & HA_NULL_IN_KEY)) 02817 { 02818 my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name); 02819 DBUG_RETURN(-1); 02820 } 02821 if (key->type == Key::SPATIAL) 02822 { 02823 my_message(ER_SPATIAL_CANT_HAVE_NULL, 02824 ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0)); 02825 DBUG_RETURN(-1); 02826 } 02827 } 02828 } 02829 if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) 02830 { 02831 if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY)) 02832 auto_increment--; // Field is used 02833 } 02834 } 02835 02836 key_part_info->fieldnr= field; 02837 key_part_info->offset= (uint16) sql_field->offset; 02838 key_part_info->key_type=sql_field->pack_flag; 02839 length= sql_field->key_length; 02840 02841 if (column->length) 02842 { 02843 if (f_is_blob(sql_field->pack_flag)) 02844 { 02845 if ((length=column->length) > max_key_length || 02846 length > file->max_key_part_length()) 02847 { 02848 length=min(max_key_length, file->max_key_part_length()); 02849 if (key->type == Key::MULTIPLE) 02850 { 02851 /* not a critical problem */ 02852 char warn_buff[MYSQL_ERRMSG_SIZE]; 02853 my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY), 02854 length); 02855 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 02856 ER_TOO_LONG_KEY, warn_buff); 02857 } 02858 else 02859 { 02860 my_error(ER_TOO_LONG_KEY,MYF(0),length); 02861 DBUG_RETURN(-1); 02862 } 02863 } 02864 } 02865 else if (!f_is_geom(sql_field->pack_flag) && 02866 (column->length > length || 02867 ((f_is_packed(sql_field->pack_flag) || 02868 ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) && 02869 (key_info->flags & HA_NOSAME))) && 02870 column->length != length))) 02871 { 02872 my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0)); 02873 DBUG_RETURN(-1); 02874 } 02875 else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) 02876 length=column->length; 02877 } 02878 else if (length == 0) 02879 { 02880 my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name); 02881 DBUG_RETURN(-1); 02882 } 02883 if (length > file->max_key_part_length() && key->type != Key::FULLTEXT) 02884 { 02885 length= file->max_key_part_length(); 02886 /* Align key length to multibyte char boundary */ 02887 length-= length % sql_field->charset->mbmaxlen; 02888 if (key->type == Key::MULTIPLE) 02889 { 02890 /* not a critical problem */ 02891 char warn_buff[MYSQL_ERRMSG_SIZE]; 02892 my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY), 02893 length); 02894 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 02895 ER_TOO_LONG_KEY, warn_buff); 02896 } 02897 else 02898 { 02899 my_error(ER_TOO_LONG_KEY,MYF(0),length); 02900 DBUG_RETURN(-1); 02901 } 02902 } 02903 key_part_info->length=(uint16) length; 02904 /* Use packed keys for long strings on the first column */ 02905 if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && 02906 (length >= KEY_DEFAULT_PACK_LENGTH && 02907 (sql_field->sql_type == MYSQL_TYPE_STRING || 02908 sql_field->sql_type == MYSQL_TYPE_VARCHAR || 02909 sql_field->pack_flag & FIELDFLAG_BLOB))) 02910 { 02911 if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB) || 02912 sql_field->sql_type == MYSQL_TYPE_VARCHAR) 02913 key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY; 02914 else 02915 key_info->flags|= HA_PACK_KEY; 02916 } 02917 key_length+=length; 02918 key_part_info++; 02919 02920 /* Create the key name based on the first column (if not given) */ 02921 if (column_nr == 0) 02922 { 02923 if (key->type == Key::PRIMARY) 02924 { 02925 if (primary_key) 02926 { 02927 my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY), 02928 MYF(0)); 02929 DBUG_RETURN(-1); 02930 } 02931 key_name=primary_key_name; 02932 primary_key=1; 02933 } 02934 else if (!(key_name = key->name)) 02935 key_name=make_unique_key_name(sql_field->field_name, 02936 *key_info_buffer, key_info); 02937 if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) 02938 { 02939 my_error(ER_DUP_KEYNAME, MYF(0), key_name); 02940 DBUG_RETURN(-1); 02941 } 02942 key_info->name=(char*) key_name; 02943 } 02944 } 02945 if (!key_info->name || check_column_name(key_info->name)) 02946 { 02947 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name); 02948 DBUG_RETURN(-1); 02949 } 02950 if (!(key_info->flags & HA_NULL_PART_KEY)) 02951 unique_key=1; 02952 key_info->key_length=(uint16) key_length; 02953 if (key_length > max_key_length && key->type != Key::FULLTEXT) 02954 { 02955 my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length); 02956 DBUG_RETURN(-1); 02957 } 02958 key_info++; 02959 } 02960 if (!unique_key && !primary_key && 02961 (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY)) 02962 { 02963 my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0)); 02964 DBUG_RETURN(-1); 02965 } 02966 if (auto_increment > 0) 02967 { 02968 my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0)); 02969 DBUG_RETURN(-1); 02970 } 02971 /* Sort keys in optimized order */ 02972 qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY), 02973 (qsort_cmp) sort_keys); 02974 create_info->null_bits= null_fields; 02975 02976 DBUG_RETURN(0); 02977 } 02978 02979 02980 /* 02981 Set table default charset, if not set 02982 02983 SYNOPSIS 02984 set_table_default_charset() 02985 create_info Table create information 02986 02987 DESCRIPTION 02988 If the table character set was not given explicitely, 02989 let's fetch the database default character set and 02990 apply it to the table. 02991 */ 02992 02993 static void set_table_default_charset(THD *thd, 02994 HA_CREATE_INFO *create_info, char *db) 02995 { 02996 /* 02997 If the table character set was not given explicitly, 02998 let's fetch the database default character set and 02999 apply it to the table. 03000 */ 03001 if (!create_info->default_table_charset) 03002 { 03003 HA_CREATE_INFO db_info; 03004 03005 load_db_opt_by_name(thd, db, &db_info); 03006 03007 create_info->default_table_charset= db_info.default_table_charset; 03008 } 03009 } 03010 03011 03012 /* 03013 Extend long VARCHAR fields to blob & prepare field if it's a blob 03014 03015 SYNOPSIS 03016 prepare_blob_field() 03017 sql_field Field to check 03018 03019 RETURN 03020 0 ok 03021 1 Error (sql_field can't be converted to blob) 03022 In this case the error is given 03023 */ 03024 03025 static bool prepare_blob_field(THD *thd, create_field *sql_field) 03026 { 03027 DBUG_ENTER("prepare_blob_field"); 03028 03029 if (sql_field->length > MAX_FIELD_VARCHARLENGTH && 03030 !(sql_field->flags & BLOB_FLAG)) 03031 { 03032 /* Convert long VARCHAR columns to TEXT or BLOB */ 03033 char warn_buff[MYSQL_ERRMSG_SIZE]; 03034 03035 if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | 03036 MODE_STRICT_ALL_TABLES))) 03037 { 03038 my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name, 03039 MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen); 03040 DBUG_RETURN(1); 03041 } 03042 sql_field->sql_type= FIELD_TYPE_BLOB; 03043 sql_field->flags|= BLOB_FLAG; 03044 sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name, 03045 (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR", 03046 (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT"); 03047 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT, 03048 warn_buff); 03049 } 03050 03051 if ((sql_field->flags & BLOB_FLAG) && sql_field->length) 03052 { 03053 if (sql_field->sql_type == FIELD_TYPE_BLOB) 03054 { 03055 /* The user has given a length to the blob column */ 03056 sql_field->sql_type= get_blob_type_from_length(sql_field->length); 03057 sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0); 03058 } 03059 sql_field->length= 0; 03060 } 03061 DBUG_RETURN(0); 03062 } 03063 03064 03065 /* 03066 Preparation of create_field for SP function return values. 03067 Based on code used in the inner loop of mysql_prepare_table() above 03068 03069 SYNOPSIS 03070 sp_prepare_create_field() 03071 thd Thread object 03072 sql_field Field to prepare 03073 03074 DESCRIPTION 03075 Prepares the field structures for field creation. 03076 03077 */ 03078 03079 void sp_prepare_create_field(THD *thd, create_field *sql_field) 03080 { 03081 if (sql_field->sql_type == FIELD_TYPE_SET || 03082 sql_field->sql_type == FIELD_TYPE_ENUM) 03083 { 03084 uint32 field_length, dummy; 03085 if (sql_field->sql_type == FIELD_TYPE_SET) 03086 { 03087 calculate_interval_lengths(sql_field->charset, 03088 sql_field->interval, &dummy, 03089 &field_length); 03090 sql_field->length= field_length + 03091 (sql_field->interval->count - 1); 03092 } 03093 else /* FIELD_TYPE_ENUM */ 03094 { 03095 calculate_interval_lengths(sql_field->charset, 03096 sql_field->interval, 03097 &field_length, &dummy); 03098 sql_field->length= field_length; 03099 } 03100 set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1); 03101 } 03102 03103 if (sql_field->sql_type == FIELD_TYPE_BIT) 03104 { 03105 sql_field->pack_flag= FIELDFLAG_NUMBER | 03106 FIELDFLAG_TREAT_BIT_AS_CHAR; 03107 } 03108 sql_field->create_length_to_internal_length(); 03109 DBUG_ASSERT(sql_field->def == 0); 03110 /* Can't go wrong as sql_field->def is not defined */ 03111 (void) prepare_blob_field(thd, sql_field); 03112 } 03113 03114 03115 /* 03116 Copy HA_CREATE_INFO struct 03117 SYNOPSIS 03118 copy_create_info() 03119 lex_create_info The create_info struct setup by parser 03120 RETURN VALUES 03121 > 0 A pointer to a copy of the lex_create_info 03122 0 Memory allocation error 03123 DESCRIPTION 03124 Allocate memory for copy of HA_CREATE_INFO structure from parser 03125 to ensure we can reuse the parser struct in stored procedures 03126 and prepared statements. 03127 */ 03128 03129 static HA_CREATE_INFO *copy_create_info(HA_CREATE_INFO *lex_create_info) 03130 { 03131 HA_CREATE_INFO *create_info; 03132 if (!(create_info= (HA_CREATE_INFO*)sql_alloc(sizeof(HA_CREATE_INFO)))) 03133 mem_alloc_error(sizeof(HA_CREATE_INFO)); 03134 else 03135 memcpy((void*)create_info, (void*)lex_create_info, sizeof(HA_CREATE_INFO)); 03136 return create_info; 03137 } 03138 03139 03140 /* 03141 Create a table 03142 03143 SYNOPSIS 03144 mysql_create_table_internal() 03145 thd Thread object 03146 db Database 03147 table_name Table name 03148 lex_create_info Create information (like MAX_ROWS) 03149 fields List of fields to create 03150 keys List of keys to create 03151 internal_tmp_table Set to 1 if this is an internal temporary table 03152 (From ALTER TABLE) 03153 select_field_count 03154 use_copy_create_info Should we make a copy of create info (we do this 03155 when this is called from sql_parse.cc where we 03156 want to ensure lex object isn't manipulated. 03157 03158 DESCRIPTION 03159 If one creates a temporary table, this is automatically opened 03160 03161 no_log is needed for the case of CREATE ... SELECT, 03162 as the logging will be done later in sql_insert.cc 03163 select_field_count is also used for CREATE ... SELECT, 03164 and must be zero for standard create of table. 03165 03166 RETURN VALUES 03167 FALSE OK 03168 TRUE error 03169 */ 03170 03171 bool mysql_create_table_internal(THD *thd, 03172 const char *db, const char *table_name, 03173 HA_CREATE_INFO *lex_create_info, 03174 List<create_field> &fields, 03175 List<Key> &keys,bool internal_tmp_table, 03176 uint select_field_count, 03177 bool use_copy_create_info) 03178 { 03179 char path[FN_REFLEN]; 03180 uint path_length; 03181 const char *alias; 03182 uint db_options, key_count; 03183 KEY *key_info_buffer; 03184 HA_CREATE_INFO *create_info; 03185 handler *file; 03186 bool error= TRUE; 03187 DBUG_ENTER("mysql_create_table_internal"); 03188 DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", 03189 db, table_name, internal_tmp_table)); 03190 03191 if (use_copy_create_info) 03192 { 03193 if (!(create_info= copy_create_info(lex_create_info))) 03194 { 03195 DBUG_RETURN(TRUE); 03196 } 03197 } 03198 else 03199 create_info= lex_create_info; 03200 03201 /* Check for duplicate fields and check type of table to create */ 03202 if (!fields.elements) 03203 { 03204 my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS), 03205 MYF(0)); 03206 DBUG_RETURN(TRUE); 03207 } 03208 if (check_engine(thd, table_name, create_info)) 03209 DBUG_RETURN(TRUE); 03210 db_options= create_info->table_options; 03211 if (create_info->row_type == ROW_TYPE_DYNAMIC) 03212 db_options|=HA_OPTION_PACK_RECORD; 03213 alias= table_case_name(create_info, table_name); 03214 if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, 03215 create_info->db_type))) 03216 { 03217 mem_alloc_error(sizeof(handler)); 03218 DBUG_RETURN(TRUE); 03219 } 03220 #ifdef WITH_PARTITION_STORAGE_ENGINE 03221 partition_info *part_info= thd->work_part_info; 03222 03223 if (!part_info && create_info->db_type->partition_flags && 03224 (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION)) 03225 { 03226 /* 03227 Table is not defined as a partitioned table but the engine handles 03228 all tables as partitioned. The handler will set up the partition info 03229 object with the default settings. 03230 */ 03231 thd->work_part_info= part_info= new partition_info(); 03232 if (!part_info) 03233 { 03234 mem_alloc_error(sizeof(partition_info)); 03235 DBUG_RETURN(TRUE); 03236 } 03237 file->set_auto_partitions(part_info); 03238 part_info->default_engine_type= create_info->db_type; 03239 part_info->is_auto_partitioned= TRUE; 03240 } 03241 if (part_info) 03242 { 03243 /* 03244 The table has been specified as a partitioned table. 03245 If this is part of an ALTER TABLE the handler will be the partition 03246 handler but we need to specify the default handler to use for 03247 partitions also in the call to check_partition_info. We transport 03248 this information in the default_db_type variable, it is either 03249 DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command. 03250 03251 Check that we don't use foreign keys in the table since it won't 03252 work even with InnoDB beneath it. 03253 */ 03254 List_iterator<Key> key_iterator(keys); 03255 Key *key; 03256 handlerton *part_engine_type= create_info->db_type; 03257 char *part_syntax_buf; 03258 uint syntax_len; 03259 handlerton *engine_type; 03260 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) 03261 { 03262 my_error(ER_PARTITION_NO_TEMPORARY, MYF(0)); 03263 goto err; 03264 } 03265 while ((key= key_iterator++)) 03266 { 03267 if (key->type == Key::FOREIGN_KEY && 03268 !part_info->is_auto_partitioned) 03269 { 03270 my_error(ER_CANNOT_ADD_FOREIGN, MYF(0)); 03271 goto err; 03272 } 03273 } 03274 if ((part_engine_type == &partition_hton) && 03275 part_info->default_engine_type) 03276 { 03277 /* 03278 This only happens at ALTER TABLE. 03279 default_engine_type was assigned from the engine set in the ALTER 03280 TABLE command. 03281 */ 03282 ; 03283 } 03284 else 03285 { 03286 if (create_info->used_fields & HA_CREATE_USED_ENGINE) 03287 { 03288 part_info->default_engine_type= create_info->db_type; 03289 } 03290 else 03291 { 03292 if (part_info->default_engine_type == NULL) 03293 { 03294 part_info->default_engine_type= ha_checktype(thd, 03295 DB_TYPE_DEFAULT, 0, 0); 03296 } 03297 } 03298 } 03299 DBUG_PRINT("info", ("db_type = %d", 03300 ha_legacy_type(part_info->default_engine_type))); 03301 if (part_info->check_partition_info(thd, &engine_type, file, create_info)) 03302 goto err; 03303 part_info->default_engine_type= engine_type; 03304 03305 /* 03306 We reverse the partitioning parser and generate a standard format 03307 for syntax stored in frm file. 03308 */ 03309 if (!(part_syntax_buf= generate_partition_syntax(part_info, 03310 &syntax_len, 03311 TRUE, TRUE))) 03312 goto err; 03313 part_info->part_info_string= part_syntax_buf; 03314 part_info->part_info_len= syntax_len; 03315 if ((!(engine_type->partition_flags && 03316 engine_type->partition_flags() & HA_CAN_PARTITION)) || 03317 create_info->db_type == &partition_hton) 03318 { 03319 /* 03320 The handler assigned to the table cannot handle partitioning. 03321 Assign the partition handler as the handler of the table. 03322 */ 03323 DBUG_PRINT("info", ("db_type: %d", 03324 ha_legacy_type(create_info->db_type))); 03325 delete file; 03326 create_info->db_type= &partition_hton; 03327 if (!(file= get_ha_partition(part_info))) 03328 { 03329 DBUG_RETURN(TRUE); 03330 } 03331 /* 03332 If we have default number of partitions or subpartitions we 03333 might require to set-up the part_info object such that it 03334 creates a proper .par file. The current part_info object is 03335 only used to create the frm-file and .par-file. 03336 */ 03337 if (part_info->use_default_no_partitions && 03338 part_info->no_parts && 03339 (int)part_info->no_parts != 03340 file->get_default_no_partitions(create_info)) 03341 { 03342 uint i; 03343 List_iterator<partition_element> part_it(part_info->partitions); 03344 part_it++; 03345 DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE); 03346 for (i= 1; i < part_info->partitions.elements; i++) 03347 (part_it++)->part_state= PART_TO_BE_DROPPED; 03348 } 03349 else if (part_info->is_sub_partitioned() && 03350 part_info->use_default_no_subpartitions && 03351 part_info->no_subparts && 03352 (int)part_info->no_subparts != 03353 file->get_default_no_partitions(create_info)) 03354 { 03355 DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE); 03356 part_info->no_subparts= file->get_default_no_partitions(create_info); 03357 } 03358 } 03359 else if (create_info->db_type != engine_type) 03360 { 03361 /* 03362 We come here when we don't use a partitioned handler. 03363 Since we use a partitioned table it must be "native partitioned". 03364 We have switched engine from defaults, most likely only specified 03365 engines in partition clauses. 03366 */ 03367 delete file; 03368 if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, 03369 engine_type))) 03370 { 03371 mem_alloc_error(sizeof(handler)); 03372 DBUG_RETURN(TRUE); 03373 } 03374 } 03375 } 03376 #endif 03377 03378 set_table_default_charset(thd, create_info, (char*) db); 03379 03380 if (mysql_prepare_table(thd, create_info, &fields, 03381 &keys, internal_tmp_table, &db_options, file, 03382 &key_info_buffer, &key_count, 03383 select_field_count)) 03384 goto err; 03385 03386 /* Check if table exists */ 03387 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) 03388 { 03389 path_length= build_tmptable_filename(thd, path, sizeof(path)); 03390 if (lower_case_table_names) 03391 my_casedn_str(files_charset_info, path); 03392 create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; 03393 } 03394 else 03395 { 03396 #ifdef FN_DEVCHAR 03397 /* check if the table name contains FN_DEVCHAR when defined */ 03398 const char *start= alias; 03399 while (*start != '\0') 03400 { 03401 if (*start == FN_DEVCHAR) 03402 { 03403 my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); 03404 DBUG_RETURN(TRUE); 03405 } 03406 start++; 03407 } 03408 #endif 03409 path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext, 03410 internal_tmp_table ? FN_IS_TMP : 0); 03411 } 03412 03413 /* Check if table already exists */ 03414 if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) && 03415 find_temporary_table(thd, db, table_name)) 03416 { 03417 if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) 03418 { 03419 create_info->table_existed= 1; // Mark that table existed 03420 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 03421 ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), 03422 alias); 03423 error= 0; 03424 goto err; 03425 } 03426 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); 03427 goto err; 03428 } 03429 03430 VOID(pthread_mutex_lock(&LOCK_open)); 03431 if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) 03432 { 03433 if (!access(path,F_OK)) 03434 { 03435 if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) 03436 goto warn; 03437 my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); 03438 goto unlock_and_end; 03439 } 03440 /* 03441 We don't assert here, but check the result, because the table could be 03442 in the table definition cache and in the same time the .frm could be 03443 missing from the disk, in case of manual intervention which deletes 03444 the .frm file. The user has to use FLUSH TABLES; to clear the cache. 03445 Then she could create the table. This case is pretty obscure and 03446 therefore we don't introduce a new error message only for it. 03447 */ 03448 if (get_cached_table_share(db, alias)) 03449 { 03450 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); 03451 goto unlock_and_end; 03452 } 03453 } 03454 03455 /* 03456 Check that table with given name does not already 03457 exist in any storage engine. In such a case it should 03458 be discovered and the error ER_TABLE_EXISTS_ERROR be returned 03459 unless user specified CREATE TABLE IF EXISTS 03460 The LOCK_open mutex has been locked to make sure no 03461 one else is attempting to discover the table. Since 03462 it's not on disk as a frm file, no one could be using it! 03463 */ 03464 if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) 03465 { 03466 bool create_if_not_exists = 03467 create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS; 03468 if (ha_table_exists_in_engine(thd, db, table_name)) 03469 { 03470 DBUG_PRINT("info", ("Table with same name already existed in handler")); 03471 03472 if (create_if_not_exists) 03473 goto warn; 03474 my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); 03475 goto unlock_and_end; 03476 } 03477 } 03478 03479 thd->proc_info="creating table"; 03480 create_info->table_existed= 0; // Mark that table is created 03481 03482 if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) 03483 create_info->data_file_name= create_info->index_file_name= 0; 03484 create_info->table_options=db_options; 03485 03486 path[path_length - reg_ext_length]= '\0'; // Remove .frm extension 03487 if (rea_create_table(thd, path, db, table_name, create_info, fields, 03488 key_count, key_info_buffer, file)) 03489 goto unlock_and_end; 03490 03491 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) 03492 { 03493 /* Open table and put in temporary table list */ 03494 if (!(open_temporary_table(thd, path, db, table_name, 1))) 03495 { 03496 (void) rm_temporary_table(create_info->db_type, path); 03497 goto unlock_and_end; 03498 } 03499 thd->tmp_table_used= 1; 03500 } 03501 03502 /* 03503 Don't write statement if: 03504 - It is an internal temporary table, 03505 - Row-based logging is used and it we are creating a temporary table, or 03506 - The binary log is not open. 03507 Otherwise, the statement shall be binlogged. 03508 */ 03509 if (!internal_tmp_table && 03510 (!thd->current_stmt_binlog_row_based || 03511 (thd->current_stmt_binlog_row_based && 03512 !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) 03513 write_bin_log(thd, TRUE, thd->query, thd->query_length); 03514 error= FALSE; 03515 unlock_and_end: 03516 VOID(pthread_mutex_unlock(&LOCK_open)); 03517 03518 err: 03519 thd->proc_info="After create"; 03520 delete file; 03521 DBUG_RETURN(error); 03522 03523 warn: 03524 error= FALSE; 03525 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 03526 ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), 03527 alias); 03528 create_info->table_existed= 1; // Mark that table existed 03529 goto unlock_and_end; 03530 } 03531 03532 03533 /* 03534 Database locking aware wrapper for mysql_create_table_internal(), 03535 */ 03536 03537 bool mysql_create_table(THD *thd, const char *db, const char *table_name, 03538 HA_CREATE_INFO *create_info, 03539 List<create_field> &fields, 03540 List<Key> &keys,bool internal_tmp_table, 03541 uint select_field_count, 03542 bool use_copy_create_info) 03543 { 03544 bool result; 03545 DBUG_ENTER("mysql_create_table"); 03546 03547 /* Wait for any database locks */ 03548 pthread_mutex_lock(&LOCK_lock_db); 03549 while (!thd->killed && 03550 hash_search(&lock_db_cache,(byte*) db, strlen(db))) 03551 { 03552 wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); 03553 pthread_mutex_lock(&LOCK_lock_db); 03554 } 03555 03556 if (thd->killed) 03557 { 03558 pthread_mutex_unlock(&LOCK_lock_db); 03559 DBUG_RETURN(TRUE); 03560 } 03561 creating_table++; 03562 pthread_mutex_unlock(&LOCK_lock_db); 03563 03564 result= mysql_create_table_internal(thd, db, table_name, create_info, 03565 fields, keys, internal_tmp_table, 03566 select_field_count, 03567 use_copy_create_info); 03568 03569 pthread_mutex_lock(&LOCK_lock_db); 03570 if (!--creating_table && creating_database) 03571 pthread_cond_signal(&COND_refresh); 03572 pthread_mutex_unlock(&LOCK_lock_db); 03573 DBUG_RETURN(result); 03574 } 03575 03576 03577 /* 03578 ** Give the key name after the first field with an optional '_#' after 03579 **/ 03580 03581 static bool 03582 check_if_keyname_exists(const char *name, KEY *start, KEY *end) 03583 { 03584 for (KEY *key=start ; key != end ; key++) 03585 if (!my_strcasecmp(system_charset_info,name,key->name)) 03586 return 1; 03587 return 0; 03588 } 03589 03590 03591 static char * 03592 make_unique_key_name(const char *field_name,KEY *start,KEY *end) 03593 { 03594 char buff[MAX_FIELD_NAME],*buff_end; 03595 03596 if (!check_if_keyname_exists(field_name,start,end) && 03597 my_strcasecmp(system_charset_info,field_name,primary_key_name)) 03598 return (char*) field_name; // Use fieldname 03599 buff_end=strmake(buff,field_name, sizeof(buff)-4); 03600 03601 /* 03602 Only 3 chars + '\0' left, so need to limit to 2 digit 03603 This is ok as we can't have more than 100 keys anyway 03604 */ 03605 for (uint i=2 ; i< 100; i++) 03606 { 03607 *buff_end= '_'; 03608 int10_to_str(i, buff_end+1, 10); 03609 if (!check_if_keyname_exists(buff,start,end)) 03610 return sql_strdup(buff); 03611 } 03612 return (char*) "not_specified"; // Should never happen 03613 } 03614 03615 03616 /**************************************************************************** 03617 ** Alter a table definition 03618 ****************************************************************************/ 03619 03620 03621 /* 03622 Rename a table. 03623 03624 SYNOPSIS 03625 mysql_rename_table() 03626 base The handlerton handle. 03627 old_db The old database name. 03628 old_name The old table name. 03629 new_db The new database name. 03630 new_name The new table name. 03631 flags flags for build_table_filename(). 03632 FN_FROM_IS_TMP old_name is temporary. 03633 FN_TO_IS_TMP new_name is temporary. 03634 03635 RETURN 03636 0 OK 03637 != 0 Error 03638 */ 03639 03640 bool 03641 mysql_rename_table(handlerton *base, const char *old_db, 03642 const char *old_name, const char *new_db, 03643 const char *new_name, uint flags) 03644 { 03645 THD *thd= current_thd; 03646 char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN]; 03647 char *from_base= from, *to_base= to; 03648 char tmp_name[NAME_LEN+1]; 03649 handler *file; 03650 int error=0; 03651 DBUG_ENTER("mysql_rename_table"); 03652 DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'", 03653 old_db, old_name, new_db, new_name)); 03654 03655 file= (base == NULL ? 0 : 03656 get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base)); 03657 03658 build_table_filename(from, sizeof(from), old_db, old_name, "", 03659 flags & FN_FROM_IS_TMP); 03660 build_table_filename(to, sizeof(to), new_db, new_name, "", 03661 flags & FN_TO_IS_TMP); 03662 03663 /* 03664 If lower_case_table_names == 2 (case-preserving but case-insensitive 03665 file system) and the storage is not HA_FILE_BASED, we need to provide 03666 a lowercase file name, but we leave the .frm in mixed case. 03667 */ 03668 if (lower_case_table_names == 2 && file && 03669 !(file->ha_table_flags() & HA_FILE_BASED)) 03670 { 03671 strmov(tmp_name, old_name); 03672 my_casedn_str(files_charset_info, tmp_name); 03673 build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "", 03674 flags & FN_FROM_IS_TMP); 03675 from_base= lc_from; 03676 03677 strmov(tmp_name, new_name); 03678 my_casedn_str(files_charset_info, tmp_name); 03679 build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "", 03680 flags & FN_TO_IS_TMP); 03681 to_base= lc_to; 03682 } 03683 03684 if (!file || !(error=file->rename_table(from_base, to_base))) 03685 { 03686 if (rename_file_ext(from,to,reg_ext)) 03687 { 03688 error=my_errno; 03689 /* Restore old file name */ 03690 if (file) 03691 file->rename_table(to_base, from_base); 03692 } 03693 } 03694 delete file; 03695 if (error == HA_ERR_WRONG_COMMAND) 03696 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE"); 03697 else if (error) 03698 my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error); 03699 DBUG_RETURN(error != 0); 03700 } 03701 03702 03703 /* 03704 Force all other threads to stop using the table 03705 03706 SYNOPSIS 03707 wait_while_table_is_used() 03708 thd Thread handler 03709 table Table to remove from cache 03710 function HA_EXTRA_PREPARE_FOR_DELETE if table is to be deleted 03711 HA_EXTRA_FORCE_REOPEN if table is not be used 03712 NOTES 03713 When returning, the table will be unusable for other threads until 03714 the table is closed. 03715 03716 PREREQUISITES 03717 Lock on LOCK_open 03718 Win32 clients must also have a WRITE LOCK on the table ! 03719 */ 03720 03721 static void wait_while_table_is_used(THD *thd,TABLE *table, 03722 enum ha_extra_function function) 03723 { 03724 DBUG_ENTER("wait_while_table_is_used"); 03725 DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %u", 03726 table->s->table_name.str, (ulong) table->s, 03727 table->db_stat, table->s->version)); 03728 03729 VOID(table->file->extra(function)); 03730 /* Mark all tables that are in use as 'old' */ 03731 mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */ 03732 03733 /* Wait until all there are no other threads that has this table open */ 03734 remove_table_from_cache(thd, table->s->db.str, 03735 table->s->table_name.str, 03736 RTFC_WAIT_OTHER_THREAD_FLAG); 03737 DBUG_VOID_RETURN; 03738 } 03739 03740 /* 03741 Close a cached table 03742 03743 SYNOPSIS 03744 close_cached_table() 03745 thd Thread handler 03746 table Table to remove from cache 03747 03748 NOTES 03749 Function ends by signaling threads waiting for the table to try to 03750 reopen the table. 03751 03752 PREREQUISITES 03753 Lock on LOCK_open 03754 Win32 clients must also have a WRITE LOCK on the table ! 03755 */ 03756 03757 void close_cached_table(THD *thd, TABLE *table) 03758 { 03759 DBUG_ENTER("close_cached_table"); 03760 03761 wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE); 03762 /* Close lock if this is not got with LOCK TABLES */ 03763 if (thd->lock) 03764 { 03765 mysql_unlock_tables(thd, thd->lock); 03766 thd->lock=0; // Start locked threads 03767 } 03768 /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ 03769 thd->open_tables=unlink_open_table(thd,thd->open_tables,table); 03770 03771 /* When lock on LOCK_open is freed other threads can continue */ 03772 broadcast_refresh(); 03773 DBUG_VOID_RETURN; 03774 } 03775 03776 static int send_check_errmsg(THD *thd, TABLE_LIST* table, 03777 const char* operator_name, const char* errmsg) 03778 03779 { 03780 Protocol *protocol= thd->protocol; 03781 protocol->prepare_for_resend(); 03782 protocol->store(table->alias, system_charset_info); 03783 protocol->store((char*) operator_name, system_charset_info); 03784 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 03785 protocol->store(errmsg, system_charset_info); 03786 thd->clear_error(); 03787 if (protocol->write()) 03788 return -1; 03789 return 1; 03790 } 03791 03792 03793 static int prepare_for_restore(THD* thd, TABLE_LIST* table, 03794 HA_CHECK_OPT *check_opt) 03795 { 03796 DBUG_ENTER("prepare_for_restore"); 03797 03798 if (table->table) // do not overwrite existing tables on restore 03799 { 03800 DBUG_RETURN(send_check_errmsg(thd, table, "restore", 03801 "table exists, will not overwrite on restore" 03802 )); 03803 } 03804 else 03805 { 03806 char* backup_dir= thd->lex->backup_dir; 03807 char src_path[FN_REFLEN], dst_path[FN_REFLEN], uname[FN_REFLEN]; 03808 char* table_name= table->table_name; 03809 char* db= table->db; 03810 03811 VOID(tablename_to_filename(table->table_name, uname, sizeof(uname))); 03812 03813 if (fn_format_relative_to_data_home(src_path, uname, backup_dir, reg_ext)) 03814 DBUG_RETURN(-1); // protect buffer overflow 03815 03816 build_table_filename(dst_path, sizeof(dst_path), 03817 db, table_name, reg_ext, 0); 03818 03819 if (lock_and_wait_for_table_name(thd,table)) 03820 DBUG_RETURN(-1); 03821 03822 if (my_copy(src_path, dst_path, MYF(MY_WME))) 03823 { 03824 pthread_mutex_lock(&LOCK_open); 03825 unlock_table_name(thd, table); 03826 pthread_mutex_unlock(&LOCK_open); 03827 DBUG_RETURN(send_check_errmsg(thd, table, "restore", 03828 "Failed copying .frm file")); 03829 } 03830 if (mysql_truncate(thd, table, 1)) 03831 { 03832 pthread_mutex_lock(&LOCK_open); 03833 unlock_table_name(thd, table); 03834 pthread_mutex_unlock(&LOCK_open); 03835 DBUG_RETURN(send_check_errmsg(thd, table, "restore", 03836 "Failed generating table from .frm file")); 03837 } 03838 } 03839 03840 /* 03841 Now we should be able to open the partially restored table 03842 to finish the restore in the handler later on 03843 */ 03844 pthread_mutex_lock(&LOCK_open); 03845 if (reopen_name_locked_table(thd, table)) 03846 { 03847 unlock_table_name(thd, table); 03848 pthread_mutex_unlock(&LOCK_open); 03849 DBUG_RETURN(send_check_errmsg(thd, table, "restore", 03850 "Failed to open partially restored table")); 03851 } 03852 pthread_mutex_unlock(&LOCK_open); 03853 DBUG_RETURN(0); 03854 } 03855 03856 03857 static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, 03858 HA_CHECK_OPT *check_opt) 03859 { 03860 int error= 0; 03861 TABLE tmp_table, *table; 03862 TABLE_SHARE *share; 03863 char from[FN_REFLEN],tmp[FN_REFLEN+32]; 03864 const char **ext; 03865 MY_STAT stat_info; 03866 DBUG_ENTER("prepare_for_repair"); 03867 03868 if (!(check_opt->sql_flags & TT_USEFRM)) 03869 DBUG_RETURN(0); 03870 03871 if (!(table= table_list->table)) /* if open_ltable failed */ 03872 { 03873 char key[MAX_DBKEY_LENGTH]; 03874 uint key_length; 03875 03876 key_length= create_table_def_key(thd, key, table_list, 0); 03877 pthread_mutex_lock(&LOCK_open); 03878 if (!(share= (get_table_share(thd, table_list, key, key_length, 0, 03879 &error)))) 03880 { 03881 pthread_mutex_unlock(&LOCK_open); 03882 DBUG_RETURN(0); // Can't open frm file 03883 } 03884 03885 if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE)) 03886 { 03887 release_table_share(share, RELEASE_NORMAL); 03888 pthread_mutex_unlock(&LOCK_open); 03889 DBUG_RETURN(0); // Out of memory 03890 } 03891 table= &tmp_table; 03892 pthread_mutex_unlock(&LOCK_open); 03893 } 03894 /* 03895 REPAIR TABLE ... USE_FRM for temporary tables makes little sense. 03896 */ 03897 if (table->s->tmp_table) 03898 { 03899 error= send_check_errmsg(thd, table_list, "repair", 03900 "Cannot repair temporary table from .frm file"); 03901 goto end; 03902 } 03903 03904 /* 03905 User gave us USE_FRM which means that the header in the index file is 03906 trashed. 03907 In this case we will try to fix the table the following way: 03908 - Rename the data file to a temporary name 03909 - Truncate the table 03910 - Replace the new data file with the old one 03911 - Run a normal repair using the new index file and the old data file 03912 */ 03913 03914 /* 03915 Check if this is a table type that stores index and data separately, 03916 like ISAM or MyISAM 03917 */ 03918 ext= table->file->bas_ext(); 03919 if (!ext[0] || !ext[1]) 03920 goto end; // No data file 03921 03922 // Name of data file 03923 strxmov(from, table->s->normalized_path.str, ext[1], NullS); 03924 if (!my_stat(from, &stat_info, MYF(0))) 03925 goto end; // Can't use USE_FRM flag 03926 03927 my_snprintf(tmp, sizeof(tmp), "%s-%lx_%lx", 03928 from, current_pid, thd->thread_id); 03929 03930 /* If we could open the table, close it */ 03931 if (table_list->table) 03932 { 03933 pthread_mutex_lock(&LOCK_open); 03934 close_cached_table(thd, table); 03935 pthread_mutex_unlock(&LOCK_open); 03936 } 03937 if (lock_and_wait_for_table_name(thd,table_list)) 03938 { 03939 error= -1; 03940 goto end; 03941 } 03942 if (my_rename(from, tmp, MYF(MY_WME))) 03943 { 03944 pthread_mutex_lock(&LOCK_open); 03945 unlock_table_name(thd, table_list); 03946 pthread_mutex_unlock(&LOCK_open); 03947 error= send_check_errmsg(thd, table_list, "repair", 03948 "Failed renaming data file"); 03949 goto end; 03950 } 03951 if (mysql_truncate(thd, table_list, 1)) 03952 { 03953 pthread_mutex_lock(&LOCK_open); 03954 unlock_table_name(thd, table_list); 03955 pthread_mutex_unlock(&LOCK_open); 03956 error= send_check_errmsg(thd, table_list, "repair", 03957 "Failed generating table from .frm file"); 03958 goto end; 03959 } 03960 if (my_rename(tmp, from, MYF(MY_WME))) 03961 { 03962 pthread_mutex_lock(&LOCK_open); 03963 unlock_table_name(thd, table_list); 03964 pthread_mutex_unlock(&LOCK_open); 03965 error= send_check_errmsg(thd, table_list, "repair", 03966 "Failed restoring .MYD file"); 03967 goto end; 03968 } 03969 03970 /* 03971 Now we should be able to open the partially repaired table 03972 to finish the repair in the handler later on. 03973 */ 03974 pthread_mutex_lock(&LOCK_open); 03975 if (reopen_name_locked_table(thd, table_list)) 03976 { 03977 unlock_table_name(thd, table_list); 03978 pthread_mutex_unlock(&LOCK_open); 03979 error= send_check_errmsg(thd, table_list, "repair", 03980 "Failed to open partially repaired table"); 03981 goto end; 03982 } 03983 pthread_mutex_unlock(&LOCK_open); 03984 03985 end: 03986 if (table == &tmp_table) 03987 { 03988 pthread_mutex_lock(&LOCK_open); 03989 closefrm(table, 1); // Free allocated memory 03990 pthread_mutex_unlock(&LOCK_open); 03991 } 03992 DBUG_RETURN(error); 03993 } 03994 03995 03996 03997 /* 03998 RETURN VALUES 03999 FALSE Message sent to net (admin operation went ok) 04000 TRUE Message should be sent by caller 04001 (admin operation or network communication failed) 04002 */ 04003 static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, 04004 HA_CHECK_OPT* check_opt, 04005 const char *operator_name, 04006 thr_lock_type lock_type, 04007 bool open_for_modify, 04008 bool no_warnings_for_error, 04009 uint extra_open_options, 04010 int (*prepare_func)(THD *, TABLE_LIST *, 04011 HA_CHECK_OPT *), 04012 int (handler::*operator_func)(THD *, 04013 HA_CHECK_OPT *), 04014 int (view_operator_func)(THD *, TABLE_LIST*)) 04015 { 04016 TABLE_LIST *table, *save_next_global, *save_next_local; 04017 SELECT_LEX *select= &thd->lex->select_lex; 04018 List<Item> field_list; 04019 Item *item; 04020 Protocol *protocol= thd->protocol; 04021 LEX *lex= thd->lex; 04022 int result_code; 04023 DBUG_ENTER("mysql_admin_table"); 04024 04025 if (end_active_trans(thd)) 04026 DBUG_RETURN(1); 04027 field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); 04028 item->maybe_null = 1; 04029 field_list.push_back(item = new Item_empty_string("Op", 10)); 04030 item->maybe_null = 1; 04031 field_list.push_back(item = new Item_empty_string("Msg_type", 10)); 04032 item->maybe_null = 1; 04033 field_list.push_back(item = new Item_empty_string("Msg_text", 255)); 04034 item->maybe_null = 1; 04035 if (protocol->send_fields(&field_list, 04036 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 04037 DBUG_RETURN(TRUE); 04038 04039 mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, FALSE); 04040 for (table= tables; table; table= table->next_local) 04041 { 04042 char table_name[NAME_LEN*2+2]; 04043 char* db = table->db; 04044 bool fatal_error=0; 04045 04046 strxmov(table_name, db, ".", table->table_name, NullS); 04047 thd->open_options|= extra_open_options; 04048 table->lock_type= lock_type; 04049 /* open only one table from local list of command */ 04050 save_next_global= table->next_global; 04051 table->next_global= 0; 04052 save_next_local= table->next_local; 04053 table->next_local= 0; 04054 select->table_list.first= (byte*)table; 04055 /* 04056 Time zone tables and SP tables can be add to lex->query_tables list, 04057 so it have to be prepared. 04058 TODO: Investigate if we can put extra tables into argument instead of 04059 using lex->query_tables 04060 */ 04061 lex->query_tables= table; 04062 lex->query_tables_last= &table->next_global; 04063 lex->query_tables_own_last= 0; 04064 thd->no_warnings_for_error= no_warnings_for_error; 04065 if (view_operator_func == NULL) 04066 table->required_type=FRMTYPE_TABLE; 04067 open_and_lock_tables(thd, table); 04068 thd->no_warnings_for_error= 0; 04069 table->next_global= save_next_global; 04070 table->next_local= save_next_local; 04071 thd->open_options&= ~extra_open_options; 04072 04073 if (prepare_func) 04074 { 04075 switch ((*prepare_func)(thd, table, check_opt)) { 04076 case 1: // error, message written to net 04077 ha_autocommit_or_rollback(thd, 1); 04078 close_thread_tables(thd); 04079 continue; 04080 case -1: // error, message could be written to net 04081 goto err; 04082 default: // should be 0 otherwise 04083 ; 04084 } 04085 } 04086 04087 /* 04088 CHECK TABLE command is only command where VIEW allowed here and this 04089 command use only temporary teble method for VIEWs resolving => there 04090 can't be VIEW tree substitition of join view => if opening table 04091 succeed then table->table will have real TABLE pointer as value (in 04092 case of join view substitution table->table can be 0, but here it is 04093 impossible) 04094 */ 04095 if (!table->table) 04096 { 04097 char buf[ERRMSGSIZE+ERRMSGSIZE+2]; 04098 const char *err_msg; 04099 protocol->prepare_for_resend(); 04100 protocol->store(table_name, system_charset_info); 04101 protocol->store(operator_name, system_charset_info); 04102 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04103 if (!(err_msg=thd->net.last_error)) 04104 err_msg=ER(ER_CHECK_NO_SUCH_TABLE); 04105 /* if it was a view will check md5 sum */ 04106 if (table->view && 04107 view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM) 04108 { 04109 strxmov(buf, err_msg, "; ", ER(ER_VIEW_CHECKSUM), NullS); 04110 err_msg= (const char *)buf; 04111 } 04112 protocol->store(err_msg, system_charset_info); 04113 lex->cleanup_after_one_table_open(); 04114 thd->clear_error(); 04115 /* 04116 View opening can be interrupted in the middle of process so some 04117 tables can be left opening 04118 */ 04119 ha_autocommit_or_rollback(thd, 1); 04120 close_thread_tables(thd); 04121 lex->reset_query_tables_list(FALSE); 04122 if (protocol->write()) 04123 goto err; 04124 continue; 04125 } 04126 04127 if (table->view) 04128 { 04129 result_code= (*view_operator_func)(thd, table); 04130 goto send_result; 04131 } 04132 04133 table->table->pos_in_table_list= table; 04134 if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify) 04135 { 04136 char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; 04137 uint length; 04138 protocol->prepare_for_resend(); 04139 protocol->store(table_name, system_charset_info); 04140 protocol->store(operator_name, system_charset_info); 04141 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04142 length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY), 04143 table_name); 04144 protocol->store(buff, length, system_charset_info); 04145 ha_autocommit_or_rollback(thd, 0); 04146 close_thread_tables(thd); 04147 lex->reset_query_tables_list(FALSE); 04148 table->table=0; // For query cache 04149 if (protocol->write()) 04150 goto err; 04151 continue; 04152 } 04153 04154 /* Close all instances of the table to allow repair to rename files */ 04155 if (lock_type == TL_WRITE && table->table->s->version && 04156 !table->table->s->log_table) 04157 { 04158 pthread_mutex_lock(&LOCK_open); 04159 const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open, 04160 "Waiting to get writelock"); 04161 mysql_lock_abort(thd,table->table, TRUE); 04162 remove_table_from_cache(thd, table->table->s->db.str, 04163 table->table->s->table_name.str, 04164 RTFC_WAIT_OTHER_THREAD_FLAG | 04165 RTFC_CHECK_KILLED_FLAG); 04166 thd->exit_cond(old_message); 04167 if (thd->killed) 04168 goto err; 04169 /* Flush entries in the query cache involving this table. */ 04170 query_cache_invalidate3(thd, table->table, 0); 04171 open_for_modify= 0; 04172 } 04173 04174 if (table->table->s->crashed && operator_func == &handler::ha_check) 04175 { 04176 protocol->prepare_for_resend(); 04177 protocol->store(table_name, system_charset_info); 04178 protocol->store(operator_name, system_charset_info); 04179 protocol->store(STRING_WITH_LEN("warning"), system_charset_info); 04180 protocol->store(STRING_WITH_LEN("Table is marked as crashed"), 04181 system_charset_info); 04182 if (protocol->write()) 04183 goto err; 04184 } 04185 04186 if (operator_func == &handler::ha_repair) 04187 { 04188 if ((table->table->file->check_old_types() == HA_ADMIN_NEEDS_ALTER) || 04189 (table->table->file->ha_check_for_upgrade(check_opt) == 04190 HA_ADMIN_NEEDS_ALTER)) 04191 { 04192 ha_autocommit_or_rollback(thd, 1); 04193 close_thread_tables(thd); 04194 tmp_disable_binlog(thd); // binlogging is done by caller if wanted 04195 result_code= mysql_recreate_table(thd, table, 0); 04196 reenable_binlog(thd); 04197 goto send_result; 04198 } 04199 04200 } 04201 04202 result_code = (table->table->file->*operator_func)(thd, check_opt); 04203 04204 send_result: 04205 04206 lex->cleanup_after_one_table_open(); 04207 thd->clear_error(); // these errors shouldn't get client 04208 protocol->prepare_for_resend(); 04209 protocol->store(table_name, system_charset_info); 04210 protocol->store(operator_name, system_charset_info); 04211 04212 send_result_message: 04213 04214 DBUG_PRINT("info", ("result_code: %d", result_code)); 04215 switch (result_code) { 04216 case HA_ADMIN_NOT_IMPLEMENTED: 04217 { 04218 char buf[ERRMSGSIZE+20]; 04219 uint length=my_snprintf(buf, ERRMSGSIZE, 04220 ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); 04221 protocol->store(STRING_WITH_LEN("note"), system_charset_info); 04222 protocol->store(buf, length, system_charset_info); 04223 } 04224 break; 04225 04226 case HA_ADMIN_NOT_BASE_TABLE: 04227 { 04228 char buf[ERRMSGSIZE+20]; 04229 uint length= my_snprintf(buf, ERRMSGSIZE, 04230 ER(ER_BAD_TABLE_ERROR), table_name); 04231 protocol->store(STRING_WITH_LEN("note"), system_charset_info); 04232 protocol->store(buf, length, system_charset_info); 04233 } 04234 break; 04235 04236 case HA_ADMIN_OK: 04237 protocol->store(STRING_WITH_LEN("status"), system_charset_info); 04238 protocol->store(STRING_WITH_LEN("OK"), system_charset_info); 04239 break; 04240 04241 case HA_ADMIN_FAILED: 04242 protocol->store(STRING_WITH_LEN("status"), system_charset_info); 04243 protocol->store(STRING_WITH_LEN("Operation failed"), 04244 system_charset_info); 04245 break; 04246 04247 case HA_ADMIN_REJECT: 04248 protocol->store(STRING_WITH_LEN("status"), system_charset_info); 04249 protocol->store(STRING_WITH_LEN("Operation need committed state"), 04250 system_charset_info); 04251 open_for_modify= FALSE; 04252 break; 04253 04254 case HA_ADMIN_ALREADY_DONE: 04255 protocol->store(STRING_WITH_LEN("status"), system_charset_info); 04256 protocol->store(STRING_WITH_LEN("Table is already up to date"), 04257 system_charset_info); 04258 break; 04259 04260 case HA_ADMIN_CORRUPT: 04261 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04262 protocol->store(STRING_WITH_LEN("Corrupt"), system_charset_info); 04263 fatal_error=1; 04264 break; 04265 04266 case HA_ADMIN_INVALID: 04267 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04268 protocol->store(STRING_WITH_LEN("Invalid argument"), 04269 system_charset_info); 04270 break; 04271 04272 case HA_ADMIN_TRY_ALTER: 04273 { 04274 /* 04275 This is currently used only by InnoDB. ha_innobase::optimize() answers 04276 "try with alter", so here we close the table, do an ALTER TABLE, 04277 reopen the table and do ha_innobase::analyze() on it. 04278 */ 04279 ha_autocommit_or_rollback(thd, 0); 04280 close_thread_tables(thd); 04281 TABLE_LIST *save_next_local= table->next_local, 04282 *save_next_global= table->next_global; 04283 table->next_local= table->next_global= 0; 04284 tmp_disable_binlog(thd); // binlogging is done by caller if wanted 04285 result_code= mysql_recreate_table(thd, table, 0); 04286 reenable_binlog(thd); 04287 ha_autocommit_or_rollback(thd, 0); 04288 close_thread_tables(thd); 04289 if (!result_code) // recreation went ok 04290 { 04291 if ((table->table= open_ltable(thd, table, lock_type)) && 04292 ((result_code= table->table->file->analyze(thd, check_opt)) > 0)) 04293 result_code= 0; // analyze went ok 04294 } 04295 if (result_code) // either mysql_recreate_table or analyze failed 04296 { 04297 const char *err_msg; 04298 if ((err_msg= thd->net.last_error)) 04299 { 04300 if (!thd->vio_ok()) 04301 { 04302 sql_print_error(err_msg); 04303 } 04304 else 04305 { 04306 /* Hijack the row already in-progress. */ 04307 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04308 protocol->store(err_msg, system_charset_info); 04309 (void)protocol->write(); 04310 /* Start off another row for HA_ADMIN_FAILED */ 04311 protocol->prepare_for_resend(); 04312 protocol->store(table_name, system_charset_info); 04313 protocol->store(operator_name, system_charset_info); 04314 } 04315 } 04316 } 04317 result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK; 04318 table->next_local= save_next_local; 04319 table->next_global= save_next_global; 04320 goto send_result_message; 04321 } 04322 case HA_ADMIN_WRONG_CHECKSUM: 04323 { 04324 protocol->store(STRING_WITH_LEN("note"), system_charset_info); 04325 protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)), 04326 system_charset_info); 04327 break; 04328 } 04329 04330 case HA_ADMIN_NEEDS_UPGRADE: 04331 case HA_ADMIN_NEEDS_ALTER: 04332 { 04333 char buf[ERRMSGSIZE]; 04334 uint length; 04335 04336 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04337 length=my_snprintf(buf, ERRMSGSIZE, ER(ER_TABLE_NEEDS_UPGRADE), table->table_name); 04338 protocol->store(buf, length, system_charset_info); 04339 fatal_error=1; 04340 break; 04341 } 04342 04343 default: // Probably HA_ADMIN_INTERNAL_ERROR 04344 { 04345 char buf[ERRMSGSIZE+20]; 04346 uint length=my_snprintf(buf, ERRMSGSIZE, 04347 "Unknown - internal error %d during operation", 04348 result_code); 04349 protocol->store(STRING_WITH_LEN("error"), system_charset_info); 04350 protocol->store(buf, length, system_charset_info); 04351 fatal_error=1; 04352 break; 04353 } 04354 } 04355 if (table->table) 04356 { 04357 /* in the below check we do not refresh the log tables */ 04358 if (fatal_error) 04359 table->table->s->version=0; // Force close of table 04360 else if (open_for_modify && !table->table->s->log_table) 04361 { 04362 if (table->table->s->tmp_table) 04363 table->table->file->info(HA_STATUS_CONST); 04364 else 04365 { 04366 pthread_mutex_lock(&LOCK_open); 04367 remove_table_from_cache(thd, table->table->s->db.str, 04368 table->table->s->table_name.str, RTFC_NO_FLAG); 04369 pthread_mutex_unlock(&LOCK_open); 04370 } 04371 /* May be something modified consequently we have to invalidate cache */ 04372 query_cache_invalidate3(thd, table->table, 0); 04373 } 04374 } 04375 ha_autocommit_or_rollback(thd, 0); 04376 close_thread_tables(thd); 04377 table->table=0; // For query cache 04378 if (protocol->write()) 04379 goto err; 04380 } 04381 04382 send_eof(thd); 04383 DBUG_RETURN(FALSE); 04384 04385 err: 04386 ha_autocommit_or_rollback(thd, 1); 04387 close_thread_tables(thd); // Shouldn't be needed 04388 if (table) 04389 table->table=0; 04390 DBUG_RETURN(TRUE); 04391 } 04392 04393 04394 bool mysql_backup_table(THD* thd, TABLE_LIST* table_list) 04395 { 04396 DBUG_ENTER("mysql_backup_table"); 04397 DBUG_RETURN(mysql_admin_table(thd, table_list, 0, 04398 "backup", TL_READ, 0, 0, 0, 0, 04399 &handler::backup, 0)); 04400 } 04401 04402 04403 bool mysql_restore_table(THD* thd, TABLE_LIST* table_list) 04404 { 04405 DBUG_ENTER("mysql_restore_table"); 04406 DBUG_RETURN(mysql_admin_table(thd, table_list, 0, 04407 "restore", TL_WRITE, 1, 1, 0, 04408 &prepare_for_restore, 04409 &handler::restore, 0)); 04410 } 04411 04412 04413 bool mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) 04414 { 04415 DBUG_ENTER("mysql_repair_table"); 04416 DBUG_RETURN(mysql_admin_table(thd, tables, check_opt, 04417 "repair", TL_WRITE, 1, 04418 test(check_opt->sql_flags & TT_USEFRM), 04419 HA_OPEN_FOR_REPAIR, 04420 &prepare_for_repair, 04421 &handler::ha_repair, 0)); 04422 } 04423 04424 04425 bool mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) 04426 { 04427 DBUG_ENTER("mysql_optimize_table"); 04428 DBUG_RETURN(mysql_admin_table(thd, tables, check_opt, 04429 "optimize", TL_WRITE, 1,0,0,0, 04430 &handler::optimize, 0)); 04431 } 04432 04433 04434 /* 04435 Assigned specified indexes for a table into key cache 04436 04437 SYNOPSIS 04438 mysql_assign_to_keycache() 04439 thd Thread object 04440 tables Table list (one table only) 04441 04442 RETURN VALUES 04443 FALSE ok 04444 TRUE error 04445 */ 04446 04447 bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables, 04448 LEX_STRING *key_cache_name) 04449 { 04450 HA_CHECK_OPT check_opt; 04451 KEY_CACHE *key_cache; 04452 DBUG_ENTER("mysql_assign_to_keycache"); 04453 04454 check_opt.init(); 04455 pthread_mutex_lock(&LOCK_global_system_variables); 04456 if (!(key_cache= get_key_cache(key_cache_name))) 04457 { 04458 pthread_mutex_unlock(&LOCK_global_system_variables); 04459 my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str); 04460 DBUG_RETURN(TRUE); 04461 } 04462 pthread_mutex_unlock(&LOCK_global_system_variables); 04463 check_opt.key_cache= key_cache; 04464 DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt, 04465 "assign_to_keycache", TL_READ_NO_INSERT, 0, 0, 04466 0, 0, &handler::assign_to_keycache, 0)); 04467 } 04468 04469 04470 /* 04471 Reassign all tables assigned to a key cache to another key cache 04472 04473 SYNOPSIS 04474 reassign_keycache_tables() 04475 thd Thread object 04476 src_cache Reference to the key cache to clean up 04477 dest_cache New key cache 04478 04479 NOTES 04480 This is called when one sets a key cache size to zero, in which 04481 case we have to move the tables associated to this key cache to 04482 the "default" one. 04483 04484 One has to ensure that one never calls this function while 04485 some other thread is changing the key cache. This is assured by 04486 the caller setting src_cache->in_init before calling this function. 04487 04488 We don't delete the old key cache as there may still be pointers pointing 04489 to it for a while after this function returns. 04490 04491 RETURN VALUES 04492 0 ok 04493 */ 04494 04495 int reassign_keycache_tables(THD *thd, KEY_CACHE *src_cache, 04496 KEY_CACHE *dst_cache) 04497 { 04498 DBUG_ENTER("reassign_keycache_tables"); 04499 04500 DBUG_ASSERT(src_cache != dst_cache); 04501 DBUG_ASSERT(src_cache->in_init); 04502 src_cache->param_buff_size= 0; // Free key cache 04503 ha_resize_key_cache(src_cache); 04504 ha_change_key_cache(src_cache, dst_cache); 04505 DBUG_RETURN(0); 04506 } 04507 04508 04509 /* 04510 Preload specified indexes for a table into key cache 04511 04512 SYNOPSIS 04513 mysql_preload_keys() 04514 thd Thread object 04515 tables Table list (one table only) 04516 04517 RETURN VALUES 04518 FALSE ok 04519 TRUE error 04520 */ 04521 04522 bool mysql_preload_keys(THD* thd, TABLE_LIST* tables) 04523 { 04524 DBUG_ENTER("mysql_preload_keys"); 04525 DBUG_RETURN(mysql_admin_table(thd, tables, 0, 04526 "preload_keys", TL_READ, 0, 0, 0, 0, 04527 &handler::preload_keys, 0)); 04528 } 04529 04530 04531 /* 04532 Create a table identical to the specified table 04533 04534 SYNOPSIS 04535 mysql_create_like_table() 04536 thd Thread object 04537 table Table list (one table only) 04538 create_info Create info 04539 table_ident Src table_ident 04540 04541 RETURN VALUES 04542 FALSE OK 04543 TRUE error 04544 */ 04545 04546 bool mysql_create_like_table(THD* thd, TABLE_LIST* table, 04547 HA_CREATE_INFO *lex_create_info, 04548 Table_ident *table_ident) 04549 { 04550 TABLE *tmp_table; 04551 char src_path[FN_REFLEN], dst_path[FN_REFLEN], tmp_path[FN_REFLEN]; 04552 uint dst_path_length; 04553 char *db= table->db; 04554 char *table_name= table->table_name; 04555 char *src_db; 04556 char *src_table= table_ident->table.str; 04557 int err; 04558 bool res= TRUE; 04559 enum legacy_db_type not_used; 04560 HA_CREATE_INFO *create_info; 04561 04562 TABLE_LIST src_tables_list; 04563 DBUG_ENTER("mysql_create_like_table"); 04564 04565 if (!(create_info= copy_create_info(lex_create_info))) 04566 { 04567 DBUG_RETURN(TRUE); 04568 } 04569 DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */ 04570 src_db= table_ident->db.str; 04571 04572 /* 04573 Validate the source table 04574 */ 04575 if (table_ident->table.length > NAME_LEN || 04576 (table_ident->table.length && 04577 check_table_name(src_table,table_ident->table.length))) 04578 { 04579 my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); 04580 DBUG_RETURN(TRUE); 04581 } 04582 if (!src_db || check_db_name(src_db)) 04583 { 04584 my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL"); 04585 DBUG_RETURN(-1); 04586 } 04587 04588 bzero((gptr)&src_tables_list, sizeof(src_tables_list)); 04589 src_tables_list.db= src_db; 04590 src_tables_list.table_name= src_table; 04591 04592 if (lock_and_wait_for_table_name(thd, &src_tables_list)) 04593 goto err; 04594 04595 if ((tmp_table= find_temporary_table(thd, src_db, src_table))) 04596 strxmov(src_path, tmp_table->s->path.str, reg_ext, NullS); 04597 else 04598 { 04599 build_table_filename(src_path, sizeof(src_path), 04600 src_db, src_table, reg_ext, 0); 04601 /* Resolve symlinks (for windows) */ 04602 unpack_filename(src_path, src_path); 04603 if (lower_case_table_names) 04604 my_casedn_str(files_charset_info, src_path); 04605 if (access(src_path, F_OK)) 04606 { 04607 my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table); 04608 goto err; 04609 } 04610 } 04611 04612 /* 04613 create like should be not allowed for Views, Triggers, ... 04614 */ 04615 if (mysql_frm_type(thd, src_path, ¬_used) != FRMTYPE_TABLE) 04616 { 04617 my_error(ER_WRONG_OBJECT, MYF(0), src_db, src_table, "BASE TABLE"); 04618 goto err; 04619 } 04620 04621 /* 04622 Validate the destination table 04623 04624 skip the destination table name checking as this is already 04625 validated. 04626 */ 04627 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) 04628 { 04629 if (find_temporary_table(thd, db, table_name)) 04630 goto table_exists; 04631 dst_path_length= build_tmptable_filename(thd, dst_path, sizeof(dst_path)); 04632 if (lower_case_table_names) 04633 my_casedn_str(files_charset_info, dst_path); 04634 create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE; 04635 } 04636 else 04637 { 04638 dst_path_length= build_table_filename(dst_path, sizeof(dst_path), 04639 db, table_name, reg_ext, 0); 04640 if (!access(dst_path, F_OK)) 04641 goto table_exists; 04642 } 04643 04644 /* 04645 Create a new table by copying from source table 04646 */ 04647 if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE))) 04648 { 04649 if (my_errno == ENOENT) 04650 my_error(ER_BAD_DB_ERROR,MYF(0),db); 04651 else 04652 my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno); 04653 goto err; 04654 } 04655 04656 /* 04657 As mysql_truncate don't work on a new table at this stage of 04658 creation, instead create the table directly (for both normal 04659 and temporary tables). 04660 */ 04661 #ifdef WITH_PARTITION_STORAGE_ENGINE 04662 /* 04663 For partitioned tables we need to copy the .par file as well since 04664 it is used in open_table_def to even be able to create a new handler. 04665 There is no way to find out here if the original table is a 04666 partitioned table so we copy the file and ignore any errors. 04667 */ 04668 fn_format(tmp_path, dst_path, reg_ext, ".par", MYF(MY_REPLACE_EXT)); 04669 strmov(dst_path, tmp_path); 04670 fn_format(tmp_path, src_path, reg_ext, ".par", MYF(MY_REPLACE_EXT)); 04671 strmov(src_path, tmp_path); 04672 my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)); 04673 #endif 04674 dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm 04675 err= ha_create_table(thd, dst_path, db, table_name, create_info, 1); 04676 04677 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) 04678 { 04679 if (err || !open_temporary_table(thd, dst_path, db, table_name, 1)) 04680 { 04681 (void) rm_temporary_table(create_info->db_type, 04682 dst_path); /* purecov: inspected */ 04683 goto err; /* purecov: inspected */ 04684 } 04685 } 04686 else if (err) 04687 { 04688 (void) quick_rm_table(create_info->db_type, db, 04689 table_name, 0); /* purecov: inspected */ 04690 goto err; /* purecov: inspected */ 04691 } 04692 04693 /* 04694 We have to write the query before we unlock the tables. 04695 */ 04696 if (thd->current_stmt_binlog_row_based) 04697 { 04698 /* 04699 Since temporary tables are not replicated under row-based 04700 replication, CREATE TABLE ... LIKE ... needs special 04701 treatement. We have four cases to consider, according to the 04702 following decision table: 04703 04704 ==== ========= ========= ============================== 04705 Case Target Source Write to binary log 04706 ==== ========= ========= ============================== 04707 1 normal normal Original statement 04708 2 normal temporary Generated statement 04709 3 temporary normal Nothing 04710 4 temporary temporary Nothing 04711 ==== ========= ========= ============================== 04712 04713 The variable 'tmp_table' below is used to see if the source 04714 table is a temporary table: if it is set, then the source table 04715 was a temporary table and we can take apropriate actions. 04716 */ 04717 if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) 04718 { 04719 if (tmp_table) // Case 2 04720 { 04721 char buf[2048]; 04722 String query(buf, sizeof(buf), system_charset_info); 04723 query.length(0); // Have to zero it since constructor doesn't 04724 TABLE *table_ptr; 04725 int error; 04726 04727 /* 04728 Let's open and lock the table: it will be closed (and 04729 unlocked) by close_thread_tables() at the end of the 04730 statement anyway. 04731 */ 04732 if (!(table_ptr= open_ltable(thd, table, TL_READ_NO_INSERT))) 04733 goto err; 04734 04735 int result= store_create_info(thd, table, &query, create_info); 04736 04737 DBUG_ASSERT(result == 0); // store_create_info() always return 0 04738 write_bin_log(thd, TRUE, query.ptr(), query.length()); 04739 } 04740 else // Case 1 04741 write_bin_log(thd, TRUE, thd->query, thd->query_length); 04742 } 04743 /* 04744 Case 3 and 4 does nothing under RBR 04745 */ 04746 } 04747 else 04748 write_bin_log(thd, TRUE, thd->query, thd->query_length); 04749 04750 res= FALSE; 04751 goto err; 04752 04753 table_exists: 04754 if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) 04755 { 04756 char warn_buff[MYSQL_ERRMSG_SIZE]; 04757 my_snprintf(warn_buff, sizeof(warn_buff), 04758 ER(ER_TABLE_EXISTS_ERROR), table_name); 04759 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 04760 ER_TABLE_EXISTS_ERROR,warn_buff); 04761 res= FALSE; 04762 } 04763 else 04764 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); 04765 04766 err: 04767 pthread_mutex_lock(&LOCK_open); 04768 unlock_table_name(thd, &src_tables_list); 04769 pthread_mutex_unlock(&LOCK_open); 04770 DBUG_RETURN(res); 04771 } 04772 04773 04774 bool mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) 04775 { 04776 thr_lock_type lock_type = TL_READ_NO_INSERT; 04777 04778 DBUG_ENTER("mysql_analyze_table"); 04779 DBUG_RETURN(mysql_admin_table(thd, tables, check_opt, 04780 "analyze", lock_type, 1, 0, 0, 0, 04781 &handler::analyze, 0)); 04782 } 04783 04784 04785 bool mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt) 04786 { 04787 thr_lock_type lock_type = TL_READ_NO_INSERT; 04788 04789 DBUG_ENTER("mysql_check_table"); 04790 DBUG_RETURN(mysql_admin_table(thd, tables, check_opt, 04791 "check", lock_type, 04792 0, HA_OPEN_FOR_REPAIR, 0, 0, 04793 &handler::ha_check, &view_checksum)); 04794 } 04795 04796 04797 /* table_list should contain just one table */ 04798 static int 04799 mysql_discard_or_import_tablespace(THD *thd, 04800 TABLE_LIST *table_list, 04801 enum tablespace_op_type tablespace_op) 04802 { 04803 TABLE *table; 04804 my_bool discard; 04805 int error; 04806 DBUG_ENTER("mysql_discard_or_import_tablespace"); 04807 04808 /* 04809 Note that DISCARD/IMPORT TABLESPACE always is the only operation in an 04810 ALTER TABLE 04811 */ 04812 04813 thd->proc_info="discard_or_import_tablespace"; 04814 04815 discard= test(tablespace_op == DISCARD_TABLESPACE); 04816 04817 /* 04818 We set this flag so that ha_innobase::open and ::external_lock() do 04819 not complain when we lock the table 04820 */ 04821 thd->tablespace_op= TRUE; 04822 if (!(table=open_ltable(thd,table_list,TL_WRITE))) 04823 { 04824 thd->tablespace_op=FALSE; 04825 DBUG_RETURN(-1); 04826 } 04827 04828 error=table->file->discard_or_import_tablespace(discard); 04829 04830 thd->proc_info="end"; 04831 04832 if (error) 04833 goto err; 04834 04835 /* 04836 The 0 in the call below means 'not in a transaction', which means 04837 immediate invalidation; that is probably what we wish here 04838 */ 04839 query_cache_invalidate3(thd, table_list, 0); 04840 04841 /* The ALTER TABLE is always in its own transaction */ 04842 error = ha_commit_stmt(thd); 04843 if (ha_commit(thd)) 04844 error=1; 04845 if (error) 04846 goto err; 04847 write_bin_log(thd, FALSE, thd->query, thd->query_length); 04848 04849 err: 04850 ha_autocommit_or_rollback(thd, error); 04851 close_thread_tables(thd); 04852 thd->tablespace_op=FALSE; 04853 04854 if (error == 0) 04855 { 04856 send_ok(thd); 04857 DBUG_RETURN(0); 04858 } 04859 04860 table->file->print_error(error, MYF(0)); 04861 04862 DBUG_RETURN(-1); 04863 } 04864 04865 04866 /* 04867 SYNOPSIS 04868 compare_tables() 04869 table The original table. 04870 create_list The fields for the new table. 04871 key_info_buffer An array of KEY structs for the new indexes. 04872 key_count The number of elements in the array. 04873 create_info Create options for the new table. 04874 alter_info Alter options. 04875 order_num Number of order list elements. 04876 index_drop_buffer OUT An array of offsets into table->key_info. 04877 index_drop_count OUT The number of elements in the array. 04878 index_add_buffer OUT An array of offsets into key_info_buffer. 04879 index_add_count OUT The number of elements in the array. 04880 04881 DESCRIPTION 04882 'table' (first argument) contains information of the original 04883 table, which includes all corresponding parts that the new 04884 table has in arguments create_list, key_list and create_info. 04885 04886 By comparing the changes between the original and new table 04887 we can determine how much it has changed after ALTER TABLE 04888 and whether we need to make a copy of the table, or just change 04889 the .frm file. 04890 04891 If there are no data changes, but index changes, 'index_drop_buffer' 04892 and/or 'index_add_buffer' are populated with offsets into 04893 table->key_info or key_info_buffer respectively for the indexes 04894 that need to be dropped and/or (re-)created. 04895 04896 RETURN VALUES 04897 0 No copy needed 04898 ALTER_TABLE_DATA_CHANGED Data changes, copy needed 04899 ALTER_TABLE_INDEX_CHANGED Index changes, copy might be needed 04900 */ 04901 04902 static uint compare_tables(TABLE *table, List<create_field> *create_list, 04903 KEY *key_info_buffer, uint key_count, 04904 HA_CREATE_INFO *create_info, 04905 ALTER_INFO *alter_info, uint order_num, 04906 uint *index_drop_buffer, uint *index_drop_count, 04907 uint *index_add_buffer, uint *index_add_count, 04908 bool varchar) 04909 { 04910 Field **f_ptr, *field; 04911 uint changes= 0, tmp; 04912 List_iterator_fast<create_field> new_field_it(*create_list); 04913 create_field *new_field; 04914 KEY_PART_INFO *key_part; 04915 KEY_PART_INFO *end; 04916 DBUG_ENTER("compare_tables"); 04917 04918 /* 04919 Some very basic checks. If number of fields changes, or the 04920 handler, we need to run full ALTER TABLE. In the future 04921 new fields can be added and old dropped without copy, but 04922 not yet. 04923 04924 Test also that engine was not given during ALTER TABLE, or 04925 we are force to run regular alter table (copy). 04926 E.g. ALTER TABLE tbl_name ENGINE=MyISAM. 04927 04928 For the following ones we also want to run regular alter table: 04929 ALTER TABLE tbl_name ORDER BY .. 04930 ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. 04931 04932 At the moment we can't handle altering temporary tables without a copy. 04933 We also test if OPTIMIZE TABLE was given and was mapped to alter table. 04934 In that case we always do full copy. 04935 04936 There was a bug prior to mysql-4.0.25. Number of null fields was 04937 calculated incorrectly. As a result frm and data files gets out of 04938 sync after fast alter table. There is no way to determine by which 04939 mysql version (in 4.0 and 4.1 branches) table was created, thus we 04940 disable fast alter table for all tables created by mysql versions 04941 prior to 5.0 branch. 04942 See BUG#6236. 04943 */ 04944 if (table->s->fields != create_list->elements || 04945 table->s->db_type != create_info->db_type || 04946 table->s->tmp_table || 04947 create_info->used_fields & HA_CREATE_USED_ENGINE || 04948 create_info->used_fields & HA_CREATE_USED_CHARSET || 04949 create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET || 04950 (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) || 04951 order_num || 04952 !table->s->mysql_version || 04953 (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)) 04954 DBUG_RETURN(ALTER_TABLE_DATA_CHANGED); 04955 04956 /* 04957 Go through fields and check if the original ones are compatible 04958 with new table. 04959 */ 04960 for (f_ptr= table->field, new_field= new_field_it++; 04961 (field= *f_ptr); f_ptr++, new_field= new_field_it++) 04962 { 04963 /* Make sure we have at least the default charset in use. */ 04964 if (!new_field->charset) 04965 new_field->charset= create_info->default_table_charset; 04966 04967 /* Check that NULL behavior is same for old and new fields */ 04968 if ((new_field->flags & NOT_NULL_FLAG) != 04969 (uint) (field->flags & NOT_NULL_FLAG)) 04970 DBUG_RETURN(ALTER_TABLE_DATA_CHANGED); 04971 04972 /* Don't pack rows in old tables if the user has requested this. */ 04973 if (create_info->row_type == ROW_TYPE_DYNAMIC || 04974 (new_field->flags & BLOB_FLAG) || 04975 new_field->sql_type == MYSQL_TYPE_VARCHAR && 04976 create_info->row_type != ROW_TYPE_FIXED) 04977 create_info->table_options|= HA_OPTION_PACK_RECORD; 04978 04979 /* Check if field was renamed */ 04980 field->flags&= ~FIELD_IS_RENAMED; 04981 if (my_strcasecmp(system_charset_info, 04982 field->field_name, 04983 new_field->field_name)) 04984 field->flags|= FIELD_IS_RENAMED; 04985 04986 /* Evaluate changes bitmap and send to check_if_incompatible_data() */ 04987 if (!(tmp= field->is_equal(new_field))) 04988 DBUG_RETURN(ALTER_TABLE_DATA_CHANGED); 04989 // Clear indexed marker 04990 field->flags&= ~FIELD_IN_ADD_INDEX; 04991 changes|= tmp; 04992 } 04993 04994 /* 04995 Go through keys and check if the original ones are compatible 04996 with new table. 04997 */ 04998 KEY *table_key; 04999 KEY *table_key_end= table->key_info + table->s->keys; 05000 KEY *new_key; 05001 KEY *new_key_end= key_info_buffer + key_count; 05002 05003 DBUG_PRINT("info", ("index count old: %d new: %d", 05004 table->s->keys, key_count)); 05005 /* 05006 Step through all keys of the old table and search matching new keys. 05007 */ 05008 *index_drop_count= 0; 05009 *index_add_count= 0; 05010 for (table_key= table->key_info; table_key < table_key_end; table_key++) 05011 { 05012 KEY_PART_INFO *table_part; 05013 KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts; 05014 KEY_PART_INFO *new_part; 05015 05016 /* Search a new key with the same name. */ 05017 for (new_key= key_info_buffer; new_key < new_key_end; new_key++) 05018 { 05019 if (! strcmp(table_key->name, new_key->name)) 05020 break; 05021 } 05022 if (new_key >= new_key_end) 05023 { 05024 /* Key not found. Add the offset of the key to the drop buffer. */ 05025 index_drop_buffer[(*index_drop_count)++]= table_key - table->key_info; 05026 DBUG_PRINT("info", ("index dropped: '%s'", table_key->name)); 05027 continue; 05028 } 05029 05030 /* Check that the key types are compatible between old and new tables. */ 05031 if ((table_key->algorithm != new_key->algorithm) || 05032 ((table_key->flags & HA_KEYFLAG_MASK) != 05033 (new_key->flags & HA_KEYFLAG_MASK)) || 05034 (table_key->key_parts != new_key->key_parts)) 05035 goto index_changed; 05036 05037 /* 05038 Check that the key parts remain compatible between the old and 05039 new tables. 05040 */ 05041 for (table_part= table_key->key_part, new_part= new_key->key_part; 05042 table_part < table_part_end; 05043 table_part++, new_part++) 05044 { 05045 /* 05046 Key definition has changed if we are using a different field or 05047 if the used key part length is different. We know that the fields 05048 did not change. Comparing field numbers is sufficient. 05049 */ 05050 if ((table_part->length != new_part->length) || 05051 (table_part->fieldnr - 1 != new_part->fieldnr)) 05052 goto index_changed; 05053 } 05054 continue; 05055 05056 index_changed: 05057 /* Key modified. Add the offset of the key to both buffers. */ 05058 index_drop_buffer[(*index_drop_count)++]= table_key - table->key_info; 05059 index_add_buffer[(*index_add_count)++]= new_key - key_info_buffer; 05060 key_part= new_key->key_part; 05061 end= key_part + new_key->key_parts; 05062 for(; key_part != end; key_part++) 05063 { 05064 // Mark field to be part of new key 05065 field= table->field[key_part->fieldnr]; 05066 field->flags|= FIELD_IN_ADD_INDEX; 05067 } 05068 DBUG_PRINT("info", ("index changed: '%s'", table_key->name)); 05069 } 05070 /*end of for (; table_key < table_key_end;) */ 05071 05072 /* 05073 Step through all keys of the new table and find matching old keys. 05074 */ 05075 for (new_key= key_info_buffer; new_key < new_key_end; new_key++) 05076 { 05077 /* Search an old key with the same name. */ 05078 for (table_key= table->key_info; table_key < table_key_end; table_key++) 05079 { 05080 if (! strcmp(table_key->name, new_key->name)) 05081 break; 05082 } 05083 if (table_key >= table_key_end) 05084 { 05085 /* Key not found. Add the offset of the key to the add buffer. */ 05086 index_add_buffer[(*index_add_count)++]= new_key - key_info_buffer; 05087 key_part= new_key->key_part; 05088 end= key_part + new_key->key_parts; 05089 for(; key_part != end; key_part++) 05090 { 05091 // Mark field to be part of new key 05092 field= table->field[key_part->fieldnr]; 05093 field->flags|= FIELD_IN_ADD_INDEX; 05094 } 05095 DBUG_PRINT("info", ("index added: '%s'", new_key->name)); 05096 } 05097 } 05098 05099 /* Check if changes are compatible with current handler without a copy */ 05100 if (table->file->check_if_incompatible_data(create_info, changes)) 05101 DBUG_RETURN(ALTER_TABLE_DATA_CHANGED); 05102 05103 if (*index_drop_count || *index_add_count) 05104 DBUG_RETURN(ALTER_TABLE_INDEX_CHANGED); 05105 05106 DBUG_RETURN(0); // Tables are compatible 05107 } 05108 05109 05110 /* 05111 Alter table 05112 */ 05113 05114 bool mysql_alter_table(THD *thd,char *new_db, char *new_name, 05115 HA_CREATE_INFO *lex_create_info, 05116 TABLE_LIST *table_list, 05117 List<create_field> &fields, List<Key> &keys, 05118 uint order_num, ORDER *order, bool ignore, 05119 ALTER_INFO *alter_info, bool do_send_ok) 05120 { 05121 TABLE *table,*new_table=0; 05122 int error; 05123 char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN]; 05124 char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias; 05125 char index_file[FN_REFLEN], data_file[FN_REFLEN]; 05126 char path[FN_REFLEN]; 05127 char reg_path[FN_REFLEN+1]; 05128 ha_rows copied,deleted; 05129 uint db_create_options, used_fields; 05130 handlerton *old_db_type, *new_db_type; 05131 HA_CREATE_INFO *create_info; 05132 uint need_copy_table= 0; 05133 bool no_table_reopen= FALSE, varchar= FALSE; 05134 #ifdef WITH_PARTITION_STORAGE_ENGINE 05135 uint fast_alter_partition= 0; 05136 bool partition_changed= FALSE; 05137 #endif 05138 List<create_field> prepared_create_list; 05139 List<Key> prepared_key_list; 05140 bool need_lock_for_indexes= TRUE; 05141 uint db_options= 0; 05142 uint key_count; 05143 KEY *key_info_buffer; 05144 uint index_drop_count; 05145 uint *index_drop_buffer; 05146 uint index_add_count; 05147 uint *index_add_buffer; 05148 bool committed= 0; 05149 DBUG_ENTER("mysql_alter_table"); 05150 05151 LINT_INIT(index_add_count); 05152 LINT_INIT(index_drop_count); 05153 LINT_INIT(index_add_buffer); 05154 LINT_INIT(index_drop_buffer); 05155 05156 if (table_list && table_list->db && 05157 !my_strcasecmp(system_charset_info, table_list->db, "mysql") && 05158 table_list->table_name) 05159 { 05160 enum enum_table_kind { NOT_LOG_TABLE= 1, GENERAL_LOG, SLOW_LOG } 05161 table_kind= NOT_LOG_TABLE; 05162 05163 if (!my_strcasecmp(system_charset_info, table_list->table_name, 05164 "general_log")) 05165 table_kind= GENERAL_LOG; 05166 else 05167 if (!my_strcasecmp(system_charset_info, table_list->table_name, 05168 "slow_log")) 05169 table_kind= SLOW_LOG; 05170 05171 /* Disable alter of enabled log tables */ 05172 if ((table_kind == GENERAL_LOG && opt_log && 05173 logger.is_general_log_table_enabled()) || 05174 (table_kind == SLOW_LOG && opt_slow_log && 05175 logger.is_slow_log_table_enabled())) 05176 { 05177 my_error(ER_CANT_ALTER_LOG_TABLE, MYF(0)); 05178 DBUG_RETURN(TRUE); 05179 } 05180 05181 /* Disable alter of log tables to unsupported engine */ 05182 if ((table_kind == GENERAL_LOG || table_kind == SLOW_LOG) && 05183 (lex_create_info->used_fields & HA_CREATE_USED_ENGINE) && 05184 (!lex_create_info->db_type || /* unknown engine */ 05185 !(lex_create_info->db_type->db_type == DB_TYPE_MYISAM || 05186 lex_create_info->db_type->db_type == DB_TYPE_CSV_DB))) 05187 { 05188 my_error(ER_BAD_LOG_ENGINE, MYF(0)); 05189 DBUG_RETURN(TRUE); 05190 } 05191 } 05192 05193 thd->proc_info="init"; 05194 if (!(create_info= copy_create_info(lex_create_info))) 05195 { 05196 DBUG_RETURN(TRUE); 05197 } 05198 table_name=table_list->table_name; 05199 alias= (lower_case_table_names == 2) ? table_list->alias : table_name; 05200 db=table_list->db; 05201 if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db)) 05202 new_db= db; 05203 build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0); 05204 build_table_filename(path, sizeof(path), db, table_name, "", 0); 05205 05206 used_fields=create_info->used_fields; 05207 05208 mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE); 05209 05210 /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ 05211 if (alter_info->tablespace_op != NO_TABLESPACE_OP) 05212 DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, 05213 alter_info->tablespace_op)); 05214 if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) 05215 DBUG_RETURN(TRUE); 05216 table->use_all_columns(); 05217 05218 /* Check that we are not trying to rename to an existing table */ 05219 if (new_name) 05220 { 05221 DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name)); 05222 strmov(new_name_buff,new_name); 05223 strmov(new_alias= new_alias_buff, new_name); 05224 if (lower_case_table_names) 05225 { 05226 if (lower_case_table_names != 2) 05227 { 05228 my_casedn_str(files_charset_info, new_name_buff); 05229 new_alias= new_name; // Create lower case table name 05230 } 05231 my_casedn_str(files_charset_info, new_name); 05232 } 05233 if (new_db == db && 05234 !my_strcasecmp(table_alias_charset, new_name_buff, table_name)) 05235 { 05236 /* 05237 Source and destination table names are equal: make later check 05238 easier. 05239 */ 05240 new_alias= new_name= table_name; 05241 } 05242 else 05243 { 05244 if (table->s->tmp_table != NO_TMP_TABLE) 05245 { 05246 if (find_temporary_table(thd,new_db,new_name_buff)) 05247 { 05248 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff); 05249 DBUG_RETURN(TRUE); 05250 } 05251 } 05252 else 05253 { 05254 build_table_filename(new_name_buff, sizeof(new_name_buff), 05255 new_db, new_name_buff, reg_ext, 0); 05256 if (!access(new_name_buff, F_OK)) 05257 { 05258 /* Table will be closed in do_command() */ 05259 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); 05260 DBUG_RETURN(TRUE); 05261 } 05262 } 05263 } 05264 } 05265 else 05266 { 05267 new_alias= (lower_case_table_names == 2) ? alias : table_name; 05268 new_name= table_name; 05269 } 05270 05271 old_db_type= table->s->db_type; 05272 if (!create_info->db_type) 05273 { 05274 #ifdef WITH_PARTITION_STORAGE_ENGINE 05275 if (table->part_info && 05276 create_info->used_fields & HA_CREATE_USED_ENGINE) 05277 { 05278 /* 05279 This case happens when the user specified 05280 ENGINE = x where x is a non-existing storage engine 05281 We set create_info->db_type to default_engine_type 05282 to ensure we don't change underlying engine type 05283 due to a erroneously given engine name. 05284 */ 05285 create_info->db_type= table->part_info->default_engine_type; 05286 } 05287 else 05288 #endif 05289 create_info->db_type= old_db_type; 05290 } 05291 05292 #ifdef WITH_PARTITION_STORAGE_ENGINE 05293 if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type, 05294 &partition_changed, &fast_alter_partition)) 05295 { 05296 DBUG_RETURN(TRUE); 05297 } 05298 #endif 05299 if (check_engine(thd, new_name, create_info)) 05300 DBUG_RETURN(TRUE); 05301 new_db_type= create_info->db_type; 05302 if (create_info->row_type == ROW_TYPE_NOT_USED) 05303 create_info->row_type= table->s->row_type; 05304 05305 DBUG_PRINT("info", ("old type: %s new type: %s", 05306 ha_resolve_storage_engine_name(old_db_type), 05307 ha_resolve_storage_engine_name(new_db_type))); 05308 if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) || 05309 ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED)) 05310 { 05311 DBUG_PRINT("info", ("doesn't support alter")); 05312 my_error(ER_ILLEGAL_HA, MYF(0), table_name); 05313 DBUG_RETURN(TRUE); 05314 } 05315 05316 thd->proc_info="setup"; 05317 if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && 05318 !table->s->tmp_table) // no need to touch frm 05319 { 05320 error=0; 05321 if (new_name != table_name || new_db != db) 05322 { 05323 thd->proc_info="rename"; 05324 VOID(pthread_mutex_lock(&LOCK_open)); 05325 /* Then do a 'simple' rename of the table */ 05326 error=0; 05327 if (!access(new_name_buff,F_OK)) 05328 { 05329 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name); 05330 error= -1; 05331 } 05332 else 05333 { 05334 *fn_ext(new_name)=0; 05335 table->s->version= 0; // Force removal of table def 05336 close_cached_table(thd, table); 05337 if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0)) 05338 error= -1; 05339 else if (Table_triggers_list::change_table_name(thd, db, table_name, 05340 new_db, new_alias)) 05341 { 05342 VOID(mysql_rename_table(old_db_type, new_db, new_alias, db, 05343 table_name, 0)); 05344 error= -1; 05345 } 05346 } 05347 VOID(pthread_mutex_unlock(&LOCK_open)); 05348 } 05349 05350 if (!error) 05351 { 05352 switch (alter_info->keys_onoff) { 05353 case LEAVE_AS_IS: 05354 break; 05355 case ENABLE: 05356 VOID(pthread_mutex_lock(&LOCK_open)); 05357 wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); 05358 VOID(pthread_mutex_unlock(&LOCK_open)); 05359 error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); 05360 /* COND_refresh will be signaled in close_thread_tables() */ 05361 break; 05362 case DISABLE: 05363 VOID(pthread_mutex_lock(&LOCK_open)); 05364 wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); 05365 VOID(pthread_mutex_unlock(&LOCK_open)); 05366 error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); 05367 /* COND_refresh will be signaled in close_thread_tables() */ 05368 break; 05369 } 05370 } 05371 05372 if (error == HA_ERR_WRONG_COMMAND) 05373 { 05374 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 05375 ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), 05376 table->alias); 05377 error=0; 05378 } 05379 if (!error) 05380 { 05381 write_bin_log(thd, TRUE, thd->query, thd->query_length); 05382 if (do_send_ok) 05383 send_ok(thd); 05384 } 05385 else if (error > 0) 05386 { 05387 table->file->print_error(error, MYF(0)); 05388 error= -1; 05389 } 05390 table_list->table=0; // For query cache 05391 query_cache_invalidate3(thd, table_list, 0); 05392 DBUG_RETURN(error); 05393 } 05394 05395 /* Full alter table */ 05396 05397 /* Let new create options override the old ones */ 05398 if (!(used_fields & HA_CREATE_USED_MIN_ROWS)) 05399 create_info->min_rows= table->s->min_rows; 05400 if (!(used_fields & HA_CREATE_USED_MAX_ROWS)) 05401 create_info->max_rows= table->s->max_rows; 05402 if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH)) 05403 create_info->avg_row_length= table->s->avg_row_length; 05404 if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET)) 05405 create_info->default_table_charset= table->s->table_charset; 05406 if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) 05407 create_info->key_block_size= table->s->key_block_size; 05408 05409 restore_record(table, s->default_values); // Empty record for DEFAULT 05410 List_iterator<Alter_drop> drop_it(alter_info->drop_list); 05411 List_iterator<create_field> def_it(fields); 05412 List_iterator<Alter_column> alter_it(alter_info->alter_list); 05413 List<create_field> create_list; // Add new fields here 05414 List<Key> key_list; // Add new keys here 05415 create_field *def; 05416 05417 /* 05418 First collect all fields from table which isn't in drop_list 05419 */ 05420 05421 Field **f_ptr,*field; 05422 for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++) 05423 { 05424 if (field->type() == MYSQL_TYPE_STRING) 05425 varchar= TRUE; 05426 /* Check if field should be dropped */ 05427 Alter_drop *drop; 05428 drop_it.rewind(); 05429 while ((drop=drop_it++)) 05430 { 05431 if (drop->type == Alter_drop::COLUMN && 05432 !my_strcasecmp(system_charset_info,field->field_name, drop->name)) 05433 { 05434 /* Reset auto_increment value if it was dropped */ 05435 if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER && 05436 !(used_fields & HA_CREATE_USED_AUTO)) 05437 { 05438 create_info->auto_increment_value=0; 05439 create_info->used_fields|=HA_CREATE_USED_AUTO; 05440 } 05441 break; 05442 } 05443 } 05444 if (drop) 05445 { 05446 drop_it.remove(); 05447 continue; 05448 } 05449 /* Check if field is changed */ 05450 def_it.rewind(); 05451 while ((def=def_it++)) 05452 { 05453 if (def->change && 05454 !my_strcasecmp(system_charset_info,field->field_name, def->change)) 05455 break; 05456 } 05457 if (def) 05458 { // Field is changed 05459 def->field=field; 05460 if (!def->after) 05461 { 05462 create_list.push_back(def); 05463 def_it.remove(); 05464 } 05465 } 05466 else 05467 { 05468 /* 05469 This field was not dropped and not changed, add it to the list 05470 for the new table. 05471 */ 05472 create_list.push_back(def=new create_field(field,field)); 05473 alter_it.rewind(); // Change default if ALTER 05474 Alter_column *alter; 05475 while ((alter=alter_it++)) 05476 { 05477 if (!my_strcasecmp(system_charset_info,field->field_name, alter->name)) 05478 break; 05479 } 05480 if (alter) 05481 { 05482 if (def->sql_type == FIELD_TYPE_BLOB) 05483 { 05484 my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change); 05485 DBUG_RETURN(TRUE); 05486 } 05487 if ((def->def=alter->def)) // Use new default 05488 def->flags&= ~NO_DEFAULT_VALUE_FLAG; 05489 else 05490 def->flags|= NO_DEFAULT_VALUE_FLAG; 05491 alter_it.remove(); 05492 } 05493 } 05494 } 05495 def_it.rewind(); 05496 List_iterator<create_field> find_it(create_list); 05497 while ((def=def_it++)) // Add new columns 05498 { 05499 if (def->change && ! def->field) 05500 { 05501 my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table_name); 05502 DBUG_RETURN(TRUE); 05503 } 05504 if (!def->after) 05505 create_list.push_back(def); 05506 else if (def->after == first_keyword) 05507 create_list.push_front(def); 05508 else 05509 { 05510 create_field *find; 05511 find_it.rewind(); 05512 while ((find=find_it++)) // Add new columns 05513 { 05514 if (!my_strcasecmp(system_charset_info,def->after, find->field_name)) 05515 break; 05516 } 05517 if (!find) 05518 { 05519 my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table_name); 05520 DBUG_RETURN(TRUE); 05521 } 05522 find_it.after(def); // Put element after this 05523 } 05524 } 05525 if (alter_info->alter_list.elements) 05526 { 05527 my_error(ER_BAD_FIELD_ERROR, MYF(0), 05528 alter_info->alter_list.head()->name, table_name); 05529 DBUG_RETURN(TRUE); 05530 } 05531 if (!create_list.elements) 05532 { 05533 my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS), 05534 MYF(0)); 05535 DBUG_RETURN(TRUE); 05536 } 05537 05538 /* 05539 Collect all keys which isn't in drop list. Add only those 05540 for which some fields exists. 05541 */ 05542 05543 List_iterator<Key> key_it(keys); 05544 List_iterator<create_field> field_it(create_list); 05545 List<key_part_spec> key_parts; 05546 05547 KEY *key_info=table->key_info; 05548 for (uint i=0 ; i < table->s->keys ; i++,key_info++) 05549 { 05550 char *key_name= key_info->name; 05551 Alter_drop *drop; 05552 drop_it.rewind(); 05553 while ((drop=drop_it++)) 05554 { 05555 if (drop->type == Alter_drop::KEY && 05556 !my_strcasecmp(system_charset_info,key_name, drop->name)) 05557 break; 05558 } 05559 if (drop) 05560 { 05561 drop_it.remove(); 05562 continue; 05563 } 05564 05565 KEY_PART_INFO *key_part= key_info->key_part; 05566 key_parts.empty(); 05567 for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) 05568 { 05569 if (!key_part->field) 05570 continue; // Wrong field (from UNIREG) 05571 const char *key_part_name=key_part->field->field_name; 05572 create_field *cfield; 05573 field_it.rewind(); 05574 while ((cfield=field_it++)) 05575 { 05576 if (cfield->change) 05577 { 05578 if (!my_strcasecmp(system_charset_info, key_part_name, 05579 cfield->change)) 05580 break; 05581 } 05582 else if (!my_strcasecmp(system_charset_info, 05583 key_part_name, cfield->field_name)) 05584 break; 05585 } 05586 if (!cfield) 05587 continue; // Field is removed 05588 uint key_part_length=key_part->length; 05589 if (cfield->field) // Not new field 05590 { 05591 /* 05592 If the field can't have only a part used in a key according to its 05593 new type, or should not be used partially according to its 05594 previous type, or the field length is less than the key part 05595 length, unset the key part length. 05596 05597 We also unset the key part length if it is the same as the 05598 old field's length, so the whole new field will be used. 05599 05600 BLOBs may have cfield->length == 0, which is why we test it before 05601 checking whether cfield->length < key_part_length (in chars). 05602 */ 05603 if (!Field::type_can_have_key_part(cfield->field->type()) || 05604 !Field::type_can_have_key_part(cfield->sql_type) || 05605 (cfield->field->field_length == key_part_length && 05606 !f_is_blob(key_part->key_type)) || 05607 (cfield->length && (cfield->length < key_part_length / 05608 key_part->field->charset()->mbmaxlen))) 05609 key_part_length= 0; // Use whole field 05610 } 05611 key_part_length /= key_part->field->charset()->mbmaxlen; 05612 key_parts.push_back(new key_part_spec(cfield->field_name, 05613 key_part_length)); 05614 } 05615 if (key_parts.elements) 05616 { 05617 KEY_CREATE_INFO key_create_info; 05618 bzero((char*) &key_create_info, sizeof(key_create_info)); 05619 05620 key_create_info.algorithm= key_info->algorithm; 05621 if (key_info->flags & HA_USES_BLOCK_SIZE) 05622 key_create_info.block_size= key_info->block_size; 05623 if (key_info->flags & HA_USES_PARSER) 05624 key_create_info.parser_name= *key_info->parser_name; 05625 05626 key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL : 05627 (key_info->flags & HA_NOSAME ? 05628 (!my_strcasecmp(system_charset_info, 05629 key_name, primary_key_name) ? 05630 Key::PRIMARY : Key::UNIQUE) : 05631 (key_info->flags & HA_FULLTEXT ? 05632 Key::FULLTEXT : Key::MULTIPLE)), 05633 key_name, 05634 &key_create_info, 05635 test(key_info->flags & HA_GENERATED_KEY), 05636 key_parts)); 05637 } 05638 } 05639 { 05640 Key *key; 05641 while ((key=key_it++)) // Add new keys 05642 { 05643 if (key->type != Key::FOREIGN_KEY) 05644 key_list.push_back(key); 05645 if (key->name && 05646 !my_strcasecmp(system_charset_info,key->name,primary_key_name)) 05647 { 05648 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name); 05649 DBUG_RETURN(TRUE); 05650 } 05651 } 05652 } 05653 05654 if (alter_info->drop_list.elements) 05655 { 05656 my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), 05657 alter_info->drop_list.head()->name); 05658 goto err; 05659 } 05660 if (alter_info->alter_list.elements) 05661 { 05662 my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), 05663 alter_info->alter_list.head()->name); 05664 goto err; 05665 } 05666 05667 db_create_options= table->s->db_create_options & ~(HA_OPTION_PACK_RECORD); 05668 my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix, 05669 current_pid, thd->thread_id); 05670 /* Safety fix for innodb */ 05671 if (lower_case_table_names) 05672 my_casedn_str(files_charset_info, tmp_name); 05673 if (new_db_type != old_db_type && !table->file->can_switch_engines()) { 05674 my_error(ER_ROW_IS_REFERENCED, MYF(0)); 05675 goto err; 05676 } 05677 create_info->db_type=new_db_type; 05678 if (!create_info->comment.str) 05679 { 05680 create_info->comment.str= table->s->comment.str; 05681 create_info->comment.length= table->s->comment.length; 05682 } 05683 05684 table->file->update_create_info(create_info); 05685 if ((create_info->table_options & 05686 (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) || 05687 (used_fields & HA_CREATE_USED_PACK_KEYS)) 05688 db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); 05689 if (create_info->table_options & 05690 (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM)) 05691 db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM); 05692 if (create_info->table_options & 05693 (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE)) 05694 db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE | 05695 HA_OPTION_NO_DELAY_KEY_WRITE); 05696 create_info->table_options|= db_create_options; 05697 05698 if (table->s->tmp_table) 05699 create_info->options|=HA_LEX_CREATE_TMP_TABLE; 05700 05701 set_table_default_charset(thd, create_info, db); 05702 05703 { 05704 /* 05705 For some purposes we need prepared table structures and translated 05706 key descriptions with proper default key name assignment. 05707 05708 Unfortunately, mysql_prepare_table() modifies the field and key 05709 lists. mysql_create_table() needs the unmodified lists. Hence, we 05710 need to copy the lists and all their elements. The lists contain 05711 pointers to the elements only. 05712 05713 We cannot copy conditionally because the partition code always 05714 needs prepared lists and compare_tables() needs them and is almost 05715 always called. 05716 */ 05717 05718 /* Copy fields. */ 05719 List_iterator<create_field> prep_field_it(create_list); 05720 create_field *prep_field; 05721 while ((prep_field= prep_field_it++)) 05722 prepared_create_list.push_back(new create_field(*prep_field)); 05723 05724 /* Copy keys and key parts. */ 05725 List_iterator<Key> prep_key_it(key_list); 05726 Key *prep_key; 05727 while ((prep_key= prep_key_it++)) 05728 { 05729 List<key_part_spec> prep_columns; 05730 List_iterator<key_part_spec> prep_col_it(prep_key->columns); 05731 key_part_spec *prep_col; 05732 05733 while ((prep_col= prep_col_it++)) 05734 prep_columns.push_back(new key_part_spec(*prep_col)); 05735 prepared_key_list.push_back(new Key(prep_key->type, prep_key->name, 05736 &prep_key->key_create_info, 05737 prep_key->generated, prep_columns)); 05738 } 05739 05740 /* Create the prepared information. */ 05741 if (mysql_prepare_table(thd, create_info, &prepared_create_list, 05742 &prepared_key_list, 05743 (table->s->tmp_table != NO_TMP_TABLE), &db_options, 05744 table->file, &key_info_buffer, &key_count, 0)) 05745 goto err; 05746 } 05747 05748 if (thd->variables.old_alter_table 05749 || (table->s->db_type != create_info->db_type) 05750 #ifdef WITH_PARTITION_STORAGE_ENGINE 05751 || partition_changed 05752 #endif 05753 ) 05754 need_copy_table= 1; 05755 else 05756 { 05757 /* Try to optimize ALTER TABLE. Allocate result buffers. */ 05758 if (! (index_drop_buffer= 05759 (uint*) thd->alloc(sizeof(uint) * table->s->keys)) || 05760 ! (index_add_buffer= 05761 (uint*) thd->alloc(sizeof(uint) * prepared_key_list.elements))) 05762 goto err; 05763 /* Check how much the tables differ. */ 05764 need_copy_table= compare_tables(table, &prepared_create_list, 05765 key_info_buffer, key_count, 05766 create_info, alter_info, order_num, 05767 index_drop_buffer, &index_drop_count, 05768 index_add_buffer, &index_add_count, 05769 varchar); 05770 } 05771 05772 /* 05773 If there are index changes only, try to do them online. "Index 05774 changes only" means also that the handler for the table does not 05775 change. The table is open and locked. The handler can be accessed. 05776 */ 05777 if (need_copy_table == ALTER_TABLE_INDEX_CHANGED) 05778 { 05779 int pk_changed= 0; 05780 ulong alter_flags= 0; 05781 ulong needed_online_flags= 0; 05782 ulong needed_fast_flags= 0; 05783 KEY *key; 05784 uint *idx_p; 05785 uint *idx_end_p; 05786 05787 if (table->s->db_type->alter_table_flags) 05788 alter_flags= table->s->db_type->alter_table_flags(alter_info->flags); 05789 DBUG_PRINT("info", ("alter_flags: %lu", alter_flags)); 05790 /* Check dropped indexes. */ 05791 for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count; 05792 idx_p < idx_end_p; 05793 idx_p++) 05794 { 05795 key= table->key_info + *idx_p; 05796 DBUG_PRINT("info", ("index dropped: '%s'", key->name)); 05797 if (key->flags & HA_NOSAME) 05798 { 05799 /* Unique key. Check for "PRIMARY". */ 05800 if (! my_strcasecmp(system_charset_info, 05801 key->name, primary_key_name)) 05802 { 05803 /* Primary key. */ 05804 needed_online_flags|= HA_ONLINE_DROP_PK_INDEX; 05805 needed_fast_flags|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES; 05806 pk_changed++; 05807 } 05808 else 05809 { 05810 /* Non-primary unique key. */ 05811 needed_online_flags|= HA_ONLINE_DROP_UNIQUE_INDEX; 05812 needed_fast_flags|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES; 05813 } 05814 } 05815 else 05816 { 05817 /* Non-unique key. */ 05818 needed_online_flags|= HA_ONLINE_DROP_INDEX; 05819 needed_fast_flags|= HA_ONLINE_DROP_INDEX_NO_WRITES; 05820 } 05821 } 05822 05823 /* Check added indexes. */ 05824 for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count; 05825 idx_p < idx_end_p; 05826 idx_p++) 05827 { 05828 key= key_info_buffer + *idx_p; 05829 DBUG_PRINT("info", ("index added: '%s'", key->name)); 05830 if (key->flags & HA_NOSAME) 05831 { 05832 /* Unique key. Check for "PRIMARY". */ 05833 if (! my_strcasecmp(system_charset_info, 05834 key->name, primary_key_name)) 05835 { 05836 /* Primary key. */ 05837 needed_online_flags|= HA_ONLINE_ADD_PK_INDEX; 05838 needed_fast_flags|= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; 05839 pk_changed++; 05840 } 05841 else 05842 { 05843 /* Non-primary unique key. */ 05844 needed_online_flags|= HA_ONLINE_ADD_UNIQUE_INDEX; 05845 needed_fast_flags|= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES; 05846 } 05847 } 05848 else 05849 { 05850 /* Non-unique key. */ 05851 needed_online_flags|= HA_ONLINE_ADD_INDEX; 05852 needed_fast_flags|= HA_ONLINE_ADD_INDEX_NO_WRITES; 05853 } 05854 } 05855 05856 /* 05857 Online or fast add/drop index is possible only if 05858 the primary key is not added and dropped in the same statement. 05859 Otherwise we have to recreate the table. 05860 need_copy_table is no-zero at this place. 05861 */ 05862 if ( pk_changed < 2 ) 05863 { 05864 if ((alter_flags & needed_online_flags) == needed_online_flags) 05865 { 05866 /* All required online flags are present. */ 05867 need_copy_table= 0; 05868 need_lock_for_indexes= FALSE; 05869 } 05870 else if ((alter_flags & needed_fast_flags) == needed_fast_flags) 05871 { 05872 /* All required fast flags are present. */ 05873 need_copy_table= 0; 05874 } 05875 } 05876 DBUG_PRINT("info", ("need_copy_table: %u need_lock: %d", 05877 need_copy_table, need_lock_for_indexes)); 05878 } 05879 05880 /* 05881 better have a negative test here, instead of positive, like 05882 alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|... 05883 so that ALTER TABLE won't break when somebody will add new flag 05884 */ 05885 if (!need_copy_table) 05886 create_info->frm_only= 1; 05887 05888 #ifdef WITH_PARTITION_STORAGE_ENGINE 05889 if (fast_alter_partition) 05890 { 05891 DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info, 05892 create_info, table_list, 05893 &create_list, &key_list, 05894 db, table_name, 05895 fast_alter_partition)); 05896 } 05897 #endif 05898 05899 /* 05900 Handling of symlinked tables: 05901 If no rename: 05902 Create new data file and index file on the same disk as the 05903 old data and index files. 05904 Copy data. 05905 Rename new data file over old data file and new index file over 05906 old index file. 05907 Symlinks are not changed. 05908 05909 If rename: 05910 Create new data file and index file on the same disk as the 05911 old data and index files. Create also symlinks to point at 05912 the new tables. 05913 Copy data. 05914 At end, rename temporary tables and symlinks to temporary table 05915 to final table name. 05916 Remove old table and old symlinks 05917 05918 If rename is made to another database: 05919 Create new tables in new database. 05920 Copy data. 05921 Remove old table and symlinks. 05922 */ 05923 if (!strcmp(db, new_db)) // Ignore symlink if db changed 05924 { 05925 if (create_info->index_file_name) 05926 { 05927 /* Fix index_file_name to have 'tmp_name' as basename */ 05928 strmov(index_file, tmp_name); 05929 create_info->index_file_name=fn_same(index_file, 05930 create_info->index_file_name, 05931 1); 05932 } 05933 if (create_info->data_file_name) 05934 { 05935 /* Fix data_file_name to have 'tmp_name' as basename */ 05936 strmov(data_file, tmp_name); 05937 create_info->data_file_name=fn_same(data_file, 05938 create_info->data_file_name, 05939 1); 05940 } 05941 } 05942 else 05943 create_info->data_file_name=create_info->index_file_name=0; 05944 05945 /* 05946 Create a table with a temporary name. 05947 With create_info->frm_only == 1 this creates a .frm file only. 05948 We don't log the statement, it will be logged later. 05949 */ 05950 tmp_disable_binlog(thd); 05951 error= mysql_create_table(thd, new_db, tmp_name, 05952 create_info,create_list,key_list,1,0,0); 05953 reenable_binlog(thd); 05954 if (error) 05955 DBUG_RETURN(error); 05956 05957 /* Open the table if we need to copy the data. */ 05958 if (need_copy_table) 05959 { 05960 if (table->s->tmp_table) 05961 { 05962 TABLE_LIST tbl; 05963 bzero((void*) &tbl, sizeof(tbl)); 05964 tbl.db= new_db; 05965 tbl.table_name= tbl.alias= tmp_name; 05966 /* Table is in thd->temporary_tables */ 05967 new_table= open_table(thd, &tbl, thd->mem_root, (bool*) 0, 05968 MYSQL_LOCK_IGNORE_FLUSH); 05969 } 05970 else 05971 { 05972 char path[FN_REFLEN]; 05973 /* table is a normal table: Create temporary table in same directory */ 05974 build_table_filename(path, sizeof(path), new_db, tmp_name, "", 05975 FN_IS_TMP); 05976 new_table=open_temporary_table(thd, path, new_db, tmp_name,0); 05977 } 05978 if (!new_table) 05979 goto err1; 05980 } 05981 05982 /* Copy the data if necessary. */ 05983 thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields 05984 thd->cuted_fields=0L; 05985 thd->proc_info="copy to tmp table"; 05986 copied=deleted=0; 05987 if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER)) 05988 { 05989 /* We don't want update TIMESTAMP fields during ALTER TABLE. */ 05990 new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; 05991 new_table->next_number_field=new_table->found_next_number_field; 05992 error=copy_data_between_tables(table, new_table, create_list, ignore, 05993 order_num, order, &copied, &deleted); 05994 } 05995 thd->count_cuted_fields= CHECK_FIELD_IGNORE; 05996 05997 /* If we did not need to copy, we might still need to add/drop indexes. */ 05998 if (! new_table) 05999 { 06000 uint *key_numbers; 06001 uint *keyno_p; 06002 KEY *key_info; 06003 KEY *key; 06004 uint *idx_p; 06005 uint *idx_end_p; 06006 KEY_PART_INFO *key_part; 06007 KEY_PART_INFO *part_end; 06008 DBUG_PRINT("info", ("No new_table, checking add/drop index")); 06009 06010 table->file->prepare_for_alter(); 06011 if (index_add_count) 06012 { 06013 #ifdef XXX_TO_BE_DONE_LATER_BY_WL3020_AND_WL1892 06014 if (! need_lock_for_indexes) 06015 { 06016 /* Downgrade the write lock. */ 06017 mysql_lock_downgrade_write(thd, table, TL_WRITE_ALLOW_WRITE); 06018 } 06019 06020 /* Create a new .frm file for crash recovery. */ 06021 /* TODO: Must set INDEX_TO_BE_ADDED flags in the frm file. */ 06022 VOID(pthread_mutex_lock(&LOCK_open)); 06023 error= (mysql_create_frm(thd, reg_path, db, table_name, 06024 create_info, prepared_create_list, key_count, 06025 key_info_buffer, table->file) || 06026 table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, 06027 create_info)); 06028 VOID(pthread_mutex_unlock(&LOCK_open)); 06029 if (error) 06030 goto err1; 06031 #endif 06032 06033 /* The add_index() method takes an array of KEY structs. */ 06034 key_info= (KEY*) thd->alloc(sizeof(KEY) * index_add_count); 06035 key= key_info; 06036 for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count; 06037 idx_p < idx_end_p; 06038 idx_p++, key++) 06039 { 06040 /* Copy the KEY struct. */ 06041 *key= key_info_buffer[*idx_p]; 06042 /* Fix the key parts. */ 06043 part_end= key->key_part + key->key_parts; 06044 for (key_part= key->key_part; key_part < part_end; key_part++) 06045 key_part->field= table->field[key_part->fieldnr]; 06046 } 06047 /* Add the indexes. */ 06048 if ((error= table->file->add_index(table, key_info, index_add_count))) 06049 { 06050 /* 06051 Exchange the key_info for the error message. If we exchange 06052 key number by key name in the message later, we need correct info. 06053 */ 06054 KEY *save_key_info= table->key_info; 06055 table->key_info= key_info; 06056 table->file->print_error(error, MYF(0)); 06057 table->key_info= save_key_info; 06058 goto err1; 06059 } 06060 } 06061 /*end of if (index_add_count)*/ 06062 06063 if (index_drop_count) 06064 { 06065 #ifdef XXX_TO_BE_DONE_LATER_BY_WL3020_AND_WL1892 06066 /* Create a new .frm file for crash recovery. */ 06067 /* TODO: Must set INDEX_IS_ADDED in the frm file. */ 06068 /* TODO: Must set INDEX_TO_BE_DROPPED in the frm file. */ 06069 VOID(pthread_mutex_lock(&LOCK_open)); 06070 error= (mysql_create_frm(thd, reg_path, db, table_name, 06071 create_info, prepared_create_list, key_count, 06072 key_info_buffer, table->file) || 06073 table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, 06074 create_info)); 06075 VOID(pthread_mutex_unlock(&LOCK_open)); 06076 if (error) 06077 goto err1; 06078 06079 if (! need_lock_for_indexes) 06080 { 06081 LOCK_PARAM_TYPE lpt; 06082 06083 lpt.thd= thd; 06084 lpt.table= table; 06085 lpt.db= db; 06086 lpt.table_name= table_name; 06087 lpt.create_info= create_info; 06088 lpt.create_list= &create_list; 06089 lpt.key_count= key_count; 06090 lpt.key_info_buffer= key_info_buffer; 06091 abort_and_upgrade_lock(lpt); 06092 } 06093 #endif 06094 06095 /* The prepare_drop_index() method takes an array of key numbers. */ 06096 key_numbers= (uint*) thd->alloc(sizeof(uint) * index_drop_count); 06097 keyno_p= key_numbers; 06098 /* Get the number of each key. */ 06099 for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count; 06100 idx_p < idx_end_p; 06101 idx_p++, keyno_p++) 06102 *keyno_p= *idx_p; 06103 /* 06104 Tell the handler to prepare for drop indexes. 06105 This re-numbers the indexes to get rid of gaps. 06106 */ 06107 if ((error= table->file->prepare_drop_index(table, key_numbers, 06108 index_drop_count))) 06109 { 06110 table->file->print_error(error, MYF(0)); 06111 goto err1; 06112 } 06113 06114 #ifdef XXX_TO_BE_DONE_LATER_BY_WL3020 06115 if (! need_lock_for_indexes) 06116 { 06117 /* Downgrade the lock again. */ 06118 if (table->reginfo.lock_type == TL_WRITE_ALLOW_READ) 06119 { 06120 LOCK_PARAM_TYPE lpt; 06121 06122 lpt.thd= thd; 06123 lpt.table= table; 06124 lpt.db= db; 06125 lpt.table_name= table_name; 06126 lpt.create_info= create_info; 06127 lpt.create_list= &create_list; 06128 lpt.key_count= key_count; 06129 lpt.key_info_buffer= key_info_buffer; 06130 close_open_tables_and_downgrade(lpt); 06131 } 06132 } 06133 #endif 06134 06135 /* Tell the handler to finally drop the indexes. */ 06136 if ((error= table->file->final_drop_index(table))) 06137 { 06138 table->file->print_error(error, MYF(0)); 06139 goto err1; 06140 } 06141 } 06142 /*end of if (index_drop_count)*/ 06143 06144 /* 06145 The final .frm file is already created as a temporary file 06146 and will be renamed to the original table name later. 06147 */ 06148 06149 /* Need to commit before a table is unlocked (NDB requirement). */ 06150 DBUG_PRINT("info", ("Committing before unlocking table")); 06151 if (ha_commit_stmt(thd) || ha_commit(thd)) 06152 goto err1; 06153 committed= 1; 06154 } 06155 /*end of if (! new_table) for add/drop index*/ 06156 06157 if (table->s->tmp_table != NO_TMP_TABLE) 06158 { 06159 /* We changed a temporary table */ 06160 if (error) 06161 goto err1; 06162 /* Close lock if this is a transactional table */ 06163 if (thd->lock) 06164 { 06165 mysql_unlock_tables(thd, thd->lock); 06166 thd->lock=0; 06167 } 06168 /* Remove link to old table and rename the new one */ 06169 close_temporary_table(thd, table, 1, 1); 06170 /* Should pass the 'new_name' as we store table name in the cache */ 06171 if (rename_temporary_table(thd, new_table, new_db, new_name)) 06172 goto err1; 06173 /* We don't replicate alter table statement on temporary tables */ 06174 if (!thd->current_stmt_binlog_row_based) 06175 write_bin_log(thd, TRUE, thd->query, thd->query_length); 06176 goto end_temporary; 06177 } 06178 06179 if (new_table) 06180 { 06181 /* close temporary table that will be the new table */ 06182 intern_close_table(new_table); 06183 my_free((gptr) new_table,MYF(0)); 06184 } 06185 VOID(pthread_mutex_lock(&LOCK_open)); 06186 if (error) 06187 { 06188 VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); 06189 VOID(pthread_mutex_unlock(&LOCK_open)); 06190 goto err; 06191 } 06192 06193 /* 06194 Data is copied. Now we rename the old table to a temp name, 06195 rename the new one to the old name, remove all entries from the old table 06196 from the cache, free all locks, close the old table and remove it. 06197 */ 06198 06199 thd->proc_info="rename result table"; 06200 my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix, 06201 current_pid, thd->thread_id); 06202 if (lower_case_table_names) 06203 my_casedn_str(files_charset_info, old_name); 06204 if (new_name != table_name || new_db != db) 06205 { 06206 if (!access(new_name_buff,F_OK)) 06207 { 06208 error=1; 06209 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff); 06210 VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); 06211 VOID(pthread_mutex_unlock(&LOCK_open)); 06212 goto err; 06213 } 06214 } 06215 06216 #if !defined( __WIN__) 06217 if (table->file->has_transactions()) 06218 #endif 06219 { 06220 /* 06221 Win32 and InnoDB can't drop a table that is in use, so we must 06222 close the original table at before doing the rename 06223 */ 06224 table->s->version= 0; // Force removal of table def 06225 close_cached_table(thd, table); 06226 table=0; // Marker that table is closed 06227 no_table_reopen= TRUE; 06228 } 06229 #if !defined( __WIN__) 06230 else 06231 table->file->extra(HA_EXTRA_FORCE_REOPEN); // Don't use this file anymore 06232 #endif 06233 06234 06235 error=0; 06236 if (!need_copy_table) 06237 new_db_type=old_db_type= NULL; // this type cannot happen in regular ALTER 06238 if (mysql_rename_table(old_db_type, db, table_name, db, old_name, 06239 FN_TO_IS_TMP)) 06240 { 06241 error=1; 06242 VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); 06243 } 06244 else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db, 06245 new_alias, FN_FROM_IS_TMP) || 06246 (new_name != table_name || new_db != db) && // we also do rename 06247 Table_triggers_list::change_table_name(thd, db, table_name, 06248 new_db, new_alias)) 06249 { 06250 /* Try to get everything back. */ 06251 error=1; 06252 VOID(quick_rm_table(new_db_type,new_db,new_alias, 0)); 06253 VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); 06254 VOID(mysql_rename_table(old_db_type, db, old_name, db, alias, 06255 FN_FROM_IS_TMP)); 06256 } 06257 if (error) 06258 { 06259 /* 06260 This shouldn't happen. We solve this the safe way by 06261 closing the locked table. 06262 */ 06263 if (table) 06264 { 06265 table->s->version= 0; // Force removal of table def 06266 close_cached_table(thd,table); 06267 } 06268 VOID(pthread_mutex_unlock(&LOCK_open)); 06269 goto err; 06270 } 06271 if (! need_copy_table) 06272 { 06273 if (! table) 06274 { 06275 VOID(pthread_mutex_unlock(&LOCK_open)); 06276 if (! (table= open_ltable(thd, table_list, TL_WRITE_ALLOW_READ))) 06277 goto err; 06278 VOID(pthread_mutex_lock(&LOCK_open)); 06279 } 06280 /* Tell the handler that a new frm file is in place. */ 06281 if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG, 06282 create_info)) 06283 { 06284 VOID(pthread_mutex_unlock(&LOCK_open)); 06285 goto err; 06286 } 06287 } 06288 if (thd->lock || new_name != table_name || no_table_reopen) // True if WIN32 06289 { 06290 /* 06291 Not table locking or alter table with rename. 06292 Free locks and remove old table 06293 */ 06294 if (table) 06295 { 06296 table->s->version= 0; // Force removal of table def 06297 close_cached_table(thd,table); 06298 } 06299 VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP)); 06300 } 06301 else 06302 { 06303 /* 06304 Using LOCK TABLES without rename. 06305 This code is never executed on WIN32! 06306 Remove old renamed table, reopen table and get new locks 06307 */ 06308 if (table) 06309 { 06310 VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file 06311 /* Mark in-use copies old */ 06312 remove_table_from_cache(thd,db,table_name,RTFC_NO_FLAG); 06313 /* end threads waiting on lock */ 06314 mysql_lock_abort(thd,table, TRUE); 06315 } 06316 VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP)); 06317 if (close_data_tables(thd,db,table_name) || 06318 reopen_tables(thd,1,0)) 06319 { // This shouldn't happen 06320 if (table) 06321 { 06322 table->s->version= 0; // Force removal of table def 06323 close_cached_table(thd,table); // Remove lock for table 06324 } 06325 VOID(pthread_mutex_unlock(&LOCK_open)); 06326 goto err; 06327 } 06328 } 06329 VOID(pthread_mutex_unlock(&LOCK_open)); 06330 broadcast_refresh(); 06331 /* 06332 The ALTER TABLE is always in its own transaction. 06333 Commit must not be called while LOCK_open is locked. It could call 06334 wait_if_global_read_lock(), which could create a deadlock if called 06335 with LOCK_open. 06336 */ 06337 if (!committed) 06338 { 06339 error = ha_commit_stmt(thd); 06340 if (ha_commit(thd)) 06341 error=1; 06342 if (error) 06343 goto err; 06344 } 06345 thd->proc_info="end"; 06346 06347 ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, 06348 thd->query, thd->query_length, 06349 db, table_name); 06350 06351 DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based && 06352 (create_info->options & HA_LEX_CREATE_TMP_TABLE))); 06353 write_bin_log(thd, TRUE, thd->query, thd->query_length); 06354 /* 06355 TODO RONM: This problem needs to handled for Berkeley DB partitions 06356 as well 06357 */ 06358 if (ha_check_storage_engine_flag(old_db_type,HTON_FLUSH_AFTER_RENAME)) 06359 { 06360 /* 06361 For the alter table to be properly flushed to the logs, we 06362 have to open the new table. If not, we get a problem on server 06363 shutdown. 06364 */ 06365 char path[FN_REFLEN]; 06366 build_table_filename(path, sizeof(path), new_db, table_name, "", 0); 06367 table=open_temporary_table(thd, path, new_db, tmp_name,0); 06368 if (table) 06369 { 06370 intern_close_table(table); 06371 my_free((char*) table, MYF(0)); 06372 } 06373 else 06374 sql_print_warning("Could not open table %s.%s after rename\n", 06375 new_db,table_name); 06376 ha_flush_logs(old_db_type); 06377 } 06378 table_list->table=0; // For query cache 06379 query_cache_invalidate3(thd, table_list, 0); 06380 06381 end_temporary: 06382 my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), 06383 (ulong) (copied + deleted), (ulong) deleted, 06384 (ulong) thd->cuted_fields); 06385 if (do_send_ok) 06386 send_ok(thd,copied+deleted,0L,tmp_name); 06387 thd->some_tables_deleted=0; 06388 DBUG_RETURN(FALSE); 06389 06390 err1: 06391 if (new_table) 06392 { 06393 /* close_temporary_table() frees the new_table pointer. */ 06394 close_temporary_table(thd, new_table, 1, 1); 06395 } 06396 else 06397 VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); 06398 06399 err: 06400 DBUG_RETURN(TRUE); 06401 } 06402 /* mysql_alter_table */ 06403 06404 static int 06405 copy_data_between_tables(TABLE *from,TABLE *to, 06406 List<create_field> &create, 06407 bool ignore, 06408 uint order_num, ORDER *order, 06409 ha_rows *copied, 06410 ha_rows *deleted) 06411 { 06412 int error; 06413 Copy_field *copy,*copy_end; 06414 ulong found_count,delete_count; 06415 THD *thd= current_thd; 06416 uint length; 06417 SORT_FIELD *sortorder; 06418 READ_RECORD info; 06419 TABLE_LIST tables; 06420 List<Item> fields; 06421 List<Item> all_fields; 06422 ha_rows examined_rows; 06423 bool auto_increment_field_copied= 0; 06424 ulong save_sql_mode; 06425 ulonglong prev_insert_id; 06426 DBUG_ENTER("copy_data_between_tables"); 06427 06428 /* 06429 Turn off recovery logging since rollback of an alter table is to 06430 delete the new table so there is no need to log the changes to it. 06431 06432 This needs to be done before external_lock 06433 */ 06434 error= ha_enable_transaction(thd, FALSE); 06435 if (error) 06436 DBUG_RETURN(-1); 06437 06438 if (!(copy= new Copy_field[to->s->fields])) 06439 DBUG_RETURN(-1); /* purecov: inspected */ 06440 06441 if (to->file->ha_external_lock(thd, F_WRLCK)) 06442 DBUG_RETURN(-1); 06443 06444 /* We can abort alter table for any table type */ 06445 thd->no_trans_update= 0; 06446 thd->abort_on_warning= !ignore && test(thd->variables.sql_mode & 06447 (MODE_STRICT_TRANS_TABLES | 06448 MODE_STRICT_ALL_TABLES)); 06449 06450 from->file->info(HA_STATUS_VARIABLE); 06451 to->file->ha_start_bulk_insert(from->file->stats.records); 06452 06453 save_sql_mode= thd->variables.sql_mode; 06454 06455 List_iterator<create_field> it(create); 06456 create_field *def; 06457 copy_end=copy; 06458 for (Field **ptr=to->field ; *ptr ; ptr++) 06459 { 06460 def=it++; 06461 if (def->field) 06462 { 06463 if (*ptr == to->next_number_field) 06464 { 06465 auto_increment_field_copied= TRUE; 06466 /* 06467 If we are going to copy contents of one auto_increment column to 06468 another auto_increment column it is sensible to preserve zeroes. 06469 This condition also covers case when we are don't actually alter 06470 auto_increment column. 06471 */ 06472 if (def->field == from->found_next_number_field) 06473 thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO; 06474 } 06475 (copy_end++)->set(*ptr,def->field,0); 06476 } 06477 06478 } 06479 06480 found_count=delete_count=0; 06481 06482 if (order) 06483 { 06484 from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), 06485 MYF(MY_FAE | MY_ZEROFILL)); 06486 bzero((char*) &tables,sizeof(tables)); 06487 tables.table= from; 06488 tables.alias= tables.table_name= from->s->table_name.str; 06489 tables.db= from->s->db.str; 06490 error=1; 06491 06492 if (thd->lex->select_lex.setup_ref_array(thd, order_num) || 06493 setup_order(thd, thd->lex->select_lex.ref_pointer_array, 06494 &tables, fields, all_fields, order) || 06495 !(sortorder=make_unireg_sortorder(order, &length)) || 06496 (from->sort.found_records = filesort(thd, from, sortorder, length, 06497 (SQL_SELECT *) 0, HA_POS_ERROR, 1, 06498 &examined_rows)) == 06499 HA_POS_ERROR) 06500 goto err; 06501 }; 06502 06503 /* Tell handler that we have values for all columns in the to table */ 06504 to->use_all_columns(); 06505 init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1); 06506 if (ignore) 06507 to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); 06508 thd->row_count= 0; 06509 restore_record(to, s->default_values); // Create empty record 06510 while (!(error=info.read_record(&info))) 06511 { 06512 if (thd->killed) 06513 { 06514 thd->send_kill_message(); 06515 error= 1; 06516 break; 06517 } 06518 thd->row_count++; 06519 if (to->next_number_field) 06520 { 06521 if (auto_increment_field_copied) 06522 to->auto_increment_field_not_null= TRUE; 06523 else 06524 to->next_number_field->reset(); 06525 } 06526 06527 for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++) 06528 { 06529 copy_ptr->do_copy(copy_ptr); 06530 } 06531 prev_insert_id= to->file->next_insert_id; 06532 if ((error=to->file->ha_write_row((byte*) to->record[0]))) 06533 { 06534 if (!ignore || 06535 to->file->is_fatal_error(error, HA_CHECK_DUP)) 06536 { 06537 if (!to->file->is_fatal_error(error, HA_CHECK_DUP)) 06538 { 06539 uint key_nr= to->file->get_dup_key(error); 06540 if ((int) key_nr >= 0) 06541 { 06542 const char *err_msg= ER(ER_DUP_ENTRY); 06543 if (key_nr == 0 && 06544 (to->key_info[0].key_part[0].field->flags & 06545 AUTO_INCREMENT_FLAG)) 06546 err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE); 06547 to->file->print_keydup_error(key_nr, err_msg); 06548 break; 06549 } 06550 } 06551 06552 to->file->print_error(error,MYF(0)); 06553 break; 06554 } 06555 to->file->restore_auto_increment(prev_insert_id); 06556 delete_count++; 06557 } 06558 else 06559 found_count++; 06560 } 06561 end_read_record(&info); 06562 free_io_cache(from); 06563 delete [] copy; // This is never 0 06564 06565 if (to->file->ha_end_bulk_insert() && error <= 0) 06566 { 06567 to->file->print_error(my_errno,MYF(0)); 06568 error=1; 06569 } 06570 to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); 06571 06572 ha_enable_transaction(thd,TRUE); 06573 06574 /* 06575 Ensure that the new table is saved properly to disk so that we 06576 can do a rename 06577 */ 06578 if (ha_commit_stmt(thd)) 06579 error=1; 06580 if (ha_commit(thd)) 06581 error=1; 06582 06583 err: 06584 thd->variables.sql_mode= save_sql_mode; 06585 thd->abort_on_warning= 0; 06586 free_io_cache(from); 06587 *copied= found_count; 06588 *deleted=delete_count; 06589 to->file->ha_release_auto_increment(); 06590 if (to->file->ha_external_lock(thd,F_UNLCK)) 06591 error=1; 06592 DBUG_RETURN(error > 0 ? -1 : 0); 06593 } 06594 06595 06596 /* 06597 Recreates tables by calling mysql_alter_table(). 06598 06599 SYNOPSIS 06600 mysql_recreate_table() 06601 thd Thread handler 06602 tables Tables to recreate 06603 do_send_ok If we should send_ok() or leave it to caller 06604 06605 RETURN 06606 Like mysql_alter_table(). 06607 */ 06608 bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, 06609 bool do_send_ok) 06610 { 06611 DBUG_ENTER("mysql_recreate_table"); 06612 LEX *lex= thd->lex; 06613 HA_CREATE_INFO create_info; 06614 lex->create_list.empty(); 06615 lex->key_list.empty(); 06616 lex->col_list.empty(); 06617 lex->alter_info.reset(); 06618 bzero((char*) &create_info,sizeof(create_info)); 06619 create_info.db_type= 0; 06620 create_info.row_type=ROW_TYPE_NOT_USED; 06621 create_info.default_table_charset=default_charset_info; 06622 /* Force alter table to recreate table */ 06623 lex->alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE); 06624 DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info, 06625 table_list, lex->create_list, 06626 lex->key_list, 0, (ORDER *) 0, 06627 0, &lex->alter_info, do_send_ok)); 06628 } 06629 06630 06631 bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, 06632 HA_CHECK_OPT *check_opt) 06633 { 06634 TABLE_LIST *table; 06635 List<Item> field_list; 06636 Item *item; 06637 Protocol *protocol= thd->protocol; 06638 DBUG_ENTER("mysql_checksum_table"); 06639 06640 field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); 06641 item->maybe_null= 1; 06642 field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21)); 06643 item->maybe_null= 1; 06644 if (protocol->send_fields(&field_list, 06645 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 06646 DBUG_RETURN(TRUE); 06647 06648 for (table= tables; table; table= table->next_local) 06649 { 06650 char table_name[NAME_LEN*2+2]; 06651 TABLE *t; 06652 06653 strxmov(table_name, table->db ,".", table->table_name, NullS); 06654 06655 t= table->table= open_ltable(thd, table, TL_READ); 06656 thd->clear_error(); // these errors shouldn't get client 06657 06658 protocol->prepare_for_resend(); 06659 protocol->store(table_name, system_charset_info); 06660 06661 if (!t) 06662 { 06663 /* Table didn't exist */ 06664 protocol->store_null(); 06665 thd->clear_error(); 06666 } 06667 else 06668 { 06669 t->pos_in_table_list= table; 06670 06671 if (t->file->ha_table_flags() & HA_HAS_CHECKSUM && 06672 !(check_opt->flags & T_EXTEND)) 06673 protocol->store((ulonglong)t->file->checksum()); 06674 else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) && 06675 (check_opt->flags & T_QUICK)) 06676 protocol->store_null(); 06677 else 06678 { 06679 /* calculating table's checksum */ 06680 ha_checksum crc= 0; 06681 uchar null_mask=256 - (1 << t->s->last_null_bit_pos); 06682 06683 t->use_all_columns(); 06684 06685 if (t->file->ha_rnd_init(1)) 06686 protocol->store_null(); 06687 else 06688 { 06689 for (;;) 06690 { 06691 ha_checksum row_crc= 0; 06692 int error= t->file->rnd_next(t->record[0]); 06693 if (unlikely(error)) 06694 { 06695 if (error == HA_ERR_RECORD_DELETED) 06696 continue; 06697 break; 06698 } 06699 if (t->s->null_bytes) 06700 { 06701 /* fix undefined null bits */ 06702 t->record[0][t->s->null_bytes-1] |= null_mask; 06703 if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD)) 06704 t->record[0][0] |= 1; 06705 06706 row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes); 06707 } 06708 06709 for (uint i= 0; i < t->s->fields; i++ ) 06710 { 06711 Field *f= t->field[i]; 06712 if ((f->type() == FIELD_TYPE_BLOB) || 06713 (f->type() == MYSQL_TYPE_VARCHAR)) 06714 { 06715 String tmp; 06716 f->val_str(&tmp); 06717 row_crc= my_checksum(row_crc, (byte*) tmp.ptr(), tmp.length()); 06718 } 06719 else 06720 row_crc= my_checksum(row_crc, (byte*) f->ptr, 06721 f->pack_length()); 06722 } 06723 06724 crc+= row_crc; 06725 } 06726 protocol->store((ulonglong)crc); 06727 t->file->ha_rnd_end(); 06728 } 06729 } 06730 thd->clear_error(); 06731 close_thread_tables(thd); 06732 table->table=0; // For query cache 06733 } 06734 if (protocol->write()) 06735 goto err; 06736 } 06737 06738 send_eof(thd); 06739 DBUG_RETURN(FALSE); 06740 06741 err: 06742 close_thread_tables(thd); // Shouldn't be needed 06743 if (table) 06744 table->table=0; 06745 DBUG_RETURN(TRUE); 06746 } 06747 06748 static bool check_engine(THD *thd, const char *table_name, 06749 HA_CREATE_INFO *create_info) 06750 { 06751 handlerton **new_engine= &create_info->db_type; 06752 handlerton *req_engine= *new_engine; 06753 bool no_substitution= 06754 test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION); 06755 if (!(*new_engine= ha_checktype(thd, ha_legacy_type(req_engine), 06756 no_substitution, 1))) 06757 return TRUE; 06758 06759 if (req_engine && req_engine != *new_engine) 06760 { 06761 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 06762 ER_WARN_USING_OTHER_HANDLER, 06763 ER(ER_WARN_USING_OTHER_HANDLER), 06764 ha_resolve_storage_engine_name(*new_engine), 06765 table_name); 06766 } 06767 if (create_info->options & HA_LEX_CREATE_TMP_TABLE && 06768 ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED)) 06769 { 06770 if (create_info->used_fields & HA_CREATE_USED_ENGINE) 06771 { 06772 my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), 06773 hton2plugin[(*new_engine)->slot]->name.str, "TEMPORARY"); 06774 *new_engine= 0; 06775 return TRUE; 06776 } 06777 *new_engine= &myisam_hton; 06778 } 06779 return FALSE; 06780 }
1.4.7

