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