~jlukas79/+junk/mysql-server

« back to all changes in this revision

Viewing changes to storage/maria/ma_open.c

manual merge 6.0-main --> 6.0-bka-review

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   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
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/* open a isam-database */
 
17
 
 
18
#include "ma_fulltext.h"
 
19
#include "ma_sp_defs.h"
 
20
#include "ma_rt_index.h"
 
21
#include "ma_blockrec.h"
 
22
#include <m_ctype.h>
 
23
 
 
24
#if defined(MSDOS) || defined(__WIN__)
 
25
#ifdef __WIN__
 
26
#include <fcntl.h>
 
27
#else
 
28
#include <process.h>                    /* Prototype for getpid */
 
29
#endif
 
30
#endif
 
31
 
 
32
static void setup_key_functions(MARIA_KEYDEF *keyinfo);
 
33
static my_bool maria_scan_init_dummy(MARIA_HA *info);
 
34
static void maria_scan_end_dummy(MARIA_HA *info);
 
35
static my_bool maria_once_init_dummy(MARIA_SHARE *, File);
 
36
static my_bool maria_once_end_dummy(MARIA_SHARE *);
 
37
static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base);
 
38
static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state);
 
39
 
 
40
#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
 
41
                                        pos+=size;}
 
42
 
 
43
 
 
44
#define disk_pos_assert(pos, end_pos) \
 
45
if (pos > end_pos)             \
 
46
{                              \
 
47
  my_errno=HA_ERR_CRASHED;     \
 
48
  goto err;                    \
 
49
}
 
50
 
 
51
 
 
52
/******************************************************************************
 
53
** Return the shared struct if the table is already open.
 
54
** In MySQL the server will handle version issues.
 
55
******************************************************************************/
 
56
 
 
57
MARIA_HA *_ma_test_if_reopen(const char *filename)
 
58
{
 
59
  LIST *pos;
 
60
 
 
61
  for (pos=maria_open_list ; pos ; pos=pos->next)
 
62
  {
 
63
    MARIA_HA *info=(MARIA_HA*) pos->data;
 
64
    MARIA_SHARE *share= info->s;
 
65
    if (!strcmp(share->unique_file_name,filename) && share->last_version)
 
66
      return info;
 
67
  }
 
68
  return 0;
 
69
}
 
70
 
 
71
 
 
72
/*
 
73
  Open a new instance of an already opened Maria table
 
74
 
 
75
  SYNOPSIS
 
76
    maria_clone_internal()
 
77
    share       Share of already open table
 
78
    mode        Mode of table (O_RDONLY | O_RDWR)
 
79
    data_file   Filedescriptor of data file to use < 0 if one should open
 
80
                open it.
 
81
 
 
82
 RETURN
 
83
    #   Maria handler
 
84
    0   Error
 
85
*/
 
86
 
 
87
 
 
88
static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode,
 
89
                                      File data_file)
 
90
{
 
91
  int save_errno;
 
92
  uint errpos;
 
93
  MARIA_HA info,*m_info;
 
94
  my_bitmap_map *changed_fields_bitmap;
 
95
  DBUG_ENTER("maria_clone_internal");
 
96
 
 
97
  errpos= 0;
 
98
  bzero((uchar*) &info,sizeof(info));
 
99
 
 
100
  if (mode == O_RDWR && share->mode == O_RDONLY)
 
101
  {
 
102
    my_errno=EACCES;                            /* Can't open in write mode */
 
103
    goto err;
 
104
  }
 
105
  if (data_file >= 0)
 
106
    info.dfile.file= data_file;
 
107
  else if (_ma_open_datafile(&info, share, -1))
 
108
    goto err;
 
109
  errpos= 5;
 
110
 
 
111
  /* alloc and set up private structure parts */
 
112
  if (!my_multi_malloc(MY_WME,
 
113
                       &m_info,sizeof(MARIA_HA),
 
114
                       &info.blobs,sizeof(MARIA_BLOB)*share->base.blobs,
 
115
                       &info.buff,(share->base.max_key_block_length*2+
 
116
                                   share->base.max_key_length),
 
117
                       &info.lastkey_buff,share->base.max_key_length*2+1,
 
118
                       &info.first_mbr_key, share->base.max_key_length,
 
119
                       &info.maria_rtree_recursion_state,
 
120
                       share->have_rtree ? 1024 : 0,
 
121
                       &changed_fields_bitmap,
 
122
                       bitmap_buffer_size(share->base.fields),
 
123
                       NullS))
 
124
    goto err;
 
125
  errpos= 6;
 
126
 
 
127
  memcpy(info.blobs,share->blobs,sizeof(MARIA_BLOB)*share->base.blobs);
 
128
  info.lastkey_buff2= info.lastkey_buff + share->base.max_key_length;
 
129
  info.last_key.data= info.lastkey_buff;
 
130
 
 
131
  info.s=share;
 
132
  info.cur_row.lastpos= HA_OFFSET_ERROR;
 
133
  info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
 
134
  info.opt_flag=READ_CHECK_USED;
 
135
  info.this_unique= (ulong) info.dfile.file; /* Uniq number in process */
 
136
#ifdef EXTERNAL_LOCKING
 
137
  if (share->data_file_type == COMPRESSED_RECORD)
 
138
    info.this_unique= share->state.unique;
 
139
  info.this_loop=0;                             /* Update counter */
 
140
  info.last_unique= share->state.unique;
 
141
  info.last_loop=   share->state.update_count;
 
142
#endif
 
143
  info.errkey= -1;
 
144
  info.page_changed=1;
 
145
  info.keyread_buff= info.buff + share->base.max_key_block_length;
 
146
 
 
147
  info.lock_type= F_UNLCK;
 
148
  if (share->options & HA_OPTION_TMP_TABLE)
 
149
    info.lock_type= F_WRLCK;
 
150
 
 
151
  _ma_set_data_pagecache_callbacks(&info.dfile, share);
 
152
  bitmap_init(&info.changed_fields, changed_fields_bitmap,
 
153
              share->base.fields, 0);
 
154
  if ((*share->init)(&info))
 
155
    goto err;
 
156
 
 
157
  /* The following should be big enough for all pinning purposes */
 
158
  if (my_init_dynamic_array(&info.pinned_pages,
 
159
                            sizeof(MARIA_PINNED_PAGE),
 
160
                            max(share->base.blobs*2 + 4,
 
161
                                MARIA_MAX_TREE_LEVELS*3), 16))
 
162
    goto err;
 
163
 
 
164
 
 
165
  pthread_mutex_lock(&share->intern_lock);
 
166
  info.read_record= share->read_record;
 
167
  share->reopen++;
 
168
  share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
 
169
  if (share->options & HA_OPTION_READ_ONLY_DATA)
 
170
  {
 
171
    info.lock_type=F_RDLCK;
 
172
    share->r_locks++;
 
173
    share->tot_locks++;
 
174
  }
 
175
  if ((share->options & HA_OPTION_DELAY_KEY_WRITE) &&
 
176
      maria_delay_key_write)
 
177
    share->delay_key_write=1;
 
178
 
 
179
  if (!share->base.born_transactional)   /* For transactional ones ... */
 
180
  {
 
181
    info.trn= &dummy_transaction_object; /* ... force crash if no trn given */
 
182
    info.state= &share->state.state;    /* Change global values by default */
 
183
  }
 
184
  else
 
185
  {
 
186
    info.state=  &share->state.common;
 
187
    *info.state= share->state.state;            /* Initial values */
 
188
  }
 
189
  info.state_start= info.state;                 /* Initial values */
 
190
 
 
191
  pthread_mutex_unlock(&share->intern_lock);
 
192
 
 
193
  /* Allocate buffer for one record */
 
194
  /* prerequisites: info->rec_buffer == 0 && info->rec_buff_size == 0 */
 
195
  if (_ma_alloc_buffer(&info.rec_buff, &info.rec_buff_size,
 
196
                       share->base.default_rec_buff_size))
 
197
    goto err;
 
198
 
 
199
  bzero(info.rec_buff, share->base.default_rec_buff_size);
 
200
 
 
201
  *m_info=info;
 
202
#ifdef THREAD
 
203
  thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
 
204
#endif
 
205
  m_info->open_list.data=(void*) m_info;
 
206
  maria_open_list=list_add(maria_open_list,&m_info->open_list);
 
207
 
 
208
  DBUG_RETURN(m_info);
 
209
 
 
210
err:
 
211
  save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
 
212
  if ((save_errno == HA_ERR_CRASHED) ||
 
213
      (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
 
214
      (save_errno == HA_ERR_CRASHED_ON_REPAIR))
 
215
    _ma_report_error(save_errno, share->open_file_name);
 
216
  switch (errpos) {
 
217
  case 6:
 
218
    (*share->end)(&info);
 
219
    delete_dynamic(&info.pinned_pages);
 
220
    my_free(m_info, MYF(0));
 
221
    /* fall through */
 
222
  case 5:
 
223
    if (data_file < 0)
 
224
      (void)(my_close(info.dfile.file, MYF(0)));
 
225
    break;
 
226
  }
 
227
  my_errno=save_errno;
 
228
  DBUG_RETURN (NULL);
 
229
} /* maria_clone_internal */
 
230
 
 
231
 
 
232
/* Make a clone of a maria table */
 
233
 
 
234
MARIA_HA *maria_clone(MARIA_SHARE *share, int mode)
 
235
{
 
236
  MARIA_HA *new_info;
 
237
  pthread_mutex_lock(&THR_LOCK_maria);
 
238
  new_info= maria_clone_internal(share, mode,
 
239
                                 share->data_file_type == BLOCK_RECORD ?
 
240
                                 share->bitmap.file.file : -1);
 
241
  pthread_mutex_unlock(&THR_LOCK_maria);
 
242
  return new_info;
 
243
}
 
244
 
 
245
 
 
246
/******************************************************************************
 
247
  open a MARIA table
 
248
 
 
249
  See my_base.h for the handle_locking argument
 
250
  if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
 
251
  is marked crashed or if we are not using locking and the table doesn't
 
252
  have an open count of 0.
 
253
******************************************************************************/
 
254
 
 
255
MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
 
256
{
 
257
  int kfile,open_mode,save_errno;
 
258
  uint i,j,len,errpos,head_length,base_pos,info_length,keys,
 
259
    key_parts,unique_key_parts,fulltext_keys,uniques;
 
260
  char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
 
261
       data_name[FN_REFLEN];
 
262
  uchar *disk_cache, *disk_pos, *end_pos;
 
263
  MARIA_HA info,*m_info,*old_info;
 
264
  MARIA_SHARE share_buff,*share;
 
265
  double rec_per_key_part[HA_MAX_POSSIBLE_KEY*HA_MAX_KEY_SEG];
 
266
  ulong  nulls_per_key_part[HA_MAX_POSSIBLE_KEY*HA_MAX_KEY_SEG];
 
267
  my_off_t key_root[HA_MAX_POSSIBLE_KEY];
 
268
  ulonglong max_key_file_length, max_data_file_length;
 
269
  my_bool versioning= 1;
 
270
  File data_file= -1;
 
271
  DBUG_ENTER("maria_open");
 
272
 
 
273
  LINT_INIT(m_info);
 
274
  kfile= -1;
 
275
  errpos= 0;
 
276
  head_length=sizeof(share_buff.state.header);
 
277
  bzero((uchar*) &info,sizeof(info));
 
278
 
 
279
  my_realpath(name_buff, fn_format(org_name,name,"",MARIA_NAME_IEXT,
 
280
                                   MY_UNPACK_FILENAME),MYF(0));
 
281
  pthread_mutex_lock(&THR_LOCK_maria);
 
282
  old_info= 0;
 
283
  if ((open_flags & HA_OPEN_COPY) ||
 
284
      !(old_info=_ma_test_if_reopen(name_buff)))
 
285
  {
 
286
    share= &share_buff;
 
287
    bzero((uchar*) &share_buff,sizeof(share_buff));
 
288
    share_buff.state.rec_per_key_part=   rec_per_key_part;
 
289
    share_buff.state.nulls_per_key_part= nulls_per_key_part;
 
290
    share_buff.state.key_root=key_root;
 
291
    share_buff.pagecache= multi_pagecache_search((uchar*) name_buff,
 
292
                                                 (uint) strlen(name_buff),
 
293
                                                 maria_pagecache);
 
294
 
 
295
    DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_open",
 
296
                    if (strstr(name, "/t1"))
 
297
                    {
 
298
                      my_errno= HA_ERR_CRASHED;
 
299
                      goto err;
 
300
                    });
 
301
    if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
 
302
    {
 
303
      if ((errno != EROFS && errno != EACCES) ||
 
304
          mode != O_RDONLY ||
 
305
          (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
 
306
        goto err;
 
307
    }
 
308
    share->mode=open_mode;
 
309
    errpos= 1;
 
310
    if (my_pread(kfile,share->state.header.file_version, head_length, 0,
 
311
                 MYF(MY_NABP)))
 
312
    {
 
313
      my_errno= HA_ERR_NOT_A_TABLE;
 
314
      goto err;
 
315
    }
 
316
    if (memcmp((uchar*) share->state.header.file_version,
 
317
               (uchar*) maria_file_magic, 4))
 
318
    {
 
319
      DBUG_PRINT("error",("Wrong header in %s",name_buff));
 
320
      DBUG_DUMP("error_dump", share->state.header.file_version,
 
321
                head_length);
 
322
      my_errno=HA_ERR_NOT_A_TABLE;
 
323
      goto err;
 
324
    }
 
325
    share->options= mi_uint2korr(share->state.header.options);
 
326
    if (share->options &
 
327
        ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
 
328
          HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
 
329
          HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
 
330
          HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
 
331
          HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS |
 
332
          HA_OPTION_PAGE_CHECKSUM))
 
333
    {
 
334
      DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
 
335
      my_errno=HA_ERR_NEW_FILE;
 
336
      goto err;
 
337
    }
 
338
    if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
 
339
        ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
 
340
    {
 
341
      DBUG_PRINT("error", ("table cannot be opened from non-sql layer"));
 
342
      my_errno= HA_ERR_UNSUPPORTED;
 
343
      goto err;
 
344
    }
 
345
    /* Don't call realpath() if the name can't be a link */
 
346
    if (!strcmp(name_buff, org_name) ||
 
347
        my_readlink(index_name, org_name, MYF(0)) == -1)
 
348
      (void) strmov(index_name, org_name);
 
349
    *strrchr(org_name, '.')= '\0';
 
350
    (void) fn_format(data_name,org_name,"",MARIA_NAME_DEXT,
 
351
                     MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
 
352
 
 
353
    info_length=mi_uint2korr(share->state.header.header_length);
 
354
    base_pos= mi_uint2korr(share->state.header.base_pos);
 
355
    if (!(disk_cache= (uchar*) my_alloca(info_length+128)))
 
356
    {
 
357
      my_errno=ENOMEM;
 
358
      goto err;
 
359
    }
 
360
    end_pos=disk_cache+info_length;
 
361
    errpos= 3;
 
362
    if (my_pread(kfile, disk_cache, info_length, 0L, MYF(MY_NABP)))
 
363
    {
 
364
      my_errno=HA_ERR_CRASHED;
 
365
      goto err;
 
366
    }
 
367
    len=mi_uint2korr(share->state.header.state_info_length);
 
368
    keys=    (uint) share->state.header.keys;
 
369
    uniques= (uint) share->state.header.uniques;
 
370
    fulltext_keys= (uint) share->state.header.fulltext_keys;
 
371
    key_parts= mi_uint2korr(share->state.header.key_parts);
 
372
    unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
 
373
    if (len != MARIA_STATE_INFO_SIZE)
 
374
    {
 
375
      DBUG_PRINT("warning",
 
376
                 ("saved_state_info_length: %d  state_info_length: %d",
 
377
                  len,MARIA_STATE_INFO_SIZE));
 
378
    }
 
379
    share->state_diff_length=len-MARIA_STATE_INFO_SIZE;
 
380
 
 
381
    _ma_state_info_read(disk_cache, &share->state);
 
382
    len= mi_uint2korr(share->state.header.base_info_length);
 
383
    if (len != MARIA_BASE_INFO_SIZE)
 
384
    {
 
385
      DBUG_PRINT("warning",("saved_base_info_length: %d  base_info_length: %d",
 
386
                            len,MARIA_BASE_INFO_SIZE));
 
387
    }
 
388
    disk_pos= _ma_base_info_read(disk_cache + base_pos, &share->base);
 
389
    share->state.state_length=base_pos;
 
390
 
 
391
    if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
 
392
        ((share->state.changed & STATE_CRASHED) ||
 
393
         ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
 
394
          (my_disable_locking && share->state.open_count))))
 
395
    {
 
396
      DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u  "
 
397
                          "changed: %u  open_count: %u  !locking: %d",
 
398
                          open_flags, share->state.changed,
 
399
                          share->state.open_count, my_disable_locking));
 
400
      my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
 
401
                HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
 
402
      goto err;
 
403
    }
 
