mi_open.c 40.7 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;
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];
unknown's avatar
unknown committed
82
  char *disk_cache, *disk_pos, *end_pos;
unknown's avatar
unknown committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96
  MI_INFO info,*m_info,*old_info;
  MYISAM_SHARE share_buff,*share;
  ulong rec_per_key_part[MI_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
  my_off_t key_root[MI_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
  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);
  bzero((byte*) &info,sizeof(info));

unknown's avatar
unknown committed
97
  my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
unknown's avatar
unknown committed
98 99 100 101 102 103 104 105
  pthread_mutex_lock(&THR_LOCK_myisam);
  if (!(old_info=test_if_reopen(name_buff)))
  {
    share= &share_buff;
    bzero((gptr) &share_buff,sizeof(share_buff));
    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;
106
    share_buff.key_cache= multi_key_cache_search(name_buff, strlen(name_buff));
unknown's avatar
unknown committed
107

108 109 110 111 112 113
    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
114 115 116 117 118 119 120
    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;
    }
121
    share->mode=open_mode;
unknown's avatar
unknown committed
122 123 124
    errpos=1;
    if (my_read(kfile,(char*) share->state.header.file_version,head_length,
		MYF(MY_NABP)))
unknown's avatar
unknown committed
125 126
    {
      my_errno= HA_ERR_NOT_A_TABLE;
unknown's avatar
unknown committed
127
      goto err;
unknown's avatar
unknown committed
128
    }
unknown's avatar
unknown committed
129 130 131 132 133 134
    if (memcmp((byte*) share->state.header.file_version,
	       (byte*) myisam_file_magic, 4))
    {
      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
135
      my_errno=HA_ERR_NOT_A_TABLE;
unknown's avatar
unknown committed
136 137 138 139 140 141 142 143 144
      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 |
	  HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE))
    {
145
      DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
unknown's avatar
unknown committed
146 147 148
      my_errno=HA_ERR_OLD_FILE;
      goto err;
    }
unknown's avatar
unknown committed
149
    /* Don't call realpath() if the name can't be a link */
150
    if (!strcmp(name_buff, org_name) ||
unknown's avatar
unknown committed
151
        my_readlink(index_name, org_name, MYF(0)) == -1)
152 153
      (void) strmov(index_name, org_name);
    (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,2+4+16);
unknown's avatar
unknown committed
154

unknown's avatar
unknown committed
155 156
    info_length=mi_uint2korr(share->state.header.header_length);
    base_pos=mi_uint2korr(share->state.header.base_pos);
157
    if (!(disk_cache=(char*) my_alloca(info_length+128)))
unknown's avatar
unknown committed
158 159 160 161
    {
      my_errno=ENOMEM;
      goto err;
    }
162
    end_pos=disk_cache+info_length;
unknown's avatar
unknown committed
163 164 165
    errpos=2;

    VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
166
    if (!(open_flags & HA_OPEN_TMP_TABLE))
unknown's avatar
unknown committed
167 168
    {
      if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
169
			      MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ?
unknown's avatar
unknown committed
170
				  0 : MY_DONT_WAIT))) &&
171
	  !(open_flags & HA_OPEN_IGNORE_IF_LOCKED))
unknown's avatar
unknown committed
172 173 174 175
	goto err;
    }
    errpos=3;
    if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
unknown's avatar
unknown committed
176 177
    {
      my_errno=HA_ERR_CRASHED;
unknown's avatar
unknown committed
178
      goto err;
unknown's avatar
unknown committed
179
    }
unknown's avatar
unknown committed
180 181 182
    len=mi_uint2korr(share->state.header.state_info_length);
    keys=    (uint) share->state.header.keys;
    uniques= (uint) share->state.header.uniques;
183
    fulltext_keys= (uint) share->state.header.fulltext_keys;
unknown's avatar
unknown committed
184 185 186 187 188 189 190 191 192 193
    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;

194
    mi_state_info_read((uchar*) disk_cache, &share->state);
unknown's avatar
unknown committed
195 196 197 198 199 200
    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",
			    len,MI_BASE_INFO_SIZE))
    }
201 202
    disk_pos= (char*) 
      my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base);
