mi_open.c 43.1 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000-2006 MySQL AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4
   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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
6

unknown's avatar
unknown committed
7 8 9 10
   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.
unknown's avatar
unknown committed
11

unknown's avatar
unknown committed
12 13 14 15 16 17 18
   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 */

/* open a isam-database */

#include "fulltext.h"
19 20
#include "sp_defs.h"
#include "rt_index.h"
unknown's avatar
unknown committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#include <m_ctype.h>

#if defined(MSDOS) || defined(__WIN__)
#ifdef __WIN__
#include <fcntl.h>
#else
#include <process.h>			/* Prototype for getpid */
#endif
#endif
#ifdef VMS
#include "static.c"
#endif

static void setup_key_functions(MI_KEYDEF *keyinfo);
#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
					pos+=size;}


39 40 41 42 43 44 45 46
#define disk_pos_assert(pos, end_pos) \
if (pos > end_pos)             \
{                              \
  my_errno=HA_ERR_CRASHED;     \
  goto err;                    \
}


unknown's avatar
unknown committed
47 48 49 50 51
/******************************************************************************
** Return the shared struct if the table is already open.
** In MySQL the server will handle version issues.
******************************************************************************/

52
MI_INFO *test_if_reopen(char *filename)
unknown's avatar
unknown committed
53 54 55 56 57 58 59
{
  LIST *pos;

  for (pos=myisam_open_list ; pos ; pos=pos->next)
  {
    MI_INFO *info=(MI_INFO*) pos->data;
    MYISAM_SHARE *share=info->s;
unknown's avatar
unknown committed
60
    if (!strcmp(share->unique_file_name,filename) && share->last_version)
unknown's avatar
unknown committed
61 62 63 64 65 66 67
      return info;
  }
  return 0;
}


/******************************************************************************
68 69 70 71 72
  open a MyISAM database.
  See my_base.h for the handle_locking argument
  if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
  is marked crashed or if we are not using locking and the table doesn't
  have an open count of 0.
unknown's avatar
unknown committed
73 74
******************************************************************************/

75
MI_INFO *mi_open(const char *name, int mode, uint open_flags)
unknown's avatar
unknown committed
76
{
77
  int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err;
unknown's avatar
unknown committed
78
  uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
79
    key_parts,unique_key_parts,fulltext_keys,uniques;
unknown's avatar
unknown committed
80
  char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
unknown's avatar
unknown committed
81
       data_name[FN_REFLEN];
82
  uchar *disk_cache, *disk_pos, *end_pos;
unknown's avatar
unknown committed
83 84
  MI_INFO info,*m_info,*old_info;
  MYISAM_SHARE share_buff,*share;
85 86
  ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
  my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
unknown's avatar
unknown committed
87 88 89 90 91 92 93 94
  ulonglong max_key_file_length, max_data_file_length;
  DBUG_ENTER("mi_open");

  LINT_INIT(m_info);
  kfile= -1;
  lock_error=1;
  errpos=0;
  head_length=sizeof(share_buff.state.header);
95
  bzero((uchar*) &info,sizeof(info));
unknown's avatar
unknown committed
96

97 98 99 100 101 102 103 104 105
  realpath_err= my_realpath(name_buff,
                  fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
  if (my_is_symlink(org_name) &&
      (realpath_err || (*myisam_test_invalid_symlink)(name_buff)))
  {
    my_errno= HA_WRONG_CREATE_OPTION;
    DBUG_RETURN (NULL);
  }

unknown's avatar
unknown committed
106 107 108 109
  pthread_mutex_lock(&THR_LOCK_myisam);
  if (!(old_info=test_if_reopen(name_buff)))
  {
    share= &share_buff;
110
    bzero((uchar*) &share_buff,sizeof(share_buff));
unknown's avatar
unknown committed
111 112 113
    share_buff.state.rec_per_key_part=rec_per_key_part;
    share_buff.state.key_root=key_root;
    share_buff.state.key_del=key_del;
114 115
    share_buff.key_cache= multi_key_cache_search((uchar*) name_buff,
                                                 strlen(name_buff));
unknown's avatar
unknown committed
116

117 118 119 120 121 122
    DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
                    if (strstr(name, "/t1"))
                    {
                      my_errno= HA_ERR_CRASHED;
                      goto err;
                    });
unknown's avatar
unknown committed
123 124 125 126 127 128 129
    if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
    {
      if ((errno != EROFS && errno != EACCES) ||
	  mode != O_RDONLY ||
	  (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
	goto err;
    }
130
    share->mode=open_mode;
unknown's avatar
unknown committed
131
    errpos=1;
132
    if (my_read(kfile, share->state.header.file_version, head_length,
unknown's avatar
unknown committed
133
		MYF(MY_NABP)))
unknown's avatar
unknown committed
134 135
    {
      my_errno= HA_ERR_NOT_A_TABLE;
unknown's avatar
unknown committed
136
      goto err;
unknown's avatar
unknown committed
137
    }
138 139
    if (memcmp((uchar*) share->state.header.file_version,
	       (uchar*) myisam_file_magic, 4))
unknown's avatar
unknown committed
140 141 142 143
    {
      DBUG_PRINT("error",("Wrong header in %s",name_buff));
      DBUG_DUMP("error_dump",(char*) share->state.header.file_version,
		head_length);
unknown's avatar
unknown committed
144
      my_errno=HA_ERR_NOT_A_TABLE;
unknown's avatar
unknown committed
145 146 147 148 149 150 151
      goto err;
    }
    share->options= mi_uint2korr(share->state.header.options);
    if (share->options &
	~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
	  HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
	  HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
152 153
          HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
          HA_OPTION_RELIES_ON_SQL_LAYER))
unknown's avatar
unknown committed
154
    {
155
      DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
unknown's avatar
unknown committed
156 157 158
      my_errno=HA_ERR_OLD_FILE;
      goto err;
    }
159 160 161 162 163 164 165
    if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
        ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
    {
      DBUG_PRINT("error", ("table cannot be openned from non-sql layer"));
      my_errno= HA_ERR_UNSUPPORTED;
      goto err;
    }
unknown's avatar
unknown committed
166
    /* Don't call realpath() if the name can't be a link */
167
    if (!strcmp(name_buff, org_name) ||
unknown's avatar
unknown committed
168
        my_readlink(index_name, org_name, MYF(0)) == -1)
169
      (void) strmov(index_name, org_name);
170 171 172
    *strrchr(org_name, '.')= '\0';
    (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,
                     MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
unknown's avatar
unknown committed
173

unknown's avatar
unknown committed
174 175
    info_length=mi_uint2korr(share->state.header.header_length);
    base_pos=mi_uint2korr(share->state.header.base_pos);
176
    if (!(disk_cache= (uchar*) my_alloca(info_length+128)))
unknown's avatar
unknown committed
177 178 179 180
    {
      my_errno=ENOMEM;
      goto err;
    }
181
    end_pos=disk_cache+info_length;
unknown's avatar
unknown committed
182 183 184
    errpos=2;

    VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
185
    if (!(open_flags & HA_OPEN_TMP_TABLE))
unknown's avatar
unknown committed
186 187
    {
      if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
188
			      MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ?
unknown's avatar
unknown committed
189
				  0 : MY_DONT_WAIT))) &&
190
	  !(open_flags & HA_OPEN_IGNORE_IF_LOCKED))
unknown's avatar
unknown committed
191 192 193 194
	goto err;
    }
    errpos=3;
    if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