404
 
 
405
    /*
 
406
      We can ignore testing uuid if STATE_NOT_MOVABLE is set, as in this
 
407
      case the uuid will be set in _ma_mark_file_changed()
 
408
    */
 
409
    if ((share->state.changed & STATE_NOT_MOVABLE) &&
 
410
        share->base.born_transactional &&
 
411
        ((!(open_flags & HA_OPEN_IGNORE_MOVED_STATE) &&
 
412
          memcmp(share->base.uuid, maria_uuid, MY_UUID_SIZE)) ||
 
413
         share->state.create_trid > trnman_get_max_trid()))
 
414
    {
 
415
      if (open_flags & HA_OPEN_FOR_REPAIR)
 
416
        share->state.changed|= STATE_MOVED;
 
417
      else
 
418
      {
 
419
        my_errno= HA_ERR_OLD_FILE;
 
420
        goto err;
 
421
      }
 
422
    }
 
423
 
 
424
    /* sanity check */
 
425
    if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
 
426
    {
 
427
      my_errno=HA_ERR_CRASHED;
 
428
      goto err;
 
429
    }
 
430
 
 
431
    key_parts+=fulltext_keys*FT_SEGS;
 
432
    if (share->base.max_key_length > maria_max_key_length() ||
 
433
        keys > MARIA_MAX_KEY || key_parts > MARIA_MAX_KEY * HA_MAX_KEY_SEG)
 
434
    {
 
435
      DBUG_PRINT("error",("Wrong key info:  Max_key_length: %d  keys: %d  key_parts: %d", share->base.max_key_length, keys, key_parts));
 
436
      my_errno=HA_ERR_UNSUPPORTED;
 
437
      goto err;
 
438
    }
 
439
 
 
440
    /* Ensure we have space in the key buffer for transaction id's */
 
441
    if (share->base.born_transactional)
 
442
      share->base.max_key_length= ALIGN_SIZE(share->base.max_key_length +
 
443
                                             MAX_PACK_TRANSID_SIZE);
 
444
 
 
445
    /*
 
446
      If page cache is not initialized, then assume we will create the
 
447
      page_cache after the table is opened!
 
448
      This is only used by maria_check to allow it to check/repair tables
 
449
      with different block sizes.
 
450
    */
 
451
    if (share->base.block_size != maria_block_size &&
 
452
        share_buff.pagecache->inited != 0)
 
453
    {
 
454
      DBUG_PRINT("error", ("Wrong block size %u; Expected %u",
 
455
                           (uint) share->base.block_size,
 
456
                           (uint) maria_block_size));
 
457
      my_errno=HA_ERR_UNSUPPORTED;
 
458
      goto err;
 
459
    }
 
460
 
 
461
    /* Correct max_file_length based on length of sizeof(off_t) */
 
462
    max_data_file_length=
 
