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

Manual merge

parents 9d785cd5 cdb40830
...@@ -62,7 +62,6 @@ From: $FROM ...@@ -62,7 +62,6 @@ From: $FROM
To: $INTERNALS To: $INTERNALS
Subject: bk commit into $VERSION tree ($CHANGESET)$BS Subject: bk commit into $VERSION tree ($CHANGESET)$BS
$BH $BH
Below is the list of changes that have just been committed into a local Below is the list of changes that have just been committed into a local
$VERSION repository of $USER. When $USER does a push these changes will $VERSION repository of $USER. When $USER does a push these changes will
be propagated to the main repository and, within 24 hours after the be propagated to the main repository and, within 24 hours after the
......
...@@ -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(THD *thd, const char *name, const char *alias, uint db_stat, int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
uint prgflag, uint ha_open_flags, TABLE *outparam) uint ha_open_flags, TABLE *outparam)
{ {
reg1 uint i; reg1 uint i;
reg2 uchar *strpos; reg2 uchar *strpos;
...@@ -76,94 +76,76 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -76,94 +76,76 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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_pos, new_frm_ver, field_pack_length; uint null_bit, 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: 0x%lx",name,outparam)); DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
error= 1; bzero((char*) outparam,sizeof(*outparam));
disk_buff= NULL; 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);
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;
bzero((char*) outparam,sizeof(*outparam)); outparam->real_name=strdup_root(&outparam->mem_root,
outparam->in_use= thd; name+dirname_length(name));
outparam->s= share= &outparam->share_not_to_be_used; outparam->table_name=my_strdup(alias,MYF(MY_WME));
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, if ((file=my_open(fn_format(index_file,name,"",reg_ext,MY_UNPACK_FILENAME),
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)
{ {
// new .frm goto err_end; /* purecov: inspected */
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
share->blob_ptr_size= sizeof(char*); if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open;
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 && head[2] != FRM_VER+1 && head[2] != FRM_VER+3))
! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4))) goto err_not_open; /* purecov: inspected */
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; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
*fn_ext(index_file)='\0'; // Remove .frm extension *fn_ext(index_file)='\0'; // Remove .frm extension
share->frm_version= head[2]; outparam->frm_version= head[2];
share->db_type= ha_checktype((enum db_type) (uint) *(head+3)); outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
share->db_create_options= db_create_options=uint2korr(head+30); outparam->db_create_options=db_create_options=uint2korr(head+30);
share->db_options_in_use= share->db_create_options; outparam->db_options_in_use=outparam->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
{ {
share->avg_row_length= uint4korr(head+34); outparam->avg_row_length=uint4korr(head+34);
share-> row_type= (row_type) head[40]; outparam->row_type=(row_type) head[40];
share->raid_type= head[41]; outparam->raid_type= head[41];
share->raid_chunks= head[42]; outparam->raid_chunks= head[42];
share->raid_chunksize= uint4korr(head+43); outparam->raid_chunksize= uint4korr(head+43);
share->table_charset= get_charset((uint) head[38],MYF(0)); outparam->table_charset=get_charset((uint) head[38],MYF(0));
null_field_first= 1; null_field_first=1;
} }
if (!share->table_charset) if (!outparam->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))
...@@ -174,34 +156,35 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -174,34 +156,35 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
"so character column sizes may have changed", "so character column sizes may have changed",
name); name);
} }
share->table_charset= default_charset_info; outparam->table_charset=default_charset_info;
} }
share->db_record_offset= 1; outparam->db_record_offset=1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR) if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
share->blob_ptr_size= portable_sizeof_char_ptr; outparam->blob_ptr_size=portable_sizeof_char_ptr;
/* Set temporarily a good value for db_low_byte_first */ /* Set temporaryly a good value for db_low_byte_first */
share->db_low_byte_first= test(share->db_type != DB_TYPE_ISAM); outparam->db_low_byte_first=test(outparam->db_type != DB_TYPE_ISAM);
error=4; error=4;
share->max_rows= uint4korr(head+18); outparam->max_rows=uint4korr(head+18);
share->min_rows= uint4korr(head+22); outparam->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; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
if (disk_buff[0] & 0x80) if (disk_buff[0] & 0x80)
{ {
share->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f); outparam->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
share->key_parts= key_parts= uint2korr(disk_buff+2); outparam->key_parts= key_parts= uint2korr(disk_buff+2);
} }
else else
{ {
share->keys= keys= disk_buff[0]; outparam->keys= keys= disk_buff[0];
share->key_parts= key_parts= disk_buff[1]; outparam->key_parts= key_parts= disk_buff[1];
} }
share->keys_for_keyread.init(0); outparam->keys_for_keyread.init(0);
share->keys_in_use.init(keys); outparam->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();
...@@ -209,7 +192,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -209,7 +192,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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; /* purecov: inspected */ goto err_not_open; /* 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);
...@@ -218,12 +201,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -218,12 +201,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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; goto err_not_open;
for (i=0 ; i < keys ; i++, keyinfo++) for (i=0 ; i < keys ; i++, keyinfo++)
{ {
keyinfo->table= outparam; if (new_frm_ver == 3)
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);
...@@ -272,9 +254,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -272,9 +254,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
keynames=(char*) key_part; keynames=(char*) key_part;
strpos+= (strmov(keynames, (char *) strpos) - keynames)+1; strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
share->reclength = uint2korr((head+16)); outparam->reclength = uint2korr((head+16));
if (*(head+26) == 1) if (*(head+26) == 1)
share->system= 1; /* one-record-database */ outparam->system=1; /* one-record-database */
#ifdef HAVE_CRYPTED_FRM #ifdef HAVE_CRYPTED_FRM
else if (*(head+26) == 2) else if (*(head+26) == 2)
{ {
...@@ -286,97 +268,84 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -286,97 +268,84 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
#endif #endif
/* Allocate handler */ /* Allocate handler */
if (!(outparam->file= get_new_handler(outparam, share->db_type))) if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
goto err; goto err_not_open;
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)) if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2;
records=2; else records=1;
else if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
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(share->reclength + 1 + rec_buff_length=ALIGN_SIZE(outparam->reclength+1+
outparam->file->extra_rec_buf_length()); outparam->file->extra_rec_buf_length());
share->rec_buff_length= rec_buff_length; if (!(outparam->record[0]= (byte*)
if (!(record= (char *) alloc_root(&outparam->mem_root, (record = (char *) alloc_root(&outparam->mem_root,
rec_buff_length * records))) rec_buff_length * records))))
goto err; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
share->default_values= (byte *) record; record[outparam->reclength]=0; // For purify and ->c_ptr()
if (my_pread(file,(byte*) record, (uint) share->reclength, outparam->rec_buff_length=rec_buff_length;
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; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
/* HACK: table->record[2] is used instead of table->default_values here */
if (records == 1) for (i=0 ; i < records ; i++, record+=rec_buff_length)
{ {
/* We are probably in hard repair, and the buffers should not be used */ outparam->record[i]=(byte*) record;
outparam->record[0]= outparam->record[1]= share->default_values; if (i)
} memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
else
{
outparam->record[0]= (byte *) record+ rec_buff_length;
if (records > 2)
outparam->record[1]= (byte *) record+ rec_buff_length*2;
else
outparam->record[1]= outparam->record[0]; // Safety
} }
#ifdef HAVE_purify if (records == 2)
/* { /* fix for select */
We need this because when we read var-length rows, we are not updating outparam->default_values=outparam->record[1];
bytes after end of varchar if (db_stat & HA_READ_ONLY)
*/ outparam->record[1]=outparam->record[0]; /* purecov: inspected */
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 outparam->insert_values=0; /* for INSERT ... UPDATE */
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))) if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
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; // Wrong password goto err_not_open; // Wrong password
} }
#endif #endif
share->fields= uint2korr(head+258); outparam->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);
share->null_fields= uint2korr(head+282); outparam->null_fields=uint2korr(head+282);
com_length= uint2korr(head+284); com_length=uint2korr(head+284);
share->comment= strdup_root(&outparam->mem_root, (char*) head+47); 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 com_length: %d", interval_count,interval_parts, share->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, outparam->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) ((share->fields+1)*sizeof(Field*)+ (uint) ((outparam->fields+1)*sizeof(Field*)+
interval_count*sizeof(TYPELIB)+ interval_count*sizeof(TYPELIB)+
(share->fields+interval_parts+ (outparam->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; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
outparam->field=field_ptr; outparam->field=field_ptr;
read_length=(uint) (share->fields * field_pack_length + read_length=(uint) (outparam->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; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
#ifdef HAVE_CRYPTED_FRM #ifdef HAVE_CRYPTED_FRM
if (crypted) if (crypted)
{ {
...@@ -387,31 +356,31 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -387,31 +356,31 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
#endif #endif
strpos= disk_buff+pos; strpos= disk_buff+pos;
share->intervals= (TYPELIB*) (field_ptr+share->fields+1); outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1);
int_array= (const char **) (share->intervals+interval_count); int_array= (const char **) (outparam->intervals+interval_count);
names= (char*) (int_array+share->fields+interval_parts+keys+3); names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
if (!interval_count) if (!interval_count)
share->intervals= 0; // For better debugging outparam->intervals=0; // For better debugging
memcpy((char*) names, strpos+(share->fields*field_pack_length), memcpy((char*) names, strpos+(outparam->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, &share->fieldnames, 1, &names); fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
fix_type_pointers(&int_array, share->intervals, interval_count, fix_type_pointers(&int_array,outparam->intervals,interval_count,
&names); &names);
{ {
/* Set ENUM and SET lengths */ /* Set ENUM and SET lengths */
TYPELIB *interval; TYPELIB *interval;
for (interval= share->intervals; for (interval= outparam->intervals;
interval < share->intervals + interval_count; interval < outparam->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; goto err_not_open;
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;
...@@ -419,33 +388,33 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -419,33 +388,33 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
} }
if (keynames) if (keynames)
fix_type_pointers(&int_array, &share->keynames, 1, &keynames); fix_type_pointers(&int_array,&outparam->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_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1; null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8; outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
} }
else else
{ {
share->null_bytes= (share->null_fields+7)/8; outparam->null_bytes=(outparam->null_fields+7)/8;
outparam->null_flags= null_pos= outparam->null_flags=null_pos=
(uchar*) (record+1+share->reclength-share->null_bytes); (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
null_bit_pos= 0; null_bit=1;
} }
use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH; use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash) if (use_hash)
use_hash= !hash_init(&share->name_hash, use_hash= !hash_init(&outparam->name_hash,
system_charset_info, system_charset_info,
share->fields,0,0, outparam->fields,0,0,
(hash_get_key) get_field_name,0,0); (hash_get_key) get_field_name,0,0);
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) for (i=0 ; i < outparam->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;
...@@ -453,7 +422,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -453,7 +422,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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);
...@@ -461,10 +430,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -461,10 +430,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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
...@@ -472,7 +442,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -472,7 +442,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
charset= &my_charset_bin; charset= &my_charset_bin;
#else #else
error= 4; // unsupported field type error= 4; // unsupported field type
goto err; goto err_not_open;
#endif #endif
} }
else else
...@@ -483,7 +453,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -483,7 +453,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{ {
error= 5; // Unknown or unavailable charset error= 5; // Unknown or unavailable charset
errarg= (int) strpos[14]; errarg= (int) strpos[14];
goto err; goto err_not_open;
} }
} }
if (!comment_length) if (!comment_length)
...@@ -503,7 +473,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -503,7 +473,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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];
...@@ -520,7 +489,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -520,7 +489,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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(share->table_charset->csname, if (!(charset= get_charset_by_csname(outparam->table_charset->csname,
MY_CS_BINSORT, MYF(0)))) MY_CS_BINSORT, MYF(0))))
charset= &my_charset_bin; charset= &my_charset_bin;
} }
...@@ -528,58 +497,51 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -528,58 +497,51 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
charset= &my_charset_bin; charset= &my_charset_bin;
} }
else else
charset= share->table_charset; charset= outparam->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= share->intervals + interval_nr - 1; TYPELIB *interval= outparam->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_pos, null_pos,null_bit,
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 ?
share->intervals+interval_nr-1 : outparam->intervals+interval_nr-1 :
(TYPELIB*) 0), (TYPELIB*) 0),
share->fieldnames.type_names[i], outparam->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; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
} }
reg_field->comment=comment; reg_field->comment=comment;
if (field_type == FIELD_TYPE_BIT) if (!(reg_field->flags & NOT_NULL_FLAG))
{ {
if ((null_bit_pos+= field_length & 7) > 7) if ((null_bit<<=1) == 256)
{ {
null_pos++; null_pos++;
null_bit_pos-= 8; null_bit=1;
}
} }
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)
share->timestamp_field_offset= i; outparam->timestamp_field_offset=i;
if (use_hash) if (use_hash)
(void) my_hash_insert(&share->name_hash,(byte*) field_ptr); // never fail (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail
} }
*field_ptr=0; // End marker *field_ptr=0; // End marker
...@@ -587,15 +549,15 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -587,15 +549,15 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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,
&share->keynames, 3) - 1); &outparam->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 < share->keys ; key++,keyinfo++) for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
{ {
uint usable_parts=0; uint usable_parts=0;
keyinfo->name=(char*) share->keynames.type_names[key]; keyinfo->name=(char*) outparam->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;
...@@ -628,8 +590,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -628,8 +590,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
(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 > share->fields) if (key_part->fieldnr > outparam->fields)
goto err; // sanity check goto err_not_open; // sanity check
#endif #endif
if (key_part->fieldnr) if (key_part->fieldnr)
{ // Should always be true ! { // Should always be true !
...@@ -645,12 +607,10 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -645,12 +607,10 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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() == MYSQL_TYPE_VARCHAR) field->real_type() == FIELD_TYPE_VAR_STRING)
{ {
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;
...@@ -661,10 +621,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -661,10 +621,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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) &&
...@@ -677,7 +633,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -677,7 +633,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{ {
if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY) if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
{ {
share->keys_for_keyread.set_bit(key); outparam->read_only_keys.clear_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)
...@@ -695,7 +652,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -695,7 +652,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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= share->keys_in_use; field->part_of_key= outparam->keys_in_use;
} }
if (field->key_length() != key_part->length) if (field->key_length() != key_part->length)
{ {
...@@ -723,16 +680,16 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -723,16 +680,16 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
} }
keyinfo->usable_key_parts=usable_parts; // Filesort keyinfo->usable_key_parts=usable_parts; // Filesort
set_if_bigger(share->max_key_length,keyinfo->key_length+ set_if_bigger(outparam->max_key_length,keyinfo->key_length+
keyinfo->key_parts); keyinfo->key_parts);
share->total_key_length+= keyinfo->key_length; outparam->total_key_length+= keyinfo->key_length;
if (keyinfo->flags & HA_NOSAME) if (keyinfo->flags & HA_NOSAME)
set_if_bigger(share->max_unique_length, keyinfo->key_length); set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
} }
if (primary_key < MAX_KEY && if (primary_key < MAX_KEY &&
(share->keys_in_use.is_set(primary_key))) (outparam->keys_in_use.is_set(primary_key)))
{ {
share->primary_key= primary_key; outparam->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'
...@@ -745,25 +702,27 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -745,25 +702,27 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
} }
} }
else else
share->primary_key = MAX_KEY; // we do not have a primary key outparam->primary_key = MAX_KEY; // we do not have a primary key
} }
else else
share->primary_key= MAX_KEY; outparam->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 */
/* Old file format with default as not null */ uint null_length=(outparam->null_fields+7)/8;
uint null_length= (share->null_fields+7)/8; bfill(outparam->null_flags,null_length,255);
bfill(share->default_values + (outparam->null_flags - (uchar*) record), bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255);
null_length, 255); if (records > 2)
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) (share->next_number_index= (uint) if ((int) (outparam->next_number_index= (uint)
find_ref_key(outparam,reg_field, find_ref_key(outparam,reg_field,
&share->next_number_key_offset)) < 0) &outparam->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;
...@@ -772,30 +731,34 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -772,30 +731,34 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
reg_field->flags|=AUTO_INCREMENT_FLAG; reg_field->flags|=AUTO_INCREMENT_FLAG;
} }
if (share->blob_fields) if (outparam->blob_fields)
{ {
Field **ptr; Field **ptr;
uint i, *save; Field_blob **save;
/* Store offsets to blob fields to find them fast */ if (!(outparam->blob_field=save=
if (!(share->blob_field= save= (Field_blob**) alloc_root(&outparam->mem_root,
(uint*) alloc_root(&outparam->mem_root, (uint) (outparam->blob_fields+1)*
(uint) (share->blob_fields* sizeof(uint))))) sizeof(Field_blob*))))
goto err; goto err_not_open;
for (i=0, ptr= outparam->field ; *ptr ; ptr++, i++) for (ptr=outparam->field ; *ptr ; ptr++)
{ {
if ((*ptr)->flags & BLOB_FLAG) if ((*ptr)->flags & BLOB_FLAG)
(*save++)= i; (*save++)= (Field_blob*) *ptr;
} }
*save=0; // End marker
} }
else
outparam->blob_field=
(Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
/* The table struct is now initialized; Open the table */ /* The table struct is now initialzed; Open the table */
error=2; error=2;
if (db_stat) if (db_stat)
{ {
int ha_err; int err;
unpack_filename(index_file,index_file); unpack_filename(index_file,index_file);
if ((ha_err= (outparam->file-> if ((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 :
...@@ -807,50 +770,45 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -807,50 +770,45 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
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 */
share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) && outparam->crashed=((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 (ha_err == HA_ERR_NO_SUCH_TABLE) if (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;
} }
else goto err_not_open; /* purecov: inspected */
{
outparam->file->print_error(ha_err, MYF(0));
error_reported= TRUE;
}
goto err; /* purecov: inspected */
} }
} }
share->db_low_byte_first= outparam->file->low_byte_first(); outparam->db_low_byte_first=outparam->file->low_byte_first();
*root_ptr= old_root; *root_ptr= old_root;
thd->status_var.opened_tables++; opened_tables++;
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (use_hash) if (use_hash)
(void) hash_check(&share->name_hash); (void) hash_check(&outparam->name_hash);
#endif #endif
DBUG_RETURN (0); DBUG_RETURN (0);
err: err_not_open:
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;
if (! error_reported) frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg);
frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG, errarg);
delete outparam->file; delete outparam->file;
outparam->file=0; // For easier errorchecking outparam->file=0; // For easyer errorchecking
outparam->db_stat=0; outparam->db_stat=0;
hash_free(&share->name_hash); hash_free(&outparam->name_hash);
free_root(&outparam->mem_root, MYF(0)); // Safe to call on bzero'd root free_root(&outparam->mem_root,MYF(0));
my_free((char*) outparam->alias, MYF(MY_ALLOW_ZERO_PTR)); my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN (error); DBUG_RETURN (error);
} /* openfrm */ } /* openfrm */
...@@ -863,18 +821,21 @@ int closefrm(register TABLE *table) ...@@ -863,18 +821,21 @@ 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();
my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR)); if (table->table_name)
table->alias= 0; {
if (table->field) my_free(table->table_name,MYF(0));
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->field= 0; table->fields=0;
} }
delete table->file; delete table->file;
table->file= 0; /* For easier errorchecking */ table->file=0; /* For easyer errorchecking */
hash_free(&table->s->name_hash); hash_free(&table->name_hash);
free_root(&table->mem_root, MYF(0)); free_root(&table->mem_root,MYF(0));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -883,11 +844,8 @@ int closefrm(register TABLE *table) ...@@ -883,11 +844,8 @@ int closefrm(register TABLE *table)
void free_blobs(register TABLE *table) void free_blobs(register TABLE *table)
{ {
uint *ptr, *end; for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ; (*ptr)->free();
ptr != end ;
ptr++)
((Field_blob*) table->field[*ptr])->free();
} }
...@@ -1035,7 +993,6 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1035,7 +993,6 @@ 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) {
...@@ -1046,11 +1003,11 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1046,11 +1003,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, real_name); my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->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:
{ {
...@@ -1059,7 +1016,7 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1059,7 +1016,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,real_name,form_dev,datext,2),my_errno); fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
break; break;
} }
case 5: case 5:
...@@ -1073,13 +1030,13 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1073,13 +1030,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, real_name); MYF(0), csname, form->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;
...@@ -1088,7 +1045,7 @@ static void frm_error(int error, TABLE *form, const char *name, ...@@ -1088,7 +1045,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 separated with some char. differents types are separated ** typeparts sepearated with some char. differents types are separated
** with a '\0' ** with a '\0'
*/ */
...@@ -1150,27 +1107,22 @@ TYPELIB *typelib(List<String> &strings) ...@@ -1150,27 +1107,22 @@ 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
NOTES ** This is needed because in some .frm fields 'fieldnr' was saved wrong
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, fields; uint i,pos;
pos=0; pos=0;
fields= form->s->fields;
for (field=form->field, i=1 ; i<= fields ; i++,field++) for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
{ {
if ((*field)->offset() == start) if ((*field)->offset() == start)
{ {
...@@ -1185,7 +1137,7 @@ static uint find_field(TABLE *form,uint start,uint length) ...@@ -1185,7 +1137,7 @@ static uint find_field(TABLE *form,uint start,uint length)
} }
/* Check that the integer is in the internal */ /* Check that the integer is in the internvall */
int set_zone(register int nr, int min_zone, int max_zone) int set_zone(register int nr, int min_zone, int max_zone)
{ {
...@@ -1249,7 +1201,7 @@ void append_unescaped(String *res, const char *pos, uint length) ...@@ -1249,7 +1201,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 readability */ res->append('\\'); /* This gives better readbility */
res->append('r'); res->append('r');
break; break;
case '\\': case '\\':
...@@ -1294,11 +1246,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, ...@@ -1294,11 +1246,7 @@ 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);
/* header */ fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3; // 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 */
...@@ -1338,20 +1286,17 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, ...@@ -1338,20 +1286,17 @@ 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->max_rows= share->max_rows; create_info->min_rows=table->min_rows;
create_info->min_rows= share->min_rows; create_info->table_options=table->db_create_options;
create_info->table_options= share->db_create_options; create_info->avg_row_length=table->avg_row_length;
create_info->avg_row_length= share->avg_row_length; create_info->row_type=table->row_type;
create_info->row_type= share->row_type; create_info->raid_type=table->raid_type;
create_info->raid_type= share->raid_type; create_info->raid_chunks=table->raid_chunks;
create_info->raid_chunks= share->raid_chunks; create_info->raid_chunksize=table->raid_chunksize;
create_info->raid_chunksize= share->raid_chunksize; create_info->default_table_charset=table->table_charset;
create_info->default_table_charset= share->table_charset;
create_info->table_charset= 0; create_info->table_charset= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1566,522 +1511,12 @@ db_type get_table_type(const char *name) ...@@ -1566,522 +1511,12 @@ 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 && head[2] != FRM_VER+1 && head[2] != FRM_VER+3))
(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