1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 */
16
/* open a isam-database */
23
#if defined(MSDOS) || defined(__WIN__)
27
#include <process.h> /* Prototype for getpid */
34
static void setup_key_functions(MI_KEYDEF *keyinfo);
35
#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
39
#define disk_pos_assert(pos, end_pos) \
42
my_errno=HA_ERR_CRASHED; \
47
/******************************************************************************
48
** Return the shared struct if the table is already open.
49
** In MySQL the server will handle version issues.
50
******************************************************************************/
52
MI_INFO *test_if_reopen(char *filename)
56
for (pos=myisam_open_list ; pos ; pos=pos->next)
58
MI_INFO *info=(MI_INFO*) pos->data;
59
MYISAM_SHARE *share=info->s;
60
if (!strcmp(share->unique_file_name,filename) && share->last_version)
67
/******************************************************************************
68
open a MyISAM database.
69
See my_base.h for the handle_locking argument
70
if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
71
is marked crashed or if we are not using locking and the table doesn't
72
have an open count of 0.
73
******************************************************************************/
75
MI_INFO *mi_open(const char *name, int mode, uint open_flags)
77
int lock_error,kfile,open_mode,save_errno,have_rtree=0;
78
uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
79
key_parts,unique_key_parts,fulltext_keys,uniques;
80
char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
82
uchar *disk_cache, *disk_pos, *end_pos;
83
MI_INFO info,*m_info,*old_info;
84
MYISAM_SHARE share_buff,*share;
85
ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
86
my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
87
ulonglong max_key_file_length, max_data_file_length;
88
DBUG_ENTER("mi_open");
93
head_length=sizeof(share_buff.state.header);
94
bzero((uchar*) &info,sizeof(info));
96
my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,
97
MY_UNPACK_FILENAME),MYF(0));
98
pthread_mutex_lock(&THR_LOCK_myisam);
99
if (!(old_info=test_if_reopen(name_buff)))
102
bzero((uchar*) &share_buff,sizeof(share_buff));
103
share_buff.state.rec_per_key_part=rec_per_key_part;
104
share_buff.state.key_root=key_root;
105
share_buff.state.key_del=key_del;
106
share_buff.key_cache= multi_key_cache_search((uchar*) name_buff,
109
DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
110
if (strstr(name, "/t1"))
112
my_errno= HA_ERR_CRASHED;
115
if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
117
if ((errno != EROFS && errno != EACCES) ||
119
(kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
122
share->mode=open_mode;
124
if (my_read(kfile, share->state.header.file_version, head_length,
127
my_errno= HA_ERR_NOT_A_TABLE;
130
if (memcmp((uchar*) share->state.header.file_version,
131
(uchar*) myisam_file_magic, 4))
133
DBUG_PRINT("error",("Wrong header in %s",name_buff));
134
DBUG_DUMP("error_dump",(uchar*) share->state.header.file_version,
136
my_errno=HA_ERR_NOT_A_TABLE;
139
share->options= mi_uint2korr(share->state.header.options);
141
~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
142
HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
143
HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
144
HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
145
HA_OPTION_RELIES_ON_SQL_LAYER))
147
DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
148
my_errno=HA_ERR_OLD_FILE;
151
if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
152
! (open_flags & HA_OPEN_FROM_SQL_LAYER))
154
DBUG_PRINT("error", ("table cannot be openned from non-sql layer"));
155
my_errno= HA_ERR_UNSUPPORTED;
158
/* Don't call realpath() if the name can't be a link */
159
if (!strcmp(name_buff, org_name) ||
160
my_readlink(index_name, org_name, MYF(0)) == -1)
161
(void) strmov(index_name, org_name);
162
*strrchr(org_name, '.')= '\0';
163
(void) fn_format(data_name,org_name,"",MI_NAME_DEXT,
164
MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
166
info_length=mi_uint2korr(share->state.header.header_length);
167
base_pos=mi_uint2korr(share->state.header.base_pos);
168
if (!(disk_cache= (uchar*) my_alloca(info_length+128)))
173
end_pos=disk_cache+info_length;
176
VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
177
if (!(open_flags & HA_OPEN_TMP_TABLE))
179
if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
180
MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ?
181
0 : MY_DONT_WAIT))) &&
182
!(open_flags & HA_OPEN_IGNORE_IF_LOCKED))
186
if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
188
my_errno=HA_ERR_CRASHED;
191
len=mi_uint2korr(share->state.header.state_info_length);
192
keys= (uint) share->state.header.keys;
193
uniques= (uint) share->state.header.uniques;
194
fulltext_keys= (uint) share->state.header.fulltext_keys;
195
key_parts= mi_uint2korr(share->state.header.key_parts);
196
unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
197
if (len != MI_STATE_INFO_SIZE)
199
DBUG_PRINT("warning",
200
("saved_state_info_length: %d state_info_length: %d",
201
len,MI_STATE_INFO_SIZE));
203
share->state_diff_length=len-MI_STATE_INFO_SIZE;
205
mi_state_info_read(disk_cache, &share->state);
206
len= mi_uint2korr(share->state.header.base_info_length);
207
if (len != MI_BASE_INFO_SIZE)
209
DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
210
len,MI_BASE_INFO_SIZE));
212
disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
213
share->state.state_length=base_pos;
215
if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
216
((share->state.changed & STATE_CRASHED) ||
217
((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
218
(my_disable_locking && share->state.open_count))))
220
DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u "
221
"changed: %u open_count: %u !locking: %d",
222
open_flags, share->state.changed,
223
share->state.open_count, my_disable_locking));
224
my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
225
HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
230
if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
232
my_errno=HA_ERR_CRASHED;
236
key_parts+=fulltext_keys*FT_SEGS;
237
if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
238
key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
240
DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts));
241
my_errno=HA_ERR_UNSUPPORTED;
245
/* Correct max_file_length based on length of sizeof(off_t) */
246
max_data_file_length=
247
(share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
248
(((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
249
(mi_safe_mul(share->base.pack_reclength,
250
(ulonglong) 1 << (share->base.rec_reflength*8))-1);
252
mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
253
((ulonglong) 1 << (share->base.key_reflength*8))-1);
254
#if SIZEOF_OFF_T == 4
255
set_if_smaller(max_data_file_length, INT_MAX32);
256
set_if_smaller(max_key_file_length, INT_MAX32);
258
#if USE_RAID && SYSTEM_SIZEOF_OFF_T == 4
259
set_if_smaller(max_key_file_length, INT_MAX32);
260
if (!share->base.raid_type)
262
set_if_smaller(max_data_file_length, INT_MAX32);
266
set_if_smaller(max_data_file_length,
267
(ulonglong) share->base.raid_chunks << 31);
269
#elif !defined(USE_RAID)
270
if (share->base.raid_type)
272
DBUG_PRINT("error",("Table uses RAID but we don't have RAID support"));
273
my_errno=HA_ERR_UNSUPPORTED;
277
share->base.max_data_file_length=(my_off_t) max_data_file_length;
278
share->base.max_key_file_length=(my_off_t) max_key_file_length;
280
if (share->options & HA_OPTION_COMPRESS_RECORD)
281
share->base.max_key_length+=2; /* For safety */
283
/* Add space for node pointer */
284
share->base.max_key_length+= share->base.key_reflength;
286
if (!my_multi_malloc(MY_WME,
287
&share,sizeof(*share),
288
&share->state.rec_per_key_part,sizeof(long)*key_parts,
289
&share->keyinfo,keys*sizeof(MI_KEYDEF),
290
&share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
292
(key_parts+unique_key_parts+keys+uniques) *
295
(share->base.fields+1)*sizeof(MI_COLUMNDEF),
296
&share->blobs,sizeof(MI_BLOB)*share->base.blobs,
297
&share->unique_file_name,strlen(name_buff)+1,
298
&share->index_file_name,strlen(index_name)+1,
299
&share->data_file_name,strlen(data_name)+1,
300
&share->state.key_root,keys*sizeof(my_off_t),
301
&share->state.key_del,
302
(share->state.header.max_block_size_index*sizeof(my_off_t)),
304
&share->key_root_lock,sizeof(rw_lock_t)*keys,
306
&share->mmap_lock,sizeof(rw_lock_t),
311
memcpy((char*) share->state.rec_per_key_part,
312
(char*) rec_per_key_part, sizeof(long)*key_parts);
313
memcpy((char*) share->state.key_root,
314
(char*) key_root, sizeof(my_off_t)*keys);
315
memcpy((char*) share->state.key_del,
316
(char*) key_del, (sizeof(my_off_t) *
317
share->state.header.max_block_size_index));
318
strmov(share->unique_file_name, name_buff);
319
share->unique_name_length= strlen(name_buff);
320
strmov(share->index_file_name, index_name);
321
strmov(share->data_file_name, data_name);
323
share->blocksize=min(IO_SIZE,myisam_block_size);
325
HA_KEYSEG *pos=share->keyparts;
326
for (i=0 ; i < keys ; i++)
328
share->keyinfo[i].share= share;
329
disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
330
disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
332
if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE)
334
set_if_smaller(share->blocksize,share->keyinfo[i].block_length);
335
share->keyinfo[i].seg=pos;
336
for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
338
disk_pos=mi_keyseg_read(disk_pos, pos);
339
if (pos->flag & HA_BLOB_PART &&
340
! (share->options & (HA_OPTION_COMPRESS_RECORD |
341
HA_OPTION_PACK_RECORD)))
343
my_errno= HA_ERR_CRASHED;
346
if (pos->type == HA_KEYTYPE_TEXT ||
347
pos->type == HA_KEYTYPE_VARTEXT1 ||
348
pos->type == HA_KEYTYPE_VARTEXT2)
351
pos->charset=default_charset_info;
352
else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
354
my_errno=HA_ERR_UNKNOWN_CHARSET;
358
else if (pos->type == HA_KEYTYPE_BINARY)
359
pos->charset= &my_charset_bin;
361
if (share->keyinfo[i].flag & HA_SPATIAL)
364
uint sp_segs=SPDIMS*2;
365
share->keyinfo[i].seg=pos-sp_segs;
366
share->keyinfo[i].keysegs--;
368
my_errno=HA_ERR_UNSUPPORTED;
372
else if (share->keyinfo[i].flag & HA_FULLTEXT)
375
{ /* 4.0 compatibility code, to be removed in 5.0 */
376
share->keyinfo[i].seg=pos-FT_SEGS;
377
share->keyinfo[i].keysegs-=FT_SEGS;
382
share->keyinfo[i].seg=pos;
383
for (k=0; k < FT_SEGS; k++)
386
pos[0].language= pos[-1].language;
387
if (!(pos[0].charset= pos[-1].charset))
389
my_errno=HA_ERR_CRASHED;
395
if (!share->ft2_keyinfo.seg)
397
memcpy(& share->ft2_keyinfo, & share->keyinfo[i], sizeof(MI_KEYDEF));
398
share->ft2_keyinfo.keysegs=1;
399
share->ft2_keyinfo.flag=0;
400
share->ft2_keyinfo.keylength=
401
share->ft2_keyinfo.minlength=
402
share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
403
share->ft2_keyinfo.seg=pos-1;
404
share->ft2_keyinfo.end=pos;
405
setup_key_functions(& share->ft2_keyinfo);
408
setup_key_functions(share->keyinfo+i);
409
share->keyinfo[i].end=pos;
410
pos->type=HA_KEYTYPE_END; /* End */
411
pos->length=share->base.rec_reflength;
413
pos->flag=0; /* For purify */
416
for (i=0 ; i < uniques ; i++)
418
disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
419
disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
420
HA_KEYSEG_SIZE, end_pos);
421
share->uniqueinfo[i].seg=pos;
422
for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
424
disk_pos=mi_keyseg_read(disk_pos, pos);
425
if (pos->type == HA_KEYTYPE_TEXT ||
426
pos->type == HA_KEYTYPE_VARTEXT1 ||
427
pos->type == HA_KEYTYPE_VARTEXT2)
430
pos->charset=default_charset_info;
431
else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
433
my_errno=HA_ERR_UNKNOWN_CHARSET;
438
share->uniqueinfo[i].end=pos;
439
pos->type=HA_KEYTYPE_END; /* End */
447
disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
448
for (i=j=offset=0 ; i < share->base.fields ; i++)
450
disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
451
share->rec[i].pack_type=0;
452
share->rec[i].huff_tree=0;
453
share->rec[i].offset=offset;
454
if (share->rec[i].type == (int) FIELD_BLOB)
456
share->blobs[j].pack_length=
457
share->rec[i].length-portable_sizeof_char_ptr;
458
share->blobs[j].offset=offset;
461
offset+=share->rec[i].length;
463
share->rec[i].type=(int) FIELD_LAST; /* End marker */
464
if (offset > share->base.reclength)
466
/* purecov: begin inspected */
467
my_errno= HA_ERR_CRASHED;
474
VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
475
lock_error=1; /* Database unlocked */
478
if (mi_open_datafile(&info, share, -1))
483
share->this_process=(ulong) getpid();
484
share->last_process= share->state.process;
485
share->base.key_parts=key_parts;
486
share->base.all_key_parts=key_parts+unique_key_parts;
487
if (!(share->last_version=share->state.version))
488
share->last_version=1; /* Safety */
489
share->rec_reflength=share->base.rec_reflength; /* May be changed */
490
share->base.margin_key_file_length=(share->base.max_key_file_length -
491
(keys ? MI_INDEX_BLOCK_MARGIN *
492
share->blocksize * keys : 0));
493
share->blocksize=min(IO_SIZE,myisam_block_size);
494
share->data_file_type=STATIC_RECORD;
495
if (share->options & HA_OPTION_COMPRESS_RECORD)
497
share->data_file_type = COMPRESSED_RECORD;
498
share->options|= HA_OPTION_READ_ONLY_DATA;
500
if (_mi_read_pack_info(&info,
502
test(!(share->options &
503
(HA_OPTION_PACK_RECORD |
504
HA_OPTION_TEMP_COMPRESS_RECORD)))))
507
else if (share->options & HA_OPTION_PACK_RECORD)
508
share->data_file_type = DYNAMIC_RECORD;
509
my_afree(disk_cache);
510
mi_setup_functions(share);
511
share->is_log_table= FALSE;
513
thr_lock_init(&share->lock);
514
VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
515
for (i=0; i<keys; i++)
516
VOID(my_rwlock_init(&share->key_root_lock[i], NULL));
517
VOID(my_rwlock_init(&share->mmap_lock, NULL));
518
if (!thr_lock_inited)
520
/* Probably a single threaded program; Don't use concurrent inserts */
521
myisam_concurrent_insert=0;
523
else if (myisam_concurrent_insert)
525
share->concurrent_insert=
526
((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
527
HA_OPTION_COMPRESS_RECORD |
528
HA_OPTION_TEMP_COMPRESS_RECORD)) ||
529
(open_flags & HA_OPEN_TMP_TABLE) ||
531
if (share->concurrent_insert)
533
share->lock.get_status=mi_get_status;
534
share->lock.copy_status=mi_copy_status;
535
share->lock.update_status=mi_update_status;
536
share->lock.restore_status= mi_restore_status;
537
share->lock.check_status=mi_check_status;
542
Memory mapping can only be requested after initializing intern_lock.
544
if (open_flags & HA_OPEN_MMAP)
547
mi_extra(&info, HA_EXTRA_MMAP, 0);
553
if (mode == O_RDWR && share->mode == O_RDONLY)
555
my_errno=EACCES; /* Can't open in write mode */
558
if (mi_open_datafile(&info, share, old_info->dfile))
561
have_rtree= old_info->rtree_recursion_state != NULL;
564
/* alloc and set up private structure parts */
565
if (!my_multi_malloc(MY_WME,
566
&m_info,sizeof(MI_INFO),
567
&info.blobs,sizeof(MI_BLOB)*share->base.blobs,
568
&info.buff,(share->base.max_key_block_length*2+
569
share->base.max_key_length),
570
&info.lastkey,share->base.max_key_length*3+1,
571
&info.first_mbr_key, share->base.max_key_length,
572
&info.filename,strlen(name)+1,
573
&info.rtree_recursion_state,have_rtree ? 1024 : 0,
579
info.rtree_recursion_state= NULL;
581
strmov(info.filename,name);
582
memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
583
info.lastkey2=info.lastkey+share->base.max_key_length;
586
info.lastpos= HA_OFFSET_ERROR;
587
info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
588
info.opt_flag=READ_CHECK_USED;
589
info.this_unique= (ulong) info.dfile; /* Uniq number in process */
590
if (share->data_file_type == COMPRESSED_RECORD)
591
info.this_unique= share->state.unique;
592
info.this_loop=0; /* Update counter */
593
info.last_unique= share->state.unique;
594
info.last_loop= share->state.update_count;
595
if (mode == O_RDONLY)
596
share->options|=HA_OPTION_READ_ONLY_DATA;
597
info.lock_type=F_UNLCK;
603
pthread_mutex_lock(&share->intern_lock);
604
info.read_record=share->read_record;
606
share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
607
if (share->options & HA_OPTION_READ_ONLY_DATA)
609
info.lock_type=F_RDLCK;
613
if ((open_flags & HA_OPEN_TMP_TABLE) ||
614
(share->options & HA_OPTION_TMP_TABLE))
616
share->temporary=share->delay_key_write=1;
617
share->write_flag=MYF(MY_NABP);
618
share->w_locks++; /* We don't have to update status */
620
info.lock_type=F_WRLCK;
622
if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) ||
623
(share->options & HA_OPTION_DELAY_KEY_WRITE)) &&
624
myisam_delay_key_write)
625
share->delay_key_write=1;
626
info.state= &share->state.state; /* Change global values by default */
627
pthread_mutex_unlock(&share->intern_lock);
629
/* Allocate buffer for one record */
631
/* prerequisites: bzero(info) && info->s=share; are met. */
632
if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff))
634
bzero(info.rec_buff, mi_get_rec_buff_len(&info, info.rec_buff));
638
thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
640
m_info->open_list.data=(void*) m_info;
641
myisam_open_list=list_add(myisam_open_list,&m_info->open_list);
643
pthread_mutex_unlock(&THR_LOCK_myisam);
644
if (myisam_log_file >= 0)
646
intern_filename(name_buff,share->index_file_name);
647
_myisam_log(MI_LOG_OPEN, m_info, (uchar*) name_buff, strlen(name_buff));
652
save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
653
if ((save_errno == HA_ERR_CRASHED) ||
654
(save_errno == HA_ERR_CRASHED_ON_USAGE) ||
655
(save_errno == HA_ERR_CRASHED_ON_REPAIR))
656
mi_report_error(save_errno, name);
659
my_free((uchar*) m_info,MYF(0));
662
VOID(my_close(info.dfile,MYF(0)));
664
break; /* Don't remove open table */
667
my_free((uchar*) share,MYF(0));
671
VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
674
my_afree(disk_cache);
677
VOID(my_close(kfile,MYF(0)));
683
pthread_mutex_unlock(&THR_LOCK_myisam);
689
uchar *mi_alloc_rec_buff(MI_INFO *info, ulong length, uchar **buf)
692
uint32 old_length= 0;
694
if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
696
uchar *newptr = *buf;
698
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
699
if (length == (ulong) -1)
701
if (info->s->options & HA_OPTION_COMPRESS_RECORD)
702
length= max(info->s->base.pack_reclength, info->s->max_pack_length);
704
length= info->s->base.pack_reclength;
705
length= max(length, info->s->base.max_key_length);
706
/* Avoid unnecessary realloc */
707
if (newptr && length == old_length)
711
extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
712
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
713
MI_REC_BUFF_OFFSET : 0);
715
newptr-= MI_REC_BUFF_OFFSET;
716
if (!(newptr=(uchar*) my_realloc((uchar*)newptr, length+extra+8,
717
MYF(MY_ALLOW_ZERO_PTR))))
719
*((uint32 *) newptr)= (uint32) length;
720
*buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
726
ulonglong mi_safe_mul(ulonglong a, ulonglong b)
728
ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */
730
if (!a || max_val / a < b)
735
/* Set up functions in structs */
737
void mi_setup_functions(register MYISAM_SHARE *share)
739
if (share->options & HA_OPTION_COMPRESS_RECORD)
741
share->read_record=_mi_read_pack_record;
742
share->read_rnd=_mi_read_rnd_pack_record;
743
if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
744
share->calc_checksum=0; /* No checksum */
745
else if (share->options & HA_OPTION_PACK_RECORD)
746
share->calc_checksum= mi_checksum;
748
share->calc_checksum= mi_static_checksum;
750
else if (share->options & HA_OPTION_PACK_RECORD)
752
share->read_record=_mi_read_dynamic_record;
753
share->read_rnd=_mi_read_rnd_dynamic_record;
754
share->delete_record=_mi_delete_dynamic_record;
755
share->compare_record=_mi_cmp_dynamic_record;
756
share->compare_unique=_mi_cmp_dynamic_unique;
757
share->calc_checksum= mi_checksum;
759
/* add bits used to pack data to pack_reclength for faster allocation */
760
share->base.pack_reclength+= share->base.pack_bits;
761
if (share->base.blobs)
763
share->update_record=_mi_update_blob_record;
764
share->write_record=_mi_write_blob_record;
768
share->write_record=_mi_write_dynamic_record;
769
share->update_record=_mi_update_dynamic_record;
774
share->read_record=_mi_read_static_record;
775
share->read_rnd=_mi_read_rnd_static_record;
776
share->delete_record=_mi_delete_static_record;
777
share->compare_record=_mi_cmp_static_record;
778
share->update_record=_mi_update_static_record;
779
share->write_record=_mi_write_static_record;
780
share->compare_unique=_mi_cmp_static_unique;
781
share->calc_checksum= mi_static_checksum;
783
share->file_read= mi_nommap_pread;
784
share->file_write= mi_nommap_pwrite;
785
if (!(share->options & HA_OPTION_CHECKSUM))
786
share->calc_checksum=0;
791
static void setup_key_functions(register MI_KEYDEF *keyinfo)
793
if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
795
#ifdef HAVE_RTREE_KEYS
796
keyinfo->ck_insert = rtree_insert;
797
keyinfo->ck_delete = rtree_delete;
799
DBUG_ASSERT(0); /* mi_open should check it never happens */
804
keyinfo->ck_insert = _mi_ck_write;
805
keyinfo->ck_delete = _mi_ck_delete;
807
if (keyinfo->flag & HA_BINARY_PACK_KEY)
808
{ /* Simple prefix compression */
809
keyinfo->bin_search=_mi_seq_search;
810
keyinfo->get_key=_mi_get_binary_pack_key;
811
keyinfo->pack_key=_mi_calc_bin_pack_key_length;
812
keyinfo->store_key=_mi_store_bin_pack_key;
814
else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
816
keyinfo->get_key= _mi_get_pack_key;
817
if (keyinfo->seg[0].flag & HA_PACK_KEY)
818
{ /* Prefix compression */
820
_mi_prefix_search() compares end-space against ASCII blank (' ').
821
It cannot be used for character sets, that do not encode the
822
blank character like ASCII does. UCS2 is an example. All
823
character sets with a fixed width > 1 or a mimimum width > 1
824
cannot represent blank like ASCII does. In these cases we have
825
to use _mi_seq_search() for the search.
827
if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
828
(keyinfo->seg->flag & HA_NULL_PART) ||
829
(keyinfo->seg->charset->mbminlen > 1))
830
keyinfo->bin_search=_mi_seq_search;
832
keyinfo->bin_search=_mi_prefix_search;
833
keyinfo->pack_key=_mi_calc_var_pack_key_length;
834
keyinfo->store_key=_mi_store_var_pack_key;
838
keyinfo->bin_search=_mi_seq_search;
839
keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
840
keyinfo->store_key=_mi_store_static_key;
845
keyinfo->bin_search=_mi_bin_search;
846
keyinfo->get_key=_mi_get_static_key;
847
keyinfo->pack_key=_mi_calc_static_key_length;
848
keyinfo->store_key=_mi_store_static_key;
855
Function to save and store the header in the index file (.MYI)
858
uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
860
uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
862
uint i, keys= (uint) state->header.keys,
863
key_blocks=state->header.max_block_size_index;
864
DBUG_ENTER("mi_state_info_write");
866
memcpy_fixed(ptr,&state->header,sizeof(state->header));
867
ptr+=sizeof(state->header);
869
/* open_count must be first because of _mi_mark_file_changed ! */
870
mi_int2store(ptr,state->open_count); ptr +=2;
871
*ptr++= (uchar)state->changed; *ptr++= state->sortkey;
872
mi_rowstore(ptr,state->state.records); ptr +=8;
873
mi_rowstore(ptr,state->state.del); ptr +=8;
874
mi_rowstore(ptr,state->split); ptr +=8;
875
mi_sizestore(ptr,state->dellink); ptr +=8;
876
mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
877
mi_sizestore(ptr,state->state.data_file_length); ptr +=8;
878
mi_sizestore(ptr,state->state.empty); ptr +=8;
879
mi_sizestore(ptr,state->state.key_empty); ptr +=8;
880
mi_int8store(ptr,state->auto_increment); ptr +=8;
881
mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8;
882
mi_int4store(ptr,state->process); ptr +=4;
883
mi_int4store(ptr,state->unique); ptr +=4;
884
mi_int4store(ptr,state->status); ptr +=4;
885
mi_int4store(ptr,state->update_count); ptr +=4;
887
ptr+=state->state_diff_length;
889
for (i=0; i < keys; i++)
891
mi_sizestore(ptr,state->key_root[i]); ptr +=8;
893
for (i=0; i < key_blocks; i++)
895
mi_sizestore(ptr,state->key_del[i]); ptr +=8;
897
if (pWrite & 2) /* From isamchk */
899
uint key_parts= mi_uint2korr(state->header.key_parts);
900
mi_int4store(ptr,state->sec_index_changed); ptr +=4;
901
mi_int4store(ptr,state->sec_index_used); ptr +=4;
902
mi_int4store(ptr,state->version); ptr +=4;
903
mi_int8store(ptr,state->key_map); ptr +=8;
904
mi_int8store(ptr,(ulonglong) state->create_time); ptr +=8;
905
mi_int8store(ptr,(ulonglong) state->recover_time); ptr +=8;
906
mi_int8store(ptr,(ulonglong) state->check_time); ptr +=8;
907
mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8;
908
for (i=0 ; i < key_parts ; i++)
910
mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4;
915
DBUG_RETURN(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
916
MYF(MY_NABP | MY_THREADSAFE)) != 0);
917
DBUG_RETURN(my_write(file, buff, (size_t) (ptr-buff),
922
uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state)
924
uint i,keys,key_parts,key_blocks;
925
memcpy_fixed(&state->header,ptr, sizeof(state->header));
926
ptr +=sizeof(state->header);
927
keys=(uint) state->header.keys;
928
key_parts=mi_uint2korr(state->header.key_parts);
929
key_blocks=state->header.max_block_size_index;
931
state->open_count = mi_uint2korr(ptr); ptr +=2;
932
state->changed= *ptr++;
933
state->sortkey = (uint) *ptr++;
934
state->state.records= mi_rowkorr(ptr); ptr +=8;
935
state->state.del = mi_rowkorr(ptr); ptr +=8;
936
state->split = mi_rowkorr(ptr); ptr +=8;
937
state->dellink= mi_sizekorr(ptr); ptr +=8;
938
state->state.key_file_length = mi_sizekorr(ptr); ptr +=8;
939
state->state.data_file_length= mi_sizekorr(ptr); ptr +=8;
940
state->state.empty = mi_sizekorr(ptr); ptr +=8;
941
state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
942
state->auto_increment=mi_uint8korr(ptr); ptr +=8;
943
state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8;
944
state->process= mi_uint4korr(ptr); ptr +=4;
945
state->unique = mi_uint4korr(ptr); ptr +=4;
946
state->status = mi_uint4korr(ptr); ptr +=4;
947
state->update_count=mi_uint4korr(ptr); ptr +=4;
949
ptr+= state->state_diff_length;
951
for (i=0; i < keys; i++)
953
state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
955
for (i=0; i < key_blocks; i++)
957
state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
959
state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
960
state->sec_index_used = mi_uint4korr(ptr); ptr +=4;
961
state->version = mi_uint4korr(ptr); ptr +=4;
962
state->key_map = mi_uint8korr(ptr); ptr +=8;
963
state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
964
state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
965
state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8;
966
state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
967
for (i=0 ; i < key_parts ; i++)
969
state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
975
uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead)
977
uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
979
if (!myisam_single_user)
983
if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
986
else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
988
mi_state_info_read(buff, state);
994
/****************************************************************************
995
** store and read of MI_BASE_INFO
996
****************************************************************************/
998
uint mi_base_info_write(File file, MI_BASE_INFO *base)
1000
uchar buff[MI_BASE_INFO_SIZE], *ptr=buff;
1002
mi_sizestore(ptr,base->keystart); ptr +=8;
1003
mi_sizestore(ptr,base->max_data_file_length); ptr +=8;
1004
mi_sizestore(ptr,base->max_key_file_length); ptr +=8;
1005
mi_rowstore(ptr,base->records); ptr +=8;
1006
mi_rowstore(ptr,base->reloc); ptr +=8;
1007
mi_int4store(ptr,base->mean_row_length); ptr +=4;
1008
mi_int4store(ptr,base->reclength); ptr +=4;
1009
mi_int4store(ptr,base->pack_reclength); ptr +=4;
1010
mi_int4store(ptr,base->min_pack_length); ptr +=4;
1011
mi_int4store(ptr,base->max_pack_length); ptr +=4;
1012
mi_int4store(ptr,base->min_block_length); ptr +=4;
1013
mi_int4store(ptr,base->fields); ptr +=4;
1014
mi_int4store(ptr,base->pack_fields); ptr +=4;
1015
*ptr++=base->rec_reflength;
1016
*ptr++=base->key_reflength;
1018
*ptr++=base->auto_key;
1019
mi_int2store(ptr,base->pack_bits); ptr +=2;
1020
mi_int2store(ptr,base->blobs); ptr +=2;
1021
mi_int2store(ptr,base->max_key_block_length); ptr +=2;
1022
mi_int2store(ptr,base->max_key_length); ptr +=2;
1023
mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2;
1024
*ptr++= base->extra_alloc_procent;
1025
*ptr++= base->raid_type;
1026
mi_int2store(ptr,base->raid_chunks); ptr +=2;
1027
mi_int4store(ptr,base->raid_chunksize); ptr +=4;
1028
bzero(ptr,6); ptr +=6; /* extra */
1029
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1033
uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
1035
base->keystart = mi_sizekorr(ptr); ptr +=8;
1036
base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
1037
base->max_key_file_length = mi_sizekorr(ptr); ptr +=8;
1038
base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8;
1039
base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8;
1040
base->mean_row_length = mi_uint4korr(ptr); ptr +=4;
1041
base->reclength = mi_uint4korr(ptr); ptr +=4;
1042
base->pack_reclength = mi_uint4korr(ptr); ptr +=4;
1043
base->min_pack_length = mi_uint4korr(ptr); ptr +=4;
1044
base->max_pack_length = mi_uint4korr(ptr); ptr +=4;
1045
base->min_block_length = mi_uint4korr(ptr); ptr +=4;
1046
base->fields = mi_uint4korr(ptr); ptr +=4;
1047
base->pack_fields = mi_uint4korr(ptr); ptr +=4;
1049
base->rec_reflength = *ptr++;
1050
base->key_reflength = *ptr++;
1052
base->auto_key= *ptr++;
1053
base->pack_bits = mi_uint2korr(ptr); ptr +=2;
1054
base->blobs = mi_uint2korr(ptr); ptr +=2;
1055
base->max_key_block_length= mi_uint2korr(ptr); ptr +=2;
1056
base->max_key_length = mi_uint2korr(ptr); ptr +=2;
1057
base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2;
1058
base->extra_alloc_procent = *ptr++;
1059
base->raid_type= *ptr++;
1060
base->raid_chunks= mi_uint2korr(ptr); ptr +=2;
1061
base->raid_chunksize= mi_uint4korr(ptr); ptr +=4;
1062
/* TO BE REMOVED: Fix for old RAID files */
1063
if (base->raid_type == 0)
1065
base->raid_chunks=0;
1066
base->raid_chunksize=0;
1073
/*--------------------------------------------------------------------------
1075
---------------------------------------------------------------------------*/
1077
uint mi_keydef_write(File file, MI_KEYDEF *keydef)
1079
uchar buff[MI_KEYDEF_SIZE];
1082
*ptr++ = (uchar) keydef->keysegs;
1083
*ptr++ = keydef->key_alg; /* Rtree or Btree */
1084
mi_int2store(ptr,keydef->flag); ptr +=2;
1085
mi_int2store(ptr,keydef->block_length); ptr +=2;
1086
mi_int2store(ptr,keydef->keylength); ptr +=2;
1087
mi_int2store(ptr,keydef->minlength); ptr +=2;
1088
mi_int2store(ptr,keydef->maxlength); ptr +=2;
1089
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1092
uchar *mi_keydef_read(uchar *ptr, MI_KEYDEF *keydef)
1094
keydef->keysegs = (uint) *ptr++;
1095
keydef->key_alg = *ptr++; /* Rtree or Btree */
1097
keydef->flag = mi_uint2korr(ptr); ptr +=2;
1098
keydef->block_length = mi_uint2korr(ptr); ptr +=2;
1099
keydef->keylength = mi_uint2korr(ptr); ptr +=2;
1100
keydef->minlength = mi_uint2korr(ptr); ptr +=2;
1101
keydef->maxlength = mi_uint2korr(ptr); ptr +=2;
1102
keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
1103
keydef->underflow_block_length=keydef->block_length/3;
1104
keydef->version = 0; /* Not saved */
1105
keydef->parser = &ft_default_parser;
1106
keydef->ftparser_nr = 0;
1110
/***************************************************************************
1112
***************************************************************************/
1114
int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
1116
uchar buff[HA_KEYSEG_SIZE];
1120
*ptr++= keyseg->type;
1121
*ptr++= keyseg->language;
1122
*ptr++= keyseg->null_bit;
1123
*ptr++= keyseg->bit_start;
1124
*ptr++= keyseg->bit_end;
1125
*ptr++= keyseg->bit_length;
1126
mi_int2store(ptr,keyseg->flag); ptr+=2;
1127
mi_int2store(ptr,keyseg->length); ptr+=2;
1128
mi_int4store(ptr,keyseg->start); ptr+=4;
1129
pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
1130
mi_int4store(ptr, pos);
1133
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1137
uchar *mi_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
1139
keyseg->type = *ptr++;
1140
keyseg->language = *ptr++;
1141
keyseg->null_bit = *ptr++;
1142
keyseg->bit_start = *ptr++;
1143
keyseg->bit_end = *ptr++;
1144
keyseg->bit_length = *ptr++;
1145
keyseg->flag = mi_uint2korr(ptr); ptr +=2;
1146
keyseg->length = mi_uint2korr(ptr); ptr +=2;
1147
keyseg->start = mi_uint4korr(ptr); ptr +=4;
1148
keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
1149
keyseg->charset=0; /* Will be filled in later */
1150
if (keyseg->null_bit)
1151
keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
1154
keyseg->bit_pos= (uint16)keyseg->null_pos;
1155
keyseg->null_pos= 0;
1160
/*--------------------------------------------------------------------------
1162
---------------------------------------------------------------------------*/
1164
uint mi_uniquedef_write(File file, MI_UNIQUEDEF *def)
1166
uchar buff[MI_UNIQUEDEF_SIZE];
1169
mi_int2store(ptr,def->keysegs); ptr+=2;
1170
*ptr++= (uchar) def->key;
1171
*ptr++ = (uchar) def->null_are_equal;
1173
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1176
uchar *mi_uniquedef_read(uchar *ptr, MI_UNIQUEDEF *def)
1178
def->keysegs = mi_uint2korr(ptr);
1180
def->null_are_equal=ptr[3];
1181
return ptr+4; /* 1 extra byte */
1184
/***************************************************************************
1186
***************************************************************************/
1188
uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo)
1190
uchar buff[MI_COLUMNDEF_SIZE];
1193
mi_int2store(ptr,recinfo->type); ptr +=2;
1194
mi_int2store(ptr,recinfo->length); ptr +=2;
1195
*ptr++ = recinfo->null_bit;
1196
mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
1197
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1200
uchar *mi_recinfo_read(uchar *ptr, MI_COLUMNDEF *recinfo)
1202
recinfo->type= mi_sint2korr(ptr); ptr +=2;
1203
recinfo->length=mi_uint2korr(ptr); ptr +=2;
1204
recinfo->null_bit= (uint8) *ptr++;
1205
recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
1209
/**************************************************************************
1210
Open data file with or without RAID
1211
We can't use dup() here as the data file descriptors need to have different
1212
active seek-positions.
1214
The argument file_to_dup is here for the future if there would on some OS
1215
exist a dup()-like call that would give us two different file descriptors.
1216
*************************************************************************/
1218
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share,
1219
File file_to_dup __attribute__((unused)))
1222
if (share->base.raid_type)
1224
info->dfile=my_raid_open(share->data_file_name,
1225
share->mode | O_SHARE,
1226
share->base.raid_type,
1227
share->base.raid_chunks,
1228
share->base.raid_chunksize,
1229
MYF(MY_WME | MY_RAID));
1233
info->dfile=my_open(share->data_file_name, share->mode | O_SHARE,
1235
return info->dfile >= 0 ? 0 : 1;
1239
int mi_open_keyfile(MYISAM_SHARE *share)
1241
if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE,
1249
Disable all indexes.
1252
mi_disable_indexes()
1253
info A pointer to the MyISAM storage engine MI_INFO struct.
1256
Disable all indexes.
1262
int mi_disable_indexes(MI_INFO *info)
1264
MYISAM_SHARE *share= info->s;
1266
mi_clear_all_keys_active(share->state.key_map);
1276
info A pointer to the MyISAM storage engine MI_INFO struct.
1279
Enable all indexes. The indexes might have been disabled
1280
by mi_disable_index() before.
1281
The function works only if both data and indexes are empty,
1282
otherwise a repair is required.
1283
To be sure, call handler::delete_all_rows() before.
1287
HA_ERR_CRASHED data or index is non-empty.
1290
int mi_enable_indexes(MI_INFO *info)
1293
MYISAM_SHARE *share= info->s;
1295
if (share->state.state.data_file_length ||
1296
(share->state.state.key_file_length != share->base.keystart))
1298
mi_print_error(info->s, HA_ERR_CRASHED);
1299
error= HA_ERR_CRASHED;
1302
mi_set_all_keys_active(share->state.key_map, share->base.keys);
1308
Test if indexes are disabled.
1311
mi_indexes_are_disabled()
1312
info A pointer to the MyISAM storage engine MI_INFO struct.
1315
Test if indexes are disabled.
1318
0 indexes are not disabled
1319
1 all indexes are disabled
1320
2 non-unique indexes are disabled
1323
int mi_indexes_are_disabled(MI_INFO *info)
1325
MYISAM_SHARE *share= info->s;
1328
No keys or all are enabled. keys is the number of keys. Left shifted
1329
gives us only one bit set. When decreased by one, gives us all all bits
1330
up to this one set and it gets unset.
1332
if (!share->base.keys ||
1333
(mi_is_all_keys_active(share->state.key_map, share->base.keys)))
1336
/* All are disabled */
1337
if (mi_is_any_key_active(share->state.key_map))
1341
We have keys. Some enabled, some disabled.
1342
Don't check for any non-unique disabled but return directly 2