ma_open.c 67.5 KB
Newer Older
1 2 3 4
/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* open a isam-database */

#include "ma_fulltext.h"
#include "ma_sp_defs.h"
#include "ma_rt_index.h"
unknown's avatar
unknown committed
21
#include "ma_blockrec.h"
22 23 24 25 26 27 28 29 30 31 32
#include <m_ctype.h>

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

static void setup_key_functions(MARIA_KEYDEF *keyinfo);
unknown's avatar
unknown committed
33 34 35 36
static my_bool maria_scan_init_dummy(MARIA_HA *info);
static void maria_scan_end_dummy(MARIA_HA *info);
static my_bool maria_once_init_dummy(MARIA_SHARE *, File);
static my_bool maria_once_end_dummy(MARIA_SHARE *);
unknown's avatar
unknown committed
37
static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base);
unknown's avatar
unknown committed
38
static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state);
unknown's avatar
unknown committed
39

40 41 42 43
#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
					pos+=size;}


Michael Widenius's avatar
Michael Widenius committed
44
#define disk_pos_assert(share, pos, end_pos)     \
45 46
if (pos > end_pos)             \
{                              \
Michael Widenius's avatar
Michael Widenius committed
47
  _ma_set_fatal_error(share, HA_ERR_CRASHED);    \
48 49 50 51 52 53 54 55 56
  goto err;                    \
}


/******************************************************************************
** Return the shared struct if the table is already open.
** In MySQL the server will handle version issues.
******************************************************************************/

57
MARIA_HA *_ma_test_if_reopen(const char *filename)
58 59 60 61 62 63
{
  LIST *pos;

  for (pos=maria_open_list ; pos ; pos=pos->next)
  {
    MARIA_HA *info=(MARIA_HA*) pos->data;
64
    MARIA_SHARE *share= info->s;
65
    if (!strcmp(share->unique_file_name.str,filename) && share->last_version)
66 67 68 69 70 71
      return info;
  }
  return 0;
}


72 73 74 75 76 77 78 79
/*
  Open a new instance of an already opened Maria table

  SYNOPSIS
    maria_clone_internal()
    share	Share of already open table
    mode	Mode of table (O_RDONLY | O_RDWR)
    data_file   Filedescriptor of data file to use < 0 if one should open
80 81
	        open it.

82
 RETURN
83 84 85 86 87
    #   Maria handler
    0   Error
*/


88 89
static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, const char *name,
                                      int mode, File data_file)
90 91 92 93
{
  int save_errno;
  uint errpos;
  MARIA_HA info,*m_info;
unknown's avatar
unknown committed
94
  my_bitmap_map *changed_fields_bitmap;
95 96 97
  DBUG_ENTER("maria_clone_internal");

  errpos= 0;
unknown's avatar
unknown committed
98
  bzero((uchar*) &info,sizeof(info));
99 100 101 102 103 104 105 106

  if (mode == O_RDWR && share->mode == O_RDONLY)
  {
    my_errno=EACCES;				/* Can't open in write mode */
    goto err;
  }
  if (data_file >= 0)
    info.dfile.file= data_file;
107
  else if (_ma_open_datafile(&info, share, name, -1))
108 109 110 111 112 113 114 115 116
    goto err;
  errpos= 5;

  /* alloc and set up private structure parts */
  if (!my_multi_malloc(MY_WME,
		       &m_info,sizeof(MARIA_HA),
		       &info.blobs,sizeof(MARIA_BLOB)*share->base.blobs,
		       &info.buff,(share->base.max_key_block_length*2+
				   share->base.max_key_length),
117
		       &info.lastkey_buff,share->base.max_key_length*2+1,
118 119 120
		       &info.first_mbr_key, share->base.max_key_length,
		       &info.maria_rtree_recursion_state,
                       share->have_rtree ? 1024 : 0,
unknown's avatar
unknown committed
121 122
                       &changed_fields_bitmap,
                       bitmap_buffer_size(share->base.fields),
123 124 125 126 127
		       NullS))
    goto err;
  errpos= 6;

  memcpy(info.blobs,share->blobs,sizeof(MARIA_BLOB)*share->base.blobs);
128 129
  info.lastkey_buff2= info.lastkey_buff + share->base.max_key_length;
  info.last_key.data= info.lastkey_buff;
130 131 132

  info.s=share;
  info.cur_row.lastpos= HA_OFFSET_ERROR;
133 134
  /* Impossible first index to force initialization in _ma_check_index() */
  info.lastinx= ~0;
135 136 137
  info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
  info.opt_flag=READ_CHECK_USED;
  info.this_unique= (ulong) info.dfile.file; /* Uniq number in process */
Michael Widenius's avatar
Michael Widenius committed
138
#ifdef MARIA_EXTERNAL_LOCKING
139 140 141 142 143
  if (share->data_file_type == COMPRESSED_RECORD)
    info.this_unique= share->state.unique;
  info.this_loop=0;				/* Update counter */
  info.last_unique= share->state.unique;
  info.last_loop=   share->state.update_count;
144
#endif
145 146 147
  info.errkey= -1;
  info.page_changed=1;
  info.keyread_buff= info.buff + share->base.max_key_block_length;
148 149 150 151 152

  info.lock_type= F_UNLCK;
  if (share->options & HA_OPTION_TMP_TABLE)
    info.lock_type= F_WRLCK;

153
  _ma_set_data_pagecache_callbacks(&info.dfile, share);
unknown's avatar
unknown committed
154 155
  bitmap_init(&info.changed_fields, changed_fields_bitmap,
              share->base.fields, 0);
156 157 158
  if ((*share->init)(&info))
    goto err;

159 160 161 162 163 164 165 166
  /* The following should be big enough for all pinning purposes */
  if (my_init_dynamic_array(&info.pinned_pages,
                            sizeof(MARIA_PINNED_PAGE),
                            max(share->base.blobs*2 + 4,
                                MARIA_MAX_TREE_LEVELS*3), 16))
    goto err;


167 168 169 170 171 172 173 174 175 176 177 178 179 180
  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++;
    share->tot_locks++;
  }
  if ((share->options & HA_OPTION_DELAY_KEY_WRITE) &&
      maria_delay_key_write)
    share->delay_key_write=1;

unknown's avatar
unknown committed
181
  if (!share->base.born_transactional)   /* For transactional ones ... */
182
  {
183 184
    /* ... force crash if no trn given */
    _ma_set_trn_for_table(&info, &dummy_transaction_object);
185 186 187 188
    info.state= &share->state.state;	/* Change global values by default */
  }
  else
  {
189
    info.state=  &share->state.common;
190 191 192 193
    *info.state= share->state.state;            /* Initial values */
  }
  info.state_start= info.state;                 /* Initial values */

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  pthread_mutex_unlock(&share->intern_lock);

  /* Allocate buffer for one record */
  /* prerequisites: info->rec_buffer == 0 && info->rec_buff_size == 0 */
  if (_ma_alloc_buffer(&info.rec_buff, &info.rec_buff_size,
                       share->base.default_rec_buff_size))
    goto err;

  bzero(info.rec_buff, share->base.default_rec_buff_size);

  *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;
  maria_open_list=list_add(maria_open_list,&m_info->open_list);

  DBUG_RETURN(m_info);

err:
214
  DBUG_PRINT("error", ("error: %d", my_errno));
215 216 217 218
  save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
  if ((save_errno == HA_ERR_CRASHED) ||
      (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
      (save_errno == HA_ERR_CRASHED_ON_REPAIR))
219
    _ma_report_error(save_errno, &share->open_file_name);
220 221 222
  switch (errpos) {
  case 6:
    (*share->end)(&info);
223 224
    delete_dynamic(&info.pinned_pages);
    my_free(m_info, MYF(0));
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    /* fall through */
  case 5:
    if (data_file < 0)
      VOID(my_close(info.dfile.file, MYF(0)));
    break;
  }
  my_errno=save_errno;
  DBUG_RETURN (NULL);
} /* maria_clone_internal */


/* Make a clone of a maria table */

MARIA_HA *maria_clone(MARIA_SHARE *share, int mode)
{
  MARIA_HA *new_info;
  pthread_mutex_lock(&THR_LOCK_maria);
242
  new_info= maria_clone_internal(share, NullS, mode,
243 244 245 246 247 248 249
                                 share->data_file_type == BLOCK_RECORD ?
                                 share->bitmap.file.file : -1);
  pthread_mutex_unlock(&THR_LOCK_maria);
  return new_info;
}


250
/******************************************************************************
251 252
  open a MARIA table

253 254 255 256 257 258 259 260
  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.
******************************************************************************/

MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
{
261
  int kfile,open_mode,save_errno;
262
  uint i,j,len,errpos,head_length,base_pos,keys, realpath_err,
263
    key_parts,unique_key_parts,fulltext_keys,uniques;
264
  size_t info_length;
265 266
  char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
       data_name[FN_REFLEN];
267
  uchar *disk_cache, *disk_pos, *end_pos;
268 269
  MARIA_HA info,*m_info,*old_info;
  MARIA_SHARE share_buff,*share;
270 271
  double *rec_per_key_part;
  ulong  *nulls_per_key_part;
unknown's avatar
unknown committed
272
  my_off_t key_root[HA_MAX_POSSIBLE_KEY];
273
  ulonglong max_key_file_length, max_data_file_length;
274
  my_bool versioning= 1;
275
  File data_file= -1;
276 277 278 279
  DBUG_ENTER("maria_open");

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

284 285 286 287 288 289 290 291 292 293
  realpath_err= my_realpath(name_buff, fn_format(org_name, name, "",
                                                 MARIA_NAME_IEXT,
                                                 MY_UNPACK_FILENAME),MYF(0));
  if (my_is_symlink(org_name) &&
      (realpath_err || (*maria_test_invalid_symlink)(name_buff)))
  {
    my_errno= HA_WRONG_CREATE_OPTION;
    DBUG_RETURN(0);
  }

294
  pthread_mutex_lock(&THR_LOCK_maria);
295 296 297
  old_info= 0;
  if ((open_flags & HA_OPEN_COPY) ||
      !(old_info=_ma_test_if_reopen(name_buff)))
298 299
  {
    share= &share_buff;
unknown's avatar
unknown committed
300
    bzero((uchar*) &share_buff,sizeof(share_buff));
301
    share_buff.state.key_root=key_root;
302
    share_buff.pagecache= multi_pagecache_search((uchar*) name_buff,
unknown's avatar
unknown committed
303
						 (uint) strlen(name_buff),
unknown's avatar
unknown committed
304
                                                 maria_pagecache);
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

    DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_open",
                    if (strstr(name, "/t1"))
                    {
                      my_errno= HA_ERR_CRASHED;
                      goto err;
                    });
    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;
    }
    share->mode=open_mode;
