18 #include "myisam_priv.h"
19 #include <drizzled/internal/my_bit.h>
20 #include <drizzled/internal/my_sys.h>
22 #include <drizzled/util/test.h>
23 #include <drizzled/charset.h>
24 #include <drizzled/error.h>
30 using namespace drizzled;
51 static inline uint32_t my_round_up_to_next_power(uint32_t v)
66 int mi_create(
const char *name,uint32_t keys,
MI_KEYDEF *keydefs,
71 register uint32_t i, j;
72 int dfile= 0, file= 0;
73 int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
75 uint32_t fields,length,max_key_length,packed,pointer,real_length_diff,
76 key_length,info_length,key_segs,options,min_key_length_skip,
77 base_pos,long_varchar_count,varchar_length,
78 max_key_block_length,unique_key_parts,fulltext_keys,offset;
79 uint32_t aligned_key_start, block_length;
80 ulong reclength, real_reclength,min_pack_length;
81 char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
83 uint64_t tot_length,max_rows, tmp;
84 enum en_fieldtype type;
90 ulong *rec_per_key_part;
91 internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
96 memset(&tmp_create_info, 0,
sizeof(tmp_create_info));
100 if (keys + uniques > MI_MAX_KEY || columns == 0)
102 return(errno=HA_WRONG_CREATE_OPTION);
106 memset(&share, 0,
sizeof(share));
108 if (flags & HA_DONT_TOUCH_DATA)
110 if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
111 options=ci->old_options &
112 (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
113 HA_OPTION_READ_ONLY_DATA |
114 HA_OPTION_TMP_TABLE );
116 options=ci->old_options &
117 (HA_OPTION_TMP_TABLE );
120 if (ci->reloc_rows > ci->max_rows)
121 ci->reloc_rows=ci->max_rows;
123 if (!(rec_per_key_part=
124 (ulong*) malloc((keys + uniques)*MI_MAX_KEY_SEG*
sizeof(
long))))
126 memset(rec_per_key_part, 0, (keys + uniques)*MI_MAX_KEY_SEG*
sizeof(
long));
130 reclength=varchar_length=long_varchar_count=packed=
131 min_pack_length=pack_reclength=0;
132 for (rec=recinfo, fields=0 ;
136 reclength+=rec->length;
137 if ((type=(
enum en_fieldtype) rec->type) != FIELD_NORMAL &&
141 if (type == FIELD_BLOB)
144 if (pack_reclength != INT32_MAX)
146 if (rec->length == 4+portable_sizeof_char_ptr)
147 pack_reclength= INT32_MAX;
149 pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8));
152 else if (type == FIELD_SKIP_PRESPACE ||
153 type == FIELD_SKIP_ENDSPACE)
155 if (pack_reclength != INT32_MAX)
156 pack_reclength+= rec->length > 255 ? 2 : 1;
159 else if (type == FIELD_VARCHAR)
161 varchar_length+= rec->length-1;
166 if (test(rec->length >= 257))
168 long_varchar_count++;
172 else if (type != FIELD_SKIP_ZERO)
174 min_pack_length+=rec->length;
179 min_pack_length+=rec->length;
181 if ((packed & 7) == 1)
183 while (rec != recinfo)
186 if (rec->type == (
int) FIELD_SKIP_ZERO && rec->length == 1)
192 rec->type=(int) FIELD_NORMAL;
200 if (packed || (flags & HA_PACK_RECORD))
201 options|=HA_OPTION_PACK_RECORD;
202 if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
203 min_pack_length+= varchar_length;
204 if (flags & HA_CREATE_TMP_TABLE)
206 options|= HA_OPTION_TMP_TABLE;
207 create_mode|= O_EXCL;
211 if (pack_reclength != INT32_MAX)
212 pack_reclength+= reclength+packed +
213 test(test_all_bits(options,
214 uint32_t(HA_PACK_RECORD)));
215 min_pack_length+=packed;
217 if (!ci->data_file_length && ci->max_rows)
219 if (pack_reclength == INT32_MAX ||
220 (~(uint64_t) 0)/ci->max_rows < (uint64_t) pack_reclength)
221 ci->data_file_length= ~(uint64_t) 0;
223 ci->data_file_length=(uint64_t) ci->max_rows*pack_reclength;
225 else if (!ci->max_rows)
226 ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
227 ((options & HA_OPTION_PACK_RECORD) ?
230 if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
231 pointer=mi_get_pointer_length(ci->data_file_length, data_pointer_size);
233 pointer=mi_get_pointer_length(ci->max_rows, data_pointer_size);
234 if (!(max_rows=(uint64_t) ci->max_rows))
235 max_rows= ((((uint64_t) 1 << (pointer*8)) -1) / min_pack_length);
238 real_reclength=reclength;
239 if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
241 if (reclength <= pointer)
245 reclength+= long_varchar_count;
247 max_key_length=0; tot_length=0 ; key_segs=0;
249 max_key_block_length=0;
250 share.state.rec_per_key_part=rec_per_key_part;
251 share.state.key_root=key_root;
252 share.state.key_del=key_del;
255 max_key_block_length= myisam_block_size;
256 max_key_length= MI_UNIQUE_HASH_LENGTH + pointer;
259 for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
262 share.state.key_root[i]= HA_OFFSET_ERROR;
263 min_key_length_skip=length=real_length_diff=0;
267 if (keydef->flag & HA_PACK_KEY)
270 if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
271 HA_VAR_LENGTH_PART)))
274 keydef->flag&= ~HA_PACK_KEY;
275 keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
279 keydef->seg[0].flag|=HA_PACK_KEY;
280 keydef->flag|=HA_VAR_LENGTH_KEY;
281 options|=HA_OPTION_PACK_KEYS;
284 if (keydef->flag & HA_BINARY_PACK_KEY)
285 options|=HA_OPTION_PACK_KEYS;
287 if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
288 share.base.auto_key=i+1;
289 for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
292 switch (keyseg->type) {
293 case HA_KEYTYPE_LONG_INT:
294 case HA_KEYTYPE_DOUBLE:
295 case HA_KEYTYPE_ULONG_INT:
296 case HA_KEYTYPE_LONGLONG:
297 case HA_KEYTYPE_ULONGLONG:
298 keyseg->flag|= HA_SWAP_KEY;
300 case HA_KEYTYPE_VARTEXT1:
301 case HA_KEYTYPE_VARTEXT2:
302 case HA_KEYTYPE_VARBINARY1:
303 case HA_KEYTYPE_VARBINARY2:
304 if (!(keyseg->flag & HA_BLOB_PART))
307 keyseg->flag|= HA_VAR_LENGTH_PART;
309 keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
310 keyseg->type == HA_KEYTYPE_VARBINARY1) ?
317 if (keyseg->flag & HA_SPACE_PACK)
319 assert(!(keyseg->flag & HA_VAR_LENGTH_PART));
320 keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
321 options|=HA_OPTION_PACK_KEYS;
323 min_key_length_skip+=keyseg->length;
324 if (keyseg->length >= 255)
326 min_key_length_skip+=2;
330 if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
332 assert(!test_all_bits(keyseg->flag,
333 (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
334 keydef->flag|=HA_VAR_LENGTH_KEY;
336 options|=HA_OPTION_PACK_KEYS;
337 min_key_length_skip+=keyseg->length;
338 if (keyseg->length >= 255)
340 min_key_length_skip+=2;
344 key_length+= keyseg->length;
345 if (keyseg->null_bit)
348 options|=HA_OPTION_PACK_KEYS;
349 keyseg->flag|=HA_NULL_PART;
350 keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
354 key_segs+=keydef->keysegs;
355 if (keydef->keysegs > MI_MAX_KEY_SEG)
357 errno=HA_WRONG_CREATE_OPTION;
365 if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
367 share.state.rec_per_key_part[key_segs-1]=1L;
370 block_length= (keydef->block_length ?
371 my_round_up_to_next_power(keydef->block_length) :
373 block_length= max(block_length, (uint32_t)MI_MIN_KEY_BLOCK_LENGTH);
374 block_length= min(block_length, (uint32_t)MI_MAX_KEY_BLOCK_LENGTH);
376 keydef->block_length= (uint16_t) MI_BLOCK_SIZE(length-real_length_diff,
377 pointer,MI_MAX_KEYPTR_SIZE,
379 if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
380 length >= MI_MAX_KEY_BUFF)
382 errno=HA_WRONG_CREATE_OPTION;
385 set_if_bigger(max_key_block_length,(uint32_t)keydef->block_length);
386 keydef->keylength= (uint16_t) key_length;
387 keydef->minlength= (uint16_t) (length-min_key_length_skip);
388 keydef->maxlength= (uint16_t) length;
390 if (length > max_key_length)
391 max_key_length= length;
392 tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
394 (ulong) keydef->block_length;
396 for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
397 key_del[i]=HA_OFFSET_ERROR;
400 offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
401 for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
403 uniquedef->key=keys+i;
404 unique_key_parts+=uniquedef->keysegs;
405 share.state.key_root[keys+i]= HA_OFFSET_ERROR;
406 tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/
407 ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))*
408 (ulong) myisam_block_size;
413 base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
414 max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
415 MI_STATE_KEYBLOCK_SIZE+
416 key_segs*MI_STATE_KEYSEG_SIZE);
417 info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
418 keys * MI_KEYDEF_SIZE+
419 uniques * MI_UNIQUEDEF_SIZE +
420 (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
421 columns*MI_COLUMNDEF_SIZE);
423 if (info_length > 65535)
425 my_printf_error(EE_OK,
"MyISAM table '%s' has too many columns and/or "
426 "indexes and/or unique constraints.",
427 MYF(0), name + internal::dirname_length(name));
428 errno= HA_WRONG_CREATE_OPTION;
432 memmove(share.state.header.file_version,myisam_file_magic,4);
433 ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
434 HA_OPTION_COMPRESS_RECORD |
435 HA_OPTION_TEMP_COMPRESS_RECORD: 0);
436 mi_int2store(share.state.header.options,ci->old_options);
437 mi_int2store(share.state.header.header_length,info_length);
438 mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
439 mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
440 mi_int2store(share.state.header.base_pos,base_pos);
441 share.state.header.language= (ci->language ?
442 ci->language : default_charset_info->number);
443 share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
445 share.state.dellink = HA_OFFSET_ERROR;
446 share.state.process= (ulong) getpid();
447 share.state.unique= (ulong) 0;
448 share.state.update_count=(ulong) 0;
449 share.state.version= (ulong) time((time_t*) 0);
450 share.state.sortkey= UINT16_MAX;
451 share.state.auto_increment=ci->auto_increment;
452 share.options=options;
453 share.base.rec_reflength=pointer;
455 tmp= (tot_length + max_key_block_length * keys *
456 MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
461 share.base.key_reflength=
462 mi_get_pointer_length(max(ci->key_file_length,tmp),3);
463 share.base.keys= share.state.header.keys= keys;
464 share.state.header.uniques= uniques;
465 share.state.header.fulltext_keys= fulltext_keys;
466 mi_int2store(share.state.header.key_parts,key_segs);
467 mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
469 mi_set_all_keys_active(share.state.key_map, keys);
470 aligned_key_start= my_round_up_to_next_power(max_key_block_length ?
471 max_key_block_length :
474 share.base.keystart= share.state.state.key_file_length=
475 MY_ALIGN(info_length, aligned_key_start);
476 share.base.max_key_block_length=max_key_block_length;
477 share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
478 share.base.records=ci->max_rows;
479 share.base.reloc= ci->reloc_rows;
480 share.base.reclength=real_reclength;
481 share.base.pack_reclength=reclength;
482 share.base.max_pack_length=pack_reclength;
483 share.base.min_pack_length=min_pack_length;
484 share.base.pack_bits=packed;
485 share.base.fields=fields;
486 share.base.pack_fields=packed;
489 if (options & HA_OPTION_TMP_TABLE)
490 share.base.max_data_file_length=(internal::my_off_t) ci->data_file_length;
492 share.base.min_block_length=
493 (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
494 ! share.base.blobs) ?
495 max(share.base.pack_reclength,(ulong)MI_MIN_BLOCK_LENGTH) :
496 MI_EXTEND_BLOCK_LENGTH;
497 if (! (flags & HA_DONT_TOUCH_DATA))
498 share.state.create_time= (long) time((time_t*) 0);
500 THR_LOCK_myisam.lock();
506 if (ci->index_file_name)
508 char *iext= strrchr((
char *)ci->index_file_name,
'.');
509 int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
510 if (options & HA_OPTION_TMP_TABLE)
514 if ((path= strrchr((
char *)ci->index_file_name, FN_LIBCHAR)))
516 internal::fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT,
517 MY_REPLACE_DIR | MY_UNPACK_FILENAME |
518 MY_RETURN_REAL_PATH | MY_APPEND_EXT);
522 internal::fn_format(filename, ci->index_file_name,
"", MI_NAME_IEXT,
523 MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
524 (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
526 internal::fn_format(linkname, name,
"", MI_NAME_IEXT,
527 MY_UNPACK_FILENAME|MY_APPEND_EXT);
528 linkname_ptr=linkname;
537 char *iext= strrchr((
char *)name,
'.');
538 int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
539 internal::fn_format(filename, name,
"", MI_NAME_IEXT,
540 MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
541 (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
544 create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
557 if (test_if_reopen(filename))
559 my_printf_error(EE_OK,
"MyISAM table '%s' is in use "
560 "(most likely by a MERGE table). Try FLUSH TABLES.",
561 MYF(0), name + internal::dirname_length(name));
562 errno= HA_ERR_TABLE_EXIST;
566 if ((file= internal::my_create_with_symlink(linkname_ptr,
570 MYF(MY_WME | create_flag))) < 0)
574 if (!(flags & HA_DONT_TOUCH_DATA))
577 if (ci->data_file_name)
579 char *dext= strrchr((
char *)ci->data_file_name,
'.');
580 int have_dext= dext && !strcmp(dext, MI_NAME_DEXT);
582 if (options & HA_OPTION_TMP_TABLE)
586 if ((path= strrchr((
char *)ci->data_file_name, FN_LIBCHAR)))
588 internal::fn_format(filename, name, ci->data_file_name, MI_NAME_DEXT,
589 MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
593 internal::fn_format(filename, ci->data_file_name,
"", MI_NAME_DEXT,
595 (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
598 internal::fn_format(linkname, name,
"",MI_NAME_DEXT,
599 MY_UNPACK_FILENAME | MY_APPEND_EXT);
600 linkname_ptr=linkname;
605 internal::fn_format(filename,name,
"", MI_NAME_DEXT,
606 MY_UNPACK_FILENAME | MY_APPEND_EXT);
608 create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
610 if ((dfile= internal::my_create_with_symlink(linkname_ptr,
611 filename, 0, create_mode,
612 MYF(MY_WME | create_flag))) < 0)
618 if (mi_state_info_write(file, &share.state, 2) ||
619 mi_base_info_write(file, &share.base))
623 for (i=0 ; i < share.base.keys - uniques; i++)
627 if (mi_keydef_write(file, &keydefs[i]))
629 for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
630 if (mi_keyseg_write(file, &keydefs[i].seg[j]))
634 offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
635 memset(&tmp_keydef, 0,
sizeof(tmp_keydef));
636 memset(&tmp_keyseg, 0,
sizeof(tmp_keyseg));
637 for (i=0; i < uniques ; i++)
639 tmp_keydef.keysegs=1;
640 tmp_keydef.flag= HA_UNIQUE_CHECK;
641 tmp_keydef.block_length= (uint16_t)myisam_block_size;
642 tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer;
643 tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
644 tmp_keyseg.type= MI_UNIQUE_HASH_TYPE;
645 tmp_keyseg.length= MI_UNIQUE_HASH_LENGTH;
646 tmp_keyseg.start= offset;
647 offset+= MI_UNIQUE_HASH_LENGTH;
648 if (mi_keydef_write(file,&tmp_keydef) ||
649 mi_keyseg_write(file,(&tmp_keyseg)))
654 for (i=0 ; i < share.state.header.uniques ; i++)
657 keyseg= uniquedefs[i].seg;
658 if (mi_uniquedef_write(file, &uniquedefs[i]))
660 for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
664 switch (keyseg->type) {
665 case HA_KEYTYPE_VARTEXT1:
666 case HA_KEYTYPE_VARTEXT2:
667 case HA_KEYTYPE_VARBINARY1:
668 case HA_KEYTYPE_VARBINARY2:
669 if (!(keyseg->flag & HA_BLOB_PART))
671 keyseg->flag|= HA_VAR_LENGTH_PART;
672 keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
673 keyseg->type == HA_KEYTYPE_VARBINARY1) ?
680 if (mi_keyseg_write(file, keyseg))
684 for (i=0 ; i < share.base.fields ; i++)
685 if (mi_recinfo_write(file, &recinfo[i]))
689 if (ftruncate(file, (off_t) share.base.keystart))
692 if (! (flags & HA_DONT_TOUCH_DATA))
695 if (ftruncate(dfile,share.base.min_pack_length*ci->reloc_rows,))
699 if (internal::my_close(dfile,MYF(0)))
703 THR_LOCK_myisam.unlock();
704 if (internal::my_close(file,MYF(0)))
706 free((
char*) rec_per_key_part);
710 THR_LOCK_myisam.unlock();
714 internal::my_close(dfile,MYF(0));
717 if (! (flags & HA_DONT_TOUCH_DATA))
718 internal::my_delete_with_symlink(internal::fn_format(filename,name,
"",MI_NAME_DEXT,
719 MY_UNPACK_FILENAME | MY_APPEND_EXT),
723 internal::my_close(file,MYF(0));
724 if (! (flags & HA_DONT_TOUCH_DATA))
725 internal::my_delete_with_symlink(internal::fn_format(filename,name,
"",MI_NAME_IEXT,
726 MY_UNPACK_FILENAME | MY_APPEND_EXT),
729 free((
char*) rec_per_key_part);
730 return(errno=save_errno);
734 uint32_t mi_get_pointer_length(uint64_t file_length, uint32_t def)
736 assert(def >= 2 && def <= 7);
739 #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
740 if (file_length >= 1ULL << 56)
744 if (file_length >= 1ULL << 48)
746 else if (file_length >= 1ULL << 40)
748 else if (file_length >= 1ULL << 32)
750 else if (file_length >= 1ULL << 24)
752 else if (file_length >= 1ULL << 16)