table.cc 57.2 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21 22
   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>
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
23
#include "md5.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
24 25 26

	/* Functions defined in this file */

27 28
static void frm_error(int error,TABLE *form,const char *name,
                      int errortype, int errarg);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
29 30 31 32 33
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);


34
static byte* get_field_name(Field **buff,uint *length,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
35 36
			    my_bool not_used __attribute__((unused)))
{
37 38
  *length= (uint) strlen((*buff)->field_name);
  return (byte*) (*buff)->field_name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
39 40
}

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/*
  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)
61
   5    Error (see frm_error: charset unavailable)
62
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
63

64 65
int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
            uint prgflag, uint ha_open_flags, TABLE *outparam)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
66 67 68
{
  reg1 uint i;
  reg2 uchar *strpos;
69
  int	 j,error, errarg= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
70
  uint	 rec_buff_length,n_length,int_length,records,key_parts,keys,
71
         interval_count,interval_parts,read_length,db_create_options;
72
  uint	 key_info_length, com_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
73
  ulong  pos;
74
  char	 index_file[FN_REFLEN], *names, *keynames, *comment_pos;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
75 76 77
  uchar  head[288],*disk_buff,new_field_pack_flag;
  my_string record;
  const char **int_array;
78
  bool	 use_hash, null_field_first;
79
  bool   error_reported= FALSE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
80 81 82 83 84
  File	 file;
  Field  **field_ptr,*reg_field;
  KEY	 *keyinfo;
  KEY_PART_INFO *key_part;
  uchar *null_pos;
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
85
  uint null_bit_pos, new_frm_ver, field_pack_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
86
  SQL_CRYPT *crypted=0;
87
  MEM_ROOT **root_ptr, *old_root;
88
  TABLE_SHARE *share;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
89
  DBUG_ENTER("openfrm");
90
  DBUG_PRINT("enter",("name: '%s'  form: 0x%lx",name,outparam));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
91

92 93
  error= 1;
  disk_buff= NULL;
monty@mysql.com's avatar
monty@mysql.com committed
94 95
  root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
  old_root= *root_ptr;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
96

97 98 99 100
  bzero((char*) outparam,sizeof(*outparam));
  outparam->in_use= thd;
  outparam->s= share= &outparam->share_not_to_be_used;

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
101 102 103 104 105 106 107
  if ((file=my_open(fn_format(index_file, name, "", reg_ext,
			      MY_UNPACK_FILENAME),
		    O_RDONLY | O_SHARE,
		    MYF(0)))
      < 0)
    goto err_w_init;

108
  error= 4;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
  if (my_read(file,(byte*) head,64,MYF(MY_NABP)))
    goto err_w_init;

  if (memcmp(head, "TYPE=", 5) == 0)
  {
    // new .frm
    my_close(file,MYF(MY_WME));

    if (db_stat & NO_ERR_ON_NEW_FRM)
      DBUG_RETURN(5);

    // caller can't process new .frm
    goto err_w_init;
  }

124 125
  share->blob_ptr_size= sizeof(char*);
  outparam->db_stat= db_stat;
126
  init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
127
  *root_ptr= &outparam->mem_root;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
128

129 130 131 132 133
  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)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
134
    goto err_not_open;
135 136
  *fn_ext(share->table_name)='\0';		// Remove extension
  *fn_ext(share->path)='\0';                    // Remove extension
bk@work.mysql.com's avatar
bk@work.mysql.com committed
137 138

  if (head[0] != (uchar) 254 || head[1] != 1 ||
139 140
      (head[2] != FRM_VER && head[2] != FRM_VER+1 &&
       ! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4)))
141
    goto err_not_open;				/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
142
  new_field_pack_flag=head[27];
143
  new_frm_ver= (head[2] - FRM_VER);
144
  field_pack_length= new_frm_ver < 2 ? 11 : 17;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
145 146 147

  error=3;
  if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
148
    goto err_not_open;				/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
149 150
  *fn_ext(index_file)='\0';			// Remove .frm extension

151 152 153 154 155
  share->frm_version= head[2];
  share->db_type= ha_checktype((enum db_type) (uint) *(head+3));
  share->db_create_options= db_create_options=uint2korr(head+30);
  share->db_options_in_use= share->db_create_options;
  null_field_first= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
156 157
  if (!head[32])				// New frm file in 3.23
  {
158 159 160 161 162 163 164 165 166 167 168 169
    share->avg_row_length= uint4korr(head+34);
    share-> row_type= (row_type) head[40];
    share->raid_type=   head[41];
    share->raid_chunks= head[42];
    share->raid_chunksize= uint4korr(head+43);
    share->table_charset= get_charset((uint) head[38],MYF(0));
    null_field_first= 1;
  }
  if (!share->table_charset)
  {
    /* unknown charset in head[38] or pre-3.23 frm */
    share->table_charset= default_charset_info;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
170
  }
171
  share->db_record_offset= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
172
  if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
173
    share->blob_ptr_size= portable_sizeof_char_ptr;
174
  /* Set temporarily a good value for db_low_byte_first */
175
  share->db_low_byte_first= test(share->db_type != DB_TYPE_ISAM);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
176
  error=4;
177 178
  share->max_rows= uint4korr(head+18);
  share->min_rows= uint4korr(head+22);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
179 180

  /* Read keyinformation */
181
  key_info_length= (uint) uint2korr(head+28);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
182
  VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
