summaryrefslogtreecommitdiff
path: root/sql/table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/table.cc')
-rw-r--r--sql/table.cc278
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;
}
/*