463
      (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
 
464
      (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
 
465
      (_ma_safe_mul(share->base.pack_reclength,
 
466
                   (ulonglong) 1 << (share->base.rec_reflength*8))-1);
 
467
 
 
468
    max_key_file_length=
 
469
      _ma_safe_mul(maria_block_size,
 
470
                  ((ulonglong) 1 << (share->base.key_reflength*8))-1);
 
471
#if SIZEOF_OFF_T == 4
 
472
    set_if_smaller(max_data_file_length, INT_MAX32);
 
473
    set_if_smaller(max_key_file_length, INT_MAX32);
 
474
#endif
 
475
    share->base.max_data_file_length=(my_off_t) max_data_file_length;
 
476
    share->base.max_key_file_length=(my_off_t) max_key_file_length;
 
477
 
 
478
    if (share->options & HA_OPTION_COMPRESS_RECORD)
 
479
      share->base.max_key_length+=2;    /* For safety */
 
480
    /* Add space for node pointer */
 
481
    share->base.max_key_length+= share->base.key_reflength;
 
482
 
 
483
    if (!my_multi_malloc(MY_WME,
 
484
                         &share,sizeof(*share),
 
485
                         &share->state.rec_per_key_part,
 
486
                         sizeof(double) * key_parts,
 
487
                         &share->state.nulls_per_key_part,
 
488
                         sizeof(long)* key_parts,
 
489
                         &share->keyinfo,keys*sizeof(MARIA_KEYDEF),
 
490
                         &share->uniqueinfo,uniques*sizeof(MARIA_UNIQUEDEF),
 
491
                         &share->keyparts,
 
492
                         (key_parts+unique_key_parts+keys+uniques) *
 
493
                         sizeof(HA_KEYSEG),
 
494
                         &share->columndef,
 
495
                         (share->base.fields+1)*sizeof(MARIA_COLUMNDEF),
 
496
                         &share->column_nr, share->base.fields*sizeof(uint16),
 
497
                         &share->blobs,sizeof(MARIA_BLOB)*share->base.blobs,
 
498
                         &share->unique_file_name,strlen(name_buff)+1,
 
499
                         &share->index_file_name,strlen(index_name)+1,
 
500
                         &share->data_file_name,strlen(data_name)+1,
 
501
                         &share->open_file_name,strlen(name)+1,
 
502
                         &share->state.key_root,keys*sizeof(my_off_t),
 
503
                         &share->mmap_lock,sizeof(rw_lock_t),
 
504
                         NullS))
 
505
      goto err;
 
506
    errpos= 4;
 
507
 
 
508
    *share=share_buff;
 
509
    memcpy((char*) share->state.rec_per_key_part,
 
510
           (char*) rec_per_key_part, sizeof(double)*key_parts);
 
511
    memcpy((char*) share->state.nulls_per_key_part,
 
512
           (char*) nulls_per_key_part, sizeof(long)*key_parts);
 
513
    memcpy((char*) share->state.key_root,
 
514
           (char*) key_root, sizeof(my_off_t)*keys);
 
515
    strmov(share->unique_file_name, name_buff);
 
516
    share->unique_name_length= (uint) strlen(name_buff);
 
517
    strmov(share->index_file_name,  index_name);
 
518
    strmov(share->data_file_name,   data_name);
 
519
    strmov(share->open_file_name,   name);
 
520
 
 
521
    share->block_size= share->base.block_size;   /* Convenience */
 
522
    {
 
523
      HA_KEYSEG *pos=share->keyparts;
 
524
      for (i=0 ; i < keys ; i++)
 
525
      {
 
526
        share->keyinfo[i].share= share;
 
527
        disk_pos=_ma_keydef_read(disk_pos, &share->keyinfo[i]);
 
528
        share->keyinfo[i].key_nr= i;
 
529
        disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
 
530
                        end_pos);
 
531
        if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE)
 
532
          share->have_rtree= 1;
 
533
        share->keyinfo[i].seg=pos;
 
534
        for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
 
535
        {
 
536
          disk_pos=_ma_keyseg_read(disk_pos, pos);
 
537
          if (pos->type == HA_KEYTYPE_TEXT ||
 
538
              pos->type == HA_KEYTYPE_VARTEXT1 ||
 
539
              pos->type == HA_KEYTYPE_VARTEXT2)
 
540
          {
 
541
            if (!pos->language)
 
542
              pos->charset=default_charset_info;
 
543
            else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
 
544
            {
 
545
              my_errno=HA_ERR_UNKNOWN_CHARSET;
 
546
              goto err;
 
547
            }
 
548
          }
 
549
          else if (pos->type == HA_KEYTYPE_BINARY)
 
550
            pos->charset= &my_charset_bin;
 
551
        }
 
552
        if (share->keyinfo[i].flag & HA_SPATIAL)
 
553
        {
 
554
#ifdef HAVE_SPATIAL
 
555
          uint sp_segs=SPDIMS*2;
 
556
          share->keyinfo[i].seg=pos-sp_segs;
 
557
          share->keyinfo[i].keysegs--;
 
558
          versioning= 0;
 
559
#else
 
560
          my_errno=HA_ERR_UNSUPPORTED;
 
561
          goto err;
 
562
#endif
 
563
        }
 
564
        else if (share->keyinfo[i].flag & HA_FULLTEXT)
 
565
        {
 
566
          versioning= 0;
 
567
          DBUG_ASSERT(fulltext_keys);
 
568
          {
 
569
            uint k;
 
570
            share->keyinfo[i].seg=pos;
 
571
            for (k=0; k < FT_SEGS; k++)
 
572
            {
 
573
              *pos= ft_keysegs[k];
 
574
              pos[0].language= pos[-1].language;
 
575
              if (!(pos[0].charset= pos[-1].charset))
 
576
              {
 
577
                my_errno=HA_ERR_CRASHED;
 
578
                goto err;
 
579
              }
 
580
              pos++;
 
581
            }
 
582
          }
 
583
          if (!share->ft2_keyinfo.seg)
 
584
          {
 
585
            memcpy(&share->ft2_keyinfo, &share->keyinfo[i],
 
586
                   sizeof(MARIA_KEYDEF));
 
587
            share->ft2_keyinfo.keysegs=1;
 
588
            share->ft2_keyinfo.flag=0;
 
589
            share->ft2_keyinfo.keylength=
 
590
            share->ft2_keyinfo.minlength=
 
591
            share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
 
592
            share->ft2_keyinfo.seg=pos-1;
 
593
            share->ft2_keyinfo.end=pos;
 
594
            setup_key_functions(& share->ft2_keyinfo);
 
595
          }
 
596
        }
 
597
        setup_key_functions(share->keyinfo+i);
 
598
        share->keyinfo[i].end=pos;
 
599
        pos->type=HA_KEYTYPE_END;                       /* End */
 
600
        pos->length=share->base.rec_reflength;
 
601
        pos->null_bit=0;
 
602
        pos->flag=0;                                    /* For purify */
 
603
        pos++;
 
604
 
 
605
        if ((share->keyinfo[i].flag & HA_NOSAME) && i != 0)
 
606
        {
 
607
          /*
 
608
            We can't yet have versioning if there is more than one unique
 
609
            key
 
610
          */
 
611
          versioning= 0;
 
612
        }
 
613
      }
 
614
      for (i=0 ; i < uniques ; i++)
 
615
      {
 
616
        disk_pos=_ma_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
 
617
        disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
 
618
                        HA_KEYSEG_SIZE, end_pos);
 
619
        share->uniqueinfo[i].seg=pos;
 
620
        for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
 
621
        {
 
622
          disk_pos=_ma_keyseg_read(disk_pos, pos);
 
623
          if (pos->type == HA_KEYTYPE_TEXT ||
 
624
              pos->type == HA_KEYTYPE_VARTEXT1 ||
 
625
              pos->type == HA_KEYTYPE_VARTEXT2)
 
626
          {
 
627
            if (!pos->language)
 
628
              pos->charset=default_charset_info;
 
629
            else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
 
630
            {
 
631
              my_errno=HA_ERR_UNKNOWN_CHARSET;
 
632
              goto err;
 
633
            }
 
634
          }
 
635
        }
 
636
        share->uniqueinfo[i].end=pos;
 
637
        pos->type=HA_KEYTYPE_END;                       /* End */
 
638
        pos->null_bit=0;
 
639
        pos->flag=0;
 
640
        pos++;
 
641
      }
 
642
      share->ftparsers= 0;
 
643
    }
 
644
    share->data_file_type= share->state.header.data_file_type;
 
645
    share->base_length= (BASE_ROW_HEADER_SIZE +
 
646
                         share->base.is_nulls_extended +
 
647
                         share->base.null_bytes +
 
648
                         share->base.pack_bytes +
 
649
                         test(share->options & HA_OPTION_CHECKSUM));
 
650
    share->keypage_header= ((share->base.born_transactional ?
 
651
                             LSN_STORE_SIZE + TRANSID_SIZE :
 
652
                             0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
 
653
                            KEYPAGE_USED_SIZE);
 
654
    share->kfile.file= kfile;
 
655
 
 
656
    if (open_flags & HA_OPEN_COPY)
 
657
    {
 
658
      /*
 
659
        this instance will be a temporary one used just to create a data
 
660
        file for REPAIR. Don't do logging. This base information will not go
 
661
        to disk.
 
662
      */
 
663
      share->base.born_transactional= FALSE;
 
664
    }
 
665
    if (share->base.born_transactional)
 
666
    {
 
667
      share->page_type= PAGECACHE_LSN_PAGE;
 
668
      if (share->state.create_rename_lsn == LSN_REPAIRED_BY_MARIA_CHK)
 
669
      {
 
670
        /*
 
671
          Was repaired with maria_chk, maybe later maria_pack-ed. Some sort of
 
672
          import into the server. It starts its existence (from the point of
 
673
          view of the server, including server's recovery) now.
 
674
        */
 
675
        if (((open_flags & HA_OPEN_FROM_SQL_LAYER) &&
 
676
             (share->state.changed & STATE_NOT_MOVABLE)) || maria_in_recovery)
 
677
          _ma_update_state_lsns_sub(share, translog_get_horizon(),
 
678
                                    trnman_get_min_safe_trid(), TRUE, TRUE);
 
679
      }
 
680
      else if ((!LSN_VALID(share->state.create_rename_lsn) ||
 
681
                !LSN_VALID(share->state.is_of_horizon) ||
 
682
                (cmp_translog_addr(share->state.create_rename_lsn,
 
683
                                   share->state.is_of_horizon) > 0) ||
 
684
                !LSN_VALID(share->state.skip_redo_lsn) ||
 
685
                (cmp_translog_addr(share->state.create_rename_lsn,
 
686
                                   share->state.skip_redo_lsn) > 0)) &&
 
687
               !(open_flags & HA_OPEN_FOR_REPAIR))
 
688
      {
 
689
        /*
 
690
          If in Recovery, it will not work. If LSN is invalid and not
 
691
          LSN_REPAIRED_BY_MARIA_CHK, header must be corrupted.
 
692
          In both cases, must repair.
 
693
        */
 
694
        my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
 
695
                  HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
 
696
        goto err;
 
697
      }
 
698
    }
 
699
    else
 
700
      share->page_type= PAGECACHE_PLAIN_PAGE;
 
701
    share->now_transactional= share->base.born_transactional;
 
702
 
 
703
    /* Use pack_reclength as we don't want to modify base.pack_recklength */
 
704
    if (share->state.header.org_data_file_type == DYNAMIC_RECORD)
 
705
    {
 
706
      /* add bits used to pack data to pack_reclength for faster allocation */
 
707
      share->base.pack_reclength+= share->base.pack_bytes;
 
708
      share->base.extra_rec_buff_size=
 
709
        (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER) + MARIA_SPLIT_LENGTH +
 
710
         MARIA_REC_BUFF_OFFSET);
 
711
    }
 
712
    if (share->data_file_type == COMPRESSED_RECORD)
 
713
    {
 
714
      /* Need some extra bytes for decode_bytes */
 
715
      share->base.extra_rec_buff_size+= 7;
 
716
    }
 
717
    share->base.default_rec_buff_size= max(share->base.pack_reclength +
 
718
                                           share->base.extra_rec_buff_size,
 
719
                                           share->base.max_key_length);
 
720
 
 
721
    disk_pos_assert(disk_pos + share->base.fields *MARIA_COLUMNDEF_SIZE,
 
722
                    end_pos);
 
723
    for (i= j= 0 ; i < share->base.fields ; i++)
 
724
    {
 
725
      disk_pos=_ma_columndef_read(disk_pos,&share->columndef[i]);
 
726
      share->columndef[i].pack_type=0;
 
727
      share->columndef[i].huff_tree=0;
 
728
      if (share->columndef[i].type == FIELD_BLOB)
 
729
      {
 
730
        share->blobs[j].pack_length=
 
731
          share->columndef[i].length-portable_sizeof_char_ptr;
 
732
        share->blobs[j].offset= share->columndef[i].offset;
 
733
        j++;
 
734
      }
 
735
    }
 
736
    share->columndef[i].type= FIELD_LAST;       /* End marker */
 
737
    disk_pos= _ma_column_nr_read(disk_pos, share->column_nr,
 
738
                                 share->base.fields);
 
739
 
 
740
    if ((share->data_file_type == BLOCK_RECORD ||
 
741
         share->data_file_type == COMPRESSED_RECORD))
 
742
    {
 
743
      if (_ma_open_datafile(&info, share, -1))
 
744
        goto err;
 
745
      data_file= info.dfile.file;
 
746
    }
 
747
    errpos= 5;
 
748
 
 
749
    if (open_flags & HA_OPEN_DELAY_KEY_WRITE)
 
750
      share->options|= HA_OPTION_DELAY_KEY_WRITE;
 
751
    if (mode == O_RDONLY)
 
752
      share->options|= HA_OPTION_READ_ONLY_DATA;
 
753
    share->is_log_table= FALSE;
 
754
 
 
755
    if (open_flags & HA_OPEN_TMP_TABLE)
 
