diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 278 |
1 files changed, 205 insertions, 73 deletions
diff --git a/sql/table.cc b/sql/table.cc index 573fa11a4c4..eb3e0e8d1a7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -30,14 +30,34 @@ static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, static uint find_field(TABLE *form,uint start,uint length); -static byte* get_field_name(Field *buff,uint *length, +static byte* get_field_name(Field **buff,uint *length, my_bool not_used __attribute__((unused))) { - *length= (uint) strlen(buff->field_name); - return (byte*) buff->field_name; + *length= (uint) strlen((*buff)->field_name); + return (byte*) (*buff)->field_name; } - /* Open a .frm file */ +/* + Open a .frm file + + SYNOPSIS + openfrm() + + name path to table-file "db/name" + alias alias for table + db_stat open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..) + can be 0 (example in ha_example_table) + prgflag READ_ALL etc.. + ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc.. + outparam result table + + RETURN VALUES + 0 ok + 1 Error (see frm_error) + 2 Error (see frm_error) + 3 Wrong data in .frm file + 4 Error (see frm_error) +*/ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam) @@ -49,7 +69,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, interval_count,interval_parts,read_length,db_create_options; uint key_info_length, com_length; ulong pos; - char index_file[FN_REFLEN], *names, *keynames; + char index_file[FN_REFLEN], *names, *keynames, *comment_pos; uchar head[288],*disk_buff,new_field_pack_flag; my_string record; const char **int_array; @@ -81,7 +101,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (!outparam->real_name || !outparam->table_name) goto err_end; - if ((file=my_open(fn_format(index_file,name,"",reg_ext,4), + if ((file=my_open(fn_format(index_file,name,"",reg_ext,MY_UNPACK_FILENAME), O_RDONLY | O_SHARE, MYF(0))) < 0) @@ -106,6 +126,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, goto err_not_open; /* purecov: inspected */ *fn_ext(index_file)='\0'; // Remove .frm extension + outparam->frm_version= head[2]; outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3)); outparam->db_create_options=db_create_options=uint2korr(head+30); outparam->db_options_in_use=outparam->db_create_options; @@ -117,8 +138,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->raid_type= head[41]; outparam->raid_chunks= head[42]; outparam->raid_chunksize= uint4korr(head+43); + outparam->table_charset=get_charset((uint) head[38],MYF(0)); null_field_first=1; } + if (!outparam->table_charset) /* unknown charset in head[38] or pre-3.23 frm */ + outparam->table_charset=default_charset_info; outparam->db_record_offset=1; if (db_create_options & HA_OPTION_LONG_BLOB_PTR) outparam->blob_ptr_size=portable_sizeof_char_ptr; @@ -133,10 +157,23 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0))); if (read_string(file,(gptr*) &disk_buff,key_info_length)) goto err_not_open; /* purecov: inspected */ - outparam->keys=keys= disk_buff[0]; - outparam->keys_for_keyread= outparam->keys_in_use= set_bits(key_map, keys); + if (disk_buff[0] & 0x80) + { + outparam->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f); + outparam->key_parts= key_parts= uint2korr(disk_buff+2); + } + else + { + outparam->keys= keys= disk_buff[0]; + outparam->key_parts= key_parts= disk_buff[1]; + } + outparam->keys_for_keyread.init(0); + outparam->keys_in_use.init(keys); + outparam->read_only_keys.init(keys); + outparam->quick_keys.init(); + outparam->used_keys.init(); + outparam->keys_in_use_for_query.init(); - outparam->key_parts=key_parts=disk_buff[1]; n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO); if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root, n_length+uint2korr(disk_buff+4)))) @@ -214,7 +251,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, #ifdef HAVE_CRYPTED_FRM else if (*(head+26) == 2) { - extern SQL_CRYPT *get_crypt_for_frm(void); my_pthread_setspecific_ptr(THR_MALLOC,old_root); crypted=get_crypt_for_frm(); my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root); @@ -242,9 +278,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, record[outparam->reclength]=0; // For purify and ->c_ptr() outparam->rec_buff_length=rec_buff_length; if (my_pread(file,(byte*) record,(uint) outparam->reclength, - (ulong) (uint2korr(head+6)+uint2korr(head+14)), + (ulong) (uint2korr(head+6)+ + ((uint2korr(head+14) == 0xffff ? + uint4korr(head+47) : uint2korr(head+14)))), MYF(MY_NABP))) goto err_not_open; /* purecov: inspected */ + /* HACK: table->record[2] is used instead of table->default_values here */ for (i=0 ; i < records ; i++, record+=rec_buff_length) { outparam->record[i]=(byte*) record; @@ -254,10 +293,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (records == 2) { /* fix for select */ - outparam->record[2]=outparam->record[1]; + outparam->default_values=outparam->record[1]; if (db_stat & HA_READ_ONLY) outparam->record[1]=outparam->record[0]; /* purecov: inspected */ } + outparam->insert_values=0; /* for INSERT ... UPDATE */ VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0))); if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open; @@ -279,7 +319,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->comment=strdup_root(&outparam->mem_root, (char*) head+47); - DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length)); + DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length, com_length)); if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root, @@ -310,6 +350,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->intervals=0; // For better debugging memcpy((char*) names, strpos+(outparam->fields*field_pack_length), (uint) (n_length+int_length)); + comment_pos=names+(n_length+int_length); + memcpy(comment_pos, disk_buff+read_length-com_length, com_length); fix_type_pointers(&int_array,&outparam->fieldnames,1,&names); fix_type_pointers(&int_array,outparam->intervals,interval_count, @@ -337,14 +379,17 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH; if (use_hash) use_hash= !hash_init(&outparam->name_hash, + system_charset_info, outparam->fields,0,0, - (hash_get_key) get_field_name,0, - HASH_CASE_INSENSITIVE); + (hash_get_key) get_field_name,0,0); for (i=0 ; i < outparam->fields; i++, strpos+=field_pack_length, field_ptr++) { uint pack_flag, interval_nr, unireg_type, recpos, field_length; enum_field_types field_type; + CHARSET_INFO *charset=NULL; + Field::geometry_type geom_type= Field::GEOM_GEOMETRY; + LEX_STRING comment; if (new_frm_ver == 3) { @@ -354,36 +399,73 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, pack_flag= uint2korr(strpos+8); unireg_type= (uint) strpos[10]; interval_nr= (uint) strpos[12]; - field_type= (enum_field_types) (uint) strpos[13]; + + uint comment_length=uint2korr(strpos+15); + field_type=(enum_field_types) (uint) strpos[13]; + + // charset and geometry_type share the same byte in frm + if (field_type == FIELD_TYPE_GEOMETRY) + { +#ifdef HAVE_SPATIAL + geom_type= (Field::geometry_type) strpos[14]; + charset= &my_charset_bin; +#else + error= 4; // unsupported field type + goto err_not_open; +#endif + } + else + { + if (!strpos[14]) + charset= &my_charset_bin; + else if (!(charset=get_charset((uint) strpos[14], MYF(0)))) + charset= outparam->table_charset; + } + if (!comment_length) + { + comment.str= (char*) ""; + comment.length=0; + } + else + { + comment.str= (char*) comment_pos; + comment.length= comment_length; + comment_pos+= comment_length; + } } else { - /* old frm file */ field_length= (uint) strpos[3]; recpos= uint2korr(strpos+4), pack_flag= uint2korr(strpos+6); unireg_type= (uint) strpos[8]; interval_nr= (uint) strpos[10]; + + /* old frm file */ field_type= (enum_field_types) f_packtype(pack_flag); + charset=f_is_binary(pack_flag) ? &my_charset_bin : outparam->table_charset; + bzero((char*) &comment, sizeof(comment)); } - *field_ptr=reg_field= make_field(record+recpos, (uint32) field_length, null_pos,null_bit, pack_flag, field_type, + charset, + geom_type, (Field::utype) MTYP_TYPENR(unireg_type), (interval_nr ? outparam->intervals+interval_nr-1 : (TYPELIB*) 0), outparam->fieldnames.type_names[i], outparam); - if (!*field_ptr) // Field in 4.1 + if (!reg_field) // Not supported field type { error= 4; goto err_not_open; /* purecov: inspected */ } + reg_field->comment=comment; if (!(reg_field->flags & NOT_NULL_FLAG)) { if ((null_bit<<=1) == 256) @@ -397,15 +479,15 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (outparam->timestamp_field == reg_field) outparam->timestamp_field_offset=i; if (use_hash) - (void) hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail + (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail } *field_ptr=0; // End marker /* Fix key->name and key_part->field */ if (key_parts) { - uint primary_key=(uint) (find_type((char*) "PRIMARY",&outparam->keynames, - 3)-1); + uint primary_key=(uint) (find_type((char*) primary_key_name, + &outparam->keynames, 3) - 1); uint ha_option=outparam->file->table_flags(); keyinfo=outparam->key_info; key_part=keyinfo->key_part; @@ -413,20 +495,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, for (uint key=0 ; key < outparam->keys ; key++,keyinfo++) { uint usable_parts=0; - ulong index_flags; keyinfo->name=(char*) outparam->keynames.type_names[key]; /* Fix fulltext keys for old .frm files */ if (outparam->key_info[key].flags & HA_FULLTEXT) outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT; - /* This has to be done after the above fulltext correction */ - index_flags=outparam->file->index_flags(key); - if (!(index_flags & HA_KEY_READ_ONLY)) - { - outparam->read_only_keys|= ((key_map) 1 << key); - outparam->keys_for_keyread&= ~((key_map) 1 << key); - } - if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME)) { /* @@ -492,20 +565,18 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, field->key_length() == keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG); if (i == 0) - field->key_start|= ((key_map) 1 << key); - if ((index_flags & HA_KEY_READ_ONLY) && - field->key_length() == key_part->length && - field->type() != FIELD_TYPE_BLOB) + field->key_start.set_bit(key); + if (field->key_length() == key_part->length && + !(field->flags & BLOB_FLAG)) { - if (field->key_type() != HA_KEYTYPE_TEXT || - ((!(ha_option & HA_KEY_READ_WRONG_STR) || - field->flags & BINARY_FLAG) && - !(keyinfo->flags & HA_FULLTEXT))) - field->part_of_key|= ((key_map) 1 << key); - if ((field->key_type() != HA_KEYTYPE_TEXT || - !(keyinfo->flags & HA_FULLTEXT)) && - !(index_flags & HA_WRONG_ASCII_ORDER)) - field->part_of_sortkey|= ((key_map) 1 << key); + if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY) + { + outparam->read_only_keys.clear_bit(key); + outparam->keys_for_keyread.set_bit(key); + field->part_of_key.set_bit(key); + } + if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER) + field->part_of_sortkey.set_bit(key); } if (!(key_part->key_part_flag & HA_REVERSE_SORT) && usable_parts == i) @@ -524,7 +595,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (field->key_length() != key_part->length) { key_part->key_part_flag|= HA_PART_KEY_SEG; - if (field->type() != FIELD_TYPE_BLOB) + if (!(field->flags & BLOB_FLAG)) { // Create a new field field=key_part->field=field->new_field(&outparam->mem_root, outparam); @@ -547,8 +618,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, } keyinfo->usable_key_parts=usable_parts; // Filesort } - if (primary_key < MAX_KEY && - (outparam->keys_in_use & ((key_map) 1 << primary_key))) + if (primary_key < MAX_KEY && + (outparam->keys_in_use.is_set(primary_key))) { outparam->primary_key=primary_key; /* @@ -863,7 +934,8 @@ static void frm_error(int error, TABLE *form, const char *name, myf errortype) break; case 2: { - datext=form->file ? *form->file->bas_ext() : ""; + datext= form->file ? *form->file->bas_ext() : ""; + datext= datext==NullS ? "" : datext; err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ? ER_FILE_USED : ER_CANT_OPEN_FILE; my_error(err_no,errortype, @@ -991,13 +1063,26 @@ ulong next_io_size(register ulong pos) } /* next_io_size */ -void append_unescaped(String *res,const char *pos) +/* + Store an SQL quoted string. + + SYNOPSIS + append_unescaped() + res result String + pos string to be quoted + length it's length + + NOTE + This function works correctly with utf8 or single-byte charset strings. + May fail with some multibyte charsets though. +*/ + +void append_unescaped(String *res, const char *pos, uint length) { -#ifdef USE_MB - const char *end= pos + strlen(pos); -#endif + const char *end= pos+length; + res->append('\''); - for (; *pos ; ) + for (; pos != end ; pos++) { #if defined(USE_MB) && MYSQL_VERSION_ID < 40100 uint mblen; @@ -1037,6 +1122,7 @@ void append_unescaped(String *res,const char *pos) } pos++; } + res->append('\''); } /* Create a .frm file */ @@ -1050,7 +1136,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, char fill[IO_SIZE]; #if SIZEOF_OFF_T > 4 - /* Fix this in MySQL 4.0; The current limit is 4G rows (QQ) */ + /* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */ if (create_info->max_rows > ~(ulong) 0) create_info->max_rows= ~(ulong) 0; if (create_info->min_rows > ~(ulong) 0) @@ -1065,13 +1151,14 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) { bzero((char*) fileinfo,64); - fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header + fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3; // Header fileinfo[3]= (uchar) ha_checktype(create_info->db_type); fileinfo[4]=1; int2store(fileinfo+6,IO_SIZE); /* Next block starts here */ key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16; length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength)); int4store(fileinfo+10,length); + if (key_length > 0xffff) key_length=0xffff; int2store(fileinfo+14,key_length); int2store(fileinfo+16,reclength); int4store(fileinfo+18,create_info->max_rows); @@ -1081,6 +1168,8 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, int2store(fileinfo+30,create_info->table_options); fileinfo[32]=0; // No filename anymore int4store(fileinfo+34,create_info->avg_row_length); + fileinfo[38]= (create_info->default_table_charset ? + create_info->default_table_charset->number : 0); fileinfo[40]= (uchar) create_info->row_type; fileinfo[41]= (uchar) create_info->raid_type; fileinfo[42]= (uchar) create_info->raid_chunks; @@ -1111,6 +1200,8 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table) create_info->raid_type=table->raid_type; create_info->raid_chunks=table->raid_chunks; create_info->raid_chunksize=table->raid_chunksize; + create_info->default_table_charset=table->table_charset; + create_info->table_charset= 0; DBUG_VOID_RETURN; } @@ -1125,17 +1216,55 @@ rename_file_ext(const char * from,const char * to,const char * ext) /* - Alloc a value as a string and return it - If field is empty, return NULL + Allocate string field in MEM_ROOT and return it as String + + SYNOPSIS + get_field() + mem MEM_ROOT for allocating + field Field for retrieving of string + res result String + + RETURN VALUES + 1 string is empty + 0 all ok +*/ + +bool get_field(MEM_ROOT *mem, Field *field, String *res) +{ + char buff[MAX_FIELD_WIDTH], *to; + String str(buff,sizeof(buff),&my_charset_bin); + uint length; + + field->val_str(&str); + if (!(length= str.length())) + return 1; + to= strmake_root(mem, str.ptr(), length); + res->set(to, length, ((Field_str*)field)->charset()); + return 0; +} + + +/* + Allocate string field in MEM_ROOT and return it as NULL-terminated string + + SYNOPSIS + get_field() + mem MEM_ROOT for allocating + field Field for retrieving of string + + RETURN VALUES + NullS string is empty + # pointer to NULL-terminated string value of field */ -char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr) +char *get_field(MEM_ROOT *mem, Field *field) { - Field *field=table->field[fieldnr]; char buff[MAX_FIELD_WIDTH], *to; - String str(buff,sizeof(buff)); - field->val_str(&str,&str); - uint length=str.length(); + String str(buff,sizeof(buff),&my_charset_bin); + uint length; + + field->val_str(&str); + length= str.length(); if (!length || !(to= (char*) alloc_root(mem,length+1))) return NullS; memcpy(to,str.ptr(),(uint) length); @@ -1162,18 +1291,20 @@ char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr) bool check_db_name(char *name) { char *start=name; - bool last_char_is_space= FALSE; + /* Used to catch empty names and names with end space */ + bool last_char_is_space= TRUE; - if (lower_case_table_names) - casedn_str(name); + if (lower_case_table_names && name != any_db) + my_casedn_str(files_charset_info, name); while (*name) { #if defined(USE_MB) && defined(USE_MB_IDENT) last_char_is_space= my_isspace(default_charset_info, *name); - if (use_mb(default_charset_info)) + if (use_mb(system_charset_info)) { - int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN); + int len=my_ismbchar(system_charset_info, name, + name+system_charset_info->mbmaxlen); if (len) { name += len; @@ -1216,9 +1347,9 @@ bool check_table_name(const char *name, uint length) { #if defined(USE_MB) && defined(USE_MB_IDENT) last_char_is_space= my_isspace(default_charset_info, *name); - if (use_mb(default_charset_info)) + if (use_mb(system_charset_info)) { - int len=my_ismbchar(default_charset_info, name, end); + int len=my_ismbchar(system_charset_info, name, end); if (len) { name += len; @@ -1241,15 +1372,16 @@ bool check_table_name(const char *name, uint length) bool check_column_name(const char *name) { const char *start= name; - bool last_char_is_space= FALSE; + bool last_char_is_space= TRUE; while (*name) { #if defined(USE_MB) && defined(USE_MB_IDENT) last_char_is_space= my_isspace(default_charset_info, *name); - if (use_mb(default_charset_info)) + if (use_mb(system_charset_info)) { - int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN); + int len=my_ismbchar(system_charset_info, name, + name+system_charset_info->mbmaxlen); if (len) { name += len; @@ -1264,7 +1396,7 @@ bool check_column_name(const char *name) name++; } /* Error if empty or too long column name */ - return last_char_is_space || (name == start || (uint) (name - start) > NAME_LEN); + return last_char_is_space || (uint) (name - start) > NAME_LEN; } /* |