unknown's avatar
unknown committed
320
    errpos= 1;
321 322
    if (my_pread(kfile,share->state.header.file_version, head_length, 0,
                 MYF(MY_NABP)))
323 324 325 326
    {
      my_errno= HA_ERR_NOT_A_TABLE;
      goto err;
    }
Michael Widenius's avatar
Michael Widenius committed
327
    if (memcmp(share->state.header.file_version, maria_file_magic, 4))
328 329
    {
      DBUG_PRINT("error",("Wrong header in %s",name_buff));
unknown's avatar
unknown committed
330
      DBUG_DUMP("error_dump", share->state.header.file_version,
331 332 333 334 335 336 337 338 339 340
		head_length);
      my_errno=HA_ERR_NOT_A_TABLE;
      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 |
341 342
          HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS |
          HA_OPTION_PAGE_CHECKSUM))
343 344
    {
      DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
345
      my_errno=HA_ERR_NEW_FILE;
346 347 348 349 350
      goto err;
    }
    if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
        ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
    {
unknown's avatar
unknown committed
351
      DBUG_PRINT("error", ("table cannot be opened from non-sql layer"));
352 353 354 355 356 357 358
      my_errno= HA_ERR_UNSUPPORTED;
      goto err;
    }
    /* Don't call realpath() if the name can't be a link */
    if (!strcmp(name_buff, org_name) ||
        my_readlink(index_name, org_name, MYF(0)) == -1)
      (void) strmov(index_name, org_name);
359
    *strrchr(org_name, FN_EXTCHAR)= '\0';
360 361 362 363
    (void) fn_format(data_name,org_name,"",MARIA_NAME_DEXT,
                     MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);

    info_length=mi_uint2korr(share->state.header.header_length);
unknown's avatar
unknown committed
364
    base_pos= mi_uint2korr(share->state.header.base_pos);
365 366 367 368 369 370 371 372 373 374 375 376 377 378

    /*
      Allocate space for header information and for data that is too
      big to keep on stack
    */
    if (!my_multi_malloc(MY_WME,
                         &disk_cache, info_length+128,
                         &rec_per_key_part,
                         (sizeof(*rec_per_key_part) * HA_MAX_POSSIBLE_KEY *
                          HA_MAX_KEY_SEG),
                         &nulls_per_key_part,
                         (sizeof(*nulls_per_key_part) * HA_MAX_POSSIBLE_KEY *
                          HA_MAX_KEY_SEG),
                         NullS))
379 380 381 382
    {
      my_errno=ENOMEM;
      goto err;
    }
383 384 385
    share_buff.state.rec_per_key_part=   rec_per_key_part;
    share_buff.state.nulls_per_key_part= nulls_per_key_part;

386
    end_pos=disk_cache+info_length;
unknown's avatar
unknown committed
387
    errpos= 3;
388
    if (my_pread(kfile, disk_cache, info_length, 0L, MYF(MY_NABP)))
389
    {
Michael Widenius's avatar
Michael Widenius committed
390
      _ma_set_fatal_error(share, HA_ERR_CRASHED);
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
      goto err;
    }
    len=mi_uint2korr(share->state.header.state_info_length);
    keys=    (uint) share->state.header.keys;
    uniques= (uint) share->state.header.uniques;
    fulltext_keys= (uint) share->state.header.fulltext_keys;
    key_parts= mi_uint2korr(share->state.header.key_parts);
    unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
    if (len != MARIA_STATE_INFO_SIZE)
    {
      DBUG_PRINT("warning",
		 ("saved_state_info_length: %d  state_info_length: %d",
		  len,MARIA_STATE_INFO_SIZE));
    }
    share->state_diff_length=len-MARIA_STATE_INFO_SIZE;

unknown's avatar
unknown committed
407
    _ma_state_info_read(disk_cache, &share->state);
408 409 410 411 412 413
    len= mi_uint2korr(share->state.header.base_info_length);
    if (len != MARIA_BASE_INFO_SIZE)
    {
      DBUG_PRINT("warning",("saved_base_info_length: %d  base_info_length: %d",
			    len,MARIA_BASE_INFO_SIZE));
    }
unknown's avatar
unknown committed
414
    disk_pos= _ma_base_info_read(disk_cache + base_pos, &share->base);
415
    share->state.state_length=base_pos;
Michael Widenius's avatar
Michael Widenius committed
416 417
    /* For newly opened tables we reset the error-has-been-printed flag */
    share->state.changed&= ~STATE_CRASHED_PRINTED;
418 419

    if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
Michael Widenius's avatar
Michael Widenius committed
420
	((share->state.changed & STATE_CRASHED_FLAGS) ||
421 422 423
	 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
	  (my_disable_locking && share->state.open_count))))
    {
424 425 426 427
      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));
428 429 430 431
      my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
		HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
      goto err;
    }
432 433
    if (share->state.open_count)
      share->open_count_not_zero_on_open= 1;
434

435 436 437 438
    /*
      We can ignore testing uuid if STATE_NOT_MOVABLE is set, as in this
      case the uuid will be set in _ma_mark_file_changed()
    */
439
    if ((share->state.changed & STATE_NOT_MOVABLE) &&
440
        share->base.born_transactional &&
441 442
        ((!(open_flags & HA_OPEN_IGNORE_MOVED_STATE) &&
          memcmp(share->base.uuid, maria_uuid, MY_UUID_SIZE)) ||
443 444
         (share->state.create_trid > trnman_get_max_trid() &&
          !maria_in_recovery)))
445
    {
446 447 448 449 450
      DBUG_PRINT("warning", ("table is moved from another system.  uuid_diff: %d  create_trid: %lu  max_trid: %lu",
                            memcmp(share->base.uuid, maria_uuid,
                                   MY_UUID_SIZE) != 0,
                             (ulong) share->state.create_trid,
                             (ulong) trnman_get_max_trid()));
451 452 453 454 455 456 457 458 459
      if (open_flags & HA_OPEN_FOR_REPAIR)
        share->state.changed|= STATE_MOVED;
      else
      {
        my_errno= HA_ERR_OLD_FILE;
        goto err;
      }
    }

460 461 462
    /* sanity check */
    if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
    {
Michael Widenius's avatar
Michael Widenius committed
463
      _ma_set_fatal_error(share, HA_ERR_CRASHED);
464 465 466 467
      goto err;
    }

    key_parts+=fulltext_keys*FT_SEGS;
468
    if (share->base.max_key_length > maria_max_key_length() ||
469
        keys > MARIA_MAX_KEY || key_parts > MARIA_MAX_KEY * HA_MAX_KEY_SEG)
470 471 472 473 474
    {
      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;
    }
475 476 477 478

    /* Ensure we have space in the key buffer for transaction id's */
    if (share->base.born_transactional)
      share->base.max_key_length= ALIGN_SIZE(share->base.max_key_length +
479
                                             MARIA_MAX_PACK_TRANSID_SIZE);
480

unknown's avatar
unknown committed
481
    /*
482 483 484 485
      If page cache is not initialized, then assume we will create the
      page_cache after the table is opened!
      This is only used by maria_check to allow it to check/repair tables
      with different block sizes.
unknown's avatar
unknown committed
486 487 488
    */
    if (share->base.block_size != maria_block_size &&
        share_buff.pagecache->inited != 0)
489 490 491 492 493 494 495
    {
      DBUG_PRINT("error", ("Wrong block size %u; Expected %u",
                           (uint) share->base.block_size,
                           (uint) maria_block_size));
      my_errno=HA_ERR_UNSUPPORTED;
      goto err;
    }