756
    {
 
757
      share->options|= HA_OPTION_TMP_TABLE;
 
758
      share->temporary= share->delay_key_write= 1;
 
759
      share->write_flag=MYF(MY_NABP);
 
760
      share->w_locks++;                 /* We don't have to update status */
 
761
      share->tot_locks++;
 
762
    }
 
763
 
 
764
    _ma_set_index_pagecache_callbacks(&share->kfile, share);
 
765
    share->this_process=(ulong) getpid();
 
766
#ifdef EXTERNAL_LOCKING
 
767
    share->last_process= share->state.process;
 
768
#endif
 
769
    share->base.key_parts=key_parts;
 
770
    share->base.all_key_parts=key_parts+unique_key_parts;
 
771
    if (!(share->last_version=share->state.version))
 
772
      share->last_version=1;                    /* Safety */
 
773
    share->rec_reflength=share->base.rec_reflength; /* May be changed */
 
774
    share->base.margin_key_file_length=(share->base.max_key_file_length -
 
775
                                        (keys ? MARIA_INDEX_BLOCK_MARGIN *
 
776
                                         share->block_size * keys : 0));
 
777
    share->block_size= share->base.block_size;
 
778
    my_afree(disk_cache);
 
779
    _ma_setup_functions(share);
 
780
    if ((*share->once_init)(share, info.dfile.file))
 
781
      goto err;
 
782
    if (share->now_transactional)
 
783
    {
 
784
      /* Setup initial state that is visible for all */
 
785
      MARIA_STATE_HISTORY_CLOSED *history;
 
786
      if ((history= (MARIA_STATE_HISTORY_CLOSED *)
 
787
           hash_search(&maria_stored_state,
 
788
                       (uchar*) &share->state.create_rename_lsn, 0)))
 
789
      {
 
790
        /* Move history from hash to share */
 
791
        share->state_history=
 
792
          _ma_remove_not_visible_states(history->state_history, 0, 0);
 
793
        history->state_history= 0;
 
794
        (void) hash_delete(&maria_stored_state, (uchar*) history);
 
795
      }
 
796
      else
 
797
      {
 
798
        /* Table is not part of any active transaction; Create new history */
 
799
        if (!(share->state_history= (MARIA_STATE_HISTORY *)
 
800
              my_malloc(sizeof(*share->state_history), MYF(MY_WME))))
 
801
          goto err;
 
802
        share->state_history->trid= 0;          /* Visibly by all */
 
803
        share->state_history->state= share->state.state;
 
804
        share->state_history->next= 0;
 
805
      }
 
806
    }
 
807
#ifdef THREAD
 
808
    thr_lock_init(&share->lock);
 
809
    (void)(pthread_mutex_init(&share->intern_lock, MY_MUTEX_INIT_FAST));
 
810
    (void)(pthread_cond_init(&share->intern_cond, 0));
 
811
    for (i=0; i<keys; i++)
 
812
      (void)(my_rwlock_init(&share->keyinfo[i].root_lock, NULL));
 
813
    (void)(my_rwlock_init(&share->mmap_lock, NULL));
 
814
 
 
815
    share->row_is_visible= _ma_row_visible_always;
 
816
    if (!thr_lock_inited)
 
817
    {
 
818
      /* Probably a single threaded program; Don't use concurrent inserts */
 
819
      maria_concurrent_insert=0;
 
820
    }
 
821
    else if (maria_concurrent_insert)
 
822
    {
 
823
      share->non_transactional_concurrent_insert=
 
824
        ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
 
825
                            HA_OPTION_COMPRESS_RECORD |
 
826
                            HA_OPTION_TEMP_COMPRESS_RECORD)) ||
 
827
         (open_flags & HA_OPEN_TMP_TABLE) ||
 
828
         share->data_file_type == BLOCK_RECORD ||
 
829
         share->have_rtree) ? 0 : 1;
 
830
      if (share->non_transactional_concurrent_insert ||
 
831
          (!share->temporary && share->now_transactional && versioning))
 
832
      {
 
833
        share->lock_key_trees= 1;
 
834
        if (share->data_file_type == BLOCK_RECORD)
 
835
        {
 
836
          DBUG_ASSERT(share->now_transactional);
 
837
          share->have_versioning= 1;
 
838
          share->row_is_visible=     _ma_row_visible_transactional_table;
 
839
          share->lock.get_status=    _ma_block_get_status;
 
840
          share->lock.update_status= _ma_block_update_status;
 
841
          share->lock.check_status=  _ma_block_check_status;
 
842
          /*
 
843
            We can for the moment only allow multiple concurrent inserts
 
844
            only if there is no auto-increment key.  To lift this restriction
 
845
            we have to:
 
846
            - Extend statement base replication to support auto-increment
 
847
            intervalls.
 
848
            - Fix that we allocate auto-increment in intervals and that
 
849
              it's properly reset if the interval was not used
 
850
          */
 
851
          share->lock.allow_multiple_concurrent_insert=
 
852
            share->base.auto_key == 0;
 
853
          share->lock_restore_status= 0;
 
854
        }
 
855
        else
 
856
        {
 
857
          share->row_is_visible=      _ma_row_visible_non_transactional_table;
 
858
          share->lock.get_status=     _ma_get_status;
 
859
          share->lock.copy_status=    _ma_copy_status;
 
860
          share->lock.update_status=  _ma_update_status;
 
861
          share->lock.restore_status= _ma_restore_status;
 
862
          share->lock.check_status=   _ma_check_status;
 
863
          share->lock_restore_status= _ma_restore_status;
 
864
        }
 
865
      }
 
866
    }
 
867
#endif
 
868
    /*
 
869
      Memory mapping can only be requested after initializing intern_lock.
 
870
    */
 
871
    if (open_flags & HA_OPEN_MMAP)
 
872
    {
 
873
      info.s= share;
 
874
      maria_extra(&info, HA_EXTRA_MMAP, 0);
 
875
    }
 
876
  }
 
877
  else
 
878
  {
 
879
    share= old_info->s;
 
880
    if (share->data_file_type == BLOCK_RECORD)
 
881
      data_file= share->bitmap.file.file;       /* Only opened once */
 
882
  }
 
883
 
 
884
  if (!(m_info= maria_clone_internal(share, mode, data_file)))
 
885
    goto err;
 
886
 
 
887
  pthread_mutex_unlock(&THR_LOCK_maria);
 
888
  DBUG_RETURN(m_info);
 
889
 
 
890
err:
 
891
  save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
 
892
  if ((save_errno == HA_ERR_CRASHED) ||
 
893
      (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
 
894
      (save_errno == HA_ERR_CRASHED_ON_REPAIR))
 
895
    _ma_report_error(save_errno, name);
 
896
  if (save_errno == HA_ERR_OLD_FILE) /* uuid is different ? */
 
897
    save_errno= HA_ERR_CRASHED_ON_USAGE; /* the code to trigger auto-repair */
 
898
  switch (errpos) {
 
899
  case 5:
 
900
    if (data_file >= 0)
 
901
      (void)(my_close(data_file, MYF(0)));
 
902
    if (old_info)
 
903
      break;                                    /* Don't remove open table */
 
904
    (*share->once_end)(share);
 
905
    /* fall through */
 
906
  case 4:
 
907
    my_free((uchar*) share,MYF(0));
 
908
    /* fall through */
 
909
  case 3:
 
910
    /* fall through */
 
911
  case 2:
 
912
    my_afree((uchar*) disk_cache);
 
913
    /* fall through */
 
914
  case 1:
 
915
    (void)(my_close(kfile,MYF(0)));
 
916
    /* fall through */
 
917
  case 0:
 
918
  default:
 
919
    break;
 
920
  }
 
921
  pthread_mutex_unlock(&THR_LOCK_maria);
 
922
  my_errno= save_errno;
 
923
  DBUG_RETURN (NULL);
 
924
} /* maria_open */
 
925
 
 
926
 
 
927
/*
 
928
  Reallocate a buffer, if the current buffer is not large enough
 
929
*/
 
930
 
 
931
my_bool _ma_alloc_buffer(uchar **old_addr, size_t *old_size,
 
932
                         size_t new_size)
 
933
{
 
934
  if (*old_size < new_size)
 
935
  {
 
936
    uchar *addr;
 
937
    if (!(addr= (uchar*) my_realloc((uchar*) *old_addr, new_size,
 
938
                                   MYF(MY_ALLOW_ZERO_PTR))))
 
939
      return 1;
 
940
    *old_addr= addr;
 
941
    *old_size= new_size;
 
942
  }
 
943
  return 0;
 
944
}
 
945
 
 
946
 
 
947
ulonglong _ma_safe_mul(ulonglong a, ulonglong b)
 
948
{
 
949
  ulonglong max_val= ~ (ulonglong) 0;           /* my_off_t is unsigned */
 
950
 
 
951
  if (!a || max_val / a < b)
 
952
    return max_val;
 
953
  return a*b;
 
954
}
 
955
 
 
956
        /* Set up functions in structs */
 
957
 
 
958
void _ma_setup_functions(register MARIA_SHARE *share)
 
