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