183
  if (read_string(file,(gptr*) &disk_buff,key_info_length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
184
    goto err_not_open; /* purecov: inspected */
serg@serg.mylan's avatar
serg@serg.mylan committed
185
  if (disk_buff[0] & 0x80)
serg@serg.mylan's avatar
serg@serg.mylan committed
186
  {
187 188
    share->keys=      keys=      (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
    share->key_parts= key_parts= uint2korr(disk_buff+2);
serg@serg.mylan's avatar
serg@serg.mylan committed
189 190 191
  }
  else
  {
192 193
    share->keys=      keys=      disk_buff[0];
    share->key_parts= key_parts= disk_buff[1];
serg@serg.mylan's avatar
serg@serg.mylan committed
194
  }
195 196
  share->keys_for_keyread.init(0);
  share->keys_in_use.init(keys);
197 198 199
  outparam->quick_keys.init();
  outparam->used_keys.init();
  outparam->keys_in_use_for_query.init();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
200 201 202 203 204 205 206

  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;
207
  key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
208 209 210 211 212 213 214 215 216
  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++)
  {
217 218
    keyinfo->table= outparam;
    if (new_frm_ver >= 3)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    {
      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;
    }
234

bk@work.mysql.com's avatar
bk@work.mysql.com committed
235 236 237 238 239 240 241 242 243
    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
244
      if (new_frm_ver >= 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
      {
	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;
    }
  }
264 265
  keynames=(char*) key_part;
  strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
266

267
  share->reclength = uint2korr((head+16));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
268
  if (*(head+26) == 1)
269
    share->system= 1;				/* one-record-database */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
270 271 272
#ifdef HAVE_CRYPTED_FRM
  else if (*(head+26) == 2)
  {
273
    *root_ptr= old_root
bk@work.mysql.com's avatar
bk@work.mysql.com committed
274
    crypted=get_crypt_for_frm();
275
    *root_ptr= &outparam->mem_root;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
276 277 278 279
    outparam->crypted=1;
  }
#endif

280
  /* Allocate handler */
281
  if (!(outparam->file= get_new_handler(outparam, share->db_type)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
282 283 284 285 286
    goto err_not_open;

  error=4;
  outparam->reginfo.lock_type= TL_UNLOCK;
  outparam->current_lock=F_UNLCK;
287 288 289 290
  if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
    records=2;
  else
    records=1;
291 292
  if (prgflag & (READ_ALL+EXTRA_RECORD))
    records++;
293
  /* QQ: TODO, remove the +1 from below */
294 295 296 297 298
  rec_buff_length= ALIGN_SIZE(share->reclength + 1 +
                              outparam->file->extra_rec_buf_length());
  share->rec_buff_length= rec_buff_length;
  if (!(record= (char *) alloc_root(&outparam->mem_root,
                                    rec_buff_length * records)))
299
    goto err_not_open;				/* purecov: inspected */
300 301
  share->default_values= record;
  if (my_pread(file,(byte*) record, (uint) share->reclength,
serg@serg.mylan's avatar
serg@serg.mylan committed
302 303
	       (ulong) (uint2korr(head+6)+
                        ((uint2korr(head+14) == 0xffff ?
serg@serg.mylan's avatar
serg@serg.mylan committed
304
                            uint4korr(head+47) : uint2korr(head+14)))),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
305
	       MYF(MY_NABP)))
306
    goto err_not_open; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
307

308 309 310 311 312
  if (records == 1)
  {
    /* We are probably in hard repair, and the buffers should not be used */
    outparam->record[0]= outparam->record[1]= share->default_values;
  }
313
  else
314 315 316 317 318 319 320
  {
    outparam->record[0]= record+ rec_buff_length;
    if (records > 2)
      outparam->record[1]= record+ rec_buff_length*2;
    else
      outparam->record[1]= outparam->record[0];   // Safety
  }
321

322 323 324 325 326 327 328 329 330 331 332 333
#ifdef HAVE_purify
  /*
    We need this because when we read var-length rows, we are not updating
    bytes after end of varchar
  */
  if (records > 1)
  {
    memcpy(outparam->record[0], share->default_values, rec_buff_length);
    if (records > 2)
      memcpy(outparam->record[1], share->default_values, rec_buff_length);
  }
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
334
  VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
335
  if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
336 337 338 339
  if (crypted)
  {
    crypted->decode((char*) head+256,288-256);
    if (sint2korr(head+284) != 0)		// Should be 0
340
      goto err_not_open;			// Wrong password
bk@work.mysql.com's avatar
bk@work.mysql.com committed
341 342
  }

343 344 345 346 347 348 349 350 351
  share->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);
  share->null_fields= uint2korr(head+282);
  com_length= uint2korr(head+284);
  share->comment= strdup_root(&outparam->mem_root, (char*) head+47);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
352

353
  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));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
354 355 356

  if (!(field_ptr = (Field **)
	alloc_root(&outparam->mem_root,
357
		   (uint) ((share->fields+1)*sizeof(Field*)+
bk@work.mysql.com's avatar
bk@work.mysql.com committed
358
			   interval_count*sizeof(TYPELIB)+
359
			   (share->fields+interval_parts+
bk@work.mysql.com's avatar
bk@work.mysql.com committed
360
			    keys+3)*sizeof(my_string)+
361
			   (n_length+int_length+com_length)))))
362
    goto err_not_open; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
363 364

  outparam->field=field_ptr;
365
  read_length=(uint) (share->fields * field_pack_length +
366
		      pos+ (uint) (n_length+int_length+com_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
367
  if (read_string(file,(gptr*) &disk_buff,read_length))
368
    goto err_not_open; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
369 370 371 372 373 374 375 376
  if (crypted)
  {
    crypted->decode((char*) disk_buff,read_length);
    delete crypted;
    crypted=0;
  }
  strpos= disk_buff+pos;

377 378 379
  share->intervals= (TYPELIB*) (field_ptr+share->fields+1);
  int_array= (const char **) (share->intervals+interval_count);
  names= (char*) (int_array+share->fields+interval_parts+keys+3);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
380
  if (!interval_count)
381 382
    share->intervals= 0;			// For better debugging
  memcpy((char*) names, strpos+(share->fields*field_pack_length),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
383
	 (uint) (n_length+int_length));
384
  comment_pos= names+(n_length+int_length);
385
  memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
386

387 388
  fix_type_pointers(&int_array, &share->fieldnames, 1, &names);
  fix_type_pointers(&int_array, share->intervals, interval_count,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
389
		    &names);
390 391 392 393

  {
    /* Set ENUM and SET lengths */
    TYPELIB *interval;
394 395
    for (interval= share->intervals;
         interval < share->intervals + interval_count;
396 397 398 399 400 401 402 403 404 405 406 407
         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++)
        interval->type_lengths[count]= strlen(interval->type_names[count]);
      interval->type_lengths[count]= 0;
    }
  }

bk@work.mysql.com's avatar
bk@work.mysql.com committed
408
  if (keynames)
409
    fix_type_pointers(&int_array, &share->keynames, 1, &keynames);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
410
  VOID(my_close(file,MYF(MY_WME)));
411
  file= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
412

413
  record= (char*) outparam->record[0]-1;	/* Fieldstart = 1 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
414 415 416
  if (null_field_first)
  {
    outparam->null_flags=null_pos=(uchar*) record+1;
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
417
    null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;
418
    share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419 420 421
  }
  else
  {
422 423 424
    share->null_bytes= (share->null_fields+7)/8;
    outparam->null_flags= null_pos=
      (uchar*) (record+1+share->reclength-share->null_bytes);
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
425
    null_bit_pos= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
426 427
  }

428
  use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
429
  if (use_hash)
430
    use_hash= !hash_init(&share->name_hash,
431
			 system_charset_info,
432
			 share->fields,0,0,
433
			 (hash_get_key) get_field_name,0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434

435
  for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
436
  {
437
    uint pack_flag, interval_nr, unireg_type, recpos, field_length;
438
    enum_field_types field_type;
439
    CHARSET_INFO *charset=NULL;
440
    Field::geometry_type geom_type= Field::GEOM_GEOMETRY;
441
    LEX_STRING comment;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
442

443
    if (new_frm_ver >= 3)
444 445
    {
      /* new frm file in 4.1 */
446 447 448 449 450 451 452
      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];
453

454
      /* charset and geometry_type share the same byte in frm */
455 456
      if (field_type == FIELD_TYPE_GEOMETRY)
      {
hf@deer.(none)'s avatar
hf@deer.(none) committed
457
#ifdef HAVE_SPATIAL
458 459
	geom_type= (Field::geometry_type) strpos[14];
	charset= &my_charset_bin;
hf@deer.(none)'s avatar
hf@deer.(none) committed
460 461 462 463
#else
	error= 4;  // unsupported field type
	goto err_not_open;
#endif
464 465 466
      }
      else
      {
467 468 469 470 471 472 473 474
        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;
        }
475
      }
476 477 478 479 480 481 482 483 484 485 486 487 488 489
      if (!comment_length)
      {
	comment.str= (char*) "";
	comment.length=0;
      }
      else
      {
	comment.str=    (char*) comment_pos;
	comment.length= comment_length;
	comment_pos+=   comment_length;
      }
    }
    else
    {
490 491 492
      field_length= (uint) strpos[3];
      recpos=	    uint2korr(strpos+4),
      pack_flag=    uint2korr(strpos+6);
493
      pack_flag&=   ~FIELDFLAG_NO_DEFAULT;     // Safety for old files
494 495 496
      unireg_type=  (uint) strpos[8];
      interval_nr=  (uint) strpos[10];

497 498
      /* old frm file */
      field_type= (enum_field_types) f_packtype(pack_flag);
bar@mysql.com's avatar
bar@mysql.com committed
499 500 501 502 503 504 505 506 507 508 509
      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
510
          if (!(charset= get_charset_by_csname(share->table_charset->csname,
bar@mysql.com's avatar
bar@mysql.com committed
511 512 513 514 515 516 517
                                               MY_CS_BINSORT, MYF(0))))
            charset= &my_charset_bin;
        }
        else
          charset= &my_charset_bin;
      }
      else
