The world's most popular open source database
00001 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 00018 /* Some general useful functions */ 00019 00020 #include "mysql_priv.h" 00021 #include "sql_trigger.h" 00022 #include <m_ctype.h> 00023 #include "md5.h" 00024 00025 /* Functions defined in this file */ 00026 00027 void open_table_error(TABLE_SHARE *share, int error, int db_errno, 00028 myf errortype, int errarg); 00029 static int open_binary_frm(THD *thd, TABLE_SHARE *share, 00030 uchar *head, File file); 00031 static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, 00032 uint types, char **names); 00033 static uint find_field(Field **fields, uint start, uint length); 00034 00035 00036 /* Get column name from column hash */ 00037 00038 static byte *get_field_name(Field **buff, uint *length, 00039 my_bool not_used __attribute__((unused))) 00040 { 00041 *length= (uint) strlen((*buff)->field_name); 00042 return (byte*) (*buff)->field_name; 00043 } 00044 00045 00046 00047 /* 00048 Returns pointer to '.frm' extension of the file name. 00049 00050 SYNOPSIS 00051 fn_rext() 00052 name file name 00053 00054 DESCRIPTION 00055 Checks file name part starting with the rightmost '.' character, 00056 and returns it if it is equal to '.frm'. 00057 00058 TODO 00059 It is a good idea to get rid of this function modifying the code 00060 to garantee that the functions presently calling fn_rext() always 00061 get arguments in the same format: either with '.frm' or without '.frm'. 00062 00063 RETURN VALUES 00064 Pointer to the '.frm' extension. If there is no extension, 00065 or extension is not '.frm', pointer at the end of file name. 00066 */ 00067 00068 char *fn_rext(char *name) 00069 { 00070 char *res= strrchr(name, '.'); 00071 if (res && !strcmp(res, reg_ext)) 00072 return res; 00073 return name + strlen(name); 00074 } 00075 00076 00077 /* 00078 Allocate a setup TABLE_SHARE structure 00079 00080 SYNOPSIS 00081 alloc_table_share() 00082 TABLE_LIST Take database and table name from there 00083 key Table cache key (db \0 table_name \0...) 00084 key_length Length of key 00085 00086 RETURN 00087 0 Error (out of memory) 00088 # Share 00089 */ 00090 00091 TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, 00092 uint key_length) 00093 { 00094 MEM_ROOT mem_root; 00095 TABLE_SHARE *share; 00096 char *key_buff, *path_buff; 00097 char path[FN_REFLEN]; 00098 uint path_length; 00099 DBUG_ENTER("alloc_table_share"); 00100 DBUG_PRINT("enter", ("table: '%s'.'%s'", 00101 table_list->db, table_list->table_name)); 00102 00103 path_length= build_table_filename(path, sizeof(path) - 1, 00104 table_list->db, 00105 table_list->table_name, "", 0); 00106 init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); 00107 if (multi_alloc_root(&mem_root, 00108 &share, sizeof(*share), 00109 &key_buff, key_length, 00110 &path_buff, path_length + 1, 00111 NULL)) 00112 { 00113 bzero((char*) share, sizeof(*share)); 00114 00115 share->set_table_cache_key(key_buff, key, key_length); 00116 00117 share->path.str= path_buff; 00118 share->path.length= path_length; 00119 strmov(share->path.str, path); 00120 share->normalized_path.str= share->path.str; 00121 share->normalized_path.length= path_length; 00122 00123 share->version= refresh_version; 00124 share->flush_version= flush_version; 00125 00126 #ifdef HAVE_ROW_BASED_REPLICATION 00127 /* 00128 This constant is used to mark that no table map version has been 00129 assigned. No arithmetic is done on the value: it will be 00130 overwritten with a value taken from MYSQL_BIN_LOG. 00131 */ 00132 share->table_map_version= ~(ulonglong)0; 00133 00134 /* 00135 Since alloc_table_share() can be called without any locking (for 00136 example, ha_create_table... functions), we do not assign a table 00137 map id here. Instead we assign a value that is not used 00138 elsewhere, and then assign a table map id inside open_table() 00139 under the protection of the LOCK_open mutex. 00140 */ 00141 share->table_map_id= ~0UL; 00142 share->cached_row_logging_check= -1; 00143 00144 #endif 00145 00146 memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root)); 00147 pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST); 00148 pthread_cond_init(&share->cond, NULL); 00149 } 00150 DBUG_RETURN(share); 00151 } 00152 00153 00154 /* 00155 Initialize share for temporary tables 00156 00157 SYNOPSIS 00158 init_tmp_table_share() 00159 share Share to fill 00160 key Table_cache_key, as generated from create_table_def_key. 00161 must start with db name. 00162 key_length Length of key 00163 table_name Table name 00164 path Path to file (possible in lower case) without .frm 00165 00166 NOTES 00167 This is different from alloc_table_share() because temporary tables 00168 don't have to be shared between threads or put into the table def 00169 cache, so we can do some things notable simpler and faster 00170 00171 If table is not put in thd->temporary_tables (happens only when 00172 one uses OPEN TEMPORARY) then one can specify 'db' as key and 00173 use key_length= 0 as neither table_cache_key or key_length will be used). 00174 */ 00175 00176 void init_tmp_table_share(TABLE_SHARE *share, const char *key, 00177 uint key_length, const char *table_name, 00178 const char *path) 00179 { 00180 DBUG_ENTER("init_tmp_table_share"); 00181 DBUG_PRINT("enter", ("table: '%s'.'%s'", key, table_name)); 00182 00183 bzero((char*) share, sizeof(*share)); 00184 init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); 00185 share->tmp_table= INTERNAL_TMP_TABLE; 00186 share->db.str= (char*) key; 00187 share->db.length= strlen(key); 00188 share->table_cache_key.str= (char*) key; 00189 share->table_cache_key.length= key_length; 00190 share->table_name.str= (char*) table_name; 00191 share->table_name.length= strlen(table_name); 00192 share->path.str= (char*) path; 00193 share->normalized_path.str= (char*) path; 00194 share->path.length= share->normalized_path.length= strlen(path); 00195 share->frm_version= FRM_VER_TRUE_VARCHAR; 00196 00197 #ifdef HAVE_ROW_BASED_REPLICATION 00198 /* 00199 Temporary tables are not replicated, but we set up these fields 00200 anyway to be able to catch errors. 00201 */ 00202 share->table_map_version= ~(ulonglong)0; 00203 share->table_map_id= ~0UL; 00204 share->cached_row_logging_check= -1; 00205 #endif 00206 00207 DBUG_VOID_RETURN; 00208 } 00209 00210 00211 /* 00212 Free table share and memory used by it 00213 00214 SYNOPSIS 00215 free_table_share() 00216 share Table share 00217 00218 NOTES 00219 share->mutex must be locked when we come here if it's not a temp table 00220 */ 00221 00222 void free_table_share(TABLE_SHARE *share) 00223 { 00224 MEM_ROOT mem_root; 00225 DBUG_ENTER("free_table_share"); 00226 DBUG_PRINT("enter", ("table: %s.%s", share->db.str, share->table_name.str)); 00227 DBUG_ASSERT(share->ref_count == 0); 00228 00229 /* 00230 If someone is waiting for this to be deleted, inform it about this. 00231 Don't do a delete until we know that no one is refering to this anymore. 00232 */ 00233 if (share->tmp_table == NO_TMP_TABLE) 00234 { 00235 /* share->mutex is locked in release_table_share() */ 00236 while (share->waiting_on_cond) 00237 { 00238 pthread_cond_broadcast(&share->cond); 00239 pthread_cond_wait(&share->cond, &share->mutex); 00240 } 00241 /* No thread refers to this anymore */ 00242 pthread_mutex_unlock(&share->mutex); 00243 pthread_mutex_destroy(&share->mutex); 00244 pthread_cond_destroy(&share->cond); 00245 } 00246 hash_free(&share->name_hash); 00247 00248 /* We must copy mem_root from share because share is allocated through it */ 00249 memcpy((char*) &mem_root, (char*) &share->mem_root, sizeof(mem_root)); 00250 free_root(&mem_root, MYF(0)); // Free's share 00251 DBUG_VOID_RETURN; 00252 } 00253 00254 00255 /* 00256 Read table definition from a binary / text based .frm file 00257 00258 SYNOPSIS 00259 open_table_def() 00260 thd Thread handler 00261 share Fill this with table definition 00262 db_flags Bit mask of the following flags: OPEN_VIEW 00263 00264 NOTES 00265 This function is called when the table definition is not cached in 00266 table_def_cache 00267 The data is returned in 'share', which is alloced by 00268 alloc_table_share().. The code assumes that share is initialized. 00269 00270 RETURN VALUES 00271 0 ok 00272 1 Error (see open_table_error) 00273 2 Error (see open_table_error) 00274 3 Wrong data in .frm file 00275 4 Error (see open_table_error) 00276 5 Error (see open_table_error: charset unavailable) 00277 6 Unknown .frm version 00278 */ 00279 00280 int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags) 00281 { 00282 int error, table_type; 00283 bool error_given; 00284 File file; 00285 uchar head[288], *disk_buff; 00286 char path[FN_REFLEN]; 00287 MEM_ROOT **root_ptr, *old_root; 00288 DBUG_ENTER("open_table_def"); 00289 DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str, 00290 share->table_name.str, share->normalized_path.str)); 00291 00292 error= 1; 00293 error_given= 0; 00294 disk_buff= NULL; 00295 00296 strxmov(path, share->normalized_path.str, reg_ext, NullS); 00297 if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) 00298 { 00299 if (strchr(share->table_name.str, '@')) 00300 goto err_not_open; 00301 00302 /* Try unecoded 5.0 name */ 00303 uint length; 00304 strxnmov(path, sizeof(path)-1, 00305 mysql_data_home, "/", share->db.str, "/", 00306 share->table_name.str, reg_ext, NullS); 00307 length= unpack_filename(path, path) - reg_ext_length; 00308 /* 00309 The following is a safety test and should never fail 00310 as the old file name should never be longer than the new one. 00311 */ 00312 DBUG_ASSERT(length <= share->normalized_path.length); 00313 /* 00314 If the old and the new names have the same length, 00315 then table name does not have tricky characters, 00316 so no need to check the old file name. 00317 */ 00318 if (length == share->normalized_path.length || 00319 ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)) 00320 goto err_not_open; 00321 00322 /* Unencoded 5.0 table name found */ 00323 path[length]= '\0'; // Remove .frm extension 00324 strmov(share->normalized_path.str, path); 00325 share->normalized_path.length= length; 00326 } 00327 00328 error= 4; 00329 if (my_read(file,(byte*) head, 64, MYF(MY_NABP))) 00330 goto err; 00331 00332 if (head[0] == (uchar) 254 && head[1] == 1) 00333 { 00334 if (head[2] == FRM_VER || head[2] == FRM_VER+1 || 00335 (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4)) 00336 table_type= 1; 00337 else 00338 { 00339 error= 6; // Unkown .frm version 00340 goto err; 00341 } 00342 } 00343 else if (memcmp(head, STRING_WITH_LEN("TYPE=")) == 0) 00344 { 00345 error= 5; 00346 if (memcmp(head+5,"VIEW",4) == 0) 00347 { 00348 share->is_view= 1; 00349 if (db_flags & OPEN_VIEW) 00350 error= 0; 00351 } 00352 goto err; 00353 } 00354 else 00355 goto err; 00356 00357 /* No handling of text based files yet */ 00358 if (table_type == 1) 00359 { 00360 root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); 00361 old_root= *root_ptr; 00362 *root_ptr= &share->mem_root; 00363 error= open_binary_frm(thd, share, head, file); 00364 *root_ptr= old_root; 00365 00366 if (share->db.length == 5 && 00367 !my_strcasecmp(system_charset_info, share->db.str, "mysql")) 00368 { 00369 /* 00370 We can't mark all tables in 'mysql' database as system since we don't 00371 allow to lock such tables for writing with any other tables (even with 00372 other system tables) and some privilege tables need this. 00373 */ 00374 if (!my_strcasecmp(system_charset_info, share->table_name.str, "proc")) 00375 share->system_table= 1; 00376 else 00377 { 00378 if (!my_strcasecmp(system_charset_info, share->table_name.str, 00379 "general_log")) 00380 share->log_table= QUERY_LOG_GENERAL; 00381 else 00382 if (!my_strcasecmp(system_charset_info, share->table_name.str, 00383 "slow_log")) 00384 share->log_table= QUERY_LOG_SLOW; 00385 } 00386 } 00387 error_given= 1; 00388 } 00389 00390 if (!error) 00391 thd->status_var.opened_shares++; 00392 00393 err: 00394 my_close(file, MYF(MY_WME)); 00395 00396 err_not_open: 00397 if (error && !error_given) 00398 { 00399 share->error= error; 00400 open_table_error(share, error, (share->open_errno= my_errno), 0); 00401 } 00402 00403 DBUG_RETURN(error); 00404 } 00405 00406 00407 /* 00408 Read data from a binary .frm file from MySQL 3.23 - 5.0 into TABLE_SHARE 00409 */ 00410 00411 static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, 00412 File file) 00413 { 00414 int error, errarg= 0; 00415 uint new_frm_ver, field_pack_length, new_field_pack_flag; 00416 uint interval_count, interval_parts, read_length, int_length; 00417 uint db_create_options, keys, key_parts, n_length; 00418 uint key_info_length, com_length, null_bit_pos; 00419 uint extra_rec_buf_length; 00420 uint i,j; 00421 bool use_hash; 00422 char *keynames, *record, *names, *comment_pos; 00423 uchar *disk_buff, *strpos, *null_flags, *null_pos; 00424 ulong pos, record_offset, *rec_per_key, rec_buff_length; 00425 handler *handler_file= 0; 00426 KEY *keyinfo; 00427 KEY_PART_INFO *key_part; 00428 SQL_CRYPT *crypted=0; 00429 Field **field_ptr, *reg_field; 00430 const char **interval_array; 00431 enum legacy_db_type legacy_db_type; 00432 my_bitmap_map *bitmaps; 00433 DBUG_ENTER("open_binary_frm"); 00434 00435 new_field_pack_flag= head[27]; 00436 new_frm_ver= (head[2] - FRM_VER); 00437 field_pack_length= new_frm_ver < 2 ? 11 : 17; 00438 disk_buff= 0; 00439 00440 error= 3; 00441 if (!(pos=get_form_pos(file,head,(TYPELIB*) 0))) 00442 goto err; /* purecov: inspected */ 00443 00444 share->frm_version= head[2]; 00445 /* 00446 Check if .frm file created by MySQL 5.0. In this case we want to 00447 display CHAR fields as CHAR and not as VARCHAR. 00448 We do it this way as we want to keep the old frm version to enable 00449 MySQL 4.1 to read these files. 00450 */ 00451 if (share->frm_version == FRM_VER_TRUE_VARCHAR -1 && head[33] == 5) 00452 share->frm_version= FRM_VER_TRUE_VARCHAR; 00453 00454 #ifdef WITH_PARTITION_STORAGE_ENGINE 00455 if (*(head+61) && 00456 !(share->default_part_db_type= 00457 ha_checktype(thd, (enum legacy_db_type) (uint) *(head+61), 1, 0))) 00458 goto err; 00459 DBUG_PRINT("info", ("default_part_db_type = %u", head[61])); 00460 #endif 00461 legacy_db_type= (enum legacy_db_type) (uint) *(head+3); 00462 share->db_type= ha_checktype(thd, legacy_db_type, 0, 0); 00463 share->db_create_options= db_create_options= uint2korr(head+30); 00464 share->db_options_in_use= share->db_create_options; 00465 share->mysql_version= uint4korr(head+51); 00466 share->null_field_first= 0; 00467 if (!head[32]) // New frm file in 3.23 00468 { 00469 share->avg_row_length= uint4korr(head+34); 00470 share-> row_type= (row_type) head[40]; 00471 share->table_charset= get_charset((uint) head[38],MYF(0)); 00472 share->null_field_first= 1; 00473 } 00474 if (!share->table_charset) 00475 { 00476 /* unknown charset in head[38] or pre-3.23 frm */ 00477 if (use_mb(default_charset_info)) 00478 { 00479 /* Warn that we may be changing the size of character columns */ 00480 sql_print_warning("'%s' had no or invalid character set, " 00481 "and default character set is multi-byte, " 00482 "so character column sizes may have changed", 00483 share->path); 00484 } 00485 share->table_charset= default_charset_info; 00486 } 00487 share->db_record_offset= 1; 00488 if (db_create_options & HA_OPTION_LONG_BLOB_PTR) 00489 share->blob_ptr_size= portable_sizeof_char_ptr; 00490 /* Set temporarily a good value for db_low_byte_first */ 00491 share->db_low_byte_first= test(legacy_db_type != DB_TYPE_ISAM); 00492 error=4; 00493 share->max_rows= uint4korr(head+18); 00494 share->min_rows= uint4korr(head+22); 00495 00496 /* Read keyinformation */ 00497 key_info_length= (uint) uint2korr(head+28); 00498 VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0))); 00499 if (read_string(file,(gptr*) &disk_buff,key_info_length)) 00500 goto err; /* purecov: inspected */ 00501 if (disk_buff[0] & 0x80) 00502 { 00503 share->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f); 00504 share->key_parts= key_parts= uint2korr(disk_buff+2); 00505 } 00506 else 00507 { 00508 share->keys= keys= disk_buff[0]; 00509 share->key_parts= key_parts= disk_buff[1]; 00510 } 00511 share->keys_for_keyread.init(0); 00512 share->keys_in_use.init(keys); 00513 00514 n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO); 00515 if (!(keyinfo = (KEY*) alloc_root(&share->mem_root, 00516 n_length + uint2korr(disk_buff+4)))) 00517 goto err; /* purecov: inspected */ 00518 bzero((char*) keyinfo,n_length); 00519 share->key_info= keyinfo; 00520 key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys); 00521 strpos=disk_buff+6; 00522 00523 if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root, 00524 sizeof(ulong*)*key_parts))) 00525 goto err; 00526 00527 for (i=0 ; i < keys ; i++, keyinfo++) 00528 { 00529 keyinfo->table= 0; // Updated in open_frm 00530 if (new_frm_ver >= 3) 00531 { 00532 keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME; 00533 keyinfo->key_length= (uint) uint2korr(strpos+2); 00534 keyinfo->key_parts= (uint) strpos[4]; 00535 keyinfo->algorithm= (enum ha_key_alg) strpos[5]; 00536 keyinfo->block_size= uint2korr(strpos+6); 00537 strpos+=8; 00538 } 00539 else 00540 { 00541 keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME; 00542 keyinfo->key_length= (uint) uint2korr(strpos+1); 00543 keyinfo->key_parts= (uint) strpos[3]; 00544 keyinfo->algorithm= HA_KEY_ALG_UNDEF; 00545 strpos+=4; 00546 } 00547 00548 keyinfo->key_part= key_part; 00549 keyinfo->rec_per_key= rec_per_key; 00550 for (j=keyinfo->key_parts ; j-- ; key_part++) 00551 { 00552 *rec_per_key++=0; 00553 key_part->fieldnr= (uint16) (uint2korr(strpos) & FIELD_NR_MASK); 00554 key_part->offset= (uint) uint2korr(strpos+2)-1; 00555 key_part->key_type= (uint) uint2korr(strpos+5); 00556 // key_part->field= (Field*) 0; // Will be fixed later 00557 if (new_frm_ver >= 1) 00558 { 00559 key_part->key_part_flag= *(strpos+4); 00560 key_part->length= (uint) uint2korr(strpos+7); 00561 strpos+=9; 00562 } 00563 else 00564 { 00565 key_part->length= *(strpos+4); 00566 key_part->key_part_flag=0; 00567 if (key_part->length > 128) 00568 { 00569 key_part->length&=127; /* purecov: inspected */ 00570 key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */ 00571 } 00572 strpos+=7; 00573 } 00574 key_part->store_length=key_part->length; 00575 } 00576 } 00577 keynames=(char*) key_part; 00578 strpos+= (strmov(keynames, (char *) strpos) - keynames)+1; 00579 00580 share->reclength = uint2korr((head+16)); 00581 if (*(head+26) == 1) 00582 share->system= 1; /* one-record-database */ 00583 #ifdef HAVE_CRYPTED_FRM 00584 else if (*(head+26) == 2) 00585 { 00586 crypted= get_crypt_for_frm(); 00587 share->crypted= 1; 00588 } 00589 #endif 00590 00591 record_offset= (ulong) (uint2korr(head+6)+ 00592 ((uint2korr(head+14) == 0xffff ? 00593 uint4korr(head+47) : uint2korr(head+14)))); 00594 00595 if ((n_length= uint4korr(head+55))) 00596 { 00597 /* Read extra data segment */ 00598 char *buff, *next_chunk, *buff_end; 00599 DBUG_PRINT("info", ("extra segment size is %u bytes", n_length)); 00600 if (!(next_chunk= buff= my_malloc(n_length, MYF(MY_WME)))) 00601 goto err; 00602 if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength, 00603 MYF(MY_NABP))) 00604 { 00605 my_free(buff, MYF(0)); 00606 goto err; 00607 } 00608 share->connect_string.length= uint2korr(buff); 00609 if (! (share->connect_string.str= strmake_root(&share->mem_root, 00610 next_chunk + 2, share->connect_string.length))) 00611 { 00612 my_free(buff, MYF(0)); 00613 goto err; 00614 } 00615 next_chunk+= share->connect_string.length + 2; 00616 buff_end= buff + n_length; 00617 if (next_chunk + 2 < buff_end) 00618 { 00619 uint str_db_type_length= uint2korr(next_chunk); 00620 LEX_STRING name= { next_chunk + 2, str_db_type_length }; 00621 handlerton *tmp_db_type= ha_resolve_by_name(thd, &name); 00622 if (tmp_db_type != NULL) 00623 { 00624 share->db_type= tmp_db_type; 00625 DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", 00626 str_db_type_length, next_chunk + 2, 00627 ha_legacy_type(share->db_type))); 00628 } 00629 #ifdef WITH_PARTITION_STORAGE_ENGINE 00630 else 00631 { 00632 if (!strncmp(next_chunk + 2, "partition", str_db_type_length)) 00633 { 00634 /* Use partition handler */ 00635 share->db_type= &partition_hton; 00636 DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", 00637 str_db_type_length, next_chunk + 2, 00638 ha_legacy_type(share->db_type))); 00639 } 00640 } 00641 #endif 00642 next_chunk+= str_db_type_length + 2; 00643 } 00644 if (next_chunk + 5 < buff_end) 00645 { 00646 uint32 partition_info_len = uint4korr(next_chunk); 00647 #ifdef WITH_PARTITION_STORAGE_ENGINE 00648 if ((share->partition_info_len= partition_info_len)) 00649 { 00650 if (!(share->partition_info= 00651 (uchar*) memdup_root(&share->mem_root, next_chunk + 4, 00652 partition_info_len + 1))) 00653 { 00654 my_free(buff, MYF(0)); 00655 goto err; 00656 } 00657 } 00658 #else 00659 if (partition_info_len) 00660 { 00661 DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined")); 00662 my_free(buff, MYF(0)); 00663 goto err; 00664 } 00665 #endif 00666 next_chunk+= 5 + partition_info_len; 00667 } 00668 #if MYSQL_VERSION_ID < 50200 00669 if (share->mysql_version >= 50106 && share->mysql_version <= 50109) 00670 { 00671 /* 00672 Partition state array was here in version 5.1.6 to 5.1.9, this code 00673 makes it possible to load a 5.1.6 table in later versions. Can most 00674 likely be removed at some point in time. Will only be used for 00675 upgrades within 5.1 series of versions. Upgrade to 5.2 can only be 00676 done from newer 5.1 versions. 00677 */ 00678 next_chunk+= 4; 00679 } 00680 else if (share->mysql_version >= 50110) 00681 #endif 00682 { 00683 /* New auto_partitioned indicator introduced in 5.1.11 */ 00684 #ifdef WITH_PARTITION_STORAGE_ENGINE 00685 share->auto_partitioned= *next_chunk; 00686 #endif 00687 next_chunk++; 00688 } 00689 keyinfo= share->key_info; 00690 for (i= 0; i < keys; i++, keyinfo++) 00691 { 00692 if (keyinfo->flags & HA_USES_PARSER) 00693 { 00694 LEX_STRING parser_name; 00695 if (next_chunk >= buff_end) 00696 { 00697 DBUG_PRINT("error", 00698 ("fulltext key uses parser that is not defined in .frm")); 00699 my_free(buff, MYF(0)); 00700 goto err; 00701 } 00702 parser_name.str= next_chunk; 00703 parser_name.length= strlen(next_chunk); 00704 keyinfo->parser= plugin_lock(&parser_name, MYSQL_FTPARSER_PLUGIN); 00705 if (! keyinfo->parser) 00706 { 00707 my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), parser_name.str); 00708 my_free(buff, MYF(0)); 00709 goto err; 00710 } 00711 } 00712 } 00713 my_free(buff, MYF(0)); 00714 } 00715 share->key_block_size= uint2korr(head+62); 00716 00717 error=4; 00718 extra_rec_buf_length= uint2korr(head+59); 00719 rec_buff_length= ALIGN_SIZE(share->reclength + 1 + extra_rec_buf_length); 00720 share->rec_buff_length= rec_buff_length; 00721 if (!(record= (char *) alloc_root(&share->mem_root, 00722 rec_buff_length))) 00723 goto err; /* purecov: inspected */ 00724 share->default_values= (byte *) record; 00725 if (my_pread(file,(byte*) record, (uint) share->reclength, 00726 record_offset, MYF(MY_NABP))) 00727 goto err; /* purecov: inspected */ 00728 00729 VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0))); 00730 if (my_read(file,(byte*) head,288,MYF(MY_NABP))) 00731 goto err; 00732 #ifdef HAVE_CRYPTED_FRM 00733 if (crypted) 00734 { 00735 crypted->decode((char*) head+256,288-256); 00736 if (sint2korr(head+284) != 0) // Should be 0 00737 goto err; // Wrong password 00738 } 00739 #endif 00740 00741 share->fields= uint2korr(head+258); 00742 pos= uint2korr(head+260); /* Length of all screens */ 00743 n_length= uint2korr(head+268); 00744 interval_count= uint2korr(head+270); 00745 interval_parts= uint2korr(head+272); 00746 int_length= uint2korr(head+274); 00747 share->null_fields= uint2korr(head+282); 00748 com_length= uint2korr(head+284); 00749 share->comment.length= (int) (head[46]); 00750 share->comment.str= strmake_root(&share->mem_root, (char*) head+47, 00751 share->comment.length); 00752 00753 DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, share->keys,n_length,int_length, com_length)); 00754 00755 if (!(field_ptr = (Field **) 00756 alloc_root(&share->mem_root, 00757 (uint) ((share->fields+1)*sizeof(Field*)+ 00758 interval_count*sizeof(TYPELIB)+ 00759 (share->fields+interval_parts+ 00760 keys+3)*sizeof(my_string)+ 00761 (n_length+int_length+com_length))))) 00762 goto err; /* purecov: inspected */ 00763 00764 share->field= field_ptr; 00765 read_length=(uint) (share->fields * field_pack_length + 00766 pos+ (uint) (n_length+int_length+com_length)); 00767 if (read_string(file,(gptr*) &disk_buff,read_length)) 00768 goto err; /* purecov: inspected */ 00769 #ifdef HAVE_CRYPTED_FRM 00770 if (crypted) 00771 { 00772 crypted->decode((char*) disk_buff,read_length); 00773 delete crypted; 00774 crypted=0; 00775 } 00776 #endif 00777 strpos= disk_buff+pos; 00778 00779 share->intervals= (TYPELIB*) (field_ptr+share->fields+1); 00780 interval_array= (const char **) (share->intervals+interval_count); 00781 names= (char*) (interval_array+share->fields+interval_parts+keys+3); 00782 if (!interval_count) 00783 share->intervals= 0; // For better debugging 00784 memcpy((char*) names, strpos+(share->fields*field_pack_length), 00785 (uint) (n_length+int_length)); 00786 comment_pos= names+(n_length+int_length); 00787 memcpy(comment_pos, disk_buff+read_length-com_length, com_length); 00788 00789 fix_type_pointers(&interval_array, &share->fieldnames, 1, &names); 00790 fix_type_pointers(&interval_array, share->intervals, interval_count, 00791 &names); 00792 00793 { 00794 /* Set ENUM and SET lengths */ 00795 TYPELIB *interval; 00796 for (interval= share->intervals; 00797 interval < share->intervals + interval_count; 00798 interval++) 00799 { 00800 uint count= (uint) (interval->count + 1) * sizeof(uint); 00801 if (!(interval->type_lengths= (uint *) alloc_root(&share->mem_root, 00802 count))) 00803 goto err; 00804 for (count= 0; count < interval->count; count++) 00805 interval->type_lengths[count]= strlen(interval->type_names[count]); 00806 interval->type_lengths[count]= 0; 00807 } 00808 } 00809 00810 if (keynames) 00811 fix_type_pointers(&interval_array, &share->keynames, 1, &keynames); 00812 00813 /* Allocate handler */ 00814 if (!(handler_file= get_new_handler(share, thd->mem_root, 00815 share->db_type))) 00816 goto err; 00817 00818 record= (char*) share->default_values-1; /* Fieldstart = 1 */ 00819 if (share->null_field_first) 00820 { 00821 null_flags= null_pos= (uchar*) record+1; 00822 null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1; 00823 /* 00824 null_bytes below is only correct under the condition that 00825 there are no bit fields. Correct values is set below after the 00826 table struct is initialized 00827 */ 00828 share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8; 00829 } 00830 #ifndef WE_WANT_TO_SUPPORT_VERY_OLD_FRM_FILES 00831 else 00832 { 00833 share->null_bytes= (share->null_fields+7)/8; 00834 null_flags= null_pos= (uchar*) (record + 1 +share->reclength - 00835 share->null_bytes); 00836 null_bit_pos= 0; 00837 } 00838 #endif 00839 00840 use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH; 00841 if (use_hash) 00842 use_hash= !hash_init(&share->name_hash, 00843 system_charset_info, 00844 share->fields,0,0, 00845 (hash_get_key) get_field_name,0,0); 00846 00847 for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) 00848 { 00849 uint pack_flag, interval_nr, unireg_type, recpos, field_length; 00850 enum_field_types field_type; 00851 CHARSET_INFO *charset=NULL; 00852 Field::geometry_type geom_type= Field::GEOM_GEOMETRY; 00853 LEX_STRING comment; 00854 00855 if (new_frm_ver >= 3) 00856 { 00857 /* new frm file in 4.1 */ 00858 field_length= uint2korr(strpos+3); 00859 recpos= uint3korr(strpos+5); 00860 pack_flag= uint2korr(strpos+8); 00861 unireg_type= (uint) strpos[10]; 00862 interval_nr= (uint) strpos[12]; 00863 uint comment_length=uint2korr(strpos+15); 00864 field_type=(enum_field_types) (uint) strpos[13]; 00865 00866 /* charset and geometry_type share the same byte in frm */ 00867 if (field_type == FIELD_TYPE_GEOMETRY) 00868 { 00869 #ifdef HAVE_SPATIAL 00870 geom_type= (Field::geometry_type) strpos[14]; 00871 charset= &my_charset_bin; 00872 #else 00873 error= 4; // unsupported field type 00874 goto err; 00875 #endif 00876 } 00877 else 00878 { 00879 if (!strpos[14]) 00880 charset= &my_charset_bin; 00881 else if (!(charset=get_charset((uint) strpos[14], MYF(0)))) 00882 { 00883 error= 5; // Unknown or unavailable charset 00884 errarg= (int) strpos[14]; 00885 goto err; 00886 } 00887 } 00888 if (!comment_length) 00889 { 00890 comment.str= (char*) ""; 00891 comment.length=0; 00892 } 00893 else 00894 { 00895 comment.str= (char*) comment_pos; 00896 comment.length= comment_length; 00897 comment_pos+= comment_length; 00898 } 00899 } 00900 else 00901 { 00902 field_length= (uint) strpos[3]; 00903 recpos= uint2korr(strpos+4), 00904 pack_flag= uint2korr(strpos+6); 00905 pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files 00906 unireg_type= (uint) strpos[8]; 00907 interval_nr= (uint) strpos[10]; 00908 00909 /* old frm file */ 00910 field_type= (enum_field_types) f_packtype(pack_flag); 00911 if (f_is_binary(pack_flag)) 00912 { 00913 /* 00914 Try to choose the best 4.1 type: 00915 - for 4.0 "CHAR(N) BINARY" or "VARCHAR(N) BINARY" 00916 try to find a binary collation for character set. 00917 - for other types (e.g. BLOB) just use my_charset_bin. 00918 */ 00919 if (!f_is_blob(pack_flag)) 00920 { 00921 // 3.23 or 4.0 string 00922 if (!(charset= get_charset_by_csname(share->table_charset->csname, 00923 MY_CS_BINSORT, MYF(0)))) 00924 charset= &my_charset_bin; 00925 } 00926 else 00927 charset= &my_charset_bin; 00928 } 00929 else 00930 charset= share->table_charset; 00931 bzero((char*) &comment, sizeof(comment)); 00932 } 00933 00934 if (interval_nr && charset->mbminlen > 1) 00935 { 00936 /* Unescape UCS2 intervals from HEX notation */ 00937 TYPELIB *interval= share->intervals + interval_nr - 1; 00938 unhex_type2(interval); 00939 } 00940 00941 #ifndef TO_BE_DELETED_ON_PRODUCTION 00942 if (field_type == FIELD_TYPE_NEWDECIMAL && !share->mysql_version) 00943 { 00944 /* 00945 Fix pack length of old decimal values from 5.0.3 -> 5.0.4 00946 The difference is that in the old version we stored precision 00947 in the .frm table while we now store the display_length 00948 */ 00949 uint decimals= f_decimals(pack_flag); 00950 field_length= my_decimal_precision_to_length(field_length, 00951 decimals, 00952 f_is_dec(pack_flag) == 0); 00953 sql_print_error("Found incompatible DECIMAL field '%s' in %s; " 00954 "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", 00955 share->fieldnames.type_names[i], share->table_name.str, 00956 share->table_name.str); 00957 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, 00958 ER_CRASHED_ON_USAGE, 00959 "Found incompatible DECIMAL field '%s' in %s; " 00960 "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", 00961 share->fieldnames.type_names[i], <