959
{
 
960
  share->once_init=          maria_once_init_dummy;
 
961
  share->once_end=           maria_once_end_dummy;
 
962
  share->init=               maria_scan_init_dummy;
 
963
  share->end=                maria_scan_end_dummy;
 
964
  share->scan_init=          maria_scan_init_dummy;/* Compat. dummy function */
 
965
  share->scan_end=           maria_scan_end_dummy;/* Compat. dummy function */
 
966
  share->scan_remember_pos=  _ma_def_scan_remember_pos;
 
967
  share->scan_restore_pos=   _ma_def_scan_restore_pos;
 
968
 
 
969
  share->write_record_init=  _ma_write_init_default;
 
970
  share->write_record_abort= _ma_write_abort_default;
 
971
  share->keypos_to_recpos=   _ma_transparent_recpos;
 
972
  share->recpos_to_keypos=   _ma_transparent_recpos;
 
973
 
 
974
  switch (share->data_file_type) {
 
975
  case COMPRESSED_RECORD:
 
976
    share->read_record= _ma_read_pack_record;
 
977
    share->scan= _ma_read_rnd_pack_record;
 
978
    share->once_init= _ma_once_init_pack_row;
 
979
    share->once_end=  _ma_once_end_pack_row;
 
980
    /*
 
981
      Calculate checksum according to data in the original, not compressed,
 
982
      row.
 
983
    */
 
984
    if (share->state.header.org_data_file_type == STATIC_RECORD &&
 
985
        ! (share->options & HA_OPTION_NULL_FIELDS))
 
986
      share->calc_checksum= _ma_static_checksum;
 
987
    else
 
988
      share->calc_checksum= _ma_checksum;
 
989
    share->calc_write_checksum= share->calc_checksum;
 
990
    break;
 
991
  case DYNAMIC_RECORD:
 
992
    share->read_record= _ma_read_dynamic_record;
 
993
    share->scan= _ma_read_rnd_dynamic_record;
 
994
    share->delete_record= _ma_delete_dynamic_record;
 
995
    share->compare_record= _ma_cmp_dynamic_record;
 
996
    share->compare_unique= _ma_cmp_dynamic_unique;
 
997
    share->calc_checksum= share->calc_write_checksum= _ma_checksum;
 
998
    if (share->base.blobs)
 
999
    {
 
1000
      share->update_record= _ma_update_blob_record;
 
1001
      share->write_record= _ma_write_blob_record;
 
1002
    }
 
1003
    else
 
1004
    {
 
1005
      share->write_record= _ma_write_dynamic_record;
 
1006
      share->update_record= _ma_update_dynamic_record;
 
1007
    }
 
1008
    break;
 
1009
  case STATIC_RECORD:
 
1010
    share->read_record=      _ma_read_static_record;
 
1011
    share->scan=             _ma_read_rnd_static_record;
 
1012
    share->delete_record=    _ma_delete_static_record;
 
1013
    share->compare_record=   _ma_cmp_static_record;
 
1014
    share->update_record=    _ma_update_static_record;
 
1015
    share->write_record=     _ma_write_static_record;
 
1016
    share->compare_unique=   _ma_cmp_static_unique;
 
1017
    share->keypos_to_recpos= _ma_static_keypos_to_recpos;
 
1018
    share->recpos_to_keypos= _ma_static_recpos_to_keypos;
 
1019
    if (share->state.header.org_data_file_type == STATIC_RECORD &&
 
1020
        ! (share->options & HA_OPTION_NULL_FIELDS))
 
1021
      share->calc_checksum= _ma_static_checksum;
 
1022
    else
 
1023
      share->calc_checksum= _ma_checksum;
 
1024
    break;
 
1025
  case BLOCK_RECORD:
 
1026
    share->once_init= _ma_once_init_block_record;
 
1027
    share->once_end=  _ma_once_end_block_record;
 
1028
    share->init=      _ma_init_block_record;
 
1029
    share->end=       _ma_end_block_record;
 
1030
    share->write_record_init= _ma_write_init_block_record;
 
1031
    share->write_record_abort= _ma_write_abort_block_record;
 
1032
    share->scan_init=   _ma_scan_init_block_record;
 
1033
    share->scan_end=    _ma_scan_end_block_record;
 
1034
    share->scan=        _ma_scan_block_record;
 
1035
    share->scan_remember_pos=  _ma_scan_remember_block_record;
 
1036
    share->scan_restore_pos=   _ma_scan_restore_block_record;
 
1037
    share->read_record= _ma_read_block_record;
 
1038
    share->delete_record= _ma_delete_block_record;
 
1039
    share->compare_record= _ma_compare_block_record;
 
1040
    share->update_record= _ma_update_block_record;
 
1041
    share->write_record=  _ma_write_block_record;
 
1042
    share->compare_unique= _ma_cmp_block_unique;
 
1043
    share->calc_checksum= _ma_checksum;
 
1044
    share->keypos_to_recpos= _ma_transaction_keypos_to_recpos;
 
1045
    share->recpos_to_keypos= _ma_transaction_recpos_to_keypos;
 
1046
 
 
1047
    /*
 
1048
      write_block_record() will calculate the checksum; Tell maria_write()
 
1049
      that it doesn't have to do this.
 
1050
    */
 
1051
    share->calc_write_checksum= 0;
 
1052
    break;
 
1053
  }
 
1054
  share->file_read= _ma_nommap_pread;
 
1055
  share->file_write= _ma_nommap_pwrite;
 
1056
  share->calc_check_checksum= share->calc_checksum;
 
1057
 
 
1058
  if (!(share->options & HA_OPTION_CHECKSUM) &&
 
1059
      share->data_file_type != COMPRESSED_RECORD)
 
1060
    share->calc_checksum= share->calc_write_checksum= 0;
 
1061
  return;
 
1062
}
 
1063
 
 
1064
 
 
1065
static void setup_key_functions(register MARIA_KEYDEF *keyinfo)
 
1066
{
 
1067
  if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
 
1068
  {
 
1069
#ifdef HAVE_RTREE_KEYS
 
1070
    keyinfo->ck_insert = maria_rtree_insert;
 
1071
    keyinfo->ck_delete = maria_rtree_delete;
 
1072
#else
 
1073
    DBUG_ASSERT(0); /* maria_open should check it never happens */
 
1074
#endif
 
1075
  }
 
1076
  else
 
1077
  {
 
1078
    keyinfo->ck_insert = _ma_ck_write;
 
1079
    keyinfo->ck_delete = _ma_ck_delete;
 
1080
  }
 
1081
  if (keyinfo->flag & HA_SPATIAL)
 
1082
    keyinfo->make_key= _ma_sp_make_key;
 
1083
  else
 
1084
    keyinfo->make_key= _ma_make_key;
 
1085
 
 
1086
  if (keyinfo->flag & HA_BINARY_PACK_KEY)
 
1087
  {                                             /* Simple prefix compression */
 
1088
    keyinfo->bin_search= _ma_seq_search;
 
1089
    keyinfo->get_key= _ma_get_binary_pack_key;
 
1090
    keyinfo->skip_key= _ma_skip_binary_pack_key;
 
1091
    keyinfo->pack_key= _ma_calc_bin_pack_key_length;
 
1092
    keyinfo->store_key= _ma_store_bin_pack_key;
 
1093
  }
 
1094
  else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
 
1095
  {
 
1096
    keyinfo->get_key=  _ma_get_pack_key;
 
1097
    keyinfo->skip_key= _ma_skip_pack_key;
 
1098
    if (keyinfo->seg[0].flag & HA_PACK_KEY)
 
1099
    {                                           /* Prefix compression */
 
1100
      /*
 
1101
        _ma_prefix_search() compares end-space against ASCII blank (' ').
 
1102
        It cannot be used for character sets, that do not encode the
 
1103
        blank character like ASCII does. UCS2 is an example. All
 
1104
        character sets with a fixed width > 1 or a mimimum width > 1
 
1105
        cannot represent blank like ASCII does. In these cases we have
 
1106
        to use _ma_seq_search() for the search.
 
1107
      */
 
1108
      if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
 
1109
          (keyinfo->seg->flag & HA_NULL_PART) ||
 
1110
          keyinfo->seg->charset->mbminlen > 1)
 
1111
        keyinfo->bin_search= _ma_seq_search;
 
1112
      else
 
1113
        keyinfo->bin_search= _ma_prefix_search;
 
1114
      keyinfo->pack_key= _ma_calc_var_pack_key_length;
 
1115
      keyinfo->store_key= _ma_store_var_pack_key;
 
1116
    }
 
1117
    else
 
1118
    {
 
1119
      keyinfo->bin_search= _ma_seq_search;
 
1120
      keyinfo->pack_key= _ma_calc_var_key_length; /* Variable length key */
 
1121
      keyinfo->store_key= _ma_store_static_key;
 
1122
    }
 
1123
  }
 
1124
  else
 
1125
  {
 
1126
    keyinfo->bin_search= _ma_bin_search;
 
1127
    keyinfo->get_key= _ma_get_static_key;
 
1128
    keyinfo->skip_key= _ma_skip_static_key;
 
1129
    keyinfo->pack_key= _ma_calc_static_key_length;
 
1130
    keyinfo->store_key= _ma_store_static_key;
 
1131
  }
 
1132
 
 
1133
  /* set keyinfo->write_comp_flag */
 
1134
  if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
 
1135
    keyinfo->write_comp_flag=SEARCH_BIGGER; /* Put after same key */
 
1136
  else if (keyinfo->flag & ( HA_NOSAME | HA_FULLTEXT))
 
1137
  {
 
1138
    keyinfo->write_comp_flag= SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
 
1139
    if (keyinfo->flag & HA_NULL_ARE_EQUAL)
 
1140
      keyinfo->write_comp_flag|= SEARCH_NULL_ARE_EQUAL;
 
1141
  }
 
1142
  else
 
1143
    keyinfo->write_comp_flag= SEARCH_SAME; /* Keys in rec-pos order */
 
1144
  keyinfo->write_comp_flag|= SEARCH_INSERT;
 
1145
  return;
 
1146
}
 
1147
 
 
1148
 
 
1149
/**
 
1150
   @brief Function to save and store the header in the index file (.MYI)
 
1151
 
 
1152
   Operates under MARIA_SHARE::intern_lock if requested.
 
1153
   Sets MARIA_SHARE::MARIA_STATE_INFO::is_of_horizon if transactional table.
 
1154
   Then calls _ma_state_info_write_sub().
 
1155
 
 
1156
   @param  share           table
 
1157
   @param  pWrite          bitmap: if 1 is set my_pwrite() is used otherwise
 
1158
                           my_write(); if 2 is set, info about keys is written
 
1159
                           (should only be needed after ALTER TABLE
 
1160
                           ENABLE/DISABLE KEYS, and REPAIR/OPTIMIZE); if 4 is
 
1161
                           set, MARIA_SHARE::intern_lock is taken.
 
1162
 
 
1163
   @return Operation status
 
1164
     @retval 0      OK
 
1165
     @retval 1      Error
 
1166
*/
 
1167
 
 
1168
uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite)
 
1169
{
 
1170
  uint res;
 
1171
  if (share->options & HA_OPTION_READ_ONLY_DATA)
 
1172
    return 0;
 
1173
 
 
1174
  if (pWrite & 4)
 
1175
    pthread_mutex_lock(&share->intern_lock);
 
1176
  else if (maria_multi_threaded)
 
1177
  {
 
1178
    safe_mutex_assert_owner(&share->intern_lock);
 
1179
  }
 
1180
  if (share->base.born_transactional && translog_status == TRANSLOG_OK &&
 
1181
      !maria_in_recovery)
 
1182
  {
 
1183
    /*
 
1184
      In a recovery, we want to set is_of_horizon to the LSN of the last
 
1185
      record executed by Recovery, not the current EOF of the log (which
 
1186
      is too new). Recovery does it by itself.
 
1187
    */
 
1188
    share->state.is_of_horizon= translog_get_horizon();
 
1189
    DBUG_PRINT("info", ("is_of_horizon set to LSN (%lu,0x%lx)",
 
1190
                        LSN_IN_PARTS(share->state.is_of_horizon)));
 
1191
  }
 
1192
  res= _ma_state_info_write_sub(share->kfile.file, &share->state, pWrite);
 
1193
  if (pWrite & 4)
 
1194
    pthread_mutex_unlock(&share->intern_lock);
 
1195
  return res;
 
1196
}
 
1197
 
 
1198
 
 
1199
/**
 
1200
   @brief Function to save and store the header in the index file (.MYI).
 
1201
 
 
1202
   Shortcut to use instead of _ma_state_info_write() when appropriate.
 
1203
 
 
1204
   @param  file            descriptor of the index file to write
 
1205
   @param  state           state information to write to the file
 
1206
   @param  pWrite          bitmap: if 1 is set my_pwrite() is used otherwise
 
1207
                           my_write(); if 2 is set, info about keys is written
 
1208
                           (should only be needed after ALTER TABLE
 
1209
                           ENABLE/DISABLE KEYS, and REPAIR/OPTIMIZE).
 
1210
 
 
1211
   @return Operation status
 
1212
     @retval 0      OK
 
1213
     @retval 1      Error
 
1214
*/
 
1215
 
 
1216
uint _ma_state_info_write_sub(File file, MARIA_STATE_INFO *state, uint pWrite)
 