unknown's avatar
unknown committed
195 196
    {
      my_errno=HA_ERR_CRASHED;
unknown's avatar
unknown committed
197
      goto err;
unknown's avatar
unknown committed
198
    }
unknown's avatar
unknown committed
199 200 201
    len=mi_uint2korr(share->state.header.state_info_length);
    keys=    (uint) share->state.header.keys;
    uniques= (uint) share->state.header.uniques;
202
    fulltext_keys= (uint) share->state.header.fulltext_keys;
unknown's avatar
unknown committed
203 204 205 206 207 208 209 210 211 212
    key_parts= mi_uint2korr(share->state.header.key_parts);
    unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
    if (len != MI_STATE_INFO_SIZE)
    {
      DBUG_PRINT("warning",
		 ("saved_state_info_length: %d  state_info_length: %d",
		  len,MI_STATE_INFO_SIZE));
    }
    share->state_diff_length=len-MI_STATE_INFO_SIZE;

213
    mi_state_info_read(disk_cache, &share->state);
unknown's avatar
unknown committed
214 215 216 217
    len= mi_uint2korr(share->state.header.base_info_length);
    if (len != MI_BASE_INFO_SIZE)
    {
      DBUG_PRINT("warning",("saved_base_info_length: %d  base_info_length: %d",
unknown's avatar
unknown committed
218
			    len,MI_BASE_INFO_SIZE));
unknown's avatar
unknown committed
219
    }
220
    disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
unknown's avatar
unknown committed
221 222
    share->state.state_length=base_pos;

223
    if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
224
	((share->state.changed & STATE_CRASHED) ||
225 226
	 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
	  (my_disable_locking && share->state.open_count))))
227
    {
228 229 230 231
      DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u  "
                          "changed: %u  open_count: %u  !locking: %d",
                          open_flags, share->state.changed,
                          share->state.open_count, my_disable_locking));
232
      my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
233
		HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
234 235
      goto err;
    }
236 237 238 239 240 241 242 243

    /* sanity check */
    if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
    {
      my_errno=HA_ERR_CRASHED;
      goto err;
    }

244
    key_parts+=fulltext_keys*FT_SEGS;
245
    if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
246
	key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
247 248 249 250 251 252
    {
      DBUG_PRINT("error",("Wrong key info:  Max_key_length: %d  keys: %d  key_parts: %d", share->base.max_key_length, keys, key_parts));
      my_errno=HA_ERR_UNSUPPORTED;
      goto err;
    }

253
    /* Correct max_file_length based on length of sizeof(off_t) */
unknown's avatar
unknown committed
254 255 256
    max_data_file_length=
      (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
      (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
257
      (mi_safe_mul(share->base.pack_reclength,
unknown's avatar
unknown committed
258 259
		   (ulonglong) 1 << (share->base.rec_reflength*8))-1);
    max_key_file_length=
unknown's avatar
unknown committed
260
      mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
unknown's avatar
unknown committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
		  ((ulonglong) 1 << (share->base.key_reflength*8))-1);
#if SIZEOF_OFF_T == 4
    set_if_smaller(max_data_file_length, INT_MAX32);
    set_if_smaller(max_key_file_length, INT_MAX32);
#endif
#if USE_RAID && SYSTEM_SIZEOF_OFF_T == 4
    set_if_smaller(max_key_file_length, INT_MAX32);
    if (!share->base.raid_type)
    {
      set_if_smaller(max_data_file_length, INT_MAX32);
    }
    else
    {
      set_if_smaller(max_data_file_length,
		     (ulonglong) share->base.raid_chunks << 31);
    }
#elif !defined(USE_RAID)
    if (share->base.raid_type)
    {
unknown's avatar
unknown committed
280
      DBUG_PRINT("error",("Table uses RAID but we don't have RAID support"));
unknown's avatar
unknown committed
281 282 283 284 285 286 287 288 289 290
      my_errno=HA_ERR_UNSUPPORTED;
      goto err;
    }
#endif
    share->base.max_data_file_length=(my_off_t) max_data_file_length;
    share->base.max_key_file_length=(my_off_t) max_key_file_length;

    if (share->options & HA_OPTION_COMPRESS_RECORD)
      share->base.max_key_length+=2;	/* For safety */

291 292 293
    /* Add space for node pointer */
    share->base.max_key_length+= share->base.key_reflength;

unknown's avatar
unknown committed
294 295 296 297 298 299 300
    if (!my_multi_malloc(MY_WME,
			 &share,sizeof(*share),
			 &share->state.rec_per_key_part,sizeof(long)*key_parts,
			 &share->keyinfo,keys*sizeof(MI_KEYDEF),
			 &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
			 &share->keyparts,
			 (key_parts+unique_key_parts+keys+uniques) *
unknown's avatar
unknown committed
301
			 sizeof(HA_KEYSEG),
unknown's avatar
unknown committed
302 303 304
			 &share->rec,
			 (share->base.fields+1)*sizeof(MI_COLUMNDEF),
			 &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
unknown's avatar
unknown committed
305 306 307
			 &share->unique_file_name,strlen(name_buff)+1,
			 &share->index_file_name,strlen(index_name)+1,
			 &share->data_file_name,strlen(data_name)+1,
unknown's avatar
unknown committed
308 309
			 &share->state.key_root,keys*sizeof(my_off_t),
			 &share->state.key_del,
310
			 (share->state.header.max_block_size_index*sizeof(my_off_t)),
unknown's avatar
unknown committed
311 312 313
#ifdef THREAD
			 &share->key_root_lock,sizeof(rw_lock_t)*keys,
#endif
unknown's avatar
unknown committed
314
			 &share->mmap_lock,sizeof(rw_lock_t),
unknown's avatar
unknown committed
315 316 317 318 319 320 321 322 323 324
			 NullS))
      goto err;
    errpos=4;
    *share=share_buff;
    memcpy((char*) share->state.rec_per_key_part,
	   (char*) rec_per_key_part, sizeof(long)*key_parts);
    memcpy((char*) share->state.key_root,
	   (char*) key_root, sizeof(my_off_t)*keys);
    memcpy((char*) share->state.key_del,
	   (char*) key_del, (sizeof(my_off_t) *
325
			     share->state.header.max_block_size_index));
unknown's avatar
unknown committed
326
    strmov(share->unique_file_name, name_buff);
327
    share->unique_name_length= strlen(name_buff);
unknown's avatar
unknown committed
328 329
    strmov(share->index_file_name,  index_name);
    strmov(share->data_file_name,   data_name);
unknown's avatar
unknown committed
330 331 332

    share->blocksize=min(IO_SIZE,myisam_block_size);
    {
unknown's avatar
unknown committed
333
      HA_KEYSEG *pos=share->keyparts;
334
      uint32 ftkey_nr= 1;
unknown's avatar
unknown committed
335 336
      for (i=0 ; i < keys ; i++)
      {
unknown's avatar
unknown committed
337
        share->keyinfo[i].share= share;
unknown's avatar
unknown committed
338
	disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
unknown's avatar
unknown committed
339
        disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
unknown's avatar
unknown committed
340
 			end_pos);
341 342
        if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE)
          have_rtree=1;
unknown's avatar
unknown committed
343 344 345 346 347
	set_if_smaller(share->blocksize,share->keyinfo[i].block_length);
	share->keyinfo[i].seg=pos;
	for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
	{
	  disk_pos=mi_keyseg_read(disk_pos, pos);
348 349 350 351 352 353 354
          if (pos->flag & HA_BLOB_PART &&
              ! (share->options & (HA_OPTION_COMPRESS_RECORD |
                                   HA_OPTION_PACK_RECORD)))
          {
            my_errno= HA_ERR_CRASHED;
            goto err;
          }
355 356 357
	  if (pos->type == HA_KEYTYPE_TEXT ||
              pos->type == HA_KEYTYPE_VARTEXT1 ||
              pos->type == HA_KEYTYPE_VARTEXT2)
unknown's avatar
unknown committed
358 359 360 361 362 363 364 365 366
	  {
	    if (!pos->language)
	      pos->charset=default_charset_info;
	    else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
	    {
	      my_errno=HA_ERR_UNKNOWN_CHARSET;
	      goto err;
	    }
	  }
367 368
	  else if (pos->type == HA_KEYTYPE_BINARY)
	    pos->charset= &my_charset_bin;
unknown's avatar
unknown committed
369
	}
370 371
	if (share->keyinfo[i].flag & HA_SPATIAL)
	{
372
#ifdef HAVE_SPATIAL
373 374 375
	  uint sp_segs=SPDIMS*2;
	  share->keyinfo[i].seg=pos-sp_segs;
	  share->keyinfo[i].keysegs--;
376 377 378 379
#else
	  my_errno=HA_ERR_UNSUPPORTED;
	  goto err;
#endif
380 381
	}
        else if (share->keyinfo[i].flag & HA_FULLTEXT)
382
	{
383 384 385 386 387 388 389
          if (!fulltext_keys)
          { /* 4.0 compatibility code, to be removed in 5.0 */
            share->keyinfo[i].seg=pos-FT_SEGS;
            share->keyinfo[i].keysegs-=FT_SEGS;
          }
          else
          {
390
            uint k;
391
            share->keyinfo[i].seg=pos;
392
            for (k=0; k < FT_SEGS; k++)
393
            {
394
              *pos= ft_keysegs[k];
395
              pos[0].language= pos[-1].language;
396 397 398 399 400
              if (!(pos[0].charset= pos[-1].charset))
              {
                my_errno=HA_ERR_CRASHED;
                goto err;
              }
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
              pos++;
            }
          }
          if (!share->ft2_keyinfo.seg)
          {
            memcpy(& share->ft2_keyinfo, & share->keyinfo[i], sizeof(MI_KEYDEF));
            share->ft2_keyinfo.keysegs=1;
            share->ft2_keyinfo.flag=0;
            share->ft2_keyinfo.keylength=
            share->ft2_keyinfo.minlength=
            share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
            share->ft2_keyinfo.seg=pos-1;
            share->ft2_keyinfo.end=pos;
            setup_key_functions(& share->ft2_keyinfo);
          }
416
          share->keyinfo[i].ftkey_nr= ftkey_nr++;
417
	}
418
        setup_key_functions(share->keyinfo+i);
unknown's avatar
unknown committed
419 420 421 422
	share->keyinfo[i].end=pos;
	pos->type=HA_KEYTYPE_END;			/* End */
	pos->length=share->base.rec_reflength;
	pos->null_bit=0;
423
	pos->flag=0;					/* For purify */
unknown's avatar
unknown committed
424 425
	pos++;
      }
