Drizzled Public API Documentation

mi_open.cc
1 /* Copyright (C) 2000-2006 MySQL AB
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 /* open a isam-database */
17 
18 #include "myisam_priv.h"
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <algorithm>
23 #include <memory>
24 #include <boost/scoped_ptr.hpp>
25 #include <boost/scoped_array.hpp>
26 
27 #include <drizzled/internal/m_string.h>
28 #include <drizzled/util/test.h>
29 #include <drizzled/charset.h>
30 #include <drizzled/memory/multi_malloc.h>
31 #include <drizzled/identifier.h>
32 
33 
34 using namespace std;
35 using namespace drizzled;
36 
37 static void setup_key_functions(MI_KEYDEF *keyinfo);
38 static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef);
39 static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg);
40 static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo);
41 static uint64_t mi_safe_mul(uint64_t a, uint64_t b);
42 static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state);
43 static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def);
44 static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base);
45 
46 #define disk_pos_assert(pos, end_pos) \
47 if (pos > end_pos) \
48 { \
49  errno=HA_ERR_CRASHED; \
50  goto err; \
51 }
52 
53 
54 /******************************************************************************
55 ** Return the shared struct if the table is already open.
56 ** In MySQL the server will handle version issues.
57 ******************************************************************************/
58 
59 MI_INFO *test_if_reopen(char *filename)
60 {
61  list<MI_INFO *>::iterator it= myisam_open_list.begin();
62  while (it != myisam_open_list.end())
63  {
64  MI_INFO *info= *it;
65  MYISAM_SHARE *share=info->s;
66  if (!strcmp(share->unique_file_name,filename) && share->last_version)
67  return info;
68  ++it;
69  }
70  return 0;
71 }
72 
73 
74 /******************************************************************************
75  open a MyISAM database.
76  See my_base.h for the handle_locking argument
77  if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
78  is marked crashed or if we are not using locking and the table doesn't
79  have an open count of 0.
80 ******************************************************************************/
81 
82 MI_INFO *mi_open(const drizzled::identifier::Table &identifier, int mode, uint32_t open_flags)
83 {
84  int lock_error,kfile,open_mode,save_errno,have_rtree=0;
85  uint32_t i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
86  key_parts,unique_key_parts,uniques;
87  char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
88  data_name[FN_REFLEN];
89 #ifndef __GNU__
90  char rp_buff[PATH_MAX];
91 #else
92  char *rp_buff = NULL;
93 #endif
94  unsigned char *disk_cache= NULL;
95  unsigned char *disk_pos, *end_pos;
96  MI_INFO info,*m_info,*old_info;
97  boost::scoped_ptr<MYISAM_SHARE> share_buff_ap(new MYISAM_SHARE);
98  MYISAM_SHARE &share_buff= *share_buff_ap.get();
99  MYISAM_SHARE *share;
100  boost::scoped_array<ulong> rec_per_key_part_ap(new ulong[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG]);
101  ulong *rec_per_key_part= rec_per_key_part_ap.get();
102  internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
103  uint64_t max_key_file_length, max_data_file_length;
104 
105  kfile= -1;
106  lock_error=1;
107  errpos=0;
108  head_length=sizeof(share_buff.state.header);
109  memset(&info, 0, sizeof(info));
110 
111  (void)internal::fn_format(org_name,
112  identifier.getPath().c_str(),
113  "",
114  MI_NAME_IEXT,
115  MY_UNPACK_FILENAME);
116 #ifndef __GNU__
117  if (!realpath(org_name,rp_buff))
118  internal::my_load_path(rp_buff,org_name, NULL);
119  rp_buff[FN_REFLEN-1]= '\0';
120  strcpy(name_buff,rp_buff);
121 #else
122  rp_buff = realpath(org_name,NULL);
123  if (!rp_buff) {
124  // (on hurd) rp_puff is initialized NULL, so there is no buffer allocated.
125  // So we cannot use it. but we can call my_load_path and ask
126  // it to directly store it the target buffer name_buff.
127  internal::my_load_path(name_buff,org_name, NULL);
128  } else {
129  if (strlen(rp_buff) >= FN_REFLEN) {
130  rp_buff[FN_REFLEN-1]= '\0';
131  }
132  strcpy(name_buff,rp_buff);
133  free(rp_buff);
134  }
135 #endif
136  THR_LOCK_myisam.lock();
137  if (!(old_info=test_if_reopen(name_buff)))
138  {
139  share= &share_buff;
140  memset(&share_buff, 0, sizeof(share_buff));
141  share_buff.state.rec_per_key_part=rec_per_key_part;
142  share_buff.state.key_root=key_root;
143  share_buff.state.key_del=key_del;
144 
145  if ((kfile=internal::my_open(name_buff,(open_mode=O_RDWR),MYF(0))) < 0)
146  {
147  if ((errno != EROFS && errno != EACCES) ||
148  mode != O_RDONLY ||
149  (kfile=internal::my_open(name_buff,(open_mode=O_RDONLY),MYF(0))) < 0)
150  goto err;
151  }
152  share->mode=open_mode;
153  errpos=1;
154  if (internal::my_read(kfile, share->state.header.file_version, head_length,
155  MYF(MY_NABP)))
156  {
157  errno= HA_ERR_NOT_A_TABLE;
158  goto err;
159  }
160  if (memcmp(share->state.header.file_version, myisam_file_magic, 4))
161  {
162  errno=HA_ERR_NOT_A_TABLE;
163  goto err;
164  }
165  share->options= mi_uint2korr(share->state.header.options);
166  static const uint64_t OLD_FILE_OPTIONS= HA_OPTION_PACK_RECORD |
167  HA_OPTION_PACK_KEYS |
168  HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
169  HA_OPTION_TEMP_COMPRESS_RECORD |
170  HA_OPTION_TMP_TABLE;
171  if (share->options & ~OLD_FILE_OPTIONS)
172  {
173  errno=HA_ERR_OLD_FILE;
174  goto err;
175  }
176 
177  /* Don't call realpath() if the name can't be a link */
178  ssize_t sym_link_size= readlink(org_name,index_name,FN_REFLEN-1);
179  if (sym_link_size >= 0 )
180  index_name[sym_link_size]= '\0';
181  if (!strcmp(name_buff, org_name) || sym_link_size == -1)
182  (void) strcpy(index_name, org_name);
183  *strrchr(org_name, '.')= '\0';
184  (void) internal::fn_format(data_name,org_name,"",MI_NAME_DEXT,
185  MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
186 
187  info_length=mi_uint2korr(share->state.header.header_length);
188  base_pos=mi_uint2korr(share->state.header.base_pos);
189  if (!(disk_cache= (unsigned char*) malloc(info_length+128)))
190  {
191  errno=ENOMEM;
192  goto err;
193  }
194  end_pos=disk_cache+info_length;
195  errpos=2;
196 
197  lseek(kfile,0,SEEK_SET);
198  errpos=3;
199  if (internal::my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
200  {
201  errno=HA_ERR_CRASHED;
202  goto err;
203  }
204  len=mi_uint2korr(share->state.header.state_info_length);
205  keys= (uint) share->state.header.keys;
206  uniques= (uint) share->state.header.uniques;
207  key_parts= mi_uint2korr(share->state.header.key_parts);
208  unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
209  share->state_diff_length=len-MI_STATE_INFO_SIZE;
210 
211  mi_state_info_read(disk_cache, &share->state);
212  len= mi_uint2korr(share->state.header.base_info_length);
213  disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
214  share->state.state_length=base_pos;
215 
216  if (share->state.changed & STATE_CRASHED)
217  {
218  errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
219  HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
220  goto err;
221  }
222 
223  /* sanity check */
224  if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
225  {
226  errno=HA_ERR_CRASHED;
227  goto err;
228  }
229 
230  if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
231  key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
232  {
233  errno=HA_ERR_UNSUPPORTED;
234  goto err;
235  }
236 
237  /* Correct max_file_length based on length of sizeof(off_t) */
238  max_data_file_length=
239  (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
240  (((uint64_t) 1 << (share->base.rec_reflength*8))-1) :
241  (mi_safe_mul(share->base.pack_reclength,
242  (uint64_t) 1 << (share->base.rec_reflength*8))-1);
243  max_key_file_length=
244  mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
245  ((uint64_t) 1 << (share->base.key_reflength*8))-1);
246 #if SIZEOF_OFF_T == 4
247  set_if_smaller(max_data_file_length, INT32_MAX);
248  set_if_smaller(max_key_file_length, INT32_MAX);
249 #endif
250  if (share->base.raid_type)
251  {
252  errno=HA_ERR_UNSUPPORTED;
253  goto err;
254  }
255  share->base.max_data_file_length=(internal::my_off_t) max_data_file_length;
256  share->base.max_key_file_length=(internal::my_off_t) max_key_file_length;
257 
258  if (share->options & HA_OPTION_COMPRESS_RECORD)
259  share->base.max_key_length+=2; /* For safety */
260 
261  /* Add space for node pointer */
262  share->base.max_key_length+= share->base.key_reflength;
263 
264  if (!drizzled::memory::multi_malloc(false,
265  &share,sizeof(*share),
266  &share->state.rec_per_key_part,sizeof(long)*key_parts,
267  &share->keyinfo,keys*sizeof(MI_KEYDEF),
268  &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
269  &share->keyparts,
270  (key_parts+unique_key_parts+keys+uniques) * sizeof(HA_KEYSEG),
271  &share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF),
272  &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
273  &share->unique_file_name,strlen(name_buff)+1,
274  &share->index_file_name,strlen(index_name)+1,
275  &share->data_file_name,strlen(data_name)+1,
276  &share->state.key_root,keys*sizeof(uint64_t),
277  &share->state.key_del,
278  (share->state.header.max_block_size_index*sizeof(uint64_t)),
279  NULL))
280  goto err;
281  errpos=4;
282  *share=share_buff;
283  memcpy(share->state.rec_per_key_part, rec_per_key_part,
284  sizeof(long)*key_parts);
285  memcpy(share->state.key_root, key_root,
286  sizeof(internal::my_off_t)*keys);
287  memcpy(share->state.key_del, key_del,
288  sizeof(internal::my_off_t) * share->state.header.max_block_size_index);
289  strcpy(share->unique_file_name, name_buff);
290  share->unique_name_length= strlen(name_buff);
291  strcpy(share->index_file_name, index_name);
292  strcpy(share->data_file_name, data_name);
293 
294  share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
295  {
296  HA_KEYSEG *pos=share->keyparts;
297  for (i=0 ; i < keys ; i++)
298  {
299  share->keyinfo[i].share= share;
300  disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
301  disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
302  end_pos);
303  set_if_smaller(share->blocksize,(uint)share->keyinfo[i].block_length);
304  share->keyinfo[i].seg=pos;
305  for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
306  {
307  disk_pos=mi_keyseg_read(disk_pos, pos);
308  if (pos->flag & HA_BLOB_PART &&
309  ! (share->options & (HA_OPTION_COMPRESS_RECORD |
310  HA_OPTION_PACK_RECORD)))
311  {
312  errno= HA_ERR_CRASHED;
313  goto err;
314  }
315  if (pos->type == HA_KEYTYPE_TEXT ||
316  pos->type == HA_KEYTYPE_VARTEXT1 ||
317  pos->type == HA_KEYTYPE_VARTEXT2)
318  {
319  if (!pos->language)
320  pos->charset=default_charset_info;
321  else if (!(pos->charset= get_charset(pos->language)))
322  {
323  errno=HA_ERR_UNKNOWN_CHARSET;
324  goto err;
325  }
326  }
327  else if (pos->type == HA_KEYTYPE_BINARY)
328  pos->charset= &my_charset_bin;
329  }
330  setup_key_functions(share->keyinfo+i);
331  share->keyinfo[i].end=pos;
332  pos->type=HA_KEYTYPE_END; /* End */
333  pos->length=share->base.rec_reflength;
334  pos->null_bit=0;
335  pos->flag=0; /* For purify */
336  pos++;
337  }
338  for (i=0 ; i < uniques ; i++)
339  {
340  disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
341  disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
342  HA_KEYSEG_SIZE, end_pos);
343  share->uniqueinfo[i].seg=pos;
344  for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
345  {
346  disk_pos=mi_keyseg_read(disk_pos, pos);
347  if (pos->type == HA_KEYTYPE_TEXT ||
348  pos->type == HA_KEYTYPE_VARTEXT1 ||
349  pos->type == HA_KEYTYPE_VARTEXT2)
350  {
351  if (!pos->language)
352  pos->charset=default_charset_info;
353  else if (!(pos->charset= get_charset(pos->language)))
354  {
355  errno=HA_ERR_UNKNOWN_CHARSET;
356  goto err;
357  }
358  }
359  }
360  share->uniqueinfo[i].end=pos;
361  pos->type=HA_KEYTYPE_END; /* End */
362  pos->null_bit=0;
363  pos->flag=0;
364  pos++;
365  }
366  }
367 
368  disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
369  for (i=j=offset=0 ; i < share->base.fields ; i++)
370  {
371  disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
372  share->rec[i].pack_type=0;
373  share->rec[i].huff_tree=0;
374  share->rec[i].offset=offset;
375  if (share->rec[i].type == (int) FIELD_BLOB)
376  {
377  share->blobs[j].pack_length=
378  share->rec[i].length-portable_sizeof_char_ptr;
379  share->blobs[j].offset=offset;
380  j++;
381  }
382  offset+=share->rec[i].length;
383  }
384  share->rec[i].type=(int) FIELD_LAST; /* End marker */
385  if (offset > share->base.reclength)
386  {
387  errno= HA_ERR_CRASHED;
388  goto err;
389  }
390 
391  if (! lock_error)
392  {
393  lock_error=1; /* Database unlocked */
394  }
395 
396  if (mi_open_datafile(&info, share, -1))
397  goto err;
398  errpos=5;
399 
400  share->kfile=kfile;
401  share->this_process=(ulong) getpid();
402  share->last_process= share->state.process;
403  share->base.key_parts=key_parts;
404  share->base.all_key_parts=key_parts+unique_key_parts;
405  if (!(share->last_version=share->state.version))
406  share->last_version=1; /* Safety */
407  share->rec_reflength=share->base.rec_reflength; /* May be changed */
408  share->base.margin_key_file_length=(share->base.max_key_file_length -
409  (keys ? MI_INDEX_BLOCK_MARGIN *
410  share->blocksize * keys : 0));
411  share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
412  share->data_file_type=STATIC_RECORD;
413  if (share->options & HA_OPTION_PACK_RECORD)
414  share->data_file_type = DYNAMIC_RECORD;
415  free(disk_cache);
416  disk_cache= NULL;
417  mi_setup_functions(share);
418  share->is_log_table= false;
419  if (myisam_concurrent_insert)
420  {
421  share->concurrent_insert=
422  ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
423  HA_OPTION_COMPRESS_RECORD |
424  HA_OPTION_TEMP_COMPRESS_RECORD)) ||
425  (open_flags & HA_OPEN_TMP_TABLE) || have_rtree) ? 0 : 1;
426  if (share->concurrent_insert)
427  {
428  assert(0);
429  }
430  }
431  }
432  else
433  {
434  share= old_info->s;
435  if (mode == O_RDWR && share->mode == O_RDONLY)
436  {
437  errno=EACCES; /* Can't open in write mode */
438  goto err;
439  }
440  if (mi_open_datafile(&info, share, old_info->dfile))
441  goto err;
442  errpos=5;
443  have_rtree= old_info->rtree_recursion_state != NULL;
444  }
445 
446  /* alloc and set up private structure parts */
447  if (!drizzled::memory::multi_malloc(MY_WME,
448  &m_info,sizeof(MI_INFO),
449  &info.blobs,sizeof(MI_BLOB)*share->base.blobs,
450  &info.buff,(share->base.max_key_block_length*2+
451  share->base.max_key_length),
452  &info.lastkey,share->base.max_key_length*3+1,
453  &info.first_mbr_key, share->base.max_key_length,
454  &info.filename, identifier.getPath().length()+1,
455  &info.rtree_recursion_state,have_rtree ? 1024 : 0,
456  NULL))
457  goto err;
458  errpos=6;
459 
460  if (!have_rtree)
461  info.rtree_recursion_state= NULL;
462 
463  strcpy(info.filename, identifier.getPath().c_str());
464  memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
465  info.lastkey2=info.lastkey+share->base.max_key_length;
466 
467  info.s=share;
468  info.lastpos= HA_OFFSET_ERROR;
469  info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
470  info.opt_flag=READ_CHECK_USED;
471  info.this_unique= (ulong) info.dfile; /* Uniq number in process */
472  if (share->data_file_type == COMPRESSED_RECORD)
473  info.this_unique= share->state.unique;
474  info.this_loop=0; /* Update counter */
475  info.last_unique= share->state.unique;
476  info.last_loop= share->state.update_count;
477  if (mode == O_RDONLY)
478  share->options|=HA_OPTION_READ_ONLY_DATA;
479  info.lock_type=F_UNLCK;
480  info.quick_mode=0;
481  info.bulk_insert=0;
482  info.errkey= -1;
483  info.page_changed=1;
484  info.read_record=share->read_record;
485  share->reopen++;
486  share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
487  if (share->options & HA_OPTION_READ_ONLY_DATA)
488  {
489  info.lock_type=F_RDLCK;
490  share->r_locks++;
491  share->tot_locks++;
492  }
493  if ((open_flags & HA_OPEN_TMP_TABLE) ||
494  (share->options & HA_OPTION_TMP_TABLE))
495  {
496  share->temporary=share->delay_key_write=1;
497  share->write_flag=MYF(MY_NABP);
498  /*
499  * The following two statements are commented out as a fix of
500  * bug https://bugs.launchpad.net/drizzle/+bug/387627
501  *
502  * UPDATE can be TRUNCATE on TEMPORARY TABLE (MyISAM).
503  * The root cause of why this makes a difference hasn't
504  * been found, but this fixes things for now.
505  */
506 // share->w_locks++; // We don't have to update status
507 // share->tot_locks++;
508  info.lock_type=F_WRLCK;
509  }
510 
511  share->delay_key_write= 1;
512  info.state= &share->state.state; /* Change global values by default */
513 
514  /* Allocate buffer for one record */
515 
516  /* prerequisites: memset(info, 0) && info->s=share; are met. */
517  if (!mi_alloc_rec_buff(&info, SIZE_MAX, &info.rec_buff))
518  goto err;
519  memset(info.rec_buff, 0, mi_get_rec_buff_len(&info, info.rec_buff));
520 
521  *m_info=info;
522  myisam_open_list.push_front(m_info);
523 
524  THR_LOCK_myisam.unlock();
525  return(m_info);
526 
527 err:
528  free(disk_cache);
529  save_errno=errno ? errno : HA_ERR_END_OF_FILE;
530  if ((save_errno == HA_ERR_CRASHED) ||
531  (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
532  (save_errno == HA_ERR_CRASHED_ON_REPAIR))
533  mi_report_error(save_errno, identifier.getPath().c_str());
534  switch (errpos) {
535  case 6:
536  free((unsigned char*) m_info);
537  /* fall through */
538  case 5:
539  internal::my_close(info.dfile,MYF(0));
540  if (old_info)
541  break; /* Don't remove open table */
542  /* fall through */
543  case 4:
544  free((unsigned char*) share);
545  /* fall through */
546  case 3:
547  /* fall through */
548  case 1:
549  internal::my_close(kfile,MYF(0));
550  /* fall through */
551  case 0:
552  default:
553  break;
554  }
555  THR_LOCK_myisam.unlock();
556  errno=save_errno;
557  return (NULL);
558 } /* mi_open */
559 
560 
561 unsigned char *mi_alloc_rec_buff(MI_INFO *info, size_t length, unsigned char **buf)
562 {
563  uint32_t extra;
564  uint32_t old_length= 0;
565 
566  if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
567  {
568  unsigned char *newptr = *buf;
569 
570  /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
571  if (length == SIZE_MAX)
572  {
573  if (info->s->options & HA_OPTION_COMPRESS_RECORD)
574  length= max(info->s->base.pack_reclength, info->s->max_pack_length);
575  else
576  length= info->s->base.pack_reclength;
577  length= max((uint32_t)length, info->s->base.max_key_length);
578  /* Avoid unnecessary realloc */
579  if (newptr && length == old_length)
580  return newptr;
581  }
582 
583  extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
584  ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
585  MI_REC_BUFF_OFFSET : 0);
586  if (extra && newptr)
587  newptr-= MI_REC_BUFF_OFFSET;
588  void *tmpnewptr= NULL;
589  if (!(tmpnewptr= realloc(newptr, length+extra+8)))
590  return newptr;
591  newptr= (unsigned char *)tmpnewptr;
592  *((uint32_t *) newptr)= (uint32_t) length;
593  *buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
594  }
595  return *buf;
596 }
597 
598 
599 static uint64_t mi_safe_mul(uint64_t a, uint64_t b)
600 {
601  uint64_t max_val= ~ (uint64_t) 0; /* internal::my_off_t is unsigned */
602 
603  if (!a || max_val / a < b)
604  return max_val;
605  return a*b;
606 }
607 
608  /* Set up functions in structs */
609 
610 void mi_setup_functions(register MYISAM_SHARE *share)
611 {
612  if (share->options & HA_OPTION_PACK_RECORD)
613  {
614  share->read_record=_mi_read_dynamic_record;
615  share->read_rnd=_mi_read_rnd_dynamic_record;
616  share->delete_record=_mi_delete_dynamic_record;
617  share->compare_record=_mi_cmp_dynamic_record;
618  share->compare_unique=_mi_cmp_dynamic_unique;
619  share->calc_checksum= mi_checksum;
620 
621  /* add bits used to pack data to pack_reclength for faster allocation */
622  share->base.pack_reclength+= share->base.pack_bits;
623  if (share->base.blobs)
624  {
625  share->update_record=_mi_update_blob_record;
626  share->write_record=_mi_write_blob_record;
627  }
628  else
629  {
630  share->write_record=_mi_write_dynamic_record;
631  share->update_record=_mi_update_dynamic_record;
632  }
633  }
634  else
635  {
636  share->read_record=_mi_read_static_record;
637  share->read_rnd=_mi_read_rnd_static_record;
638  share->delete_record=_mi_delete_static_record;
639  share->compare_record=_mi_cmp_static_record;
640  share->update_record=_mi_update_static_record;
641  share->write_record=_mi_write_static_record;
642  share->compare_unique=_mi_cmp_static_unique;
643  share->calc_checksum= mi_static_checksum;
644  }
645  share->file_read= mi_nommap_pread;
646  share->file_write= mi_nommap_pwrite;
647  share->calc_checksum=0;
648 }
649 
650 
651 static void setup_key_functions(register MI_KEYDEF *keyinfo)
652 {
653  {
654  keyinfo->ck_insert = _mi_ck_write;
655  keyinfo->ck_delete = _mi_ck_delete;
656  }
657  if (keyinfo->flag & HA_BINARY_PACK_KEY)
658  { /* Simple prefix compression */
659  keyinfo->bin_search=_mi_seq_search;
660  keyinfo->get_key=_mi_get_binary_pack_key;
661  keyinfo->pack_key=_mi_calc_bin_pack_key_length;
662  keyinfo->store_key=_mi_store_bin_pack_key;
663  }
664  else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
665  {
666  keyinfo->get_key= _mi_get_pack_key;
667  if (keyinfo->seg[0].flag & HA_PACK_KEY)
668  { /* Prefix compression */
669  /*
670  _mi_prefix_search() compares end-space against ASCII blank (' ').
671  It cannot be used for character sets, that do not encode the
672  blank character like ASCII does. UCS2 is an example. All
673  character sets with a fixed width > 1 or a mimimum width > 1
674  cannot represent blank like ASCII does. In these cases we have
675  to use _mi_seq_search() for the search.
676  */
677  if (not keyinfo->seg->charset || keyinfo->seg->charset->use_strnxfrm() ||
678  (keyinfo->seg->flag & HA_NULL_PART) ||
679  (keyinfo->seg->charset->mbminlen > 1))
680  keyinfo->bin_search=_mi_seq_search;
681  else
682  keyinfo->bin_search=_mi_prefix_search;
683  keyinfo->pack_key=_mi_calc_var_pack_key_length;
684  keyinfo->store_key=_mi_store_var_pack_key;
685  }
686  else
687  {
688  keyinfo->bin_search=_mi_seq_search;
689  keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
690  keyinfo->store_key=_mi_store_static_key;
691  }
692  }
693  else
694  {
695  keyinfo->bin_search=_mi_bin_search;
696  keyinfo->get_key=_mi_get_static_key;
697  keyinfo->pack_key=_mi_calc_static_key_length;
698  keyinfo->store_key=_mi_store_static_key;
699  }
700  return;
701 }
702 
703 
704 /*
705  Function to save and store the header in the index file (.MYI)
706 */
707 
708 uint32_t mi_state_info_write(int file, MI_STATE_INFO *state, uint32_t pWrite)
709 {
710  unsigned char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
711  unsigned char *ptr=buff;
712  uint i, keys= (uint) state->header.keys,
713  key_blocks=state->header.max_block_size_index;
714 
715  memcpy(ptr,&state->header,sizeof(state->header));
716  ptr+=sizeof(state->header);
717 
718  /* open_count must be first because of _mi_mark_file_changed ! */
719  mi_int2store(ptr,state->open_count); ptr +=2;
720  *ptr++= (unsigned char)state->changed; *ptr++= state->sortkey;
721  mi_rowstore(ptr,state->state.records); ptr +=8;
722  mi_rowstore(ptr,state->state.del); ptr +=8;
723  mi_rowstore(ptr,state->split); ptr +=8;
724  mi_sizestore(ptr,state->dellink); ptr +=8;
725  mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
726  mi_sizestore(ptr,state->state.data_file_length); ptr +=8;
727  mi_sizestore(ptr,state->state.empty); ptr +=8;
728  mi_sizestore(ptr,state->state.key_empty); ptr +=8;
729  mi_int8store(ptr,state->auto_increment); ptr +=8;
730  mi_int8store(ptr,(uint64_t) state->state.checksum);ptr +=8;
731  mi_int4store(ptr,state->process); ptr +=4;
732  mi_int4store(ptr,state->unique); ptr +=4;
733  mi_int4store(ptr,state->status); ptr +=4;
734  mi_int4store(ptr,state->update_count); ptr +=4;
735 
736  ptr+=state->state_diff_length;
737 
738  for (i=0; i < keys; i++)
739  {
740  mi_sizestore(ptr,state->key_root[i]); ptr +=8;
741  }
742  for (i=0; i < key_blocks; i++)
743  {
744  mi_sizestore(ptr,state->key_del[i]); ptr +=8;
745  }
746  if (pWrite & 2) /* From isamchk */
747  {
748  uint32_t key_parts= mi_uint2korr(state->header.key_parts);
749  mi_int4store(ptr,state->sec_index_changed); ptr +=4;
750  mi_int4store(ptr,state->sec_index_used); ptr +=4;
751  mi_int4store(ptr,state->version); ptr +=4;
752  mi_int8store(ptr,state->key_map); ptr +=8;
753  mi_int8store(ptr,(uint64_t) state->create_time); ptr +=8;
754  mi_int8store(ptr,(uint64_t) state->recover_time); ptr +=8;
755  mi_int8store(ptr,(uint64_t) state->check_time); ptr +=8;
756  mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8;
757  for (i=0 ; i < key_parts ; i++)
758  {
759  mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4;
760  }
761  }
762 
763  if (pWrite & 1)
764  return(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
765  MYF(MY_NABP | MY_THREADSAFE)) != 0);
766  return(internal::my_write(file, buff, (size_t) (ptr-buff),
767  MYF(MY_NABP)) != 0);
768 }
769 
770 
771 static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state)
772 {
773  uint32_t i,keys,key_parts,key_blocks;
774  memcpy(&state->header,ptr, sizeof(state->header));
775  ptr +=sizeof(state->header);
776  keys=(uint) state->header.keys;
777  key_parts=mi_uint2korr(state->header.key_parts);
778  key_blocks=state->header.max_block_size_index;
779 
780  state->open_count = mi_uint2korr(ptr); ptr +=2;
781  state->changed= *ptr++;
782  state->sortkey = (uint) *ptr++;
783  state->state.records= mi_rowkorr(ptr); ptr +=8;
784  state->state.del = mi_rowkorr(ptr); ptr +=8;
785  state->split = mi_rowkorr(ptr); ptr +=8;
786  state->dellink= mi_sizekorr(ptr); ptr +=8;
787  state->state.key_file_length = mi_sizekorr(ptr); ptr +=8;
788  state->state.data_file_length= mi_sizekorr(ptr); ptr +=8;
789  state->state.empty = mi_sizekorr(ptr); ptr +=8;
790  state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
791  state->auto_increment=mi_uint8korr(ptr); ptr +=8;
792  state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8;
793  state->process= mi_uint4korr(ptr); ptr +=4;
794  state->unique = mi_uint4korr(ptr); ptr +=4;
795  state->status = mi_uint4korr(ptr); ptr +=4;
796  state->update_count=mi_uint4korr(ptr); ptr +=4;
797 
798  ptr+= state->state_diff_length;
799 
800  for (i=0; i < keys; i++)
801  {
802  state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
803  }
804  for (i=0; i < key_blocks; i++)
805  {
806  state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
807  }
808  state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
809  state->sec_index_used = mi_uint4korr(ptr); ptr +=4;
810  state->version = mi_uint4korr(ptr); ptr +=4;
811  state->key_map = mi_uint8korr(ptr); ptr +=8;
812  state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
813  state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
814  state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8;
815  state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
816  for (i=0 ; i < key_parts ; i++)
817  {
818  state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
819  }
820  return ptr;
821 }
822 
823 
824 uint32_t mi_state_info_read_dsk(int file, MI_STATE_INFO *state, bool pRead)
825 {
826  unsigned char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
827 
828  if (pRead)
829  {
830  if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
831  return 1;
832  }
833  else if (internal::my_read(file, buff, state->state_length,MYF(MY_NABP)))
834  return 1;
835  mi_state_info_read(buff, state);
836 
837  return 0;
838 }
839 
840 
841 /****************************************************************************
842 ** store and read of MI_BASE_INFO
843 ****************************************************************************/
844 
845 uint32_t mi_base_info_write(int file, MI_BASE_INFO *base)
846 {
847  unsigned char buff[MI_BASE_INFO_SIZE], *ptr=buff;
848 
849  mi_sizestore(ptr,base->keystart); ptr +=8;
850  mi_sizestore(ptr,base->max_data_file_length); ptr +=8;
851  mi_sizestore(ptr,base->max_key_file_length); ptr +=8;
852  mi_rowstore(ptr,base->records); ptr +=8;
853  mi_rowstore(ptr,base->reloc); ptr +=8;
854  mi_int4store(ptr,base->mean_row_length); ptr +=4;
855  mi_int4store(ptr,base->reclength); ptr +=4;
856  mi_int4store(ptr,base->pack_reclength); ptr +=4;
857  mi_int4store(ptr,base->min_pack_length); ptr +=4;
858  mi_int4store(ptr,base->max_pack_length); ptr +=4;
859  mi_int4store(ptr,base->min_block_length); ptr +=4;
860  mi_int4store(ptr,base->fields); ptr +=4;
861  mi_int4store(ptr,base->pack_fields); ptr +=4;
862  *ptr++=base->rec_reflength;
863  *ptr++=base->key_reflength;
864  *ptr++=base->keys;
865  *ptr++=base->auto_key;
866  mi_int2store(ptr,base->pack_bits); ptr +=2;
867  mi_int2store(ptr,base->blobs); ptr +=2;
868  mi_int2store(ptr,base->max_key_block_length); ptr +=2;
869  mi_int2store(ptr,base->max_key_length); ptr +=2;
870  mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2;
871  *ptr++= base->extra_alloc_procent;
872  /* old raid info slots */
873  *ptr++= 0;
874  mi_int2store(ptr,UINT16_C(0)); ptr +=2;
875  mi_int4store(ptr,UINT32_C(0)); ptr +=4;
876 
877  memset(ptr, 0, 6); ptr +=6; /* extra */
878  return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
879 }
880 
881 
882 static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base)
883 {
884  base->keystart = mi_sizekorr(ptr); ptr +=8;
885  base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
886  base->max_key_file_length = mi_sizekorr(ptr); ptr +=8;
887  base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8;
888  base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8;
889  base->mean_row_length = mi_uint4korr(ptr); ptr +=4;
890  base->reclength = mi_uint4korr(ptr); ptr +=4;
891  base->pack_reclength = mi_uint4korr(ptr); ptr +=4;
892  base->min_pack_length = mi_uint4korr(ptr); ptr +=4;
893  base->max_pack_length = mi_uint4korr(ptr); ptr +=4;
894  base->min_block_length = mi_uint4korr(ptr); ptr +=4;
895  base->fields = mi_uint4korr(ptr); ptr +=4;
896  base->pack_fields = mi_uint4korr(ptr); ptr +=4;
897 
898  base->rec_reflength = *ptr++;
899  base->key_reflength = *ptr++;
900  base->keys= *ptr++;
901  base->auto_key= *ptr++;
902  base->pack_bits = mi_uint2korr(ptr); ptr +=2;
903  base->blobs = mi_uint2korr(ptr); ptr +=2;
904  base->max_key_block_length= mi_uint2korr(ptr); ptr +=2;
905  base->max_key_length = mi_uint2korr(ptr); ptr +=2;
906  base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2;
907  base->extra_alloc_procent = *ptr++;
908 
909  /* advance past raid_type (1) raid_chunks (2) and raid_chunksize (4) */
910  ptr+= 7;
911 
912  ptr+=6;
913  return ptr;
914 }
915 
916 /*--------------------------------------------------------------------------
917  mi_keydef
918 ---------------------------------------------------------------------------*/
919 
920 uint32_t mi_keydef_write(int file, MI_KEYDEF *keydef)
921 {
922  unsigned char buff[MI_KEYDEF_SIZE];
923  unsigned char *ptr=buff;
924 
925  *ptr++ = (unsigned char) keydef->keysegs;
926  *ptr++ = keydef->key_alg; /* Rtree or Btree */
927  mi_int2store(ptr,keydef->flag); ptr +=2;
928  mi_int2store(ptr,keydef->block_length); ptr +=2;
929  mi_int2store(ptr,keydef->keylength); ptr +=2;
930  mi_int2store(ptr,keydef->minlength); ptr +=2;
931  mi_int2store(ptr,keydef->maxlength); ptr +=2;
932  return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
933 }
934 
935 static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef)
936 {
937  keydef->keysegs = (uint) *ptr++;
938  keydef->key_alg = *ptr++; /* Rtree or Btree */
939 
940  keydef->flag = mi_uint2korr(ptr); ptr +=2;
941  keydef->block_length = mi_uint2korr(ptr); ptr +=2;
942  keydef->keylength = mi_uint2korr(ptr); ptr +=2;
943  keydef->minlength = mi_uint2korr(ptr); ptr +=2;
944  keydef->maxlength = mi_uint2korr(ptr); ptr +=2;
945  keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
946  keydef->underflow_block_length=keydef->block_length/3;
947  keydef->version = 0; /* Not saved */
948  return ptr;
949 }
950 
951 /***************************************************************************
952 ** mi_keyseg
953 ***************************************************************************/
954 
955 int mi_keyseg_write(int file, const HA_KEYSEG *keyseg)
956 {
957  unsigned char buff[HA_KEYSEG_SIZE];
958  unsigned char *ptr=buff;
959  ulong pos;
960 
961  *ptr++= keyseg->type;
962  *ptr++= keyseg->language;
963  *ptr++= keyseg->null_bit;
964  *ptr++= keyseg->bit_start;
965  *ptr++= keyseg->bit_end;
966  *ptr++= keyseg->bit_length;
967  mi_int2store(ptr,keyseg->flag); ptr+=2;
968  mi_int2store(ptr,keyseg->length); ptr+=2;
969  mi_int4store(ptr,keyseg->start); ptr+=4;
970  pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
971  mi_int4store(ptr, pos);
972  ptr+=4;
973 
974  return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
975 }
976 
977 
978 static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg)
979 {
980  keyseg->type = *ptr++;
981  keyseg->language = *ptr++;
982  keyseg->null_bit = *ptr++;
983  keyseg->bit_start = *ptr++;
984  keyseg->bit_end = *ptr++;
985  keyseg->bit_length = *ptr++;
986  keyseg->flag = mi_uint2korr(ptr); ptr +=2;
987  keyseg->length = mi_uint2korr(ptr); ptr +=2;
988  keyseg->start = mi_uint4korr(ptr); ptr +=4;
989  keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
990  keyseg->charset=0; /* Will be filled in later */
991  if (keyseg->null_bit)
992  keyseg->bit_pos= (uint16_t)(keyseg->null_pos + (keyseg->null_bit == 7));
993  else
994  {
995  keyseg->bit_pos= (uint16_t)keyseg->null_pos;
996  keyseg->null_pos= 0;
997  }
998  return ptr;
999 }
1000 
1001 /*--------------------------------------------------------------------------
1002  mi_uniquedef
1003 ---------------------------------------------------------------------------*/
1004 
1005 uint32_t mi_uniquedef_write(int file, MI_UNIQUEDEF *def)
1006 {
1007  unsigned char buff[MI_UNIQUEDEF_SIZE];
1008  unsigned char *ptr=buff;
1009 
1010  mi_int2store(ptr,def->keysegs); ptr+=2;
1011  *ptr++= (unsigned char) def->key;
1012  *ptr++ = (unsigned char) def->null_are_equal;
1013 
1014  return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1015 }
1016 
1017 static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def)
1018 {
1019  def->keysegs = mi_uint2korr(ptr);
1020  def->key = ptr[2];
1021  def->null_are_equal=ptr[3];
1022  return ptr+4; /* 1 extra byte */
1023 }
1024 
1025 /***************************************************************************
1026 ** MI_COLUMNDEF
1027 ***************************************************************************/
1028 
1029 uint32_t mi_recinfo_write(int file, MI_COLUMNDEF *recinfo)
1030 {
1031  unsigned char buff[MI_COLUMNDEF_SIZE];
1032  unsigned char *ptr=buff;
1033 
1034  mi_int2store(ptr,recinfo->type); ptr +=2;
1035  mi_int2store(ptr,recinfo->length); ptr +=2;
1036  *ptr++ = recinfo->null_bit;
1037  mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
1038  return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1039 }
1040 
1041 static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo)
1042 {
1043  recinfo->type= mi_sint2korr(ptr); ptr +=2;
1044  recinfo->length=mi_uint2korr(ptr); ptr +=2;
1045  recinfo->null_bit= (uint8_t) *ptr++;
1046  recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
1047  return ptr;
1048 }
1049 
1050 /**************************************************************************
1051 Open data file
1052 We can't use dup() here as the data file descriptors need to have different
1053 active seek-positions.
1054 
1055 The argument file_to_dup is here for the future if there would on some OS
1056 exist a dup()-like call that would give us two different file descriptors.
1057 *************************************************************************/
1058 
1059 int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, int file_to_dup)
1060 {
1061  (void)file_to_dup;
1062  info->dfile=internal::my_open(share->data_file_name, share->mode,
1063  MYF(MY_WME));
1064  return info->dfile >= 0 ? 0 : 1;
1065 }
1066 
1067 
1068 int mi_open_keyfile(MYISAM_SHARE *share)
1069 {
1070  if ((share->kfile=internal::my_open(share->unique_file_name, share->mode,
1071  MYF(MY_WME))) < 0)
1072  return 1;
1073  return 0;
1074 }
1075 
1076 
1077 /*
1078  Disable all indexes.
1079 
1080  SYNOPSIS
1081  mi_disable_indexes()
1082  info A pointer to the MyISAM storage engine MI_INFO struct.
1083 
1084  DESCRIPTION
1085  Disable all indexes.
1086 
1087  RETURN
1088  0 ok
1089 */
1090 
1091 int mi_disable_indexes(MI_INFO *info)
1092 {
1093  MYISAM_SHARE *share= info->s;
1094 
1095  mi_clear_all_keys_active(share->state.key_map);
1096  return 0;
1097 }
1098 
1099 
1100 /*
1101  Enable all indexes
1102 
1103  SYNOPSIS
1104  mi_enable_indexes()
1105  info A pointer to the MyISAM storage engine MI_INFO struct.
1106 
1107  DESCRIPTION
1108  Enable all indexes. The indexes might have been disabled
1109  by mi_disable_index() before.
1110  The function works only if both data and indexes are empty,
1111  otherwise a repair is required.
1112  To be sure, call handler::delete_all_rows() before.
1113 
1114  RETURN
1115  0 ok
1116  HA_ERR_CRASHED data or index is non-empty.
1117 */
1118 
1119 int mi_enable_indexes(MI_INFO *info)
1120 {
1121  int error= 0;
1122  MYISAM_SHARE *share= info->s;
1123 
1124  if (share->state.state.data_file_length ||
1125  (share->state.state.key_file_length != share->base.keystart))
1126  {
1127  mi_print_error(info->s, HA_ERR_CRASHED);
1128  error= HA_ERR_CRASHED;
1129  }
1130  else
1131  mi_set_all_keys_active(share->state.key_map, share->base.keys);
1132  return error;
1133 }
1134 
1135 
1136 /*
1137  Test if indexes are disabled.
1138 
1139  SYNOPSIS
1140  mi_indexes_are_disabled()
1141  info A pointer to the MyISAM storage engine MI_INFO struct.
1142 
1143  DESCRIPTION
1144  Test if indexes are disabled.
1145 
1146  RETURN
1147  0 indexes are not disabled
1148  1 all indexes are disabled
1149  2 non-unique indexes are disabled
1150 */
1151 
1152 int mi_indexes_are_disabled(MI_INFO *info)
1153 {
1154  MYISAM_SHARE *share= info->s;
1155 
1156  /*
1157  No keys or all are enabled. keys is the number of keys. Left shifted
1158  gives us only one bit set. When decreased by one, gives us all all bits
1159  up to this one set and it gets unset.
1160  */
1161  if (!share->base.keys ||
1162  (mi_is_all_keys_active(share->state.key_map, share->base.keys)))
1163  return 0;
1164 
1165  /* All are disabled */
1166  if (mi_is_any_key_active(share->state.key_map))
1167  return 1;
1168 
1169  /*
1170  We have keys. Some enabled, some disabled.
1171  Don't check for any non-unique disabled but return directly 2
1172  */
1173  return 2;
1174 }
1175