1217
{
 
1218
  uchar  buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
 
1219
  uchar *ptr=buff;
 
1220
  uint  i, keys= (uint) state->header.keys;
 
1221
  size_t res;
 
1222
  DBUG_ENTER("_ma_state_info_write_sub");
 
1223
 
 
1224
  memcpy_fixed(ptr,&state->header,sizeof(state->header));
 
1225
  ptr+=sizeof(state->header);
 
1226
 
 
1227
  /* open_count must be first because of _ma_mark_file_changed ! */
 
1228
  mi_int2store(ptr,state->open_count);                  ptr+= 2;
 
1229
  /* changed must be second, because of _ma_mark_file_crashed */
 
1230
  mi_int2store(ptr,state->changed);                     ptr+= 2;
 
1231
 
 
1232
  /*
 
1233
    If you change the offset of these LSNs, note that some functions do a
 
1234
    direct write of them without going through this function.
 
1235
  */
 
1236
  lsn_store(ptr, state->create_rename_lsn);             ptr+= LSN_STORE_SIZE;
 
1237
  lsn_store(ptr, state->is_of_horizon);                 ptr+= LSN_STORE_SIZE;
 
1238
  lsn_store(ptr, state->skip_redo_lsn);                 ptr+= LSN_STORE_SIZE;
 
1239
  mi_rowstore(ptr,state->state.records);                ptr+= 8;
 
1240
  mi_rowstore(ptr,state->state.del);                    ptr+= 8;
 
1241
  mi_rowstore(ptr,state->split);                        ptr+= 8;
 
1242
  mi_sizestore(ptr,state->dellink);                     ptr+= 8;
 
1243
  mi_sizestore(ptr,state->first_bitmap_with_space);     ptr+= 8;
 
1244
  mi_sizestore(ptr,state->state.key_file_length);       ptr+= 8;
 
1245
  mi_sizestore(ptr,state->state.data_file_length);      ptr+= 8;
 
1246
  mi_sizestore(ptr,state->state.empty);                 ptr+= 8;
 
1247
  mi_sizestore(ptr,state->state.key_empty);             ptr+= 8;
 
1248
  mi_int8store(ptr,state->auto_increment);              ptr+= 8;
 
1249
  mi_int8store(ptr,(ulonglong) state->state.checksum);  ptr+= 8;
 
1250
  mi_int8store(ptr,state->create_trid);                 ptr+= 8;
 
1251
  mi_int4store(ptr,state->status);                      ptr+= 4;
 
1252
  mi_int4store(ptr,state->update_count);                ptr+= 4;
 
1253
  *ptr++= state->sortkey;
 
1254
  *ptr++= 0;                                    /* Reserved */
 
1255
  ptr+= state->state_diff_length;
 
1256
 
 
1257
  for (i=0; i < keys; i++)
 
1258
  {
 
1259
    mi_sizestore(ptr,state->key_root[i]);               ptr+= 8;
 
1260
  }
 
1261
  mi_sizestore(ptr,state->key_del);                     ptr+= 8;
 
1262
  if (pWrite & 2)                               /* From maria_chk */
 
1263
  {
 
1264
    uint key_parts= mi_uint2korr(state->header.key_parts);
 
1265
    mi_int4store(ptr,state->sec_index_changed);         ptr+= 4;
 
1266
    mi_int4store(ptr,state->sec_index_used);            ptr+= 4;
 
1267
    mi_int4store(ptr,state->version);                   ptr+= 4;
 
1268
    mi_int8store(ptr,state->key_map);                   ptr+= 8;
 
1269
    mi_int8store(ptr,(ulonglong) state->create_time);   ptr+= 8;
 
1270
    mi_int8store(ptr,(ulonglong) state->recover_time);  ptr+= 8;
 
1271
    mi_int8store(ptr,(ulonglong) state->check_time);    ptr+= 8;
 
1272
    mi_sizestore(ptr, state->records_at_analyze);       ptr+= 8;
 
1273
    /* reserve place for some information per key */
 
1274
    bzero(ptr, keys*4);                                 ptr+= keys*4;
 
1275
    for (i=0 ; i < key_parts ; i++)
 
1276
    {
 
1277
      float8store(ptr, state->rec_per_key_part[i]);     ptr+= 8;
 
1278
      mi_int4store(ptr, state->nulls_per_key_part[i]);  ptr+= 4;
 
1279
    }
 
1280
  }
 
1281
 
 
1282
  res= (pWrite & 1) ?
 
1283
    my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
 
1284
              MYF(MY_NABP | MY_THREADSAFE)) :
 
1285
    my_write(file,  buff, (size_t) (ptr-buff),
 
1286
             MYF(MY_NABP));
 
1287
  DBUG_RETURN(res != 0);
 
1288
}
 
1289
 
 
1290
 
 
1291
static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state)
 
1292
{
 
1293
  uint i,keys,key_parts;
 
1294
  memcpy_fixed(&state->header,ptr, sizeof(state->header));
 
1295
  ptr+= sizeof(state->header);
 
1296
  keys= (uint) state->header.keys;
 
1297
  key_parts= mi_uint2korr(state->header.key_parts);
 
1298
 
 
1299
  state->open_count = mi_uint2korr(ptr);                ptr+= 2;
 
1300
  state->changed= mi_uint2korr(ptr);                    ptr+= 2;
 
1301
  state->create_rename_lsn= lsn_korr(ptr);              ptr+= LSN_STORE_SIZE;
 
1302
  state->is_of_horizon= lsn_korr(ptr);                  ptr+= LSN_STORE_SIZE;
 
1303
  state->skip_redo_lsn= lsn_korr(ptr);                  ptr+= LSN_STORE_SIZE;
 
1304
  state->state.records= mi_rowkorr(ptr);                ptr+= 8;
 
1305
  state->state.del = mi_rowkorr(ptr);                   ptr+= 8;
 
1306
  state->split  = mi_rowkorr(ptr);                      ptr+= 8;
 
1307
  state->dellink= mi_sizekorr(ptr);                     ptr+= 8;
 
1308
  state->first_bitmap_with_space= mi_sizekorr(ptr);     ptr+= 8;
 
1309
  state->state.key_file_length = mi_sizekorr(ptr);      ptr+= 8;
 
1310
  state->state.data_file_length= mi_sizekorr(ptr);      ptr+= 8;
 
1311
  state->state.empty    = mi_sizekorr(ptr);             ptr+= 8;
 
1312
  state->state.key_empty= mi_sizekorr(ptr);             ptr+= 8;
 
1313
  state->auto_increment=mi_uint8korr(ptr);              ptr+= 8;
 
1314
  state->state.checksum=(ha_checksum) mi_uint8korr(ptr);ptr+= 8;
 
1315
  state->create_trid= mi_uint8korr(ptr);                ptr+= 8;
 
1316
  state->status = mi_uint4korr(ptr);                    ptr+= 4;
 
1317
  state->update_count=mi_uint4korr(ptr);                ptr+= 4;
 
1318
  state->sortkey=                                       (uint) *ptr++;
 
1319
  ptr++;                                                /* reserved */
 
1320
 
 
1321
  ptr+= state->state_diff_length;
 
1322
 
 
1323
  for (i=0; i < keys; i++)
 
1324
  {
 
1325
    state->key_root[i]= mi_sizekorr(ptr);               ptr+= 8;
 
1326
  }
 
1327
  state->key_del= mi_sizekorr(ptr);                     ptr+= 8;
 
1328
  state->sec_index_changed = mi_uint4korr(ptr);         ptr+= 4;
 
1329
  state->sec_index_used =    mi_uint4korr(ptr);         ptr+= 4;
 
1330
  state->version     = mi_uint4korr(ptr);               ptr+= 4;
 
1331
  state->key_map     = mi_uint8korr(ptr);               ptr+= 8;
 
1332
  state->create_time = (time_t) mi_sizekorr(ptr);       ptr+= 8;
 
1333
  state->recover_time =(time_t) mi_sizekorr(ptr);       ptr+= 8;
 
1334
  state->check_time =  (time_t) mi_sizekorr(ptr);       ptr+= 8;
 
1335
  state->records_at_analyze=    mi_sizekorr(ptr);       ptr+= 8;
 
1336
  ptr+= keys * 4;                               /* Skip reserved bytes */
 
1337
  for (i=0 ; i < key_parts ; i++)
 
1338
  {
 
1339
    float8get(state->rec_per_key_part[i], ptr);         ptr+= 8;
 
1340
    state->nulls_per_key_part[i]= mi_uint4korr(ptr);    ptr+= 4;
 
1341
  }
 
1342
  return ptr;
 
1343
}
 
1344
 
 
1345
 
 
1346
/**
 
1347
   @brief Fills the state by reading its copy on disk.
 
1348
 
 
1349
   Should not be called for transactional tables, as their state on disk is
 
1350
   rarely current and so is often misleading for a reader.
 
1351
   Does nothing in single user mode.
 
1352
 
 
1353
   @param  file            file to read from
 
1354
   @param  state           state which will be filled
 
1355
*/
 
1356
 
 
1357
uint _ma_state_info_read_dsk(File file __attribute__((unused)),
 
1358
                             MARIA_STATE_INFO *state __attribute__((unused)))
 
1359
{
 
1360
#ifdef EXTERNAL_LOCKING
 
1361
  uchar buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
 
1362
 
 
1363
  /* trick to detect transactional tables */
 
1364
  DBUG_ASSERT(state->create_rename_lsn == LSN_IMPOSSIBLE);
 
1365
  if (!maria_single_user)
 
1366
  {
 
1367
    if (my_pread(file, buff, state->state_length, 0L, MYF(MY_NABP)))
 
1368
      return 1;
 
1369
    _ma_state_info_read(buff, state);
 
1370
  }
 
1371
#endif
 
1372
  return 0;
 
1373
}
 
1374
 
 
1375
 
 
1376
/****************************************************************************
 
1377
**  store and read of MARIA_BASE_INFO
 
1378
****************************************************************************/
 
1379
 
 
1380
uint _ma_base_info_write(File file, MARIA_BASE_INFO *base)
 
