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