496 497 498 499 500 501 502

    /* Correct max_file_length based on length of sizeof(off_t) */
    max_data_file_length=
      (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
      (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
      (_ma_safe_mul(share->base.pack_reclength,
		   (ulonglong) 1 << (share->base.rec_reflength*8))-1);
unknown's avatar
unknown committed
503

504
    max_key_file_length=
505
      _ma_safe_mul(share->base.block_size,
506 507 508 509 510 511 512 513 514 515
		  ((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
    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 */
516 517
    /* Add space for node pointer */
    share->base.max_key_length+= share->base.key_reflength;
518

519 520 521 522
    share->unique_file_name.length= strlen(name_buff);
    share->index_file_name.length=  strlen(index_name);
    share->data_file_name.length=   strlen(data_name);
    share->open_file_name.length=   strlen(name);
523 524
    if (!my_multi_malloc(MY_WME,
			 &share,sizeof(*share),
525 526 527 528
			 &share->state.rec_per_key_part,
                         sizeof(double) * key_parts,
                         &share->state.nulls_per_key_part,
                         sizeof(long)* key_parts,
529 530 531 532 533
			 &share->keyinfo,keys*sizeof(MARIA_KEYDEF),
			 &share->uniqueinfo,uniques*sizeof(MARIA_UNIQUEDEF),
			 &share->keyparts,
			 (key_parts+unique_key_parts+keys+uniques) *
			 sizeof(HA_KEYSEG),
534
			 &share->columndef,
535
			 (share->base.fields+1)*sizeof(MARIA_COLUMNDEF),
536
                         &share->column_nr, share->base.fields*sizeof(uint16),
537
			 &share->blobs,sizeof(MARIA_BLOB)*share->base.blobs,
538 539 540 541 542 543 544 545
			 &share->unique_file_name.str,
			 share->unique_file_name.length+1,
			 &share->index_file_name.str,
                         share->index_file_name.length+1,
			 &share->data_file_name.str,
                         share->data_file_name.length+1,
                         &share->open_file_name.str,
                         share->open_file_name.length+1,
546 547 548 549
			 &share->state.key_root,keys*sizeof(my_off_t),
			 &share->mmap_lock,sizeof(rw_lock_t),
			 NullS))
      goto err;
unknown's avatar
unknown committed
550 551
    errpos= 4;

552 553
    *share=share_buff;
    memcpy((char*) share->state.rec_per_key_part,
554 555 556
	   (char*) rec_per_key_part, sizeof(double)*key_parts);
    memcpy((char*) share->state.nulls_per_key_part,
	   (char*) nulls_per_key_part, sizeof(long)*key_parts);
557 558
    memcpy((char*) share->state.key_root,
	   (char*) key_root, sizeof(my_off_t)*keys);
559 560 561 562
    strmov(share->unique_file_name.str, name_buff);
    strmov(share->index_file_name.str, index_name);
    strmov(share->data_file_name.str,  data_name);
    strmov(share->open_file_name.str,  name);
563

564
    share->block_size= share->base.block_size;   /* Convenience */
565
    share->max_index_block_size= share->block_size - KEYPAGE_CHECKSUM_SIZE;
566 567 568 569
    share->keypage_header= ((share->base.born_transactional ?
                             LSN_STORE_SIZE + TRANSID_SIZE :
                             0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
                            KEYPAGE_USED_SIZE);
570 571
    {
      HA_KEYSEG *pos=share->keyparts;
572
      uint32 ftkey_nr= 1;
573 574
      for (i=0 ; i < keys ; i++)
      {
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
        MARIA_KEYDEF *keyinfo= &share->keyinfo[i];
        keyinfo->share= share;
	disk_pos=_ma_keydef_read(disk_pos, keyinfo);
        keyinfo->key_nr= i;

        /* See ma_delete.cc::underflow() */
        if (!(keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
          keyinfo->underflow_block_length= keyinfo->block_length/3;
        else
        {
          /* Packed key, ensure we don't get overflow in underflow() */
          keyinfo->underflow_block_length=
            max((int) (share->max_index_block_size - keyinfo->maxlength * 3),
                (int) (share->keypage_header + share->base.key_reflength));
          set_if_smaller(keyinfo->underflow_block_length,
                         keyinfo->block_length/3);
        }

Michael Widenius's avatar
Michael Widenius committed
593
        disk_pos_assert(share,
594
                        disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE,
595
 			end_pos);
596
        if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
597
          share->have_rtree= 1;
598 599
	keyinfo->seg=pos;
	for (j=0 ; j < keyinfo->keysegs; j++,pos++)
600 601 602 603 604 605 606 607 608 609 610 611 612 613
	{
	  disk_pos=_ma_keyseg_read(disk_pos, pos);
	  if (pos->type == HA_KEYTYPE_TEXT ||
              pos->type == HA_KEYTYPE_VARTEXT1 ||
              pos->type == HA_KEYTYPE_VARTEXT2)
	  {
	    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;
	    }
	  }
614 615
	  else if (pos->type == HA_KEYTYPE_BINARY)
	    pos->charset= &my_charset_bin;
616
	}
617
	if (keyinfo->flag & HA_SPATIAL)
618 619 620
	{
#ifdef HAVE_SPATIAL
	  uint sp_segs=SPDIMS*2;
621 622
	  keyinfo->seg=pos-sp_segs;
	  keyinfo->keysegs--;
623
          versioning= 0;
624 625 626 627 628
#else
	  my_errno=HA_ERR_UNSUPPORTED;
	  goto err;
#endif
	}
629
        else if (keyinfo->flag & HA_FULLTEXT)
630
	{
631 632
          versioning= 0;
          DBUG_ASSERT(fulltext_keys);
633
          {
634
            uint k;
635
            keyinfo->seg=pos;
636
            for (k=0; k < FT_SEGS; k++)
637
            {
638
              *pos= ft_keysegs[k];
639 640 641
              pos[0].language= pos[-1].language;
              if (!(pos[0].charset= pos[-1].charset))
              {
Michael Widenius's avatar
Michael Widenius committed
642
                _ma_set_fatal_error(share, HA_ERR_CRASHED);
643 644 645 646 647 648 649
                goto err;
              }
              pos++;
            }
          }
          if (!share->ft2_keyinfo.seg)
          {
650
            memcpy(&share->ft2_keyinfo, keyinfo, sizeof(MARIA_KEYDEF));
651 652 653 654 655 656 657 658 659
            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);
          }
660
          keyinfo->ftkey_nr= ftkey_nr++;
661
	}
662 663
        setup_key_functions(keyinfo);
	keyinfo->end=pos;
664 665 666 667 668 669 670 671 672
	pos->type=HA_KEYTYPE_END;			/* End */
	pos->length=share->base.rec_reflength;
	pos->null_bit=0;
	pos->flag=0;					/* For purify */
	pos++;
      }
      for (i=0 ; i < uniques ; i++)
      {
	disk_pos=_ma_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
Michael Widenius's avatar
Michael Widenius committed
673 674
        disk_pos_assert(share,
                        disk_pos + share->uniqueinfo[i].keysegs *
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
			HA_KEYSEG_SIZE, end_pos);
	share->uniqueinfo[i].seg=pos;
	for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
	{
	  disk_pos=_ma_keyseg_read(disk_pos, pos);
	  if (pos->type == HA_KEYTYPE_TEXT ||
              pos->type == HA_KEYTYPE_VARTEXT1 ||
              pos->type == HA_KEYTYPE_VARTEXT2)
	  {
	    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;
	pos->flag=0;
	pos++;
      }
699
      share->ftkeys= ftkey_nr;
700
    }
unknown's avatar
unknown committed
701 702 703 704 705 706
    share->data_file_type= share->state.header.data_file_type;
    share->base_length= (BASE_ROW_HEADER_SIZE +
                         share->base.is_nulls_extended +
                         share->base.null_bytes +
                         share->base.pack_bytes +
                         test(share->options & HA_OPTION_CHECKSUM));
unknown's avatar
unknown committed
707
    share->kfile.file= kfile;
708

709
    if (open_flags & HA_OPEN_COPY)
unknown's avatar
unknown committed
710
    {
unknown's avatar
unknown committed
711 712 713 714 715 716 717 718 719 720
      /*
        this instance will be a temporary one used just to create a data
        file for REPAIR. Don't do logging. This base information will not go
        to disk.
      */
      share->base.born_transactional= FALSE;
    }
    if (share->base.born_transactional)
    {
      share->page_type= PAGECACHE_LSN_PAGE;
721
      if (share->state.create_rename_lsn == LSN_NEEDS_NEW_STATE_LSNS)
unknown's avatar
unknown committed
722 723
      {
        /*
unknown's avatar
unknown committed
724 725 726
          Was repaired with maria_chk, maybe later maria_pack-ed. Some sort of
          import into the server. It starts its existence (from the point of
          view of the server, including server's recovery) now.
unknown's avatar
unknown committed
727
        */
728 729
        if (((open_flags & HA_OPEN_FROM_SQL_LAYER) &&
             (share->state.changed & STATE_NOT_MOVABLE)) || maria_in_recovery)
730
          _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE,
731
                                    trnman_get_min_safe_trid(), TRUE, TRUE);
unknown's avatar
unknown committed
732
      }
unknown's avatar
unknown committed
733
      else if ((!LSN_VALID(share->state.create_rename_lsn) ||
unknown's avatar
unknown committed
734
                !LSN_VALID(share->state.is_of_horizon) ||
unknown's avatar
unknown committed
735
                (cmp_translog_addr(share->state.create_rename_lsn,
unknown's avatar
unknown committed
736 737 738 739
                                   share->state.is_of_horizon) > 0) ||
                !LSN_VALID(share->state.skip_redo_lsn) ||
                (cmp_translog_addr(share->state.create_rename_lsn,
                                   share->state.skip_redo_lsn) > 0)) &&
unknown's avatar
unknown committed
740 741 742 743
               !(open_flags & HA_OPEN_FOR_REPAIR))
      {
        /*
          If in Recovery, it will not work. If LSN is invalid and not
744
          LSN_NEEDS_NEW_STATE_LSNS, header must be corrupted.
unknown's avatar
unknown committed
745 746 747 748 749
          In both cases, must repair.
        */
        my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
                  HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
        goto err;
unknown's avatar
unknown committed
750
      }
751 752 753 754 755
      else
      {
        /* create_rename_lsn != LSN_NEEDS_NEW_STATE_LSNS */
        share->state.changed|= STATE_NOT_MOVABLE;
      }
unknown's avatar
unknown committed
756
    }
unknown's avatar
unknown committed
757 758 759 760
    else
      share->page_type= PAGECACHE_PLAIN_PAGE;
    share->now_transactional= share->base.born_transactional;

761 762
    /* Use pack_reclength as we don't want to modify base.pack_recklength */
    if (share->state.header.org_data_file_type == DYNAMIC_RECORD)
unknown's avatar
unknown committed
763
    {
764
      /* add bits used to pack data to pack_reclength for faster allocation */
765
      share->base.pack_reclength+= share->base.pack_bytes;
unknown's avatar
unknown committed
766 767 768 769
      share->base.extra_rec_buff_size=
        (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER) + MARIA_SPLIT_LENGTH +
         MARIA_REC_BUFF_OFFSET);
    }
770 771 772
    if (share->data_file_type == COMPRESSED_RECORD)
    {
      /* Need some extra bytes for decode_bytes */
773
      share->base.extra_rec_buff_size+= 7;
774
    }
775 776 777 778
    share->base.default_rec_buff_size= max(share->base.pack_reclength +
                                           share->base.extra_rec_buff_size,
                                           share->base.max_key_length);

Michael Widenius's avatar
Michael Widenius committed
779 780
    disk_pos_assert(share,
                    disk_pos + share->base.fields *MARIA_COLUMNDEF_SIZE,
unknown's avatar
unknown committed
781 782
                    end_pos);
    for (i= j= 0 ; i < share->base.fields ; i++)
783
    {
784 785 786
      disk_pos=_ma_columndef_read(disk_pos,&share->columndef[i]);
      share->columndef[i].pack_type=0;
      share->columndef[i].huff_tree=0;
unknown's avatar
unknown committed
787
      if (share->columndef[i].type == FIELD_BLOB)
788 789
      {
	share->blobs[j].pack_length=
790
	  share->columndef[i].length-portable_sizeof_char_ptr;
791
	share->blobs[j].offset= share->columndef[i].offset;
792 793 794
	j++;
      }
    }
unknown's avatar
unknown committed
795
    share->columndef[i].type= FIELD_LAST;	/* End marker */
796 797
    disk_pos= _ma_column_nr_read(disk_pos, share->column_nr,
                                 share->base.fields);
798 799 800

    if ((share->data_file_type == BLOCK_RECORD ||
         share->data_file_type == COMPRESSED_RECORD))
801
    {
802
      if (_ma_open_datafile(&info, share, name, -1))
803 804
        goto err;
      data_file= info.dfile.file;
805
    }
unknown's avatar
unknown committed
806
    errpos= 5;
807

808 809 810 811 812 813
    if (open_flags & HA_OPEN_DELAY_KEY_WRITE)
      share->options|= HA_OPTION_DELAY_KEY_WRITE;
    if (mode == O_RDONLY)
      share->options|= HA_OPTION_READ_ONLY_DATA;
    share->is_log_table= FALSE;

814 815
    if (open_flags & HA_OPEN_TMP_TABLE ||
        (share->options & HA_OPTION_TMP_TABLE))
816 817 818 819 820 821 822 823
    {
      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 */
      share->tot_locks++;
    }

824
    _ma_set_index_pagecache_callbacks(&share->kfile, share);
825
    share->this_process=(ulong) getpid();
Michael Widenius's avatar
Michael Widenius committed
826
#ifdef MARIA_EXTERNAL_LOCKING
827
    share->last_process= share->state.process;
828
#endif
829 830 831 832 833 834 835
    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 ? MARIA_INDEX_BLOCK_MARGIN *
unknown's avatar
unknown committed
836
					 share->block_size * keys : 0));
837

838
    my_free(disk_cache, MYF(0));
839
    _ma_setup_functions(share);
unknown's avatar
unknown committed
840
    if ((*share->once_init)(share, info.dfile.file))
unknown's avatar
unknown committed
841
      goto err;
842 843 844 845 846 847 848 849
    if (share->now_transactional)
    {
      /* Setup initial state that is visible for all */
      MARIA_STATE_HISTORY_CLOSED *history;
      if ((history= (MARIA_STATE_HISTORY_CLOSED *)
           hash_search(&maria_stored_state,
                       (uchar*) &share->state.create_rename_lsn, 0)))
      {
850 851 852 853
        /*
          Move history from hash to share. This is safe to do as we
          don't have a lock on share->intern_lock.
        */
854 855 856 857 858 859 860 861 862 863 864
        share->state_history=
          _ma_remove_not_visible_states(history->state_history, 0, 0);
        history->state_history= 0;
        (void) hash_delete(&maria_stored_state, (uchar*) history);
      }
      else
      {
        /* Table is not part of any active transaction; Create new history */
        if (!(share->state_history= (MARIA_STATE_HISTORY *)
              my_malloc(sizeof(*share->state_history), MYF(MY_WME))))
          goto err;
865
        share->state_history->trid= 0;          /* Visible by all */
866 867 868 869
        share->state_history->state= share->state.state;
        share->state_history->next= 0;
      }
    }
870 871
#ifdef THREAD
    thr_lock_init(&share->lock);
872 873 874
    pthread_mutex_init(&share->intern_lock, MY_MUTEX_INIT_FAST);
    pthread_mutex_init(&share->key_del_lock, MY_MUTEX_INIT_FAST);
    pthread_cond_init(&share->key_del_cond, 0);
875
    pthread_mutex_init(&share->close_lock, MY_MUTEX_INIT_FAST);
876
    for (i=0; i<keys; i++)
877
      VOID(my_rwlock_init(&share->keyinfo[i].root_lock, NULL));
878
    VOID(my_rwlock_init(&share->mmap_lock, NULL));
879 880

    share->row_is_visible= _ma_row_visible_always;
881
    share->lock.get_status= _ma_reset_update_flag;
882 883 884 885 886 887 888
    if (!thr_lock_inited)
    {
      /* Probably a single threaded program; Don't use concurrent inserts */
      maria_concurrent_insert=0;
    }
    else if (maria_concurrent_insert)
    {
889
      share->non_transactional_concurrent_insert=
890
	((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
unknown's avatar
unknown committed
891 892
                            HA_OPTION_COMPRESS_RECORD |
                            HA_OPTION_TEMP_COMPRESS_RECORD)) ||
893
	 (open_flags & HA_OPEN_TMP_TABLE) ||
unknown's avatar
unknown committed
894
         share->data_file_type == BLOCK_RECORD ||
895
	 share->have_rtree) ? 0 : 1;
896
      if (share->non_transactional_concurrent_insert ||
897
          (!share->temporary && share->now_transactional && versioning))
898
      {
899
        share->lock_key_trees= 1;
unknown's avatar
unknown committed
900 901
        if (share->data_file_type == BLOCK_RECORD)
        {
902 903 904
          DBUG_ASSERT(share->now_transactional);
          share->have_versioning= 1;
          share->row_is_visible=     _ma_row_visible_transactional_table;
unknown's avatar
unknown committed
905 906
          share->lock.get_status=    _ma_block_get_status;
          share->lock.check_status=  _ma_block_check_status;
907
          share->lock.start_trans=   _ma_block_start_trans;
908 909 910 911 912 913 914 915 916 917 918
          /*
            We can for the moment only allow multiple concurrent inserts
            only if there is no auto-increment key.  To lift this restriction
            we have to:
            - Extend statement base replication to support auto-increment
            intervalls.
            - Fix that we allocate auto-increment in intervals and that
              it's properly reset if the interval was not used
          */
          share->lock.allow_multiple_concurrent_insert=
            share->base.auto_key == 0;
919
          share->lock_restore_status= 0;
unknown's avatar
unknown committed
920 921 922
        }
        else
        {
923 924 925 926 927 928
          share->row_is_visible=      _ma_row_visible_non_transactional_table;
          share->lock.get_status=     _ma_get_status;
          share->lock.copy_status=    _ma_copy_status;
          share->lock.update_status=  _ma_update_status;
          share->lock.restore_status= _ma_restore_status;
          share->lock.check_status=   _ma_check_status;
929
          share->lock_restore_status= _ma_restore_status;
unknown's avatar
unknown committed
930
        }
931
      }
932 933 934
      else if (share->now_transactional)
      {
        DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
935
        share->lock.start_trans=    _ma_block_start_trans_no_versioning;
936
      }
937
    }
938 939 940 941 942 943
#endif
#ifdef SAFE_MUTEX
    if (share->data_file_type == BLOCK_RECORD)
    {
      /*
        We must have internal_lock before bitmap_lock because we call
Michael Widenius's avatar
Michael Widenius committed
944
        _ma_flush_table_files() with internal_lock locked.
945 946 947 948 949 950
      */
      pthread_mutex_lock(&share->intern_lock);
      pthread_mutex_lock(&share->bitmap.bitmap_lock);
      pthread_mutex_unlock(&share->bitmap.bitmap_lock);
      pthread_mutex_unlock(&share->intern_lock);
    }
951
#endif
952 953 954 955 956 957 958 959
    /*
      Memory mapping can only be requested after initializing intern_lock.
    */
    if (open_flags & HA_OPEN_MMAP)
    {
      info.s= share;
      maria_extra(&info, HA_EXTRA_MMAP, 0);
    }
960 961 962 963
  }
  else
  {
    share= old_info->s;
unknown's avatar
unknown committed
964
    if (share->data_file_type == BLOCK_RECORD)
965
      data_file= share->bitmap.file.file;       /* Only opened once */
966 967
  }

968
  if (!(m_info= maria_clone_internal(share, name, mode, data_file)))
969
    goto err;
970

971 972 973 974
  if (maria_is_crashed(m_info))
    DBUG_PRINT("warning", ("table is crashed: changed: %u",
                           share->state.changed));

975 976 977 978
  pthread_mutex_unlock(&THR_LOCK_maria);
  DBUG_RETURN(m_info);

err:
979
  DBUG_PRINT("error", ("error: %d  errpos: %d", my_errno, errpos));
980 981 982 983
  save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
  if ((save_errno == HA_ERR_CRASHED) ||
      (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
      (save_errno == HA_ERR_CRASHED_ON_REPAIR))
984 985 986 987 988 989
  {
    LEX_STRING tmp_name;
    tmp_name.str= (char*) name;
    tmp_name.length= strlen(name);
    _ma_report_error(save_errno, &tmp_name);
  }
990 991
  switch (errpos) {
  case 5:
992 993
    if (data_file >= 0)
      VOID(my_close(data_file, MYF(0)));
994 995
    if (old_info)
      break;					/* Don't remove open table */
996
    (*share->once_end)(share);
997 998
    /* fall through */
  case 4:
Michael Widenius's avatar
Michael Widenius committed
999
    my_free(share,MYF(0));
1000 1001
    /* fall through */
  case 3:
1002
    my_free(disk_cache, MYF(0));
1003 1004 1005 1006 1007 1008 1009 1010 1011
    /* fall through */
  case 1:
    VOID(my_close(kfile,MYF(0)));
    /* fall through */
  case 0:
  default:
    break;
  }
  pthread_mutex_unlock(&THR_LOCK_maria);
1012
  my_errno= save_errno;
1013 1014 1015 1016
  DBUG_RETURN (NULL);
} /* maria_open */


unknown's avatar
unknown committed
1017 1018 1019
/*
  Reallocate a buffer, if the current buffer is not large enough
*/
1020

unknown's avatar
unknown committed
1021 1022
my_bool _ma_alloc_buffer(uchar **old_addr, size_t *old_size,
                         size_t new_size)
unknown's avatar
unknown committed
1023 1024
{
  if (*old_size < new_size)
1025
  {
unknown's avatar
unknown committed
1026
    uchar *addr;
Michael Widenius's avatar
Michael Widenius committed
1027 1028
    if (!(addr= (uchar*) my_realloc(*old_addr, new_size,
                                    MYF(MY_ALLOW_ZERO_PTR))))
unknown's avatar
unknown committed
1029 1030 1031
      return 1;
    *old_addr= addr;
    *old_size= new_size;
1032
  }
unknown's avatar
unknown committed
1033
  return 0;
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
}


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

void _ma_setup_functions(register MARIA_SHARE *share)
{
unknown's avatar
unknown committed
1050 1051 1052 1053
  share->once_init=          maria_once_init_dummy;
  share->once_end=           maria_once_end_dummy;
  share->init=      	     maria_scan_init_dummy;
  share->end=       	     maria_scan_end_dummy;
1054 1055
  share->scan_init=          maria_scan_init_dummy;/* Compat. dummy function */
  share->scan_end=           maria_scan_end_dummy;/* Compat. dummy function */
1056 1057 1058
  share->scan_remember_pos=  _ma_def_scan_remember_pos;
  share->scan_restore_pos=   _ma_def_scan_restore_pos;

unknown's avatar
unknown committed
1059 1060
  share->write_record_init=  _ma_write_init_default;
  share->write_record_abort= _ma_write_abort_default;
1061 1062
  share->keypos_to_recpos=   _ma_transparent_recpos;
  share->recpos_to_keypos=   _ma_transparent_recpos;
unknown's avatar
unknown committed
1063 1064 1065

  switch (share->data_file_type) {
  case COMPRESSED_RECORD:
1066
    share->read_record= _ma_read_pack_record;
unknown's avatar
unknown committed
1067 1068 1069
    share->scan= _ma_read_rnd_pack_record;
    share->once_init= _ma_once_init_pack_row;
    share->once_end=  _ma_once_end_pack_row;
1070 1071 1072 1073
    /*
      Calculate checksum according to data in the original, not compressed,
      row.
    */
1074 1075
    if (share->state.header.org_data_file_type == STATIC_RECORD &&
        ! (share->options & HA_OPTION_NULL_FIELDS))
1076
      share->calc_checksum= _ma_static_checksum;
unknown's avatar
unknown committed
1077 1078 1079 1080 1081
    else
      share->calc_checksum= _ma_checksum;
    share->calc_write_checksum= share->calc_checksum;
    break;
  case DYNAMIC_RECORD:
1082
    share->read_record= _ma_read_dynamic_record;
unknown's avatar
unknown committed
1083
    share->scan= _ma_read_rnd_dynamic_record;
1084 1085 1086
    share->delete_record= _ma_delete_dynamic_record;
    share->compare_record= _ma_cmp_dynamic_record;
    share->compare_unique= _ma_cmp_dynamic_unique;
unknown's avatar
unknown committed
1087
    share->calc_checksum= share->calc_write_checksum= _ma_checksum;
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
    if (share->base.blobs)
    {
      share->update_record= _ma_update_blob_record;
      share->write_record= _ma_write_blob_record;
    }
    else
    {
      share->write_record= _ma_write_dynamic_record;
      share->update_record= _ma_update_dynamic_record;
    }
unknown's avatar
unknown committed
1098 1099
    break;
  case STATIC_RECORD:
1100 1101 1102 1103 1104 1105 1106 1107 1108
    share->read_record=      _ma_read_static_record;
    share->scan=             _ma_read_rnd_static_record;
    share->delete_record=    _ma_delete_static_record;
    share->compare_record=   _ma_cmp_static_record;
    share->update_record=    _ma_update_static_record;
    share->write_record=     _ma_write_static_record;
    share->compare_unique=   _ma_cmp_static_unique;
    share->keypos_to_recpos= _ma_static_keypos_to_recpos;
    share->recpos_to_keypos= _ma_static_recpos_to_keypos;
1109 1110 1111 1112 1113
    if (share->state.header.org_data_file_type == STATIC_RECORD &&
        ! (share->options & HA_OPTION_NULL_FIELDS))
      share->calc_checksum= _ma_static_checksum;
    else
      share->calc_checksum= _ma_checksum;
unknown's avatar
unknown committed
1114 1115
    break;
  case BLOCK_RECORD:
1116 1117 1118 1119
    share->once_init= _ma_once_init_block_record;
    share->once_end=  _ma_once_end_block_record;
    share->init=      _ma_init_block_record;
    share->end=       _ma_end_block_record;
unknown's avatar
unknown committed
1120 1121 1122 1123 1124
    share->write_record_init= _ma_write_init_block_record;
    share->write_record_abort= _ma_write_abort_block_record;
    share->scan_init=   _ma_scan_init_block_record;
    share->scan_end=    _ma_scan_end_block_record;
    share->scan=        _ma_scan_block_record;
1125 1126 1127
    share->scan_remember_pos=  _ma_scan_remember_block_record;
    share->scan_restore_pos=   _ma_scan_restore_block_record;
    share->read_record= _ma_read_block_record;
unknown's avatar
unknown committed
1128 1129 1130 1131 1132 1133
    share->delete_record= _ma_delete_block_record;
    share->compare_record= _ma_compare_block_record;
    share->update_record= _ma_update_block_record;
    share->write_record=  _ma_write_block_record;
    share->compare_unique= _ma_cmp_block_unique;
    share->calc_checksum= _ma_checksum;
1134 1135 1136
    share->keypos_to_recpos= _ma_transaction_keypos_to_recpos;
    share->recpos_to_keypos= _ma_transaction_recpos_to_keypos;

1137 1138 1139 1140
    /*
      write_block_record() will calculate the checksum; Tell maria_write()
      that it doesn't have to do this.
    */
unknown's avatar
unknown committed
1141 1142
    share->calc_write_checksum= 0;
    break;
1143 1144 1145
  }
  share->file_read= _ma_nommap_pread;
  share->file_write= _ma_nommap_pwrite;
1146
  share->calc_check_checksum= share->calc_checksum;
1147

unknown's avatar
unknown committed
1148 1149 1150
  if (!(share->options & HA_OPTION_CHECKSUM) &&
      share->data_file_type != COMPRESSED_RECORD)
    share->calc_checksum= share->calc_write_checksum= 0;
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
  return;
}


static void setup_key_functions(register MARIA_KEYDEF *keyinfo)
{
  if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
  {
#ifdef HAVE_RTREE_KEYS
    keyinfo->ck_insert = maria_rtree_insert;
    keyinfo->ck_delete = maria_rtree_delete;
#else
    DBUG_ASSERT(0); /* maria_open should check it never happens */
#endif
  }
  else
  {
    keyinfo->ck_insert = _ma_ck_write;
    keyinfo->ck_delete = _ma_ck_delete;
  }
1171 1172 1173 1174 1175
  if (keyinfo->flag & HA_SPATIAL)
    keyinfo->make_key= _ma_sp_make_key;
  else
    keyinfo->make_key= _ma_make_key;

1176 1177 1178 1179
  if (keyinfo->flag & HA_BINARY_PACK_KEY)
  {						/* Simple prefix compression */
    keyinfo->bin_search= _ma_seq_search;
    keyinfo->get_key= _ma_get_binary_pack_key;
1180
    keyinfo->skip_key= _ma_skip_binary_pack_key;
1181 1182 1183 1184 1185
    keyinfo->pack_key= _ma_calc_bin_pack_key_length;
    keyinfo->store_key= _ma_store_bin_pack_key;
  }
  else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
  {
1186 1187
    keyinfo->get_key=  _ma_get_pack_key;
    keyinfo->skip_key= _ma_skip_pack_key;
1188 1189
    if (keyinfo->seg[0].flag & HA_PACK_KEY)
    {						/* Prefix compression */
1190 1191 1192 1193 1194 1195 1196 1197
      /*
        _ma_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 _ma_seq_search() for the search.
      */
1198
      if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
1199 1200
          (keyinfo->seg->flag & HA_NULL_PART) ||
          keyinfo->seg->charset->mbminlen > 1)
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
        keyinfo->bin_search= _ma_seq_search;
      else
        keyinfo->bin_search= _ma_prefix_search;
      keyinfo->pack_key= _ma_calc_var_pack_key_length;
      keyinfo->store_key= _ma_store_var_pack_key;
    }
    else
    {
      keyinfo->bin_search= _ma_seq_search;
      keyinfo->pack_key= _ma_calc_var_key_length; /* Variable length key */
      keyinfo->store_key= _ma_store_static_key;
    }
  }
  else
  {
    keyinfo->bin_search= _ma_bin_search;
    keyinfo->get_key= _ma_get_static_key;
1218
    keyinfo->skip_key= _ma_skip_static_key;
1219 1220 1221
    keyinfo->pack_key= _ma_calc_static_key_length;
    keyinfo->store_key= _ma_store_static_key;
  }
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233

  /* set keyinfo->write_comp_flag */
  if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
    keyinfo->write_comp_flag=SEARCH_BIGGER; /* Put after same key */
  else if (keyinfo->flag & ( HA_NOSAME | HA_FULLTEXT))
  {
    keyinfo->write_comp_flag= SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
    if (keyinfo->flag & HA_NULL_ARE_EQUAL)
      keyinfo->write_comp_flag|= SEARCH_NULL_ARE_EQUAL;
  }
  else
    keyinfo->write_comp_flag= SEARCH_SAME; /* Keys in rec-pos order */
1234
  keyinfo->write_comp_flag|= SEARCH_INSERT;
1235 1236 1237 1238
  return;
}


1239 1240 1241
/**
   @brief Function to save and store the header in the index file (.MYI)

unknown's avatar
unknown committed
1242
   Operates under MARIA_SHARE::intern_lock if requested.
unknown's avatar
unknown committed
1243
   Sets MARIA_SHARE::MARIA_STATE_INFO::is_of_horizon if transactional table.
unknown's avatar
unknown committed
1244 1245 1246
   Then calls _ma_state_info_write_sub().

   @param  share           table
1247 1248 1249 1250 1251 1252 1253
   @param  pWrite          bitmap: if 1 (MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)
                           is set my_pwrite() is used otherwise my_write();
                           if 2 (MA_STATE_INFO_WRITE_FULL_INFO) is set, info
                           about keys is written (should only be needed
                           after ALTER TABLE ENABLE/DISABLE KEYS, and
                           REPAIR/OPTIMIZE); if 4 (MA_STATE_INFO_WRITE_LOCK)
                           is set, MARIA_SHARE::intern_lock is taken.
unknown's avatar
unknown committed
1254 1255 1256 1257 1258 1259 1260 1261

   @return Operation status
     @retval 0      OK
     @retval 1      Error
*/

uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite)
{
unknown's avatar
unknown committed
1262
  uint res;
1263 1264 1265
  if (share->options & HA_OPTION_READ_ONLY_DATA)
    return 0;

1266
  if (pWrite & MA_STATE_INFO_WRITE_LOCK)
unknown's avatar
unknown committed
1267 1268
    pthread_mutex_lock(&share->intern_lock);
  else if (maria_multi_threaded)
1269
  {
unknown's avatar
unknown committed
1270
    safe_mutex_assert_owner(&share->intern_lock);
1271
  }
1272
  if (share->base.born_transactional && translog_status == TRANSLOG_OK &&
unknown's avatar
unknown committed
1273 1274 1275
      !maria_in_recovery)
  {
    /*
unknown's avatar
unknown committed
1276
      In a recovery, we want to set is_of_horizon to the LSN of the last
unknown's avatar
unknown committed
1277 1278 1279
      record executed by Recovery, not the current EOF of the log (which
      is too new). Recovery does it by itself.
    */
unknown's avatar
unknown committed
1280
    share->state.is_of_horizon= translog_get_horizon();
1281 1282
    DBUG_PRINT("info", ("is_of_horizon set to LSN (%lu,0x%lx)",
                        LSN_IN_PARTS(share->state.is_of_horizon)));
unknown's avatar
unknown committed
1283 1284
  }
  res= _ma_state_info_write_sub(share->kfile.file, &share->state, pWrite);
1285
  if (pWrite & MA_STATE_INFO_WRITE_LOCK)
unknown's avatar
unknown committed
1286
    pthread_mutex_unlock(&share->intern_lock);
1287 1288
  /* If open_count != 0 we have to write the state again at close */
  share->changed= share->state.open_count != 0;
unknown's avatar
unknown committed
1289 1290 1291 1292 1293 1294 1295 1296 1297
  return res;
}