unknown's avatar
unknown committed
203 204
    share->state.state_length=base_pos;

205
    if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
206
	((share->state.changed & STATE_CRASHED) ||
207 208
	 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
	  (my_disable_locking && share->state.open_count))))
209
    {
210 211 212 213
      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));
214
      my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
215
		HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
216 217
      goto err;
    }
218 219 220 221 222 223 224 225

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

226
    key_parts+=fulltext_keys*FT_SEGS;
227
    if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
228
	key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
229 230 231 232 233 234
    {
      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;
    }

235
    /* Correct max_file_length based on length of sizeof(off_t) */
unknown's avatar
unknown committed
236 237 238
    max_data_file_length=
      (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
      (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
239
      (mi_safe_mul(share->base.pack_reclength,
unknown's avatar
unknown committed
240 241
		   (ulonglong) 1 << (share->base.rec_reflength*8))-1);
    max_key_file_length=
unknown's avatar
unknown committed
242
      mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
unknown's avatar
unknown committed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
		  ((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
262
      DBUG_PRINT("error",("Table uses RAID but we don't have RAID support"));
unknown's avatar
unknown committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
      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 */

    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
280
			 sizeof(HA_KEYSEG),
unknown's avatar
unknown committed
281 282 283
			 &share->rec,
			 (share->base.fields+1)*sizeof(MI_COLUMNDEF),
			 &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
unknown's avatar
unknown committed
284 285 286
			 &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
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
			 &share->state.key_root,keys*sizeof(my_off_t),
			 &share->state.key_del,
			 (share->state.header.max_block_size*sizeof(my_off_t)),
#ifdef THREAD
			 &share->key_root_lock,sizeof(rw_lock_t)*keys,
#endif
			 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) *
			     share->state.header.max_block_size));
unknown's avatar
unknown committed
304
    strmov(share->unique_file_name, name_buff);
305
    share->unique_name_length= strlen(name_buff);
unknown's avatar
unknown committed
306 307
    strmov(share->index_file_name,  index_name);
    strmov(share->data_file_name,   data_name);
unknown's avatar
unknown committed
308 309 310

    share->blocksize=min(IO_SIZE,myisam_block_size);
    {
unknown's avatar
unknown committed
311
      HA_KEYSEG *pos=share->keyparts;
unknown's avatar
unknown committed
312 313
      for (i=0 ; i < keys ; i++)
      {
unknown's avatar
unknown committed
314
        share->keyinfo[i].share= share;
unknown's avatar
unknown committed
315
	disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
unknown's avatar
unknown committed
316
        disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
unknown's avatar
unknown committed
317
 			end_pos);
318 319
        if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE)
          have_rtree=1;
unknown's avatar
unknown committed
320 321 322 323 324
	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);
325 326 327 328 329 330 331
          if (pos->flag & HA_BLOB_PART &&
              ! (share->options & (HA_OPTION_COMPRESS_RECORD |
                                   HA_OPTION_PACK_RECORD)))
          {
            my_errno= HA_ERR_CRASHED;
            goto err;
          }
332 333 334
	  if (pos->type == HA_KEYTYPE_TEXT ||
              pos->type == HA_KEYTYPE_VARTEXT1 ||
              pos->type == HA_KEYTYPE_VARTEXT2)
unknown's avatar
unknown committed
335 336 337 338 339 340 341 342 343
	  {
	    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;
	    }
	  }
344 345
	  else if (pos->type == HA_KEYTYPE_BINARY)
	    pos->charset= &my_charset_bin;
unknown's avatar
unknown committed
346
	}
347 348
	if (share->keyinfo[i].flag & HA_SPATIAL)
	{
349
#ifdef HAVE_SPATIAL
350 351 352
	  uint sp_segs=SPDIMS*2;
	  share->keyinfo[i].seg=pos-sp_segs;
	  share->keyinfo[i].keysegs--;
353 354 355 356
#else
	  my_errno=HA_ERR_UNSUPPORTED;
	  goto err;
#endif
357 358
	}
        else if (share->keyinfo[i].flag & HA_FULLTEXT)
