Commit e6b22e6f authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com

Manual merge

parent 6e06100b
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include <errno.h> #include <errno.h>
#include <m_ctype.h> #include <m_ctype.h>
#include "md5.h"
/* Functions defined in this file */ /* Functions defined in this file */
...@@ -61,8 +61,8 @@ static byte* get_field_name(Field **buff,uint *length, ...@@ -61,8 +61,8 @@ static byte* get_field_name(Field **buff,uint *length,
5 Error (see frm_error: charset unavailable) 5 Error (see frm_error: charset unavailable)
*/ */
int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
uint ha_open_flags, TABLE *outparam) uint prgflag, uint ha_open_flags, TABLE *outparam)
{ {
reg1 uint i; reg1 uint i;
reg2 uchar *strpos; reg2 uchar *strpos;
...@@ -76,76 +76,94 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -76,76 +76,94 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
my_string record; my_string record;
const char **int_array; const char **int_array;
bool use_hash, null_field_first; bool use_hash, null_field_first;
bool error_reported= FALSE;
File file; File file;
Field **field_ptr,*reg_field; Field **field_ptr,*reg_field;
KEY *keyinfo; KEY *keyinfo;
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
uchar *null_pos; uchar *null_pos;
uint null_bit, new_frm_ver, field_pack_length; uint null_bit_pos, new_frm_ver, field_pack_length;
SQL_CRYPT *crypted=0; SQL_CRYPT *crypted=0;
MEM_ROOT **root_ptr, *old_root; MEM_ROOT **root_ptr, *old_root;
TABLE_SHARE *share;
DBUG_ENTER("openfrm"); DBUG_ENTER("openfrm");
DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam)); DBUG_PRINT("enter",("name: '%s' form: 0x%lx",name,outparam));
bzero((char*) outparam,sizeof(*outparam));
outparam->blob_ptr_size=sizeof(char*);
disk_buff=NULL; record= NULL; keynames=NullS;
outparam->db_stat = db_stat;
error=1;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); error= 1;
disk_buff= NULL;
root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
old_root= *root_ptr; old_root= *root_ptr;
*root_ptr= &outparam->mem_root;
outparam->real_name=strdup_root(&outparam->mem_root, bzero((char*) outparam,sizeof(*outparam));
name+dirname_length(name)); outparam->in_use= thd;
outparam->table_name=my_strdup(alias,MYF(MY_WME)); outparam->s= share= &outparam->share_not_to_be_used;
if (!outparam->real_name || !outparam->table_name)
goto err_end;
*fn_ext(outparam->real_name)='\0'; // Remove extension
if ((file=my_open(fn_format(index_file,name,"",reg_ext,MY_UNPACK_FILENAME), if ((file=my_open(fn_format(index_file, name, "", reg_ext,
MY_UNPACK_FILENAME),
O_RDONLY | O_SHARE, O_RDONLY | O_SHARE,
MYF(0))) MYF(0)))
< 0) < 0)
goto err;
error= 4;
if (my_read(file,(byte*) head,64,MYF(MY_NABP)))
goto err;
if (memcmp(head, "TYPE=", 5) == 0)
{ {
goto err_end; /* purecov: inspected */ // new .frm
my_close(file,MYF(MY_WME));
if (db_stat & NO_ERR_ON_NEW_FRM)
DBUG_RETURN(5);
file= -1;
// caller can't process new .frm
goto err;
} }
error=4;
if (!(outparam->path= strdup_root(&outparam->mem_root,name)))
goto err_not_open;
*fn_ext(outparam->path)='\0'; // Remove extension
if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open; share->blob_ptr_size= sizeof(char*);
outparam->db_stat= db_stat;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
*root_ptr= &outparam->mem_root;
share->table_name= strdup_root(&outparam->mem_root,
name+dirname_length(name));
share->path= strdup_root(&outparam->mem_root, name);
outparam->alias= my_strdup(alias, MYF(MY_WME));
if (!share->table_name || !share->path || !outparam->alias)
goto err;
*fn_ext(share->table_name)='\0'; // Remove extension
*fn_ext(share->path)='\0'; // Remove extension
if (head[0] != (uchar) 254 || head[1] != 1 || if (head[0] != (uchar) 254 || head[1] != 1 ||
(head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3)) (head[2] != FRM_VER && head[2] != FRM_VER+1 &&
goto err_not_open; /* purecov: inspected */ ! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4)))
goto err; /* purecov: inspected */
new_field_pack_flag=head[27]; new_field_pack_flag=head[27];
new_frm_ver= (head[2] - FRM_VER); new_frm_ver= (head[2] - FRM_VER);
field_pack_length= new_frm_ver < 2 ? 11 : 17; field_pack_length= new_frm_ver < 2 ? 11 : 17;
error=3; error=3;
if (!(pos=get_form_pos(file,head,(TYPELIB*) 0))) if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
*fn_ext(index_file)='\0'; // Remove .frm extension *fn_ext(index_file)='\0'; // Remove .frm extension
outparam->frm_version= head[2]; share->frm_version= head[2];
outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3)); share->db_type= ha_checktype((enum db_type) (uint) *(head+3));
outparam->db_create_options=db_create_options=uint2korr(head+30); share->db_create_options= db_create_options=uint2korr(head+30);
outparam->db_options_in_use=outparam->db_create_options; share->db_options_in_use= share->db_create_options;
null_field_first=0; null_field_first= 0;
if (!head[32]) // New frm file in 3.23 if (!head[32]) // New frm file in 3.23
{ {
outparam->avg_row_length=uint4korr(head+34); share->avg_row_length= uint4korr(head+34);
outparam->row_type=(row_type) head[40]; share-> row_type= (row_type) head[40];
outparam->raid_type= head[41]; share->raid_type= head[41];
outparam->raid_chunks= head[42]; share->raid_chunks= head[42];
outparam->raid_chunksize= uint4korr(head+43); share->raid_chunksize= uint4korr(head+43);
outparam->table_charset=get_charset((uint) head[38],MYF(0)); share->table_charset= get_charset((uint) head[38],MYF(0));
null_field_first=1; null_field_first= 1;
} }
if (!outparam->table_charset) if (!share->table_charset)
{ {
/* unknown charset in head[38] or pre-3.23 frm */ /* unknown charset in head[38] or pre-3.23 frm */
if (use_mb(default_charset_info)) if (use_mb(default_charset_info))
...@@ -156,35 +174,34 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -156,35 +174,34 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
"so character column sizes may have changed", "so character column sizes may have changed",
name); name);
} }
outparam->table_charset=default_charset_info; share->table_charset= default_charset_info;
} }
outparam->db_record_offset=1; share->db_record_offset= 1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR) if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
outparam->blob_ptr_size=portable_sizeof_char_ptr; share->blob_ptr_size= portable_sizeof_char_ptr;
/* Set temporaryly a good value for db_low_byte_first */ /* Set temporarily a good value for db_low_byte_first */
outparam->db_low_byte_first=test(outparam->db_type != DB_TYPE_ISAM); share->db_low_byte_first= test(share->db_type != DB_TYPE_ISAM);
error=4; error=4;
outparam->max_rows=uint4korr(head+18); share->max_rows= uint4korr(head+18);
outparam->min_rows=uint4korr(head+22); share->min_rows= uint4korr(head+22);
/* Read keyinformation */ /* Read keyinformation */
key_info_length= (uint) uint2korr(head+28); key_info_length= (uint) uint2korr(head+28);
VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0))); VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
if (read_string(file,(gptr*) &disk_buff,key_info_length)) if (read_string(file,(gptr*) &disk_buff,key_info_length))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
if (disk_buff[0] & 0x80) if (disk_buff[0] & 0x80)
{ {
outparam->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f); share->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
outparam->key_parts= key_parts= uint2korr(disk_buff+2); share->key_parts= key_parts= uint2korr(disk_buff+2);
} }
else else
{ {
outparam->keys= keys= disk_buff[0]; share->keys= keys= disk_buff[0];
outparam->key_parts= key_parts= disk_buff[1]; share->key_parts= key_parts= disk_buff[1];
} }
outparam->keys_for_keyread.init(0); share->keys_for_keyread.init(0);
outparam->keys_in_use.init(keys); share->keys_in_use.init(keys);
outparam->read_only_keys.init(keys);
outparam->quick_keys.init(); outparam->quick_keys.init();
outparam->used_keys.init(); outparam->used_keys.init();
outparam->keys_in_use_for_query.init(); outparam->keys_in_use_for_query.init();
...@@ -192,7 +209,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -192,7 +209,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO); n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root, if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
n_length+uint2korr(disk_buff+4)))) n_length+uint2korr(disk_buff+4))))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
bzero((char*) keyinfo,n_length); bzero((char*) keyinfo,n_length);
outparam->key_info=keyinfo; outparam->key_info=keyinfo;
key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys); key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
...@@ -201,11 +218,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -201,11 +218,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
ulong *rec_per_key; ulong *rec_per_key;
if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root, if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root,
sizeof(ulong*)*key_parts))) sizeof(ulong*)*key_parts)))
goto err_not_open; goto err;
for (i=0 ; i < keys ; i++, keyinfo++) for (i=0 ; i < keys ; i++, keyinfo++)
{ {
if (new_frm_ver == 3) keyinfo->table= outparam;
if (new_frm_ver >= 3)
{ {
keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME; keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME;
keyinfo->key_length= (uint) uint2korr(strpos+2); keyinfo->key_length= (uint) uint2korr(strpos+2);
...@@ -254,9 +272,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -254,9 +272,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keynames=(char*) key_part; keynames=(char*) key_part;
strpos+= (strmov(keynames, (char *) strpos) - keynames)+1; strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
outparam->reclength = uint2korr((head+16)); share->reclength = uint2korr((head+16));
if (*(head+26) == 1) if (*(head+26) == 1)
outparam->system=1; /* one-record-database */ share->system= 1; /* one-record-database */
#ifdef HAVE_CRYPTED_FRM #ifdef HAVE_CRYPTED_FRM
else if (*(head+26) == 2) else if (*(head+26) == 2)
{ {
...@@ -268,84 +286,97 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -268,84 +286,97 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
#endif #endif
/* Allocate handler */ /* Allocate handler */
if (!(outparam->file= get_new_handler(outparam,outparam->db_type))) if (!(outparam->file= get_new_handler(outparam, share->db_type)))
goto err_not_open; goto err;
error=4; error=4;
outparam->reginfo.lock_type= TL_UNLOCK; outparam->reginfo.lock_type= TL_UNLOCK;
outparam->current_lock=F_UNLCK; outparam->current_lock=F_UNLCK;
if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2; if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
else records=1; records=2;
if (prgflag & (READ_ALL+EXTRA_RECORD)) records++; else
records=1;
if (prgflag & (READ_ALL+EXTRA_RECORD))
records++;
/* QQ: TODO, remove the +1 from below */ /* QQ: TODO, remove the +1 from below */
rec_buff_length=ALIGN_SIZE(outparam->reclength+1+ rec_buff_length= ALIGN_SIZE(share->reclength + 1 +
outparam->file->extra_rec_buf_length()); outparam->file->extra_rec_buf_length());
if (!(outparam->record[0]= (byte*) share->rec_buff_length= rec_buff_length;
(record = (char *) alloc_root(&outparam->mem_root, if (!(record= (char *) alloc_root(&outparam->mem_root,
rec_buff_length * records)))) rec_buff_length * records)))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
record[outparam->reclength]=0; // For purify and ->c_ptr() share->default_values= (byte *) record;
outparam->rec_buff_length=rec_buff_length; if (my_pread(file,(byte*) record, (uint) share->reclength,
if (my_pread(file,(byte*) record,(uint) outparam->reclength,
(ulong) (uint2korr(head+6)+ (ulong) (uint2korr(head+6)+
((uint2korr(head+14) == 0xffff ? ((uint2korr(head+14) == 0xffff ?
uint4korr(head+47) : uint2korr(head+14)))), uint4korr(head+47) : uint2korr(head+14)))),
MYF(MY_NABP))) MYF(MY_NABP)))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
/* HACK: table->record[2] is used instead of table->default_values here */
for (i=0 ; i < records ; i++, record+=rec_buff_length) if (records == 1)
{ {
outparam->record[i]=(byte*) record; /* We are probably in hard repair, and the buffers should not be used */
if (i) outparam->record[0]= outparam->record[1]= share->default_values;
memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
} }
else
if (records == 2) {
{ /* fix for select */ outparam->record[0]= (byte *) record+ rec_buff_length;
outparam->default_values=outparam->record[1]; if (records > 2)
if (db_stat & HA_READ_ONLY) outparam->record[1]= (byte *) record+ rec_buff_length*2;
outparam->record[1]=outparam->record[0]; /* purecov: inspected */ else
outparam->record[1]= outparam->record[0]; // Safety
} }
outparam->insert_values=0; /* for INSERT ... UPDATE */
#ifdef HAVE_purify
/*
We need this because when we read var-length rows, we are not updating
bytes after end of varchar
*/
if (records > 1)
{
memcpy(outparam->record[0], share->default_values, rec_buff_length);
if (records > 2)
memcpy(outparam->record[1], share->default_values, rec_buff_length);
}
#endif
VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0))); VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open; if (my_read(file,(byte*) head,288,MYF(MY_NABP)))
goto err;
#ifdef HAVE_CRYPTED_FRM #ifdef HAVE_CRYPTED_FRM
if (crypted) if (crypted)
{ {
crypted->decode((char*) head+256,288-256); crypted->decode((char*) head+256,288-256);
if (sint2korr(head+284) != 0) // Should be 0 if (sint2korr(head+284) != 0) // Should be 0
goto err_not_open; // Wrong password goto err; // Wrong password
} }
#endif #endif
outparam->fields= uint2korr(head+258); share->fields= uint2korr(head+258);
pos=uint2korr(head+260); /* Length of all screens */ pos= uint2korr(head+260); /* Length of all screens */
n_length=uint2korr(head+268); n_length= uint2korr(head+268);
interval_count=uint2korr(head+270); interval_count= uint2korr(head+270);
interval_parts=uint2korr(head+272); interval_parts= uint2korr(head+272);
int_length=uint2korr(head+274); int_length= uint2korr(head+274);
outparam->null_fields=uint2korr(head+282); share->null_fields= uint2korr(head+282);
com_length=uint2korr(head+284); com_length= uint2korr(head+284);
outparam->comment=strdup_root(&outparam->mem_root, share->comment= strdup_root(&outparam->mem_root, (char*) head+47);
(char*) head+47);
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)); 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));
if (!(field_ptr = (Field **) if (!(field_ptr = (Field **)
alloc_root(&outparam->mem_root, alloc_root(&outparam->mem_root,
(uint) ((outparam->fields+1)*sizeof(Field*)+ (uint) ((share->fields+1)*sizeof(Field*)+
interval_count*sizeof(TYPELIB)+ interval_count*sizeof(TYPELIB)+
(outparam->fields+interval_parts+ (share->fields+interval_parts+
keys+3)*sizeof(my_string)+ keys+3)*sizeof(my_string)+
(n_length+int_length+com_length))))) (n_length+int_length+com_length)))))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
outparam->field=field_ptr; outparam->field=field_ptr;
read_length=(uint) (outparam->fields * field_pack_length + read_length=(uint) (share->fields * field_pack_length +
pos+ (uint) (n_length+int_length+com_length)); pos+ (uint) (n_length+int_length+com_length));
if (read_string(file,(gptr*) &disk_buff,read_length)) if (read_string(file,(gptr*) &disk_buff,read_length))
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
#ifdef HAVE_CRYPTED_FRM #ifdef HAVE_CRYPTED_FRM
if (crypted) if (crypted)
{ {
...@@ -356,31 +387,31 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -356,31 +387,31 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
#endif #endif
strpos= disk_buff+pos; strpos= disk_buff+pos;
outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1); share->intervals= (TYPELIB*) (field_ptr+share->fields+1);
int_array= (const char **) (outparam->intervals+interval_count); int_array= (const char **) (share->intervals+interval_count);
names= (char*) (int_array+outparam->fields+interval_parts+keys+3); names= (char*) (int_array+share->fields+interval_parts+keys+3);
if (!interval_count) if (!interval_count)
outparam->intervals=0; // For better debugging share->intervals= 0; // For better debugging
memcpy((char*) names, strpos+(outparam->fields*field_pack_length), memcpy((char*) names, strpos+(share->fields*field_pack_length),
(uint) (n_length+int_length)); (uint) (n_length+int_length));
comment_pos=names+(n_length+int_length); comment_pos= names+(n_length+int_length);
memcpy(comment_pos, disk_buff+read_length-com_length, com_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, &share->fieldnames, 1, &names);
fix_type_pointers(&int_array,outparam->intervals,interval_count, fix_type_pointers(&int_array, share->intervals, interval_count,
&names); &names);
{ {
/* Set ENUM and SET lengths */ /* Set ENUM and SET lengths */
TYPELIB *interval; TYPELIB *interval;
for (interval= outparam->intervals; for (interval= share->intervals;
interval < outparam->intervals + interval_count; interval < share->intervals + interval_count;
interval++) interval++)
{ {
uint count= (uint) (interval->count + 1) * sizeof(uint); uint count= (uint) (interval->count + 1) * sizeof(uint);
if (!(interval->type_lengths= (uint *) alloc_root(&outparam->mem_root, if (!(interval->type_lengths= (uint *) alloc_root(&outparam->mem_root,
count))) count)))
goto err_not_open; goto err;
for (count= 0; count < interval->count; count++) for (count= 0; count < interval->count; count++)
interval->type_lengths[count]= strlen(interval->type_names[count]); interval->type_lengths[count]= strlen(interval->type_names[count]);
interval->type_lengths[count]= 0; interval->type_lengths[count]= 0;
...@@ -388,33 +419,33 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -388,33 +419,33 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
} }
if (keynames) if (keynames)
fix_type_pointers(&int_array,&outparam->keynames,1,&keynames); fix_type_pointers(&int_array, &share->keynames, 1, &keynames);
VOID(my_close(file,MYF(MY_WME))); VOID(my_close(file,MYF(MY_WME)));
file= -1; file= -1;
record=(char*) outparam->record[0]-1; /* Fieldstart = 1 */ record= (char*) outparam->record[0]-1; /* Fieldstart = 1 */
if (null_field_first) if (null_field_first)
{ {
outparam->null_flags=null_pos=(uchar*) record+1; outparam->null_flags=null_pos=(uchar*) record+1;
null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2; null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;
outparam->null_bytes=(outparam->null_fields+null_bit+6)/8; share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;
} }
else else
{ {
outparam->null_bytes=(outparam->null_fields+7)/8; share->null_bytes= (share->null_fields+7)/8;
outparam->null_flags=null_pos= outparam->null_flags= null_pos=
(uchar*) (record+1+outparam->reclength-outparam->null_bytes); (uchar*) (record+1+share->reclength-share->null_bytes);
null_bit=1; null_bit_pos= 0;
} }
use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH; use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash) if (use_hash)
use_hash= !hash_init(&outparam->name_hash, use_hash= !hash_init(&share->name_hash,
system_charset_info, system_charset_info,
outparam->fields,0,0, share->fields,0,0,
(hash_get_key) get_field_name,0,0); (hash_get_key) get_field_name,0,0);
for (i=0 ; i < outparam->fields; i++, strpos+=field_pack_length, field_ptr++) for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
{ {
uint pack_flag, interval_nr, unireg_type, recpos, field_length; uint pack_flag, interval_nr, unireg_type, recpos, field_length;
enum_field_types field_type; enum_field_types field_type;
...@@ -422,7 +453,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -422,7 +453,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
Field::geometry_type geom_type= Field::GEOM_GEOMETRY; Field::geometry_type geom_type= Field::GEOM_GEOMETRY;
LEX_STRING comment; LEX_STRING comment;
if (new_frm_ver == 3) if (new_frm_ver >= 3)
{ {
/* new frm file in 4.1 */ /* new frm file in 4.1 */
field_length= uint2korr(strpos+3); field_length= uint2korr(strpos+3);
...@@ -430,11 +461,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -430,11 +461,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
pack_flag= uint2korr(strpos+8); pack_flag= uint2korr(strpos+8);
unireg_type= (uint) strpos[10]; unireg_type= (uint) strpos[10];
interval_nr= (uint) strpos[12]; interval_nr= (uint) strpos[12];
uint comment_length=uint2korr(strpos+15); uint comment_length=uint2korr(strpos+15);
field_type=(enum_field_types) (uint) strpos[13]; field_type=(enum_field_types) (uint) strpos[13];
// charset and geometry_type share the same byte in frm /* charset and geometry_type share the same byte in frm */
if (field_type == FIELD_TYPE_GEOMETRY) if (field_type == FIELD_TYPE_GEOMETRY)
{ {
#ifdef HAVE_SPATIAL #ifdef HAVE_SPATIAL
...@@ -442,7 +472,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -442,7 +472,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
charset= &my_charset_bin; charset= &my_charset_bin;
#else #else
error= 4; // unsupported field type error= 4; // unsupported field type
goto err_not_open; goto err;
#endif #endif
} }
else else
...@@ -453,7 +483,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -453,7 +483,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{ {
error= 5; // Unknown or unavailable charset error= 5; // Unknown or unavailable charset
errarg= (int) strpos[14]; errarg= (int) strpos[14];
goto err_not_open; goto err;
} }
} }
if (!comment_length) if (!comment_length)
...@@ -473,6 +503,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -473,6 +503,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
field_length= (uint) strpos[3]; field_length= (uint) strpos[3];
recpos= uint2korr(strpos+4), recpos= uint2korr(strpos+4),
pack_flag= uint2korr(strpos+6); pack_flag= uint2korr(strpos+6);
pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files
unireg_type= (uint) strpos[8]; unireg_type= (uint) strpos[8];
interval_nr= (uint) strpos[10]; interval_nr= (uint) strpos[10];
...@@ -489,7 +520,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -489,7 +520,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (!f_is_blob(pack_flag)) if (!f_is_blob(pack_flag))
{ {
// 3.23 or 4.0 string // 3.23 or 4.0 string
if (!(charset= get_charset_by_csname(outparam->table_charset->csname, if (!(charset= get_charset_by_csname(share->table_charset->csname,
MY_CS_BINSORT, MYF(0)))) MY_CS_BINSORT, MYF(0))))
charset= &my_charset_bin; charset= &my_charset_bin;
} }
...@@ -497,51 +528,58 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -497,51 +528,58 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
charset= &my_charset_bin; charset= &my_charset_bin;
} }
else else
charset= outparam->table_charset; charset= share->table_charset;
bzero((char*) &comment, sizeof(comment)); bzero((char*) &comment, sizeof(comment));
} }
if (interval_nr && charset->mbminlen > 1) if (interval_nr && charset->mbminlen > 1)
{ {
/* Unescape UCS2 intervals from HEX notation */ /* Unescape UCS2 intervals from HEX notation */
TYPELIB *interval= outparam->intervals + interval_nr - 1; TYPELIB *interval= share->intervals + interval_nr - 1;
unhex_type2(interval); unhex_type2(interval);
} }
*field_ptr=reg_field= *field_ptr=reg_field=
make_field(record+recpos, make_field(record+recpos,
(uint32) field_length, (uint32) field_length,
null_pos,null_bit, null_pos, null_bit_pos,
pack_flag, pack_flag,
field_type, field_type,
charset, charset,
geom_type, geom_type,
(Field::utype) MTYP_TYPENR(unireg_type), (Field::utype) MTYP_TYPENR(unireg_type),
(interval_nr ? (interval_nr ?
outparam->intervals+interval_nr-1 : share->intervals+interval_nr-1 :
(TYPELIB*) 0), (TYPELIB*) 0),
outparam->fieldnames.type_names[i], share->fieldnames.type_names[i],
outparam); outparam);
if (!reg_field) // Not supported field type if (!reg_field) // Not supported field type
{ {
error= 4; error= 4;
goto err_not_open; /* purecov: inspected */ goto err; /* purecov: inspected */
} }
reg_field->comment=comment; reg_field->comment=comment;
if (!(reg_field->flags & NOT_NULL_FLAG)) if (field_type == FIELD_TYPE_BIT)
{ {
if ((null_bit<<=1) == 256) if ((null_bit_pos+= field_length & 7) > 7)
{ {
null_pos++; null_pos++;
null_bit=1; null_bit_pos-= 8;
} }
} }
if (!(reg_field->flags & NOT_NULL_FLAG))
{
if (!(null_bit_pos= (null_bit_pos + 1) & 7))
null_pos++;
}
if (f_no_default(pack_flag))
reg_field->flags|= NO_DEFAULT_VALUE_FLAG;
if (reg_field->unireg_check == Field::NEXT_NUMBER) if (reg_field->unireg_check == Field::NEXT_NUMBER)
outparam->found_next_number_field= reg_field; outparam->found_next_number_field= reg_field;
if (outparam->timestamp_field == reg_field) if (outparam->timestamp_field == reg_field)
outparam->timestamp_field_offset=i; share->timestamp_field_offset= i;
if (use_hash) if (use_hash)
(void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail (void) my_hash_insert(&share->name_hash,(byte*) field_ptr); // never fail
} }
*field_ptr=0; // End marker *field_ptr=0; // End marker
...@@ -549,15 +587,15 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -549,15 +587,15 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (key_parts) if (key_parts)
{ {
uint primary_key=(uint) (find_type((char*) primary_key_name, uint primary_key=(uint) (find_type((char*) primary_key_name,
&outparam->keynames, 3) - 1); &share->keynames, 3) - 1);
uint ha_option=outparam->file->table_flags(); uint ha_option=outparam->file->table_flags();
keyinfo=outparam->key_info; keyinfo=outparam->key_info;
key_part=keyinfo->key_part; key_part=keyinfo->key_part;
for (uint key=0 ; key < outparam->keys ; key++,keyinfo++) for (uint key=0 ; key < share->keys ; key++,keyinfo++)
{ {
uint usable_parts=0; uint usable_parts=0;
keyinfo->name=(char*) outparam->keynames.type_names[key]; keyinfo->name=(char*) share->keynames.type_names[key];
/* Fix fulltext keys for old .frm files */ /* Fix fulltext keys for old .frm files */
if (outparam->key_info[key].flags & HA_FULLTEXT) if (outparam->key_info[key].flags & HA_FULLTEXT)
outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT; outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT;
...@@ -590,8 +628,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -590,8 +628,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(uint) key_part->offset, (uint) key_part->offset,
(uint) key_part->length); (uint) key_part->length);
#ifdef EXTRA_DEBUG #ifdef EXTRA_DEBUG
if (key_part->fieldnr > outparam->fields) if (key_part->fieldnr > share->fields)
goto err_not_open; // sanity check goto err; // sanity check
#endif #endif
if (key_part->fieldnr) if (key_part->fieldnr)
{ // Should always be true ! { // Should always be true !
...@@ -607,10 +645,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -607,10 +645,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->key_length+= HA_KEY_NULL_LENGTH; keyinfo->key_length+= HA_KEY_NULL_LENGTH;
} }
if (field->type() == FIELD_TYPE_BLOB || if (field->type() == FIELD_TYPE_BLOB ||
field->real_type() == FIELD_TYPE_VAR_STRING) field->real_type() == MYSQL_TYPE_VARCHAR)
{ {
if (field->type() == FIELD_TYPE_BLOB) if (field->type() == FIELD_TYPE_BLOB)
key_part->key_part_flag|= HA_BLOB_PART; key_part->key_part_flag|= HA_BLOB_PART;
else
key_part->key_part_flag|= HA_VAR_LENGTH_PART;
keyinfo->extra_length+=HA_KEY_BLOB_LENGTH; keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
key_part->store_length+=HA_KEY_BLOB_LENGTH; key_part->store_length+=HA_KEY_BLOB_LENGTH;
keyinfo->key_length+= HA_KEY_BLOB_LENGTH; keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
...@@ -621,6 +661,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -621,6 +661,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (!(field->flags & BINARY_FLAG)) if (!(field->flags & BINARY_FLAG))
keyinfo->flags|= HA_END_SPACE_KEY; keyinfo->flags|= HA_END_SPACE_KEY;
} }
set_if_bigger(share->max_key_length, keyinfo->key_length);
if (field->type() == MYSQL_TYPE_BIT)
key_part->key_part_flag|= HA_BIT_PART;
if (i == 0 && key != primary_key) if (i == 0 && key != primary_key)
field->flags |= field->flags |=
((keyinfo->flags & HA_NOSAME) && ((keyinfo->flags & HA_NOSAME) &&
...@@ -633,8 +677,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -633,8 +677,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{ {
if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY) if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
{ {
outparam->read_only_keys.clear_bit(key); share->keys_for_keyread.set_bit(key);
outparam->keys_for_keyread.set_bit(key);
field->part_of_key.set_bit(key); field->part_of_key.set_bit(key);
} }
if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER) if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER)
...@@ -652,7 +695,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -652,7 +695,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
the primary key, then we can use any key to find this column the primary key, then we can use any key to find this column
*/ */
if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX) if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
field->part_of_key= outparam->keys_in_use; field->part_of_key= share->keys_in_use;
} }
if (field->key_length() != key_part->length) if (field->key_length() != key_part->length)
{ {
...@@ -680,16 +723,16 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -680,16 +723,16 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
} }
keyinfo->usable_key_parts=usable_parts; // Filesort keyinfo->usable_key_parts=usable_parts; // Filesort
set_if_bigger(outparam->max_key_length,keyinfo->key_length+ set_if_bigger(share->max_key_length,keyinfo->key_length+
keyinfo->key_parts); keyinfo->key_parts);
outparam->total_key_length+= keyinfo->key_length; share->total_key_length+= keyinfo->key_length;
if (keyinfo->flags & HA_NOSAME) if (keyinfo->flags & HA_NOSAME)
set_if_bigger(outparam->max_unique_length,keyinfo->key_length); set_if_bigger(share->max_unique_length, keyinfo->key_length);
} }
if (primary_key < MAX_KEY && if (primary_key < MAX_KEY &&
(outparam->keys_in_use.is_set(primary_key))) (share->keys_in_use.is_set(primary_key)))
{ {
outparam->primary_key=primary_key; share->primary_key= primary_key;
/* /*
If we are using an integer as the primary key then allow the user to If we are using an integer as the primary key then allow the user to
refer to it as '_rowid' refer to it as '_rowid'
...@@ -702,27 +745,25 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -702,27 +745,25 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
} }
} }
else else
outparam->primary_key = MAX_KEY; // we do not have a primary key share->primary_key = MAX_KEY; // we do not have a primary key
} }
else else
outparam->primary_key= MAX_KEY; share->primary_key= MAX_KEY;
x_free((gptr) disk_buff); x_free((gptr) disk_buff);
disk_buff=0; disk_buff=0;
if (new_field_pack_flag <= 1) if (new_field_pack_flag <= 1)
{ /* Old file format with default null */ {
uint null_length=(outparam->null_fields+7)/8; /* Old file format with default as not null */
bfill(outparam->null_flags,null_length,255); uint null_length= (share->null_fields+7)/8;
bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255); bfill(share->default_values + (outparam->null_flags - (uchar*) record),
if (records > 2) null_length, 255);
bfill(outparam->null_flags+outparam->rec_buff_length*2,null_length,255);
} }
if ((reg_field=outparam->found_next_number_field)) if ((reg_field=outparam->found_next_number_field))
{ {
if ((int) (outparam->next_number_index= (uint) if ((int) (share->next_number_index= (uint)
find_ref_key(outparam,reg_field, find_ref_key(outparam,reg_field,
&outparam->next_number_key_offset)) < 0) &share->next_number_key_offset)) < 0)
{ {
reg_field->unireg_check=Field::NONE; /* purecov: inspected */ reg_field->unireg_check=Field::NONE; /* purecov: inspected */
outparam->found_next_number_field=0; outparam->found_next_number_field=0;
...@@ -731,84 +772,85 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -731,84 +772,85 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
reg_field->flags|=AUTO_INCREMENT_FLAG; reg_field->flags|=AUTO_INCREMENT_FLAG;
} }
if (outparam->blob_fields) if (share->blob_fields)
{ {
Field **ptr; Field **ptr;
Field_blob **save; uint i, *save;
if (!(outparam->blob_field=save= /* Store offsets to blob fields to find them fast */
(Field_blob**) alloc_root(&outparam->mem_root, if (!(share->blob_field= save=
(uint) (outparam->blob_fields+1)* (uint*) alloc_root(&outparam->mem_root,
sizeof(Field_blob*)))) (uint) (share->blob_fields* sizeof(uint)))))
goto err_not_open; goto err;
for (ptr=outparam->field ; *ptr ; ptr++) for (i=0, ptr= outparam->field ; *ptr ; ptr++, i++)
{ {
if ((*ptr)->flags & BLOB_FLAG) if ((*ptr)->flags & BLOB_FLAG)
(*save++)= (Field_blob*) *ptr; (*save++)= i;
} }
*save=0; // End marker
} }
else
outparam->blob_field=
(Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
/* The table struct is now initialzed; Open the table */ /* The table struct is now initialized; Open the table */
error=2; error=2;
if (db_stat) if (db_stat)
{ {
int err; int ha_err;
unpack_filename(index_file,index_file); unpack_filename(index_file,index_file);
if ((err=(outparam->file-> if ((ha_err= (outparam->file->
ha_open(index_file, ha_open(index_file,
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR), (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
(db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE : (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
((db_stat & HA_WAIT_IF_LOCKED) || ((db_stat & HA_WAIT_IF_LOCKED) ||
(specialflag & SPECIAL_WAIT_IF_LOCKED)) ? (specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
HA_OPEN_WAIT_IF_LOCKED : HA_OPEN_WAIT_IF_LOCKED :
(db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ? (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
HA_OPEN_ABORT_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED :
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags)))) HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{ {
/* Set a flag if the table is crashed and it can be auto. repaired */ /* Set a flag if the table is crashed and it can be auto. repaired */
outparam->crashed=((err == HA_ERR_CRASHED_ON_USAGE) && share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) &&
outparam->file->auto_repair() && outparam->file->auto_repair() &&
!(ha_open_flags & HA_OPEN_FOR_REPAIR)); !(ha_open_flags & HA_OPEN_FOR_REPAIR));
if (err==HA_ERR_NO_SUCH_TABLE) if (ha_err == HA_ERR_NO_SUCH_TABLE)
{ {
/* The table did not exists in storage engine, use same error message /* The table did not exists in storage engine, use same error message
as if the .frm file didn't exist */ as if the .frm file didn't exist */
error= 1; error= 1;
my_errno= ENOENT; my_errno= ENOENT;
} }
goto err_not_open; /* purecov: inspected */ else
{
outparam->file->print_error(ha_err, MYF(0));
error_reported= TRUE;
}
goto err; /* purecov: inspected */
} }
} }
outparam->db_low_byte_first=outparam->file->low_byte_first(); share->db_low_byte_first= outparam->file->low_byte_first();
*root_ptr= old_root; *root_ptr= old_root;
opened_tables++; thd->status_var.opened_tables++;
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (use_hash) if (use_hash)
(void) hash_check(&outparam->name_hash); (void) hash_check(&share->name_hash);
#endif #endif
DBUG_RETURN (0); DBUG_RETURN (0);
err_not_open: err:
x_free((gptr) disk_buff); x_free((gptr) disk_buff);
if (file > 0) if (file > 0)
VOID(my_close(file,MYF(MY_WME))); VOID(my_close(file,MYF(MY_WME)));
err_end: /* Here when no file */
delete crypted; delete crypted;
*root_ptr= old_root; *root_ptr= old_root;
frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg); if (! error_reported)
frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG, errarg);
delete outparam->file; delete outparam->file;
outparam->file=0; // For easyer errorchecking outparam->file=0; // For easier errorchecking
outparam->db_stat=0; outparam->db_stat=0;
hash_free(&outparam->name_hash); hash_free(&share->name_hash);
free_root(&outparam->mem_root,MYF(0)); free_root(&outparam->mem_root, MYF(0)); // Safe to call on bzero'd root
my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) outparam->alias, MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN (error); DBUG_RETURN (error);
} /* openfrm */ } /* openfrm */
...@@ -821,21 +863,18 @@ int closefrm(register TABLE *table) ...@@ -821,21 +863,18 @@ int closefrm(register TABLE *table)
DBUG_ENTER("closefrm"); DBUG_ENTER("closefrm");
if (table->db_stat) if (table->db_stat)
error=table->file->close(); error=table->file->close();
if (table->table_name) my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR));
{ table->alias= 0;
my_free(table->table_name,MYF(0)); if (table->field)
table->table_name=0;
}
if (table->fields)
{ {
for (Field **ptr=table->field ; *ptr ; ptr++) for (Field **ptr=table->field ; *ptr ; ptr++)
delete *ptr; delete *ptr;
table->fields=0; table->field= 0;
} }
delete table->file; delete table->file;
table->file=0; /* For easyer errorchecking */ table->file= 0; /* For easier errorchecking */
hash_free(&table->name_hash); hash_free(&table->s->name_hash);
free_root(&table->mem_root,MYF(0)); free_root(&table->mem_root, MYF(0));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -844,8 +883,11 @@ int closefrm(register TABLE *table) ...@@ -844,8 +883,11 @@ int closefrm(register TABLE *table)
void free_blobs(register TABLE *table) void free_blobs(register TABLE *table)
{ {
for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++) uint *ptr, *end;
(*ptr)->free(); for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
ptr != end ;
ptr++)
((Field_blob*) table->field[*ptr])->free();
} }
...@@ -993,6 +1035,7 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -993,6 +1035,7 @@ static void frm_error(int error, TABLE *form, const char *name,
int err_no; int err_no;
char buff[FN_REFLEN]; char buff[FN_REFLEN];
const char *form_dev="",*datext; const char *form_dev="",*datext;
const char *real_name= (char*) name+dirname_length(name);
DBUG_ENTER("frm_error"); DBUG_ENTER("frm_error");
switch (error) { switch (error) {
...@@ -1003,11 +1046,11 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1003,11 +1046,11 @@ static void frm_error(int error, TABLE *form, const char *name,
uint length=dirname_part(buff,name); uint length=dirname_part(buff,name);
buff[length-1]=0; buff[length-1]=0;
db=buff+dirname_length(buff); db=buff+dirname_length(buff);
my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name); my_error(ER_NO_SUCH_TABLE, MYF(0), db, real_name);
} }
else else
my_error(ER_FILE_NOT_FOUND,errortype, my_error(ER_FILE_NOT_FOUND, errortype,
fn_format(buff,name,form_dev,reg_ext,0),my_errno); fn_format(buff, name, form_dev, reg_ext, 0), my_errno);
break; break;
case 2: case 2:
{ {
...@@ -1016,7 +1059,7 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1016,7 +1059,7 @@ static void frm_error(int error, TABLE *form, const char *name,
err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ? err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
ER_FILE_USED : ER_CANT_OPEN_FILE; ER_FILE_USED : ER_CANT_OPEN_FILE;
my_error(err_no,errortype, my_error(err_no,errortype,
fn_format(buff,form->real_name,form_dev,datext,2),my_errno); fn_format(buff,real_name,form_dev,datext,2),my_errno);
break; break;
} }
case 5: case 5:
...@@ -1030,13 +1073,13 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1030,13 +1073,13 @@ static void frm_error(int error, TABLE *form, const char *name,
} }
my_printf_error(ER_UNKNOWN_COLLATION, my_printf_error(ER_UNKNOWN_COLLATION,
"Unknown collation '%s' in table '%-.64s' definition", "Unknown collation '%s' in table '%-.64s' definition",
MYF(0), csname, form->real_name); MYF(0), csname, real_name);
break; break;
} }
default: /* Better wrong error than none */ default: /* Better wrong error than none */
case 4: case 4:
my_error(ER_NOT_FORM_FILE,errortype, my_error(ER_NOT_FORM_FILE, errortype,
fn_format(buff,name,form_dev,reg_ext,0)); fn_format(buff, name, form_dev, reg_ext, 0));
break; break;
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -1045,7 +1088,7 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1045,7 +1088,7 @@ static void frm_error(int error, TABLE *form, const char *name,
/* /*
** fix a str_type to a array type ** fix a str_type to a array type
** typeparts sepearated with some char. differents types are separated ** typeparts separated with some char. differents types are separated
** with a '\0' ** with a '\0'
*/ */
...@@ -1107,22 +1150,27 @@ TYPELIB *typelib(List<String> &strings) ...@@ -1107,22 +1150,27 @@ TYPELIB *typelib(List<String> &strings)
} }
/* /*
** Search after a field with given start & length Search after a field with given start & length
** If an exact field isn't found, return longest field with starts If an exact field isn't found, return longest field with starts
** at right position. at right position.
** Return 0 on error, else field number+1
** This is needed because in some .frm fields 'fieldnr' was saved wrong NOTES
*/ This is needed because in some .frm fields 'fieldnr' was saved wrong
RETURN
0 error
# field number +1
*/
static uint find_field(TABLE *form,uint start,uint length) static uint find_field(TABLE *form,uint start,uint length)
{ {
Field **field; Field **field;
uint i,pos; uint i, pos, fields;
pos=0; pos=0;
fields= form->s->fields;
for (field=form->field, i=1 ; i<= form->fields ; i++,field++) for (field=form->field, i=1 ; i<= fields ; i++,field++)
{ {
if ((*field)->offset() == start) if ((*field)->offset() == start)
{ {
...@@ -1137,7 +1185,7 @@ static uint find_field(TABLE *form,uint start,uint length) ...@@ -1137,7 +1185,7 @@ static uint find_field(TABLE *form,uint start,uint length)
} }
/* Check that the integer is in the internvall */ /* Check that the integer is in the internal */
int set_zone(register int nr, int min_zone, int max_zone) int set_zone(register int nr, int min_zone, int max_zone)
{ {
...@@ -1201,7 +1249,7 @@ void append_unescaped(String *res, const char *pos, uint length) ...@@ -1201,7 +1249,7 @@ void append_unescaped(String *res, const char *pos, uint length)
res->append('n'); res->append('n');
break; break;
case '\r': case '\r':
res->append('\\'); /* This gives better readbility */ res->append('\\'); /* This gives better readability */
res->append('r'); res->append('r');
break; break;
case '\\': case '\\':
...@@ -1246,7 +1294,11 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, ...@@ -1246,7 +1294,11 @@ 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) if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
{ {
bzero((char*) fileinfo,64); bzero((char*) fileinfo,64);
fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3; // Header /* header */
fileinfo[0]=(uchar) 254;
fileinfo[1]= 1;
fileinfo[2]= FRM_VER+3+ test(create_info->varchar);
fileinfo[3]= (uchar) ha_checktype(create_info->db_type); fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
fileinfo[4]=1; fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */ int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
...@@ -1286,17 +1338,20 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, ...@@ -1286,17 +1338,20 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table) void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
{ {
TABLE_SHARE *share= table->s;
DBUG_ENTER("update_create_info_from_table"); DBUG_ENTER("update_create_info_from_table");
create_info->max_rows=table->max_rows;
create_info->min_rows=table->min_rows; create_info->max_rows= share->max_rows;
create_info->table_options=table->db_create_options; create_info->min_rows= share->min_rows;
create_info->avg_row_length=table->avg_row_length; create_info->table_options= share->db_create_options;
create_info->row_type=table->row_type; create_info->avg_row_length= share->avg_row_length;
create_info->raid_type=table->raid_type; create_info->row_type= share->row_type;
create_info->raid_chunks=table->raid_chunks; create_info->raid_type= share->raid_type;
create_info->raid_chunksize=table->raid_chunksize; create_info->raid_chunks= share->raid_chunks;
create_info->default_table_charset=table->table_charset; create_info->raid_chunksize= share->raid_chunksize;
create_info->default_table_charset= share->table_charset;
create_info->table_charset= 0; create_info->table_charset= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1399,7 +1454,7 @@ bool check_db_name(char *name) ...@@ -1399,7 +1454,7 @@ bool check_db_name(char *name)
if (use_mb(system_charset_info)) if (use_mb(system_charset_info))
{ {
int len=my_ismbchar(system_charset_info, name, int len=my_ismbchar(system_charset_info, name,
name+system_charset_info->mbmaxlen); name+system_charset_info->mbmaxlen);
if (len) if (len)
{ {
name += len; name += len;
...@@ -1468,7 +1523,7 @@ bool check_column_name(const char *name) ...@@ -1468,7 +1523,7 @@ bool check_column_name(const char *name)
{ {
const char *start= name; const char *start= name;
bool last_char_is_space= TRUE; bool last_char_is_space= TRUE;
while (*name) while (*name)
{ {
#if defined(USE_MB) && defined(USE_MB_IDENT) #if defined(USE_MB) && defined(USE_MB_IDENT)
...@@ -1476,7 +1531,7 @@ bool check_column_name(const char *name) ...@@ -1476,7 +1531,7 @@ bool check_column_name(const char *name)
if (use_mb(system_charset_info)) if (use_mb(system_charset_info))
{ {
int len=my_ismbchar(system_charset_info, name, int len=my_ismbchar(system_charset_info, name,
name+system_charset_info->mbmaxlen); name+system_charset_info->mbmaxlen);
if (len) if (len)
{ {
name += len; name += len;
...@@ -1511,12 +1566,522 @@ db_type get_table_type(const char *name) ...@@ -1511,12 +1566,522 @@ db_type get_table_type(const char *name)
error=my_read(file,(byte*) head,4,MYF(MY_NABP)); error=my_read(file,(byte*) head,4,MYF(MY_NABP));
my_close(file,MYF(0)); my_close(file,MYF(0));
if (error || head[0] != (uchar) 254 || head[1] != 1 || if (error || head[0] != (uchar) 254 || head[1] != 1 ||
(head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3)) (head[2] != FRM_VER && head[2] != FRM_VER+1 &&
(head[2] < FRM_VER+3 || head[2] > FRM_VER+4)))
DBUG_RETURN(DB_TYPE_UNKNOWN); DBUG_RETURN(DB_TYPE_UNKNOWN);
DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3))); DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
} }
/*
calculate md5 of query
SYNOPSIS
st_table_list::calc_md5()
buffer buffer for md5 writing
*/
void st_table_list::calc_md5(char *buffer)
{
my_MD5_CTX context;
uchar digest[16];
my_MD5Init(&context);
my_MD5Update(&context,(uchar *) query.str, query.length);
my_MD5Final(digest, &context);
sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
digest[4], digest[5], digest[6], digest[7],
digest[8], digest[9], digest[10], digest[11],
digest[12], digest[13], digest[14], digest[15]);
}
/*
set ancestor TABLE for table place holder of VIEW
SYNOPSIS
st_table_list::set_ancestor()
*/
void st_table_list::set_ancestor()
{
/* process all tables of view */
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->ancestor)
ancestor->set_ancestor();
tbl->table->grant= grant;
}
/* if view contain only one table, substitute TABLE of it */
if (!ancestor->next_local)
{
table= ancestor->table;
schema_table= ancestor->schema_table;
}
}
/*
Save old want_privilege and clear want_privilege
SYNOPSIS
save_and_clear_want_privilege()
*/
void st_table_list::save_and_clear_want_privilege()
{
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->table)
{
privilege_backup= tbl->table->grant.want_privilege;
tbl->table->grant.want_privilege= 0;
}
else
{
DBUG_ASSERT(tbl->view && tbl->ancestor &&
tbl->ancestor->next_local);
tbl->save_and_clear_want_privilege();
}
}
}
/*
restore want_privilege saved by save_and_clear_want_privilege
SYNOPSIS
restore_want_privilege()
*/
void st_table_list::restore_want_privilege()
{
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->table)
tbl->table->grant.want_privilege= privilege_backup;
else
{
DBUG_ASSERT(tbl->view && tbl->ancestor &&
tbl->ancestor->next_local);
tbl->restore_want_privilege();
}
}
}
/*
setup fields of placeholder of merged VIEW
SYNOPSIS
st_table_list::setup_ancestor()
thd - thread handler
conds - condition of this JOIN
check_opt_type - WHITH CHECK OPTION type (VIEW_CHECK_NONE,
VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED)
DESCRIPTION
It is:
- preparing translation table for view columns (fix_fields() for every
call and creation for first call)
- preparing WHERE, ON and CHECK OPTION condition (fix_fields() for every
call and merging for first call).
If there are underlying view(s) procedure first will be called for them.
RETURN
0 - OK
1 - error
*/
bool st_table_list::setup_ancestor(THD *thd, Item **conds,
uint8 check_opt_type)
{
Field_translator *transl;
SELECT_LEX *select= &view->select_lex;
SELECT_LEX *current_select_save= thd->lex->current_select;
Item *item;
TABLE_LIST *tbl;
List_iterator_fast<Item> it(select->item_list);
uint i= 0;
bool save_set_query_id= thd->set_query_id;
bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
bool save_allow_sum_func= thd->allow_sum_func;
DBUG_ENTER("st_table_list::setup_ancestor");
for (tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->ancestor &&
tbl->setup_ancestor(thd, conds,
(check_opt_type == VIEW_CHECK_CASCADED ?
VIEW_CHECK_CASCADED :
VIEW_CHECK_NONE)))
DBUG_RETURN(1);
}
if (field_translation)
{
DBUG_PRINT("info", ("there are already translation table"));
/* prevent look up in SELECTs tree */
thd->lex->current_select= &thd->lex->select_lex;
thd->lex->select_lex.no_wrap_view_item= 1;
thd->set_query_id= 1;
/* this view was prepared already on previous PS/SP execution */
Field_translator *end= field_translation + select->item_list.elements;
/* real rights will be checked in VIEW field */
save_and_clear_want_privilege();
/* aggregate function are allowed */
thd->allow_sum_func= 1;
for (transl= field_translation; transl < end; transl++)
{
if (!transl->item->fixed &&
transl->item->fix_fields(thd, ancestor, &transl->item))
goto err;
}
for (tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->on_expr && !tbl->on_expr->fixed &&
tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
goto err;
}
if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
goto err;
if (check_option && !check_option->fixed &&
check_option->fix_fields(thd, ancestor, &check_option))
goto err;
restore_want_privilege();
/* WHERE/ON resolved => we can rename fields */
for (transl= field_translation; transl < end; transl++)
{
transl->item->rename((char *)transl->name);
}
goto ok;
}
/* view fields translation table */
if (!(transl=
(Field_translator*)(thd->current_arena->
alloc(select->item_list.elements *
sizeof(Field_translator)))))
{
DBUG_RETURN(1);
}
/* prevent look up in SELECTs tree */
thd->lex->current_select= &thd->lex->select_lex;
thd->lex->select_lex.no_wrap_view_item= 1;
/*
Resolve all view items against ancestor table.
TODO: do it only for real used fields "on demand" to mark really
used fields correctly.
*/
thd->set_query_id= 1;
/* real rights will be checked in VIEW field */
save_and_clear_want_privilege();
/* aggregate function are allowed */
thd->allow_sum_func= 1;
while ((item= it++))
{
/* save original name of view column */
char *name= item->name;
transl[i].item= item;
if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item))
goto err;
/* set new item get in fix fields and original column name */
transl[i++].name= name;
}
field_translation= transl;
/* TODO: sort this list? Use hash for big number of fields */
for (tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->on_expr && !tbl->on_expr->fixed &&
tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
goto err;
}
if (where ||
(check_opt_type == VIEW_CHECK_CASCADED &&
ancestor->check_option))
{
Item_arena *arena= thd->current_arena, backup;
TABLE_LIST *tbl= this;
if (arena->is_conventional())
arena= 0; // For easier test
if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
goto err;
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
if (check_opt_type)
{
if (where)
check_option= where->copy_andor_structure(thd);
if (check_opt_type == VIEW_CHECK_CASCADED)
{
check_option= and_conds(check_option, ancestor->check_option);
}
}
/*
check that it is not VIEW in which we insert with INSERT SELECT
(in this case we can't add view WHERE condition to main SELECT_LEX)
*/
if (where && !no_where_clause)
{
/* Go up to join tree and try to find left join */
for (; tbl; tbl= tbl->embedding)
{
if (tbl->outer_join)
{
/*
Store WHERE condition to ON expression for outer join, because
we can't use WHERE to correctly execute left joins on VIEWs and
this expression will not be moved to WHERE condition (i.e. will
be clean correctly for PS/SP)
*/
tbl->on_expr= and_conds(tbl->on_expr, where);
break;
}
}
if (tbl == 0)
{
if (outer_join)
{
/*
Store WHERE condition to ON expression for outer join, because
we can't use WHERE to correctly execute left joins on VIEWs and
this expression will not be moved to WHERE condition (i.e. will
be clean correctly for PS/SP)
*/
on_expr= and_conds(on_expr, where);
}
else
{
/*
It is conds of JOIN, but it will be stored in
st_select_lex::prep_where for next reexecution
*/
*conds= and_conds(*conds, where);
}
}
}
if (arena)
thd->restore_backup_item_arena(arena, &backup);
}
restore_want_privilege();
/*
fix_fields do not need tables, because new are only AND operation and we
just need recollect statistics
*/
if (check_option && !check_option->fixed &&
check_option->fix_fields(thd, 0, &check_option))
goto err;
/* WHERE/ON resolved => we can rename fields */
{
Field_translator *end= field_translation + select->item_list.elements;
for (transl= field_translation; transl < end; transl++)
{
transl->item->rename((char *)transl->name);
}
}
/* full text function moving to current select */
if (view->select_lex.ftfunc_list->elements)
{
Item_arena *arena= thd->current_arena, backup;
if (arena->is_conventional())
arena= 0; // For easier test
else
thd->set_n_backup_item_arena(arena, &backup);
Item_func_match *ifm;
List_iterator_fast<Item_func_match>
li(*(view->select_lex.ftfunc_list));
while ((ifm= li++))
current_select_save->ftfunc_list->push_front(ifm);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
}
ok:
thd->lex->select_lex.no_wrap_view_item= save_wrapper;
thd->lex->current_select= current_select_save;
thd->set_query_id= save_set_query_id;
thd->allow_sum_func= save_allow_sum_func;
DBUG_RETURN(0);
err:
/* Hide "Unknown column" or "Unknown function" error */
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
{
thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
}
thd->lex->select_lex.no_wrap_view_item= save_wrapper;
thd->lex->current_select= current_select_save;
thd->set_query_id= save_set_query_id;
thd->allow_sum_func= save_allow_sum_func;
DBUG_RETURN(1);
}
/*
cleunup items belonged to view fields translation table
SYNOPSIS
st_table_list::cleanup_items()
*/
void st_table_list::cleanup_items()
{
if (!field_translation)
return;
Field_translator *end= (field_translation +
view->select_lex.item_list.elements);
for (Field_translator *transl= field_translation; transl < end; transl++)
transl->item->walk(&Item::cleanup_processor, 0);
}
/*
check CHECK OPTION condition
SYNOPSIS
check_option()
ignore_failure ignore check option fail
RETURN
VIEW_CHECK_OK OK
VIEW_CHECK_ERROR FAILED
VIEW_CHECK_SKIP FAILED, but continue
*/
int st_table_list::view_check_option(THD *thd, bool ignore_failure)
{
if (check_option && check_option->val_int() == 0)
{
if (ignore_failure)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED),
view_db.str, view_name.str);
return(VIEW_CHECK_SKIP);
}
else
{
my_error(ER_VIEW_CHECK_FAILED, MYF(0), view_db.str, view_name.str);
return(VIEW_CHECK_ERROR);
}
}
return(VIEW_CHECK_OK);
}
/*
Find table in underlying tables by mask and check that only this
table belong to given mask
SYNOPSIS
st_table_list::check_single_table()
table reference on variable where to store found table
(should be 0 on call, to find table, or point to table for
unique test)
map bit mask of tables
RETURN
FALSE table not found or found only one
TRUE found several tables
*/
bool st_table_list::check_single_table(st_table_list **table, table_map map)
{
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->table)
{
if (tbl->table->map & map)
{
if (*table)
return TRUE;
else
*table= tbl;
}
}
else
if (tbl->check_single_table(table, map))
return TRUE;
}
return FALSE;
}
/*
Set insert_values buffer
SYNOPSIS
set_insert_values()
mem_root memory pool for allocating
RETURN
FALSE - OK
TRUE - out of memory
*/
bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
{
if (table)
{
if (!table->insert_values &&
!(table->insert_values= (byte *)alloc_root(mem_root,
table->s->rec_buff_length)))
return TRUE;
}
else
{
DBUG_ASSERT(view && ancestor && ancestor->next_local);
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
if (tbl->set_insert_values(mem_root))
return TRUE;
}
return FALSE;
}
void Field_iterator_view::set(TABLE_LIST *table)
{
ptr= table->field_translation;
array_end= ptr + table->view->select_lex.item_list.elements;
}
const char *Field_iterator_table::name()
{
return (*ptr)->field_name;
}
Item *Field_iterator_table::item(THD *thd)
{
return new Item_field(thd, *ptr);
}
const char *Field_iterator_view::name()
{
return ptr->name;
}
/***************************************************************************** /*****************************************************************************
** Instansiate templates ** Instansiate templates
*****************************************************************************/ *****************************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment