1 /*
2    Copyright (c) 2000, 2011, Oracle and/or its affiliates
3    Copyright (c) 2009, 2013, Monty Program Ab.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; version 2 of the License.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
17 
18 /* Create a MyISAM table */
19 
20 #include "ftdefs.h"
21 #include "sp_defs.h"
22 #include <my_bit.h>
23 
24 #ifdef __WIN__
25 #include <fcntl.h>
26 #endif
27 #include <m_ctype.h>
28 
29 /*
30   Old options is used when recreating database, from myisamchk
31 */
32 
mi_create(const char * name,uint keys,MI_KEYDEF * keydefs,uint columns,MI_COLUMNDEF * recinfo,uint uniques,MI_UNIQUEDEF * uniquedefs,MI_CREATE_INFO * ci,uint flags)33 int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
34 	      uint columns, MI_COLUMNDEF *recinfo,
35 	      uint uniques, MI_UNIQUEDEF *uniquedefs,
36 	      MI_CREATE_INFO *ci,uint flags)
37 {
38   register uint i,j;
39   File UNINIT_VAR(dfile),UNINIT_VAR(file);
40   int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
41   myf create_flag;
42   uint fields,length,max_key_length,packed,pack_bytes,pointer,real_length_diff,
43        key_length,info_length,key_segs,options,min_key_length_skip,
44        base_pos,long_varchar_count,varchar_length,
45        max_key_block_length,unique_key_parts,fulltext_keys,offset;
46   uint aligned_key_start, block_length, res;
47   uint internal_table= flags & HA_CREATE_INTERNAL_TABLE;
48   ulong reclength, real_reclength,min_pack_length;
49   char kfilename[FN_REFLEN],klinkname[FN_REFLEN], *klinkname_ptr= 0;
50   char dfilename[FN_REFLEN],dlinkname[FN_REFLEN], *dlinkname_ptr= 0;
51   ulong pack_reclength;
52   ulonglong tot_length,max_rows, tmp;
53   enum en_fieldtype type;
54   MYISAM_SHARE share;
55   MI_KEYDEF *keydef,tmp_keydef;
56   MI_UNIQUEDEF *uniquedef;
57   HA_KEYSEG *keyseg,tmp_keyseg;
58   MI_COLUMNDEF *rec;
59   ulong *rec_per_key_part;
60   my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
61   MI_CREATE_INFO tmp_create_info;
62   DBUG_ENTER("mi_create");
63   DBUG_PRINT("enter", ("keys: %u  columns: %u  uniques: %u  flags: %u",
64                       keys, columns, uniques, flags));
65 
66   if (!ci)
67   {
68     bzero((char*) &tmp_create_info,sizeof(tmp_create_info));
69     ci=&tmp_create_info;
70   }
71 
72   if (keys + uniques > MI_MAX_KEY || columns == 0)
73   {
74     DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION);
75   }
76 
77   errpos=0;
78   options=0;
79   bzero((uchar*) &share,sizeof(share));
80 
81   if (flags & HA_DONT_TOUCH_DATA)
82   {
83     if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
84       options=ci->old_options &
85 	(HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
86 	 HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM |
87 	 HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
88     else
89       options=ci->old_options &
90 	(HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
91   }
92 
93   if (ci->reloc_rows > ci->max_rows)
94     ci->reloc_rows=ci->max_rows;		/* Check if wrong parameter */
95 
96   if (!(rec_per_key_part=
97 	(ulong*) my_malloc((keys + uniques)*HA_MAX_KEY_SEG*sizeof(long),
98 			   MYF(MY_WME | MY_ZEROFILL))))
99     DBUG_RETURN(my_errno);
100 
101 	/* Start by checking fields and field-types used */
102 
103   reclength=varchar_length=long_varchar_count=packed=
104     min_pack_length=pack_reclength=0;
105   for (rec=recinfo, fields=0 ;
106        fields != columns ;
107        rec++,fields++)
108   {
109     reclength+=rec->length;
110     if (rec->null_bit)
111       options|= HA_OPTION_NULL_FIELDS;
112 
113     if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
114 	type != FIELD_CHECK)
115     {
116       packed++;
117       if (type == FIELD_BLOB)
118       {
119 	share.base.blobs++;
120 	if (pack_reclength != INT_MAX32)
121 	{
122 	  if (rec->length == 4+portable_sizeof_char_ptr)
123 	    pack_reclength= INT_MAX32;
124 	  else
125 	    pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8)); /* Max blob length */
126 	}
127       }
128       else if (type == FIELD_SKIP_PRESPACE ||
129 	       type == FIELD_SKIP_ENDSPACE)
130       {
131 	if (pack_reclength != INT_MAX32)
132 	  pack_reclength+= rec->length > 255 ? 2 : 1;
133 	min_pack_length++;
134       }
135       else if (type == FIELD_VARCHAR)
136       {
137 	varchar_length+= rec->length-1;          /* Used for min_pack_length */
138 	packed--;
139 	pack_reclength++;
140         min_pack_length++;
141         /* We must test for 257 as length includes pack-length */
142         if (MY_TEST(rec->length >= 257))
143 	{
144 	  long_varchar_count++;
145 	  pack_reclength+= 2;			/* May be packed on 3 bytes */
146 	}
147         options|= HA_OPTION_NULL_FIELDS;        /* Use of mi_checksum() */
148       }
149       else if (type != FIELD_SKIP_ZERO)
150       {
151 	min_pack_length+=rec->length;
152 	packed--;				/* Not a pack record type */
153       }
154     }
155     else					/* FIELD_NORMAL */
156       min_pack_length+=rec->length;
157   }
158   if ((packed & 7) == 1)
159   {				/* Bad packing, try to remove a zero-field */
160     while (rec != recinfo)
161     {
162       rec--;
163       if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1)
164       {
165         /*
166           NOTE1: here we change a field type FIELD_SKIP_ZERO ->
167           FIELD_NORMAL
168         */
169 	rec->type=(int) FIELD_NORMAL;
170 	packed--;
171 	min_pack_length++;
172 	break;
173       }
174     }
175   }
176 
177   if (packed || (flags & HA_PACK_RECORD))
178     options|=HA_OPTION_PACK_RECORD;	/* Must use packed records */
179   /* We can't use checksum with static length rows */
180   if (!(options & HA_OPTION_PACK_RECORD))
181     options&= ~HA_OPTION_CHECKSUM;
182   if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
183     min_pack_length+= varchar_length;
184   if (flags & HA_CREATE_TMP_TABLE)
185   {
186     options|= HA_OPTION_TMP_TABLE;
187     create_mode|= O_NOFOLLOW | (internal_table ? 0 : O_EXCL);
188   }
189   if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
190   {
191     options|= HA_OPTION_CHECKSUM;
192     min_pack_length++;
193   }
194   /*
195     Don't set HA_OPTION_NULL_FIELDS if no checksums, as this flag makes
196     that file incompatible with MySQL.  This is ok, as this flag is only
197     used if one specifics table level checksums.
198   */
199   if (!(options & HA_OPTION_CHECKSUM))
200     options&= ~HA_OPTION_NULL_FIELDS;
201   if (flags & HA_CREATE_DELAY_KEY_WRITE)
202     options|= HA_OPTION_DELAY_KEY_WRITE;
203   if (flags & HA_CREATE_RELIES_ON_SQL_LAYER)
204     options|= HA_OPTION_RELIES_ON_SQL_LAYER;
205 
206   pack_bytes= (packed+7)/8;
207   if (pack_reclength != INT_MAX32)
208     pack_reclength+= reclength+packed +
209       MY_TEST(test_all_bits(options, HA_OPTION_CHECKSUM |
210                                      HA_OPTION_PACK_RECORD));
211   min_pack_length+= pack_bytes;
212 
213   if (!ci->data_file_length && ci->max_rows)
214   {
215     if (pack_reclength == INT_MAX32 ||
216              (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength)
217       ci->data_file_length= ~(ulonglong) 0;
218     else
219       ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength;
220   }
221   else if (!ci->max_rows)
222     ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
223 					 ((options & HA_OPTION_PACK_RECORD) ?
224 					  3 : 0)));
225 
226   if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
227     pointer=mi_get_pointer_length(ci->data_file_length,myisam_data_pointer_size);
228   else
229     pointer=mi_get_pointer_length(ci->max_rows,myisam_data_pointer_size);
230   if (!(max_rows=(ulonglong) ci->max_rows))
231     max_rows= ((((ulonglong) 1 << (pointer*8)) -1) / min_pack_length);
232 
233 
234   real_reclength=reclength;
235   if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
236   {
237     if (reclength <= pointer)
238       reclength=pointer+1;		/* reserve place for delete link */
239   }
240   else
241     reclength+= long_varchar_count;	/* We need space for varchar! */
242 
243   max_key_length=0; tot_length=0 ; key_segs=0;
244   fulltext_keys=0;
245   max_key_block_length=0;
246   share.state.rec_per_key_part=rec_per_key_part;
247   share.state.key_root=key_root;
248   share.state.key_del=key_del;
249   if (uniques)
250   {
251     max_key_block_length= myisam_block_size;
252     max_key_length=	  MI_UNIQUE_HASH_LENGTH + pointer;
253   }
254 
255   for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
256   {
257 
258     share.state.key_root[i]= HA_OFFSET_ERROR;
259     min_key_length_skip=length=real_length_diff=0;
260     key_length=pointer;
261     if (keydef->flag & HA_SPATIAL)
262     {
263 #ifdef HAVE_SPATIAL
264       /* BAR TODO to support 3D and more dimensions in the future */
265       uint sp_segs=SPDIMS*2;
266       keydef->flag=HA_SPATIAL;
267 
268       if (flags & HA_DONT_TOUCH_DATA)
269       {
270         /*
271            called by myisamchk - i.e. table structure was taken from
272            MYI file and SPATIAL key *does have* additional sp_segs keysegs.
273            keydef->seg here points right at the GEOMETRY segment,
274            so we only need to decrease keydef->keysegs.
275            (see recreate_table() in mi_check.c)
276         */
277         keydef->keysegs= 1;
278       }
279 
280       for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
281 	   j++, keyseg++)
282       {
283         if (keyseg->type != HA_KEYTYPE_BINARY &&
284 	    keyseg->type != HA_KEYTYPE_VARBINARY1 &&
285             keyseg->type != HA_KEYTYPE_VARBINARY2)
286         {
287           my_errno=HA_WRONG_CREATE_OPTION;
288           goto err_no_lock;
289         }
290       }
291       DBUG_ASSERT(keydef->keysegs == 1);
292       keydef->keysegs= sp_segs + 1;
293       key_length+=SPLEN*sp_segs;
294       length++;                              /* At least one length byte */
295       min_key_length_skip+=SPLEN*2*SPDIMS;
296 #else
297       my_errno= HA_ERR_UNSUPPORTED;
298       goto err_no_lock;
299 #endif /*HAVE_SPATIAL*/
300     }
301     else if (keydef->flag & HA_FULLTEXT)
302     {
303       keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
304       options|=HA_OPTION_PACK_KEYS;             /* Using packed keys */
305 
306       for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
307 	   j++, keyseg++)
308       {
309         if (keyseg->type != HA_KEYTYPE_TEXT &&
310 	    keyseg->type != HA_KEYTYPE_VARTEXT1 &&
311             keyseg->type != HA_KEYTYPE_VARTEXT2)
312         {
313           my_errno=HA_WRONG_CREATE_OPTION;
314           goto err_no_lock;
315         }
316         if (!(keyseg->flag & HA_BLOB_PART) &&
317 	    (keyseg->type == HA_KEYTYPE_VARTEXT1 ||
318              keyseg->type == HA_KEYTYPE_VARTEXT2))
319         {
320           /* Make a flag that this is a VARCHAR */
321           keyseg->flag|= HA_VAR_LENGTH_PART;
322           /* Store in bit_start number of bytes used to pack the length */
323           keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)?
324                               1 : 2);
325         }
326       }
327 
328       fulltext_keys++;
329       key_length+= HA_FT_MAXBYTELEN+HA_FT_WLEN;
330       length++;                              /* At least one length byte */
331       min_key_length_skip+=HA_FT_MAXBYTELEN;
332       real_length_diff=HA_FT_MAXBYTELEN-FT_MAX_WORD_LEN_FOR_SORT;
333     }
334     else
335     {
336       /* Test if prefix compression */
337       if (keydef->flag & HA_PACK_KEY)
338       {
339 	/* Can't use space_compression on number keys */
340 	if ((keydef->seg[0].flag & HA_SPACE_PACK) &&
341 	    keydef->seg[0].type == (int) HA_KEYTYPE_NUM)
342 	  keydef->seg[0].flag&= ~HA_SPACE_PACK;
343 
344 	/* Only use HA_PACK_KEY when first segment is a variable length key */
345 	if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
346 				     HA_VAR_LENGTH_PART)))
347 	{
348 	  /* pack relative to previous key */
349 	  keydef->flag&= ~HA_PACK_KEY;
350 	  keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
351 	}
352 	else
353 	{
354 	  keydef->seg[0].flag|=HA_PACK_KEY;	/* for easyer intern test */
355 	  keydef->flag|=HA_VAR_LENGTH_KEY;
356 	  options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
357 	}
358       }
359       if (keydef->flag & HA_BINARY_PACK_KEY)
360 	options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
361 
362       if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
363 	share.base.auto_key=i+1;
364       for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
365       {
366 	/* numbers are stored with high by first to make compression easier */
367 	switch (keyseg->type) {
368 	case HA_KEYTYPE_SHORT_INT:
369 	case HA_KEYTYPE_LONG_INT:
370 	case HA_KEYTYPE_FLOAT:
371 	case HA_KEYTYPE_DOUBLE:
372 	case HA_KEYTYPE_USHORT_INT:
373 	case HA_KEYTYPE_ULONG_INT:
374 	case HA_KEYTYPE_LONGLONG:
375 	case HA_KEYTYPE_ULONGLONG:
376 	case HA_KEYTYPE_INT24:
377 	case HA_KEYTYPE_UINT24:
378 	case HA_KEYTYPE_INT8:
379 	  keyseg->flag|= HA_SWAP_KEY;
380           break;
381         case HA_KEYTYPE_VARTEXT1:
382         case HA_KEYTYPE_VARTEXT2:
383         case HA_KEYTYPE_VARBINARY1:
384         case HA_KEYTYPE_VARBINARY2:
385           if (!(keyseg->flag & HA_BLOB_PART))
386           {
387             /* Make a flag that this is a VARCHAR */
388             keyseg->flag|= HA_VAR_LENGTH_PART;
389             /* Store in bit_start number of bytes used to pack the length */
390             keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
391                                  keyseg->type == HA_KEYTYPE_VARBINARY1) ?
392                                 1 : 2);
393           }
394           break;
395 	default:
396 	  break;
397 	}
398 	if (keyseg->flag & HA_SPACE_PACK)
399 	{
400           DBUG_ASSERT(!(keyseg->flag & HA_VAR_LENGTH_PART));
401 	  keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
402 	  options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
403 	  length++;				/* At least one length byte */
404 	  min_key_length_skip+=keyseg->length;
405 	  if (keyseg->length >= 255)
406 	  {					/* prefix may be 3 bytes */
407 	    min_key_length_skip+=2;
408 	    length+=2;
409 	  }
410 	}
411 	if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
412 	{
413           DBUG_ASSERT(!test_all_bits(keyseg->flag,
414                                     (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
415 	  keydef->flag|=HA_VAR_LENGTH_KEY;
416 	  length++;				/* At least one length byte */
417 	  options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
418 	  min_key_length_skip+=keyseg->length;
419 	  if (keyseg->length >= 255)
420 	  {					/* prefix may be 3 bytes */
421 	    min_key_length_skip+=2;
422 	    length+=2;
423 	  }
424 	}
425 	key_length+= keyseg->length;
426 	if (keyseg->null_bit)
427 	{
428 	  key_length++;
429 	  options|=HA_OPTION_PACK_KEYS;
430 	  keyseg->flag|=HA_NULL_PART;
431 	  keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
432 	}
433       }
434     } /* if HA_FULLTEXT */
435     key_segs+=keydef->keysegs;
436     if (keydef->keysegs > HA_MAX_KEY_SEG)
437     {
438       my_errno=HA_WRONG_CREATE_OPTION;
439       goto err_no_lock;
440     }
441     /*
442       key_segs may be 0 in the case when we only want to be able to
443       add on row into the table. This can happen with some DISTINCT queries
444       in MySQL
445     */
446     if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
447 	key_segs)
448       share.state.rec_per_key_part[key_segs-1]=1L;
449     length+=key_length;
450     /* Get block length for key, if defined by user */
451     block_length= (keydef->block_length ?
452                    my_round_up_to_next_power(keydef->block_length) :
453                    myisam_block_size);
454     block_length= MY_MAX(block_length, MI_MIN_KEY_BLOCK_LENGTH);
455     block_length= MY_MIN(block_length, MI_MAX_KEY_BLOCK_LENGTH);
456 
457     keydef->block_length= (uint16) MI_BLOCK_SIZE(length-real_length_diff,
458                                                  pointer,MI_MAX_KEYPTR_SIZE,
459                                                  block_length);
460     if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
461         length >= HA_MAX_KEY_BUFF)
462     {
463       my_errno=HA_WRONG_CREATE_OPTION;
464       goto err_no_lock;
465     }
466     set_if_bigger(max_key_block_length,keydef->block_length);
467     keydef->keylength= (uint16) key_length;
468     keydef->minlength= (uint16) (length-min_key_length_skip);
469     keydef->maxlength= (uint16) length;
470 
471     if (length > max_key_length)
472       max_key_length= length;
473     tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
474 				    (length*2)))*
475       (ulong) keydef->block_length;
476   }
477   for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
478     key_del[i]=HA_OFFSET_ERROR;
479 
480   unique_key_parts=0;
481   for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
482   {
483     uniquedef->key=keys+i;
484     unique_key_parts+=uniquedef->keysegs;
485     share.state.key_root[keys+i]= HA_OFFSET_ERROR;
486     tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/
487                          ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))*
488                          (ulong) myisam_block_size;
489   }
490   keys+=uniques;				/* Each unique has 1 key */
491   key_segs+=uniques;				/* Each unique has 1 key seg */
492 
493   base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
494 	    max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
495 	    MI_STATE_KEYBLOCK_SIZE+
496 	    key_segs*MI_STATE_KEYSEG_SIZE);
497   info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
498 			       keys * MI_KEYDEF_SIZE+
499 			       uniques * MI_UNIQUEDEF_SIZE +
500 			       (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
501 			       columns*MI_COLUMNDEF_SIZE);
502   DBUG_PRINT("info", ("info_length: %u", info_length));
503   /* There are only 16 bits for the total header length. */
504   if (info_length > 65535)
505   {
506     my_printf_error(HA_WRONG_CREATE_OPTION,
507                     "MyISAM table '%s' has too many columns and/or "
508                     "indexes and/or unique constraints.",
509                     MYF(0), name + dirname_length(name));
510     my_errno= HA_WRONG_CREATE_OPTION;
511     goto err_no_lock;
512   }
513 
514   bmove(share.state.header.file_version,(uchar*) myisam_file_magic,4);
515   ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
516 			HA_OPTION_COMPRESS_RECORD |
517 			HA_OPTION_TEMP_COMPRESS_RECORD: 0);
518   mi_int2store(share.state.header.options,ci->old_options);
519   mi_int2store(share.state.header.header_length,info_length);
520   mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
521   mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
522   mi_int2store(share.state.header.base_pos,base_pos);
523   share.state.header.language= (ci->language ?
524 				ci->language : default_charset_info->number);
525   share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
526 
527   share.state.dellink = HA_OFFSET_ERROR;
528   share.state.process=	(ulong) getpid();
529   share.state.unique=	(ulong) 0;
530   share.state.update_count=(ulong) 0;
531   share.state.version=	(ulong) time((time_t*) 0);
532   share.state.sortkey=  (ushort) ~0;
533   share.state.auto_increment=ci->auto_increment;
534   share.options=options;
535   share.base.rec_reflength=pointer;
536   /* Get estimate for index file length (this may be wrong for FT keys) */
537   tmp= (tot_length + max_key_block_length * keys *
538 	MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
539   /*
540     use maximum of key_file_length we calculated and key_file_length value we
541     got from MYI file header (see also myisampack.c:save_state)
542   */
543   share.base.key_reflength=
544     mi_get_pointer_length(MY_MAX(ci->key_file_length,tmp),3);
545   share.base.keys= share.state.header.keys= keys;
546   share.state.header.uniques= uniques;
547   share.state.header.fulltext_keys= fulltext_keys;
548   mi_int2store(share.state.header.key_parts,key_segs);
549   mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
550 
551   mi_set_all_keys_active(share.state.key_map, keys);
552   aligned_key_start= my_round_up_to_next_power(max_key_block_length ?
553                                                max_key_block_length :
554                                                myisam_block_size);
555 
556   share.base.keystart= share.state.state.key_file_length=
557     MY_ALIGN(info_length, aligned_key_start);
558   share.base.max_key_block_length=max_key_block_length;
559   share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
560   share.base.records=ci->max_rows;
561   share.base.reloc=  ci->reloc_rows;
562   share.base.reclength=real_reclength;
563   share.base.pack_reclength= reclength + MY_TEST(options & HA_OPTION_CHECKSUM);
564   share.base.max_pack_length=pack_reclength;
565   share.base.min_pack_length=min_pack_length;
566   share.base.pack_bits= pack_bytes;
567   share.base.fields=fields;
568   share.base.pack_fields=packed;
569 
570   /* max_data_file_length and max_key_file_length are recalculated on open */
571   if (options & HA_OPTION_TMP_TABLE)
572     share.base.max_data_file_length=(my_off_t) ci->data_file_length;
573 
574   share.base.min_block_length=
575     (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
576      ! share.base.blobs) ?
577     MY_MAX(share.base.pack_reclength,MI_MIN_BLOCK_LENGTH) :
578     MI_EXTEND_BLOCK_LENGTH;
579   if (! (flags & HA_DONT_TOUCH_DATA))
580     share.state.create_time= time((time_t*) 0);
581 
582   if (!internal_table)
583     mysql_mutex_lock(&THR_LOCK_myisam);
584 
585   /*
586     NOTE: For test_if_reopen() we need a real path name. Hence we need
587     MY_RETURN_REAL_PATH for every fn_format(filename, ...).
588   */
589   if (ci->index_file_name)
590   {
591     char *iext= strrchr(ci->index_file_name, '.');
592     int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
593     if (options & HA_OPTION_TMP_TABLE)
594     {
595       char *path;
596       /* chop off the table name, tempory tables use generated name */
597       if ((path= strrchr(ci->index_file_name, FN_LIBCHAR)))
598         *path= '\0';
599       fn_format(kfilename, name, ci->index_file_name, MI_NAME_IEXT,
600                 MY_REPLACE_DIR | MY_UNPACK_FILENAME |
601                 MY_RETURN_REAL_PATH | MY_APPEND_EXT);
602     }
603     else
604     {
605       fn_format(kfilename, ci->index_file_name, "", MI_NAME_IEXT,
606                 MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
607                 (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
608     }
609     fn_format(klinkname, name, "", MI_NAME_IEXT,
610               MY_UNPACK_FILENAME|MY_APPEND_EXT);
611     klinkname_ptr= klinkname;
612     /*
613       Don't create the table if the link or file exists to ensure that one
614       doesn't accidentally destroy another table.
615     */
616     create_flag=0;
617   }
618   else
619   {
620     char *iext= strrchr(name, '.');
621     int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
622     fn_format(kfilename, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME |
623               (internal_table ? 0 : MY_RETURN_REAL_PATH) |
624               (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
625     /* Replace the current file */
626     create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
627   }
628 
629   /*
630     If a MRG_MyISAM table is in use, the mapped MyISAM tables are open,
631     but no entry is made in the table cache for them.
632     A TRUNCATE command checks for the table in the cache only and could
633     be fooled to believe, the table is not open.
634     Pull the emergency brake in this situation. (Bug #8306)
635 
636     NOTE: The filename is compared against unique_file_name of every
637     open table. Hence we need a real path here.
638   */
639   if (!internal_table && test_if_reopen(kfilename))
640   {
641     my_printf_error(HA_ERR_TABLE_EXIST, "MyISAM table '%s' is in use "
642                     "(most likely by a MERGE table). Try FLUSH TABLES.",
643                     MYF(0), name + dirname_length(name));
644     my_errno= HA_ERR_TABLE_EXIST;
645     goto err;
646   }
647 
648   if ((file= mysql_file_create_with_symlink(mi_key_file_kfile,
649                                             klinkname_ptr, kfilename, 0,
650                                             create_mode,
651                                             MYF(MY_WME | create_flag))) < 0)
652     goto err;
653   errpos=1;
654 
655   if (!(flags & HA_DONT_TOUCH_DATA))
656   {
657     {
658       if (ci->data_file_name)
659       {
660         char *dext= strrchr(ci->data_file_name, '.');
661         int have_dext= dext && !strcmp(dext, MI_NAME_DEXT);
662 
663         if (options & HA_OPTION_TMP_TABLE)
664         {
665           char *path;
666           /* chop off the table name, tempory tables use generated name */
667           if ((path= strrchr(ci->data_file_name, FN_LIBCHAR)))
668             *path= '\0';
669           fn_format(dfilename, name, ci->data_file_name, MI_NAME_DEXT,
670                     MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
671         }
672         else
673         {
674           fn_format(dfilename, ci->data_file_name, "", MI_NAME_DEXT,
675                     MY_UNPACK_FILENAME |
676                     (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
677         }
678 
679 	fn_format(dlinkname, name, "",MI_NAME_DEXT,
680 	          MY_UNPACK_FILENAME | MY_APPEND_EXT);
681 	dlinkname_ptr= dlinkname;
682 	create_flag=0;
683       }
684       else
685       {
686 	fn_format(dfilename,name,"", MI_NAME_DEXT,
687 	          MY_UNPACK_FILENAME | MY_APPEND_EXT);
688 	dlinkname_ptr= 0;
689         create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
690       }
691       if ((dfile=
692            mysql_file_create_with_symlink(mi_key_file_dfile,
693                                           dlinkname_ptr, dfilename, 0,
694                                           create_mode,
695                                           MYF(MY_WME | create_flag))) < 0)
696 	goto err;
697     }
698     errpos=3;
699   }
700 
701   DBUG_PRINT("info", ("write state info and base info"));
702   if (mi_state_info_write(file, &share.state, 2) ||
703       mi_base_info_write(file, &share.base))
704     goto err;
705 #ifndef DBUG_OFF
706   if ((uint) mysql_file_tell(file, MYF(0)) != base_pos + MI_BASE_INFO_SIZE)
707   {
708     uint pos=(uint) mysql_file_tell(file, MYF(0));
709     DBUG_PRINT("warning",("base_length: %d  != used_length: %d",
710 			  base_pos+ MI_BASE_INFO_SIZE, pos));
711   }
712 #endif
713 
714   /* Write key and keyseg definitions
715 
716     TODO: update key and keyseg definitions for inplace alter (grep sql layer by
717           MDEV-25803). Do the same for Aria.
718   */
719   DBUG_PRINT("info", ("write key and keyseg definitions"));
720   for (i=0 ; i < share.base.keys - uniques; i++)
721   {
722     uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0;
723 
724     if (mi_keydef_write(file, &keydefs[i]))
725       goto err;
726     for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
727       if (mi_keyseg_write(file, &keydefs[i].seg[j]))
728        goto err;
729 #ifdef HAVE_SPATIAL
730     for (j=0 ; j < sp_segs ; j++)
731     {
732       HA_KEYSEG sseg;
733       sseg.type=SPTYPE;
734       sseg.language= 7;                         /* Binary */
735       sseg.null_bit=0;
736       sseg.bit_start=0;
737       sseg.bit_length= 0;
738       sseg.bit_pos= 0;
739       sseg.length=SPLEN;
740       sseg.null_pos=0;
741       sseg.start=j*SPLEN;
742       sseg.flag= HA_SWAP_KEY;
743       if (mi_keyseg_write(file, &sseg))
744         goto err;
745     }
746 #endif
747   }
748   /* Create extra keys for unique definitions */
749   offset= real_reclength - uniques * MI_UNIQUE_HASH_LENGTH;
750   bzero((char*) &tmp_keydef,sizeof(tmp_keydef));
751   bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg));
752   for (i=0; i < uniques ; i++)
753   {
754     tmp_keydef.keysegs=1;
755     tmp_keydef.flag=		HA_UNIQUE_CHECK;
756     tmp_keydef.block_length=	(uint16)myisam_block_size;
757     tmp_keydef.keylength=	MI_UNIQUE_HASH_LENGTH + pointer;
758     tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
759     tmp_keyseg.type=		MI_UNIQUE_HASH_TYPE;
760     tmp_keyseg.length=		MI_UNIQUE_HASH_LENGTH;
761     tmp_keyseg.start=		offset;
762     offset+=			MI_UNIQUE_HASH_LENGTH;
763     if (mi_keydef_write(file,&tmp_keydef) ||
764 	mi_keyseg_write(file,(&tmp_keyseg)))
765       goto err;
766   }
767 
768   /* Save unique definition */
769   DBUG_PRINT("info", ("write unique definitions"));
770   for (i=0 ; i < share.state.header.uniques ; i++)
771   {
772     HA_KEYSEG *keyseg_end;
773     keyseg= uniquedefs[i].seg;
774     if (mi_uniquedef_write(file, &uniquedefs[i]))
775       goto err;
776     for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
777          keyseg < keyseg_end;
778          keyseg++)
779     {
780       switch (keyseg->type) {
781       case HA_KEYTYPE_VARTEXT1:
782       case HA_KEYTYPE_VARTEXT2:
783       case HA_KEYTYPE_VARBINARY1:
784       case HA_KEYTYPE_VARBINARY2:
785         if (!(keyseg->flag & HA_BLOB_PART))
786         {
787           keyseg->flag|= HA_VAR_LENGTH_PART;
788           keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
789                                keyseg->type == HA_KEYTYPE_VARBINARY1) ?
790                               1 : 2);
791         }
792         break;
793       default:
794         break;
795       }
796       if (mi_keyseg_write(file, keyseg))
797 	goto err;
798     }
799   }
800   DBUG_PRINT("info", ("write field definitions"));
801   for (i=0 ; i < share.base.fields ; i++)
802     if (mi_recinfo_write(file, &recinfo[i]))
803       goto err;
804 
805 #ifndef DBUG_OFF
806   if ((uint) mysql_file_tell(file, MYF(0)) != info_length)
807   {
808     uint pos= (uint) mysql_file_tell(file, MYF(0));
809     DBUG_PRINT("warning",("info_length: %d  != used_length: %d",
810 			  info_length, pos));
811   }
812 #endif
813 
814 	/* Enlarge files */
815   DBUG_PRINT("info", ("enlarge to keystart: %lu", (ulong) share.base.keystart));
816   if (mysql_file_chsize(file, (ulong) share.base.keystart, 0, MYF(0)))
817     goto err;
818 
819   if (! (flags & HA_DONT_TOUCH_DATA))
820   {
821 #ifdef USE_RELOC
822     if (mysql_file_chsize(dfile, share.base.min_pack_length*ci->reloc_rows,
823                           0, MYF(0)))
824       goto err;
825 #endif
826     errpos=2;
827     if (mysql_file_close(dfile, MYF(0)))
828       goto err;
829   }
830   errpos=0;
831   if (!internal_table)
832     mysql_mutex_unlock(&THR_LOCK_myisam);
833   res= 0;
834   if (mysql_file_close(file, MYF(0)))
835     res= my_errno;
836   my_free(rec_per_key_part);
837   DBUG_RETURN(res);
838 
839 err:
840   if (!internal_table)
841     mysql_mutex_unlock(&THR_LOCK_myisam);
842 
843 err_no_lock:
844   save_errno=my_errno;
845   switch (errpos) {
846   case 3:
847     (void) mysql_file_close(dfile, MYF(0));
848     /* fall through */
849   case 2:
850     if (! (flags & HA_DONT_TOUCH_DATA))
851     {
852       mysql_file_delete(mi_key_file_dfile, dfilename, MYF(0));
853       if (dlinkname_ptr)
854         mysql_file_delete(mi_key_file_dfile, dlinkname_ptr, MYF(0));
855     }
856     /* fall through */
857   case 1:
858     (void) mysql_file_close(file, MYF(0));
859     if (! (flags & HA_DONT_TOUCH_DATA))
860     {
861       mysql_file_delete(mi_key_file_kfile, kfilename, MYF(0));
862       if (klinkname_ptr)
863         mysql_file_delete(mi_key_file_kfile, klinkname_ptr, MYF(0));
864     }
865   }
866   my_free(rec_per_key_part);
867   DBUG_RETURN(my_errno=save_errno);		/* return the fatal errno */
868 }
869 
870 
mi_get_pointer_length(ulonglong file_length,uint def)871 uint mi_get_pointer_length(ulonglong file_length, uint def)
872 {
873   DBUG_ASSERT(def >= 2 && def <= 7);
874   if (file_length)				/* If not default */
875   {
876 #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
877     if (file_length >= 1ULL << 56)
878       def=8;
879     else
880 #endif
881     if (file_length >= 1ULL << 48)
882       def=7;
883     else if (file_length >= 1ULL << 40)
884       def=6;
885     else if (file_length >= 1ULL << 32)
886       def=5;
887     else if (file_length >= 1ULL << 24)
888       def=4;
889     else if (file_length >= 1ULL << 16)
890       def=3;
891     else
892       def=2;
893   }
894   return def;
895 }
896