359
	{
360 361 362 363 364 365 366
          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
          {
367
            uint k;
368
            share->keyinfo[i].seg=pos;
369
            for (k=0; k < FT_SEGS; k++)
370
            {
371
              *pos= ft_keysegs[k];
372
              pos[0].language= pos[-1].language;
373 374 375 376 377
              if (!(pos[0].charset= pos[-1].charset))
              {
                my_errno=HA_ERR_CRASHED;
                goto err;
              }
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
              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);
          }
393
	}
394
        setup_key_functions(share->keyinfo+i);
unknown's avatar
unknown committed
395 396 397 398
	share->keyinfo[i].end=pos;
	pos->type=HA_KEYTYPE_END;			/* End */
	pos->length=share->base.rec_reflength;
	pos->null_bit=0;
399
	pos->flag=0;					/* For purify */
unknown's avatar
unknown committed
400 401 402 403 404
	pos++;
      }
      for (i=0 ; i < uniques ; i++)
      {
	disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
405
        disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
unknown's avatar
unknown committed
406
			HA_KEYSEG_SIZE, end_pos);
unknown's avatar
unknown committed
407 408 409 410
	share->uniqueinfo[i].seg=pos;
	for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
	{
	  disk_pos=mi_keyseg_read(disk_pos, pos);
411 412 413
	  if (pos->type == HA_KEYTYPE_TEXT ||
              pos->type == HA_KEYTYPE_VARTEXT1 ||
              pos->type == HA_KEYTYPE_VARTEXT2)
unknown's avatar
unknown committed
414 415 416 417 418 419 420 421 422 423 424 425 426
	  {
	    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;
427
	pos->flag=0;
unknown's avatar
unknown committed
428 429 430 431
	pos++;
      }
    }

432
    disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
unknown's avatar
unknown committed
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    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=
	  share->rec[i].length-mi_portable_sizeof_char_ptr;;
	share->blobs[j].offset=offset;
	j++;
      }
      offset+=share->rec[i].length;
    }
    share->rec[i].type=(int) FIELD_LAST;	/* End marker */
449 450 451 452 453 454 455
    if (offset > share->base.reclength)
    {
      /* purecov: begin inspected */
      my_errno= HA_ERR_CRASHED;
      goto err;
      /* purecov: end */
    }
unknown's avatar
unknown committed
456 457 458 459 460 461 462

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

unknown's avatar
unknown committed
463
    if (mi_open_datafile(&info, share, -1))
unknown's avatar
unknown committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
      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;
    my_afree((gptr) disk_cache);
496
    mi_setup_functions(share);
unknown's avatar
unknown committed
497 498
#ifdef THREAD
    thr_lock_init(&share->lock);
499
    VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
unknown's avatar
unknown committed
500 501 502 503 504 505 506 507 508 509 510 511 512
    for (i=0; i<keys; i++)
      VOID(my_rwlock_init(&share->key_root_lock[i], NULL));
    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)) ||
513 514
	 (open_flags & HA_OPEN_TMP_TABLE) ||
	 have_rtree) ? 0 : 1;
unknown's avatar
unknown committed
515 516 517 518 519
      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;
520
        share->lock.restore_status= mi_restore_status;
unknown's avatar
unknown committed
521 522 523 524 525 526 527 528 529 530 531 532 533
	share->lock.check_status=mi_check_status;
      }
    }
#endif
  }
  else
  {
    share= old_info->s;
    if (mode == O_RDWR && share->mode == O_RDONLY)
    {
      my_errno=EACCES;				/* Can't open in write mode */
      goto err;
    }
unknown's avatar
unknown committed
534
    if (mi_open_datafile(&info, share, old_info->dfile))
unknown's avatar
unknown committed
535 536
      goto err;
    errpos=5;
537
    have_rtree= old_info->rtree_recursion_state != NULL;
unknown's avatar
unknown committed
538 539 540 541 542 543 544 545 546
  }

  /* 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,
547
		       &info.first_mbr_key, share->base.max_key_length,
548
		       &info.filename,strlen(name)+1,
549
		       &info.rtree_recursion_state,have_rtree ? 1024 : 0,
unknown's avatar
unknown committed
550 551 552
		       NullS))
    goto err;
  errpos=6;
553 554

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

557
  strmov(info.filename,name);
unknown's avatar
unknown committed
558 559 560 561 562 563 564 565 566 567
  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;
568
  info.this_loop=0;				/* Update counter */
unknown's avatar
unknown committed
569
  info.last_unique= share->state.unique;
570
  info.last_loop=   share->state.update_count;
unknown's avatar
unknown committed
571 572 573 574
  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
575
  info.bulk_insert=0;
576
  info.ft1_to_ft2=0;
unknown's avatar
unknown committed
577 578 579 580 581 582 583 584 585 586
  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++;
587
    share->tot_locks++;
unknown's avatar
unknown committed
588
  }
589
  if ((open_flags & HA_OPEN_TMP_TABLE) ||
unknown's avatar
unknown committed
590 591 592 593 594
      (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 */
595
    share->tot_locks++;
unknown's avatar
unknown committed
596 597
    info.lock_type=F_WRLCK;
  }
598
  if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) ||
unknown's avatar
unknown committed
599 600 601 602 603 604 605 606
      (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 */

607
  /* prerequisites: bzero(info) && info->s=share; are met. */
608
  if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff))
unknown's avatar
unknown committed
609
    goto err;
610
  bzero(info.rec_buff, mi_get_rec_buff_len(&info, info.rec_buff));
unknown's avatar
unknown committed
611 612 613 614 615 616 617 618 619

  *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);
620 621
  if (myisam_log_file >= 0)
  {
unknown's avatar
unknown committed
622
    intern_filename(name_buff,share->index_file_name);
623 624
    _myisam_log(MI_LOG_OPEN,m_info,name_buff,(uint) strlen(name_buff));
  }
unknown's avatar
unknown committed
625 626 627 628
  DBUG_RETURN(m_info);

err:
  save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
629 630 631 632
  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
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
  switch (errpos) {
  case 6:
    my_free((gptr) m_info,MYF(0));
    /* fall through */
  case 5:
    VOID(my_close(info.dfile,MYF(0)));
    if (old_info)
      break;					/* Don't remove open table */
    /* fall through */
  case 4:
    my_free((gptr) share,MYF(0));
    /* 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:
    my_afree((gptr) disk_cache);
    /* 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 */

664

665
byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
666 667
{
  uint extra;
668 669
  uint32 old_length;
  LINT_INIT(old_length);
670

671
  if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
672 673 674 675
  {
    byte *newptr = *buf;

    /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
676
    if (length == (ulong) -1)
677
    {
678 679 680 681 682
      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);
683 684 685 686
      /* Avoid unnecessary realloc */
      if (newptr && length == old_length)
	return newptr;
    }
687 688

    extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
689 690
	    ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
	    MI_REC_BUFF_OFFSET : 0);
691
    if (extra && newptr)
692
      newptr-= MI_REC_BUFF_OFFSET;
693
    if (!(newptr=(byte*) my_realloc((gptr)newptr, length+extra+8,
694 695
                                     MYF(MY_ALLOW_ZERO_PTR))))
      return newptr;
696
    *((uint32 *) newptr)= (uint32) length;
697
    *buf= newptr+(extra ?  MI_REC_BUFF_OFFSET : 0);
698 699 700
  }
  return *buf;
}
unknown's avatar
unknown committed
701

702

unknown's avatar
unknown committed
703 704 705 706 707 708 709 710 711 712 713
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 */

714
void mi_setup_functions(register MYISAM_SHARE *share)
unknown's avatar
unknown committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
{
  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
736 737
    /* 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
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
    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;
  }
  if (!(share->options & HA_OPTION_CHECKSUM))
    share->calc_checksum=0;
  return;
}


static void setup_key_functions(register MI_KEYDEF *keyinfo)
{
768 769
  if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
  {
770
#ifdef HAVE_RTREE_KEYS
771 772
    keyinfo->ck_insert = rtree_insert;
    keyinfo->ck_delete = rtree_delete;
773 774
#else
    DBUG_ASSERT(0); /* mi_open should check it never happens */
775
#endif
776 777 778 779 780 781
  }
  else
  {
    keyinfo->ck_insert = _mi_ck_write;
    keyinfo->ck_delete = _mi_ck_delete;
  }
