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-1301 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 | |
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; |
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; |
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 accidently 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, |
623 | MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | |
624 | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); |
625 | klinkname_ptr= 0; |
626 | /* Replace the current file */ |
627 | create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; |
628 | } |
629 | |
630 | /* |
631 | If a MRG_MyISAM table is in use, the mapped MyISAM tables are open, |
632 | but no entry is made in the table cache for them. |
633 | A TRUNCATE command checks for the table in the cache only and could |
634 | be fooled to believe, the table is not open. |
635 | Pull the emergency brake in this situation. (Bug #8306) |
636 | |
637 | NOTE: The filename is compared against unique_file_name of every |
638 | open table. Hence we need a real path here. |
639 | */ |
640 | if (!internal_table && test_if_reopen(kfilename)) |
641 | { |
642 | my_printf_error(HA_ERR_TABLE_EXIST, "MyISAM table '%s' is in use " |
643 | "(most likely by a MERGE table). Try FLUSH TABLES." , |
644 | MYF(0), name + dirname_length(name)); |
645 | my_errno= HA_ERR_TABLE_EXIST; |
646 | goto err; |
647 | } |
648 | |
649 | if ((file= mysql_file_create_with_symlink(mi_key_file_kfile, |
650 | klinkname_ptr, kfilename, 0, |
651 | create_mode, |
652 | MYF(MY_WME | create_flag))) < 0) |
653 | goto err; |
654 | errpos=1; |
655 | |
656 | if (!(flags & HA_DONT_TOUCH_DATA)) |
657 | { |
658 | { |
659 | if (ci->data_file_name) |
660 | { |
661 | char *dext= strrchr(ci->data_file_name, '.'); |
662 | int have_dext= dext && !strcmp(dext, MI_NAME_DEXT); |
663 | |
664 | if (options & HA_OPTION_TMP_TABLE) |
665 | { |
666 | char *path; |
667 | /* chop off the table name, tempory tables use generated name */ |
668 | if ((path= strrchr(ci->data_file_name, FN_LIBCHAR))) |
669 | *path= '\0'; |
670 | fn_format(dfilename, name, ci->data_file_name, MI_NAME_DEXT, |
671 | MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT); |
672 | } |
673 | else |
674 | { |
675 | fn_format(dfilename, ci->data_file_name, "" , MI_NAME_DEXT, |
676 | MY_UNPACK_FILENAME | |
677 | (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT)); |
678 | } |
679 | |
680 | fn_format(dlinkname, name, "" ,MI_NAME_DEXT, |
681 | MY_UNPACK_FILENAME | MY_APPEND_EXT); |
682 | dlinkname_ptr= dlinkname; |
683 | create_flag=0; |
684 | } |
685 | else |
686 | { |
687 | fn_format(dfilename,name,"" , MI_NAME_DEXT, |
688 | MY_UNPACK_FILENAME | MY_APPEND_EXT); |
689 | dlinkname_ptr= 0; |
690 | create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; |
691 | } |
692 | if ((dfile= |
693 | mysql_file_create_with_symlink(mi_key_file_dfile, |
694 | dlinkname_ptr, dfilename, 0, |
695 | create_mode, |
696 | MYF(MY_WME | create_flag))) < 0) |
697 | goto err; |
698 | } |
699 | errpos=3; |
700 | } |
701 | |
702 | DBUG_PRINT("info" , ("write state info and base info" )); |
703 | if (mi_state_info_write(file, &share.state, 2) || |
704 | mi_base_info_write(file, &share.base)) |
705 | goto err; |
706 | #ifndef DBUG_OFF |
707 | if ((uint) mysql_file_tell(file, MYF(0)) != base_pos + MI_BASE_INFO_SIZE) |
708 | { |
709 | uint pos=(uint) mysql_file_tell(file, MYF(0)); |
710 | DBUG_PRINT("warning" ,("base_length: %d != used_length: %d" , |
711 | base_pos+ MI_BASE_INFO_SIZE, pos)); |
712 | } |
713 | #endif |
714 | |
715 | /* Write key and keyseg definitions */ |
716 | DBUG_PRINT("info" , ("write key and keyseg definitions" )); |
717 | for (i=0 ; i < share.base.keys - uniques; i++) |
718 | { |
719 | uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0; |
720 | |
721 | if (mi_keydef_write(file, &keydefs[i])) |
722 | goto err; |
723 | for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++) |
724 | if (mi_keyseg_write(file, &keydefs[i].seg[j])) |
725 | goto err; |
726 | #ifdef HAVE_SPATIAL |
727 | for (j=0 ; j < sp_segs ; j++) |
728 | { |
729 | HA_KEYSEG sseg; |
730 | sseg.type=SPTYPE; |
731 | sseg.language= 7; /* Binary */ |
732 | sseg.null_bit=0; |
733 | sseg.bit_start=0; |
734 | sseg.bit_length= 0; |
735 | sseg.bit_pos= 0; |
736 | sseg.length=SPLEN; |
737 | sseg.null_pos=0; |
738 | sseg.start=j*SPLEN; |
739 | sseg.flag= HA_SWAP_KEY; |
740 | if (mi_keyseg_write(file, &sseg)) |
741 | goto err; |
742 | } |
743 | #endif |
744 | } |
745 | /* Create extra keys for unique definitions */ |
746 | offset= real_reclength - uniques * MI_UNIQUE_HASH_LENGTH; |
747 | bzero((char*) &tmp_keydef,sizeof(tmp_keydef)); |
748 | bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg)); |
749 | for (i=0; i < uniques ; i++) |
750 | { |
751 | tmp_keydef.keysegs=1; |
752 | tmp_keydef.flag= HA_UNIQUE_CHECK; |
753 | tmp_keydef.block_length= (uint16)myisam_block_size; |
754 | tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer; |
755 | tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength; |
756 | tmp_keyseg.type= MI_UNIQUE_HASH_TYPE; |
757 | tmp_keyseg.length= MI_UNIQUE_HASH_LENGTH; |
758 | tmp_keyseg.start= offset; |
759 | offset+= MI_UNIQUE_HASH_LENGTH; |
760 | if (mi_keydef_write(file,&tmp_keydef) || |
761 | mi_keyseg_write(file,(&tmp_keyseg))) |
762 | goto err; |
763 | } |
764 | |
765 | /* Save unique definition */ |
766 | DBUG_PRINT("info" , ("write unique definitions" )); |
767 | for (i=0 ; i < share.state.header.uniques ; i++) |
768 | { |
769 | HA_KEYSEG *keyseg_end; |
770 | keyseg= uniquedefs[i].seg; |
771 | if (mi_uniquedef_write(file, &uniquedefs[i])) |
772 | goto err; |
773 | for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs; |
774 | keyseg < keyseg_end; |
775 | keyseg++) |
776 | { |
777 | switch (keyseg->type) { |
778 | case HA_KEYTYPE_VARTEXT1: |
779 | case HA_KEYTYPE_VARTEXT2: |
780 | case HA_KEYTYPE_VARBINARY1: |
781 | case HA_KEYTYPE_VARBINARY2: |
782 | if (!(keyseg->flag & HA_BLOB_PART)) |
783 | { |
784 | keyseg->flag|= HA_VAR_LENGTH_PART; |
785 | keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 || |
786 | keyseg->type == HA_KEYTYPE_VARBINARY1) ? |
787 | 1 : 2); |
788 | } |
789 | break; |
790 | default: |
791 | break; |
792 | } |
793 | if (mi_keyseg_write(file, keyseg)) |
794 | goto err; |
795 | } |
796 | } |
797 | DBUG_PRINT("info" , ("write field definitions" )); |
798 | for (i=0 ; i < share.base.fields ; i++) |
799 | if (mi_recinfo_write(file, &recinfo[i])) |
800 | goto err; |
801 | |
802 | #ifndef DBUG_OFF |
803 | if ((uint) mysql_file_tell(file, MYF(0)) != info_length) |
804 | { |
805 | uint pos= (uint) mysql_file_tell(file, MYF(0)); |
806 | DBUG_PRINT("warning" ,("info_length: %d != used_length: %d" , |
807 | info_length, pos)); |
808 | } |
809 | #endif |
810 | |
811 | /* Enlarge files */ |
812 | DBUG_PRINT("info" , ("enlarge to keystart: %lu" , (ulong) share.base.keystart)); |
813 | if (mysql_file_chsize(file, (ulong) share.base.keystart, 0, MYF(0))) |
814 | goto err; |
815 | |
816 | if (! (flags & HA_DONT_TOUCH_DATA)) |
817 | { |
818 | #ifdef USE_RELOC |
819 | if (mysql_file_chsize(dfile, share.base.min_pack_length*ci->reloc_rows, |
820 | 0, MYF(0))) |
821 | goto err; |
822 | #endif |
823 | errpos=2; |
824 | if (mysql_file_close(dfile, MYF(0))) |
825 | goto err; |
826 | } |
827 | errpos=0; |
828 | if (!internal_table) |
829 | mysql_mutex_unlock(&THR_LOCK_myisam); |
830 | res= 0; |
831 | if (mysql_file_close(file, MYF(0))) |
832 | res= my_errno; |
833 | my_free(rec_per_key_part); |
834 | DBUG_RETURN(res); |
835 | |
836 | err: |
837 | if (!internal_table) |
838 | mysql_mutex_unlock(&THR_LOCK_myisam); |
839 | |
840 | err_no_lock: |
841 | save_errno=my_errno; |
842 | switch (errpos) { |
843 | case 3: |
844 | (void) mysql_file_close(dfile, MYF(0)); |
845 | /* fall through */ |
846 | case 2: |
847 | if (! (flags & HA_DONT_TOUCH_DATA)) |
848 | { |
849 | mysql_file_delete(mi_key_file_dfile, dfilename, MYF(0)); |
850 | if (dlinkname_ptr) |
851 | mysql_file_delete(mi_key_file_dfile, dlinkname_ptr, MYF(0)); |
852 | } |
853 | /* fall through */ |
854 | case 1: |
855 | (void) mysql_file_close(file, MYF(0)); |
856 | if (! (flags & HA_DONT_TOUCH_DATA)) |
857 | { |
858 | mysql_file_delete(mi_key_file_kfile, kfilename, MYF(0)); |
859 | if (klinkname_ptr) |
860 | mysql_file_delete(mi_key_file_kfile, klinkname_ptr, MYF(0)); |
861 | } |
862 | } |
863 | my_free(rec_per_key_part); |
864 | DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */ |
865 | } |
866 | |
867 | |
868 | uint mi_get_pointer_length(ulonglong file_length, uint def) |
869 | { |
870 | DBUG_ASSERT(def >= 2 && def <= 7); |
871 | if (file_length) /* If not default */ |
872 | { |
873 | #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS |
874 | if (file_length >= 1ULL << 56) |
875 | def=8; |
876 | else |
877 | #endif |
878 | if (file_length >= 1ULL << 48) |
879 | def=7; |
880 | else if (file_length >= 1ULL << 40) |
881 | def=6; |
882 | else if (file_length >= 1ULL << 32) |
883 | def=5; |
884 | else if (file_length >= 1ULL << 24) |
885 | def=4; |
886 | else if (file_length >= 1ULL << 16) |
887 | def=3; |
888 | else |
889 | def=2; |
890 | } |
891 | return def; |
892 | } |
893 | |