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