unknown's avatar
unknown committed
782 783 784 785 786 787 788 789 790 791 792 793
  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 */
794
      if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
795 796 797 798
          (keyinfo->seg->flag & HA_NULL_PART))
        keyinfo->bin_search=_mi_seq_search;
      else
        keyinfo->bin_search=_mi_prefix_search;
unknown's avatar
unknown committed
799 800 801 802 803
      keyinfo->pack_key=_mi_calc_var_pack_key_length;
      keyinfo->store_key=_mi_store_var_pack_key;
    }
    else
    {
804
      keyinfo->bin_search=_mi_seq_search;
unknown's avatar
unknown committed
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
      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;
}


820 821 822
/*
   Function to save and store the header in the index file (.MYI)
*/
unknown's avatar
unknown committed
823 824 825 826 827 828 829

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,
	key_blocks=state->header.max_block_size;
830
  DBUG_ENTER("mi_state_info_write");
unknown's avatar
unknown committed
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846

  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;
847
  mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8;
unknown's avatar
unknown committed
848 849 850
  mi_int4store(ptr,state->process);		ptr +=4;
  mi_int4store(ptr,state->unique);		ptr +=4;
  mi_int4store(ptr,state->status);		ptr +=4;
851
  mi_int4store(ptr,state->update_count);	ptr +=4;
unknown's avatar
unknown committed
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880

  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)
881 882 883 884
    DBUG_RETURN(my_pwrite(file,(char*) buff, (uint) (ptr-buff), 0L,
			  MYF(MY_NABP | MY_THREADSAFE)));
  DBUG_RETURN(my_write(file,  (char*) buff, (uint) (ptr-buff),
		       MYF(MY_NABP)));
unknown's avatar
unknown committed
885 886 887
}


888
uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state)
unknown's avatar
unknown committed
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
{
  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);
  key_blocks=state->header.max_block_size;

  state->open_count = mi_uint2korr(ptr);	ptr +=2;
  state->changed= (bool) *ptr++;
  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;
909
  state->state.checksum=(ha_checksum) mi_uint8korr(ptr);	ptr +=8;
unknown's avatar
unknown committed
910 911 912
  state->process= mi_uint4korr(ptr);		ptr +=4;
  state->unique = mi_uint4korr(ptr);		ptr +=4;
  state->status = mi_uint4korr(ptr);		ptr +=4;
913 914
  state->update_count=mi_uint4korr(ptr);	ptr +=4;

915 916
  ptr+= state->state_diff_length;

unknown's avatar
unknown committed
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
  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)
{
  char	buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];

945
  if (!myisam_single_user)
unknown's avatar
unknown committed
946
  {
947 948 949 950 951 952
    if (pRead)
    {
      if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
	return (MY_FILE_ERROR);
    }
    else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
unknown's avatar
unknown committed
953
      return (MY_FILE_ERROR);
954
    mi_state_info_read((uchar*) buff, state);
unknown's avatar
unknown committed
955 956 957 958 959 960 961 962 963 964 965 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 992 993 994 995 996 997 998
  }
  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 */
  return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}


999
uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
unknown's avatar
unknown committed
1000 1001 1002 1003 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 1044 1045 1046 1047 1048
{
  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;
1049
  *ptr++ = keydef->key_alg;			/* Rtree or Btree */
unknown's avatar
unknown committed
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
  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;
  return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}

char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef)
{
   keydef->keysegs	= (uint) *ptr++;
1061
   keydef->key_alg	= *ptr++;		/* Rtree or Btree */
1062

unknown's avatar
unknown committed
1063 1064 1065 1066 1067
   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;
unknown's avatar
unknown committed
1068
   keydef->block_size	= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
unknown's avatar
unknown committed
1069 1070 1071 1072 1073 1074 1075 1076 1077
   keydef->underflow_block_length=keydef->block_length/3;
   keydef->version	= 0;			/* Not saved */
   return ptr;
}

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

