mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1594 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1594 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation; either version 2 of the License, or
 | 
						|
   (at your option) any later version.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
						|
 | 
						|
 | 
						|
/* Some general useful functions */
 | 
						|
 | 
						|
#include "mysql_priv.h"
 | 
						|
#include <errno.h>
 | 
						|
#include <m_ctype.h>
 | 
						|
 | 
						|
 | 
						|
	/* Functions defined in this file */
 | 
						|
 | 
						|
static void frm_error(int error,TABLE *form,const char *name,
 | 
						|
                      int errortype, int errarg);
 | 
						|
static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
 | 
						|
			      uint types, char **names);
 | 
						|
static uint find_field(TABLE *form,uint start,uint length);
 | 
						|
 | 
						|
 | 
						|
static byte* get_field_name(Field **buff,uint *length,
 | 
						|
			    my_bool not_used __attribute__((unused)))
 | 
						|
{
 | 
						|
  *length= (uint) strlen((*buff)->field_name);
 | 
						|
  return (byte*) (*buff)->field_name;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Open a .frm file 
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    openfrm()
 | 
						|
 | 
						|
    name           path to table-file "db/name"
 | 
						|
    alias          alias for table
 | 
						|
    db_stat        open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..)
 | 
						|
                   can be 0 (example in ha_example_table)
 | 
						|
    prgflag        READ_ALL etc..
 | 
						|
    ha_open_flags  HA_OPEN_ABORT_IF_LOCKED etc..
 | 
						|
    outparam       result table
 | 
						|
 | 
						|
  RETURN VALUES
 | 
						|
   0	ok
 | 
						|
   1	Error (see frm_error)
 | 
						|
   2    Error (see frm_error)
 | 
						|
   3    Wrong data in .frm file
 | 
						|
   4    Error (see frm_error)
 | 
						|
   5    Error (see frm_error: charset unavailable)
 | 
						|
   6    Unknown .frm version
 | 
						|
*/
 | 
						|
 | 
						|
