1/*
2 Copyright (c) 2000, 2011, Oracle and/or its affiliates
3
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.
7
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.
12
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 */
16
17/*
18 open a isam-database
19
20 Internal temporary tables
21 -------------------------
22 Since only single instance of internal temporary table is required by
23 optimizer, such tables are not registered on myisam_open_list. In effect
24 it means (a) THR_LOCK_myisam is not held while such table is being created,
25 opened or closed; (b) no iteration through myisam_open_list while opening a
26 table. This optimization gives nice scalability benefit in concurrent
27 environment. MEMORY internal temporary tables are optimized similarly.
28*/
29
30#include "fulltext.h"
31#include "sp_defs.h"
32#include "rt_index.h"
33#include <m_ctype.h>
34#include <mysql_version.h>
35
36#ifdef __WIN__
37#include <fcntl.h>
38#endif
39
40static void setup_key_functions(MI_KEYDEF *keyinfo);
41#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
42 pos+=size;}
43
44
45#define disk_pos_assert(pos, end_pos) \
46if (pos > end_pos) \
47{ \
48 my_errno=HA_ERR_CRASHED; \
49 goto err; \
50}
51
52
53/******************************************************************************
54** Return the shared struct if the table is already open.
55** In MySQL the server will handle version issues.
56******************************************************************************/
57
58MI_INFO *test_if_reopen(char *filename)
59{
60 LIST *pos;
61
62 for (pos=myisam_open_list ; pos ; pos=pos->next)
63 {
64 MI_INFO *info=(MI_INFO*) pos->data;
65 MYISAM_SHARE *share=info->s;
66 DBUG_ASSERT(strcmp(share->unique_file_name,filename) ||
67 share->last_version);
68 if (!strcmp(share->unique_file_name,filename) && share->last_version)
69 return info;
70 }
71 return 0;
72}
73
74
75/******************************************************************************
76 open a MyISAM database.
77 See my_base.h for the handle_locking argument
78 if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
79 is marked crashed or if we are not using locking and the table doesn't
80 have an open count of 0.
81******************************************************************************/
82
83MI_INFO *mi_open(const char *name, int mode, uint open_flags)
84{
85 int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err;
86 uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
87 key_parts,unique_key_parts,base_key_parts,fulltext_keys,uniques;
88 uint internal_table= open_flags & HA_OPEN_INTERNAL_TABLE;
89 char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
90 data_name[FN_REFLEN];
91 uchar *UNINIT_VAR(disk_cache), *disk_pos, *end_pos;
92 MI_INFO info,*UNINIT_VAR(m_info),*old_info= NULL;
93 MYISAM_SHARE share_buff,*share;
94 ulong *rec_per_key_part= 0;
95 my_off_t *key_root, *key_del;
96 ulonglong max_key_file_length, max_data_file_length;
97 DBUG_ENTER("mi_open");
98
99 kfile= -1;
100 lock_error=1;
101 errpos=0;
102 head_length=sizeof(share_buff.state.header);
103 bzero((uchar*) &info,sizeof(info));
104
105 realpath_err= my_realpath(name_buff,
106 fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
107 if (realpath_err > 0) /* File not found, no point in looking further. */
108 {
109 DBUG_RETURN(NULL);
110 }
111
112 if (my_is_symlink(org_name) &&
113 (realpath_err || mysys_test_invalid_symlink(name_buff)))
114 {
115 my_errno= HA_WRONG_CREATE_OPTION;
116 DBUG_RETURN (NULL);
117 }
118
119 if (!internal_table)
120 {
121 mysql_mutex_lock(&THR_LOCK_myisam);
122 old_info= test_if_reopen(name_buff);
123 }
124
125 if (!old_info)
126 {
127 share= &share_buff;
128 bzero((uchar*) &share_buff,sizeof(share_buff));
129 share_buff.key_cache= multi_key_cache_search((uchar*) name_buff,
130 (uint)strlen(name_buff),
131 dflt_key_cache);
132
133 DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
134 if (strstr(name, "crashed"))
135 {
136 my_errno= HA_ERR_CRASHED;
137 goto err;
138 });
139
140 DEBUG_SYNC_C("mi_open_kfile");
141 if ((kfile= mysql_file_open(mi_key_file_kfile, name_buff,
142 (open_mode= O_RDWR) | O_SHARE | O_NOFOLLOW,
143 MYF(MY_NOSYMLINKS))) < 0)
144 {
145 if ((errno != EROFS && errno != EACCES) ||
146 mode != O_RDONLY ||
147 (kfile= mysql_file_open(mi_key_file_kfile, name_buff,
148 (open_mode= O_RDONLY) | O_SHARE| O_NOFOLLOW,
149 MYF(MY_NOSYMLINKS))) < 0)
150 goto err;
151 }
152 share->mode=open_mode;
153 errpos=1;
154 if (mysql_file_read(kfile, (uchar*)&share->state.header, head_length,
155 MYF(MY_NABP)))
156 {
157 my_errno= HA_ERR_NOT_A_TABLE;
158 goto err;
159 }
160 if (bcmp(share->state.header.file_version, myisam_file_magic, 4))
161 {
162 DBUG_PRINT("error",("Wrong header in %s",name_buff));
163 DBUG_DUMP("error_dump", share->state.header.file_version,
164 (size_t) head_length);
165 my_errno=HA_ERR_NOT_A_TABLE;
166 goto err;
167 }
168 share->options= mi_uint2korr(share->state.header.options);
169 if (share->options &
170 ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
171 HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
172 HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
173 HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
174 HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS))
175 {
176 DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
177 my_errno=HA_ERR_OLD_FILE;
178 goto err;
179 }
180 if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
181 ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
182 {
183 DBUG_PRINT("error", ("table cannot be openned from non-sql layer"));
184 my_errno= HA_ERR_UNSUPPORTED;
185 goto err;
186 }
187 /* Don't call realpath() if the name can't be a link */
188 if (!strcmp(name_buff, org_name) ||
189 my_readlink(index_name, org_name, MYF(0)) == -1)
190 (void) strmov(index_name, org_name);
191 *strrchr(org_name, '.')= '\0';
192 (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,
193 MY_APPEND_EXT|MY_UNPACK_FILENAME);
194 if (my_is_symlink(data_name))
195 {
196 if (my_realpath(data_name, data_name, MYF(0)))
197 goto err;
198 if (mysys_test_invalid_symlink(data_name))
199 {
200 my_errno= HA_WRONG_CREATE_OPTION;
201 goto err;
202 }
203 share->mode|= O_NOFOLLOW; /* all symlinks are resolved by realpath() */
204 }
205
206 info_length=mi_uint2korr(share->state.header.header_length);
207 base_pos=mi_uint2korr(share->state.header.base_pos);
208 if (!(disk_cache= (uchar*) my_alloca(info_length+128)))
209 {
210 my_errno=ENOMEM;
211 goto err;
212 }
213 end_pos=disk_cache+info_length;
214 errpos=2;
215
216 mysql_file_seek(kfile, 0L, MY_SEEK_SET, MYF(0));
217 if (!(open_flags & HA_OPEN_TMP_TABLE))
218 {
219 if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
220 MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ?
221 0 : MY_SHORT_WAIT))) &&
222 !(open_flags & HA_OPEN_IGNORE_IF_LOCKED))
223 goto err;
224 }
225 errpos=3;
226 if (mysql_file_read(kfile, disk_cache, info_length, MYF(MY_NABP)))
227 {
228 my_errno=HA_ERR_CRASHED;
229 goto err;
230 }
231 len=mi_uint2korr(share->state.header.state_info_length);
232 keys= (uint) share->state.header.keys;
233 uniques= (uint) share->state.header.uniques;
234 fulltext_keys= (uint) share->state.header.fulltext_keys;
235 base_key_parts= key_parts= mi_uint2korr(share->state.header.key_parts);
236 unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
237 if (len != MI_STATE_INFO_SIZE)
238 {
239 DBUG_PRINT("warning",
240 ("saved_state_info_length: %d state_info_length: %d",
241 len,MI_STATE_INFO_SIZE));
242 }
243 share->state_diff_length=len-MI_STATE_INFO_SIZE;
244
245 if (!mi_state_info_read(disk_cache, &share->state))
246 goto err;
247 rec_per_key_part= share->state.rec_per_key_part;
248 key_root= share->state.key_root;
249 key_del= share->state.key_del;
250
251 len= mi_uint2korr(share->state.header.base_info_length);
252 if (len != MI_BASE_INFO_SIZE)
253 {
254 DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
255 len,MI_BASE_INFO_SIZE));
256 }
257 disk_pos= mi_n_base_info_read(disk_cache + base_pos, &share->base);
258 share->state.state_length=base_pos;
259
260 if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
261 ((share->state.changed & STATE_CRASHED) ||
262 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
263 (my_disable_locking && share->state.open_count))))
264 {
265 DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u "
266 "changed: %u open_count: %u !locking: %d",
267 open_flags, share->state.changed,
268 share->state.open_count, my_disable_locking));
269 my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
270 HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
271 goto err;
272 }
273
274 /* sanity check */
275 if (share->base.keystart > 65535 ||
276 share->base.rec_reflength > 8 || share->base.key_reflength > 7)
277 {
278 my_errno=HA_ERR_CRASHED;
279 goto err;
280 }
281
282 key_parts+=fulltext_keys*FT_SEGS;
283 if (share->base.max_key_length > HA_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
284 key_parts > MI_MAX_KEY * HA_MAX_KEY_SEG)
285 {
286 DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts));
287 my_errno=HA_ERR_UNSUPPORTED;
288 goto err;
289 }
290
291 /* Correct max_file_length based on length of sizeof(off_t) */
292 max_data_file_length=
293 (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
294 (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
295 (mi_safe_mul(share->base.pack_reclength,
296 (ulonglong) 1 << (share->base.rec_reflength*8))-1);
297 max_key_file_length=
298 mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
299 ((ulonglong) 1 << (share->base.key_reflength*8))-1);
300#if SIZEOF_OFF_T == 4
301 set_if_smaller(max_data_file_length, INT_MAX32);
302 set_if_smaller(max_key_file_length, INT_MAX32);
303#endif
304 share->base.max_data_file_length=(my_off_t) max_data_file_length;
305 share->base.max_key_file_length=(my_off_t) max_key_file_length;
306
307 if (share->options & HA_OPTION_COMPRESS_RECORD)
308 share->base.max_key_length+=2; /* For safety */
309
310 /* Add space for node pointer */
311 share->base.max_key_length+= share->base.key_reflength;
312
313 if (!my_multi_malloc(MY_WME,
314 &share,sizeof(*share),
315 &share->state.rec_per_key_part,
316 sizeof(long)*base_key_parts,
317 &share->keyinfo,keys*sizeof(MI_KEYDEF),
318 &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
319 &share->keyparts,
320 (key_parts+unique_key_parts+keys+uniques) *
321 sizeof(HA_KEYSEG),
322 &share->rec,
323 (share->base.fields+1)*sizeof(MI_COLUMNDEF),
324 &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
325 &share->unique_file_name,strlen(name_buff)+1,
326 &share->index_file_name,strlen(index_name)+1,
327 &share->data_file_name,strlen(data_name)+1,
328 &share->state.key_root,keys*sizeof(my_off_t),
329 &share->state.key_del,
330 (share->state.header.max_block_size_index*sizeof(my_off_t)),
331 &share->key_root_lock, sizeof(mysql_rwlock_t)*keys,
332 &share->mmap_lock, sizeof(mysql_rwlock_t),
333 NullS))
334 goto err;
335 errpos=4;
336 *share=share_buff;
337 memcpy((char*) share->state.rec_per_key_part,
338 (char*) rec_per_key_part, sizeof(long)*base_key_parts);
339 memcpy((char*) share->state.key_root,
340 (char*) key_root, sizeof(my_off_t)*keys);
341 memcpy((char*) share->state.key_del,
342 (char*) key_del, (sizeof(my_off_t) *
343 share->state.header.max_block_size_index));
344 strmov(share->unique_file_name, name_buff);
345 share->unique_name_length= (uint)strlen(name_buff);
346 strmov(share->index_file_name, index_name);
347 strmov(share->data_file_name, data_name);
348
349 share->vreclength= share->base.reclength;
350 share->blocksize=MY_MIN(IO_SIZE,myisam_block_size);
351 {
352 HA_KEYSEG *pos=share->keyparts;
353 uint32 ftkey_nr= 1;
354 for (i=0 ; i < keys ; i++)
355 {
356 MI_KEYDEF *keyinfo= share->keyinfo + i;
357 keyinfo->share= share;
358 disk_pos=mi_keydef_read(disk_pos, keyinfo);
359 disk_pos_assert(disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE, end_pos);
360 if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
361 have_rtree=1;
362 set_if_smaller(share->blocksize, keyinfo->block_length);
363 keyinfo->seg= pos;
364 for (j=0 ; j < keyinfo->keysegs; j++,pos++)
365 {
366 disk_pos=mi_keyseg_read(disk_pos, pos);
367 if (pos->flag & HA_BLOB_PART &&
368 ! (share->options & (HA_OPTION_COMPRESS_RECORD |
369 HA_OPTION_PACK_RECORD)))
370 {
371 my_errno= HA_ERR_CRASHED;
372 goto err;
373 }
374 if (pos->type == HA_KEYTYPE_TEXT ||
375 pos->type == HA_KEYTYPE_VARTEXT1 ||
376 pos->type == HA_KEYTYPE_VARTEXT2)
377 {
378 if (!pos->language)
379 pos->charset=default_charset_info;
380 else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
381 {
382 my_errno=HA_ERR_UNKNOWN_CHARSET;
383 goto err;
384 }
385 }
386 else if (pos->type == HA_KEYTYPE_BINARY)
387 pos->charset= &my_charset_bin;
388 }
389 if (keyinfo->flag & HA_SPATIAL)
390 {
391#ifdef HAVE_SPATIAL
392 uint sp_segs= SPDIMS*2;
393 keyinfo->seg= pos - sp_segs;
394 DBUG_ASSERT(keyinfo->keysegs == sp_segs + 1);
395 keyinfo->keysegs= sp_segs;
396#else
397 my_errno=HA_ERR_UNSUPPORTED;
398 goto err;
399#endif
400 }
401 else if (keyinfo->flag & HA_FULLTEXT)
402 {
403 if (!fulltext_keys)
404 { /* 4.0 compatibility code, to be removed in 5.0 */
405 keyinfo->seg= pos - FT_SEGS;
406 keyinfo->keysegs-= FT_SEGS;
407 }
408 else
409 {
410 uint k;
411 keyinfo->seg= pos;
412 for (k=0; k < FT_SEGS; k++)
413 {
414 *pos= ft_keysegs[k];
415 pos[0].language= pos[-1].language;
416 if (!(pos[0].charset= pos[-1].charset))
417 {
418 my_errno=HA_ERR_CRASHED;
419 goto err;
420 }
421 pos++;
422 }
423 }
424 if (!share->ft2_keyinfo.seg)
425 {
426 memcpy(& share->ft2_keyinfo, keyinfo, sizeof(MI_KEYDEF));
427 share->ft2_keyinfo.keysegs=1;
428 share->ft2_keyinfo.flag=0;
429 share->ft2_keyinfo.keylength=
430 share->ft2_keyinfo.minlength=
431 share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
432 share->ft2_keyinfo.seg=pos-1;
433 share->ft2_keyinfo.end=pos;
434 setup_key_functions(& share->ft2_keyinfo);
435 }
436 keyinfo->ftkey_nr= ftkey_nr++;
437 }
438 setup_key_functions(keyinfo);
439 keyinfo->end= pos;
440 pos->type=HA_KEYTYPE_END; /* End */
441 pos->length=share->base.rec_reflength;
442 pos->null_bit=0;
443 pos->flag=0; /* For purify */
444 pos++;
445 }
446
447 for (i=0 ; i < uniques ; i++)
448 {
449 disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
450 disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
451 HA_KEYSEG_SIZE, end_pos);
452 share->uniqueinfo[i].seg=pos;
453 for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
454 {
455 disk_pos=mi_keyseg_read(disk_pos, pos);
456 if (pos->type == HA_KEYTYPE_TEXT ||
457 pos->type == HA_KEYTYPE_VARTEXT1 ||
458 pos->type == HA_KEYTYPE_VARTEXT2)
459 {
460 if (!pos->language)
461 pos->charset=default_charset_info;
462 else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
463 {
464 my_errno=HA_ERR_UNKNOWN_CHARSET;
465 goto err;
466 }
467 }
468 }
469 share->uniqueinfo[i].end=pos;
470 pos->type=HA_KEYTYPE_END; /* End */
471 pos->null_bit=0;
472 pos->flag=0;
473 pos++;
474 }
475 share->ftkeys= ftkey_nr;
476 }
477
478 disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
479 for (i=j=offset=0 ; i < share->base.fields ; i++)
480 {
481 disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
482 share->rec[i].pack_type=0;
483 share->rec[i].huff_tree=0;
484 share->rec[i].offset=offset;
485 if (share->rec[i].type == FIELD_BLOB)
486 {
487 share->blobs[j].pack_length=
488 share->rec[i].length - portable_sizeof_char_ptr;
489 share->blobs[j].offset=offset;
490 j++;
491 }
492 /* This is to detect how to calculate checksums */
493 if (share->rec[i].null_bit)
494 share->has_null_fields= 1;
495 if (share->rec[i].type == FIELD_VARCHAR)
496 share->has_varchar_fields= 1;
497 offset+=share->rec[i].length;
498 }
499 share->rec[i].type=(int) FIELD_LAST; /* End marker */
500 if (offset > share->base.reclength)
501 {
502 /* purecov: begin inspected */
503 my_errno= HA_ERR_CRASHED;
504 goto err;
505 /* purecov: end */
506 }
507
508 if (! lock_error)
509 {
510 (void) my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
511 lock_error=1; /* Database unlocked */
512 }
513
514 if (mi_open_datafile(&info, share))
515 goto err;
516 errpos=5;
517
518 share->kfile=kfile;
519 share->this_process=(ulong) getpid();
520 share->last_process= share->state.process;
521 share->base.key_parts=key_parts;
522 share->base.all_key_parts=key_parts+unique_key_parts;
523 if (!(share->last_version=share->state.version))
524 share->last_version=1; /* Safety */
525 share->rec_reflength=share->base.rec_reflength; /* May be changed */
526 share->base.margin_key_file_length=(share->base.max_key_file_length -
527 (keys ? MI_INDEX_BLOCK_MARGIN *
528 share->blocksize * keys : 0));
529 share->blocksize=MY_MIN(IO_SIZE,myisam_block_size);
530 share->data_file_type=STATIC_RECORD;
531 if (share->options & HA_OPTION_COMPRESS_RECORD)
532 {
533 share->data_file_type = COMPRESSED_RECORD;
534 share->options|= HA_OPTION_READ_ONLY_DATA;
535 info.s=share;
536 if (_mi_read_pack_info(&info,
537 (pbool)
538 MY_TEST(!(share->options &
539 (HA_OPTION_PACK_RECORD |
540 HA_OPTION_TEMP_COMPRESS_RECORD)))))
541 goto err;
542 }
543 else if (share->options & HA_OPTION_PACK_RECORD)
544 share->data_file_type = DYNAMIC_RECORD;
545 my_afree(disk_cache);
546 mi_setup_functions(share);
547 share->is_log_table= FALSE;
548 thr_lock_init(&share->lock);
549 mysql_mutex_init(mi_key_mutex_MYISAM_SHARE_intern_lock,
550 &share->intern_lock, MY_MUTEX_INIT_FAST);
551 for (i=0; i<keys; i++)
552 mysql_rwlock_init(mi_key_rwlock_MYISAM_SHARE_key_root_lock,
553 &share->key_root_lock[i]);
554 mysql_rwlock_init(mi_key_rwlock_MYISAM_SHARE_mmap_lock, &share->mmap_lock);
555 if (!thr_lock_inited)
556 {
557 /* Probably a single threaded program; Don't use concurrent inserts */
558 myisam_concurrent_insert=0;
559 }
560 else if (myisam_concurrent_insert)
561 {
562 share->concurrent_insert=
563 ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
564 HA_OPTION_COMPRESS_RECORD |
565 HA_OPTION_TEMP_COMPRESS_RECORD)) ||
566 (open_flags & HA_OPEN_TMP_TABLE) ||
567 have_rtree) ? 0 : 1;
568 if (share->concurrent_insert)
569 {
570 share->lock.get_status=mi_get_status;
571 share->lock.copy_status=mi_copy_status;
572 share->lock.update_status=mi_update_status;
573 share->lock.restore_status= mi_restore_status;
574 share->lock.check_status=mi_check_status;
575 share->lock.fix_status= (void (*)(void *, void *)) mi_fix_status;
576 }
577 }
578 /*
579 Memory mapping can only be requested after initializing intern_lock.
580 */
581 if (open_flags & HA_OPEN_MMAP)
582 {
583 info.s= share;
584 mi_extra(&info, HA_EXTRA_MMAP, 0);
585 }
586 }
587 else
588 {
589 share= old_info->s;
590 if (mode == O_RDWR && share->mode == O_RDONLY)
591 {
592 my_errno=EACCES; /* Can't open in write mode */
593 goto err;
594 }
595 if (mi_open_datafile(&info, share))
596 goto err;
597 errpos=5;
598 have_rtree= old_info->rtree_recursion_state != NULL;
599 }
600
601 /* alloc and set up private structure parts */
602 if (!my_multi_malloc(MY_WME,
603 &m_info,sizeof(MI_INFO),
604 &info.blobs,sizeof(MI_BLOB)*share->base.blobs,
605 &info.buff,(share->base.max_key_block_length*2+
606 share->base.max_key_length),
607 &info.lastkey,share->base.max_key_length*3+1,
608 &info.first_mbr_key, share->base.max_key_length,
609 &info.filename,strlen(name)+1,
610 &info.rtree_recursion_state,have_rtree ? 1024 : 0,
611 NullS))
612 goto err;
613 errpos=6;
614
615 if (!have_rtree)
616 info.rtree_recursion_state= NULL;
617
618 strmov(info.filename,name);
619 memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
620 info.lastkey2=info.lastkey+share->base.max_key_length;
621
622 info.s=share;
623 info.lastpos= HA_OFFSET_ERROR;
624 info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
625 info.open_flag= open_flags;
626 info.opt_flag=READ_CHECK_USED;
627 info.this_unique= (ulong) info.dfile; /* Uniq number in process */
628 if (share->data_file_type == COMPRESSED_RECORD)
629 info.this_unique= share->state.unique;
630 info.this_loop=0; /* Update counter */
631 info.last_unique= share->state.unique;
632 info.last_loop= share->state.update_count;
633 if (mode == O_RDONLY)
634 share->options|=HA_OPTION_READ_ONLY_DATA;
635 info.lock_type=F_UNLCK;
636 info.quick_mode=0;
637 info.bulk_insert=0;
638 info.ft1_to_ft2=0;
639 info.errkey= -1;
640 info.page_changed=1;
641 mysql_mutex_lock(&share->intern_lock);
642 info.read_record=share->read_record;
643 share->reopen++;
644 share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
645 if (share->options & HA_OPTION_READ_ONLY_DATA)
646 {
647 info.lock_type=F_RDLCK;
648 share->r_locks++;
649 share->tot_locks++;
650 }
651 if ((open_flags & HA_OPEN_TMP_TABLE) ||
652 (share->options & HA_OPTION_TMP_TABLE))
653 {
654 share->temporary=share->delay_key_write=1;
655 share->write_flag=MYF(MY_NABP);
656 share->w_locks++; /* We don't have to update status */
657 share->tot_locks++;
658 info.lock_type=F_WRLCK;
659 }
660 if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) ||
661 (share->options & HA_OPTION_DELAY_KEY_WRITE)) &&
662 myisam_delay_key_write)
663 share->delay_key_write=1;
664 info.state= &share->state.state; /* Change global values by default */
665 mysql_mutex_unlock(&share->intern_lock);
666
667 /* Allocate buffer for one record */
668
669 /* prerequisites: bzero(info) && info->s=share; are met. */
670 if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff))
671 goto err;
672 bzero(info.rec_buff, mi_get_rec_buff_len(&info, info.rec_buff));
673
674 *m_info=info;
675 thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
676
677 if (!internal_table)
678 {
679 m_info->open_list.data= (void*) m_info;
680 myisam_open_list= list_add(myisam_open_list, &m_info->open_list);
681 mysql_mutex_unlock(&THR_LOCK_myisam);
682 }
683
684 bzero(info.buff, share->base.max_key_block_length * 2);
685 my_free(rec_per_key_part);
686
687 if (myisam_log_file >= 0)
688 {
689 intern_filename(name_buff,share->index_file_name);
690 _myisam_log(MI_LOG_OPEN, m_info, (uchar*) name_buff, (uint)strlen(name_buff));
691 }
692 DBUG_RETURN(m_info);
693
694err:
695 save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
696 if ((save_errno == HA_ERR_CRASHED) ||
697 (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
698 (save_errno == HA_ERR_CRASHED_ON_REPAIR))
699 mi_report_error(save_errno, name);
700 switch (errpos) {
701 case 6:
702 my_free(m_info);
703 /* fall through */
704 case 5:
705 (void) mysql_file_close(info.dfile, MYF(0));
706 if (old_info)
707 break; /* Don't remove open table */
708 /* fall through */
709 case 4:
710 my_free(share);
711 /* fall through */
712 case 3:
713 if (! lock_error)
714 (void) my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE));
715 my_free(rec_per_key_part);
716 /* fall through */
717 case 2:
718 my_afree(disk_cache);
719 /* fall through */
720 case 1:
721 (void) mysql_file_close(kfile, MYF(0));
722 /* fall through */
723 case 0:
724 default:
725 break;
726 }
727 if (!internal_table)
728 mysql_mutex_unlock(&THR_LOCK_myisam);
729 my_errno=save_errno;
730 DBUG_RETURN (NULL);
731} /* mi_open */
732
733
734uchar *mi_alloc_rec_buff(MI_INFO *info, ulong length, uchar **buf)
735{
736 uint extra;
737 uint32 UNINIT_VAR(old_length);
738
739 if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
740 {
741 uchar *newptr = *buf;
742
743 /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
744 if (length == (ulong) -1)
745 {
746 if (info->s->options & HA_OPTION_COMPRESS_RECORD)
747 length= MY_MAX(info->s->base.pack_reclength, info->s->max_pack_length);
748 else
749 length= info->s->base.pack_reclength;
750 length= MY_MAX(length, info->s->base.max_key_length);
751 length= MY_MAX(length, info->s->vreclength);
752 /* Avoid unnecessary realloc */
753 if (newptr && length == old_length)
754 return newptr;
755 }
756
757 extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
758 ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
759 MI_REC_BUFF_OFFSET : 0);
760 if (extra && newptr)
761 newptr-= MI_REC_BUFF_OFFSET;
762 if (!(newptr=(uchar*) my_realloc((uchar*)newptr, length+extra+8,
763 MYF(MY_ALLOW_ZERO_PTR))))
764 return NULL;
765 *((uint32 *) newptr)= (uint32) length;
766 *buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
767 }
768 return *buf;
769}
770
771
772ulonglong mi_safe_mul(ulonglong a, ulonglong b)
773{
774 ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */
775
776 if (!a || max_val / a < b)
777 return max_val;
778 return a*b;
779}
780
781 /* Set up functions in structs */
782
783void mi_setup_functions(register MYISAM_SHARE *share)
784{
785 if (share->options & HA_OPTION_COMPRESS_RECORD)
786 {
787 share->read_record=_mi_read_pack_record;
788 share->read_rnd=_mi_read_rnd_pack_record;
789 if ((share->options &
790 (HA_OPTION_PACK_RECORD | HA_OPTION_NULL_FIELDS)) ||
791 share->has_varchar_fields)
792 share->calc_checksum= mi_checksum;
793 else
794 share->calc_checksum= mi_static_checksum;
795 share->calc_check_checksum= share->calc_checksum;
796 if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
797 share->calc_checksum=0; /* No checksum */
798 }
799 else if (share->options & HA_OPTION_PACK_RECORD)
800 {
801 share->read_record=_mi_read_dynamic_record;
802 share->read_rnd=_mi_read_rnd_dynamic_record;
803 share->delete_record=_mi_delete_dynamic_record;
804 share->compare_record=_mi_cmp_dynamic_record;
805 share->compare_unique=_mi_cmp_dynamic_unique;
806 share->calc_checksum= mi_checksum;
807 share->calc_check_checksum= share->calc_checksum;
808
809 /* add bits used to pack data to pack_reclength for faster allocation */
810 share->base.pack_reclength+= share->base.pack_bits;
811 if (share->base.blobs)
812 {
813 share->update_record=_mi_update_blob_record;
814 share->write_record=_mi_write_blob_record;
815 }
816 else
817 {
818 share->write_record=_mi_write_dynamic_record;
819 share->update_record=_mi_update_dynamic_record;
820 }
821 }
822 else
823 {
824 share->read_record=_mi_read_static_record;
825 share->read_rnd=_mi_read_rnd_static_record;
826 share->delete_record=_mi_delete_static_record;
827 share->compare_record=_mi_cmp_static_record;
828 share->update_record=_mi_update_static_record;
829 share->write_record=_mi_write_static_record;
830 share->compare_unique=_mi_cmp_static_unique;
831 if (share->options & HA_OPTION_NULL_FIELDS)
832 share->calc_checksum= mi_checksum;
833 else
834 share->calc_checksum= mi_static_checksum;
835 share->calc_check_checksum= share->calc_checksum;
836 }
837 share->file_read= mi_nommap_pread;
838 share->file_write= mi_nommap_pwrite;
839 if (!(share->options & HA_OPTION_CHECKSUM))
840 share->calc_checksum=0;
841 return;
842}
843
844
845static void setup_key_functions(register MI_KEYDEF *keyinfo)
846{
847 if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
848 {
849#ifdef HAVE_RTREE_KEYS
850 keyinfo->ck_insert = rtree_insert;
851 keyinfo->ck_delete = rtree_delete;
852#else
853 DBUG_ASSERT(0); /* mi_open should check it never happens */
854#endif
855 }
856 else
857 {
858 keyinfo->ck_insert = _mi_ck_write;
859 keyinfo->ck_delete = _mi_ck_delete;
860 }
861 if (keyinfo->flag & HA_BINARY_PACK_KEY)
862 { /* Simple prefix compression */
863 keyinfo->bin_search=_mi_seq_search;
864 keyinfo->get_key=_mi_get_binary_pack_key;
865 keyinfo->pack_key=_mi_calc_bin_pack_key_length;
866 keyinfo->store_key=_mi_store_bin_pack_key;
867 }
868 else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
869 {
870 keyinfo->get_key= _mi_get_pack_key;
871 if (keyinfo->seg[0].flag & HA_PACK_KEY)
872 { /* Prefix compression */
873 /*
874 _mi_prefix_search() compares end-space against ASCII blank (' ').
875 It cannot be used for character sets, that do not encode the
876 blank character like ASCII does. UCS2 is an example. All
877 character sets with a fixed width > 1 or a mimimum width > 1
878 cannot represent blank like ASCII does. In these cases we have
879 to use _mi_seq_search() for the search.
880 */
881 if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
882 (keyinfo->seg->flag & HA_NULL_PART) ||
883 (keyinfo->seg->charset->mbminlen > 1))
884 keyinfo->bin_search=_mi_seq_search;
885 else
886 keyinfo->bin_search=_mi_prefix_search;
887 keyinfo->pack_key=_mi_calc_var_pack_key_length;
888 keyinfo->store_key=_mi_store_var_pack_key;
889 }
890 else
891 {
892 keyinfo->bin_search=_mi_seq_search;
893 keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
894 keyinfo->store_key=_mi_store_static_key;
895 }
896 }
897 else
898 {
899 keyinfo->bin_search=_mi_bin_search;
900 keyinfo->get_key=_mi_get_static_key;
901 keyinfo->pack_key=_mi_calc_static_key_length;
902 keyinfo->store_key=_mi_store_static_key;
903 }
904 return;
905}
906
907
908/*
909 Function to save and store the header in the index file (.MYI)
910*/
911
912uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
913{
914 uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
915 uchar *ptr=buff;
916 uint i, keys= (uint) state->header.keys,
917 key_blocks=state->header.max_block_size_index;
918 DBUG_ENTER("mi_state_info_write");
919
920 memcpy(ptr, &state->header, sizeof(state->header));
921 ptr+=sizeof(state->header);
922
923 /* open_count must be first because of _mi_mark_file_changed ! */
924 mi_int2store(ptr,state->open_count); ptr +=2;
925 *ptr++= (uchar)state->changed; *ptr++= state->sortkey;
926 mi_rowstore(ptr,state->state.records); ptr +=8;
927 mi_rowstore(ptr,state->state.del); ptr +=8;
928 mi_rowstore(ptr,state->split); ptr +=8;
929 mi_sizestore(ptr,state->dellink); ptr +=8;
930 mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
931 mi_sizestore(ptr,state->state.data_file_length); ptr +=8;
932 mi_sizestore(ptr,state->state.empty); ptr +=8;
933 mi_sizestore(ptr,state->state.key_empty); ptr +=8;
934 mi_int8store(ptr,state->auto_increment); ptr +=8;
935 mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8;
936 mi_int4store(ptr,state->process); ptr +=4;
937 mi_int4store(ptr,state->unique); ptr +=4;
938 mi_int4store(ptr,state->status); ptr +=4;
939 mi_int4store(ptr,state->update_count); ptr +=4;
940
941 ptr+=state->state_diff_length;
942
943 for (i=0; i < keys; i++)
944 {
945 mi_sizestore(ptr,state->key_root[i]); ptr +=8;
946 }
947 for (i=0; i < key_blocks; i++)
948 {
949 mi_sizestore(ptr,state->key_del[i]); ptr +=8;
950 }
951 if (pWrite & 2) /* From isamchk */
952 {
953 uint key_parts= mi_uint2korr(state->header.key_parts);
954 mi_int4store(ptr,state->sec_index_changed); ptr +=4;
955 mi_int4store(ptr,state->sec_index_used); ptr +=4;
956 mi_int4store(ptr,state->version); ptr +=4;
957 mi_int8store(ptr,state->key_map); ptr +=8;
958 mi_int8store(ptr,(ulonglong) state->create_time); ptr +=8;
959 mi_int8store(ptr,(ulonglong) state->recover_time); ptr +=8;
960 mi_int8store(ptr,(ulonglong) state->check_time); ptr +=8;
961 mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8;
962 for (i=0 ; i < key_parts ; i++)
963 {
964 mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4;
965 }
966 }
967
968 if (pWrite & 1)
969 DBUG_RETURN(mysql_file_pwrite(file, buff, (size_t) (ptr-buff), 0L,
970 MYF(MY_NABP | MY_THREADSAFE)) != 0);
971 DBUG_RETURN(mysql_file_write(file, buff, (size_t) (ptr-buff),
972 MYF(MY_NABP)) != 0);
973}
974
975
976uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state)
977{
978 uint i,keys,key_parts,key_blocks;
979 memcpy(&state->header, ptr, sizeof(state->header));
980 ptr +=sizeof(state->header);
981 keys=(uint) state->header.keys;
982 key_parts=mi_uint2korr(state->header.key_parts);
983 key_blocks=state->header.max_block_size_index;
984
985 state->open_count = mi_uint2korr(ptr); ptr +=2;
986 state->changed= *ptr++;
987 state->sortkey = (uint) *ptr++;
988 state->state.records= mi_rowkorr(ptr); ptr +=8;
989 state->state.del = mi_rowkorr(ptr); ptr +=8;
990 state->split = mi_rowkorr(ptr); ptr +=8;
991 state->dellink= mi_sizekorr(ptr); ptr +=8;
992 state->state.key_file_length = mi_sizekorr(ptr); ptr +=8;
993 state->state.data_file_length= mi_sizekorr(ptr); ptr +=8;
994 state->state.empty = mi_sizekorr(ptr); ptr +=8;
995 state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
996 state->auto_increment=mi_uint8korr(ptr); ptr +=8;
997 state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8;
998 state->process= mi_uint4korr(ptr); ptr +=4;
999 state->unique = mi_uint4korr(ptr); ptr +=4;
1000 state->status = mi_uint4korr(ptr); ptr +=4;
1001 state->update_count=mi_uint4korr(ptr); ptr +=4;
1002
1003 ptr+= state->state_diff_length;
1004
1005 if (!state->rec_per_key_part)
1006 {
1007 if (!my_multi_malloc(MY_WME,
1008 &state->rec_per_key_part,sizeof(long)*key_parts,
1009 &state->key_root, keys*sizeof(my_off_t),
1010 &state->key_del, key_blocks*sizeof(my_off_t),
1011 NullS))
1012 return(0);
1013 }
1014
1015 for (i=0; i < keys; i++)
1016 {
1017 state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
1018 }
1019 for (i=0; i < key_blocks; i++)
1020 {
1021 state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
1022 }
1023 state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
1024 state->sec_index_used = mi_uint4korr(ptr); ptr +=4;
1025 state->version = mi_uint4korr(ptr); ptr +=4;
1026 state->key_map = mi_uint8korr(ptr); ptr +=8;
1027 state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
1028 state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
1029 state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8;
1030 state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
1031 for (i=0 ; i < key_parts ; i++)
1032 {
1033 state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
1034 }
1035 return ptr;
1036}
1037
1038
1039uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead)
1040{
1041 uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
1042
1043 if (!myisam_single_user)
1044 {
1045 if (pRead)
1046 {
1047 if (mysql_file_pread(file, buff, state->state_length, 0L, MYF(MY_NABP)))
1048 return 1;
1049 }
1050 else if (mysql_file_read(file, buff, state->state_length, MYF(MY_NABP)))
1051 return 1;
1052 mi_state_info_read(buff, state);
1053 }
1054 return 0;
1055}
1056
1057
1058/****************************************************************************
1059** store and read of MI_BASE_INFO
1060****************************************************************************/
1061
1062uint mi_base_info_write(File file, MI_BASE_INFO *base)
1063{
1064 uchar buff[MI_BASE_INFO_SIZE], *ptr=buff;
1065
1066 mi_sizestore(ptr,base->keystart); ptr +=8;
1067 mi_sizestore(ptr,base->max_data_file_length); ptr +=8;
1068 mi_sizestore(ptr,base->max_key_file_length); ptr +=8;
1069 mi_rowstore(ptr,base->records); ptr +=8;
1070 mi_rowstore(ptr,base->reloc); ptr +=8;
1071 mi_int4store(ptr,base->mean_row_length); ptr +=4;
1072 mi_int4store(ptr,base->reclength); ptr +=4;
1073 mi_int4store(ptr,base->pack_reclength); ptr +=4;
1074 mi_int4store(ptr,base->min_pack_length); ptr +=4;
1075 mi_int4store(ptr,base->max_pack_length); ptr +=4;
1076 mi_int4store(ptr,base->min_block_length); ptr +=4;
1077 mi_int4store(ptr,base->fields); ptr +=4;
1078 mi_int4store(ptr,base->pack_fields); ptr +=4;
1079 *ptr++=base->rec_reflength;
1080 *ptr++=base->key_reflength;
1081 *ptr++=base->keys;
1082 *ptr++=base->auto_key;
1083 mi_int2store(ptr,base->pack_bits); ptr +=2;
1084 mi_int2store(ptr,base->blobs); ptr +=2;
1085 mi_int2store(ptr,base->max_key_block_length); ptr +=2;
1086 mi_int2store(ptr,base->max_key_length); ptr +=2;
1087 mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2;
1088 *ptr++= base->extra_alloc_procent;
1089 bzero(ptr,13); ptr +=13; /* extra */
1090 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1091}
1092
1093
1094uchar *mi_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
1095{
1096 base->keystart = mi_sizekorr(ptr); ptr +=8;
1097 base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
1098 base->max_key_file_length = mi_sizekorr(ptr); ptr +=8;
1099 base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8;
1100 base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8;
1101 base->mean_row_length = mi_uint4korr(ptr); ptr +=4;
1102 base->reclength = mi_uint4korr(ptr); ptr +=4;
1103 base->pack_reclength = mi_uint4korr(ptr); ptr +=4;
1104 base->min_pack_length = mi_uint4korr(ptr); ptr +=4;
1105 base->max_pack_length = mi_uint4korr(ptr); ptr +=4;
1106 base->min_block_length = mi_uint4korr(ptr); ptr +=4;
1107 base->fields = mi_uint4korr(ptr); ptr +=4;
1108 base->pack_fields = mi_uint4korr(ptr); ptr +=4;
1109
1110 base->rec_reflength = *ptr++;
1111 base->key_reflength = *ptr++;
1112 base->keys= *ptr++;
1113 base->auto_key= *ptr++;
1114 base->pack_bits = mi_uint2korr(ptr); ptr +=2;
1115 base->blobs = mi_uint2korr(ptr); ptr +=2;
1116 base->max_key_block_length= mi_uint2korr(ptr); ptr +=2;
1117 base->max_key_length = mi_uint2korr(ptr); ptr +=2;
1118 base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2;
1119 base->extra_alloc_procent = *ptr++;
1120
1121 ptr+=13;
1122 return ptr;
1123}
1124
1125/*--------------------------------------------------------------------------
1126 mi_keydef
1127---------------------------------------------------------------------------*/
1128
1129uint mi_keydef_write(File file, MI_KEYDEF *keydef)
1130{
1131 uchar buff[MI_KEYDEF_SIZE];
1132 uchar *ptr=buff;
1133
1134 *ptr++ = (uchar) keydef->keysegs;
1135 *ptr++ = keydef->key_alg; /* Rtree or Btree */
1136 mi_int2store(ptr,keydef->flag); ptr +=2;
1137 mi_int2store(ptr,keydef->block_length); ptr +=2;
1138 mi_int2store(ptr,keydef->keylength); ptr +=2;
1139 mi_int2store(ptr,keydef->minlength); ptr +=2;
1140 mi_int2store(ptr,keydef->maxlength); ptr +=2;
1141 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1142}
1143
1144uchar *mi_keydef_read(uchar *ptr, MI_KEYDEF *keydef)
1145{
1146 keydef->keysegs = (uint) *ptr++;
1147 keydef->key_alg = *ptr++; /* Rtree or Btree */
1148
1149 keydef->flag = mi_uint2korr(ptr); ptr +=2;
1150 keydef->block_length = mi_uint2korr(ptr); ptr +=2;
1151 keydef->keylength = mi_uint2korr(ptr); ptr +=2;
1152 keydef->minlength = mi_uint2korr(ptr); ptr +=2;
1153 keydef->maxlength = mi_uint2korr(ptr); ptr +=2;
1154 keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
1155 keydef->underflow_block_length=keydef->block_length/3;
1156 keydef->version = 0; /* Not saved */
1157 keydef->parser = &ft_default_parser;
1158 keydef->ftkey_nr = 0;
1159 return ptr;
1160}
1161
1162/***************************************************************************
1163** mi_keyseg
1164***************************************************************************/
1165
1166int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
1167{
1168 uchar buff[HA_KEYSEG_SIZE];
1169 uchar *ptr=buff;
1170 ulong pos;
1171
1172 *ptr++= keyseg->type;
1173 *ptr++= keyseg->language & 0xFF; /* Collation ID, low byte */
1174 *ptr++= keyseg->null_bit;
1175 *ptr++= keyseg->bit_start;
1176 *ptr++= keyseg->language >> 8; /* Collation ID, high byte */
1177 *ptr++= keyseg->bit_length;
1178 mi_int2store(ptr,keyseg->flag); ptr+=2;
1179 mi_int2store(ptr,keyseg->length); ptr+=2;
1180 mi_int4store(ptr,keyseg->start); ptr+=4;
1181 pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
1182 mi_int4store(ptr, pos);
1183 ptr+=4;
1184
1185 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1186}
1187
1188
1189uchar *mi_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
1190{
1191 keyseg->type = *ptr++;
1192 keyseg->language = *ptr++;
1193 keyseg->null_bit = *ptr++;
1194 keyseg->bit_start = *ptr++;
1195 keyseg->language += ((uint16) (*ptr++)) << 8;
1196 keyseg->bit_length = *ptr++;
1197 keyseg->flag = mi_uint2korr(ptr); ptr +=2;
1198 keyseg->length = mi_uint2korr(ptr); ptr +=2;
1199 keyseg->start = mi_uint4korr(ptr); ptr +=4;
1200 keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
1201 keyseg->charset=0; /* Will be filled in later */
1202 if (keyseg->null_bit)
1203 /* We adjust bit_pos if null_bit is last in the byte */
1204 keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == (1 << 7)));
1205 else
1206 {
1207 keyseg->bit_pos= (uint16)keyseg->null_pos;
1208 keyseg->null_pos= 0;
1209 }
1210 return ptr;
1211}
1212
1213/*--------------------------------------------------------------------------
1214 mi_uniquedef
1215---------------------------------------------------------------------------*/
1216
1217uint mi_uniquedef_write(File file, MI_UNIQUEDEF *def)
1218{
1219 uchar buff[MI_UNIQUEDEF_SIZE];
1220 uchar *ptr=buff;
1221
1222 mi_int2store(ptr,def->keysegs); ptr+=2;
1223 *ptr++= (uchar) def->key;
1224 *ptr++ = (uchar) def->null_are_equal;
1225
1226 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1227}
1228
1229uchar *mi_uniquedef_read(uchar *ptr, MI_UNIQUEDEF *def)
1230{
1231 def->keysegs = mi_uint2korr(ptr);
1232 def->key = ptr[2];
1233 def->null_are_equal=ptr[3];
1234 return ptr+4; /* 1 extra byte */
1235}
1236
1237/***************************************************************************
1238** MI_COLUMNDEF
1239***************************************************************************/
1240
1241uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo)
1242{
1243 uchar buff[MI_COLUMNDEF_SIZE];
1244 uchar *ptr=buff;
1245
1246 mi_int2store(ptr,recinfo->type); ptr +=2;
1247 mi_int2store(ptr,recinfo->length); ptr +=2;
1248 *ptr++ = recinfo->null_bit;
1249 mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
1250 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1251}
1252
1253uchar *mi_recinfo_read(uchar *ptr, MI_COLUMNDEF *recinfo)
1254{
1255 recinfo->type= mi_sint2korr(ptr); ptr +=2;
1256 recinfo->length=mi_uint2korr(ptr); ptr +=2;
1257 recinfo->null_bit= (uint8) *ptr++;
1258 recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
1259 return ptr;
1260}
1261
1262/**************************************************************************
1263Open data file.
1264We can't use dup() here as the data file descriptors need to have different
1265active seek-positions.
1266*************************************************************************/
1267
1268int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share)
1269{
1270 myf flags= MY_WME | (share->mode & O_NOFOLLOW ? MY_NOSYMLINKS: 0);
1271 DEBUG_SYNC_C("mi_open_datafile");
1272 info->dfile= mysql_file_open(mi_key_file_dfile, share->data_file_name,
1273 share->mode | O_SHARE, MYF(flags));
1274 return info->dfile >= 0 ? 0 : 1;
1275}
1276
1277
1278int mi_open_keyfile(MYISAM_SHARE *share)
1279{
1280 if ((share->kfile= mysql_file_open(mi_key_file_kfile,
1281 share->unique_file_name,
1282 share->mode | O_SHARE | O_NOFOLLOW,
1283 MYF(MY_NOSYMLINKS | MY_WME))) < 0)
1284 return 1;
1285 return 0;
1286}
1287
1288
1289/*
1290 Disable all indexes.
1291
1292 SYNOPSIS
1293 mi_disable_indexes()
1294 info A pointer to the MyISAM storage engine MI_INFO struct.
1295
1296 DESCRIPTION
1297 Disable all indexes.
1298
1299 RETURN
1300 0 ok
1301*/
1302
1303int mi_disable_indexes(MI_INFO *info)
1304{
1305 MYISAM_SHARE *share= info->s;
1306
1307 mi_clear_all_keys_active(share->state.key_map);
1308 return 0;
1309}
1310
1311
1312/*
1313 Enable all indexes
1314
1315 SYNOPSIS
1316 mi_enable_indexes()
1317 info A pointer to the MyISAM storage engine MI_INFO struct.
1318
1319 DESCRIPTION
1320 Enable all indexes. The indexes might have been disabled
1321 by mi_disable_index() before.
1322 The function works only if both data and indexes are empty,
1323 otherwise a repair is required.
1324 To be sure, call handler::delete_all_rows() before.
1325
1326 RETURN
1327 0 ok
1328 HA_ERR_CRASHED data or index is non-empty.
1329*/
1330
1331int mi_enable_indexes(MI_INFO *info)
1332{
1333 int error= 0;
1334 MYISAM_SHARE *share= info->s;
1335
1336 if (share->state.state.data_file_length ||
1337 (share->state.state.key_file_length != share->base.keystart))
1338 {
1339 mi_print_error(info->s, HA_ERR_CRASHED);
1340 error= HA_ERR_CRASHED;
1341 }
1342 else
1343 mi_set_all_keys_active(share->state.key_map, share->base.keys);
1344 return error;
1345}
1346
1347
1348/*
1349 Test if indexes are disabled.
1350
1351 SYNOPSIS
1352 mi_indexes_are_disabled()
1353 info A pointer to the MyISAM storage engine MI_INFO struct.
1354
1355 DESCRIPTION
1356 Test if indexes are disabled.
1357
1358 RETURN
1359 0 indexes are not disabled
1360 1 all indexes are disabled
1361 2 non-unique indexes are disabled
1362*/
1363
1364int mi_indexes_are_disabled(MI_INFO *info)
1365{
1366 MYISAM_SHARE *share= info->s;
1367
1368 /*
1369 No keys or all are enabled. keys is the number of keys. Left shifted
1370 gives us only one bit set. When decreased by one, gives us all all bits
1371 up to this one set and it gets unset.
1372 */
1373 if (!share->base.keys ||
1374 (mi_is_all_keys_active(share->state.key_map, share->base.keys)))
1375 return 0;
1376
1377 /* All are disabled */
1378 if (mi_is_any_key_active(share->state.key_map))
1379 return 1;
1380
1381 /*
1382 We have keys. Some enabled, some disabled.
1383 Don't check for any non-unique disabled but return directly 2
1384 */
1385 return 2;
1386}
1387