/**
   @brief Function to save and store the header in the index file (.MYI).

   Shortcut to use instead of _ma_state_info_write() when appropriate.

1298 1299
   @param  file            descriptor of the index file to write
   @param  state           state information to write to the file
1300 1301 1302 1303 1304 1305
   @param  pWrite          bitmap: if 1 (MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)
                           is set my_pwrite() is used otherwise my_write();
                           if 2 (MA_STATE_INFO_WRITE_FULL_INFO) is set, info
                           about keys is written (should only be needed
                           after ALTER TABLE ENABLE/DISABLE KEYS, and
                           REPAIR/OPTIMIZE).
1306

1307 1308 1309 1310 1311 1312 1313
   @notes
     For transactional multiuser tables, this function is called
     with intern_lock & translog_lock or when the last thread who
     is using the table is closing it.
     Because of the translog_lock we don't need to have a lock on
     key_del_lock.

1314 1315 1316
   @return Operation status
     @retval 0      OK
     @retval 1      Error
1317 1318
*/

unknown's avatar
unknown committed
1319
uint _ma_state_info_write_sub(File file, MARIA_STATE_INFO *state, uint pWrite)
1320 1321 1322
{
  uchar  buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
  uchar *ptr=buff;
unknown's avatar
unknown committed
1323
  uint	i, keys= (uint) state->header.keys;
unknown's avatar
unknown committed
1324
  size_t res;
1325
  DBUG_ENTER("_ma_state_info_write_sub");
1326 1327 1328 1329 1330

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

  /* open_count must be first because of _ma_mark_file_changed ! */
unknown's avatar
unknown committed
1331
  mi_int2store(ptr,state->open_count);			ptr+= 2;
1332 1333 1334
  /* changed must be second, because of _ma_mark_file_crashed */
  mi_int2store(ptr,state->changed);			ptr+= 2;

1335
  /*
unknown's avatar
unknown committed
1336 1337
    If you change the offset of these LSNs, note that some functions do a
    direct write of them without going through this function.
1338 1339
  */
  lsn_store(ptr, state->create_rename_lsn);		ptr+= LSN_STORE_SIZE;
unknown's avatar
unknown committed
1340
  lsn_store(ptr, state->is_of_horizon);			ptr+= LSN_STORE_SIZE;
unknown's avatar
unknown committed
1341
  lsn_store(ptr, state->skip_redo_lsn);			ptr+= LSN_STORE_SIZE;
unknown's avatar
unknown committed
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
  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->first_bitmap_with_space);	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;
  mi_int8store(ptr,(ulonglong) state->state.checksum);	ptr+= 8;