426
      
unknown's avatar
unknown committed
427 428 429
      for (i=0 ; i < uniques ; i++)
      {
	disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
430
        disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
unknown's avatar
unknown committed
431
			HA_KEYSEG_SIZE, end_pos);
unknown's avatar
unknown committed
432 433 434 435
	share->uniqueinfo[i].seg=pos;
	for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
	{
	  disk_pos=mi_keyseg_read(disk_pos, pos);
436 437 438
	  if (pos->type == HA_KEYTYPE_TEXT ||
              pos->type == HA_KEYTYPE_VARTEXT1 ||
              pos->type == HA_KEYTYPE_VARTEXT2)
unknown's avatar
unknown committed
439 440 441 442 443 444 445 446 447 448 449 450 451
	  {
	    if (!pos->language)
	      pos->charset=default_charset_info;
	    else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
	    {
	      my_errno=HA_ERR_UNKNOWN_CHARSET;
	      goto err;
	    }
	  }
	}
	share->uniqueinfo[i].end=pos;
	pos->type=HA_KEYTYPE_END;			/* End */
	pos->null_bit=0;
452
	pos->flag=0;
unknown's avatar
unknown committed
453 454
	pos++;
      }
455
      share->ftkeys= ftkey_nr;
unknown's avatar
unknown committed
456 457
    }

458
    disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
unknown's avatar
unknown committed
459 460 461 462 463 464 465 466 467
    for (i=j=offset=0 ; i < share->base.fields ; i++)
    {
      disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
      share->rec[i].pack_type=0;
      share->rec[i].huff_tree=0;
      share->rec[i].offset=offset;
      if (share->rec[i].type == (int) FIELD_BLOB)
      {
	share->blobs[j].pack_length=
468
	  share->rec[i].length-portable_sizeof_char_ptr;
unknown's avatar
unknown committed
469 470 471 472 473 474
	share->blobs[j].offset=offset;
	j++;
      }
      offset+=share->rec[i].length;
    }
    share->rec[i].type=(int) FIELD_LAST;	/* End marker */
475 476 477 478 479 480 481
    if (offset > share->base.reclength)
    {
      /* purecov: begin inspected */
      my_errno= HA_ERR_CRASHED;
      goto err;
      /* purecov: end */
    }
unknown's avatar
unknown committed
482 483 484 485 486 487 488

    if (! lock_error)
    {
      VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
      lock_error=1;			/* Database unlocked */
    }

489
    if (mi_open_datafile(&info, share, name, -1))
unknown's avatar
unknown committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
      goto err;
    errpos=5;

    share->kfile=kfile;
    share->this_process=(ulong) getpid();
    share->last_process= share->state.process;
    share->base.key_parts=key_parts;
    share->base.all_key_parts=key_parts+unique_key_parts;
    if (!(share->last_version=share->state.version))
      share->last_version=1;			/* Safety */
    share->rec_reflength=share->base.rec_reflength; /* May be changed */
    share->base.margin_key_file_length=(share->base.max_key_file_length -
					(keys ? MI_INDEX_BLOCK_MARGIN *
					 share->blocksize * keys : 0));
    share->blocksize=min(IO_SIZE,myisam_block_size);
    share->data_file_type=STATIC_RECORD;
    if (share->options & HA_OPTION_COMPRESS_RECORD)
    {
      share->data_file_type = COMPRESSED_RECORD;
      share->options|= HA_OPTION_READ_ONLY_DATA;
      info.s=share;
      if (_mi_read_pack_info(&info,
			     (pbool)
			     test(!(share->options &
				    (HA_OPTION_PACK_RECORD |
				     HA_OPTION_TEMP_COMPRESS_RECORD)))))
	goto err;
    }
    else if (share->options & HA_OPTION_PACK_RECORD)
      share->data_file_type = DYNAMIC_RECORD;