1381
{
 
1382
  uchar buff[MARIA_BASE_INFO_SIZE], *ptr=buff;
 
1383
 
 
1384
  bmove(ptr, maria_uuid, MY_UUID_SIZE);
 
1385
  ptr+= MY_UUID_SIZE;
 
1386
  mi_sizestore(ptr,base->keystart);                     ptr+= 8;
 
1387
  mi_sizestore(ptr,base->max_data_file_length);         ptr+= 8;
 
1388
  mi_sizestore(ptr,base->max_key_file_length);          ptr+= 8;
 
1389
  mi_rowstore(ptr,base->records);                       ptr+= 8;
 
1390
  mi_rowstore(ptr,base->reloc);                         ptr+= 8;
 
1391
  mi_int4store(ptr,base->mean_row_length);              ptr+= 4;
 
1392
  mi_int4store(ptr,base->reclength);                    ptr+= 4;
 
1393
  mi_int4store(ptr,base->pack_reclength);               ptr+= 4;
 
1394
  mi_int4store(ptr,base->min_pack_length);              ptr+= 4;
 
1395
  mi_int4store(ptr,base->max_pack_length);              ptr+= 4;
 
1396
  mi_int4store(ptr,base->min_block_length);             ptr+= 4;
 
1397
  mi_int2store(ptr,base->fields);                       ptr+= 2;
 
1398
  mi_int2store(ptr,base->fixed_not_null_fields);        ptr+= 2;
 
1399
  mi_int2store(ptr,base->fixed_not_null_fields_length); ptr+= 2;
 
1400
  mi_int2store(ptr,base->max_field_lengths);            ptr+= 2;
 
1401
  mi_int2store(ptr,base->pack_fields);                  ptr+= 2;
 
1402
  mi_int2store(ptr,base->extra_options)                 ptr+= 2;
 
1403
  mi_int2store(ptr,base->null_bytes);                   ptr+= 2;
 
1404
  mi_int2store(ptr,base->original_null_bytes);          ptr+= 2;
 
1405
  mi_int2store(ptr,base->field_offsets);                ptr+= 2;
 
1406
  mi_int2store(ptr,0);                                  ptr+= 2; /* reserved */
 
1407
  mi_int2store(ptr,base->block_size);                   ptr+= 2;
 
1408
  *ptr++= base->rec_reflength;
 
1409
  *ptr++= base->key_reflength;
 
1410
  *ptr++= base->keys;
 
1411
  *ptr++= base->auto_key;
 
1412
  *ptr++= base->born_transactional;
 
1413
  *ptr++= 0;                                    /* Reserved */
 
1414
  mi_int2store(ptr,base->pack_bytes);                   ptr+= 2;
 
1415
  mi_int2store(ptr,base->blobs);                        ptr+= 2;
 
1416
  mi_int2store(ptr,base->max_key_block_length);         ptr+= 2;
 
1417
  mi_int2store(ptr,base->max_key_length);               ptr+= 2;
 
1418
  mi_int2store(ptr,base->extra_alloc_bytes);            ptr+= 2;
 
1419
  *ptr++= base->extra_alloc_procent;
 
1420
  bzero(ptr,16);                                        ptr+= 16; /* extra */
 
1421
  DBUG_ASSERT((ptr - buff) == MARIA_BASE_INFO_SIZE);
 
1422
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
 
1423
}
 
1424
 
 
1425
 
 
1426
static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base)
 
1427
{
 
1428
  bmove(base->uuid, ptr, MY_UUID_SIZE);                 ptr+= MY_UUID_SIZE;
 
1429
  base->keystart= mi_sizekorr(ptr);                     ptr+= 8;
 
1430
  base->max_data_file_length= mi_sizekorr(ptr);         ptr+= 8;
 
1431
  base->max_key_file_length= mi_sizekorr(ptr);          ptr+= 8;
 
1432
  base->records=  (ha_rows) mi_sizekorr(ptr);           ptr+= 8;
 
1433
  base->reloc= (ha_rows) mi_sizekorr(ptr);              ptr+= 8;
 
1434
  base->mean_row_length= mi_uint4korr(ptr);             ptr+= 4;
 
1435
  base->reclength= mi_uint4korr(ptr);                   ptr+= 4;
 
1436
  base->pack_reclength= mi_uint4korr(ptr);              ptr+= 4;
 
1437
  base->min_pack_length= mi_uint4korr(ptr);             ptr+= 4;
 
1438
  base->max_pack_length= mi_uint4korr(ptr);             ptr+= 4;
 
1439
  base->min_block_length= mi_uint4korr(ptr);            ptr+= 4;
 
1440
  base->fields= mi_uint2korr(ptr);                      ptr+= 2;
 
1441
  base->fixed_not_null_fields= mi_uint2korr(ptr);       ptr+= 2;
 
1442
  base->fixed_not_null_fields_length= mi_uint2korr(ptr);ptr+= 2;
 
1443
  base->max_field_lengths= mi_uint2korr(ptr);           ptr+= 2;
 
1444
  base->pack_fields= mi_uint2korr(ptr);                 ptr+= 2;
 
1445
  base->extra_options= mi_uint2korr(ptr);               ptr+= 2;
 
1446
  base->null_bytes= mi_uint2korr(ptr);                  ptr+= 2;
 
1447
  base->original_null_bytes= mi_uint2korr(ptr);         ptr+= 2;
 
1448
  base->field_offsets= mi_uint2korr(ptr);               ptr+= 2;
 
1449
                                                        ptr+= 2;
 
1450
  base->block_size= mi_uint2korr(ptr);                  ptr+= 2;
 
1451
 
 
1452
  base->rec_reflength= *ptr++;
 
1453
  base->key_reflength= *ptr++;
 
1454
  base->keys=          *ptr++;
 
1455
  base->auto_key=      *ptr++;
 
1456
  base->born_transactional= *ptr++;
 
1457
  ptr++;
 
1458
  base->pack_bytes= mi_uint2korr(ptr);                  ptr+= 2;
 
1459
  base->blobs= mi_uint2korr(ptr);                       ptr+= 2;
 
1460
  base->max_key_block_length= mi_uint2korr(ptr);        ptr+= 2;
 
1461
  base->max_key_length= mi_uint2korr(ptr);              ptr+= 2;
 
1462
  base->extra_alloc_bytes= mi_uint2korr(ptr);           ptr+= 2;
 
1463
  base->extra_alloc_procent= *ptr++;
 
1464
  ptr+= 16;
 
1465
  return ptr;
 
1466
}
 
1467
 
 
1468
/*--------------------------------------------------------------------------
 
1469
  maria_keydef
 
1470
---------------------------------------------------------------------------*/
 
1471
 
 
1472
my_bool _ma_keydef_write(File file, MARIA_KEYDEF *keydef)
 
1473
{
 
1474
  uchar buff[MARIA_KEYDEF_SIZE];
 
1475
  uchar *ptr=buff;
 
1476
 
 
1477
  *ptr++= (uchar) keydef->keysegs;
 
1478
  *ptr++= keydef->key_alg;                      /* Rtree or Btree */
 
1479
  mi_int2store(ptr,keydef->flag);               ptr+= 2;
 
1480
  mi_int2store(ptr,keydef->block_length);       ptr+= 2;
 
1481
  mi_int2store(ptr,keydef->keylength);          ptr+= 2;
 
1482
  mi_int2store(ptr,keydef->minlength);          ptr+= 2;
 
1483
  mi_int2store(ptr,keydef->maxlength);          ptr+= 2;
 
1484
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
 
1485
}
 
1486
 
 
1487
uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef)
 
1488
{
 
1489
   keydef->keysegs      = (uint) *ptr++;
 
1490
   keydef->key_alg      = *ptr++;               /* Rtree or Btree */
 
1491
 
 
1492
   keydef->flag         = mi_uint2korr(ptr);    ptr+= 2;
 
1493
   keydef->block_length = mi_uint2korr(ptr);    ptr+= 2;
 
1494
   keydef->keylength    = mi_uint2korr(ptr);    ptr+= 2;
 
1495
   keydef->minlength    = mi_uint2korr(ptr);    ptr+= 2;
 
1496
   keydef->maxlength    = mi_uint2korr(ptr);    ptr+= 2;
 
1497
   keydef->underflow_block_length=keydef->block_length/3;
 
1498
   keydef->version      = 0;                    /* Not saved */
 
1499
   keydef->parser       = &ft_default_parser;
 
1500
   keydef->ftparser_nr  = 0;
 
1501
   return ptr;
 
1502
}
 
1503
 
 
1504
/***************************************************************************
 
1505
**  maria_keyseg
 
1506
***************************************************************************/
 
1507
 
 
1508
my_bool _ma_keyseg_write(File file, const HA_KEYSEG *keyseg)
 
1509
{
 
1510
  uchar buff[HA_KEYSEG_SIZE];
 
1511
  uchar *ptr=buff;
 
1512
  ulong pos;
 
1513
 
 
1514
  *ptr++= keyseg->type;
 
1515
  *ptr++= keyseg->language;
 
1516
  *ptr++= keyseg->null_bit;
 
1517
  *ptr++= keyseg->bit_start;
 
1518
  *ptr++= keyseg->bit_end;
 
1519
  *ptr++= keyseg->bit_length;
 
1520
  mi_int2store(ptr,keyseg->flag);       ptr+= 2;
 
1521
  mi_int2store(ptr,keyseg->length);     ptr+= 2;
 
1522
  mi_int4store(ptr,keyseg->start);      ptr+= 4;
 
1523
  pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
 
1524
  mi_int4store(ptr, pos);
 
1525
  ptr+=4;
 
1526
 
 
1527
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
 
1528
}
 
1529
 
 
1530
 
 
1531
uchar *_ma_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
 
1532
{
 
1533
   keyseg->type         = *ptr++;
 
1534
   keyseg->language     = *ptr++;
 
1535
   keyseg->null_bit     = *ptr++;
 
1536
   keyseg->bit_start    = *ptr++;
 
1537
   keyseg->bit_end      = *ptr++;
 
1538
   keyseg->bit_length   = *ptr++;
 
1539
   keyseg->flag         = mi_uint2korr(ptr);  ptr+= 2;
 
1540
   keyseg->length       = mi_uint2korr(ptr);  ptr+= 2;
 
1541
   keyseg->start        = mi_uint4korr(ptr);  ptr+= 4;
 
1542
   keyseg->null_pos     = mi_uint4korr(ptr);  ptr+= 4;
 
1543
   keyseg->charset=0;                           /* Will be filled in later */
 
1544
   if (keyseg->null_bit)
 
1545
     keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
 
1546
   else
 
1547
   {
 
1548
     keyseg->bit_pos= (uint16)keyseg->null_pos;
 
1549
     keyseg->null_pos= 0;
 
1550
   }
 
1551
   return ptr;
 
1552
}
 
1553
 
 
1554
/*--------------------------------------------------------------------------
 
1555
  maria_uniquedef
 
1556
---------------------------------------------------------------------------*/
 
1557
 
 
1558
my_bool _ma_uniquedef_write(File file, MARIA_UNIQUEDEF *def)
 
1559
{
 
1560
  uchar buff[MARIA_UNIQUEDEF_SIZE];
 
1561
  uchar *ptr=buff;
 
1562
 
 
1563
  mi_int2store(ptr,def->keysegs);               ptr+=2;
 
1564
  *ptr++=  (uchar) def->key;
 
1565
  *ptr++ = (uchar) def->null_are_equal;
 
1566
 
 
1567
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
 
1568
}
 
1569
 
 
1570
uchar *_ma_uniquedef_read(uchar *ptr, MARIA_UNIQUEDEF *def)
 
1571
{
 
1572
   def->keysegs = mi_uint2korr(ptr);
 
1573
   def->key     = ptr[2];
 
1574
   def->null_are_equal=ptr[3];
 
1575
   return ptr+4;                                /* 1 extra uchar */
 
1576
}
 
1577
 
 
1578
/***************************************************************************
 
1579
**  MARIA_COLUMNDEF
 
1580
***************************************************************************/
 
1581
 
 
1582
my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef)
 
1583
{
 
1584
  uchar buff[MARIA_COLUMNDEF_SIZE];
 
1585
  uchar *ptr=buff;
 
1586
 
 
1587
  mi_int2store(ptr,(ulong) columndef->column_nr); ptr+= 2;
 
1588
  mi_int2store(ptr,(ulong) columndef->offset);    ptr+= 2;
 
1589
  mi_int2store(ptr,columndef->type);              ptr+= 2;
 
1590
  mi_int2store(ptr,columndef->length);            ptr+= 2;
 
1591
  mi_int2store(ptr,columndef->fill_length);       ptr+= 2;
 
1592
  mi_int2store(ptr,columndef->null_pos);          ptr+= 2;
 
1593
  mi_int2store(ptr,columndef->empty_pos);         ptr+= 2;
 
1594
 
 
1595
  (*ptr++)= columndef->null_bit;
 
1596
  (*ptr++)= columndef->empty_bit;
 
1597
  ptr[0]= ptr[1]= ptr[2]= ptr[3]= 0;            ptr+= 4;  /* For future */
 
1598
  return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
 
1599
}
 
