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