1353
  mi_int8store(ptr,state->create_trid);			ptr+= 8;
unknown's avatar
unknown committed
1354 1355
  mi_int4store(ptr,state->status);			ptr+= 4;
  mi_int4store(ptr,state->update_count);		ptr+= 4;
1356 1357
  *ptr++= state->sortkey;
  *ptr++= 0;                                    /* Reserved */
unknown's avatar
unknown committed
1358
  ptr+=	state->state_diff_length;
1359 1360 1361

  for (i=0; i < keys; i++)
  {
unknown's avatar
unknown committed
1362
    mi_sizestore(ptr,state->key_root[i]);		ptr+= 8;
1363
  }
unknown's avatar
unknown committed
1364
  mi_sizestore(ptr,state->key_del);	        	ptr+= 8;
1365
  if (pWrite & MA_STATE_INFO_WRITE_FULL_INFO)	/* From maria_chk */
1366 1367
  {
    uint key_parts= mi_uint2korr(state->header.key_parts);
unknown's avatar
unknown committed
1368 1369 1370 1371 1372 1373 1374
    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;
1375 1376 1377
    mi_sizestore(ptr, state->records_at_analyze);	ptr+= 8;
    /* reserve place for some information per key */
    bzero(ptr, keys*4); 				ptr+= keys*4;
1378 1379
    for (i=0 ; i < key_parts ; i++)
    {
1380 1381
      float8store(ptr, state->rec_per_key_part[i]);  	ptr+= 8;
      mi_int4store(ptr, state->nulls_per_key_part[i]);  ptr+= 4;
1382 1383 1384
    }
  }