1600
 
 
1601
uchar *_ma_columndef_read(uchar *ptr, MARIA_COLUMNDEF *columndef)
 
1602
{
 
1603
  columndef->column_nr= mi_uint2korr(ptr);      ptr+= 2;
 
1604
  columndef->offset= mi_uint2korr(ptr);         ptr+= 2;
 
1605
  columndef->type=   mi_sint2korr(ptr);         ptr+= 2;
 
1606
  columndef->length= mi_uint2korr(ptr);         ptr+= 2;
 
1607
  columndef->fill_length= mi_uint2korr(ptr);    ptr+= 2;
 
1608
  columndef->null_pos= mi_uint2korr(ptr);       ptr+= 2;
 
1609
  columndef->empty_pos= mi_uint2korr(ptr);      ptr+= 2;
 
1610
  columndef->null_bit=  (uint8) *ptr++;
 
1611
  columndef->empty_bit= (uint8) *ptr++;
 
1612
  ptr+= 4;
 
1613
  return ptr;
 
1614
}
 
1615
 
 
1616
my_bool _ma_column_nr_write(File file, uint16 *offsets, uint columns)
 
1617
{
 
1618
  uchar *buff, *ptr, *end;
 
1619
  size_t size= columns*2;
 
1620
  my_bool res;
 
1621
 
 
1622
  if (!(buff= (uchar*) my_alloca(size)))
 
1623
    return 1;
 
1624
  for (ptr= buff, end= ptr + size; ptr < end ; ptr+= 2, offsets++)
 
1625
    int2store(ptr, *offsets);
 
1626
  res= my_write(file, buff, size, MYF(MY_NABP)) != 0;
 
1627
  my_afree(buff);
 
1628
  return res;
 
1629
}
 
1630
 
 
1631
 
 
1632
uchar *_ma_column_nr_read(uchar *ptr, uint16 *offsets, uint columns)
 
1633
{
 
1634
  uchar *end;
 
1635
  size_t size= columns*2;
 
1636
  for (end= ptr + size; ptr < end ; ptr+=2, offsets++)
 
1637
    *offsets= uint2korr(ptr);
 
1638
  return ptr;
 
1639
}
 
1640
 
 
1641
/**
 
1642
   @brief Set callbacks for data pages
 
1643
 
 
1644
   @note
 
1645
   We don't use pagecache_file_init here, as we want to keep the
 
1646
   code readable
 
1647
*/
 
1648
 
 
1649
void _ma_set_data_pagecache_callbacks(PAGECACHE_FILE *file,
 
1650
                                      MARIA_SHARE *share)
 
1651
{
 
1652
  file->callback_data= (uchar*) share;
 
1653
  file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
 
1654
 
 
1655
  if (share->temporary)
 
1656
  {
 
1657
    file->read_callback=  &maria_page_crc_check_none;
 
1658
    file->write_callback= &maria_page_filler_set_none;
 
1659
  }
 
1660
  else
 
1661
  {
 
1662
    file->read_callback=  &maria_page_crc_check_data;
 
1663
    if (share->options & HA_OPTION_PAGE_CHECKSUM)
 
1664
      file->write_callback= &maria_page_crc_set_normal;
 
1665
    else
 
1666
      file->write_callback= &maria_page_filler_set_normal;
 
1667
    if (share->now_transactional)
 
1668
      file->flush_log_callback= maria_flush_log_for_page;
 
1669
  }
 
1670
}
 
1671
 
 
1672
 
 
1673
/**
 
1674
   @brief Set callbacks for index pages
 
1675
 
 
1676
   @note
 
1677
   We don't use pagecache_file_init here, as we want to keep the
 
1678
   code readable
 
1679
*/
 
1680
 
 
1681
void _ma_set_index_pagecache_callbacks(PAGECACHE_FILE *file,
 
1682
                                       MARIA_SHARE *share)
 
1683
{
 
1684
  file->callback_data= (uchar*) share;
 
1685
  file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
 
1686
  file->write_fail= maria_page_write_failure;
 
1687
 
 
1688
  if (share->temporary)
 
1689
  {
 
1690
    file->read_callback=  &maria_page_crc_check_none;
 
1691
    file->write_callback= &maria_page_filler_set_none;
 
1692
  }
 
1693
  else
 
1694
  {
 
1695
    file->read_callback=  &maria_page_crc_check_index;
 
1696
    if (share->options & HA_OPTION_PAGE_CHECKSUM)
 
1697
      file->write_callback= &maria_page_crc_set_index;
 
1698
    else
 
1699
      file->write_callback= &maria_page_filler_set_normal;
 
1700
 
 
1701
    if (share->now_transactional)
 
1702
      file->flush_log_callback= maria_flush_log_for_page;
 
1703
  }
 
1704
}
 
1705
 
 
1706
 
 
1707
/**************************************************************************
 
1708
 Open data file
 
1709
  We can't use dup() here as the data file descriptors need to have different
 
1710
  active seek-positions.
 
1711
 
 
1712
  The argument file_to_dup is here for the future if there would on some OS
 
1713
  exist a dup()-like call that would give us two different file descriptors.
 
1714
*************************************************************************/
 
1715
 
 
1716
int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share,
 
1717
                      File file_to_dup __attribute__((unused)))
 
1718
{
 
1719
  info->dfile.file= share->bitmap.file.file=
 
1720
    my_open(share->data_file_name, share->mode | O_SHARE,
 
1721
            MYF(MY_WME));
 
1722
  return info->dfile.file >= 0 ? 0 : 1;
 
1723
}
 
1724
 
 
1725
 
 
1726
int _ma_open_keyfile(MARIA_SHARE *share)
 
1727
{
 
1728
  /*
 
1729
    Modifications to share->kfile should be under intern_lock to protect
 
1730
    against a concurrent checkpoint.
 
1731
  */
 
1732
  pthread_mutex_lock(&share->intern_lock);
 
1733
  share->kfile.file= my_open(share->unique_file_name,
 
1734
                             share->mode | O_SHARE,
 
1735
                             MYF(MY_WME));
 
1736
  pthread_mutex_unlock(&share->intern_lock);
 
1737
  return (share->kfile.file < 0);
 
1738
}
 
1739
 
 
1740
 
 
1741
/*
 
1742
  Disable all indexes.
 
1743
 
 
1744
  SYNOPSIS
 
1745
    maria_disable_indexes()
 
1746
    info        A pointer to the MARIA storage engine MARIA_HA struct.
 
1747
 
 
1748
  DESCRIPTION
 
1749
    Disable all indexes.
 
1750
 
 
1751
  RETURN
 
1752
    0  ok
 
1753
*/
 
1754
 
 
1755
int maria_disable_indexes(MARIA_HA *info)
 
1756
{
 
1757
  MARIA_SHARE *share= info->s;
 
1758
 
 
1759
  maria_clear_all_keys_active(share->state.key_map);
 
1760
  return 0;
 
1761
}
 
1762
 
 
1763
 
 
1764
/*
 
1765
  Enable all indexes
 
1766
 
 
1767
  SYNOPSIS
 
1768
    maria_enable_indexes()
 
1769
    info        A pointer to the MARIA storage engine MARIA_HA struct.
 
1770
 
 
1771
  DESCRIPTION
 
1772
    Enable all indexes. The indexes might have been disabled
 
1773
    by maria_disable_index() before.
 
1774
    The function works only if both data and indexes are empty,
 
1775
    otherwise a repair is required.
 
1776
    To be sure, call handler::delete_all_rows() before.
 
1777
 
 
1778
  RETURN
 
1779
    0  ok
 
1780
    HA_ERR_CRASHED data or index is non-empty.
 
1781
*/
 
1782
 
 
1783
int maria_enable_indexes(MARIA_HA *info)
 
1784
{
 
1785
  int error= 0;
 
1786
  MARIA_SHARE *share= info->s;
 
1787
  DBUG_ENTER("maria_enable_indexes");
 
1788
 
 
1789
  if ((share->state.state.data_file_length !=
 
1790
       (share->data_file_type == BLOCK_RECORD ? share->block_size : 0)) ||
 
1791
      (share->state.state.key_file_length != share->base.keystart))
 
1792
  {
 
1793
    DBUG_PRINT("error", ("data_file_length: %lu  key_file_length: %lu",
 
1794
                         (ulong) share->state.state.data_file_length,
 
1795
                         (ulong) share->state.state.key_file_length));
 
1796
    maria_print_error(info->s, HA_ERR_CRASHED);
 
1797
    error= HA_ERR_CRASHED;
 
1798
  }
 
1799
  else
 
1800
    maria_set_all_keys_active(share->state.key_map, share->base.keys);
 
1801
  DBUG_RETURN(error);
 
1802
}
 
1803
 
 
1804
 
 
1805
/*
 
1806
  Test if indexes are disabled.
 
1807
 
 
1808
  SYNOPSIS
 
1809
    maria_indexes_are_disabled()
 
1810
    info        A pointer to the MARIA storage engine MARIA_HA struct.
 
1811
 
 
1812
  DESCRIPTION
 
1813
    Test if indexes are disabled.
 
1814
 
 
1815
  RETURN
 
1816
    0  indexes are not disabled
 
1817
    1  all indexes are disabled
 
1818
    2  non-unique indexes are disabled
 
1819
*/
 
1820
 
 
1821
int maria_indexes_are_disabled(MARIA_HA *info)
 
1822
{
 
1823
  MARIA_SHARE *share= info->s;
 
1824
 
 
1825
  /*
 
1826
    No keys or all are enabled. keys is the number of keys. Left shifted
 
1827
    gives us only one bit set. When decreased by one, gives us all all bits
 
1828
    up to this one set and it gets unset.
 
1829
  */
 
1830
  if (!share->base.keys ||
 
1831
      (maria_is_all_keys_active(share->state.key_map, share->base.keys)))
 
1832
    return 0;
 
1833
 
 
1834
  /* All are disabled */
 
1835
  if (maria_is_any_key_active(share->state.key_map))
 
1836
    return 1;
 
1837
 
 
1838
  /*
 
1839
    We have keys. Some enabled, some disabled.
 
1840
    Don't check for any non-unique disabled but return directly 2
 
1841
  */
 
1842
  return 2;
 
1843
}
 
1844
 
 
1845
 
 
1846
static my_bool maria_scan_init_dummy(MARIA_HA *info __attribute__((unused)))
 
1847
{
 
1848
  return 0;
 
1849
}
 
1850
 
 
1851
static void maria_scan_end_dummy(MARIA_HA *info __attribute__((unused)))
 
1852
{
 
1853
}
 
1854
 
 
1855
static my_bool maria_once_init_dummy(MARIA_SHARE *share
 
1856
                                     __attribute__((unused)),
 
1857
                                     File dfile __attribute__((unused)))
 
1858
{
 
1859
  return 0;
 
1860
}
 
1861
 
 
1862
static my_bool maria_once_end_dummy(MARIA_SHARE *share __attribute__((unused)))
 
1863
{
 
1864
  return 0;
 
1865
}