mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / myisam / mi_open.c
blob57efd2188b33c4571e2497fdde83257680211481
1 /*
2 Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 /* open a isam-database */
20 #include "fulltext.h"
21 #include "sp_defs.h"
22 #include "rt_index.h"
23 #include <m_ctype.h>
25 #if defined(MSDOS) || defined(__WIN__)
26 #ifdef __WIN__
27 #include <fcntl.h>
28 #else
29 #include <process.h> /* Prototype for getpid */
30 #endif
31 #endif
32 #ifdef VMS
33 #include "static.c"
34 #endif
36 static void setup_key_functions(MI_KEYDEF *keyinfo);
37 #define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
38 pos+=size;}
41 #define disk_pos_assert(pos, end_pos) \
42 if (pos > end_pos) \
43 { \
44 my_errno=HA_ERR_CRASHED; \
45 goto err; \
49 /******************************************************************************
50 ** Return the shared struct if the table is already open.
51 ** In MySQL the server will handle version issues.
52 ******************************************************************************/
54 MI_INFO *test_if_reopen(char *filename)
56 LIST *pos;
58 for (pos=myisam_open_list ; pos ; pos=pos->next)
60 MI_INFO *info=(MI_INFO*) pos->data;
61 MYISAM_SHARE *share=info->s;
62 if (!strcmp(share->unique_file_name,filename) && share->last_version)
63 return info;
65 return 0;
69 /******************************************************************************
70 open a MyISAM database.
71 See my_base.h for the handle_locking argument
72 if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
73 is marked crashed or if we are not using locking and the table doesn't
74 have an open count of 0.
75 ******************************************************************************/
77 MI_INFO *mi_open(const char *name, int mode, uint open_flags)
79 int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err;
80 uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
81 key_parts,unique_key_parts,fulltext_keys,uniques;
82 char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
83 data_name[FN_REFLEN];
84 uchar *disk_cache, *disk_pos, *end_pos;
85 MI_INFO info,*m_info,*old_info;
86 MYISAM_SHARE share_buff,*share;
87 ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
88 my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
89 ulonglong max_key_file_length, max_data_file_length;
90 DBUG_ENTER("mi_open");
92 LINT_INIT(m_info);
93 kfile= -1;
94 lock_error=1;
95 errpos=0;
96 head_length=sizeof(share_buff.state.header);
97 bzero((uchar*) &info,sizeof(info));
99 realpath_err= my_realpath(name_buff,
100 fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
101 if (my_is_symlink(org_name) &&
102 (realpath_err || (*myisam_test_invalid_symlink)(name_buff)))
104 my_errno= HA_WRONG_CREATE_OPTION;
105 DBUG_RETURN (NULL);
108 pthread_mutex_lock(&THR_LOCK_myisam);
109 if (!(old_info=test_if_reopen(name_buff)))
111 share= &share_buff;
112 bzero((uchar*) &share_buff,sizeof(share_buff));
113 share_buff.state.rec_per_key_part=rec_per_key_part;
114 share_buff.state.key_root=key_root;
115 share_buff.state.key_del=key_del;
116 share_buff.key_cache= multi_key_cache_search((uchar*) name_buff,
117 strlen(name_buff));
119 DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
120 if (strstr(name, "/t1"))
122 my_errno= HA_ERR_CRASHED;
123 goto err;
125 if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
127 if ((errno != EROFS && errno != EACCES) ||
128 mode != O_RDONLY ||
129 (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
130 goto err;
132 share->mode=open_mode;
133 errpos=1;
134 if (my_read(kfile, share->state.header.file_version, head_length,
135 MYF(MY_NABP)))
137 my_errno= HA_ERR_NOT_A_TABLE;
138 goto err;
140 if (memcmp((uchar*) share->state.header.file_version,
141 (uchar*) myisam_file_magic, 4))
143 DBUG_PRINT("error",("Wrong header in %s",name_buff));
144 DBUG_DUMP("error_dump", share->state.header.file_version,
145 head_length);
146 my_errno=HA_ERR_NOT_A_TABLE;
147 goto err;
149 share->options= mi_uint2korr(share->state.header.options);
150 if (share->options &
151 ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
152 HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
153 HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
154 HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
155 HA_OPTION_RELIES_ON_SQL_LAYER))
157 DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
158 my_errno=HA_ERR_OLD_FILE;
159 goto err;
161 if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
162 ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
164 DBUG_PRINT("error", ("table cannot be openned from non-sql layer"));
165 my_errno= HA_ERR_UNSUPPORTED;
166 goto err;
168 /* Don't call realpath() if the name can't be a link */
169 if (!strcmp(name_buff, org_name) ||
170 my_readlink(index_name, org_name, MYF(0)) == -1)
171 (void) strmov(index_name, org_name);
172 *strrchr(org_name, '.')= '\0';
173 (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,
174 MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
176 info_length=mi_uint2korr(share->state.header.header_length);
177 base_pos=mi_uint2korr(share->state.header.base_pos);
178 if (!(disk_cache= (uchar*) my_alloca(info_length+128)))
180 my_errno=ENOMEM;
181 goto err;
183 end_pos=disk_cache+info_length;
184 errpos=2;
186 VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
187 if (!(open_flags & HA_OPEN_TMP_TABLE))
189 if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
190 MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ?
191 0 : MY_DONT_WAIT))) &&
192 !(open_flags & HA_OPEN_IGNORE_IF_LOCKED))
193 goto err;
195 errpos=3;
196 if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
198 my_errno=HA_ERR_CRASHED;
199 goto err;
201 len=mi_uint2korr(share->state.header.state_info_length);
202 keys= (uint) share->state.header.keys;
203 uniques= (uint) share->state.header.uniques;
204 fulltext_keys= (uint) share->state.header.fulltext_keys;
205 key_parts= mi_uint2korr(share->state.header.key_parts);
206 unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
207 if (len != MI_STATE_INFO_SIZE)
209 DBUG_PRINT("warning",
210 ("saved_state_info_length: %d state_info_length: %d",
211 len,MI_STATE_INFO_SIZE));
213 share->state_diff_length=len-MI_STATE_INFO_SIZE;
215 mi_state_info_read(disk_cache, &share->state);
216 len= mi_uint2korr(share->state.header.base_info_length);
217 if (len != MI_BASE_INFO_SIZE)
219 DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
220 len,MI_BASE_INFO_SIZE));
222 disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
223 share->state.state_length=base_pos;
225 if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
226 ((share->state.changed & STATE_CRASHED) ||
227 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
228 (my_disable_locking && share->state.open_count))))
230 DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u "
231 "changed: %u open_count: %u !locking: %d",
232 open_flags, share->state.changed,
233 share->state.open_count, my_disable_locking));
234 my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
235 HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
236 goto err;
239 /* sanity check */
240 if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
242 my_errno=HA_ERR_CRASHED;
243 goto err;
246 key_parts+=fulltext_keys*FT_SEGS;
247 if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
248 key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
250 DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts));
251 my_errno=HA_ERR_UNSUPPORTED;
252 goto err;
255 /* Correct max_file_length based on length of sizeof(off_t) */
256 max_data_file_length=
257 (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
258 (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
259 (mi_safe_mul(share->base.pack_reclength,
260 (ulonglong) 1 << (share->base.rec_reflength*8))-1);
261 max_key_file_length=
262 mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
263 ((ulonglong) 1 << (share->base.key_reflength*8))-1);
264 #if SIZEOF_OFF_T == 4
265 set_if_smaller(max_data_file_length, INT_MAX32);
266 set_if_smaller(max_key_file_length, INT_MAX32);
267 #endif
268 #if USE_RAID && SYSTEM_SIZEOF_OFF_T == 4
269 set_if_smaller(max_key_file_length, INT_MAX32);
270 if (!share->base.raid_type)
272 set_if_smaller(max_data_file_length, INT_MAX32);
274 else
276 set_if_smaller(max_data_file_length,
277 (ulonglong) share->base.raid_chunks << 31);
279 #elif !defined(USE_RAID)
280 if (share->base.raid_type)
282 DBUG_PRINT("error",("Table uses RAID but we don't have RAID support"));
283 my_errno=HA_ERR_UNSUPPORTED;
284 goto err;
286 #endif
287 share->base.max_data_file_length=(my_off_t) max_data_file_length;
288 share->base.max_key_file_length=(my_off_t) max_key_file_length;
290 if (share->options & HA_OPTION_COMPRESS_RECORD)
291 share->base.max_key_length+=2; /* For safety */
293 /* Add space for node pointer */
294 share->base.max_key_length+= share->base.key_reflength;
296 if (!my_multi_malloc(MY_WME,
297 &share,sizeof(*share),
298 &share->state.rec_per_key_part,sizeof(long)*key_parts,
299 &share->keyinfo,keys*sizeof(MI_KEYDEF),
300 &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
301 &share->keyparts,
302 (key_parts+unique_key_parts+keys+uniques) *
303 sizeof(HA_KEYSEG),
304 &share->rec,
305 (share->base.fields+1)*sizeof(MI_COLUMNDEF),
306 &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
307 &share->unique_file_name,strlen(name_buff)+1,
308 &share->index_file_name,strlen(index_name)+1,
309 &share->data_file_name,strlen(data_name)+1,
310 &share->state.key_root,keys*sizeof(my_off_t),
311 &share->state.key_del,
312 (share->state.header.max_block_size_index*sizeof(my_off_t)),
313 #ifdef THREAD
314 &share->key_root_lock,sizeof(rw_lock_t)*keys,
315 #endif
316 &share->mmap_lock,sizeof(rw_lock_t),
317 NullS))
318 goto err;
319 errpos=4;
320 *share=share_buff;
321 memcpy((char*) share->state.rec_per_key_part,
322 (char*) rec_per_key_part, sizeof(long)*key_parts);
323 memcpy((char*) share->state.key_root,
324 (char*) key_root, sizeof(my_off_t)*keys);
325 memcpy((char*) share->state.key_del,
326 (char*) key_del, (sizeof(my_off_t) *
327 share->state.header.max_block_size_index));
328 strmov(share->unique_file_name, name_buff);
329 share->unique_name_length= strlen(name_buff);
330 strmov(share->index_file_name, index_name);
331 strmov(share->data_file_name, data_name);
333 share->blocksize=min(IO_SIZE,myisam_block_size);
335 HA_KEYSEG *pos=share->keyparts;
336 uint32 ftkey_nr= 1;
337 for (i=0 ; i < keys ; i++)
339 share->keyinfo[i].share= share;
340 disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
341 disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
342 end_pos);
343 if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE)
344 have_rtree=1;
345 set_if_smaller(share->blocksize,share->keyinfo[i].block_length);
346 share->keyinfo[i].seg=pos;
347 for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
349 disk_pos=mi_keyseg_read(disk_pos, pos);
350 if (pos->flag & HA_BLOB_PART &&
351 ! (share->options & (HA_OPTION_COMPRESS_RECORD |
352 HA_OPTION_PACK_RECORD)))
354 my_errno= HA_ERR_CRASHED;
355 goto err;
357 if (pos->type == HA_KEYTYPE_TEXT ||
358 pos->type == HA_KEYTYPE_VARTEXT1 ||
359 pos->type == HA_KEYTYPE_VARTEXT2)
361 if (!pos->language)
362 pos->charset=default_charset_info;
363 else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
365 my_errno=HA_ERR_UNKNOWN_CHARSET;
366 goto err;
369 else if (pos->type == HA_KEYTYPE_BINARY)
370 pos->charset= &my_charset_bin;
372 if (share->keyinfo[i].flag & HA_SPATIAL)
374 #ifdef HAVE_SPATIAL
375 uint sp_segs=SPDIMS*2;
376 share->keyinfo[i].seg=pos-sp_segs;
377 share->keyinfo[i].keysegs--;
378 #else
379 my_errno=HA_ERR_UNSUPPORTED;
380 goto err;
381 #endif
383 else if (share->keyinfo[i].flag & HA_FULLTEXT)
385 if (!fulltext_keys)
386 { /* 4.0 compatibility code, to be removed in 5.0 */
387 share->keyinfo[i].seg=pos-FT_SEGS;
388 share->keyinfo[i].keysegs-=FT_SEGS;
390 else
392 uint k;
393 share->keyinfo[i].seg=pos;
394 for (k=0; k < FT_SEGS; k++)
396 *pos= ft_keysegs[k];
397 pos[0].language= pos[-1].language;
398 if (!(pos[0].charset= pos[-1].charset))
400 my_errno=HA_ERR_CRASHED;
401 goto err;
403 pos++;
406 if (!share->ft2_keyinfo.seg)
408 memcpy(& share->ft2_keyinfo, & share->keyinfo[i], sizeof(MI_KEYDEF));
409 share->ft2_keyinfo.keysegs=1;
410 share->ft2_keyinfo.flag=0;
411 share->ft2_keyinfo.keylength=
412 share->ft2_keyinfo.minlength=
413 share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
414 share->ft2_keyinfo.seg=pos-1;
415 share->ft2_keyinfo.end=pos;
416 setup_key_functions(& share->ft2_keyinfo);
418 share->keyinfo[i].ftkey_nr= ftkey_nr++;
420 setup_key_functions(share->keyinfo+i);
421 share->keyinfo[i].end=pos;
422 pos->type=HA_KEYTYPE_END; /* End */
423 pos->length=share->base.rec_reflength;
424 pos->null_bit=0;
425 pos->flag=0; /* For purify */
426 pos++;
429 for (i=0 ; i < uniques ; i++)
431 disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
432 disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
433 HA_KEYSEG_SIZE, end_pos);
434 share->uniqueinfo[i].seg=pos;
435 for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
437 disk_pos=mi_keyseg_read(disk_pos, pos);
438 if (pos->type == HA_KEYTYPE_TEXT ||
439 pos->type == HA_KEYTYPE_VARTEXT1 ||
440 pos->type == HA_KEYTYPE_VARTEXT2)
442 if (!pos->language)
443 pos->charset=default_charset_info;
444 else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
446 my_errno=HA_ERR_UNKNOWN_CHARSET;
447 goto err;
451 share->uniqueinfo[i].end=pos;
452 pos->type=HA_KEYTYPE_END; /* End */
453 pos->null_bit=0;
454 pos->flag=0;
455 pos++;
457 share->ftkeys= ftkey_nr;
460 disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
461 for (i=j=offset=0 ; i < share->base.fields ; i++)
463 disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
464 share->rec[i].pack_type=0;
465 share->rec[i].huff_tree=0;
466 share->rec[i].offset=offset;
467 if (share->rec[i].type == (int) FIELD_BLOB)
469 share->blobs[j].pack_length=
470 share->rec[i].length-portable_sizeof_char_ptr;
471 share->blobs[j].offset=offset;
472 j++;
474 offset+=share->rec[i].length;
476 share->rec[i].type=(int) FIELD_LAST; /* End marker */
477 if (offset > share->base.reclength)
479 /* purecov: begin inspected */
480 my_errno= HA_ERR_CRASHED;
481 goto err;
482 /* purecov: end */
485 if (! lock_error)
487 VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
488 lock_error=1; /* Database unlocked */
491 if (mi_open_datafile(&info, share, name, -1))
492 goto err;
493 errpos=5;
495 share->kfile=kfile;
496 share->this_process=(ulong) getpid();
497 share->last_process= share->state.process;
498 share->base.key_parts=key_parts;
499 share->base.all_key_parts=key_parts+unique_key_parts;
500 if (!(share->last_version=share->state.version))
501 share->last_version=1; /* Safety */
502 share->rec_reflength=share->base.rec_reflength; /* May be changed */
503 share->base.margin_key_file_length=(share->base.max_key_file_length -
504 (keys ? MI_INDEX_BLOCK_MARGIN *
505 share->blocksize * keys : 0));
506 share->blocksize=min(IO_SIZE,myisam_block_size);
507 share->data_file_type=STATIC_RECORD;
508 if (share->options & HA_OPTION_COMPRESS_RECORD)
510 share->data_file_type = COMPRESSED_RECORD;
511 share->options|= HA_OPTION_READ_ONLY_DATA;
512 info.s=share;
513 if (_mi_read_pack_info(&info,
514 (pbool)
515 test(!(share->options &
516 (HA_OPTION_PACK_RECORD |
517 HA_OPTION_TEMP_COMPRESS_RECORD)))))
518 goto err;
520 else if (share->options & HA_OPTION_PACK_RECORD)
521 share->data_file_type = DYNAMIC_RECORD;
522 my_afree(disk_cache);
523 mi_setup_functions(share);
524 share->is_log_table= FALSE;
525 #ifdef THREAD
526 thr_lock_init(&share->lock);
527 VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
528 for (i=0; i<keys; i++)
529 VOID(my_rwlock_init(&share->key_root_lock[i], NULL));
530 VOID(my_rwlock_init(&share->mmap_lock, NULL));
531 if (!thr_lock_inited)
533 /* Probably a single threaded program; Don't use concurrent inserts */
534 myisam_concurrent_insert=0;
536 else if (myisam_concurrent_insert)
538 share->concurrent_insert=
539 ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
540 HA_OPTION_COMPRESS_RECORD |
541 HA_OPTION_TEMP_COMPRESS_RECORD)) ||
542 (open_flags & HA_OPEN_TMP_TABLE) ||
543 have_rtree) ? 0 : 1;
544 if (share->concurrent_insert)
546 share->lock.get_status=mi_get_status;
547 share->lock.copy_status=mi_copy_status;
548 share->lock.update_status=mi_update_status;
549 share->lock.restore_status= mi_restore_status;
550 share->lock.check_status=mi_check_status;
553 #endif
555 Memory mapping can only be requested after initializing intern_lock.
557 if (open_flags & HA_OPEN_MMAP)
559 info.s= share;
560 mi_extra(&info, HA_EXTRA_MMAP, 0);
563 else
565 share= old_info->s;
566 if (mode == O_RDWR && share->mode == O_RDONLY)
568 my_errno=EACCES; /* Can't open in write mode */
569 goto err;
571 if (mi_open_datafile(&info, share, name, old_info->dfile))
572 goto err;
573 errpos=5;
574 have_rtree= old_info->rtree_recursion_state != NULL;
577 /* alloc and set up private structure parts */
578 if (!my_multi_malloc(MY_WME,
579 &m_info,sizeof(MI_INFO),
580 &info.blobs,sizeof(MI_BLOB)*share->base.blobs,
581 &info.buff,(share->base.max_key_block_length*2+
582 share->base.max_key_length),
583 &info.lastkey,share->base.max_key_length*3+1,
584 &info.first_mbr_key, share->base.max_key_length,
585 &info.filename,strlen(name)+1,
586 &info.rtree_recursion_state,have_rtree ? 1024 : 0,
587 NullS))
588 goto err;
589 errpos=6;
591 if (!have_rtree)
592 info.rtree_recursion_state= NULL;
594 strmov(info.filename,name);
595 memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
596 info.lastkey2=info.lastkey+share->base.max_key_length;
598 info.s=share;
599 info.lastpos= HA_OFFSET_ERROR;
600 info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
601 info.opt_flag=READ_CHECK_USED;
602 info.this_unique= (ulong) info.dfile; /* Uniq number in process */
603 if (share->data_file_type == COMPRESSED_RECORD)
604 info.this_unique= share->state.unique;
605 info.this_loop=0; /* Update counter */
606 info.last_unique= share->state.unique;
607 info.last_loop= share->state.update_count;
608 if (mode == O_RDONLY)
609 share->options|=HA_OPTION_READ_ONLY_DATA;
610 info.lock_type=F_UNLCK;
611 info.quick_mode=0;
612 info.bulk_insert=0;
613 info.ft1_to_ft2=0;
614 info.errkey= -1;
615 info.page_changed=1;
616 pthread_mutex_lock(&share->intern_lock);
617 info.read_record=share->read_record;
618 share->reopen++;
619 share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
620 if (share->options & HA_OPTION_READ_ONLY_DATA)
622 info.lock_type=F_RDLCK;
623 share->r_locks++;
624 share->tot_locks++;
626 if ((open_flags & HA_OPEN_TMP_TABLE) ||
627 (share->options & HA_OPTION_TMP_TABLE))
629 share->temporary=share->delay_key_write=1;
630 share->write_flag=MYF(MY_NABP);
631 share->w_locks++; /* We don't have to update status */
632 share->tot_locks++;
633 info.lock_type=F_WRLCK;
635 if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) ||
636 (share->options & HA_OPTION_DELAY_KEY_WRITE)) &&
637 myisam_delay_key_write)
638 share->delay_key_write=1;
639 info.state= &share->state.state; /* Change global values by default */
640 pthread_mutex_unlock(&share->intern_lock);
642 /* Allocate buffer for one record */
644 /* prerequisites: bzero(info) && info->s=share; are met. */
645 if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff))
646 goto err;
647 bzero(info.rec_buff, mi_get_rec_buff_len(&info, info.rec_buff));
649 *m_info=info;
650 #ifdef THREAD
651 thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
652 #endif
653 m_info->open_list.data=(void*) m_info;
654 myisam_open_list=list_add(myisam_open_list,&m_info->open_list);
656 pthread_mutex_unlock(&THR_LOCK_myisam);
658 bzero(info.buff, share->base.max_key_block_length * 2);
660 if (myisam_log_file >= 0)
662 intern_filename(name_buff,share->index_file_name);
663 _myisam_log(MI_LOG_OPEN, m_info, (uchar*) name_buff, strlen(name_buff));
665 DBUG_RETURN(m_info);
667 err:
668 save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
669 if ((save_errno == HA_ERR_CRASHED) ||
670 (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
671 (save_errno == HA_ERR_CRASHED_ON_REPAIR))
672 mi_report_error(save_errno, name);
673 switch (errpos) {
674 case 6:
675 my_free((uchar*) m_info,MYF(0));
676 /* fall through */
677 case 5:
678 VOID(my_close(info.dfile,MYF(0)));
679 if (old_info)
680 break; /* Don't remove open table */
681 /* fall through */
682 case 4:
683 my_free((uchar*) share,MYF(0));
684 /* fall through */
685 case 3:
686 if (! lock_error)
687 VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
688 /* fall through */
689 case 2:
690 my_afree(disk_cache);
691 /* fall through */
692 case 1:
693 VOID(my_close(kfile,MYF(0)));
694 /* fall through */
695 case 0:
696 default:
697 break;
699 pthread_mutex_unlock(&THR_LOCK_myisam);
700 my_errno=save_errno;
701 DBUG_RETURN (NULL);
702 } /* mi_open */
705 uchar *mi_alloc_rec_buff(MI_INFO *info, ulong length, uchar **buf)
707 uint extra;
708 uint32 UNINIT_VAR(old_length);
709 LINT_INIT(old_length);
711 if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
713 uchar *newptr = *buf;
715 /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
716 if (length == (ulong) -1)
718 if (info->s->options & HA_OPTION_COMPRESS_RECORD)
719 length= max(info->s->base.pack_reclength, info->s->max_pack_length);
720 else
721 length= info->s->base.pack_reclength;
722 length= max(length, info->s->base.max_key_length);
723 /* Avoid unnecessary realloc */
724 if (newptr && length == old_length)
725 return newptr;
728 extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
729 ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
730 MI_REC_BUFF_OFFSET : 0);
731 if (extra && newptr)
732 newptr-= MI_REC_BUFF_OFFSET;
733 if (!(newptr=(uchar*) my_realloc((uchar*)newptr, length+extra+8,
734 MYF(MY_ALLOW_ZERO_PTR))))
735 return newptr;
736 *((uint32 *) newptr)= (uint32) length;
737 *buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
739 return *buf;
743 ulonglong mi_safe_mul(ulonglong a, ulonglong b)
745 ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */
747 if (!a || max_val / a < b)
748 return max_val;
749 return a*b;
752 /* Set up functions in structs */
754 void mi_setup_functions(register MYISAM_SHARE *share)
756 if (share->options & HA_OPTION_COMPRESS_RECORD)
758 share->read_record=_mi_read_pack_record;
759 share->read_rnd=_mi_read_rnd_pack_record;
760 if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
761 share->calc_checksum=0; /* No checksum */
762 else if (share->options & HA_OPTION_PACK_RECORD)
763 share->calc_checksum= mi_checksum;
764 else
765 share->calc_checksum= mi_static_checksum;
767 else if (share->options & HA_OPTION_PACK_RECORD)
769 share->read_record=_mi_read_dynamic_record;
770 share->read_rnd=_mi_read_rnd_dynamic_record;
771 share->delete_record=_mi_delete_dynamic_record;
772 share->compare_record=_mi_cmp_dynamic_record;
773 share->compare_unique=_mi_cmp_dynamic_unique;
774 share->calc_checksum= mi_checksum;
776 /* add bits used to pack data to pack_reclength for faster allocation */
777 share->base.pack_reclength+= share->base.pack_bits;
778 if (share->base.blobs)
780 share->update_record=_mi_update_blob_record;
781 share->write_record=_mi_write_blob_record;
783 else
785 share->write_record=_mi_write_dynamic_record;
786 share->update_record=_mi_update_dynamic_record;
789 else
791 share->read_record=_mi_read_static_record;
792 share->read_rnd=_mi_read_rnd_static_record;
793 share->delete_record=_mi_delete_static_record;
794 share->compare_record=_mi_cmp_static_record;
795 share->update_record=_mi_update_static_record;
796 share->write_record=_mi_write_static_record;
797 share->compare_unique=_mi_cmp_static_unique;
798 share->calc_checksum= mi_static_checksum;
800 share->file_read= mi_nommap_pread;
801 share->file_write= mi_nommap_pwrite;
802 if (!(share->options & HA_OPTION_CHECKSUM))
803 share->calc_checksum=0;
804 return;
808 static void setup_key_functions(register MI_KEYDEF *keyinfo)
810 if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
812 #ifdef HAVE_RTREE_KEYS
813 keyinfo->ck_insert = rtree_insert;
814 keyinfo->ck_delete = rtree_delete;
815 #else
816 DBUG_ASSERT(0); /* mi_open should check it never happens */
817 #endif
819 else
821 keyinfo->ck_insert = _mi_ck_write;
822 keyinfo->ck_delete = _mi_ck_delete;
824 if (keyinfo->flag & HA_BINARY_PACK_KEY)
825 { /* Simple prefix compression */
826 keyinfo->bin_search=_mi_seq_search;
827 keyinfo->get_key=_mi_get_binary_pack_key;
828 keyinfo->pack_key=_mi_calc_bin_pack_key_length;
829 keyinfo->store_key=_mi_store_bin_pack_key;
831 else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
833 keyinfo->get_key= _mi_get_pack_key;
834 if (keyinfo->seg[0].flag & HA_PACK_KEY)
835 { /* Prefix compression */
837 _mi_prefix_search() compares end-space against ASCII blank (' ').
838 It cannot be used for character sets, that do not encode the
839 blank character like ASCII does. UCS2 is an example. All
840 character sets with a fixed width > 1 or a mimimum width > 1
841 cannot represent blank like ASCII does. In these cases we have
842 to use _mi_seq_search() for the search.
844 if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
845 (keyinfo->seg->flag & HA_NULL_PART) ||
846 (keyinfo->seg->charset->mbminlen > 1))
847 keyinfo->bin_search=_mi_seq_search;
848 else
849 keyinfo->bin_search=_mi_prefix_search;
850 keyinfo->pack_key=_mi_calc_var_pack_key_length;
851 keyinfo->store_key=_mi_store_var_pack_key;
853 else
855 keyinfo->bin_search=_mi_seq_search;
856 keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
857 keyinfo->store_key=_mi_store_static_key;
860 else
862 keyinfo->bin_search=_mi_bin_search;
863 keyinfo->get_key=_mi_get_static_key;
864 keyinfo->pack_key=_mi_calc_static_key_length;
865 keyinfo->store_key=_mi_store_static_key;
867 return;
872 Function to save and store the header in the index file (.MYI)
875 uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
877 uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
878 uchar *ptr=buff;
879 uint i, keys= (uint) state->header.keys,
880 key_blocks=state->header.max_block_size_index;
881 DBUG_ENTER("mi_state_info_write");
883 memcpy_fixed(ptr,&state->header,sizeof(state->header));
884 ptr+=sizeof(state->header);
886 /* open_count must be first because of _mi_mark_file_changed ! */
887 mi_int2store(ptr,state->open_count); ptr +=2;
888 *ptr++= (uchar)state->changed; *ptr++= state->sortkey;
889 mi_rowstore(ptr,state->state.records); ptr +=8;
890 mi_rowstore(ptr,state->state.del); ptr +=8;
891 mi_rowstore(ptr,state->split); ptr +=8;
892 mi_sizestore(ptr,state->dellink); ptr +=8;
893 mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
894 mi_sizestore(ptr,state->state.data_file_length); ptr +=8;
895 mi_sizestore(ptr,state->state.empty); ptr +=8;
896 mi_sizestore(ptr,state->state.key_empty); ptr +=8;
897 mi_int8store(ptr,state->auto_increment); ptr +=8;
898 mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8;
899 mi_int4store(ptr,state->process); ptr +=4;
900 mi_int4store(ptr,state->unique); ptr +=4;
901 mi_int4store(ptr,state->status); ptr +=4;
902 mi_int4store(ptr,state->update_count); ptr +=4;
904 ptr+=state->state_diff_length;
906 for (i=0; i < keys; i++)
908 mi_sizestore(ptr,state->key_root[i]); ptr +=8;
910 for (i=0; i < key_blocks; i++)
912 mi_sizestore(ptr,state->key_del[i]); ptr +=8;
914 if (pWrite & 2) /* From isamchk */
916 uint key_parts= mi_uint2korr(state->header.key_parts);
917 mi_int4store(ptr,state->sec_index_changed); ptr +=4;
918 mi_int4store(ptr,state->sec_index_used); ptr +=4;
919 mi_int4store(ptr,state->version); ptr +=4;
920 mi_int8store(ptr,state->key_map); ptr +=8;
921 mi_int8store(ptr,(ulonglong) state->create_time); ptr +=8;
922 mi_int8store(ptr,(ulonglong) state->recover_time); ptr +=8;
923 mi_int8store(ptr,(ulonglong) state->check_time); ptr +=8;
924 mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8;
925 for (i=0 ; i < key_parts ; i++)
927 mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4;
931 if (pWrite & 1)
932 DBUG_RETURN(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
933 MYF(MY_NABP | MY_THREADSAFE)) != 0);
934 DBUG_RETURN(my_write(file, buff, (size_t) (ptr-buff),
935 MYF(MY_NABP)) != 0);
939 uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state)
941 uint i,keys,key_parts,key_blocks;
942 memcpy_fixed(&state->header,ptr, sizeof(state->header));
943 ptr +=sizeof(state->header);
944 keys=(uint) state->header.keys;
945 key_parts=mi_uint2korr(state->header.key_parts);
946 key_blocks=state->header.max_block_size_index;
948 state->open_count = mi_uint2korr(ptr); ptr +=2;
949 state->changed= *ptr++;
950 state->sortkey = (uint) *ptr++;
951 state->state.records= mi_rowkorr(ptr); ptr +=8;
952 state->state.del = mi_rowkorr(ptr); ptr +=8;
953 state->split = mi_rowkorr(ptr); ptr +=8;
954 state->dellink= mi_sizekorr(ptr); ptr +=8;
955 state->state.key_file_length = mi_sizekorr(ptr); ptr +=8;
956 state->state.data_file_length= mi_sizekorr(ptr); ptr +=8;
957 state->state.empty = mi_sizekorr(ptr); ptr +=8;
958 state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
959 state->auto_increment=mi_uint8korr(ptr); ptr +=8;
960 state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8;
961 state->process= mi_uint4korr(ptr); ptr +=4;
962 state->unique = mi_uint4korr(ptr); ptr +=4;
963 state->status = mi_uint4korr(ptr); ptr +=4;
964 state->update_count=mi_uint4korr(ptr); ptr +=4;
966 ptr+= state->state_diff_length;
968 for (i=0; i < keys; i++)
970 state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
972 for (i=0; i < key_blocks; i++)
974 state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
976 state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
977 state->sec_index_used = mi_uint4korr(ptr); ptr +=4;
978 state->version = mi_uint4korr(ptr); ptr +=4;
979 state->key_map = mi_uint8korr(ptr); ptr +=8;
980 state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
981 state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
982 state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8;
983 state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
984 for (i=0 ; i < key_parts ; i++)
986 state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
988 return ptr;
992 uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead)
994 uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
996 if (!myisam_single_user)
998 if (pRead)
1000 if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
1001 return 1;
1003 else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
1004 return 1;
1005 mi_state_info_read(buff, state);
1007 return 0;
1011 /****************************************************************************
1012 ** store and read of MI_BASE_INFO
1013 ****************************************************************************/
1015 uint mi_base_info_write(File file, MI_BASE_INFO *base)
1017 uchar buff[MI_BASE_INFO_SIZE], *ptr=buff;
1019 mi_sizestore(ptr,base->keystart); ptr +=8;
1020 mi_sizestore(ptr,base->max_data_file_length); ptr +=8;
1021 mi_sizestore(ptr,base->max_key_file_length); ptr +=8;
1022 mi_rowstore(ptr,base->records); ptr +=8;
1023 mi_rowstore(ptr,base->reloc); ptr +=8;
1024 mi_int4store(ptr,base->mean_row_length); ptr +=4;
1025 mi_int4store(ptr,base->reclength); ptr +=4;
1026 mi_int4store(ptr,base->pack_reclength); ptr +=4;
1027 mi_int4store(ptr,base->min_pack_length); ptr +=4;
1028 mi_int4store(ptr,base->max_pack_length); ptr +=4;
1029 mi_int4store(ptr,base->min_block_length); ptr +=4;
1030 mi_int4store(ptr,base->fields); ptr +=4;
1031 mi_int4store(ptr,base->pack_fields); ptr +=4;
1032 *ptr++=base->rec_reflength;
1033 *ptr++=base->key_reflength;
1034 *ptr++=base->keys;
1035 *ptr++=base->auto_key;
1036 mi_int2store(ptr,base->pack_bits); ptr +=2;
1037 mi_int2store(ptr,base->blobs); ptr +=2;
1038 mi_int2store(ptr,base->max_key_block_length); ptr +=2;
1039 mi_int2store(ptr,base->max_key_length); ptr +=2;
1040 mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2;
1041 *ptr++= base->extra_alloc_procent;
1042 *ptr++= base->raid_type;
1043 mi_int2store(ptr,base->raid_chunks); ptr +=2;
1044 mi_int4store(ptr,base->raid_chunksize); ptr +=4;
1045 bzero(ptr,6); ptr +=6; /* extra */
1046 return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1050 uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
1052 base->keystart = mi_sizekorr(ptr); ptr +=8;
1053 base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
1054 base->max_key_file_length = mi_sizekorr(ptr); ptr +=8;
1055 base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8;
1056 base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8;
1057 base->mean_row_length = mi_uint4korr(ptr); ptr +=4;
1058 base->reclength = mi_uint4korr(ptr); ptr +=4;
1059 base->pack_reclength = mi_uint4korr(ptr); ptr +=4;
1060 base->min_pack_length = mi_uint4korr(ptr); ptr +=4;
1061 base->max_pack_length = mi_uint4korr(ptr); ptr +=4;
1062 base->min_block_length = mi_uint4korr(ptr); ptr +=4;
1063 base->fields = mi_uint4korr(ptr); ptr +=4;
1064 base->pack_fields = mi_uint4korr(ptr); ptr +=4;
1066 base->rec_reflength = *ptr++;
1067 base->key_reflength = *ptr++;
1068 base->keys= *ptr++;
1069 base->auto_key= *ptr++;
1070 base->pack_bits = mi_uint2korr(ptr); ptr +=2;
1071 base->blobs = mi_uint2korr(ptr); ptr +=2;
1072 base->max_key_block_length= mi_uint2korr(ptr); ptr +=2;
1073 base->max_key_length = mi_uint2korr(ptr); ptr +=2;
1074 base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2;
1075 base->extra_alloc_procent = *ptr++;
1076 base->raid_type= *ptr++;
1077 base->raid_chunks= mi_uint2korr(ptr); ptr +=2;
1078 base->raid_chunksize= mi_uint4korr(ptr); ptr +=4;
1079 /* TO BE REMOVED: Fix for old RAID files */
1080 if (base->raid_type == 0)
1082 base->raid_chunks=0;
1083 base->raid_chunksize=0;
1086 ptr+=6;
1087 return ptr;
1090 /*--------------------------------------------------------------------------
1091 mi_keydef
1092 ---------------------------------------------------------------------------*/
1094 uint mi_keydef_write(File file, MI_KEYDEF *keydef)
1096 uchar buff[MI_KEYDEF_SIZE];
1097 uchar *ptr=buff;
1099 *ptr++ = (uchar) keydef->keysegs;
1100 *ptr++ = keydef->key_alg; /* Rtree or Btree */
1101 mi_int2store(ptr,keydef->flag); ptr +=2;
1102 mi_int2store(ptr,keydef->block_length); ptr +=2;
1103 mi_int2store(ptr,keydef->keylength); ptr +=2;
1104 mi_int2store(ptr,keydef->minlength); ptr +=2;
1105 mi_int2store(ptr,keydef->maxlength); ptr +=2;
1106 return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1109 uchar *mi_keydef_read(uchar *ptr, MI_KEYDEF *keydef)
1111 keydef->keysegs = (uint) *ptr++;
1112 keydef->key_alg = *ptr++; /* Rtree or Btree */
1114 keydef->flag = mi_uint2korr(ptr); ptr +=2;
1115 keydef->block_length = mi_uint2korr(ptr); ptr +=2;
1116 keydef->keylength = mi_uint2korr(ptr); ptr +=2;
1117 keydef->minlength = mi_uint2korr(ptr); ptr +=2;
1118 keydef->maxlength = mi_uint2korr(ptr); ptr +=2;
1119 keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
1120 keydef->underflow_block_length=keydef->block_length/3;
1121 keydef->version = 0; /* Not saved */
1122 keydef->parser = &ft_default_parser;
1123 keydef->ftkey_nr = 0;
1124 return ptr;
1127 /***************************************************************************
1128 ** mi_keyseg
1129 ***************************************************************************/
1131 int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
1133 uchar buff[HA_KEYSEG_SIZE];
1134 uchar *ptr=buff;
1135 ulong pos;
1137 *ptr++= keyseg->type;
1138 *ptr++= keyseg->language;
1139 *ptr++= keyseg->null_bit;
1140 *ptr++= keyseg->bit_start;
1141 *ptr++= keyseg->bit_end;
1142 *ptr++= keyseg->bit_length;
1143 mi_int2store(ptr,keyseg->flag); ptr+=2;
1144 mi_int2store(ptr,keyseg->length); ptr+=2;
1145 mi_int4store(ptr,keyseg->start); ptr+=4;
1146 pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
1147 mi_int4store(ptr, pos);
1148 ptr+=4;
1150 return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1154 uchar *mi_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
1156 keyseg->type = *ptr++;
1157 keyseg->language = *ptr++;
1158 keyseg->null_bit = *ptr++;
1159 keyseg->bit_start = *ptr++;
1160 keyseg->bit_end = *ptr++;
1161 keyseg->bit_length = *ptr++;
1162 keyseg->flag = mi_uint2korr(ptr); ptr +=2;
1163 keyseg->length = mi_uint2korr(ptr); ptr +=2;
1164 keyseg->start = mi_uint4korr(ptr); ptr +=4;
1165 keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
1166 keyseg->charset=0; /* Will be filled in later */
1167 if (keyseg->null_bit)
1168 /* We adjust bit_pos if null_bit is last in the byte */
1169 keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == (1 << 7)));
1170 else
1172 keyseg->bit_pos= (uint16)keyseg->null_pos;
1173 keyseg->null_pos= 0;
1175 return ptr;
1178 /*--------------------------------------------------------------------------
1179 mi_uniquedef
1180 ---------------------------------------------------------------------------*/
1182 uint mi_uniquedef_write(File file, MI_UNIQUEDEF *def)
1184 uchar buff[MI_UNIQUEDEF_SIZE];
1185 uchar *ptr=buff;
1187 mi_int2store(ptr,def->keysegs); ptr+=2;
1188 *ptr++= (uchar) def->key;
1189 *ptr++ = (uchar) def->null_are_equal;
1191 return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1194 uchar *mi_uniquedef_read(uchar *ptr, MI_UNIQUEDEF *def)
1196 def->keysegs = mi_uint2korr(ptr);
1197 def->key = ptr[2];
1198 def->null_are_equal=ptr[3];
1199 return ptr+4; /* 1 extra byte */
1202 /***************************************************************************
1203 ** MI_COLUMNDEF
1204 ***************************************************************************/
1206 uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo)
1208 uchar buff[MI_COLUMNDEF_SIZE];
1209 uchar *ptr=buff;
1211 mi_int2store(ptr,recinfo->type); ptr +=2;
1212 mi_int2store(ptr,recinfo->length); ptr +=2;
1213 *ptr++ = recinfo->null_bit;
1214 mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
1215 return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1218 uchar *mi_recinfo_read(uchar *ptr, MI_COLUMNDEF *recinfo)
1220 recinfo->type= mi_sint2korr(ptr); ptr +=2;
1221 recinfo->length=mi_uint2korr(ptr); ptr +=2;
1222 recinfo->null_bit= (uint8) *ptr++;
1223 recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
1224 return ptr;
1227 /**************************************************************************
1228 Open data file with or without RAID
1229 We can't use dup() here as the data file descriptors need to have different
1230 active seek-positions.
1232 The argument file_to_dup is here for the future if there would on some OS
1233 exist a dup()-like call that would give us two different file descriptors.
1234 *************************************************************************/
1236 int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name,
1237 File file_to_dup __attribute__((unused)))
1239 char *data_name= share->data_file_name;
1240 char real_data_name[FN_REFLEN];
1242 if (org_name)
1244 fn_format(real_data_name,org_name,"",MI_NAME_DEXT,4);
1245 if (my_is_symlink(real_data_name))
1247 if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
1248 (*myisam_test_invalid_symlink)(real_data_name))
1250 my_errno= HA_WRONG_CREATE_OPTION;
1251 return 1;
1253 data_name= real_data_name;
1256 #ifdef USE_RAID
1257 if (share->base.raid_type)
1259 info->dfile=my_raid_open(data_name,
1260 share->mode | O_SHARE,
1261 share->base.raid_type,
1262 share->base.raid_chunks,
1263 share->base.raid_chunksize,
1264 MYF(MY_WME | MY_RAID));
1266 else
1267 #endif
1268 info->dfile=my_open(data_name, share->mode | O_SHARE, MYF(MY_WME));
1269 return info->dfile >= 0 ? 0 : 1;
1273 int mi_open_keyfile(MYISAM_SHARE *share)
1275 if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE,
1276 MYF(MY_WME))) < 0)
1277 return 1;
1278 return 0;
1283 Disable all indexes.
1285 SYNOPSIS
1286 mi_disable_indexes()
1287 info A pointer to the MyISAM storage engine MI_INFO struct.
1289 DESCRIPTION
1290 Disable all indexes.
1292 RETURN
1293 0 ok
1296 int mi_disable_indexes(MI_INFO *info)
1298 MYISAM_SHARE *share= info->s;
1300 mi_clear_all_keys_active(share->state.key_map);
1301 return 0;
1306 Enable all indexes
1308 SYNOPSIS
1309 mi_enable_indexes()
1310 info A pointer to the MyISAM storage engine MI_INFO struct.
1312 DESCRIPTION
1313 Enable all indexes. The indexes might have been disabled
1314 by mi_disable_index() before.
1315 The function works only if both data and indexes are empty,
1316 otherwise a repair is required.
1317 To be sure, call handler::delete_all_rows() before.
1319 RETURN
1320 0 ok
1321 HA_ERR_CRASHED data or index is non-empty.
1324 int mi_enable_indexes(MI_INFO *info)
1326 int error= 0;
1327 MYISAM_SHARE *share= info->s;
1329 if (share->state.state.data_file_length ||
1330 (share->state.state.key_file_length != share->base.keystart))
1332 mi_print_error(info->s, HA_ERR_CRASHED);
1333 error= HA_ERR_CRASHED;
1335 else
1336 mi_set_all_keys_active(share->state.key_map, share->base.keys);
1337 return error;
1342 Test if indexes are disabled.
1344 SYNOPSIS
1345 mi_indexes_are_disabled()
1346 info A pointer to the MyISAM storage engine MI_INFO struct.
1348 DESCRIPTION
1349 Test if indexes are disabled.
1351 RETURN
1352 0 indexes are not disabled
1353 1 all indexes are disabled
1354 2 non-unique indexes are disabled
1357 int mi_indexes_are_disabled(MI_INFO *info)
1359 MYISAM_SHARE *share= info->s;
1362 No keys or all are enabled. keys is the number of keys. Left shifted
1363 gives us only one bit set. When decreased by one, gives us all all bits
1364 up to this one set and it gets unset.
1366 if (!share->base.keys ||
1367 (mi_is_all_keys_active(share->state.key_map, share->base.keys)))
1368 return 0;
1370 /* All are disabled */
1371 if (mi_is_any_key_active(share->state.key_map))
1372 return 1;
1375 We have keys. Some enabled, some disabled.
1376 Don't check for any non-unique disabled but return directly 2
1378 return 2;