int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
 | 
						|
	    uint ha_open_flags, TABLE *outparam)
 | 
						|
{
 | 
						|
  reg1 uint i;
 | 
						|
  reg2 uchar *strpos;
 | 
						|
  int	 j,error, errarg= 0;
 | 
						|
  uint	 rec_buff_length,n_length,int_length,records,key_parts,keys,
 | 
						|
         interval_count,interval_parts,read_length,db_create_options;
 | 
						|
  uint	 key_info_length, com_length;
 | 
						|
  ulong  pos;
 | 
						|
  char	 index_file[FN_REFLEN], *names, *keynames, *comment_pos;
 | 
						|
  uchar  head[288],*disk_buff,new_field_pack_flag;
 | 
						|
  my_string record;
 | 
						|
  const char **int_array;
 | 
						|
  bool	 use_hash, null_field_first;
 | 
						|
  bool   error_reported= FALSE;
 | 
						|
  File	 file;
 | 
						|
  Field  **field_ptr,*reg_field;
 | 
						|
  KEY	 *keyinfo;
 | 
						|
  KEY_PART_INFO *key_part;
 | 
						|
  uchar *null_pos;
 | 
						|
  uint null_bit, new_frm_ver, field_pack_length;
 | 
						|
  SQL_CRYPT *crypted=0;
 | 
						|
  MEM_ROOT **root_ptr, *old_root;
 | 
						|
  DBUG_ENTER("openfrm");
 | 
						|
  DBUG_PRINT("enter",("name: '%s'  form: %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);
 | 
						|
  root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
 | 
						|
  old_root= *root_ptr;
 | 
						|
  *root_ptr= &outparam->mem_root;
 | 
						|
 | 
						|
  outparam->real_name=strdup_root(&outparam->mem_root,
 | 
						|
                                  name+dirname_length(name));
 | 
						|
  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,MY_UNPACK_FILENAME),
 | 
						|
		    O_RDONLY | O_SHARE,
 | 
						|
		    MYF(0)))
 | 
						|
      < 0)
 | 
						|
  {
 | 
						|
    goto err_end; /* purecov: inspected */
 | 
						|
  }
 | 
						|
  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;
 | 
						|
  if (head[0] != (uchar) 254 || head[1] != 1)
 | 
						|
    goto err_not_open;				/* purecov: inspected */
 | 
						|
  if (head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3)
 | 
						|
  {
 | 
						|
    error= 6;
 | 
						|
    goto err_not_open;				/* purecov: inspected */
 | 
						|
  }
 | 
						|
  new_field_pack_flag=head[27];
 | 
						|
  new_frm_ver= (head[2] - FRM_VER);
 | 
						|
  field_pack_length= new_frm_ver < 2 ? 11 : 17;
 | 
						|
 | 
						|
  error=3;
 | 
						|
  if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
 | 
						|
    goto err_not_open;				/* purecov: inspected */
 | 
						|
  *fn_ext(index_file)='\0';			// Remove .frm extension
 | 
						|
 | 
						|
  outparam->frm_version= head[2];
 | 
						|
  outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
 | 
						|
  outparam->db_create_options=db_create_options=uint2korr(head+30);
 | 
						|
  outparam->db_options_in_use=outparam->db_create_options;
 | 
						|
  null_field_first=0;
 | 
						|
  if (!head[32])				// New frm file in 3.23
 | 
						|
  {
 | 
						|
    outparam->avg_row_length=uint4korr(head+34);
 | 
						|
    outparam->row_type=(row_type) head[40];
 | 
						|
    outparam->raid_type=   head[41];
 | 
						|
    outparam->raid_chunks= head[42];
 | 
						|
    outparam->raid_chunksize= uint4korr(head+43);
 | 
						|
    outparam->table_charset=get_charset((uint) head[38],MYF(0));
 | 
						|
    null_field_first=1;
 | 
						|
  }
 | 
						|
  if (!outparam->table_charset)
 | 
						|
  {
 | 
						|
    /* unknown charset in head[38] or pre-3.23 frm */
 | 
						|
    if (use_mb(default_charset_info))
 | 
						|
    {
 | 
						|
      /* Warn that we may be changing the size of character columns */
 | 
						|
      sql_print_warning("'%s' had no or invalid character set, "
 | 
						|
                        "and default character set is multi-byte, "
 | 
						|
                        "so character column sizes may have changed",
 | 
						|
                        name);
 | 
						|
    }
 | 
						|
    outparam->table_charset=default_charset_info;
 | 
						|
  }
 | 
						|
  outparam->db_record_offset=1;
 | 
						|
  if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
 | 
						|
    outparam->blob_ptr_size=portable_sizeof_char_ptr;
 | 
						|
  /* Set temporaryly a good value for db_low_byte_first */
 | 
						|
  outparam->db_low_byte_first=test(outparam->db_type != DB_TYPE_ISAM);
 | 
						|
  error=4;
 | 
						|
  outparam->max_rows=uint4korr(head+18);
 | 
						|
  outparam->min_rows=uint4korr(head+22);
 | 
						|
 | 
						|
  /* Read keyinformation */
 | 
						|
  key_info_length= (uint) uint2korr(head+28);
 | 
						|
  VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
 | 
						|
  if (read_string(file,(gptr*) &disk_buff,key_info_length))
 | 
						|
    goto err_not_open; /* purecov: inspected */
 | 
						|
  if (disk_buff[0] & 0x80)
 | 
						|
  {
 | 
						|
    outparam->keys=      keys=      (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
 | 
						|
    outparam->key_parts= key_parts= uint2korr(disk_buff+2);
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    outparam->keys=      keys=      disk_buff[0];
 | 
						|
    outparam->key_parts= key_parts= disk_buff[1];
 | 
						|
  }
 | 
						|
  outparam->keys_for_keyread.init(0);
 | 
						|
  outparam->keys_in_use.init(keys);
 | 
						|
  outparam->read_only_keys.init(keys);
 | 
						|
  outparam->quick_keys.init();
 | 
						|
  outparam->used_keys.init();
 | 
						|
  outparam->keys_in_use_for_query.init();
 | 
						|
 | 
						|
  n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
 | 
						|
  if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
 | 
						|
				    n_length+uint2korr(disk_buff+4))))
 | 
						|
    goto err_not_open; /* purecov: inspected */
 | 
						|
  bzero((char*) keyinfo,n_length);
 | 
						|
  outparam->key_info=keyinfo;
 | 
						|
  key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
 | 
						|
  strpos=disk_buff+6;
 | 
						|
 | 
						|
  ulong *rec_per_key;
 | 
						|
  if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root,
 | 
						|
					 sizeof(ulong*)*key_parts)))
 | 
						|
    goto err_not_open;
 | 
						|
 | 
						|
  for (i=0 ; i < keys ; i++, keyinfo++)
 | 
						|
  {
 | 
						|
    if (new_frm_ver == 3)
 | 
						|
    {
 | 
						|
      keyinfo->flags=	   (uint) uint2korr(strpos) ^ HA_NOSAME;
 | 
						|
      keyinfo->key_length= (uint) uint2korr(strpos+2);
 | 
						|
      keyinfo->key_parts=  (uint) strpos[4];
 | 
						|
      keyinfo->algorithm=  (enum ha_key_alg) strpos[5];
 | 
						|
      strpos+=8;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      keyinfo->flags=	 ((uint) strpos[0]) ^ HA_NOSAME;
 | 
						|
      keyinfo->key_length= (uint) uint2korr(strpos+1);
 | 
						|
      keyinfo->key_parts=  (uint) strpos[3];
 | 
						|
      keyinfo->algorithm= HA_KEY_ALG_UNDEF;
 | 
						|
      strpos+=4;
 | 
						|
    }
 | 
						|
 | 
						|
    keyinfo->key_part=	 key_part;
 | 
						|
    keyinfo->rec_per_key= rec_per_key;
 | 
						|
    for (j=keyinfo->key_parts ; j-- ; key_part++)
 | 
						|
    {
 | 
						|
      *rec_per_key++=0;
 | 
						|
      key_part->fieldnr=	(uint16) (uint2korr(strpos) & FIELD_NR_MASK);
 | 
						|
      key_part->offset= (uint) uint2korr(strpos+2)-1;
 | 
						|
      key_part->key_type=	(uint) uint2korr(strpos+5);
 | 
						|
      // key_part->field=	(Field*) 0;	// Will be fixed later
 | 
						|
      if (new_frm_ver >= 1)
 | 
						|
      {
 | 
						|
	key_part->key_part_flag= *(strpos+4);
 | 
						|
	key_part->length=	(uint) uint2korr(strpos+7);
 | 
						|
	strpos+=9;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
	key_part->length=	*(strpos+4);
 | 
						|
	key_part->key_part_flag=0;
 | 
						|
	if (key_part->length > 128)
 | 
						|
	{
 | 
						|
	  key_part->length&=127;		/* purecov: inspected */
 | 
						|
	  key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */
 | 
						|
	}
 | 
						|
	strpos+=7;
 | 
						|
      }
 | 
						|
      key_part->store_length=key_part->length;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  keynames=(char*) key_part;
 | 
						|
  strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
 | 
						|
 | 
						|
  outparam->reclength = uint2korr((head+16));
 | 
						|
  if (*(head+26) == 1)
 | 
						|
    outparam->system=1;				/* one-record-database */
 | 
						|
#ifdef HAVE_CRYPTED_FRM
 | 
						|
  else if (*(head+26) == 2)
 | 
						|
  {
 | 
						|
    *root_ptr= old_root
 | 
						|
    crypted=get_crypt_for_frm();
 | 
						|
    *root_ptr= &outparam->mem_root;
 | 
						|
    outparam->crypted=1;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  /* Allocate handler */
 | 
						|
  if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
 | 
						|
    goto err_not_open;
 | 
						|
 | 
						|
  error=4;
 | 
						|
  outparam->reginfo.lock_type= TL_UNLOCK;
 | 
						|
  outparam->current_lock=F_UNLCK;
 | 
						|
  if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2;
 | 
						|
  else records=1;
 | 
						|
  if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
 | 
						|
  /* QQ: TODO, remove the +1 from below */
 | 
						|
  rec_buff_length=ALIGN_SIZE(outparam->reclength+1+
 | 
						|
			     outparam->file->extra_rec_buf_length());
 | 
						|
  if (!(outparam->record[0]= (byte*)
 | 
						|
	(record = (char *) alloc_root(&outparam->mem_root,
 | 
						|
				      rec_buff_length * records))))
 | 
						|
    goto err_not_open;				/* purecov: inspected */
 | 
						|
  record[outparam->reclength]=0;		// For purify and ->c_ptr()
 | 
						|
  outparam->rec_buff_length=rec_buff_length;
 | 
						|
  if (my_pread(file,(byte*) record,(uint) outparam->reclength,
 | 
						|
	       (ulong) (uint2korr(head+6)+
 | 
						|
                        ((uint2korr(head+14) == 0xffff ?
 | 
						|
                            uint4korr(head+47) : uint2korr(head+14)))),
 | 
						|
	       MYF(MY_NABP)))
 | 
						|
    goto err_not_open; /* purecov: inspected */
 | 
						|
  /* HACK: table->record[2] is used instead of table->default_values here */
 | 
						|
  for (i=0 ; i < records ; i++, record+=rec_buff_length)
 | 
						|
  {
 | 
						|
    outparam->record[i]=(byte*) record;
 | 
						|
    if (i)
 | 
						|
      memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
 | 
						|
  }
 | 
						|
 | 
						|
  if (records == 2)
 | 
						|
  {						/* fix for select */
 | 
						|
    outparam->default_values=outparam->record[1];
 | 
						|
    if (db_stat & HA_READ_ONLY)
 | 
						|
      outparam->record[1]=outparam->record[0]; /* purecov: inspected */
 | 
						|
  }
 | 
						|
  outparam->insert_values=0;                   /* for INSERT ... UPDATE */
 | 
						|
 | 
						|
  VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
 | 
						|
  if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
 | 
						|
#ifdef HAVE_CRYPTED_FRM
 | 
						|
  if (crypted)
 | 
						|
  {
 | 
						|
    crypted->decode((char*) head+256,288-256);
 | 
						|
    if (sint2korr(head+284) != 0)		// Should be 0
 | 
						|
      goto err_not_open;			// Wrong password
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  outparam->fields= uint2korr(head+258);
 | 
						|
  pos=uint2korr(head+260);			/* Length of all screens */
 | 
						|
  n_length=uint2korr(head+268);
 | 
						|
  interval_count=uint2korr(head+270);
 | 
						|
  interval_parts=uint2korr(head+272);
 | 
						|
  int_length=uint2korr(head+274);
 | 
						|
  outparam->null_fields=uint2korr(head+282);
 | 
						|
  com_length=uint2korr(head+284);
 | 
						|
  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, outparam->keys,n_length,int_length, com_length));
 | 
						|
 | 
						|
  if (!(field_ptr = (Field **)
 | 
						|
	alloc_root(&outparam->mem_root,
 | 
						|
		   (uint) ((outparam->fields+1)*sizeof(Field*)+
 | 
						|
			   interval_count*sizeof(TYPELIB)+
 | 
						|
			   (outparam->fields+interval_parts+
 | 
						|
			    keys+3)*sizeof(my_string)+
 | 
						|
			   (n_length+int_length+com_length)))))
 | 
						|
    goto err_not_open; /* purecov: inspected */
 | 
						|
 | 
						|
  outparam->field=field_ptr;
 | 
						|
  read_length=(uint) (outparam->fields * field_pack_length +
 | 
						|
		      pos+ (uint) (n_length+int_length+com_length));
 | 
						|
  if (read_string(file,(gptr*) &disk_buff,read_length))
 | 
						|
    goto err_not_open; /* purecov: inspected */
 | 
						|
#ifdef HAVE_CRYPTED_FRM
 | 
						|
  if (crypted)
 | 
						|
  {
 | 
						|
    crypted->decode((char*) disk_buff,read_length);
 | 
						|
    delete crypted;
 | 
						|
    crypted=0;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  strpos= disk_buff+pos;
 | 
						|
 | 
						|
  outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1);
 | 
						|
  int_array= (const char **) (outparam->intervals+interval_count);
 | 
						|
  names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
 | 
						|
  if (!interval_count)
 | 
						|
    outparam->intervals=0;			// For better debugging
 | 
						|
  memcpy((char*) names, strpos+(outparam->fields*field_pack_length),
 | 
						|
	 (uint) (n_length+int_length));
 | 
						|
  comment_pos=names+(n_length+int_length);
 | 
						|
  memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
 | 
						|
 | 
						|
  fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
 | 
						|
  fix_type_pointers(&int_array,outparam->intervals,interval_count,
 | 
						|
		    &names);
 | 
						|
 | 
						|
  {
 | 
						|
    /* Set ENUM and SET lengths */
 | 
						|
    TYPELIB *interval;
 | 
						|
    for (interval= outparam->intervals;
 | 
						|
         interval < outparam->intervals + interval_count;
 | 
						|
         interval++)
 | 
						|
    {
 | 
						|
      uint count= (uint) (interval->count + 1) * sizeof(uint);
 | 
						|
      if (!(interval->type_lengths= (uint *) alloc_root(&outparam->mem_root,
 | 
						|
                                                        count)))
 | 
						|
        goto err_not_open;
 | 
						|
      for (count= 0; count < interval->count; count++)
 | 
						|
      {
 | 
						|
        char *val= (char*) interval->type_names[count];
 | 
						|
        interval->type_lengths[count]= strlen(val);
 | 
						|
        /*
 | 
						|
          Replace all ',' symbols with NAMES_SEP_CHAR.
 | 
						|
          See the comment in unireg.cc, pack_fields() function
 | 
						|
          for details.
 | 
						|
        */
 | 
						|
        for (uint cnt= 0 ; cnt < interval->type_lengths[count] ; cnt++)
 | 
						|
        {
 | 
						|
          char c= val[cnt];
 | 
						|
          if (c == ',')
 | 
						|
            val[cnt]= NAMES_SEP_CHAR;
 | 
						|
        }       
 | 
						|
      }
 | 
						|
      interval->type_lengths[count]= 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (keynames)
 | 
						|
    fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
 | 
						|
  VOID(my_close(file,MYF(MY_WME)));
 | 
						|
  file= -1;
 | 
						|
 | 
						|
  record=(char*) outparam->record[0]-1;		/* Fieldstart = 1 */
 | 
						|
  if (null_field_first)
 | 
						|
  {
 | 
						|
    outparam->null_flags=null_pos=(uchar*) record+1;
 | 
						|
    null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
 | 
						|
    outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    outparam->null_bytes=(outparam->null_fields+7)/8;
 | 
						|
    outparam->null_flags=null_pos=
 | 
						|
      (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
 | 
						|
    null_bit=1;
 | 
						|
  }
 | 
						|
 | 
						|
  use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
 | 
						|
  if (use_hash)
 | 
						|
    use_hash= !hash_init(&outparam->name_hash,
 | 
						|
			 system_charset_info,
 | 
						|
			 outparam->fields,0,0,
 | 
						|
			 (hash_get_key) get_field_name,0,0);
 | 
						|
 | 
						|
  for (i=0 ; i < outparam->fields; i++, strpos+=field_pack_length, field_ptr++)
 | 
						|
  {
 | 
						|
    uint pack_flag, interval_nr, unireg_type, recpos, field_length;
 | 
						|
    enum_field_types field_type;
 | 
						|
    CHARSET_INFO *charset=NULL;
 | 
						|
    Field::geometry_type geom_type= Field::GEOM_GEOMETRY;
 | 
						|
    LEX_STRING comment;
 | 
						|
 | 
						|
    if (new_frm_ver == 3)
 | 
						|
    {
 | 
						|
      /* new frm file in 4.1 */
 | 
						|
      field_length= uint2korr(strpos+3);
 | 
						|
      recpos=	    uint3korr(strpos+5);
 | 
						|
      pack_flag=    uint2korr(strpos+8);
 | 
						|
      unireg_type=  (uint) strpos[10];
 | 
						|
      interval_nr=  (uint) strpos[12];
 | 
						|
 | 
						|
      uint comment_length=uint2korr(strpos+15);
 | 
						|
      field_type=(enum_field_types) (uint) strpos[13];
 | 
						|
 | 
						|
      // charset and geometry_type share the same byte in frm
 | 
						|
      if (field_type == FIELD_TYPE_GEOMETRY)
 | 
						|
      {
 | 
						|
#ifdef HAVE_SPATIAL
 | 
						|
	geom_type= (Field::geometry_type) strpos[14];
 | 
						|
	charset= &my_charset_bin;
 | 
						|
#else
 | 
						|
	error= 4;  // unsupported field type
 | 
						|
	goto err_not_open;
 | 
						|
#endif
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        if (!strpos[14])
 | 
						|
          charset= &my_charset_bin;
 | 
						|
        else if (!(charset=get_charset((uint) strpos[14], MYF(0))))
 | 
						|
        {
 | 
						|
          error= 5; // Unknown or unavailable charset
 | 
						|
          errarg= (int) strpos[14];
 | 
						|
          goto err_not_open;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (!comment_length)
 | 
						|
      {
 | 
						|
	comment.str= (char*) "";
 | 
						|
	comment.length=0;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
	comment.str=    (char*) comment_pos;
 | 
						|
	comment.length= comment_length;
 | 
						|
	comment_pos+=   comment_length;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      field_length= (uint) strpos[3];
 | 
						|
      recpos=	    uint2korr(strpos+4),
 | 
						|
      pack_flag=    uint2korr(strpos+6);
 | 
						|
      unireg_type=  (uint) strpos[8];
 | 
						|
      interval_nr=  (uint) strpos[10];
 | 
						|
 | 
						|
      /* old frm file */
 | 
						|
      field_type= (enum_field_types) f_packtype(pack_flag);
 | 
						|
      if (f_is_binary(pack_flag))
 | 
						|
      {
 | 
						|
        /*
 | 
						|
          Try to choose the best 4.1 type:
 | 
						|
          - for 4.0 "CHAR(N) BINARY" or "VARCHAR(N) BINARY" 
 | 
						|
            try to find a binary collation for character set.
 | 
						|
          - for other types (e.g. BLOB) just use my_charset_bin. 
 | 
						|
        */
 | 
						|
        if (!f_is_blob(pack_flag))
 | 
						|
        {
 | 
						|
          // 3.23 or 4.0 string
 | 
						|
          if (!(charset= get_charset_by_csname(outparam->table_charset->csname,
 | 
						|
                                               MY_CS_BINSORT, MYF(0))))
 | 
						|
            charset= &my_charset_bin;
 | 
						|
        }
 | 
						|
        else
 | 
						|
          charset= &my_charset_bin;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        charset= outparam->table_charset;
 | 
						|
      bzero((char*) &comment, sizeof(comment));
 | 
						|
    }
 | 
						|
 | 
						|
    if (interval_nr && charset->mbminlen > 1)
 | 
						|
    {
 | 
						|
      /* Unescape UCS2 intervals from HEX notation */
 | 
						|
      TYPELIB *interval= outparam->intervals + interval_nr - 1;
 | 
						|
      unhex_type2(interval);
 | 
						|
    }
 | 
						|
    
 | 
						|
    *field_ptr=reg_field=
 | 
						|
      make_field(record+recpos,
 | 
						|
		 (uint32) field_length,
 | 
						|
		 null_pos,null_bit,
 | 
						|
		 pack_flag,
 | 
						|
		 field_type,
 | 
						|
		 charset,
 | 
						|
		 geom_type,
 | 
						|
		 (Field::utype) MTYP_TYPENR(unireg_type),
 | 
						|
		 (interval_nr ?
 | 
						|
		  outparam->intervals+interval_nr-1 :
 | 
						|
		  (TYPELIB*) 0),
 | 
						|
		 outparam->fieldnames.type_names[i],
 | 
						|
		 outparam);
 | 
						|
    if (!reg_field)				// Not supported field type
 | 
						|
    {
 | 
						|
      error= 4;
 | 
						|
      goto err_not_open;			/* purecov: inspected */
 | 
						|
    }
 | 
						|
    reg_field->comment=comment;
 | 
						|
    if (!(reg_field->flags & NOT_NULL_FLAG))
 | 
						|
    {
 | 
						|
      if ((null_bit<<=1) == 256)
 | 
						|
      {
 | 
						|
	null_pos++;
 | 
						|
	null_bit=1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (reg_field->unireg_check == Field::NEXT_NUMBER)
 | 
						|
      outparam->found_next_number_field= reg_field;
 | 
						|
    if (outparam->timestamp_field == reg_field)
 | 
						|
      outparam->timestamp_field_offset=i;
 | 
						|
    if (use_hash)
 | 
						|
      (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail
 | 
						|
  }
 | 
						|
  *field_ptr=0;					// End marker
 | 
						|
 | 
						|
  /* Fix key->name and key_part->field */
 | 
						|
  if (key_parts)
 | 
						|
  {
 | 
						|
    uint primary_key=(uint) (find_type((char*) primary_key_name,
 | 
						|
				       &outparam->keynames, 3) - 1);
 | 
						|
    uint ha_option=outparam->file->table_flags();
 | 
						|
    keyinfo=outparam->key_info;
 | 
						|
    key_part=keyinfo->key_part;
 | 
						|
 | 
						|
    for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
 | 
						|
    {
 | 
						|
      uint usable_parts=0;
 | 
						|
      keyinfo->name=(char*) outparam->keynames.type_names[key];
 | 
						|
      /* Fix fulltext keys for old .frm files */
 | 
						|
      if (outparam->key_info[key].flags & HA_FULLTEXT)
 | 
						|
	outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT;
 | 
						|
 | 
						|
      if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
 | 
						|
      {
 | 
						|
	/*
 | 
						|
	  If the UNIQUE key doesn't have NULL columns and is not a part key
 | 
						|
	  declare this as a primary key.
 | 
						|
	*/
 | 
						|
	primary_key=key;
 | 
						|
	for (i=0 ; i < keyinfo->key_parts ;i++)
 | 
						|
	{
 | 
						|
	  uint fieldnr= key_part[i].fieldnr;
 | 
						|
	  if (!fieldnr ||
 | 
						|
	      outparam->field[fieldnr-1]->null_ptr ||
 | 
						|
	      outparam->field[fieldnr-1]->key_length() !=
 | 
						|
	      key_part[i].length)
 | 
						|
	  {
 | 
						|
	    primary_key=MAX_KEY;		// Can't be used
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
 | 
						|
      for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
 | 
						|
      {
 | 
						|
	if (new_field_pack_flag <= 1)
 | 
						|
	  key_part->fieldnr=(uint16) find_field(outparam,
 | 
						|
						(uint) key_part->offset,
 | 
						|
						(uint) key_part->length);
 | 
						|
#ifdef EXTRA_DEBUG
 | 
						|
	if (key_part->fieldnr > outparam->fields)
 | 
						|
	  goto err_not_open; // sanity check
 | 
						|
#endif
 | 
						|
	if (key_part->fieldnr)
 | 
						|
	{					// Should always be true !
 | 
						|
	  Field *field=key_part->field=outparam->field[key_part->fieldnr-1];
 | 
						|
	  if (field->null_ptr)
 | 
						|
	  {
 | 
						|
	    key_part->null_offset=(uint) ((byte*) field->null_ptr -
 | 
						|
					  outparam->record[0]);
 | 
						|
	    key_part->null_bit= field->null_bit;
 | 
						|
	    key_part->store_length+=HA_KEY_NULL_LENGTH;
 | 
						|
	    keyinfo->flags|=HA_NULL_PART_KEY;
 | 
						|
	    keyinfo->extra_length+= HA_KEY_NULL_LENGTH;
 | 
						|
	    keyinfo->key_length+= HA_KEY_NULL_LENGTH;
 | 
						|
	  }
 | 
						|
	  if (field->type() == FIELD_TYPE_BLOB ||
 | 
						|
	      field->real_type() == FIELD_TYPE_VAR_STRING)
 | 
						|
	  {
 | 
						|
	    if (field->type() == FIELD_TYPE_BLOB)
 | 
						|
	      key_part->key_part_flag|= HA_BLOB_PART;
 | 
						|
	    keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
 | 
						|
	    key_part->store_length+=HA_KEY_BLOB_LENGTH;
 | 
						|
	    keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
 | 
						|
	    /*
 | 
						|
	      Mark that there may be many matching values for one key
 | 
						|
	      combination ('a', 'a ', 'a  '...)
 | 
						|
	    */
 | 
						|
	    if (!(field->flags & BINARY_FLAG))
 | 
						|
	      keyinfo->flags|= HA_END_SPACE_KEY;
 | 
						|
	  }
 | 
						|
	  if (i == 0 && key != primary_key)
 | 
						|
	    field->flags |=
 | 
						|
	      ((keyinfo->flags & HA_NOSAME) &&
 | 
						|
	       field->key_length() ==
 | 
						|
	       keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
 | 
						|
	  if (i == 0)
 | 
						|
	    field->key_start.set_bit(key);
 | 
						|
	  if (field->key_length() == key_part->length &&
 | 
						|
	      !(field->flags & BLOB_FLAG))
 | 
						|
	  {
 | 
						|
            if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
 | 
						|
            {
 | 
						|
              outparam->read_only_keys.clear_bit(key);
 | 
						|
              outparam->keys_for_keyread.set_bit(key);
 | 
						|
	      field->part_of_key.set_bit(key);
 | 
						|
            }
 | 
						|
	    if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER)
 | 
						|
	      field->part_of_sortkey.set_bit(key);
 | 
						|
	  }
 | 
						|
	  if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
 | 
						|
	      usable_parts == i)
 | 
						|
	    usable_parts++;			// For FILESORT
 | 
						|
	  field->flags|= PART_KEY_FLAG;
 | 
						|
	  if (key == primary_key)
 | 
						|
	  {
 | 
						|
	    field->flags|= PRI_KEY_FLAG;
 | 
						|
	    /*
 | 
						|
	      If this field is part of the primary key and all keys contains
 | 
						|
	      the primary key, then we can use any key to find this column
 | 
						|
	    */
 | 
						|
	    if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
 | 
						|
	      field->part_of_key= outparam->keys_in_use;
 | 
						|
	  }
 | 
						|
	  if (field->key_length() != key_part->length)
 | 
						|
	  {
 | 
						|
	    key_part->key_part_flag|= HA_PART_KEY_SEG;
 | 
						|
	    if (!(field->flags & BLOB_FLAG))
 | 
						|
	    {					// Create a new field
 | 
						|
	      field=key_part->field=field->new_field(&outparam->mem_root,
 | 
						|
						     outparam);
 | 
						|
	      field->field_length=key_part->length;
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	  /*
 | 
						|
	    If the field can be NULL, don't optimize away the test
 | 
						|
	    key_part_column = expression from the WHERE clause
 | 
						|
	    as we need to test for NULL = NULL.
 | 
						|
	  */
 | 
						|
	  if (field->real_maybe_null())
 | 
						|
	    key_part->key_part_flag|= HA_NULL_PART;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{					// Error: shorten key
 | 
						|
	  keyinfo->key_parts=usable_parts;
 | 
						|
	  keyinfo->flags=0;
 | 
						|
	}
 | 
						|
      }
 | 
						|
      keyinfo->usable_key_parts=usable_parts; // Filesort
 | 
						|
 | 
						|
      set_if_bigger(outparam->max_key_length,keyinfo->key_length+
 | 
						|
		    keyinfo->key_parts);
 | 
						|
      outparam->total_key_length+= keyinfo->key_length;
 | 
						|
      /*
 | 
						|
        MERGE tables do not have unique indexes. But every key could be
 | 
						|
        an unique index on the underlying MyISAM table. (Bug #10400)
 | 
						|
      */
 | 
						|
      if ((keyinfo->flags & HA_NOSAME) ||
 | 
						|
          (ha_option & HA_ANY_INDEX_MAY_BE_UNIQUE))
 | 
						|
        set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
 | 
						|
    }
 | 
						|
    if (primary_key < MAX_KEY &&
 | 
						|
	(outparam->keys_in_use.is_set(primary_key)))
 | 
						|
    {
 | 
						|
      outparam->primary_key=primary_key;
 | 
						|
      /*
 | 
						|
	If we are using an integer as the primary key then allow the user to
 | 
						|
	refer to it as '_rowid'
 | 
						|
      */
 | 
						|
      if (outparam->key_info[primary_key].key_parts == 1)
 | 
						|
      {
 | 
						|
	Field *field= outparam->key_info[primary_key].key_part[0].field;
 | 
						|
	if (field && field->result_type() == INT_RESULT)
 | 
						|
	  outparam->rowid_field=field;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
      outparam->primary_key = MAX_KEY; // we do not have a primary key
 | 
						|
  }
 | 
						|
  else
 | 
						|
    outparam->primary_key= MAX_KEY;
 | 
						|
  x_free((gptr) disk_buff);
 | 
						|
  disk_buff=0;
 | 
						|
  if (new_field_pack_flag <= 1)
 | 
						|
  {			/* Old file format with default null */
 | 
						|
    uint null_length=(outparam->null_fields+7)/8;
 | 
						|
    bfill(outparam->null_flags,null_length,255);
 | 
						|
    bfill(outparam->null_flags+outparam->rec_buff_length,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 ((int) (outparam->next_number_index= (uint)
 | 
						|
	       find_ref_key(outparam,reg_field,
 | 
						|
			    &outparam->next_number_key_offset)) < 0)
 | 
						|
    {
 | 
						|
      reg_field->unireg_check=Field::NONE;	/* purecov: inspected */
 | 
						|
      outparam->found_next_number_field=0;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      reg_field->flags|=AUTO_INCREMENT_FLAG;
 | 
						|
  }
 | 
						|
 | 
						|
  if (outparam->blob_fields)
 | 
						|
  {
 | 
						|
    Field **ptr;
 | 
						|
    Field_blob **save;
 | 
						|
 | 
						|
    if (!(outparam->blob_field=save=
 | 
						|
	  (Field_blob**) alloc_root(&outparam->mem_root,
 | 
						|
				    (uint) (outparam->blob_fields+1)*
 | 
						|
				    sizeof(Field_blob*))))
 | 
						|
      goto err_not_open;
 | 
						|
    for (ptr=outparam->field ; *ptr ; ptr++)
 | 
						|
    {
 | 
						|
      if ((*ptr)->flags & BLOB_FLAG)
 | 
						|
	(*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 initialzed;  Open the table */
 | 
						|
  error=2;
 | 
						|
  if (db_stat)
 | 
						|
  {
 | 
						|
    int err;
 | 
						|
    unpack_filename(index_file,index_file);
 | 
						|
    if ((err=(outparam->file->
 | 
						|
	      ha_open(index_file,
 | 
						|
		      (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
 | 
						|
		      (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
 | 
						|
		       ((db_stat & HA_WAIT_IF_LOCKED) ||
 | 
						|
			(specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
 | 
						|
		       HA_OPEN_WAIT_IF_LOCKED :
 | 
						|
		       (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
 | 
						|
		       HA_OPEN_ABORT_IF_LOCKED :
 | 
						|
		       HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
 | 
						|
    {
 | 
						|
      /* Set a flag if the table is crashed and it can be auto. repaired */
 | 
						|
      outparam->crashed=((err == HA_ERR_CRASHED_ON_USAGE) &&
 | 
						|
			 outparam->file->auto_repair() &&
 | 
						|
			 !(ha_open_flags & HA_OPEN_FOR_REPAIR));
 | 
						|
 | 
						|
      if (err==HA_ERR_NO_SUCH_TABLE)
 | 
						|
      {
 | 
						|
	/* The table did not exists in storage engine, use same error message
 | 
						|
	   as if the .frm file didn't exist */
 | 
						|
	error= 1;
 | 
						|
	my_errno= ENOENT;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        outparam->file->print_error(err, MYF(0));
 | 
						|
        error_reported= TRUE;
 | 
						|
      }
 | 
						|
      goto err_not_open; /* purecov: inspected */
 | 
						|
    }
 | 
						|
  }
 | 
						|
  outparam->db_low_byte_first=outparam->file->low_byte_first();
 | 
						|
 | 
						|
  *root_ptr= old_root;
 | 
						|
  opened_tables++;
 | 
						|
#ifndef DBUG_OFF
 | 
						|
  if (use_hash)
 | 
						|
    (void) hash_check(&outparam->name_hash);
 | 
						|
#endif
 | 
						|
  DBUG_RETURN (0);
 | 
						|
 | 
						|
 err_not_open:
 | 
						|
  x_free((gptr) disk_buff);
 | 
						|
  if (file > 0)
 | 
						|
    VOID(my_close(file,MYF(MY_WME)));
 | 
						|
 | 
						|
 err_end:					/* Here when no file */
 | 
						|
  delete crypted;
 | 
						|
  *root_ptr= old_root;
 | 
						|
  if (!error_reported)
 | 
						|
    frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg);
 | 
						|
  delete outparam->file;
 | 
						|
  outparam->file=0;				// For easyer errorchecking
 | 
						|
  outparam->db_stat=0;
 | 
						|
  hash_free(&outparam->name_hash);
 | 
						|
  free_root(&outparam->mem_root,MYF(0));
 | 
						|
  my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
 | 
						|
  DBUG_RETURN (error);
 | 
						|
} /* openfrm */
 | 
						|
 | 
						|
 | 
						|
	/* close a .frm file and it's tables */
 | 
						|
 | 
						|
int closefrm(register TABLE *table)
 | 
						|
{
 | 
						|
  int error=0;
 | 
						|
  DBUG_ENTER("closefrm");
 | 
						|
  if (table->db_stat)
 | 
						|
    error=table->file->close();
 | 
						|
  if (table->table_name)
 | 
						|
  {
 | 
						|
    my_free(table->table_name,MYF(0));
 | 
						|
    table->table_name=0;
 | 
						|
  }
 | 
						|
  if (table->fields)
 | 
						|
  {
 | 
						|
    for (Field **ptr=table->field ; *ptr ; ptr++)
 | 
						|
      delete *ptr;
 | 
						|
    table->fields=0;
 | 
						|
  }
 | 
						|
  delete table->file;
 | 
						|
  table->file=0;				/* For easyer errorchecking */
 | 
						|
  hash_free(&table->name_hash);
 | 
						|
  free_root(&table->mem_root,MYF(0));
 | 
						|
  DBUG_RETURN(error);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Deallocate temporary blob storage */
 | 
						|
 | 
						|
void free_blobs(register TABLE *table)
 | 
						|
{
 | 
						|
  for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
 | 
						|
    (*ptr)->free();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
	/* Find where a form starts */
 | 
						|
	/* if formname is NullS then only formnames is read */
 | 
						|
 | 
						|
ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
 | 
						|
{
 | 
						|
  uint a_length,names,length;
 | 
						|
  uchar *pos,*buf;
 | 
						|
  ulong ret_value=0;
 | 
						|
  DBUG_ENTER("get_form_pos");
 | 
						|
 | 
						|
  names=uint2korr(head+8);
 | 
						|
  a_length=(names+2)*sizeof(my_string);		/* Room for two extra */
 | 
						|
 | 
						|
  if (!save_names)
 | 
						|
    a_length=0;
 | 
						|
  else
 | 
						|
    save_names->type_names=0;			/* Clear if error */
 | 
						|
 | 
						|
  if (names)
 | 
						|
  {
 | 
						|
    length=uint2korr(head+4);
 | 
						|
    VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
 | 
						|
    if (!(buf= (uchar*) my_malloc((uint) length+a_length+names*4,
 | 
						|
				  MYF(MY_WME))) ||
 | 
						|
	my_read(file,(byte*) buf+a_length,(uint) (length+names*4),
 | 
						|
		MYF(MY_NABP)))
 | 
						|
    {						/* purecov: inspected */
 | 
						|
      x_free((gptr) buf);			/* purecov: inspected */
 | 
						|
      DBUG_RETURN(0L);				/* purecov: inspected */
 | 
						|
    }
 | 
						|
    pos= buf+a_length+length;
 | 
						|
    ret_value=uint4korr(pos);
 | 
						|
  }
 | 
						|
  if (! save_names)
 | 
						|
    my_free((gptr) buf,MYF(0));
 | 
						|
  else if (!names)
 | 
						|
    bzero((char*) save_names,sizeof(save_names));
 | 
						|
  else
 | 
						|
  {
 | 
						|
    char *str;
 | 
						|
    str=(char *) (buf+a_length);
 | 
						|
    fix_type_pointers((const char ***) &buf,save_names,1,&str);
 | 
						|
  }
 | 
						|
  DBUG_RETURN(ret_value);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
	/* Read string from a file with malloc */
 | 
						|
 | 
						|
int read_string(File file, gptr *to, uint length)
 | 
						|
{
 | 
						|
  DBUG_ENTER("read_string");
 | 
						|
 | 
						|
  x_free((gptr) *to);
 | 
						|
  if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
 | 
						|
      my_read(file,(byte*) *to,length,MYF(MY_NABP)))
 | 
						|
  {
 | 
						|
    x_free((gptr) *to); /* purecov: inspected */
 | 
						|
    *to= 0; /* purecov: inspected */
 | 
						|
    DBUG_RETURN(1); /* purecov: inspected */
 | 
						|
  }
 | 
						|
  *((char*) *to+length)= '\0';
 | 
						|
  DBUG_RETURN (0);
 | 
						|
} /* read_string */
 | 
						|
 | 
						|
 | 
						|
	/* Add a new form to a form file */
 | 
						|
 | 
						|
ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
 | 
						|
		     const char *newname)
 | 
						|
{
 | 
						|
  uint i,bufflength,maxlength,n_length,length,names;
 | 
						|
  ulong endpos,newpos;
 | 
						|
  char buff[IO_SIZE];
 | 
						|
  uchar *pos;
 | 
						|
  DBUG_ENTER("make_new_entry");
 | 
						|
 | 
						|
  length=(uint) strlen(newname)+1;
 | 
						|
  n_length=uint2korr(fileinfo+4);
 | 
						|
  maxlength=uint2korr(fileinfo+6);
 | 
						|
  names=uint2korr(fileinfo+8);
 | 
						|
  newpos=uint4korr(fileinfo+10);
 | 
						|
 | 
						|
  if (64+length+n_length+(names+1)*4 > maxlength)
 | 
						|
  {						/* Expand file */
 | 
						|
    newpos+=IO_SIZE;
 | 
						|
    int4store(fileinfo+10,newpos);
 | 
						|
    endpos=(ulong) my_seek(file,0L,MY_SEEK_END,MYF(0));/* Copy from file-end */
 | 
						|
    bufflength= (uint) (endpos & (IO_SIZE-1));	/* IO_SIZE is a power of 2 */
 | 
						|
 | 
						|
    while (endpos > maxlength)
 | 
						|
    {
 | 
						|
      VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
 | 
						|
      if (my_read(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
 | 
						|
	DBUG_RETURN(0L);
 | 
						|
      VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
 | 
						|
		   MYF(0)));
 | 
						|
      if ((my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME))))
 | 
						|
	DBUG_RETURN(0);
 | 
						|
      endpos-=bufflength; bufflength=IO_SIZE;
 | 
						|
    }
 | 
						|
    bzero(buff,IO_SIZE);			/* Null new block */
 | 
						|
    VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
 | 
						|
    if (my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
 | 
						|
	DBUG_RETURN(0L);
 | 
						|
    maxlength+=IO_SIZE;				/* Fix old ref */
 | 
						|
    int2store(fileinfo+6,maxlength);
 | 
						|
    for (i=names, pos= (uchar*) *formnames->type_names+n_length-1; i-- ;
 | 
						|
	 pos+=4)
 | 
						|
    {
 | 
						|
      endpos=uint4korr(pos)+IO_SIZE;
 | 
						|
      int4store(pos,endpos);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (n_length == 1 )
 | 
						|
  {						/* First name */
 | 
						|
    length++;
 | 
						|
    VOID(strxmov(buff,"/",newname,"/",NullS));
 | 
						|
  }
 | 
						|
  else
 | 
						|
    VOID(strxmov(buff,newname,"/",NullS)); /* purecov: inspected */
 | 
						|
  VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
 | 
						|
  if (my_write(file,(byte*) buff,(uint) length+1,MYF(MY_NABP+MY_WME)) ||
 | 
						|
      (names && my_write(file,(byte*) (*formnames->type_names+n_length-1),
 | 
						|
			 names*4, MYF(MY_NABP+MY_WME))) ||
 | 
						|
      my_write(file,(byte*) fileinfo+10,(uint) 4,MYF(MY_NABP+MY_WME)))
 | 
						|
    DBUG_RETURN(0L); /* purecov: inspected */
 | 
						|
 | 
						|
  int2store(fileinfo+8,names+1);
 | 
						|
  int2store(fileinfo+4,n_length+length);
 | 
						|
  VOID(my_chsize(file, newpos, 0, MYF(MY_WME)));/* Append file with '\0' */
 | 
						|
  DBUG_RETURN(newpos);
 | 
						|
} /* make_new_entry */
 | 
						|
 | 
						|
 | 
						|
	/* error message when opening a form file */
 | 
						|
 | 
						|
static void frm_error(int error, TABLE *form, const char *name,
 | 
						|
                      myf errortype, int errarg)
 | 
						|
{
 | 
						|
  int err_no;
 | 
						|
  char buff[FN_REFLEN];
 | 
						|
  const char *form_dev="",*datext;
 | 
						|
  DBUG_ENTER("frm_error");
 | 
						|
 | 
						|
  switch (error) {
 | 
						|
  case 1:
 | 
						|
    if (my_errno == ENOENT)
 | 
						|
    {
 | 
						|
      char *db;
 | 
						|
      uint length=dirname_part(buff,name);
 | 
						|
      buff[length-1]=0;
 | 
						|
      db=buff+dirname_length(buff);
 | 
						|
      my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name);
 | 
						|
    }
 | 
						|
    else
 | 
						|
      my_error(ER_FILE_NOT_FOUND,errortype,
 | 
						|
	       fn_format(buff,name,form_dev,reg_ext,0),my_errno);
 | 
						|
    break;
 | 
						|
  case 2:
 | 
						|
  {
 | 
						|
    datext= form->file ? *form->file->bas_ext() : "";
 | 
						|
    datext= datext==NullS ? "" : datext;
 | 
						|
    err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
 | 
						|
      ER_FILE_USED : ER_CANT_OPEN_FILE;
 | 
						|
    my_error(err_no,errortype,
 | 
						|
	     fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 5:
 | 
						|
  {
 | 
						|
    const char *csname= get_charset_name((uint) errarg);
 | 
						|
    char tmp[10];
 | 
						|
    if (!csname || csname[0] =='?')
 | 
						|
    {
 | 
						|
      my_snprintf(tmp, sizeof(tmp), "#%d", errarg);
 | 
						|
      csname= tmp;
 | 
						|
    }
 | 
						|
    my_printf_error(ER_UNKNOWN_COLLATION,
 | 
						|
                    "Unknown collation '%s' in table '%-.64s' definition", 
 | 
						|
                    MYF(0), csname, form->real_name);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 6:
 | 
						|
    my_printf_error(ER_NOT_FORM_FILE,
 | 
						|
                    "Table '%-.64s' was created with a different version "
 | 
						|
                    "of MySQL and cannot be read",
 | 
						|
                    MYF(0), name);
 | 
						|
    break;
 | 
						|
  default:				/* Better wrong error than none */
 | 
						|
  case 4:
 | 
						|
    my_error(ER_NOT_FORM_FILE,errortype,
 | 
						|
	     fn_format(buff,name,form_dev,reg_ext,0));
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
} /* frm_error */
 | 
						|
 | 
						|
 | 
						|
	/*
 | 
						|
	** fix a str_type to a array type
 | 
						|
	** typeparts sepearated with some char. differents types are separated
 | 
						|
	** with a '\0'
 | 
						|
	*/
 | 
						|
 | 
						|
static void
 | 
						|
fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types,
 | 
						|
		  char **names)
 | 
						|
{
 | 
						|
  char *type_name, *ptr;
 | 
						|
  char chr;
 | 
						|
 | 
						|
  ptr= *names;
 | 
						|
  while (types--)
 | 
						|
  {
 | 
						|
    point_to_type->name=0;
 | 
						|
    point_to_type->type_names= *array;
 | 
						|
 | 
						|
    if ((chr= *ptr))			/* Test if empty type */
 | 
						|
    {
 | 
						|
      while ((type_name=strchr(ptr+1,chr)) != NullS)
 | 
						|
      {
 | 
						|
	*((*array)++) = ptr+1;
 | 
						|
	*type_name= '\0';		/* End string */
 | 
						|
	ptr=type_name;
 | 
						|
      }
 | 
						|
      ptr+=2;				/* Skip end mark and last 0 */
 | 
						|
    }
 | 
						|
    else
 | 
						|
      ptr++;
 | 
						|
    point_to_type->count= (uint) (*array - point_to_type->type_names);
 | 
						|
    point_to_type++;
 | 
						|
    *((*array)++)= NullS;		/* End of type */
 | 
						|
  }
 | 
						|
  *names=ptr;				/* Update end */
 | 
						|
  return;
 | 
						|
} /* fix_type_pointers */
 | 
						|
 | 
						|
 | 
						|
TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings)
 | 
						|
{
 | 
						|
  TYPELIB *result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
 | 
						|
  if (!result)
 | 
						|
    return 0;
 | 
						|
  result->count=strings.elements;
 | 
						|
  result->name="";
 | 
						|
  uint nbytes= (sizeof(char*) + sizeof(uint)) * (result->count + 1);
 | 
						|
  if (!(result->type_names= (const char**) alloc_root(mem_root, nbytes)))
 | 
						|
    return 0;
 | 
						|
  result->type_lengths= (uint*) (result->type_names + result->count + 1);
 | 
						|
  List_iterator<String> it(strings);
 | 
						|
  String *tmp;
 | 
						|
  for (uint i=0; (tmp=it++) ; i++)
 | 
						|
  {
 | 
						|
    result->type_names[i]= tmp->ptr();
 | 
						|
    result->type_lengths[i]= tmp->length();
 | 
						|
  }
 | 
						|
  result->type_names[result->count]= 0;		// End marker
 | 
						|
  result->type_lengths[result->count]= 0;
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
	/*
 | 
						|
	** Search after a field with given start & length
 | 
						|
	** If an exact field isn't found, return longest field with starts
 | 
						|
	** at right position.
 | 
						|
	** Return 0 on error, else field number+1
 | 
						|
	** This is needed because in some .frm fields 'fieldnr' was saved wrong
 | 
						|
	*/
 | 
						|
 | 
						|
static uint find_field(TABLE *form,uint start,uint length)
 | 
						|
{
 | 
						|
  Field **field;
 | 
						|
  uint i,pos;
 | 
						|
 | 
						|
  pos=0;
 | 
						|
 | 
						|
  for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
 | 
						|
  {
 | 
						|
    if ((*field)->offset() == start)
 | 
						|
    {
 | 
						|
      if ((*field)->key_length() == length)
 | 
						|
	return (i);
 | 
						|
      if (!pos || form->field[pos-1]->pack_length() <
 | 
						|
	  (*field)->pack_length())
 | 
						|
	pos=i;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (pos);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
	/* Check that the integer is in the internvall */
 | 
						|
 | 
						|
int set_zone(register int nr, int min_zone, int max_zone)
 | 
						|
{
 | 
						|
  if (nr<=min_zone)
 | 
						|
    return (min_zone);
 | 
						|
  if (nr>=max_zone)
 | 
						|
    return (max_zone);
 | 
						|
  return (nr);
 | 
						|
} /* set_zone */
 | 
						|
 | 
						|
	/* Adjust number to next larger disk buffer */
 | 
						|
 | 
						|
ulong next_io_size(register ulong pos)
 | 
						|
{
 | 
						|
  reg2 ulong offset;
 | 
						|
  if ((offset= pos & (IO_SIZE-1)))
 | 
						|
    return pos-offset+IO_SIZE;
 | 
						|
  return pos;
 | 
						|
} /* next_io_size */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Store an SQL quoted string.
 | 
						|
 | 
						|
  SYNOPSIS  
 | 
						|
    append_unescaped()
 | 
						|
    res		result String
 | 
						|
    pos		string to be quoted
 | 
						|
    length	it's length
 | 
						|
 | 
						|
  NOTE
 | 
						|
    This function works correctly with utf8 or single-byte charset strings.
 | 
						|
    May fail with some multibyte charsets though.
 | 
						|
*/
 | 
						|
 | 
						|
void append_unescaped(String *res, const char *pos, uint length)
 | 
						|
{
 | 
						|
  const char *end= pos+length;
 | 
						|
  res->append('\'');
 | 
						|
 | 
						|
  for (; pos != end ; pos++)
 | 
						|
  {
 | 
						|
#if defined(USE_MB) && MYSQL_VERSION_ID < 40100
 | 
						|
    uint mblen;
 | 
						|
    if (use_mb(default_charset_info) &&
 | 
						|
        (mblen= my_ismbchar(default_charset_info, pos, end)))
 | 
						|
    {
 | 
						|
      res->append(pos, mblen);
 | 
						|
      pos+= mblen;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    switch (*pos) {
 | 
						|
    case 0:				/* Must be escaped for 'mysql' */
 | 
						|
      res->append('\\');
 | 
						|
      res->append('0');
 | 
						|
      break;
 | 
						|
    case '\n':				/* Must be escaped for logs */
 | 
						|
      res->append('\\');
 | 
						|
      res->append('n');
 | 
						|
      break;
 | 
						|
    case '\r':
 | 
						|
      res->append('\\');		/* This gives better readbility */
 | 
						|
      res->append('r');
 | 
						|
      break;
 | 
						|
    case '\\':
 | 
						|
      res->append('\\');		/* Because of the sql syntax */
 | 
						|
      res->append('\\');
 | 
						|
      break;
 | 
						|
    case '\'':
 | 
						|
      res->append('\'');		/* Because of the sql syntax */
 | 
						|
      res->append('\'');
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      res->append(*pos);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  res->append('\'');
 | 
						|
}
 | 
						|
 | 
						|
	/* Create a .frm file */
 | 
						|
 | 
						|
File create_frm(register my_string name,  const char *db, const char *table,
 | 
						|
                uint reclength, uchar *fileinfo,
 | 
						|
		HA_CREATE_INFO *create_info, uint keys)
 | 
						|
{
 | 
						|
  register File file;
 | 
						|
  uint key_length;
 | 
						|
  ulong length;
 | 
						|
  char fill[IO_SIZE];
 | 
						|
  int create_flags= O_RDWR | O_TRUNC;
 | 
						|
 | 
						|
  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
 | 
						|
    create_flags|= O_EXCL | O_NOFOLLOW;
 | 
						|
 | 
						|
#if SIZEOF_OFF_T > 4
 | 
						|
  /* Fix this when we have new .frm files;  Current limit is 4G rows (QQ) */
 | 
						|
  if (create_info->max_rows > ~(ulong) 0)
 | 
						|
    create_info->max_rows= ~(ulong) 0;
 | 
						|
  if (create_info->min_rows > ~(ulong) 0)
 | 
						|
    create_info->min_rows= ~(ulong) 0;
 | 
						|
#endif
 | 
						|
  /*
 | 
						|
    Ensure that raid_chunks can't be larger than 255, as this would cause
 | 
						|
    problems with drop database
 | 
						|
  */
 | 
						|
  set_if_smaller(create_info->raid_chunks, 255);
 | 
						|
 | 
						|
  if ((file= my_create(name, CREATE_MODE, create_flags, MYF(0))) >= 0)
 | 
						|
  {
 | 
						|
    bzero((char*) fileinfo,64);
 | 
						|
    fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3; // Header
 | 
						|
    fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
 | 
						|
    fileinfo[4]=1;
 | 
						|
    int2store(fileinfo+6,IO_SIZE);		/* Next block starts here */
 | 
						|
    key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
 | 
						|
    length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
 | 
						|
    int4store(fileinfo+10,length);
 | 
						|
    if (key_length > 0xffff) key_length=0xffff;
 | 
						|
    int2store(fileinfo+14,key_length);
 | 
						|
    int2store(fileinfo+16,reclength);
 | 
						|
    int4store(fileinfo+18,create_info->max_rows);
 | 
						|
    int4store(fileinfo+22,create_info->min_rows);
 | 
						|
    fileinfo[27]=2;				// Use long pack-fields
 | 
						|
    create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
 | 
						|
    int2store(fileinfo+30,create_info->table_options);
 | 
						|
    fileinfo[32]=0;				// No filename anymore
 | 
						|
    int4store(fileinfo+34,create_info->avg_row_length);
 | 
						|
    fileinfo[38]= (create_info->default_table_charset ?
 | 
						|
		   create_info->default_table_charset->number : 0);
 | 
						|
    fileinfo[40]= (uchar) create_info->row_type;
 | 
						|
    fileinfo[41]= (uchar) create_info->raid_type;
 | 
						|
    fileinfo[42]= (uchar) create_info->raid_chunks;
 | 
						|
    int4store(fileinfo+43,create_info->raid_chunksize);
 | 
						|
    bzero(fill,IO_SIZE);
 | 
						|
    for (; length > IO_SIZE ; length-= IO_SIZE)
 | 
						|
    {
 | 
						|
      if (my_write(file,(byte*) fill,IO_SIZE,MYF(MY_WME | MY_NABP)))
 | 
						|
      {
 | 
						|
	VOID(my_close(file,MYF(0)));
 | 
						|
	VOID(my_delete(name,MYF(0)));
 | 
						|
	return(-1);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if (my_errno == ENOENT)
 | 
						|
      my_error(ER_BAD_DB_ERROR,MYF(0),db);
 | 
						|
    else
 | 
						|
      my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno);
 | 
						|
  }
 | 
						|
  return (file);
 | 
						|
} /* create_frm */
 | 
						|
 | 
						|
 | 
						|
void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
 | 
						|
{
 | 
						|
  DBUG_ENTER("update_create_info_from_table");
 | 
						|
  create_info->max_rows=table->max_rows;
 | 
						|
  create_info->min_rows=table->min_rows;
 | 
						|
  create_info->table_options=table->db_create_options;
 | 
						|
  create_info->avg_row_length=table->avg_row_length;
 | 
						|
  create_info->row_type=table->row_type;
 | 
						|
  create_info->raid_type=table->raid_type;
 | 
						|
  create_info->raid_chunks=table->raid_chunks;
 | 
						|
  create_info->raid_chunksize=table->raid_chunksize;
 | 
						|
  create_info->default_table_charset=table->table_charset;
 | 
						|
  create_info->table_charset= 0;
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rename_file_ext(const char * from,const char * to,const char * ext)
 | 
						|
{
 | 
						|
  char from_b[FN_REFLEN],to_b[FN_REFLEN];
 | 
						|
  VOID(strxmov(from_b,from,ext,NullS));
 | 
						|
  VOID(strxmov(to_b,to,ext,NullS));
 | 
						|
  return (my_rename(from_b,to_b,MYF(MY_WME)));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Allocate string field in MEM_ROOT and return it as String
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    get_field()
 | 
						|
    mem   	MEM_ROOT for allocating
 | 
						|
    field 	Field for retrieving of string
 | 
						|
    res         result String
 | 
						|
 | 
						|
  RETURN VALUES
 | 
						|
    1   string is empty
 | 
						|
    0	all ok
 | 
						|
*/
 | 
						|
 | 
						|
bool get_field(MEM_ROOT *mem, Field *field, String *res)
 | 
						|
{
 | 
						|
  char buff[MAX_FIELD_WIDTH], *to;
 | 
						|
  String str(buff,sizeof(buff),&my_charset_bin);
 | 
						|
  uint length;
 | 
						|
 | 
						|
  field->val_str(&str);
 | 
						|
  if (!(length= str.length()))
 | 
						|
    return 1;
 | 
						|
  to= strmake_root(mem, str.ptr(), length);
 | 
						|
  res->set(to, length, ((Field_str*)field)->charset());
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Allocate string field in MEM_ROOT and return it as NULL-terminated string
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    get_field()
 | 
						|
    mem   	MEM_ROOT for allocating
 | 
						|
    field 	Field for retrieving of string
 | 
						|
 | 
						|
  RETURN VALUES
 | 
						|
    NullS  string is empty
 | 
						|
    #      pointer to NULL-terminated string value of field
 | 
						|
*/
 | 
						|
 | 
						|
char *get_field(MEM_ROOT *mem, Field *field)
 | 
						|
{
 | 
						|
  char buff[MAX_FIELD_WIDTH], *to;
 | 
						|
  String str(buff,sizeof(buff),&my_charset_bin);
 | 
						|
  uint length;
 | 
						|
 | 
						|
  field->val_str(&str);
 | 
						|
  length= str.length();
 | 
						|
  if (!length || !(to= (char*) alloc_root(mem,length+1)))
 | 
						|
    return NullS;
 | 
						|
  memcpy(to,str.ptr(),(uint) length);
 | 
						|
  to[length]=0;
 | 
						|
  return to;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Check if database name is valid
 | 
						|
 | 
						|
  SYNPOSIS
 | 
						|
    check_db_name()
 | 
						|
    name		Name of database
 | 
						|
 | 
						|
  NOTES
 | 
						|
    If lower_case_table_names is set then database is converted to lower case
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0	ok
 | 
						|
    1   error
 | 
						|
*/
 | 
						|
 | 
						|
bool check_db_name(char *name)
 | 
						|
{
 | 
						|
  char *start= name;
 | 
						|
  /* Used to catch empty names and names with end space */
 | 
						|
  bool last_char_is_space= TRUE;
 | 
						|
 | 
						|
  if (lower_case_table_names && name != any_db)
 | 
						|
    my_casedn_str(files_charset_info, name);
 | 
						|
 | 
						|
  while (*name)
 | 
						|
  {
 | 
						|
#if defined(USE_MB) && defined(USE_MB_IDENT)
 | 
						|
    last_char_is_space= my_isspace(system_charset_info, *name);
 | 
						|
    if (use_mb(system_charset_info))
 | 
						|
    {
 | 
						|
      int len=my_ismbchar(system_charset_info, name, 
 | 
						|
		name+system_charset_info->mbmaxlen);
 | 
						|
      if (len)
 | 
						|
      {
 | 
						|
        name += len;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
#else
 | 
						|
    last_char_is_space= *name==' ';
 | 
						|
#endif
 | 
						|
    if (*name == '/' || *name == '\\' || *name == FN_LIBCHAR ||
 | 
						|
	*name == FN_EXTCHAR)
 | 
						|
      return 1;
 | 
						|
    name++;
 | 
						|
  }
 | 
						|
  return last_char_is_space || (uint) (name - start) > NAME_LEN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Allow anything as a table name, as long as it doesn't contain an
 | 
						|
  a '/', or a '.' character
 | 
						|
  or ' ' at the end
 | 
						|
  returns 1 on error
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
bool check_table_name(const char *name, uint length)
 | 
						|
{
 | 
						|
  const char *end= name+length;
 | 
						|
  if (!length || length > NAME_LEN)
 | 
						|
    return 1;
 | 
						|
#if defined(USE_MB) && defined(USE_MB_IDENT)
 | 
						|
  bool last_char_is_space= FALSE;
 | 
						|
#else
 | 
						|
  if (name[length-1]==' ')
 | 
						|
    return 1;
 | 
						|
#endif
 | 
						|
 | 
						|
  while (name != end)
 | 
						|
  {
 | 
						|
#if defined(USE_MB) && defined(USE_MB_IDENT)
 | 
						|
    last_char_is_space= my_isspace(system_charset_info, *name);
 | 
						|
    if (use_mb(system_charset_info))
 | 
						|
    {
 | 
						|
      int len=my_ismbchar(system_charset_info, name, end);
 | 
						|
      if (len)
 | 
						|
      {
 | 
						|
        name += len;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    if (*name == '/' || *name == '\\' || *name == FN_EXTCHAR)
 | 
						|
      return 1;
 | 
						|
    name++;
 | 
						|
  }
 | 
						|
#if defined(USE_MB) && defined(USE_MB_IDENT)
 | 
						|
  return last_char_is_space;
 | 
						|
#else
 | 
						|
  return 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool check_column_name(const char *name)
 | 
						|
{
 | 
						|
  const char *start= name;
 | 
						|
  bool last_char_is_space= TRUE;
 | 
						|
 | 
						|
  while (*name)
 | 
						|
  {
 | 
						|
#if defined(USE_MB) && defined(USE_MB_IDENT)
 | 
						|
    last_char_is_space= my_isspace(system_charset_info, *name);
 | 
						|
    if (use_mb(system_charset_info))
 | 
						|
    {
 | 
						|
      int len=my_ismbchar(system_charset_info, name, 
 | 
						|
		name+system_charset_info->mbmaxlen);
 | 
						|
      if (len)
 | 
						|
      {
 | 
						|
        name += len;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
#else
 | 
						|
    last_char_is_space= *name==' ';
 | 
						|
#endif
 | 
						|
    if (*name == NAMES_SEP_CHAR)
 | 
						|
      return 1;
 | 
						|
    name++;
 | 
						|
  }
 | 
						|
  /* Error if empty or too long column name */
 | 
						|
  return last_char_is_space || (uint) (name - start) > NAME_LEN;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Get type of table from .frm file
 | 
						|
*/
 | 
						|
 | 
						|
db_type get_table_type(const char *name)
 | 
						|
{
 | 
						|
  File	 file;
 | 
						|
  uchar head[4];
 | 
						|
  int error;
 | 
						|
  DBUG_ENTER("get_table_type");
 | 
						|
  DBUG_PRINT("enter",("name: '%s'",name));
 | 
						|
 | 
						|
  if ((file=my_open(name,O_RDONLY, MYF(0))) < 0)
 | 
						|
    DBUG_RETURN(DB_TYPE_UNKNOWN);
 | 
						|
  error=my_read(file,(byte*) head,4,MYF(MY_NABP));
 | 
						|
  my_close(file,MYF(0));
 | 
						|
  if (error || head[0] != (uchar) 254 || head[1] != 1 ||
 | 
						|
      (head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3))
 | 
						|
    DBUG_RETURN(DB_TYPE_UNKNOWN);
 | 
						|
  DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Cleanup this table for re-execution.
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    st_table_list::reinit_before_use()
 | 
						|
*/
 | 
						|
 | 
						|
void st_table_list::reinit_before_use(THD * /* thd */)
 | 
						|
{
 | 
						|
  /*
 | 
						|
    Reset old pointers to TABLEs: they are not valid since the tables
 | 
						|
    were closed in the end of previous prepare or execute call.
 | 
						|
  */
 | 
						|
  table= 0;
 | 
						|
  table_list= 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
** Instansiate templates
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
#ifdef __GNUC__
 | 
						|
template class List<String>;
 | 
						|
template class List_iterator<String>;
 | 
						|
#endif
 |