520
    my_afree(disk_cache);
521
    mi_setup_functions(share);
522
    share->is_log_table= FALSE;
unknown's avatar
unknown committed
523 524
#ifdef THREAD
    thr_lock_init(&share->lock);
525
    VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
unknown's avatar
unknown committed
526 527
    for (i=0; i<keys; i++)
      VOID(my_rwlock_init(&share->key_root_lock[i], NULL));
unknown's avatar
unknown committed
528
    VOID(my_rwlock_init(&share->mmap_lock, NULL));
unknown's avatar
unknown committed
529 530 531 532 533 534 535 536 537 538 539
    if (!thr_lock_inited)
    {
      /* Probably a single threaded program; Don't use concurrent inserts */
      myisam_concurrent_insert=0;
    }
    else if (myisam_concurrent_insert)
    {
      share->concurrent_insert=
	((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
			   HA_OPTION_COMPRESS_RECORD |
			   HA_OPTION_TEMP_COMPRESS_RECORD)) ||
540 541
	 (open_flags & HA_OPEN_TMP_TABLE) ||
	 have_rtree) ? 0 : 1;
unknown's avatar
unknown committed
542 543 544 545 546
      if (share->concurrent_insert)
      {
	share->lock.get_status=mi_get_status;
	share->lock.copy_status=mi_copy_status;
	share->lock.update_status=mi_update_status;
547
        share->lock.restore_status= mi_restore_status;
unknown's avatar
unknown committed
548 549 550 551
	share->lock.check_status=mi_check_status;
      }
    }
#endif
552 553 554 555 556 557 558 559
    /*
      Memory mapping can only be requested after initializing intern_lock.
    */
    if (open_flags & HA_OPEN_MMAP)
    {
      info.s= share;
      mi_extra(&info, HA_EXTRA_MMAP, 0);
    }
unknown's avatar
unknown committed
560 561 562 563 564 565 566 567 568
  }
  else
  {
    share= old_info->s;
    if (mode == O_RDWR && share->mode == O_RDONLY)
    {
      my_errno=EACCES;				/* Can't open in write mode */
      goto err;
    }
569
    if (mi_open_datafile(&info, share, name, old_info->dfile))
unknown's avatar
unknown committed
570 571
      goto err;
    errpos=5;
572
    have_rtree= old_info->rtree_recursion_state != NULL;
unknown's avatar
unknown committed
573 574 575 576 577 578 579 580 581
  }

  /* alloc and set up private structure parts */
  if (!my_multi_malloc(MY_WME,
		       &m_info,sizeof(MI_INFO),
		       &info.blobs,sizeof(MI_BLOB)*share->base.blobs,
		       &info.buff,(share->base.max_key_block_length*2+
				   share->base.max_key_length),
		       &info.lastkey,share->base.max_key_length*3+1,
582
		       &info.first_mbr_key, share->base.max_key_length,
583
		       &info.filename,strlen(name)+1,
584
		       &info.rtree_recursion_state,have_rtree ? 1024 : 0,
unknown's avatar
unknown committed
585 586 587
		       NullS))
    goto err;
  errpos=6;
588 589

  if (!have_rtree)
590
    info.rtree_recursion_state= NULL;
unknown's avatar
unknown committed
591

592
  strmov(info.filename,name);
unknown's avatar
unknown committed
593 594 595 596 597 598 599 600 601 602
  memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
  info.lastkey2=info.lastkey+share->base.max_key_length;

  info.s=share;
  info.lastpos= HA_OFFSET_ERROR;
  info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
  info.opt_flag=READ_CHECK_USED;
  info.this_unique= (ulong) info.dfile; /* Uniq number in process */
  if (share->data_file_type == COMPRESSED_RECORD)
    info.this_unique= share->state.unique;
603
  info.this_loop=0;				/* Update counter */
unknown's avatar
unknown committed
604
  info.last_unique= share->state.unique;
605
  info.last_loop=   share->state.update_count;
unknown's avatar
unknown committed
606 607 608 609
  if (mode == O_RDONLY)
    share->options|=HA_OPTION_READ_ONLY_DATA;
  info.lock_type=F_UNLCK;
  info.quick_mode=0;
unknown's avatar
unknown committed
610
  info.bulk_insert=0;
611
  info.ft1_to_ft2=0;
unknown's avatar
unknown committed
612 613 614 615 616 617 618 619 620 621
  info.errkey= -1;
  info.page_changed=1;
  pthread_mutex_lock(&share->intern_lock);
  info.read_record=share->read_record;
  share->reopen++;
  share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
  if (share->options & HA_OPTION_READ_ONLY_DATA)
  {
    info.lock_type=F_RDLCK;
    share->r_locks++;
622
    share->tot_locks++;
unknown's avatar
unknown committed
623
  }
624
  if ((open_flags & HA_OPEN_TMP_TABLE) ||
unknown's avatar
unknown committed
625 626 627 628 629
      (share->options & HA_OPTION_TMP_TABLE))
  {
    share->temporary=share->delay_key_write=1;
    share->write_flag=MYF(MY_NABP);
    share->w_locks++;			/* We don't have to update status */
630
    share->tot_locks++;
unknown's avatar
unknown committed
631 632
    info.lock_type=F_WRLCK;
  }
633
  if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) ||
unknown's avatar
unknown committed
634 635 636 637 638 639 640 641
      (share->options & HA_OPTION_DELAY_KEY_WRITE)) &&
      myisam_delay_key_write)
    share->delay_key_write=1;
  info.state= &share->state.state;	/* Change global values by default */
  pthread_mutex_unlock(&share->intern_lock);

  /* Allocate buffer for one record */

642
  /* prerequisites: bzero(info) && info->s=share; are met. */
643
  if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff))
unknown's avatar
unknown committed
644
    goto err;
645
  bzero(info.rec_buff, mi_get_rec_buff_len(&info, info.rec_buff));
unknown's avatar
unknown committed
646 647 648 649 650 651 652 653 654

  *m_info=info;
#ifdef THREAD
  thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
#endif
  m_info->open_list.data=(void*) m_info;
  myisam_open_list=list_add(myisam_open_list,&m_info->open_list);

  pthread_mutex_unlock(&THR_LOCK_myisam);
655 656 657

  bzero(info.buff, share->base.max_key_block_length * 2);

658 659
  if (myisam_log_file >= 0)
  {
unknown's avatar
unknown committed
660
    intern_filename(name_buff,share->index_file_name);
661
    _myisam_log(MI_LOG_OPEN, m_info, (uchar*) name_buff, strlen(name_buff));
662
  }
unknown's avatar
unknown committed
663 664 665 666
  DBUG_RETURN(m_info);

err:
  save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