1385
  res= (pWrite & MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET) ?
unknown's avatar
unknown committed
1386 1387 1388 1389 1390
    my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
              MYF(MY_NABP | MY_THREADSAFE)) :
    my_write(file,  buff, (size_t) (ptr-buff),
             MYF(MY_NABP));
  DBUG_RETURN(res != 0);
1391 1392 1393
}


unknown's avatar
unknown committed
1394
static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state)
1395
{
unknown's avatar
unknown committed
1396
  uint i,keys,key_parts;
1397
  memcpy_fixed(&state->header,ptr, sizeof(state->header));
unknown's avatar
unknown committed
1398 1399 1400 1401 1402
  ptr+= sizeof(state->header);
  keys= (uint) state->header.keys;
  key_parts= mi_uint2korr(state->header.key_parts);

  state->open_count = mi_uint2korr(ptr);		ptr+= 2;
1403
  state->changed= mi_uint2korr(ptr);			ptr+= 2;
1404
  state->create_rename_lsn= lsn_korr(ptr);		ptr+= LSN_STORE_SIZE;
unknown's avatar
unknown committed
1405
  state->is_of_horizon= lsn_korr(ptr);			ptr+= LSN_STORE_SIZE;
unknown's avatar
unknown committed
1406
  state->skip_redo_lsn= lsn_korr(ptr);			ptr+= LSN_STORE_SIZE;
unknown's avatar
unknown committed
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
  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->first_bitmap_with_space= 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;
  state->state.checksum=(ha_checksum) mi_uint8korr(ptr);ptr+= 8;
1418
  state->create_trid= mi_uint8korr(ptr);		ptr+= 8;
unknown's avatar
unknown committed
1419 1420
  state->status = mi_uint4korr(ptr);			ptr+= 4;
  state->update_count=mi_uint4korr(ptr);		ptr+= 4;
1421 1422
  state->sortkey= 					(uint) *ptr++;
  ptr++;                                                /* reserved */
1423 1424 1425 1426 1427

  ptr+= state->state_diff_length;

  for (i=0; i < keys; i++)
  {
unknown's avatar
unknown committed
1428
    state->key_root[i]= mi_sizekorr(ptr);		ptr+= 8;
1429
  }
unknown's avatar
unknown committed
1430 1431 1432 1433 1434 1435 1436 1437
  state->key_del= 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;
1438 1439
  state->records_at_analyze=    mi_sizekorr(ptr);	ptr+= 8;
  ptr+= keys * 4;                               /* Skip reserved bytes */
1440 1441
  for (i=0 ; i < key_parts ; i++)
  {
1442 1443
    float8get(state->rec_per_key_part[i], ptr);		ptr+= 8;
    state->nulls_per_key_part[i]= mi_uint4korr(ptr);	ptr+= 4;
1444 1445 1446 1447 1448
  }
  return ptr;
}


