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