667 668 669 670
  if ((save_errno == HA_ERR_CRASHED) ||
      (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
      (save_errno == HA_ERR_CRASHED_ON_REPAIR))
    mi_report_error(save_errno, name);
unknown's avatar
unknown committed
671 672
  switch (errpos) {
  case 6:
673
    my_free((uchar*) m_info,MYF(0));
unknown's avatar
unknown committed
674 675 676 677 678 679 680
    /* fall through */
  case 5:
    VOID(my_close(info.dfile,MYF(0)));
    if (old_info)
      break;					/* Don't remove open table */
    /* fall through */
  case 4:
681
    my_free((uchar*) share,MYF(0));
unknown's avatar
unknown committed
682 683 684 685 686 687
    /* fall through */
  case 3:
    if (! lock_error)
      VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
    /* fall through */
  case 2:
688
    my_afree(disk_cache);
unknown's avatar
unknown committed
689 690 691 692 693 694 695 696 697 698 699 700 701
    /* fall through */
  case 1:
    VOID(my_close(kfile,MYF(0)));
    /* fall through */
  case 0:
  default:
    break;
  }
  pthread_mutex_unlock(&THR_LOCK_myisam);
  my_errno=save_errno;
  DBUG_RETURN (NULL);
} /* mi_open */

702

703
uchar *mi_alloc_rec_buff(MI_INFO *info, ulong length, uchar **buf)
704 705
{
  uint extra;
706
  uint32 UNINIT_VAR(old_length);
707
  LINT_INIT(old_length);
708

709
  if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
710
  {
711
    uchar *newptr = *buf;
712 713

    /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
714
    if (length == (ulong) -1)
715
    {
716 717 718 719 720
      if (info->s->options & HA_OPTION_COMPRESS_RECORD)
        length= max(info->s->base.pack_reclength, info->s->max_pack_length);
      else
        length= info->s->base.pack_reclength;
      length= max(length, info->s->base.max_key_length);
721 722 723 724
      /* Avoid unnecessary realloc */
      if (newptr && length == old_length)
	return newptr;
    }
725 726

    extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
727 728
	    ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
	    MI_REC_BUFF_OFFSET : 0);
729
    if (extra && newptr)
730
      newptr-= MI_REC_BUFF_OFFSET;
731
    if (!(newptr=(uchar*) my_realloc((uchar*)newptr, length+extra+8,
732 733
                                     MYF(MY_ALLOW_ZERO_PTR))))
      return newptr;
734
    *((uint32 *) newptr)= (uint32) length;
735
    *buf= newptr+(extra ?  MI_REC_BUFF_OFFSET : 0);
736 737 738
  }
  return *buf;
}
unknown's avatar
unknown committed
739

740

unknown's avatar
unknown committed
741 742 743 744 745 746 747 748 749 750 751
ulonglong mi_safe_mul(ulonglong a, ulonglong b)
{
  ulonglong max_val= ~ (ulonglong) 0;		/* my_off_t is unsigned */

  if (!a || max_val / a < b)
    return max_val;
  return a*b;
}

	/* Set up functions in structs */

752
void mi_setup_functions(register MYISAM_SHARE *share)
unknown's avatar
unknown committed
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
{
  if (share->options & HA_OPTION_COMPRESS_RECORD)
  {
    share->read_record=_mi_read_pack_record;
    share->read_rnd=_mi_read_rnd_pack_record;
    if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
      share->calc_checksum=0;				/* No checksum */
    else if (share->options & HA_OPTION_PACK_RECORD)
      share->calc_checksum= mi_checksum;
    else
      share->calc_checksum= mi_static_checksum;
  }
  else if (share->options & HA_OPTION_PACK_RECORD)
  {
    share->read_record=_mi_read_dynamic_record;
    share->read_rnd=_mi_read_rnd_dynamic_record;
    share->delete_record=_mi_delete_dynamic_record;
    share->compare_record=_mi_cmp_dynamic_record;
    share->compare_unique=_mi_cmp_dynamic_unique;
    share->calc_checksum= mi_checksum;

unknown's avatar
unknown committed
774 775
    /* add bits used to pack data to pack_reclength for faster allocation */
    share->base.pack_reclength+= share->base.pack_bits;
unknown's avatar
unknown committed
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
    if (share->base.blobs)
    {
      share->update_record=_mi_update_blob_record;
      share->write_record=_mi_write_blob_record;
    }
    else
    {
      share->write_record=_mi_write_dynamic_record;
      share->update_record=_mi_update_dynamic_record;
    }
  }
  else
  {
    share->read_record=_mi_read_static_record;
    share->read_rnd=_mi_read_rnd_static_record;
    share->delete_record=_mi_delete_static_record;
    share->compare_record=_mi_cmp_static_record;
    share->update_record=_mi_update_static_record;
    share->write_record=_mi_write_static_record;
    share->compare_unique=_mi_cmp_static_unique;
    share->calc_checksum= mi_static_checksum;
  }
unknown's avatar
unknown committed
798 799
  share->file_read= mi_nommap_pread;
  share->file_write= mi_nommap_pwrite;
unknown's avatar
unknown committed
800 801 802 803 804 805 806 807
  if (!(share->options & HA_OPTION_CHECKSUM))
    share->calc_checksum=0;
  return;
}


static void setup_key_functions(register MI_KEYDEF *keyinfo)
{
808 809
  if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
  {
810
#ifdef HAVE_RTREE_KEYS
811 812
    keyinfo->ck_insert = rtree_insert;
    keyinfo->ck_delete = rtree_delete;
813 814
#else
    DBUG_ASSERT(0); /* mi_open should check it never happens */
815
#endif
816 817 818 819 820 821
  }
  else
  {
    keyinfo->ck_insert = _mi_ck_write;
    keyinfo->ck_delete = _mi_ck_delete;
  }
unknown's avatar
unknown committed
822 823 824 825 826 827 828 829 830 831 832 833
  if (keyinfo->flag & HA_BINARY_PACK_KEY)
  {						/* Simple prefix compression */
    keyinfo->bin_search=_mi_seq_search;
    keyinfo->get_key=_mi_get_binary_pack_key;
    keyinfo->pack_key=_mi_calc_bin_pack_key_length;
    keyinfo->store_key=_mi_store_bin_pack_key;
  }
  else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
  {
    keyinfo->get_key= _mi_get_pack_key;
    if (keyinfo->seg[0].flag & HA_PACK_KEY)
    {						/* Prefix compression */
834 835 836 837 838 839 840 841
      /*
        _mi_prefix_search() compares end-space against ASCII blank (' ').
        It cannot be used for character sets, that do not encode the
        blank character like ASCII does. UCS2 is an example. All
        character sets with a fixed width > 1 or a mimimum width > 1
        cannot represent blank like ASCII does. In these cases we have
        to use _mi_seq_search() for the search.
      */
842
      if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
843 844
          (keyinfo->seg->flag & HA_NULL_PART) ||
          (keyinfo->seg->charset->mbminlen > 1))
845 846 847
        keyinfo->bin_search=_mi_seq_search;
      else
        keyinfo->bin_search=_mi_prefix_search;
unknown's avatar
unknown committed
848 849 850 851 852
      keyinfo->pack_key=_mi_calc_var_pack_key_length;
      keyinfo->store_key=_mi_store_var_pack_key;
    }
    else
    {
853
      keyinfo->bin_search=_mi_seq_search;
unknown's avatar
unknown committed
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
      keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
      keyinfo->store_key=_mi_store_static_key;
    }
  }
  else
  {
    keyinfo->bin_search=_mi_bin_search;
    keyinfo->get_key=_mi_get_static_key;
    keyinfo->pack_key=_mi_calc_static_key_length;
    keyinfo->store_key=_mi_store_static_key;
  }
  return;
}


869 870 871
/*
   Function to save and store the header in the index file (.MYI)
*/
unknown's avatar
unknown committed
872 873 874 875 876 877

uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
{
  uchar  buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
  uchar *ptr=buff;
  uint	i, keys= (uint) state->header.keys,
878
	key_blocks=state->header.max_block_size_index;
879
  DBUG_ENTER("mi_state_info_write");
unknown's avatar
unknown committed
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895

  memcpy_fixed(ptr,&state->header,sizeof(state->header));
  ptr+=sizeof(state->header);

  /* open_count must be first because of _mi_mark_file_changed ! */
  mi_int2store(ptr,state->open_count);		ptr +=2;
  *ptr++= (uchar)state->changed; *ptr++= state->sortkey;
  mi_rowstore(ptr,state->state.records);	ptr +=8;
  mi_rowstore(ptr,state->state.del);		ptr +=8;
  mi_rowstore(ptr,state->split);		ptr +=8;
  mi_sizestore(ptr,state->dellink);		ptr +=8;
  mi_sizestore(ptr,state->state.key_file_length);	ptr +=8;
  mi_sizestore(ptr,state->state.data_file_length);	ptr +=8;
  mi_sizestore(ptr,state->state.empty);		ptr +=8;
  mi_sizestore(ptr,state->state.key_empty);	ptr +=8;
  mi_int8store(ptr,state->auto_increment);	ptr +=8;
896
  mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8;
unknown's avatar
unknown committed
897 898 899
  mi_int4store(ptr,state->process);		ptr +=4;
  mi_int4store(ptr,state->unique);		ptr +=4;
  mi_int4store(ptr,state->status);		ptr +=4;
900
  mi_int4store(ptr,state->update_count);	ptr +=4;
unknown's avatar
unknown committed
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

  ptr+=state->state_diff_length;

  for (i=0; i < keys; i++)
  {
    mi_sizestore(ptr,state->key_root[i]);	ptr +=8;
  }
  for (i=0; i < key_blocks; i++)
  {
    mi_sizestore(ptr,state->key_del[i]);	ptr +=8;
  }
  if (pWrite & 2)				/* From isamchk */
  {
    uint key_parts= mi_uint2korr(state->header.key_parts);
    mi_int4store(ptr,state->sec_index_changed); ptr +=4;
    mi_int4store(ptr,state->sec_index_used);	ptr +=4;
    mi_int4store(ptr,state->version);		ptr +=4;
    mi_int8store(ptr,state->key_map);		ptr +=8;
    mi_int8store(ptr,(ulonglong) state->create_time);	ptr +=8;
    mi_int8store(ptr,(ulonglong) state->recover_time);	ptr +=8;
    mi_int8store(ptr,(ulonglong) state->check_time);	ptr +=8;
    mi_sizestore(ptr,state->rec_per_key_rows);	ptr+=8;
    for (i=0 ; i < key_parts ; i++)
    {
      mi_int4store(ptr,state->rec_per_key_part[i]);  ptr+=4;
    }
  }

  if (pWrite & 1)
930 931 932 933
    DBUG_RETURN(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
			  MYF(MY_NABP | MY_THREADSAFE)) != 0);
  DBUG_RETURN(my_write(file, buff, (size_t) (ptr-buff),
		       MYF(MY_NABP)) != 0);
unknown's avatar
unknown committed
934 935 936
}


937
uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state)
unknown's avatar
unknown committed
938 939 940 941 942 943
{
  uint i,keys,key_parts,key_blocks;
  memcpy_fixed(&state->header,ptr, sizeof(state->header));
  ptr +=sizeof(state->header);
  keys=(uint) state->header.keys;
  key_parts=mi_uint2korr(state->header.key_parts);
944
  key_blocks=state->header.max_block_size_index;
unknown's avatar
unknown committed
945 946

  state->open_count = mi_uint2korr(ptr);	ptr +=2;
947
  state->changed= *ptr++;
unknown's avatar
unknown committed
948 949 950 951 952 953 954 955 956 957
  state->sortkey = (uint) *ptr++;
  state->state.records= mi_rowkorr(ptr);	ptr +=8;
  state->state.del = mi_rowkorr(ptr);		ptr +=8;
  state->split	= mi_rowkorr(ptr);		ptr +=8;
  state->dellink= mi_sizekorr(ptr);		ptr +=8;
  state->state.key_file_length = mi_sizekorr(ptr);	ptr +=8;
  state->state.data_file_length= mi_sizekorr(ptr);	ptr +=8;
  state->state.empty	= mi_sizekorr(ptr);	ptr +=8;
  state->state.key_empty= mi_sizekorr(ptr);	ptr +=8;
  state->auto_increment=mi_uint8korr(ptr);	ptr +=8;
958
  state->state.checksum=(ha_checksum) mi_uint8korr(ptr);	ptr +=8;
unknown's avatar
unknown committed
959 960 961
  state->process= mi_uint4korr(ptr);		ptr +=4;
  state->unique = mi_uint4korr(ptr);		ptr +=4;
  state->status = mi_uint4korr(ptr);		ptr +=4;
962 963
  state->update_count=mi_uint4korr(ptr);	ptr +=4;

964 965
  ptr+= state->state_diff_length;

unknown's avatar
unknown committed
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
  for (i=0; i < keys; i++)
  {
    state->key_root[i]= mi_sizekorr(ptr);	ptr +=8;
  }
  for (i=0; i < key_blocks; i++)
  {
    state->key_del[i] = mi_sizekorr(ptr);	ptr +=8;
  }
  state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
  state->sec_index_used =    mi_uint4korr(ptr); ptr +=4;
  state->version     = mi_uint4korr(ptr);	ptr +=4;
  state->key_map     = mi_uint8korr(ptr);	ptr +=8;
  state->create_time = (time_t) mi_sizekorr(ptr);	ptr +=8;
  state->recover_time =(time_t) mi_sizekorr(ptr);	ptr +=8;
  state->check_time =  (time_t) mi_sizekorr(ptr);	ptr +=8;
  state->rec_per_key_rows=mi_sizekorr(ptr);	ptr +=8;
  for (i=0 ; i < key_parts ; i++)
  {
    state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
  }
  return ptr;
}


uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead)
{
992
  uchar	buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
unknown's avatar
unknown committed
993

994
  if (!myisam_single_user)
unknown's avatar
unknown committed
995
  {
996 997 998
    if (pRead)
    {
      if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
999
	return 1;
1000 1001
    }
    else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
1002
      return 1;
1003
    mi_state_info_read(buff, state);
unknown's avatar
unknown committed
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
  }
  return 0;
}


/****************************************************************************
**  store and read of MI_BASE_INFO
****************************************************************************/

