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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
/* open a isam-database */
18
#include "myisam_priv.h"
23
#include <boost/scoped_ptr.hpp>
24
#include <boost/scoped_array.hpp>
26
#include <drizzled/internal/m_string.h>
27
#include <drizzled/util/test.h>
28
#include <drizzled/charset.h>
29
#include <drizzled/memory/multi_malloc.h>
30
#include <drizzled/identifier.h>
34
using namespace drizzled;
36
static void setup_key_functions(MI_KEYDEF *keyinfo);
37
static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef);
38
static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg);
39
static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo);
40
static uint64_t mi_safe_mul(uint64_t a, uint64_t b);
41
static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state);
42
static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def);
43
static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base);
45
#define disk_pos_assert(pos, end_pos) \
48
errno=HA_ERR_CRASHED; \
53
/******************************************************************************
54
** Return the shared struct if the table is already open.
55
** In MySQL the server will handle version issues.
56
******************************************************************************/
58
MI_INFO *test_if_reopen(char *filename)
60
list<MI_INFO *>::iterator it= myisam_open_list.begin();
61
while (it != myisam_open_list.end())
64
MYISAM_SHARE *share=info->s;
65
if (!strcmp(share->unique_file_name,filename) && share->last_version)
73
/******************************************************************************
74
open a MyISAM database.
75
See my_base.h for the handle_locking argument
76
if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
77
is marked crashed or if we are not using locking and the table doesn't
78
have an open count of 0.
79
******************************************************************************/
81
MI_INFO *mi_open(const drizzled::identifier::Table &identifier, int mode, uint32_t open_flags)
83
int lock_error,kfile,open_mode,save_errno,have_rtree=0;
84
uint32_t i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
85
key_parts,unique_key_parts,uniques;
86
char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
87
data_name[FN_REFLEN], rp_buff[PATH_MAX];
88
unsigned char *disk_cache= NULL;
89
unsigned char *disk_pos, *end_pos;
90
MI_INFO info,*m_info,*old_info;
91
boost::scoped_ptr<MYISAM_SHARE> share_buff_ap(new MYISAM_SHARE);
92
MYISAM_SHARE &share_buff= *share_buff_ap.get();
94
boost::scoped_array<ulong> rec_per_key_part_ap(new ulong[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG]);
95
ulong *rec_per_key_part= rec_per_key_part_ap.get();
96
internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
97
uint64_t max_key_file_length, max_data_file_length;
102
head_length=sizeof(share_buff.state.header);
103
memset(&info, 0, sizeof(info));
105
(void)internal::fn_format(org_name,
106
identifier.getPath().c_str(),
110
if (!realpath(org_name,rp_buff))
111
internal::my_load_path(rp_buff,org_name, NULL);
112
rp_buff[FN_REFLEN-1]= '\0';
113
strcpy(name_buff,rp_buff);
114
THR_LOCK_myisam.lock();
115
if (!(old_info=test_if_reopen(name_buff)))
118
memset(&share_buff, 0, sizeof(share_buff));
119
share_buff.state.rec_per_key_part=rec_per_key_part;
120
share_buff.state.key_root=key_root;
121
share_buff.state.key_del=key_del;
123
if ((kfile=internal::my_open(name_buff,(open_mode=O_RDWR),MYF(0))) < 0)
125
if ((errno != EROFS && errno != EACCES) ||
127
(kfile=internal::my_open(name_buff,(open_mode=O_RDONLY),MYF(0))) < 0)
130
share->mode=open_mode;
132
if (internal::my_read(kfile, share->state.header.file_version, head_length,
135
errno= HA_ERR_NOT_A_TABLE;
138
if (memcmp(share->state.header.file_version, myisam_file_magic, 4))
140
errno=HA_ERR_NOT_A_TABLE;
143
share->options= mi_uint2korr(share->state.header.options);
144
static const uint64_t OLD_FILE_OPTIONS= HA_OPTION_PACK_RECORD |
145
HA_OPTION_PACK_KEYS |
146
HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
147
HA_OPTION_TEMP_COMPRESS_RECORD |
149
if (share->options & ~OLD_FILE_OPTIONS)
151
errno=HA_ERR_OLD_FILE;
155
/* Don't call realpath() if the name can't be a link */
156
ssize_t sym_link_size= readlink(org_name,index_name,FN_REFLEN-1);
157
if (sym_link_size >= 0 )
158
index_name[sym_link_size]= '\0';
159
if (!strcmp(name_buff, org_name) || sym_link_size == -1)
160
(void) strcpy(index_name, org_name);
161
*strrchr(org_name, '.')= '\0';
162
(void) internal::fn_format(data_name,org_name,"",MI_NAME_DEXT,
163
MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
165
info_length=mi_uint2korr(share->state.header.header_length);
166
base_pos=mi_uint2korr(share->state.header.base_pos);
167
if (!(disk_cache= (unsigned char*) malloc(info_length+128)))
172
end_pos=disk_cache+info_length;
175
lseek(kfile,0,SEEK_SET);
177
if (internal::my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
179
errno=HA_ERR_CRASHED;
182
len=mi_uint2korr(share->state.header.state_info_length);
183
keys= (uint) share->state.header.keys;
184
uniques= (uint) share->state.header.uniques;
185
key_parts= mi_uint2korr(share->state.header.key_parts);
186
unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
187
share->state_diff_length=len-MI_STATE_INFO_SIZE;
189
mi_state_info_read(disk_cache, &share->state);
190
len= mi_uint2korr(share->state.header.base_info_length);
191
disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
192
share->state.state_length=base_pos;
194
if (share->state.changed & STATE_CRASHED)
196
errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
197
HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
202
if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
204
errno=HA_ERR_CRASHED;
208
if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
209
key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
211
errno=HA_ERR_UNSUPPORTED;
215
/* Correct max_file_length based on length of sizeof(off_t) */
216
max_data_file_length=
217
(share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
218
(((uint64_t) 1 << (share->base.rec_reflength*8))-1) :
219
(mi_safe_mul(share->base.pack_reclength,
220
(uint64_t) 1 << (share->base.rec_reflength*8))-1);
222
mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
223
((uint64_t) 1 << (share->base.key_reflength*8))-1);
224
#if SIZEOF_OFF_T == 4
225
set_if_smaller(max_data_file_length, INT32_MAX);
226
set_if_smaller(max_key_file_length, INT32_MAX);
228
if (share->base.raid_type)
230
errno=HA_ERR_UNSUPPORTED;
233
share->base.max_data_file_length=(internal::my_off_t) max_data_file_length;
234
share->base.max_key_file_length=(internal::my_off_t) max_key_file_length;
236
if (share->options & HA_OPTION_COMPRESS_RECORD)
237
share->base.max_key_length+=2; /* For safety */
239
/* Add space for node pointer */
240
share->base.max_key_length+= share->base.key_reflength;
242
if (!drizzled::memory::multi_malloc(false,
243
&share,sizeof(*share),
244
&share->state.rec_per_key_part,sizeof(long)*key_parts,
245
&share->keyinfo,keys*sizeof(MI_KEYDEF),
246
&share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
248
(key_parts+unique_key_parts+keys+uniques) * sizeof(HA_KEYSEG),
249
&share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF),
250
&share->blobs,sizeof(MI_BLOB)*share->base.blobs,
251
&share->unique_file_name,strlen(name_buff)+1,
252
&share->index_file_name,strlen(index_name)+1,
253
&share->data_file_name,strlen(data_name)+1,
254
&share->state.key_root,keys*sizeof(uint64_t),
255
&share->state.key_del,
256
(share->state.header.max_block_size_index*sizeof(uint64_t)),
261
memcpy(share->state.rec_per_key_part, rec_per_key_part,
262
sizeof(long)*key_parts);
263
memcpy(share->state.key_root, key_root,
264
sizeof(internal::my_off_t)*keys);
265
memcpy(share->state.key_del, key_del,
266
sizeof(internal::my_off_t) * share->state.header.max_block_size_index);
267
strcpy(share->unique_file_name, name_buff);
268
share->unique_name_length= strlen(name_buff);
269
strcpy(share->index_file_name, index_name);
270
strcpy(share->data_file_name, data_name);
272
share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
274
HA_KEYSEG *pos=share->keyparts;
275
for (i=0 ; i < keys ; i++)
277
share->keyinfo[i].share= share;
278
disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
279
disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
281
set_if_smaller(share->blocksize,(uint)share->keyinfo[i].block_length);
282
share->keyinfo[i].seg=pos;
283
for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
285
disk_pos=mi_keyseg_read(disk_pos, pos);
286
if (pos->flag & HA_BLOB_PART &&
287
! (share->options & (HA_OPTION_COMPRESS_RECORD |
288
HA_OPTION_PACK_RECORD)))
290
errno= HA_ERR_CRASHED;
293
if (pos->type == HA_KEYTYPE_TEXT ||
294
pos->type == HA_KEYTYPE_VARTEXT1 ||
295
pos->type == HA_KEYTYPE_VARTEXT2)
298
pos->charset=default_charset_info;
299
else if (!(pos->charset= get_charset(pos->language)))
301
errno=HA_ERR_UNKNOWN_CHARSET;
305
else if (pos->type == HA_KEYTYPE_BINARY)
306
pos->charset= &my_charset_bin;
308
setup_key_functions(share->keyinfo+i);
309
share->keyinfo[i].end=pos;
310
pos->type=HA_KEYTYPE_END; /* End */
311
pos->length=share->base.rec_reflength;
313
pos->flag=0; /* For purify */
316
for (i=0 ; i < uniques ; i++)
318
disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
319
disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
320
HA_KEYSEG_SIZE, end_pos);
321
share->uniqueinfo[i].seg=pos;
322
for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
324
disk_pos=mi_keyseg_read(disk_pos, pos);
325
if (pos->type == HA_KEYTYPE_TEXT ||
326
pos->type == HA_KEYTYPE_VARTEXT1 ||
327
pos->type == HA_KEYTYPE_VARTEXT2)
330
pos->charset=default_charset_info;
331
else if (!(pos->charset= get_charset(pos->language)))
333
errno=HA_ERR_UNKNOWN_CHARSET;
338
share->uniqueinfo[i].end=pos;
339
pos->type=HA_KEYTYPE_END; /* End */
346
disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
347
for (i=j=offset=0 ; i < share->base.fields ; i++)
349
disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
350
share->rec[i].pack_type=0;
351
share->rec[i].huff_tree=0;
352
share->rec[i].offset=offset;
353
if (share->rec[i].type == (int) FIELD_BLOB)
355
share->blobs[j].pack_length=
356
share->rec[i].length-portable_sizeof_char_ptr;
357
share->blobs[j].offset=offset;
360
offset+=share->rec[i].length;
362
share->rec[i].type=(int) FIELD_LAST; /* End marker */
363
if (offset > share->base.reclength)
365
errno= HA_ERR_CRASHED;
371
lock_error=1; /* Database unlocked */
374
if (mi_open_datafile(&info, share, -1))
379
share->this_process=(ulong) getpid();
380
share->last_process= share->state.process;
381
share->base.key_parts=key_parts;
382
share->base.all_key_parts=key_parts+unique_key_parts;
383
if (!(share->last_version=share->state.version))
384
share->last_version=1; /* Safety */
385
share->rec_reflength=share->base.rec_reflength; /* May be changed */
386
share->base.margin_key_file_length=(share->base.max_key_file_length -
387
(keys ? MI_INDEX_BLOCK_MARGIN *
388
share->blocksize * keys : 0));
389
share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
390
share->data_file_type=STATIC_RECORD;
391
if (share->options & HA_OPTION_PACK_RECORD)
392
share->data_file_type = DYNAMIC_RECORD;
395
mi_setup_functions(share);
396
share->is_log_table= false;
397
if (myisam_concurrent_insert)
399
share->concurrent_insert=
400
((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
401
HA_OPTION_COMPRESS_RECORD |
402
HA_OPTION_TEMP_COMPRESS_RECORD)) ||
403
(open_flags & HA_OPEN_TMP_TABLE) || have_rtree) ? 0 : 1;
404
if (share->concurrent_insert)
413
if (mode == O_RDWR && share->mode == O_RDONLY)
415
errno=EACCES; /* Can't open in write mode */
418
if (mi_open_datafile(&info, share, old_info->dfile))
421
have_rtree= old_info->rtree_recursion_state != NULL;
424
/* alloc and set up private structure parts */
425
if (!drizzled::memory::multi_malloc(MY_WME,
426
&m_info,sizeof(MI_INFO),
427
&info.blobs,sizeof(MI_BLOB)*share->base.blobs,
428
&info.buff,(share->base.max_key_block_length*2+
429
share->base.max_key_length),
430
&info.lastkey,share->base.max_key_length*3+1,
431
&info.first_mbr_key, share->base.max_key_length,
432
&info.filename, identifier.getPath().length()+1,
433
&info.rtree_recursion_state,have_rtree ? 1024 : 0,
439
info.rtree_recursion_state= NULL;
441
strcpy(info.filename, identifier.getPath().c_str());
442
memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
443
info.lastkey2=info.lastkey+share->base.max_key_length;
446
info.lastpos= HA_OFFSET_ERROR;
447
info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
448
info.opt_flag=READ_CHECK_USED;
449
info.this_unique= (ulong) info.dfile; /* Uniq number in process */
450
if (share->data_file_type == COMPRESSED_RECORD)
451
info.this_unique= share->state.unique;
452
info.this_loop=0; /* Update counter */
453
info.last_unique= share->state.unique;
454
info.last_loop= share->state.update_count;
455
if (mode == O_RDONLY)
456
share->options|=HA_OPTION_READ_ONLY_DATA;
457
info.lock_type=F_UNLCK;
462
info.read_record=share->read_record;
464
share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
465
if (share->options & HA_OPTION_READ_ONLY_DATA)
467
info.lock_type=F_RDLCK;
471
if ((open_flags & HA_OPEN_TMP_TABLE) ||
472
(share->options & HA_OPTION_TMP_TABLE))
474
share->temporary=share->delay_key_write=1;
475
share->write_flag=MYF(MY_NABP);
477
* The following two statements are commented out as a fix of
478
* bug https://bugs.launchpad.net/drizzle/+bug/387627
480
* UPDATE can be TRUNCATE on TEMPORARY TABLE (MyISAM).
481
* The root cause of why this makes a difference hasn't
482
* been found, but this fixes things for now.
484
// share->w_locks++; // We don't have to update status
485
// share->tot_locks++;
486
info.lock_type=F_WRLCK;
489
share->delay_key_write= 1;
490
info.state= &share->state.state; /* Change global values by default */
492
/* Allocate buffer for one record */
494
/* prerequisites: memset(info, 0) && info->s=share; are met. */
495
if (!mi_alloc_rec_buff(&info, SIZE_MAX, &info.rec_buff))
497
memset(info.rec_buff, 0, mi_get_rec_buff_len(&info, info.rec_buff));
500
myisam_open_list.push_front(m_info);
502
THR_LOCK_myisam.unlock();
507
save_errno=errno ? errno : HA_ERR_END_OF_FILE;
508
if ((save_errno == HA_ERR_CRASHED) ||
509
(save_errno == HA_ERR_CRASHED_ON_USAGE) ||
510
(save_errno == HA_ERR_CRASHED_ON_REPAIR))
511
mi_report_error(save_errno, identifier.getPath().c_str());
514
free((unsigned char*) m_info);
517
internal::my_close(info.dfile,MYF(0));
519
break; /* Don't remove open table */
522
free((unsigned char*) share);
527
internal::my_close(kfile,MYF(0));
533
THR_LOCK_myisam.unlock();
539
unsigned char *mi_alloc_rec_buff(MI_INFO *info, size_t length, unsigned char **buf)
542
uint32_t old_length= 0;
544
if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
546
unsigned char *newptr = *buf;
548
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
549
if (length == SIZE_MAX)
551
if (info->s->options & HA_OPTION_COMPRESS_RECORD)
552
length= max(info->s->base.pack_reclength, info->s->max_pack_length);
554
length= info->s->base.pack_reclength;
555
length= max((uint32_t)length, info->s->base.max_key_length);
556
/* Avoid unnecessary realloc */
557
if (newptr && length == old_length)
561
extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
562
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
563
MI_REC_BUFF_OFFSET : 0);
565
newptr-= MI_REC_BUFF_OFFSET;
566
void *tmpnewptr= NULL;
567
if (!(tmpnewptr= realloc(newptr, length+extra+8)))
569
newptr= (unsigned char *)tmpnewptr;
570
*((uint32_t *) newptr)= (uint32_t) length;
571
*buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
577
static uint64_t mi_safe_mul(uint64_t a, uint64_t b)
579
uint64_t max_val= ~ (uint64_t) 0; /* internal::my_off_t is unsigned */
581
if (!a || max_val / a < b)
586
/* Set up functions in structs */
588
void mi_setup_functions(register MYISAM_SHARE *share)
590
if (share->options & HA_OPTION_PACK_RECORD)
592
share->read_record=_mi_read_dynamic_record;
593
share->read_rnd=_mi_read_rnd_dynamic_record;
594
share->delete_record=_mi_delete_dynamic_record;
595
share->compare_record=_mi_cmp_dynamic_record;
596
share->compare_unique=_mi_cmp_dynamic_unique;
597
share->calc_checksum= mi_checksum;
599
/* add bits used to pack data to pack_reclength for faster allocation */
600
share->base.pack_reclength+= share->base.pack_bits;
601
if (share->base.blobs)
603
share->update_record=_mi_update_blob_record;
604
share->write_record=_mi_write_blob_record;
608
share->write_record=_mi_write_dynamic_record;
609
share->update_record=_mi_update_dynamic_record;
614
share->read_record=_mi_read_static_record;
615
share->read_rnd=_mi_read_rnd_static_record;
616
share->delete_record=_mi_delete_static_record;
617
share->compare_record=_mi_cmp_static_record;
618
share->update_record=_mi_update_static_record;
619
share->write_record=_mi_write_static_record;
620
share->compare_unique=_mi_cmp_static_unique;
621
share->calc_checksum= mi_static_checksum;
623
share->file_read= mi_nommap_pread;
624
share->file_write= mi_nommap_pwrite;
625
share->calc_checksum=0;
629
static void setup_key_functions(register MI_KEYDEF *keyinfo)
632
keyinfo->ck_insert = _mi_ck_write;
633
keyinfo->ck_delete = _mi_ck_delete;
635
if (keyinfo->flag & HA_BINARY_PACK_KEY)
636
{ /* Simple prefix compression */
637
keyinfo->bin_search=_mi_seq_search;
638
keyinfo->get_key=_mi_get_binary_pack_key;
639
keyinfo->pack_key=_mi_calc_bin_pack_key_length;
640
keyinfo->store_key=_mi_store_bin_pack_key;
642
else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
644
keyinfo->get_key= _mi_get_pack_key;
645
if (keyinfo->seg[0].flag & HA_PACK_KEY)
646
{ /* Prefix compression */
648
_mi_prefix_search() compares end-space against ASCII blank (' ').
649
It cannot be used for character sets, that do not encode the
650
blank character like ASCII does. UCS2 is an example. All
651
character sets with a fixed width > 1 or a mimimum width > 1
652
cannot represent blank like ASCII does. In these cases we have
653
to use _mi_seq_search() for the search.
655
if (not keyinfo->seg->charset || keyinfo->seg->charset->use_strnxfrm() ||
656
(keyinfo->seg->flag & HA_NULL_PART) ||
657
(keyinfo->seg->charset->mbminlen > 1))
658
keyinfo->bin_search=_mi_seq_search;
660
keyinfo->bin_search=_mi_prefix_search;
661
keyinfo->pack_key=_mi_calc_var_pack_key_length;
662
keyinfo->store_key=_mi_store_var_pack_key;
666
keyinfo->bin_search=_mi_seq_search;
667
keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
668
keyinfo->store_key=_mi_store_static_key;
673
keyinfo->bin_search=_mi_bin_search;
674
keyinfo->get_key=_mi_get_static_key;
675
keyinfo->pack_key=_mi_calc_static_key_length;
676
keyinfo->store_key=_mi_store_static_key;
683
Function to save and store the header in the index file (.MYI)
686
uint32_t mi_state_info_write(int file, MI_STATE_INFO *state, uint32_t pWrite)
688
unsigned char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
689
unsigned char *ptr=buff;
690
uint i, keys= (uint) state->header.keys,
691
key_blocks=state->header.max_block_size_index;
693
memcpy(ptr,&state->header,sizeof(state->header));
694
ptr+=sizeof(state->header);
696
/* open_count must be first because of _mi_mark_file_changed ! */
697
mi_int2store(ptr,state->open_count); ptr +=2;
698
*ptr++= (unsigned char)state->changed; *ptr++= state->sortkey;
699
mi_rowstore(ptr,state->state.records); ptr +=8;
700
mi_rowstore(ptr,state->state.del); ptr +=8;
701
mi_rowstore(ptr,state->split); ptr +=8;
702
mi_sizestore(ptr,state->dellink); ptr +=8;
703
mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
704
mi_sizestore(ptr,state->state.data_file_length); ptr +=8;
705
mi_sizestore(ptr,state->state.empty); ptr +=8;
706
mi_sizestore(ptr,state->state.key_empty); ptr +=8;
707
mi_int8store(ptr,state->auto_increment); ptr +=8;
708
mi_int8store(ptr,(uint64_t) state->state.checksum);ptr +=8;
709
mi_int4store(ptr,state->process); ptr +=4;
710
mi_int4store(ptr,state->unique); ptr +=4;
711
mi_int4store(ptr,state->status); ptr +=4;
712
mi_int4store(ptr,state->update_count); ptr +=4;
714
ptr+=state->state_diff_length;
716
for (i=0; i < keys; i++)
718
mi_sizestore(ptr,state->key_root[i]); ptr +=8;
720
for (i=0; i < key_blocks; i++)
722
mi_sizestore(ptr,state->key_del[i]); ptr +=8;
724
if (pWrite & 2) /* From isamchk */
726
uint32_t key_parts= mi_uint2korr(state->header.key_parts);
727
mi_int4store(ptr,state->sec_index_changed); ptr +=4;
728
mi_int4store(ptr,state->sec_index_used); ptr +=4;
729
mi_int4store(ptr,state->version); ptr +=4;
730
mi_int8store(ptr,state->key_map); ptr +=8;
731
mi_int8store(ptr,(uint64_t) state->create_time); ptr +=8;
732
mi_int8store(ptr,(uint64_t) state->recover_time); ptr +=8;
733
mi_int8store(ptr,(uint64_t) state->check_time); ptr +=8;
734
mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8;
735
for (i=0 ; i < key_parts ; i++)
737
mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4;
742
return(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
743
MYF(MY_NABP | MY_THREADSAFE)) != 0);
744
return(internal::my_write(file, buff, (size_t) (ptr-buff),
749
static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state)
751
uint32_t i,keys,key_parts,key_blocks;
752
memcpy(&state->header,ptr, sizeof(state->header));
753
ptr +=sizeof(state->header);
754
keys=(uint) state->header.keys;
755
key_parts=mi_uint2korr(state->header.key_parts);
756
key_blocks=state->header.max_block_size_index;
758
state->open_count = mi_uint2korr(ptr); ptr +=2;
759
state->changed= *ptr++;
760
state->sortkey = (uint) *ptr++;
761
state->state.records= mi_rowkorr(ptr); ptr +=8;
762
state->state.del = mi_rowkorr(ptr); ptr +=8;
763
state->split = mi_rowkorr(ptr); ptr +=8;
764
state->dellink= mi_sizekorr(ptr); ptr +=8;
765
state->state.key_file_length = mi_sizekorr(ptr); ptr +=8;
766
state->state.data_file_length= mi_sizekorr(ptr); ptr +=8;
767
state->state.empty = mi_sizekorr(ptr); ptr +=8;
768
state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
769
state->auto_increment=mi_uint8korr(ptr); ptr +=8;
770
state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8;
771
state->process= mi_uint4korr(ptr); ptr +=4;
772
state->unique = mi_uint4korr(ptr); ptr +=4;
773
state->status = mi_uint4korr(ptr); ptr +=4;
774
state->update_count=mi_uint4korr(ptr); ptr +=4;
776
ptr+= state->state_diff_length;
778
for (i=0; i < keys; i++)
780
state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
782
for (i=0; i < key_blocks; i++)
784
state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
786
state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
787
state->sec_index_used = mi_uint4korr(ptr); ptr +=4;
788
state->version = mi_uint4korr(ptr); ptr +=4;
789
state->key_map = mi_uint8korr(ptr); ptr +=8;
790
state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
791
state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
792
state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8;
793
state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
794
for (i=0 ; i < key_parts ; i++)
796
state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
802
uint32_t mi_state_info_read_dsk(int file, MI_STATE_INFO *state, bool pRead)
804
unsigned char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
808
if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
811
else if (internal::my_read(file, buff, state->state_length,MYF(MY_NABP)))
813
mi_state_info_read(buff, state);
819
/****************************************************************************
820
** store and read of MI_BASE_INFO
821
****************************************************************************/
823
uint32_t mi_base_info_write(int file, MI_BASE_INFO *base)
825
unsigned char buff[MI_BASE_INFO_SIZE], *ptr=buff;
827
mi_sizestore(ptr,base->keystart); ptr +=8;
828
mi_sizestore(ptr,base->max_data_file_length); ptr +=8;
829
mi_sizestore(ptr,base->max_key_file_length); ptr +=8;
830
mi_rowstore(ptr,base->records); ptr +=8;
831
mi_rowstore(ptr,base->reloc); ptr +=8;
832
mi_int4store(ptr,base->mean_row_length); ptr +=4;
833
mi_int4store(ptr,base->reclength); ptr +=4;
834
mi_int4store(ptr,base->pack_reclength); ptr +=4;
835
mi_int4store(ptr,base->min_pack_length); ptr +=4;
836
mi_int4store(ptr,base->max_pack_length); ptr +=4;
837
mi_int4store(ptr,base->min_block_length); ptr +=4;
838
mi_int4store(ptr,base->fields); ptr +=4;
839
mi_int4store(ptr,base->pack_fields); ptr +=4;
840
*ptr++=base->rec_reflength;
841
*ptr++=base->key_reflength;
843
*ptr++=base->auto_key;
844
mi_int2store(ptr,base->pack_bits); ptr +=2;
845
mi_int2store(ptr,base->blobs); ptr +=2;
846
mi_int2store(ptr,base->max_key_block_length); ptr +=2;
847
mi_int2store(ptr,base->max_key_length); ptr +=2;
848
mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2;
849
*ptr++= base->extra_alloc_procent;
850
/* old raid info slots */
852
mi_int2store(ptr,UINT16_C(0)); ptr +=2;
853
mi_int4store(ptr,UINT32_C(0)); ptr +=4;
855
memset(ptr, 0, 6); ptr +=6; /* extra */
856
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
860
static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base)
862
base->keystart = mi_sizekorr(ptr); ptr +=8;
863
base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
864
base->max_key_file_length = mi_sizekorr(ptr); ptr +=8;
865
base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8;
866
base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8;
867
base->mean_row_length = mi_uint4korr(ptr); ptr +=4;
868
base->reclength = mi_uint4korr(ptr); ptr +=4;
869
base->pack_reclength = mi_uint4korr(ptr); ptr +=4;
870
base->min_pack_length = mi_uint4korr(ptr); ptr +=4;
871
base->max_pack_length = mi_uint4korr(ptr); ptr +=4;
872
base->min_block_length = mi_uint4korr(ptr); ptr +=4;
873
base->fields = mi_uint4korr(ptr); ptr +=4;
874
base->pack_fields = mi_uint4korr(ptr); ptr +=4;
876
base->rec_reflength = *ptr++;
877
base->key_reflength = *ptr++;
879
base->auto_key= *ptr++;
880
base->pack_bits = mi_uint2korr(ptr); ptr +=2;
881
base->blobs = mi_uint2korr(ptr); ptr +=2;
882
base->max_key_block_length= mi_uint2korr(ptr); ptr +=2;
883
base->max_key_length = mi_uint2korr(ptr); ptr +=2;
884
base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2;
885
base->extra_alloc_procent = *ptr++;
887
/* advance past raid_type (1) raid_chunks (2) and raid_chunksize (4) */
894
/*--------------------------------------------------------------------------
896
---------------------------------------------------------------------------*/
898
uint32_t mi_keydef_write(int file, MI_KEYDEF *keydef)
900
unsigned char buff[MI_KEYDEF_SIZE];
901
unsigned char *ptr=buff;
903
*ptr++ = (unsigned char) keydef->keysegs;
904
*ptr++ = keydef->key_alg; /* Rtree or Btree */
905
mi_int2store(ptr,keydef->flag); ptr +=2;
906
mi_int2store(ptr,keydef->block_length); ptr +=2;
907
mi_int2store(ptr,keydef->keylength); ptr +=2;
908
mi_int2store(ptr,keydef->minlength); ptr +=2;
909
mi_int2store(ptr,keydef->maxlength); ptr +=2;
910
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
913
static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef)
915
keydef->keysegs = (uint) *ptr++;
916
keydef->key_alg = *ptr++; /* Rtree or Btree */
918
keydef->flag = mi_uint2korr(ptr); ptr +=2;
919
keydef->block_length = mi_uint2korr(ptr); ptr +=2;
920
keydef->keylength = mi_uint2korr(ptr); ptr +=2;
921
keydef->minlength = mi_uint2korr(ptr); ptr +=2;
922
keydef->maxlength = mi_uint2korr(ptr); ptr +=2;
923
keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
924
keydef->underflow_block_length=keydef->block_length/3;
925
keydef->version = 0; /* Not saved */
929
/***************************************************************************
931
***************************************************************************/
933
int mi_keyseg_write(int file, const HA_KEYSEG *keyseg)
935
unsigned char buff[HA_KEYSEG_SIZE];
936
unsigned char *ptr=buff;
939
*ptr++= keyseg->type;
940
*ptr++= keyseg->language;
941
*ptr++= keyseg->null_bit;
942
*ptr++= keyseg->bit_start;
943
*ptr++= keyseg->bit_end;
944
*ptr++= keyseg->bit_length;
945
mi_int2store(ptr,keyseg->flag); ptr+=2;
946
mi_int2store(ptr,keyseg->length); ptr+=2;
947
mi_int4store(ptr,keyseg->start); ptr+=4;
948
pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
949
mi_int4store(ptr, pos);
952
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
956
static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg)
958
keyseg->type = *ptr++;
959
keyseg->language = *ptr++;
960
keyseg->null_bit = *ptr++;
961
keyseg->bit_start = *ptr++;
962
keyseg->bit_end = *ptr++;
963
keyseg->bit_length = *ptr++;
964
keyseg->flag = mi_uint2korr(ptr); ptr +=2;
965
keyseg->length = mi_uint2korr(ptr); ptr +=2;
966
keyseg->start = mi_uint4korr(ptr); ptr +=4;
967
keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
968
keyseg->charset=0; /* Will be filled in later */
969
if (keyseg->null_bit)
970
keyseg->bit_pos= (uint16_t)(keyseg->null_pos + (keyseg->null_bit == 7));
973
keyseg->bit_pos= (uint16_t)keyseg->null_pos;
979
/*--------------------------------------------------------------------------
981
---------------------------------------------------------------------------*/
983
uint32_t mi_uniquedef_write(int file, MI_UNIQUEDEF *def)
985
unsigned char buff[MI_UNIQUEDEF_SIZE];
986
unsigned char *ptr=buff;
988
mi_int2store(ptr,def->keysegs); ptr+=2;
989
*ptr++= (unsigned char) def->key;
990
*ptr++ = (unsigned char) def->null_are_equal;
992
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
995
static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def)
997
def->keysegs = mi_uint2korr(ptr);
999
def->null_are_equal=ptr[3];
1000
return ptr+4; /* 1 extra byte */
1003
/***************************************************************************
1005
***************************************************************************/
1007
uint32_t mi_recinfo_write(int file, MI_COLUMNDEF *recinfo)
1009
unsigned char buff[MI_COLUMNDEF_SIZE];
1010
unsigned char *ptr=buff;
1012
mi_int2store(ptr,recinfo->type); ptr +=2;
1013
mi_int2store(ptr,recinfo->length); ptr +=2;
1014
*ptr++ = recinfo->null_bit;
1015
mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
1016
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1019
static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo)
1021
recinfo->type= mi_sint2korr(ptr); ptr +=2;
1022
recinfo->length=mi_uint2korr(ptr); ptr +=2;
1023
recinfo->null_bit= (uint8_t) *ptr++;
1024
recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
1028
/**************************************************************************
1030
We can't use dup() here as the data file descriptors need to have different
1031
active seek-positions.
1033
The argument file_to_dup is here for the future if there would on some OS
1034
exist a dup()-like call that would give us two different file descriptors.
1035
*************************************************************************/
1037
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, int file_to_dup)
1040
info->dfile=internal::my_open(share->data_file_name, share->mode,
1042
return info->dfile >= 0 ? 0 : 1;
1046
int mi_open_keyfile(MYISAM_SHARE *share)
1048
if ((share->kfile=internal::my_open(share->unique_file_name, share->mode,
1056
Disable all indexes.
1059
mi_disable_indexes()
1060
info A pointer to the MyISAM storage engine MI_INFO struct.
1063
Disable all indexes.
1069
int mi_disable_indexes(MI_INFO *info)
1071
MYISAM_SHARE *share= info->s;
1073
mi_clear_all_keys_active(share->state.key_map);
1083
info A pointer to the MyISAM storage engine MI_INFO struct.
1086
Enable all indexes. The indexes might have been disabled
1087
by mi_disable_index() before.
1088
The function works only if both data and indexes are empty,
1089
otherwise a repair is required.
1090
To be sure, call handler::delete_all_rows() before.
1094
HA_ERR_CRASHED data or index is non-empty.
1097
int mi_enable_indexes(MI_INFO *info)
1100
MYISAM_SHARE *share= info->s;
1102
if (share->state.state.data_file_length ||
1103
(share->state.state.key_file_length != share->base.keystart))
1105
mi_print_error(info->s, HA_ERR_CRASHED);
1106
error= HA_ERR_CRASHED;
1109
mi_set_all_keys_active(share->state.key_map, share->base.keys);
1115
Test if indexes are disabled.
1118
mi_indexes_are_disabled()
1119
info A pointer to the MyISAM storage engine MI_INFO struct.
1122
Test if indexes are disabled.
1125
0 indexes are not disabled
1126
1 all indexes are disabled
1127
2 non-unique indexes are disabled
1130
int mi_indexes_are_disabled(MI_INFO *info)
1132
MYISAM_SHARE *share= info->s;
1135
No keys or all are enabled. keys is the number of keys. Left shifted
1136
gives us only one bit set. When decreased by one, gives us all all bits
1137
up to this one set and it gets unset.
1139
if (!share->base.keys ||
1140
(mi_is_all_keys_active(share->state.key_map, share->base.keys)))
1143
/* All are disabled */
1144
if (mi_is_any_key_active(share->state.key_map))
1148
We have keys. Some enabled, some disabled.
1149
Don't check for any non-unique disabled but return directly 2