518
        charset= share->table_charset;
519 520
      bzero((char*) &comment, sizeof(comment));
    }
521 522 523 524

    if (interval_nr && charset->mbminlen > 1)
    {
      /* Unescape UCS2 intervals from HEX notation */
525
      TYPELIB *interval= share->intervals + interval_nr - 1;
526
      unhex_type2(interval);
527 528
    }
    
bk@work.mysql.com's avatar
bk@work.mysql.com committed
529
    *field_ptr=reg_field=
530 531
      make_field(record+recpos,
		 (uint32) field_length,
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
532
		 null_pos, null_bit_pos,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
533
		 pack_flag,
534
		 field_type,
535
		 charset,
536
		 geom_type,
537
		 (Field::utype) MTYP_TYPENR(unireg_type),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
538
		 (interval_nr ?
539
		  share->intervals+interval_nr-1 :
bk@work.mysql.com's avatar
bk@work.mysql.com committed
540
		  (TYPELIB*) 0),
541
		 share->fieldnames.type_names[i],
bk@work.mysql.com's avatar
bk@work.mysql.com committed
542
		 outparam);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
543
    if (!reg_field)				// Not supported field type
544 545 546 547
    {
      error= 4;
      goto err_not_open;			/* purecov: inspected */
    }
548
    reg_field->comment=comment;
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
549
    if (field_type == FIELD_TYPE_BIT)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
550
    {
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
551
      if ((null_bit_pos+= field_length & 7) > 7)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
552
      {
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
553 554
        null_pos++;
        null_bit_pos-= 8;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
555 556
      }
    }
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
557 558 559 560 561
    if (!(reg_field->flags & NOT_NULL_FLAG))
    {
      if (!(null_bit_pos= (null_bit_pos + 1) & 7))
        null_pos++;
    }
562 563
    if (f_no_default(pack_flag))
      reg_field->flags|= NO_DEFAULT_VALUE_FLAG;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
564
    if (reg_field->unireg_check == Field::NEXT_NUMBER)
565
      outparam->found_next_number_field= reg_field;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
566
    if (outparam->timestamp_field == reg_field)
567
      share->timestamp_field_offset= i;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
568
    if (use_hash)
569
      (void) my_hash_insert(&share->name_hash,(byte*) field_ptr); // never fail