uint mi_base_info_write(File file, MI_BASE_INFO *base)
{
  uchar buff[MI_BASE_INFO_SIZE], *ptr=buff;

  mi_sizestore(ptr,base->keystart);			ptr +=8;
  mi_sizestore(ptr,base->max_data_file_length);		ptr +=8;
  mi_sizestore(ptr,base->max_key_file_length);		ptr +=8;
  mi_rowstore(ptr,base->records);			ptr +=8;
  mi_rowstore(ptr,base->reloc);				ptr +=8;
  mi_int4store(ptr,base->mean_row_length);		ptr +=4;
  mi_int4store(ptr,base->reclength);			ptr +=4;
  mi_int4store(ptr,base->pack_reclength);		ptr +=4;
  mi_int4store(ptr,base->min_pack_length);		ptr +=4;
  mi_int4store(ptr,base->max_pack_length);		ptr +=4;
  mi_int4store(ptr,base->min_block_length);		ptr +=4;
  mi_int4store(ptr,base->fields);			ptr +=4;
  mi_int4store(ptr,base->pack_fields);			ptr +=4;
  *ptr++=base->rec_reflength;
  *ptr++=base->key_reflength;
  *ptr++=base->keys;
  *ptr++=base->auto_key;
  mi_int2store(ptr,base->pack_bits);			ptr +=2;
  mi_int2store(ptr,base->blobs);			ptr +=2;
  mi_int2store(ptr,base->max_key_block_length);		ptr +=2;
  mi_int2store(ptr,base->max_key_length);		ptr +=2;
  mi_int2store(ptr,base->extra_alloc_bytes);		ptr +=2;
  *ptr++= base->extra_alloc_procent;
  *ptr++= base->raid_type;
  mi_int2store(ptr,base->raid_chunks);			ptr +=2;
  mi_int4store(ptr,base->raid_chunksize);		ptr +=4;
  bzero(ptr,6);						ptr +=6; /* extra */
1044
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
unknown's avatar
unknown committed
1045 1046 1047
}


1048
uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
unknown's avatar
unknown committed
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
{
  base->keystart = mi_sizekorr(ptr);			ptr +=8;
  base->max_data_file_length = mi_sizekorr(ptr);	ptr +=8;
  base->max_key_file_length = mi_sizekorr(ptr);		ptr +=8;
  base->records =  (ha_rows) mi_sizekorr(ptr);		ptr +=8;
  base->reloc = (ha_rows) mi_sizekorr(ptr);		ptr +=8;
  base->mean_row_length = mi_uint4korr(ptr);		ptr +=4;
  base->reclength = mi_uint4korr(ptr);			ptr +=4;
  base->pack_reclength = mi_uint4korr(ptr);		ptr +=4;
  base->min_pack_length = mi_uint4korr(ptr);		ptr +=4;
  base->max_pack_length = mi_uint4korr(ptr);		ptr +=4;
  base->min_block_length = mi_uint4korr(ptr);		ptr +=4;
  base->fields = mi_uint4korr(ptr);			ptr +=4;
  base->pack_fields = mi_uint4korr(ptr);		ptr +=4;

  base->rec_reflength = *ptr++;
  base->key_reflength = *ptr++;
  base->keys=		*ptr++;
  base->auto_key=	*ptr++;
  base->pack_bits = mi_uint2korr(ptr);			ptr +=2;
  base->blobs = mi_uint2korr(ptr);			ptr +=2;
  base->max_key_block_length= mi_uint2korr(ptr);	ptr +=2;
  base->max_key_length = mi_uint2korr(ptr);		ptr +=2;
  base->extra_alloc_bytes = mi_uint2korr(ptr);		ptr +=2;
  base->extra_alloc_procent = *ptr++;
  base->raid_type= *ptr++;
  base->raid_chunks= mi_uint2korr(ptr);			ptr +=2;
  base->raid_chunksize= mi_uint4korr(ptr);		ptr +=4;
  /* TO BE REMOVED: Fix for old RAID files */
  if (base->raid_type == 0)
  {
    base->raid_chunks=0;
    base->raid_chunksize=0;
  }

  ptr+=6;
  return ptr;
}

/*--------------------------------------------------------------------------
  mi_keydef
---------------------------------------------------------------------------*/

uint mi_keydef_write(File file, MI_KEYDEF *keydef)
{
  uchar buff[MI_KEYDEF_SIZE];
  uchar *ptr=buff;

  *ptr++ = (uchar) keydef->keysegs;
1098
  *ptr++ = keydef->key_alg;			/* Rtree or Btree */
unknown's avatar
unknown committed
1099 1100 1101 1102 1103
  mi_int2store(ptr,keydef->flag);		ptr +=2;
  mi_int2store(ptr,keydef->block_length);	ptr +=2;
  mi_int2store(ptr,keydef->keylength);		ptr +=2;
  mi_int2store(ptr,keydef->minlength);		ptr +=2;
  mi_int2store(ptr,keydef->maxlength);		ptr +=2;
1104
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
unknown's avatar
unknown committed
1105 1106
}

1107
uchar *mi_keydef_read(uchar *ptr, MI_KEYDEF *keydef)
unknown's avatar
unknown committed
1108 1109
{
   keydef->keysegs	= (uint) *ptr++;
1110
   keydef->key_alg	= *ptr++;		/* Rtree or Btree */
1111

unknown's avatar
unknown committed
1112 1113 1114 1115 1116
   keydef->flag		= mi_uint2korr(ptr);	ptr +=2;
   keydef->block_length = mi_uint2korr(ptr);	ptr +=2;
   keydef->keylength	= mi_uint2korr(ptr);	ptr +=2;
   keydef->minlength	= mi_uint2korr(ptr);	ptr +=2;
   keydef->maxlength	= mi_uint2korr(ptr);	ptr +=2;
1117
   keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
unknown's avatar
unknown committed
1118 1119
   keydef->underflow_block_length=keydef->block_length/3;
   keydef->version	= 0;			/* Not saved */
1120
   keydef->parser       = &ft_default_parser;
1121
   keydef->ftkey_nr     = 0;
unknown's avatar
unknown committed
1122 1123 1124 1125 1126 1127 1128
   return ptr;
}

/***************************************************************************
**  mi_keyseg
***************************************************************************/

unknown's avatar
unknown committed
1129
int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
unknown's avatar
unknown committed
1130
{
unknown's avatar
unknown committed
1131
  uchar buff[HA_KEYSEG_SIZE];
unknown's avatar
unknown committed
1132
  uchar *ptr=buff;
unknown's avatar
unknown committed
1133
  ulong pos;
unknown's avatar
unknown committed
1134

unknown's avatar
unknown committed
1135 1136 1137 1138 1139
  *ptr++= keyseg->type;
  *ptr++= keyseg->language;
  *ptr++= keyseg->null_bit;
  *ptr++= keyseg->bit_start;
  *ptr++= keyseg->bit_end;
unknown's avatar
unknown committed
1140
  *ptr++= keyseg->bit_length;
unknown's avatar
unknown committed
1141 1142 1143
  mi_int2store(ptr,keyseg->flag);	ptr+=2;
  mi_int2store(ptr,keyseg->length);	ptr+=2;
  mi_int4store(ptr,keyseg->start);	ptr+=4;
unknown's avatar
unknown committed
1144 1145
  pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
  mi_int4store(ptr, pos);
unknown's avatar
unknown committed
1146 1147
  ptr+=4;
  
1148
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
unknown's avatar
unknown committed
1149 1150 1151
}


