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