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