unknown's avatar
unknown committed
1449 1450 1451
/**
   @brief Fills the state by reading its copy on disk.

unknown's avatar
unknown committed
1452 1453 1454
   Should not be called for transactional tables, as their state on disk is
   rarely current and so is often misleading for a reader.
   Does nothing in single user mode.
unknown's avatar
unknown committed
1455 1456 1457 1458 1459

   @param  file            file to read from
   @param  state           state which will be filled
*/

1460 1461
uint _ma_state_info_read_dsk(File file __attribute__((unused)),
                             MARIA_STATE_INFO *state __attribute__((unused)))
1462
{
Michael Widenius's avatar
Michael Widenius committed
1463
#ifdef MARIA_EXTERNAL_LOCKING
1464
  uchar	buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
1465

unknown's avatar
unknown committed
1466 1467
  /* trick to detect transactional tables */
  DBUG_ASSERT(state->create_rename_lsn == LSN_IMPOSSIBLE);
1468 1469
  if (!maria_single_user)
  {
1470
    if (my_pread(file, buff, state->state_length, 0L, MYF(MY_NABP)))
1471
      return 1;
unknown's avatar
unknown committed
1472
    _ma_state_info_read(buff, state);
1473
  }
Michael Widenius's avatar
Michael Widenius committed
1474
#endif
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
  return 0;
}


/****************************************************************************
**  store and read of MARIA_BASE_INFO
****************************************************************************/

uint _ma_base_info_write(File file, MARIA_BASE_INFO *base)
{
  uchar buff[MARIA_BASE_INFO_SIZE], *ptr=buff;

1487 1488
  bmove(ptr, maria_uuid, MY_UUID_SIZE);
  ptr+= MY_UUID_SIZE;
unknown's avatar
unknown committed
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
  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_int2store(ptr,base->fields);			ptr+= 2;
  mi_int2store(ptr,base->fixed_not_null_fields);	ptr+= 2;
  mi_int2store(ptr,base->fixed_not_null_fields_length);	ptr+= 2;
  mi_int2store(ptr,base->max_field_lengths);		ptr+= 2;
  mi_int2store(ptr,base->pack_fields);			ptr+= 2;
1505
  mi_int2store(ptr,base->extra_options)			ptr+= 2;
unknown's avatar
unknown committed
1506 1507 1508
  mi_int2store(ptr,base->null_bytes);                   ptr+= 2;
  mi_int2store(ptr,base->original_null_bytes);	        ptr+= 2;
  mi_int2store(ptr,base->field_offsets);	        ptr+= 2;
1509
  mi_int2store(ptr,0);				        ptr+= 2; /* reserved */
unknown's avatar
unknown committed
1510 1511 1512 1513 1514
  mi_int2store(ptr,base->block_size);	        	ptr+= 2;
  *ptr++= base->rec_reflength;
  *ptr++= base->key_reflength;
  *ptr++= base->keys;
  *ptr++= base->auto_key;
unknown's avatar
unknown committed
1515
  *ptr++= base->born_transactional;
unknown's avatar
unknown committed
1516 1517 1518 1519 1520 1521
  *ptr++= 0;                                    /* Reserved */
  mi_int2store(ptr,base->pack_bytes);			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;
1522
  *ptr++= base->extra_alloc_procent;
unknown's avatar
unknown committed
1523 1524
  bzero(ptr,16);					ptr+= 16; /* extra */
  DBUG_ASSERT((ptr - buff) == MARIA_BASE_INFO_SIZE);
1525
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1526 1527 1528
}


unknown's avatar
unknown committed
1529
static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base)
1530
{
1531
  bmove(base->uuid, ptr, MY_UUID_SIZE);                 ptr+= MY_UUID_SIZE;
unknown's avatar
unknown committed
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
  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_uint2korr(ptr);			ptr+= 2;
  base->fixed_not_null_fields= mi_uint2korr(ptr);       ptr+= 2;
  base->fixed_not_null_fields_length= mi_uint2korr(ptr);ptr+= 2;
  base->max_field_lengths= mi_uint2korr(ptr);	        ptr+= 2;
  base->pack_fields= mi_uint2korr(ptr);			ptr+= 2;
1548
  base->extra_options= mi_uint2korr(ptr);		ptr+= 2;
unknown's avatar
unknown committed
1549 1550 1551
  base->null_bytes= mi_uint2korr(ptr);			ptr+= 2;
  base->original_null_bytes= mi_uint2korr(ptr);		ptr+= 2;
  base->field_offsets= mi_uint2korr(ptr);		ptr+= 2;
1552
                                                        ptr+= 2;
unknown's avatar
unknown committed
1553 1554 1555 1556 1557 1558
  base->block_size= mi_uint2korr(ptr);			ptr+= 2;

  base->rec_reflength= *ptr++;
  base->key_reflength= *ptr++;
  base->keys=	       *ptr++;
  base->auto_key=      *ptr++;
unknown's avatar
unknown committed
1559
  base->born_transactional= *ptr++;
unknown's avatar
unknown committed
1560 1561 1562 1563 1564 1565 1566 1567
  ptr++;
  base->pack_bytes= 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++;
  ptr+= 16;
1568 1569 1570 1571 1572 1573 1574
  return ptr;
}

/*--------------------------------------------------------------------------
  maria_keydef
---------------------------------------------------------------------------*/

1575
my_bool _ma_keydef_write(File file, MARIA_KEYDEF *keydef)
1576 1577 1578 1579
{
  uchar buff[MARIA_KEYDEF_SIZE];
  uchar *ptr=buff;

unknown's avatar
unknown committed
1580 1581 1582 1583 1584 1585 1586
  *ptr++= (uchar) keydef->keysegs;
  *ptr++= keydef->key_alg;			/* Rtree or Btree */
  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;
1587
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1588 1589
}

1590
uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef)
1591 1592 1593 1594
{
   keydef->keysegs	= (uint) *ptr++;
   keydef->key_alg	= *ptr++;		/* Rtree or Btree */

unknown's avatar
unknown committed
1595 1596 1597 1598 1599
   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;
1600 1601
   keydef->version	= 0;			/* Not saved */
   keydef->parser       = &ft_default_parser;
1602
   keydef->ftkey_nr     = 0;
1603 1604 1605 1606 1607 1608 1609
   return ptr;
}

/***************************************************************************
**  maria_keyseg
***************************************************************************/

1610
my_bool _ma_keyseg_write(File file, const HA_KEYSEG *keyseg)
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
{
  uchar buff[HA_KEYSEG_SIZE];
  uchar *ptr=buff;
  ulong pos;

  *ptr++= keyseg->type;
  *ptr++= keyseg->language;
  *ptr++= keyseg->null_bit;
  *ptr++= keyseg->bit_start;
  *ptr++= keyseg->bit_end;
  *ptr++= keyseg->bit_length;
unknown's avatar
unknown committed
1622 1623 1624
  mi_int2store(ptr,keyseg->flag);	ptr+= 2;
  mi_int2store(ptr,keyseg->length);	ptr+= 2;
  mi_int4store(ptr,keyseg->start);	ptr+= 4;
1625 1626 1627 1628
  pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
  mi_int4store(ptr, pos);
  ptr+=4;

1629
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1630 1631 1632
}


1633
uchar *_ma_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
1634 1635 1636 1637 1638 1639 1640
{
   keyseg->type		= *ptr++;
   keyseg->language	= *ptr++;
   keyseg->null_bit	= *ptr++;
   keyseg->bit_start	= *ptr++;
   keyseg->bit_end	= *ptr++;
   keyseg->bit_length   = *ptr++;
unknown's avatar
unknown committed
1641 1642 1643 1644
   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;
1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
   keyseg->charset=0;				/* Will be filled in later */
   if (keyseg->null_bit)
     keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
   else
   {
     keyseg->bit_pos= (uint16)keyseg->null_pos;
     keyseg->null_pos= 0;
   }
   return ptr;
}

/*--------------------------------------------------------------------------
  maria_uniquedef
---------------------------------------------------------------------------*/

1660
my_bool _ma_uniquedef_write(File file, MARIA_UNIQUEDEF *def)
1661 1662 1663 1664 1665 1666 1667 1668
{
  uchar buff[MARIA_UNIQUEDEF_SIZE];
  uchar *ptr=buff;

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

1669
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1670 1671
}

1672
uchar *_ma_uniquedef_read(uchar *ptr, MARIA_UNIQUEDEF *def)
1673 1674 1675 1676
{
   def->keysegs = mi_uint2korr(ptr);
   def->key	= ptr[2];
   def->null_are_equal=ptr[3];
unknown's avatar
unknown committed
1677
   return ptr+4;				/* 1 extra uchar */
1678 1679 1680 1681 1682 1683
}

/***************************************************************************
**  MARIA_COLUMNDEF
***************************************************************************/