bk@work.mysql.com's avatar
bk@work.mysql.com committed
570 571 572 573 574 575
  }
  *field_ptr=0;					// End marker

  /* Fix key->name and key_part->field */
  if (key_parts)
  {
576
    uint primary_key=(uint) (find_type((char*) primary_key_name,
577
				       &share->keynames, 3) - 1);
578
    uint ha_option=outparam->file->table_flags();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
579 580 581
    keyinfo=outparam->key_info;
    key_part=keyinfo->key_part;

582
    for (uint key=0 ; key < share->keys ; key++,keyinfo++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
583 584
    {
      uint usable_parts=0;
585
      keyinfo->name=(char*) share->keynames.type_names[key];
586 587 588 589
      /* Fix fulltext keys for old .frm files */
      if (outparam->key_info[key].flags & HA_FULLTEXT)
	outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
590 591 592
      if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
      {
	/*
593 594
	  If the UNIQUE key doesn't have NULL columns and is not a part key
	  declare this as a primary key.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
595 596 597 598
	*/
	primary_key=key;
	for (i=0 ; i < keyinfo->key_parts ;i++)
	{
599 600 601 602 603
	  uint fieldnr= key_part[i].fieldnr;
	  if (!fieldnr ||
	      outparam->field[fieldnr-1]->null_ptr ||
	      outparam->field[fieldnr-1]->key_length() !=
	      key_part[i].length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
604 605 606 607 608 609 610 611 612 613 614 615 616 617
	  {
	    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
618
	if (key_part->fieldnr > share->fields)
619
	  goto err_not_open; // sanity check
bk@work.mysql.com's avatar
bk@work.mysql.com committed
620 621 622 623 624 625 626 627 628 629 630 631
#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;
632
	    keyinfo->key_length+= HA_KEY_NULL_LENGTH;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
633 634
	  }
	  if (field->type() == FIELD_TYPE_BLOB ||
635
	      field->real_type() == MYSQL_TYPE_VARCHAR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
636 637 638
	  {
	    if (field->type() == FIELD_TYPE_BLOB)
	      key_part->key_part_flag|= HA_BLOB_PART;
639 640
            else
              key_part->key_part_flag|= HA_VAR_LENGTH_PART;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
641 642
	    keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
	    key_part->store_length+=HA_KEY_BLOB_LENGTH;
643
	    keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
644 645 646 647 648 649
	    /*
	      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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
650
	  }
monty@mysql.com's avatar
monty@mysql.com committed
651 652 653
	  if (field->type() == MYSQL_TYPE_BIT)
            key_part->key_part_flag|= HA_BIT_PART;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
654 655 656 657 658 659
	  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)
660
	    field->key_start.set_bit(key);
661
	  if (field->key_length() == key_part->length &&
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
662
	      !(field->flags & BLOB_FLAG))
663
	  {
664
            if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
665
            {
666
              share->keys_for_keyread.set_bit(key);
667
	      field->part_of_key.set_bit(key);
668
            }
669
	    if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER)
670
	      field->part_of_sortkey.set_bit(key);
671
	  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
672 673 674 675 676 677 678
	  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;
679 680 681 682
	    /*
	      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
	    */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
683
	    if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
684
	      field->part_of_key= share->keys_in_use;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
685 686 687
	  }
	  if (field->key_length() != key_part->length)
	  {
688
	    key_part->key_part_flag|= HA_PART_KEY_SEG;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
689
	    if (!(field->flags & BLOB_FLAG))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
690
	    {					// Create a new field
691 692
	      field=key_part->field=field->new_field(&outparam->mem_root,
						     outparam);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
693 694 695
	      field->field_length=key_part->length;
	    }
	  }
696 697 698 699 700 701
	  /*
	    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())
702
	    key_part->key_part_flag|= HA_PART_KEY_SEG;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
703 704 705 706 707 708 709 710
	}
	else
	{					// Error: shorten key
	  keyinfo->key_parts=usable_parts;
	  keyinfo->flags=0;
	}
      }
      keyinfo->usable_key_parts=usable_parts; // Filesort
711

712
      set_if_bigger(share->max_key_length,keyinfo->key_length+
713
                    keyinfo->key_parts);
714
      share->total_key_length+= keyinfo->key_length;
715
      if (keyinfo->flags & HA_NOSAME)
716
        set_if_bigger(share->max_unique_length, keyinfo->key_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
717
    }
718
    if (primary_key < MAX_KEY &&
719
	(share->keys_in_use.is_set(primary_key)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
720
    {
721
      share->primary_key= primary_key;
722 723 724 725
      /*
	If we are using an integer as the primary key then allow the user to
	refer to it as '_rowid'
      */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
726 727 728 729 730 731 732 733
      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
734
      share->primary_key = MAX_KEY; // we do not have a primary key
bk@work.mysql.com's avatar
bk@work.mysql.com committed
735
  }
736
  else
737
    share->primary_key= MAX_KEY;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
738
  x_free((gptr) disk_buff);
739
  disk_buff=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
740
  if (new_field_pack_flag <= 1)
741 742 743 744 745
  {
    /* Old file format with default as not null */
    uint null_length= (share->null_fields+7)/8;
    bfill(share->default_values + (outparam->null_flags - (uchar*) record),
          null_length, 255);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
746 747
  }

748 749
  if ((reg_field=outparam->found_next_number_field))
  {
750
    if ((int) (share->next_number_index= (uint)
751
	       find_ref_key(outparam,reg_field,
752
			    &share->next_number_key_offset)) < 0)
753 754 755 756 757 758 759 760
    {
      reg_field->unireg_check=Field::NONE;	/* purecov: inspected */
      outparam->found_next_number_field=0;
    }
    else
      reg_field->flags|=AUTO_INCREMENT_FLAG;
  }

761
  if (share->blob_fields)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
762 763
  {
    Field **ptr;
764
    uint i, *save;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
765

766 767 768 769
    /* Store offsets to blob fields to find them fast */
    if (!(share->blob_field= save=
	  (uint*) alloc_root(&outparam->mem_root,
                             (uint) (share->blob_fields* sizeof(uint)))))
770
      goto err_not_open;
771
    for (i=0, ptr= outparam->field ; *ptr ; ptr++, i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
772 773
    {
      if ((*ptr)->flags & BLOB_FLAG)
774
	(*save++)= i;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
775 776 777
    }
  }

778
  /* The table struct is now initialized;  Open the table */
779 780 781 782
  error=2;
  if (db_stat)
  {
    int err;
783
    unpack_filename(index_file,index_file);
784
    if ((err=(outparam->file->
785
	      ha_open(index_file,
786 787 788 789 790 791 792 793 794 795
		      (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 */
796 797 798
      share->crashed= ((err == HA_ERR_CRASHED_ON_USAGE) &&
                       outparam->file->auto_repair() &&
                       !(ha_open_flags & HA_OPEN_FOR_REPAIR));
799

800
      if (err == HA_ERR_NO_SUCH_TABLE)
801 802 803 804 805 806
      {
	/* 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;
      }
807 808 809 810 811
      else
      {
        outparam->file->print_error(err, MYF(0));
        error_reported= TRUE;
      }
812 813 814
      goto err_not_open; /* purecov: inspected */
    }
  }
815
  share->db_low_byte_first= outparam->file->low_byte_first();
816

817
  *root_ptr= old_root;
818
  thd->status_var.opened_tables++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
819 820
#ifndef DBUG_OFF
  if (use_hash)
821
    (void) hash_check(&share->name_hash);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
822 823 824
#endif
  DBUG_RETURN (0);

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
825
 err_w_init:
826 827 828 829 830
  /*
    Avoid problem with uninitialized data
    Note that we don't have to initialize outparam->s here becasue
    the caller will check if the pointer exists in case of errors
  */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
831 832
  bzero((char*) outparam,sizeof(*outparam));

bk@work.mysql.com's avatar
bk@work.mysql.com committed
833 834
 err_not_open:
  x_free((gptr) disk_buff);
835 836
  if (file > 0)
    VOID(my_close(file,MYF(MY_WME)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
837 838

  delete crypted;
839
  *root_ptr= old_root;
840
  if (! error_reported)
serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
841
    frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG, errarg);
842
  delete outparam->file;
843
  outparam->file=0;				// For easier errorchecking
844
  outparam->db_stat=0;
845
  hash_free(&share->name_hash);
846
  free_root(&outparam->mem_root, MYF(0));
847
  my_free((char*) outparam->alias, MYF(MY_ALLOW_ZERO_PTR));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
848 849 850 851 852 853 854 855 856 857 858 859
  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();
860 861 862
  my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR));
  table->alias= 0;
  if (table->field)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
863 864 865
  {
    for (Field **ptr=table->field ; *ptr ; ptr++)
      delete *ptr;
866
    table->field= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
867 868
  }
  delete table->file;
869 870 871
  table->file= 0;				/* For easier errorchecking */
  hash_free(&table->s->name_hash);
  free_root(&table->mem_root, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
872 873 874 875 876 877 878 879
  DBUG_RETURN(error);
}


/* Deallocate temporary blob storage */

void free_blobs(register TABLE *table)
{
880 881 882 883 884
  uint *ptr, *end;
  for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
       ptr != end ;
       ptr++)
    ((Field_blob*) table->field[*ptr])->free();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
}


	/* 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");

965
  length=(uint) strlen(newname)+1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
966 967 968 969 970 971 972 973 974
  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);
975
    endpos=(ulong) my_seek(file,0L,MY_SEEK_END,MYF(0));/* Copy from file-end */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
    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);
1019
  VOID(my_chsize(file, newpos, 0, MYF(MY_WME)));/* Append file with '\0' */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1020 1021 1022 1023 1024 1025
  DBUG_RETURN(newpos);
} /* make_new_entry */


	/* error message when opening a form file */

1026 1027
static void frm_error(int error, TABLE *form, const char *name,
                      myf errortype, int errarg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1028 1029 1030 1031
{
  int err_no;
  char buff[FN_REFLEN];
  const char *form_dev="",*datext;
1032
  const char *real_name= (char*) name+dirname_length(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
  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);
1043
      my_error(ER_NO_SUCH_TABLE, MYF(0), db, real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1044 1045
    }
    else
1046 1047
      my_error(ER_FILE_NOT_FOUND, errortype,
               fn_format(buff, name, form_dev, reg_ext, 0), my_errno);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1048 1049 1050
    break;
  case 2:
  {
1051 1052
    datext= form->file ? *form->file->bas_ext() : "";
    datext= datext==NullS ? "" : datext;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1053 1054 1055
    err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
      ER_FILE_USED : ER_CANT_OPEN_FILE;
    my_error(err_no,errortype,
1056
	     fn_format(buff,real_name,form_dev,datext,2),my_errno);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1057 1058
    break;
  }
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
  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", 
1070
                    MYF(0), csname, real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1071 1072 1073 1074
    break;
  }
  default:				/* Better wrong error than none */
  case 4:
1075 1076
    my_error(ER_NOT_FORM_FILE, errortype,
             fn_format(buff, name, form_dev, reg_ext, 0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1077 1078 1079 1080 1081 1082 1083 1084
    break;
  }
  DBUG_VOID_RETURN;
} /* frm_error */


	/*
	** fix a str_type to a array type
1085
	** typeparts separated with some char. differents types are separated
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
	** 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;
      }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1110
      ptr+=2;				/* Skip end mark and last 0 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
    }
    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(List<String> &strings)
{
  TYPELIB *result=(TYPELIB*) sql_alloc(sizeof(TYPELIB));
  if (!result)
    return 0;
  result->count=strings.elements;
  result->name="";
1130 1131
  uint nbytes= (sizeof(char*) + sizeof(uint)) * (result->count + 1);
  if (!(result->type_names= (const char**) sql_alloc(nbytes)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1132
    return 0;
1133
  result->type_lengths= (uint*) (result->type_names + result->count + 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1134 1135 1136
  List_iterator<String> it(strings);
  String *tmp;
  for (uint i=0; (tmp=it++) ; i++)
1137 1138 1139 1140 1141 1142
  {
    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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1143 1144 1145 1146
  return result;
}


1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
/*
 Search after a field with given start & length
 If an exact field isn't found, return longest field with starts
 at right position.
 
 NOTES
   This is needed because in some .frm fields 'fieldnr' was saved wrong

 RETURN
   0  error
   #  field number +1
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1159 1160 1161 1162

static uint find_field(TABLE *form,uint start,uint length)
{
  Field **field;
1163
  uint i, pos, fields;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1164 1165

  pos=0;
1166 1167
  fields= form->s->fields;
  for (field=form->field, i=1 ; i<= fields ; i++,field++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
  {
    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);
}


1182
	/* Check that the integer is in the internal */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203

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 */


1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
/*
  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.
*/
1217

1218
void append_unescaped(String *res, const char *pos, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1219
{
1220 1221 1222 1223
  const char *end= pos+length;
  res->append('\'');

  for (; pos != end ; pos++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1224
  {
monty@mysql.com's avatar
monty@mysql.com committed
1225
#if defined(USE_MB) && MYSQL_VERSION_ID < 40100
bar@mysql.com's avatar
bar@mysql.com committed
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
    uint mblen;
    if (use_mb(default_charset_info) &&
        (mblen= my_ismbchar(default_charset_info, pos, end)))
    {
      res->append(pos, mblen);
      pos+= mblen;
      continue;
    }
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
    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':
1246
      res->append('\\');		/* This gives better readability */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
      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;
    }
  }
1262
  res->append('\'');
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
}

	/* Create a .frm file */

File create_frm(register my_string name, uint reclength, uchar *fileinfo,
		HA_CREATE_INFO *create_info, uint keys)
{
  register File file;
  uint key_length;
  ulong length;
  char fill[IO_SIZE];

#if SIZEOF_OFF_T > 4
monty@mysql.com's avatar
monty@mysql.com committed
1276
  /* Fix this when we have new .frm files;  Current limit is 4G rows (QQ) */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1277 1278 1279 1280 1281
  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
1282 1283 1284 1285 1286
  /*
    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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1287 1288 1289 1290

  if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
  {
    bzero((char*) fileinfo,64);
1291 1292 1293 1294 1295
    /* header */
    fileinfo[0]=(uchar) 254;
    fileinfo[1]= 1;
    fileinfo[2]= FRM_VER+3+ test(create_info->varchar);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1296 1297 1298 1299 1300 1301
    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);
serg@serg.mylan's avatar
serg@serg.mylan committed
1302
    if (key_length > 0xffff) key_length=0xffff;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1303 1304 1305 1306 1307 1308 1309 1310 1311
    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);
1312 1313
    fileinfo[38]= (create_info->default_table_charset ?
		   create_info->default_table_charset->number : 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
    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);
      }
    }
  }
  return (file);
} /* create_frm */


void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
{
1335
  TABLE_SHARE *share= table->s;
1336
  DBUG_ENTER("update_create_info_from_table");
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346

  create_info->max_rows= share->max_rows;
  create_info->min_rows= share->min_rows;
  create_info->table_options= share->db_create_options;
  create_info->avg_row_length= share->avg_row_length;
  create_info->row_type= share->row_type;
  create_info->raid_type= share->raid_type;
  create_info->raid_chunks= share->raid_chunks;
  create_info->raid_chunksize= share->raid_chunksize;
  create_info->default_table_charset= share->table_charset;
1347
  create_info->table_charset= 0;
1348

1349
  DBUG_VOID_RETURN;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1350
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361

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)));
}


vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
/*
  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
1372 1373
    1   string is empty
    0	all ok
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1374 1375 1376 1377
*/

bool get_field(MEM_ROOT *mem, Field *field, String *res)
{
1378
  char buff[MAX_FIELD_WIDTH], *to;
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1379
  String str(buff,sizeof(buff),&my_charset_bin);
1380 1381
  uint length;

1382
  field->val_str(&str);
1383 1384 1385 1386 1387
  if (!(length= str.length()))
    return 1;
  to= strmake_root(mem, str.ptr(), length);
  res->set(to, length, ((Field_str*)field)->charset());
  return 0;
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1388 1389
}

1390

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1391
/*
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
  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
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1402 1403
*/

1404
char *get_field(MEM_ROOT *mem, Field *field)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1405
{
monty@mysql.com's avatar
monty@mysql.com committed
1406
  char buff[MAX_FIELD_WIDTH], *to;
1407
  String str(buff,sizeof(buff),&my_charset_bin);
1408 1409
  uint length;

1410
  field->val_str(&str);
monty@mysql.com's avatar
monty@mysql.com committed
1411
  length= str.length();
1412
  if (!length || !(to= (char*) alloc_root(mem,length+1)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1413 1414 1415 1416 1417 1418
    return NullS;
  memcpy(to,str.ptr(),(uint) length);
  to[length]=0;
  return to;
}

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435

/*
  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)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1436
{
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1437
  char *start=name;
monty@mysql.com's avatar
monty@mysql.com committed
1438 1439
  /* Used to catch empty names and names with end space */
  bool last_char_is_space= TRUE;
1440

1441
  if (lower_case_table_names && name != any_db)
1442
    my_casedn_str(files_charset_info, name);
1443

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1444 1445 1446
  while (*name)
  {
#if defined(USE_MB) && defined(USE_MB_IDENT)
1447
    last_char_is_space= my_isspace(default_charset_info, *name);
1448
    if (use_mb(system_charset_info))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1449
    {
1450
      int len=my_ismbchar(system_charset_info, name, 
1451
                          name+system_charset_info->mbmaxlen);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1452 1453 1454 1455 1456 1457
      if (len)
      {
        name += len;
        continue;
      }
    }
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1458
#else
1459
    last_char_is_space= *name==' ';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1460
#endif
1461 1462
    if (*name == '/' || *name == '\\' || *name == FN_LIBCHAR ||
	*name == FN_EXTCHAR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1463 1464 1465
      return 1;
    name++;
  }
1466
  return last_char_is_space || (uint) (name - start) > NAME_LEN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1467 1468 1469 1470 1471 1472
}


/*
  Allow anything as a table name, as long as it doesn't contain an
  a '/', or a '.' character
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1473
  or ' ' at the end
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1474 1475 1476 1477 1478 1479 1480
  returns 1 on error
*/


bool check_table_name(const char *name, uint length)
{
  const char *end= name+length;
1481 1482
  if (!length || length > NAME_LEN)
    return 1;
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1483
#if defined(USE_MB) && defined(USE_MB_IDENT)
1484
  bool last_char_is_space= FALSE;
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1485 1486 1487 1488
#else
  if (name[length-1]==' ')
    return 1;
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1489 1490 1491 1492

  while (name != end)
  {
#if defined(USE_MB) && defined(USE_MB_IDENT)
1493
    last_char_is_space= my_isspace(default_charset_info, *name);
1494
    if (use_mb(system_charset_info))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1495
    {
1496
      int len=my_ismbchar(system_charset_info, name, end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1497 1498 1499 1500 1501 1502 1503
      if (len)
      {
        name += len;
        continue;
      }
    }
#endif
1504
    if (*name == '/' || *name == '\\' || *name == FN_EXTCHAR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1505 1506 1507
      return 1;
    name++;
  }
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1508
#if defined(USE_MB) && defined(USE_MB_IDENT)
1509 1510
  return last_char_is_space;
#else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1511
  return 0;
1512
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1513 1514
}

monty@mysql.com's avatar
monty@mysql.com committed
1515

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1516 1517
bool check_column_name(const char *name)
{
1518
  const char *start= name;
monty@mysql.com's avatar
monty@mysql.com committed
1519
  bool last_char_is_space= TRUE;
1520
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1521 1522 1523
  while (*name)
  {
#if defined(USE_MB) && defined(USE_MB_IDENT)
1524
    last_char_is_space= my_isspace(default_charset_info, *name);
1525
    if (use_mb(system_charset_info))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1526
    {
1527
      int len=my_ismbchar(system_charset_info, name, 
1528
                          name+system_charset_info->mbmaxlen);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1529 1530 1531 1532 1533 1534
      if (len)
      {
        name += len;
        continue;
      }
    }
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1535
#else
1536
    last_char_is_space= *name==' ';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1537 1538 1539 1540 1541
#endif
    if (*name == NAMES_SEP_CHAR)
      return 1;
    name++;
  }
1542
  /* Error if empty or too long column name */
monty@mysql.com's avatar
monty@mysql.com committed
1543
  return last_char_is_space || (uint) (name - start) > NAME_LEN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
}

/*
** 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 ||
1563 1564
      (head[2] != FRM_VER && head[2] != FRM_VER+1 &&
       (head[2] < FRM_VER+3 || head[2] > FRM_VER+4)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1565 1566 1567 1568 1569
    DBUG_RETURN(DB_TYPE_UNKNOWN);
  DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
}


bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1570 1571 1572 1573 1574 1575 1576
/*
  calculate md5 of query

  SYNOPSIS
    st_table_list::calc_md5()
    buffer	buffer for md5 writing
*/
1577

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1578 1579 1580
void  st_table_list::calc_md5(char *buffer)
{
  my_MD5_CTX context;
1581 1582 1583 1584
  uchar digest[16];
  my_MD5Init(&context);
  my_MD5Update(&context,(uchar *) query.str, query.length);
  my_MD5Final(digest, &context);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
  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()
*/
1600

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1601 1602
void st_table_list::set_ancestor()
{
1603 1604 1605 1606 1607 1608 1609 1610 1611
  /* 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)
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1612
  {
1613
    table= ancestor->table;
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1614 1615
    schema_table= ancestor->schema_table;
  }
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664
}


/*
  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();
    }
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1665 1666 1667 1668 1669 1670 1671 1672
}


/*
  setup fields of placeholder of merged VIEW

  SYNOPSIS
    st_table_list::setup_ancestor()
1673 1674 1675 1676
    thd		    - thread handler
    conds           - condition of this JOIN
    check_opt_type  - WHITH CHECK OPTION type (VIEW_CHECK_NONE,
                      VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1677

1678 1679 1680 1681 1682 1683 1684 1685
  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.

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1686 1687 1688 1689
  RETURN
    0 - OK
    1 - error
*/
1690

1691 1692
bool st_table_list::setup_ancestor(THD *thd, Item **conds,
				   uint8 check_opt_type)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1693
{
1694
  Field_translator *transl;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1695
  SELECT_LEX *select= &view->select_lex;
1696
  SELECT_LEX *current_select_save= thd->lex->current_select;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1697
  Item *item;
1698
  TABLE_LIST *tbl;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1699 1700 1701
  List_iterator_fast<Item> it(select->item_list);
  uint i= 0;
  bool save_set_query_id= thd->set_query_id;
1702
  bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
1703
  bool save_allow_sum_func= thd->allow_sum_func;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1704 1705
  DBUG_ENTER("st_table_list::setup_ancestor");

1706 1707
  for (tbl= ancestor; tbl; tbl= tbl->next_local)
  {
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1708 1709 1710 1711 1712
    if (tbl->ancestor &&
        tbl->setup_ancestor(thd, conds,
                            (check_opt_type == VIEW_CHECK_CASCADED ?
                             VIEW_CHECK_CASCADED :
                             VIEW_CHECK_NONE)))
1713 1714
      DBUG_RETURN(1);
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1715 1716 1717

  if (field_translation)
  {
1718
    DBUG_PRINT("info", ("there are already translation table"));
1719 1720
    /* prevent look up in SELECTs tree */
    thd->lex->current_select= &thd->lex->select_lex;
1721
    thd->lex->select_lex.no_wrap_view_item= 1;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1722 1723
    thd->set_query_id= 1;
    /* this view was prepared already on previous PS/SP execution */
1724 1725 1726 1727 1728 1729
    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++)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1730
    {
1731 1732
      if (!transl->item->fixed &&
          transl->item->fix_fields(thd, ancestor, &transl->item))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1733
        goto err;
1734 1735 1736 1737 1738 1739 1740 1741 1742
    }
    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;
1743
    if (check_option && !check_option->fixed &&
1744
        check_option->fix_fields(thd, ancestor, &check_option))
1745
      goto err;
1746 1747 1748 1749 1750 1751
    restore_want_privilege();

    /* WHERE/ON resolved => we can rename fields */
    for (transl= field_translation; transl < end; transl++)
    {
      transl->item->rename((char *)transl->name);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1752 1753 1754 1755 1756 1757
    }
    goto ok;
  }

  /* view fields translation table */
  if (!(transl=
1758 1759 1760
	(Field_translator*)(thd->current_arena->
                            alloc(select->item_list.elements *
                                  sizeof(Field_translator)))))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1761 1762 1763
  {
    DBUG_RETURN(1);
  }
1764 1765 1766

  /* prevent look up in SELECTs tree */
  thd->lex->current_select= &thd->lex->select_lex;
1767 1768
  thd->lex->select_lex.no_wrap_view_item= 1;

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1769 1770 1771 1772 1773 1774 1775
  /*
    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;
1776 1777 1778 1779
  /* real rights will be checked in VIEW field */
  save_and_clear_want_privilege();
  /* aggregate function are allowed */
  thd->allow_sum_func= 1;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1780 1781
  while ((item= it++))
  {
1782 1783
    /* save original name of view column */
    char *name= item->name;
1784 1785
    transl[i].item= item;
    if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1786
      goto err;
1787
    /* set new item get in fix fields and original column name */
1788
    transl[i++].name= name;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1789 1790
  }
  field_translation= transl;
1791
  /* TODO: sort this list? Use hash for big number of fields */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1792

1793 1794 1795 1796 1797 1798
  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;
  }
1799
  if (where ||
1800
      (check_opt_type == VIEW_CHECK_CASCADED &&
1801
       ancestor->check_option))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1802 1803
  {
    Item_arena *arena= thd->current_arena, backup;
1804
    TABLE_LIST *tbl= this;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1805
    if (arena->is_conventional())
1806 1807
      arena= 0;                                   // For easier test

1808
    if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1809 1810 1811
      goto err;

    if (arena)
1812
      thd->set_n_backup_item_arena(arena, &backup);
1813

1814
    if (check_opt_type)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1815
    {
1816 1817
      if (where)
	check_option= where->copy_andor_structure(thd);
1818
      if (check_opt_type == VIEW_CHECK_CASCADED)
1819
      {
1820
        check_option= and_conds(check_option, ancestor->check_option);
1821
      }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1822
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1823 1824 1825 1826 1827

    /*
      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)
    */
1828
    if (where && !no_where_clause)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1829
    {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1830 1831
      /* Go up to join tree and try to find left join */
      for (; tbl; tbl= tbl->embedding)
1832
      {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1833 1834 1835 1836
        if (tbl->outer_join)
        {
          /*
            Store WHERE condition to ON expression for outer join, because
1837
            we can't use WHERE to correctly execute left joins on VIEWs and
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1838 1839 1840 1841 1842 1843
            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;
        }
1844
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1845
      if (tbl == 0)
1846
      {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1847 1848 1849 1850
        if (outer_join)
        {
          /*
            Store WHERE condition to ON expression for outer join, because
1851
            we can't use WHERE to correctly execute left joins on VIEWs and
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864
            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);
        }
1865
      }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1866
    }
1867

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1868 1869 1870
    if (arena)
      thd->restore_backup_item_arena(arena, &backup);
  }
1871 1872
  restore_want_privilege();

1873 1874 1875 1876 1877 1878 1879
  /*
    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;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1880

1881 1882 1883 1884 1885 1886 1887 1888
  /* 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);
    }
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1889

1890 1891 1892
  /* full text function moving to current select */
  if (view->select_lex.ftfunc_list->elements)
  {
1893 1894 1895 1896 1897 1898
    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);

1899 1900 1901 1902 1903
    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);
1904 1905
    if (arena)
      thd->restore_backup_item_arena(arena, &backup);
1906 1907
  }

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1908
ok:
1909
  thd->lex->select_lex.no_wrap_view_item= save_wrapper;
1910
  thd->lex->current_select= current_select_save;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1911
  thd->set_query_id= save_set_query_id;
1912
  thd->allow_sum_func= save_allow_sum_func;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1913 1914 1915
  DBUG_RETURN(0);

err:
1916 1917 1918
  /* 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)
1919 1920 1921 1922
  {
    thd->clear_error();
    my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
  }
1923
  thd->lex->select_lex.no_wrap_view_item= save_wrapper;
1924
  thd->lex->current_select= current_select_save;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1925
  thd->set_query_id= save_set_query_id;
1926
  thd->allow_sum_func= save_allow_sum_func;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1927 1928 1929 1930
  DBUG_RETURN(1);
}


bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
/*
  cleunup items belonged to view fields translation table

  SYNOPSIS
    st_table_list::cleanup_items()
*/

void st_table_list::cleanup_items()
{
  if (!field_translation)
    return;

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1943 1944 1945 1946
  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);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1947 1948 1949
}


bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
/*
  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);
}


1984
/*
1985
  Find table in underlying tables by mask and check that only this
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1986
  table belong to given mask
1987 1988 1989 1990 1991 1992 1993 1994 1995

  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
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1996 1997
    FALSE table not found or found only one
    TRUE  found several tables
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
*/

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)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2009
	  return TRUE;
2010 2011 2012 2013 2014 2015
	else
	  *table= tbl;
      }
    }
    else
      if (tbl->check_single_table(table, map))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2016
	return TRUE;
2017
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2018
  return FALSE;
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
}


/*
  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,
2040
                                                   table->s->rec_buff_length)))
2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
      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;
}


bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
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()
{
2075
  return ptr->name;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2076 2077 2078
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2079 2080 2081 2082 2083 2084 2085 2086
/*****************************************************************************
** Instansiate templates
*****************************************************************************/

#ifdef __GNUC__
template class List<String>;
template class List_iterator<String>;
#endif