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