1684
my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef)
1685 1686 1687
{
  uchar buff[MARIA_COLUMNDEF_SIZE];
  uchar *ptr=buff;
1688 1689
  uint low_offset=  (uint) (columndef->offset & 0xffff);
  uint high_offset= (uint) (columndef->offset >> 16);
1690

1691
  mi_int2store(ptr,(ulong) columndef->column_nr); ptr+= 2;
1692
  mi_int2store(ptr, low_offset);		  ptr+= 2;
1693 1694 1695 1696 1697 1698
  mi_int2store(ptr,columndef->type);		  ptr+= 2;
  mi_int2store(ptr,columndef->length);		  ptr+= 2;
  mi_int2store(ptr,columndef->fill_length);	  ptr+= 2;
  mi_int2store(ptr,columndef->null_pos);	  ptr+= 2;
  mi_int2store(ptr,columndef->empty_pos);	  ptr+= 2;

1699 1700
  (*ptr++)= columndef->null_bit;
  (*ptr++)= columndef->empty_bit;
1701 1702
  mi_int2store(ptr, high_offset);                 ptr+= 2;
  ptr[0]= ptr[1]= 0;                              ptr+= 2;  /* For future */
1703
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1704 1705
}

1706
uchar *_ma_columndef_read(uchar *ptr, MARIA_COLUMNDEF *columndef)
1707
{
1708
  uint high_offset;
1709
  columndef->column_nr= mi_uint2korr(ptr);      ptr+= 2;
1710
  columndef->offset= mi_uint2korr(ptr);         ptr+= 2;
1711 1712 1713 1714 1715 1716 1717
  columndef->type=   mi_sint2korr(ptr);		ptr+= 2;
  columndef->length= mi_uint2korr(ptr);		ptr+= 2;
  columndef->fill_length= mi_uint2korr(ptr);	ptr+= 2;
  columndef->null_pos= mi_uint2korr(ptr);	ptr+= 2;
  columndef->empty_pos= mi_uint2korr(ptr);	ptr+= 2;
  columndef->null_bit=  (uint8) *ptr++;
  columndef->empty_bit= (uint8) *ptr++;
1718 1719 1720
  high_offset=       mi_uint2korr(ptr);         ptr+= 2;  
  columndef->offset|= ((ulong) high_offset << 16);
  ptr+= 2;
unknown's avatar
unknown committed
1721
  return ptr;
1722 1723
}

1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748
my_bool _ma_column_nr_write(File file, uint16 *offsets, uint columns)
{
  uchar *buff, *ptr, *end;
  size_t size= columns*2;
  my_bool res;

  if (!(buff= (uchar*) my_alloca(size)))
    return 1;
  for (ptr= buff, end= ptr + size; ptr < end ; ptr+= 2, offsets++)
    int2store(ptr, *offsets);
  res= my_write(file, buff, size, MYF(MY_NABP)) != 0;
  my_afree(buff);
  return res;
}


uchar *_ma_column_nr_read(uchar *ptr, uint16 *offsets, uint columns)
{
  uchar *end;
  size_t size= columns*2;
  for (end= ptr + size; ptr < end ; ptr+=2, offsets++)
    *offsets= uint2korr(ptr);
  return ptr;
}

1749 1750 1751 1752 1753 1754 1755
/**
   @brief Set callbacks for data pages

   @note
   We don't use pagecache_file_init here, as we want to keep the
   code readable
*/
1756

1757 1758
void _ma_set_data_pagecache_callbacks(PAGECACHE_FILE *file,
                                      MARIA_SHARE *share)
1759
{
1760 1761 1762
  file->callback_data= (uchar*) share;
  file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */

1763
  if (share->temporary)
1764 1765 1766 1767
  {
    file->read_callback=  &maria_page_crc_check_none;
    file->write_callback= &maria_page_filler_set_none;
  }
1768
  else
1769 1770 1771 1772 1773 1774 1775 1776 1777
  {
    file->read_callback=  &maria_page_crc_check_data;
    if (share->options & HA_OPTION_PAGE_CHECKSUM)
      file->write_callback= &maria_page_crc_set_normal;
    else
      file->write_callback= &maria_page_filler_set_normal;
    if (share->now_transactional)
      file->flush_log_callback= maria_flush_log_for_page;
  }
1778 1779 1780
}


1781 1782 1783 1784 1785 1786 1787 1788 1789 1790
/**
   @brief Set callbacks for index pages

   @note
   We don't use pagecache_file_init here, as we want to keep the
   code readable
*/

void _ma_set_index_pagecache_callbacks(PAGECACHE_FILE *file,
                                       MARIA_SHARE *share)
1791
{
1792 1793 1794 1795
  file->callback_data= (uchar*) share;
  file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
  file->write_fail= maria_page_write_failure;

1796
  if (share->temporary)
1797 1798 1799 1800
  {
    file->read_callback=  &maria_page_crc_check_none;
    file->write_callback= &maria_page_filler_set_none;
  }
1801
  else
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
  {
    file->read_callback=  &maria_page_crc_check_index;
    if (share->options & HA_OPTION_PAGE_CHECKSUM)
      file->write_callback= &maria_page_crc_set_index;
    else
      file->write_callback= &maria_page_filler_set_normal;

    if (share->now_transactional)
      file->flush_log_callback= maria_flush_log_for_page;
  }
1812 1813 1814
}


1815
/**************************************************************************
unknown's avatar
unknown committed
1816 1817 1818
 Open data file
  We can't use dup() here as the data file descriptors need to have different
  active seek-positions.
1819

unknown's avatar
unknown committed
1820 1821
  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.
1822 1823
*************************************************************************/

1824
int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share, const char *org_name,
unknown's avatar
unknown committed
1825
                      File file_to_dup __attribute__((unused)))
1826
{
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844
  char *data_name= share->data_file_name.str;
  char real_data_name[FN_REFLEN];

  if (org_name)
  {
    fn_format(real_data_name, org_name, "", MARIA_NAME_DEXT, 4);
    if (my_is_symlink(real_data_name))
    {
      if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
          (*maria_test_invalid_symlink)(real_data_name))
      {
        my_errno= HA_WRONG_CREATE_OPTION;
        return 1;
      }
      data_name= real_data_name;
    }
  }

1845
  info->dfile.file= share->bitmap.file.file=
1846
    my_open(data_name, share->mode | O_SHARE, MYF(MY_WME));
unknown's avatar
unknown committed
1847
  return info->dfile.file >= 0 ? 0 : 1;
1848 1849 1850 1851 1852
}


int _ma_open_keyfile(MARIA_SHARE *share)
{
unknown's avatar
unknown committed
1853 1854 1855 1856 1857
  /*
    Modifications to share->kfile should be under intern_lock to protect
    against a concurrent checkpoint.
  */
  pthread_mutex_lock(&share->intern_lock);
1858
  share->kfile.file= my_open(share->unique_file_name.str,
unknown's avatar
unknown committed
1859 1860 1861 1862
                             share->mode | O_SHARE,
                             MYF(MY_WME));
  pthread_mutex_unlock(&share->intern_lock);
  return (share->kfile.file < 0);
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911
}


/*
  Disable all indexes.

  SYNOPSIS
    maria_disable_indexes()
    info        A pointer to the MARIA storage engine MARIA_HA struct.

  DESCRIPTION
    Disable all indexes.

  RETURN
    0  ok
*/

int maria_disable_indexes(MARIA_HA *info)
{
  MARIA_SHARE *share= info->s;

  maria_clear_all_keys_active(share->state.key_map);
  return 0;
}


/*
  Enable all indexes

  SYNOPSIS
    maria_enable_indexes()
    info        A pointer to the MARIA storage engine MARIA_HA struct.

  DESCRIPTION
    Enable all indexes. The indexes might have been disabled
    by maria_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 maria_enable_indexes(MARIA_HA *info)
{
  int error= 0;
  MARIA_SHARE *share= info->s;
1912
  DBUG_ENTER("maria_enable_indexes");
1913

unknown's avatar
unknown committed
1914 1915
  if ((share->state.state.data_file_length !=
       (share->data_file_type == BLOCK_RECORD ? share->block_size : 0)) ||
1916 1917
      (share->state.state.key_file_length != share->base.keystart))
  {
1918 1919 1920
    DBUG_PRINT("error", ("data_file_length: %lu  key_file_length: %lu",
                         (ulong) share->state.state.data_file_length,
                         (ulong) share->state.state.key_file_length));
Michael Widenius's avatar
Michael Widenius committed
1921
    _ma_set_fatal_error(share, HA_ERR_CRASHED);
1922 1923 1924 1925
    error= HA_ERR_CRASHED;
  }
  else
    maria_set_all_keys_active(share->state.key_map, share->base.keys);
1926
  DBUG_RETURN(error);
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
}


/*
  Test if indexes are disabled.

  SYNOPSIS
    maria_indexes_are_disabled()
    info        A pointer to the MARIA storage engine MARIA_HA struct.

  DESCRIPTION
    Test if indexes are disabled.

  RETURN
    0  indexes are not disabled
    1  all indexes are disabled
1943
    2  non-unique indexes are disabled
1944 1945 1946 1947 1948 1949
*/

int maria_indexes_are_disabled(MARIA_HA *info)
{
  MARIA_SHARE *share= info->s;

1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
  /*
    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 ||
      (maria_is_all_keys_active(share->state.key_map, share->base.keys)))
    return 0;

  /* All are disabled */
  if (maria_is_any_key_active(share->state.key_map))
    return 1;

  /*
    We have keys. Some enabled, some disabled.
    Don't check for any non-unique disabled but return directly 2
  */
  return 2;
1968
}
unknown's avatar
unknown committed
1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990


static my_bool maria_scan_init_dummy(MARIA_HA *info __attribute__((unused)))
{
  return 0;
}

static void maria_scan_end_dummy(MARIA_HA *info __attribute__((unused)))
{
}

static my_bool maria_once_init_dummy(MARIA_SHARE *share
                                     __attribute__((unused)),
                                     File dfile __attribute__((unused)))
{
  return 0;
}

static my_bool maria_once_end_dummy(MARIA_SHARE *share __attribute__((unused)))
{
  return 0;
}