1152
uchar *mi_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
unknown's avatar
unknown committed
1153 1154 1155 1156 1157 1158
{
   keyseg->type		= *ptr++;
   keyseg->language	= *ptr++;
   keyseg->null_bit	= *ptr++;
   keyseg->bit_start	= *ptr++;
   keyseg->bit_end	= *ptr++;
unknown's avatar
unknown committed
1159
   keyseg->bit_length   = *ptr++;
unknown's avatar
unknown committed
1160 1161 1162 1163 1164
   keyseg->flag		= mi_uint2korr(ptr);  ptr +=2;
   keyseg->length	= mi_uint2korr(ptr);  ptr +=2;
   keyseg->start	= mi_uint4korr(ptr);  ptr +=4;
   keyseg->null_pos	= mi_uint4korr(ptr);  ptr +=4;
   keyseg->charset=0;				/* Will be filled in later */
unknown's avatar
unknown committed
1165
   if (keyseg->null_bit)
1166 1167
     /* We adjust bit_pos if null_bit is last in the byte */
     keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == (1 << 7)));
unknown's avatar
unknown committed
1168 1169
   else
   {
1170
     keyseg->bit_pos= (uint16)keyseg->null_pos;
unknown's avatar
unknown committed
1171 1172
     keyseg->null_pos= 0;
   }
unknown's avatar
unknown committed
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
   return ptr;
}

/*--------------------------------------------------------------------------
  mi_uniquedef
---------------------------------------------------------------------------*/

uint mi_uniquedef_write(File file, MI_UNIQUEDEF *def)
{
  uchar buff[MI_UNIQUEDEF_SIZE];
  uchar *ptr=buff;

  mi_int2store(ptr,def->keysegs);		ptr+=2;
  *ptr++=  (uchar) def->key;
  *ptr++ = (uchar) def->null_are_equal;

1189
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
unknown's avatar
unknown committed
1190 1191
}

1192
uchar *mi_uniquedef_read(uchar *ptr, MI_UNIQUEDEF *def)
unknown's avatar
unknown committed
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
{
   def->keysegs = mi_uint2korr(ptr);
   def->key	= ptr[2];
   def->null_are_equal=ptr[3];
   return ptr+4;				/* 1 extra byte */
}

/***************************************************************************
**  MI_COLUMNDEF
***************************************************************************/

uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo)
{
  uchar buff[MI_COLUMNDEF_SIZE];
  uchar *ptr=buff;

  mi_int2store(ptr,recinfo->type);	ptr +=2;
  mi_int2store(ptr,recinfo->length);	ptr +=2;
  *ptr++ = recinfo->null_bit;
  mi_int2store(ptr,recinfo->null_pos);	ptr+= 2;
1213
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
unknown's avatar
unknown committed
1214 1215
}

1216
uchar *mi_recinfo_read(uchar *ptr, MI_COLUMNDEF *recinfo)
unknown's avatar
unknown committed
1217 1218 1219 1220 1221 1222 1223
{
   recinfo->type=  mi_sint2korr(ptr);	ptr +=2;
   recinfo->length=mi_uint2korr(ptr);	ptr +=2;
   recinfo->null_bit= (uint8) *ptr++;
   recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
   return ptr;
}
1224 1225

/**************************************************************************
1226
Open data file with or without RAID
1227
We can't use dup() here as the data file descriptors need to have different
1228 1229 1230 1231 1232
active seek-positions.

The argument file_to_dup is here for the future if there would on some OS
exist a dup()-like call that would give us two different file descriptors.
*************************************************************************/
1233

1234
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name,
1235
                     File file_to_dup __attribute__((unused)))
1236
{
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
  char *data_name= share->data_file_name;
  char real_data_name[FN_REFLEN];

  if (org_name)
  {
    fn_format(real_data_name,org_name,"",MI_NAME_DEXT,4);
    if (my_is_symlink(real_data_name))
    {
      if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
          (*myisam_test_invalid_symlink)(real_data_name))
      {
        my_errno= HA_WRONG_CREATE_OPTION;
        return 1;
      }
      data_name= real_data_name;
    }
  }
1254 1255 1256
#ifdef USE_RAID
  if (share->base.raid_type)
  {
1257
    info->dfile=my_raid_open(data_name,
unknown's avatar
unknown committed
1258 1259 1260 1261 1262
			     share->mode | O_SHARE,
			     share->base.raid_type,
			     share->base.raid_chunks,
			     share->base.raid_chunksize,
			     MYF(MY_WME | MY_RAID));
1263 1264 1265
  }
  else
#endif
1266
    info->dfile=my_open(data_name, share->mode | O_SHARE, MYF(MY_WME));
unknown's avatar
unknown committed
1267
  return info->dfile >= 0 ? 0 : 1;
1268 1269 1270 1271 1272
}


int mi_open_keyfile(MYISAM_SHARE *share)
{
unknown's avatar
unknown committed
1273
  if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE,
unknown's avatar
unknown committed
1274
                            MYF(MY_WME))) < 0)
1275 1276 1277
    return 1;
  return 0;
}
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297


/*
  Disable all indexes.

  SYNOPSIS
    mi_disable_indexes()
    info        A pointer to the MyISAM storage engine MI_INFO struct.

  DESCRIPTION
    Disable all indexes.

  RETURN
    0  ok
*/

int mi_disable_indexes(MI_INFO *info)
{
  MYISAM_SHARE *share= info->s;

1298
  mi_clear_all_keys_active(share->state.key_map);
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
  return 0;
}


/*
  Enable all indexes

  SYNOPSIS
    mi_enable_indexes()
    info        A pointer to the MyISAM storage engine MI_INFO struct.

  DESCRIPTION
    Enable all indexes. The indexes might have been disabled
    by mi_disable_index() before.
    The function works only if both data and indexes are empty,
    otherwise a repair is required.
    To be sure, call handler::delete_all_rows() before.

  RETURN
    0  ok
    HA_ERR_CRASHED data or index is non-empty.
*/

int mi_enable_indexes(MI_INFO *info)
{
  int error= 0;
  MYISAM_SHARE *share= info->s;

  if (share->state.state.data_file_length ||
      (share->state.state.key_file_length != share->base.keystart))
1329
  {
unknown's avatar
unknown committed
1330
    mi_print_error(info->s, HA_ERR_CRASHED);
1331
    error= HA_ERR_CRASHED;
1332
  }
1333
  else
1334
    mi_set_all_keys_active(share->state.key_map, share->base.keys);
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
  return error;
}


/*
  Test if indexes are disabled.

  SYNOPSIS
    mi_indexes_are_disabled()
    info        A pointer to the MyISAM storage engine MI_INFO struct.

  DESCRIPTION
    Test if indexes are disabled.

  RETURN
    0  indexes are not disabled
    1  all indexes are disabled
unknown's avatar
unknown committed
1352
    2  non-unique indexes are disabled
1353 1354 1355 1356 1357 1358
*/

int mi_indexes_are_disabled(MI_INFO *info)
{
  MYISAM_SHARE *share= info->s;

unknown's avatar
unknown committed
1359 1360 1361 1362 1363 1364
  /*
    No keys or all are enabled. keys is the number of keys. Left shifted
    gives us only one bit set. When decreased by one, gives us all all bits
    up to this one set and it gets unset.
  */
  if (!share->base.keys ||
1365
      (mi_is_all_keys_active(share->state.key_map, share->base.keys)))
unknown's avatar
unknown committed
1366 1367 1368
    return 0;

  /* All are disabled */
1369
  if (mi_is_any_key_active(share->state.key_map))
unknown's avatar
unknown committed
1370 1371 1372 1373 1374 1375 1376
    return 1;

  /*
    We have keys. Some enabled, some disabled.
    Don't check for any non-unique disabled but return directly 2
  */
  return 2;
1377 1378
}