unknown's avatar
unknown committed
1078
int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
unknown's avatar
unknown committed
1079
{
unknown's avatar
unknown committed
1080
  uchar buff[HA_KEYSEG_SIZE];
unknown's avatar
unknown committed
1081
  uchar *ptr=buff;
unknown's avatar
unknown committed
1082
  ulong pos;
unknown's avatar
unknown committed
1083

unknown's avatar
unknown committed
1084 1085 1086 1087 1088
  *ptr++= keyseg->type;
  *ptr++= keyseg->language;
  *ptr++= keyseg->null_bit;
  *ptr++= keyseg->bit_start;
  *ptr++= keyseg->bit_end;
unknown's avatar
unknown committed
1089
  *ptr++= keyseg->bit_length;
unknown's avatar
unknown committed
1090 1091 1092
  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
1093 1094
  pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
  mi_int4store(ptr, pos);
unknown's avatar
unknown committed
1095 1096
  ptr+=4;
  
unknown's avatar
unknown committed
1097 1098 1099 1100
  return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}


unknown's avatar
unknown committed
1101
char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg)
unknown's avatar
unknown committed
1102 1103 1104 1105 1106 1107
{
   keyseg->type		= *ptr++;
   keyseg->language	= *ptr++;
   keyseg->null_bit	= *ptr++;
   keyseg->bit_start	= *ptr++;
   keyseg->bit_end	= *ptr++;
unknown's avatar
unknown committed
1108
   keyseg->bit_length   = *ptr++;
unknown's avatar
unknown committed
1109 1110 1111 1112 1113
   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
1114
   if (keyseg->null_bit)
1115
     keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
unknown's avatar
unknown committed
1116 1117
   else
   {
1118
     keyseg->bit_pos= (uint16)keyseg->null_pos;
unknown's avatar
unknown committed
1119 1120
     keyseg->null_pos= 0;
   }
unknown's avatar
unknown committed
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
   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;

  return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}

char *mi_uniquedef_read(char *ptr, MI_UNIQUEDEF *def)
{
   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;
  return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}

char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo)
{
   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;
}
1172 1173

/**************************************************************************
1174
Open data file with or without RAID
1175
We can't use dup() here as the data file descriptors need to have different
1176 1177 1178 1179 1180
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.
*************************************************************************/
1181

1182
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attribute__((unused)))
1183 1184 1185 1186
{
#ifdef USE_RAID
  if (share->base.raid_type)
  {
unknown's avatar
unknown committed
1187 1188 1189 1190 1191 1192
    info->dfile=my_raid_open(share->data_file_name,
			     share->mode | O_SHARE,
			     share->base.raid_type,
			     share->base.raid_chunks,
			     share->base.raid_chunksize,
			     MYF(MY_WME | MY_RAID));
1193 1194 1195
  }
  else
#endif
1196 1197
    info->dfile=my_open(share->data_file_name, share->mode | O_SHARE,
			MYF(MY_WME));
unknown's avatar
unknown committed
1198
  return info->dfile >= 0 ? 0 : 1;
1199 1200 1201 1202 1203
}


int mi_open_keyfile(MYISAM_SHARE *share)
{
unknown's avatar
unknown committed
1204
  if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE,
unknown's avatar
unknown committed
1205
                            MYF(MY_WME))) < 0)
1206 1207 1208
    return 1;
  return 0;
}
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228


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

1229
  mi_clear_all_keys_active(share->state.key_map);
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
  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))
1260
  {
unknown's avatar
unknown committed
1261
    mi_print_error(info->s, HA_ERR_CRASHED);
1262
    error= HA_ERR_CRASHED;
1263
  }
1264
  else
1265
    mi_set_all_keys_active(share->state.key_map, share->base.keys);
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
  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
1283
    2  non-unique indexes are disabled
1284 1285 1286 1287 1288 1289
*/

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

unknown's avatar
unknown committed
1290 1291 1292 1293 1294 1295
  /*
    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 ||
1296
      (mi_is_all_keys_active(share->state.key_map, share->base.keys)))
unknown's avatar
unknown committed
1297 1298 1299
    return 0;

  /* All are disabled */
1300
  if (mi_is_any_key_active(share->state.key_map))
unknown's avatar
unknown committed
1301 1302 1303 1304 1305 1306 1307
    return 1;

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