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