1 | /* |
2 | Copyright (c) 2000, 2011, 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 as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
16 | |
17 | /* |
18 | open a isam-database |
19 | |
20 | Internal temporary tables |
21 | ------------------------- |
22 | Since only single instance of internal temporary table is required by |
23 | optimizer, such tables are not registered on myisam_open_list. In effect |
24 | it means (a) THR_LOCK_myisam is not held while such table is being created, |
25 | opened or closed; (b) no iteration through myisam_open_list while opening a |
26 | table. This optimization gives nice scalability benefit in concurrent |
27 | environment. MEMORY internal temporary tables are optimized similarly. |
28 | */ |
29 | |
30 | #include "fulltext.h" |
31 | #include "sp_defs.h" |
32 | #include "rt_index.h" |
33 | #include <m_ctype.h> |
34 | #include <mysql_version.h> |
35 | |
36 | #ifdef __WIN__ |
37 | #include <fcntl.h> |
38 | #endif |
39 | |
40 | static void setup_key_functions(MI_KEYDEF *keyinfo); |
41 | #define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \ |
42 | pos+=size;} |
43 | |
44 | |
45 | #define disk_pos_assert(pos, end_pos) \ |
46 | if (pos > end_pos) \ |
47 | { \ |
48 | my_errno=HA_ERR_CRASHED; \ |
49 | goto err; \ |
50 | } |
51 | |
52 | |
53 | /****************************************************************************** |
54 | ** Return the shared struct if the table is already open. |
55 | ** In MySQL the server will handle version issues. |
56 | ******************************************************************************/ |
57 | |
58 | MI_INFO *test_if_reopen(char *filename) |
59 | { |
60 | LIST *pos; |
61 | |
62 | for (pos=myisam_open_list ; pos ; pos=pos->next) |
63 | { |
64 | MI_INFO *info=(MI_INFO*) pos->data; |
65 | MYISAM_SHARE *share=info->s; |
66 | DBUG_ASSERT(strcmp(share->unique_file_name,filename) || |
67 | share->last_version); |
68 | if (!strcmp(share->unique_file_name,filename) && share->last_version) |
69 | return info; |
70 | } |
71 | return 0; |
72 | } |
73 | |
74 | |
75 | /****************************************************************************** |
76 | open a MyISAM database. |
77 | See my_base.h for the handle_locking argument |
78 | if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table |
79 | is marked crashed or if we are not using locking and the table doesn't |
80 | have an open count of 0. |
81 | ******************************************************************************/ |
82 | |
83 | MI_INFO *mi_open(const char *name, int mode, uint open_flags) |
84 | { |
85 | int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err; |
86 | uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, |
87 | key_parts,unique_key_parts,base_key_parts,fulltext_keys,uniques; |
88 | uint internal_table= open_flags & HA_OPEN_INTERNAL_TABLE; |
89 | char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN], |
90 | data_name[FN_REFLEN]; |
91 | uchar *UNINIT_VAR(disk_cache), *disk_pos, *end_pos; |
92 | MI_INFO info,*UNINIT_VAR(m_info),*old_info= NULL; |
93 | MYISAM_SHARE share_buff,*share; |
94 | ulong *rec_per_key_part= 0; |
95 | my_off_t *key_root, *key_del; |
96 | ulonglong max_key_file_length, max_data_file_length; |
97 | DBUG_ENTER("mi_open" ); |
98 | |
99 | kfile= -1; |
100 | lock_error=1; |
101 | errpos=0; |
102 | head_length=sizeof(share_buff.state.header); |
103 | bzero((uchar*) &info,sizeof(info)); |
104 | |
105 | realpath_err= my_realpath(name_buff, |
106 | fn_format(org_name,name,"" ,MI_NAME_IEXT,4),MYF(0)); |
107 | if (realpath_err > 0) /* File not found, no point in looking further. */ |
108 | { |
109 | DBUG_RETURN(NULL); |
110 | } |
111 | |
112 | if (my_is_symlink(org_name) && |
113 | (realpath_err || mysys_test_invalid_symlink(name_buff))) |
114 | { |
115 | my_errno= HA_WRONG_CREATE_OPTION; |
116 | DBUG_RETURN (NULL); |
117 | } |
118 | |
119 | if (!internal_table) |
120 | { |
121 | mysql_mutex_lock(&THR_LOCK_myisam); |
122 | old_info= test_if_reopen(name_buff); |
123 | } |
124 | |
125 | if (!old_info) |
126 | { |
127 | share= &share_buff; |
128 | bzero((uchar*) &share_buff,sizeof(share_buff)); |
129 | share_buff.key_cache= multi_key_cache_search((uchar*) name_buff, |
130 | (uint)strlen(name_buff), |
131 | dflt_key_cache); |
132 | |
133 | DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open" , |
134 | if (strstr(name, "crashed" )) |
135 | { |
136 | my_errno= HA_ERR_CRASHED; |
137 | goto err; |
138 | }); |
139 | |
140 | DEBUG_SYNC_C("mi_open_kfile" ); |
141 | if ((kfile= mysql_file_open(mi_key_file_kfile, name_buff, |
142 | (open_mode= O_RDWR) | O_SHARE | O_NOFOLLOW, |
143 | MYF(MY_NOSYMLINKS))) < 0) |
144 | { |
145 | if ((errno != EROFS && errno != EACCES) || |
146 | mode != O_RDONLY || |
147 | (kfile= mysql_file_open(mi_key_file_kfile, name_buff, |
148 | (open_mode= O_RDONLY) | O_SHARE| O_NOFOLLOW, |
149 | MYF(MY_NOSYMLINKS))) < 0) |
150 | goto err; |
151 | } |
152 | share->mode=open_mode; |
153 | errpos=1; |
154 | if (mysql_file_read(kfile, (uchar*)&share->state.header, head_length, |
155 | MYF(MY_NABP))) |
156 | { |
157 | my_errno= HA_ERR_NOT_A_TABLE; |
158 | goto err; |
159 | } |
160 | if (bcmp(share->state.header.file_version, myisam_file_magic, 4)) |
161 | { |
162 | DBUG_PRINT("error" ,("Wrong header in %s" ,name_buff)); |
163 | DBUG_DUMP("error_dump" , share->state.header.file_version, |
164 | (size_t) head_length); |
165 | my_errno=HA_ERR_NOT_A_TABLE; |
166 | goto err; |
167 | } |
168 | share->options= mi_uint2korr(share->state.header.options); |
169 | if (share->options & |
170 | ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS | |
171 | HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA | |
172 | HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM | |
173 | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE | |
174 | HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS)) |
175 | { |
176 | DBUG_PRINT("error" ,("wrong options: 0x%lx" , share->options)); |
177 | my_errno=HA_ERR_OLD_FILE; |
178 | goto err; |
179 | } |
180 | if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) && |
181 | ! (open_flags & HA_OPEN_FROM_SQL_LAYER)) |
182 | { |
183 | DBUG_PRINT("error" , ("table cannot be openned from non-sql layer" )); |
184 | my_errno= HA_ERR_UNSUPPORTED; |
185 | goto err; |
186 | } |
187 | /* Don't call realpath() if the name can't be a link */ |
188 | if (!strcmp(name_buff, org_name) || |
189 | my_readlink(index_name, org_name, MYF(0)) == -1) |
190 | (void) strmov(index_name, org_name); |
191 | *strrchr(org_name, '.')= '\0'; |
192 | (void) fn_format(data_name,org_name,"" ,MI_NAME_DEXT, |
193 | MY_APPEND_EXT|MY_UNPACK_FILENAME); |
194 | if (my_is_symlink(data_name)) |
195 | { |
196 | if (my_realpath(data_name, data_name, MYF(0))) |
197 | goto err; |
198 | if (mysys_test_invalid_symlink(data_name)) |
199 | { |
200 | my_errno= HA_WRONG_CREATE_OPTION; |
201 | goto err; |
202 | } |
203 | share->mode|= O_NOFOLLOW; /* all symlinks are resolved by realpath() */ |
204 | } |
205 | |
206 | info_length=mi_uint2korr(share->state.header.header_length); |
207 | base_pos=mi_uint2korr(share->state.header.base_pos); |
208 | if (!(disk_cache= (uchar*) my_alloca(info_length+128))) |
209 | { |
210 | my_errno=ENOMEM; |
211 | goto err; |
212 | } |
213 | end_pos=disk_cache+info_length; |
214 | errpos=2; |
215 | |
216 | mysql_file_seek(kfile, 0L, MY_SEEK_SET, MYF(0)); |
217 | if (!(open_flags & HA_OPEN_TMP_TABLE)) |
218 | { |
219 | if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF, |
220 | MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ? |
221 | 0 : MY_SHORT_WAIT))) && |
222 | !(open_flags & HA_OPEN_IGNORE_IF_LOCKED)) |
223 | goto err; |
224 | } |
225 | errpos=3; |
226 | if (mysql_file_read(kfile, disk_cache, info_length, MYF(MY_NABP))) |
227 | { |
228 | my_errno=HA_ERR_CRASHED; |
229 | goto err; |
230 | } |
231 | len=mi_uint2korr(share->state.header.state_info_length); |
232 | keys= (uint) share->state.header.keys; |
233 | uniques= (uint) share->state.header.uniques; |
234 | fulltext_keys= (uint) share->state.header.fulltext_keys; |
235 | base_key_parts= key_parts= mi_uint2korr(share->state.header.key_parts); |
236 | unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts); |
237 | if (len != MI_STATE_INFO_SIZE) |
238 | { |
239 | DBUG_PRINT("warning" , |
240 | ("saved_state_info_length: %d state_info_length: %d" , |
241 | len,MI_STATE_INFO_SIZE)); |
242 | } |
243 | share->state_diff_length=len-MI_STATE_INFO_SIZE; |
244 | |
245 | if (!mi_state_info_read(disk_cache, &share->state)) |
246 | goto err; |
247 | rec_per_key_part= share->state.rec_per_key_part; |
248 | key_root= share->state.key_root; |
249 | key_del= share->state.key_del; |
250 | |
251 | len= mi_uint2korr(share->state.header.base_info_length); |
252 | if (len != MI_BASE_INFO_SIZE) |
253 | { |
254 | DBUG_PRINT("warning" ,("saved_base_info_length: %d base_info_length: %d" , |
255 | len,MI_BASE_INFO_SIZE)); |
256 | } |
257 | disk_pos= mi_n_base_info_read(disk_cache + base_pos, &share->base); |
258 | share->state.state_length=base_pos; |
259 | |
260 | if (!(open_flags & HA_OPEN_FOR_REPAIR) && |
261 | ((share->state.changed & STATE_CRASHED) || |
262 | ((open_flags & HA_OPEN_ABORT_IF_CRASHED) && |
263 | (my_disable_locking && share->state.open_count)))) |
264 | { |
265 | DBUG_PRINT("error" ,("Table is marked as crashed. open_flags: %u " |
266 | "changed: %u open_count: %u !locking: %d" , |
267 | open_flags, share->state.changed, |
268 | share->state.open_count, my_disable_locking)); |
269 | my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ? |
270 | HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE); |
271 | goto err; |
272 | } |
273 | |
274 | /* sanity check */ |
275 | if (share->base.keystart > 65535 || |
276 | share->base.rec_reflength > 8 || share->base.key_reflength > 7) |
277 | { |
278 | my_errno=HA_ERR_CRASHED; |
279 | goto err; |
280 | } |
281 | |
282 | key_parts+=fulltext_keys*FT_SEGS; |
283 | if (share->base.max_key_length > HA_MAX_KEY_BUFF || keys > MI_MAX_KEY || |
284 | key_parts > MI_MAX_KEY * HA_MAX_KEY_SEG) |
285 | { |
286 | DBUG_PRINT("error" ,("Wrong key info: Max_key_length: %d keys: %d key_parts: %d" , share->base.max_key_length, keys, key_parts)); |
287 | my_errno=HA_ERR_UNSUPPORTED; |
288 | goto err; |
289 | } |
290 | |
291 | /* Correct max_file_length based on length of sizeof(off_t) */ |
292 | max_data_file_length= |
293 | (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? |
294 | (((ulonglong) 1 << (share->base.rec_reflength*8))-1) : |
295 | (mi_safe_mul(share->base.pack_reclength, |
296 | (ulonglong) 1 << (share->base.rec_reflength*8))-1); |
297 | max_key_file_length= |
298 | mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH, |
299 | ((ulonglong) 1 << (share->base.key_reflength*8))-1); |
300 | #if SIZEOF_OFF_T == 4 |
301 | set_if_smaller(max_data_file_length, INT_MAX32); |
302 | set_if_smaller(max_key_file_length, INT_MAX32); |
303 | #endif |
304 | share->base.max_data_file_length=(my_off_t) max_data_file_length; |
305 | share->base.max_key_file_length=(my_off_t) max_key_file_length; |
306 | |
307 | if (share->options & HA_OPTION_COMPRESS_RECORD) |
308 | share->base.max_key_length+=2; /* For safety */ |
309 | |
310 | /* Add space for node pointer */ |
311 | share->base.max_key_length+= share->base.key_reflength; |
312 | |
313 | if (!my_multi_malloc(MY_WME, |
314 | &share,sizeof(*share), |
315 | &share->state.rec_per_key_part, |
316 | sizeof(long)*base_key_parts, |
317 | &share->keyinfo,keys*sizeof(MI_KEYDEF), |
318 | &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF), |
319 | &share->keyparts, |
320 | (key_parts+unique_key_parts+keys+uniques) * |
321 | sizeof(HA_KEYSEG), |
322 | &share->rec, |
323 | (share->base.fields+1)*sizeof(MI_COLUMNDEF), |
324 | &share->blobs,sizeof(MI_BLOB)*share->base.blobs, |
325 | &share->unique_file_name,strlen(name_buff)+1, |
326 | &share->index_file_name,strlen(index_name)+1, |
327 | &share->data_file_name,strlen(data_name)+1, |
328 | &share->state.key_root,keys*sizeof(my_off_t), |
329 | &share->state.key_del, |
330 | (share->state.header.max_block_size_index*sizeof(my_off_t)), |
331 | &share->key_root_lock, sizeof(mysql_rwlock_t)*keys, |
332 | &share->mmap_lock, sizeof(mysql_rwlock_t), |
333 | NullS)) |
334 | goto err; |
335 | errpos=4; |
336 | *share=share_buff; |
337 | memcpy((char*) share->state.rec_per_key_part, |
338 | (char*) rec_per_key_part, sizeof(long)*base_key_parts); |
339 | memcpy((char*) share->state.key_root, |
340 | (char*) key_root, sizeof(my_off_t)*keys); |
341 | memcpy((char*) share->state.key_del, |
342 | (char*) key_del, (sizeof(my_off_t) * |
343 | share->state.header.max_block_size_index)); |
344 | strmov(share->unique_file_name, name_buff); |
345 | share->unique_name_length= (uint)strlen(name_buff); |
346 | strmov(share->index_file_name, index_name); |
347 | strmov(share->data_file_name, data_name); |
348 | |
349 | share->vreclength= share->base.reclength; |
350 | share->blocksize=MY_MIN(IO_SIZE,myisam_block_size); |
351 | { |
352 | HA_KEYSEG *pos=share->keyparts; |
353 | uint32 ftkey_nr= 1; |
354 | for (i=0 ; i < keys ; i++) |
355 | { |
356 | MI_KEYDEF *keyinfo= share->keyinfo + i; |
357 | keyinfo->share= share; |
358 | disk_pos=mi_keydef_read(disk_pos, keyinfo); |
359 | disk_pos_assert(disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE, end_pos); |
360 | if (keyinfo->key_alg == HA_KEY_ALG_RTREE) |
361 | have_rtree=1; |
362 | set_if_smaller(share->blocksize, keyinfo->block_length); |
363 | keyinfo->seg= pos; |
364 | for (j=0 ; j < keyinfo->keysegs; j++,pos++) |
365 | { |
366 | disk_pos=mi_keyseg_read(disk_pos, pos); |
367 | if (pos->flag & HA_BLOB_PART && |
368 | ! (share->options & (HA_OPTION_COMPRESS_RECORD | |
369 | HA_OPTION_PACK_RECORD))) |
370 | { |
371 | my_errno= HA_ERR_CRASHED; |
372 | goto err; |
373 | } |
374 | if (pos->type == HA_KEYTYPE_TEXT || |
375 | pos->type == HA_KEYTYPE_VARTEXT1 || |
376 | pos->type == HA_KEYTYPE_VARTEXT2) |
377 | { |
378 | if (!pos->language) |
379 | pos->charset=default_charset_info; |
380 | else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME)))) |
381 | { |
382 | my_errno=HA_ERR_UNKNOWN_CHARSET; |
383 | goto err; |
384 | } |
385 | } |
386 | else if (pos->type == HA_KEYTYPE_BINARY) |
387 | pos->charset= &my_charset_bin; |
388 | } |
389 | if (keyinfo->flag & HA_SPATIAL) |
390 | { |
391 | #ifdef HAVE_SPATIAL |
392 | uint sp_segs= SPDIMS*2; |
393 | keyinfo->seg= pos - sp_segs; |
394 | DBUG_ASSERT(keyinfo->keysegs == sp_segs + 1); |
395 | keyinfo->keysegs= sp_segs; |
396 | #else |
397 | my_errno=HA_ERR_UNSUPPORTED; |
398 | goto err; |
399 | #endif |
400 | } |
401 | else if (keyinfo->flag & HA_FULLTEXT) |
402 | { |
403 | if (!fulltext_keys) |
404 | { /* 4.0 compatibility code, to be removed in 5.0 */ |
405 | keyinfo->seg= pos - FT_SEGS; |
406 | keyinfo->keysegs-= FT_SEGS; |
407 | } |
408 | else |
409 | { |
410 | uint k; |
411 | keyinfo->seg= pos; |
412 | for (k=0; k < FT_SEGS; k++) |
413 | { |
414 | *pos= ft_keysegs[k]; |
415 | pos[0].language= pos[-1].language; |
416 | if (!(pos[0].charset= pos[-1].charset)) |
417 | { |
418 | my_errno=HA_ERR_CRASHED; |
419 | goto err; |
420 | } |
421 | pos++; |
422 | } |
423 | } |
424 | if (!share->ft2_keyinfo.seg) |
425 | { |
426 | memcpy(& share->ft2_keyinfo, keyinfo, sizeof(MI_KEYDEF)); |
427 | share->ft2_keyinfo.keysegs=1; |
428 | share->ft2_keyinfo.flag=0; |
429 | share->ft2_keyinfo.keylength= |
430 | share->ft2_keyinfo.minlength= |
431 | share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength; |
432 | share->ft2_keyinfo.seg=pos-1; |
433 | share->ft2_keyinfo.end=pos; |
434 | setup_key_functions(& share->ft2_keyinfo); |
435 | } |
436 | keyinfo->ftkey_nr= ftkey_nr++; |
437 | } |
438 | setup_key_functions(keyinfo); |
439 | keyinfo->end= pos; |
440 | pos->type=HA_KEYTYPE_END; /* End */ |
441 | pos->length=share->base.rec_reflength; |
442 | pos->null_bit=0; |
443 | pos->flag=0; /* For purify */ |
444 | pos++; |
445 | } |
446 | |
447 | for (i=0 ; i < uniques ; i++) |
448 | { |
449 | disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]); |
450 | disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs * |
451 | HA_KEYSEG_SIZE, end_pos); |
452 | share->uniqueinfo[i].seg=pos; |
453 | for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++) |
454 | { |
455 | disk_pos=mi_keyseg_read(disk_pos, pos); |
456 | if (pos->type == HA_KEYTYPE_TEXT || |
457 | pos->type == HA_KEYTYPE_VARTEXT1 || |
458 | pos->type == HA_KEYTYPE_VARTEXT2) |
459 | { |
460 | if (!pos->language) |
461 | pos->charset=default_charset_info; |
462 | else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME)))) |
463 | { |
464 | my_errno=HA_ERR_UNKNOWN_CHARSET; |
465 | goto err; |
466 | } |
467 | } |
468 | } |
469 | share->uniqueinfo[i].end=pos; |
470 | pos->type=HA_KEYTYPE_END; /* End */ |
471 | pos->null_bit=0; |
472 | pos->flag=0; |
473 | pos++; |
474 | } |
475 | share->ftkeys= ftkey_nr; |
476 | } |
477 | |
478 | disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos); |
479 | for (i=j=offset=0 ; i < share->base.fields ; i++) |
480 | { |
481 | disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]); |
482 | share->rec[i].pack_type=0; |
483 | share->rec[i].huff_tree=0; |
484 | share->rec[i].offset=offset; |
485 | if (share->rec[i].type == FIELD_BLOB) |
486 | { |
487 | share->blobs[j].pack_length= |
488 | share->rec[i].length - portable_sizeof_char_ptr; |
489 | share->blobs[j].offset=offset; |
490 | j++; |
491 | } |
492 | /* This is to detect how to calculate checksums */ |
493 | if (share->rec[i].null_bit) |
494 | share->has_null_fields= 1; |
495 | if (share->rec[i].type == FIELD_VARCHAR) |
496 | share->has_varchar_fields= 1; |
497 | offset+=share->rec[i].length; |
498 | } |
499 | share->rec[i].type=(int) FIELD_LAST; /* End marker */ |
500 | if (offset > share->base.reclength) |
501 | { |
502 | /* purecov: begin inspected */ |
503 | my_errno= HA_ERR_CRASHED; |
504 | goto err; |
505 | /* purecov: end */ |
506 | } |
507 | |
508 | if (! lock_error) |
509 | { |
510 | (void) my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)); |
511 | lock_error=1; /* Database unlocked */ |
512 | } |
513 | |
514 | if (mi_open_datafile(&info, share)) |
515 | goto err; |
516 | errpos=5; |
517 | |
518 | share->kfile=kfile; |
519 | share->this_process=(ulong) getpid(); |
520 | share->last_process= share->state.process; |
521 | share->base.key_parts=key_parts; |
522 | share->base.all_key_parts=key_parts+unique_key_parts; |
523 | if (!(share->last_version=share->state.version)) |
524 | share->last_version=1; /* Safety */ |
525 | share->rec_reflength=share->base.rec_reflength; /* May be changed */ |
526 | share->base.margin_key_file_length=(share->base.max_key_file_length - |
527 | (keys ? MI_INDEX_BLOCK_MARGIN * |
528 | share->blocksize * keys : 0)); |
529 | share->blocksize=MY_MIN(IO_SIZE,myisam_block_size); |
530 | share->data_file_type=STATIC_RECORD; |
531 | if (share->options & HA_OPTION_COMPRESS_RECORD) |
532 | { |
533 | share->data_file_type = COMPRESSED_RECORD; |
534 | share->options|= HA_OPTION_READ_ONLY_DATA; |
535 | info.s=share; |
536 | if (_mi_read_pack_info(&info, |
537 | (pbool) |
538 | MY_TEST(!(share->options & |
539 | (HA_OPTION_PACK_RECORD | |
540 | HA_OPTION_TEMP_COMPRESS_RECORD))))) |
541 | goto err; |
542 | } |
543 | else if (share->options & HA_OPTION_PACK_RECORD) |
544 | share->data_file_type = DYNAMIC_RECORD; |
545 | my_afree(disk_cache); |
546 | mi_setup_functions(share); |
547 | share->is_log_table= FALSE; |
548 | thr_lock_init(&share->lock); |
549 | mysql_mutex_init(mi_key_mutex_MYISAM_SHARE_intern_lock, |
550 | &share->intern_lock, MY_MUTEX_INIT_FAST); |
551 | for (i=0; i<keys; i++) |
552 | mysql_rwlock_init(mi_key_rwlock_MYISAM_SHARE_key_root_lock, |
553 | &share->key_root_lock[i]); |
554 | mysql_rwlock_init(mi_key_rwlock_MYISAM_SHARE_mmap_lock, &share->mmap_lock); |
555 | if (!thr_lock_inited) |
556 | { |
557 | /* Probably a single threaded program; Don't use concurrent inserts */ |
558 | myisam_concurrent_insert=0; |
559 | } |
560 | else if (myisam_concurrent_insert) |
561 | { |
562 | share->concurrent_insert= |
563 | ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE | |
564 | HA_OPTION_COMPRESS_RECORD | |
565 | HA_OPTION_TEMP_COMPRESS_RECORD)) || |
566 | (open_flags & HA_OPEN_TMP_TABLE) || |
567 | have_rtree) ? 0 : 1; |
568 | if (share->concurrent_insert) |
569 | { |
570 | share->lock.get_status=mi_get_status; |
571 | share->lock.copy_status=mi_copy_status; |
572 | share->lock.update_status=mi_update_status; |
573 | share->lock.restore_status= mi_restore_status; |
574 | share->lock.check_status=mi_check_status; |
575 | share->lock.fix_status= (void (*)(void *, void *)) mi_fix_status; |
576 | } |
577 | } |
578 | /* |
579 | Memory mapping can only be requested after initializing intern_lock. |
580 | */ |
581 | if (open_flags & HA_OPEN_MMAP) |
582 | { |
583 | info.s= share; |
584 | mi_extra(&info, HA_EXTRA_MMAP, 0); |
585 | } |
586 | } |
587 | else |
588 | { |
589 | share= old_info->s; |
590 | if (mode == O_RDWR && share->mode == O_RDONLY) |
591 | { |
592 | my_errno=EACCES; /* Can't open in write mode */ |
593 | goto err; |
594 | } |
595 | if (mi_open_datafile(&info, share)) |
596 | goto err; |
597 | errpos=5; |
598 | have_rtree= old_info->rtree_recursion_state != NULL; |
599 | } |
600 | |
601 | /* alloc and set up private structure parts */ |
602 | if (!my_multi_malloc(MY_WME, |
603 | &m_info,sizeof(MI_INFO), |
604 | &info.blobs,sizeof(MI_BLOB)*share->base.blobs, |
605 | &info.buff,(share->base.max_key_block_length*2+ |
606 | share->base.max_key_length), |
607 | &info.lastkey,share->base.max_key_length*3+1, |
608 | &info.first_mbr_key, share->base.max_key_length, |
609 | &info.filename,strlen(name)+1, |
610 | &info.rtree_recursion_state,have_rtree ? 1024 : 0, |
611 | NullS)) |
612 | goto err; |
613 | errpos=6; |
614 | |
615 | if (!have_rtree) |
616 | info.rtree_recursion_state= NULL; |
617 | |
618 | strmov(info.filename,name); |
619 | memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs); |
620 | info.lastkey2=info.lastkey+share->base.max_key_length; |
621 | |
622 | info.s=share; |
623 | info.lastpos= HA_OFFSET_ERROR; |
624 | info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND); |
625 | info.open_flag= open_flags; |
626 | info.opt_flag=READ_CHECK_USED; |
627 | info.this_unique= (ulong) info.dfile; /* Uniq number in process */ |
628 | if (share->data_file_type == COMPRESSED_RECORD) |
629 | info.this_unique= share->state.unique; |
630 | info.this_loop=0; /* Update counter */ |
631 | info.last_unique= share->state.unique; |
632 | info.last_loop= share->state.update_count; |
633 | if (mode == O_RDONLY) |
634 | share->options|=HA_OPTION_READ_ONLY_DATA; |
635 | info.lock_type=F_UNLCK; |
636 | info.quick_mode=0; |
637 | info.bulk_insert=0; |
638 | info.ft1_to_ft2=0; |
639 | info.errkey= -1; |
640 | info.page_changed=1; |
641 | mysql_mutex_lock(&share->intern_lock); |
642 | info.read_record=share->read_record; |
643 | share->reopen++; |
644 | share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL); |
645 | if (share->options & HA_OPTION_READ_ONLY_DATA) |
646 | { |
647 | info.lock_type=F_RDLCK; |
648 | share->r_locks++; |
649 | share->tot_locks++; |
650 | } |
651 | if ((open_flags & HA_OPEN_TMP_TABLE) || |
652 | (share->options & HA_OPTION_TMP_TABLE)) |
653 | { |
654 | share->temporary=share->delay_key_write=1; |
655 | share->write_flag=MYF(MY_NABP); |
656 | share->w_locks++; /* We don't have to update status */ |
657 | share->tot_locks++; |
658 | info.lock_type=F_WRLCK; |
659 | } |
660 | if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) || |
661 | (share->options & HA_OPTION_DELAY_KEY_WRITE)) && |
662 | myisam_delay_key_write) |
663 | share->delay_key_write=1; |
664 | info.state= &share->state.state; /* Change global values by default */ |
665 | mysql_mutex_unlock(&share->intern_lock); |
666 | |
667 | /* Allocate buffer for one record */ |
668 | |
669 | /* prerequisites: bzero(info) && info->s=share; are met. */ |
670 | if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff)) |
671 | goto err; |
672 | bzero(info.rec_buff, mi_get_rec_buff_len(&info, info.rec_buff)); |
673 | |
674 | *m_info=info; |
675 | thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info); |
676 | |
677 | if (!internal_table) |
678 | { |
679 | m_info->open_list.data= (void*) m_info; |
680 | myisam_open_list= list_add(myisam_open_list, &m_info->open_list); |
681 | mysql_mutex_unlock(&THR_LOCK_myisam); |
682 | } |
683 | |
684 | bzero(info.buff, share->base.max_key_block_length * 2); |
685 | my_free(rec_per_key_part); |
686 | |
687 | if (myisam_log_file >= 0) |
688 | { |
689 | intern_filename(name_buff,share->index_file_name); |
690 | _myisam_log(MI_LOG_OPEN, m_info, (uchar*) name_buff, (uint)strlen(name_buff)); |
691 | } |
692 | DBUG_RETURN(m_info); |
693 | |
694 | err: |
695 | save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE; |
696 | if ((save_errno == HA_ERR_CRASHED) || |
697 | (save_errno == HA_ERR_CRASHED_ON_USAGE) || |
698 | (save_errno == HA_ERR_CRASHED_ON_REPAIR)) |
699 | mi_report_error(save_errno, name); |
700 | switch (errpos) { |
701 | case 6: |
702 | my_free(m_info); |
703 | /* fall through */ |
704 | case 5: |
705 | (void) mysql_file_close(info.dfile, MYF(0)); |
706 | if (old_info) |
707 | break; /* Don't remove open table */ |
708 | /* fall through */ |
709 | case 4: |
710 | my_free(share); |
711 | /* fall through */ |
712 | case 3: |
713 | if (! lock_error) |
714 | (void) my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)); |
715 | my_free(rec_per_key_part); |
716 | /* fall through */ |
717 | case 2: |
718 | my_afree(disk_cache); |
719 | /* fall through */ |
720 | case 1: |
721 | (void) mysql_file_close(kfile, MYF(0)); |
722 | /* fall through */ |
723 | case 0: |
724 | default: |
725 | break; |
726 | } |
727 | if (!internal_table) |
728 | mysql_mutex_unlock(&THR_LOCK_myisam); |
729 | my_errno=save_errno; |
730 | DBUG_RETURN (NULL); |
731 | } /* mi_open */ |
732 | |
733 | |
734 | uchar *mi_alloc_rec_buff(MI_INFO *info, ulong length, uchar **buf) |
735 | { |
736 | uint ; |
737 | uint32 UNINIT_VAR(old_length); |
738 | |
739 | if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf))) |
740 | { |
741 | uchar *newptr = *buf; |
742 | |
743 | /* to simplify initial init of info->rec_buf in mi_open and mi_extra */ |
744 | if (length == (ulong) -1) |
745 | { |
746 | if (info->s->options & HA_OPTION_COMPRESS_RECORD) |
747 | length= MY_MAX(info->s->base.pack_reclength, info->s->max_pack_length); |
748 | else |
749 | length= info->s->base.pack_reclength; |
750 | length= MY_MAX(length, info->s->base.max_key_length); |
751 | length= MY_MAX(length, info->s->vreclength); |
752 | /* Avoid unnecessary realloc */ |
753 | if (newptr && length == old_length) |
754 | return newptr; |
755 | } |
756 | |
757 | extra= ((info->s->options & HA_OPTION_PACK_RECORD) ? |
758 | ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+ |
759 | MI_REC_BUFF_OFFSET : 0); |
760 | if (extra && newptr) |
761 | newptr-= MI_REC_BUFF_OFFSET; |
762 | if (!(newptr=(uchar*) my_realloc((uchar*)newptr, length+extra+8, |
763 | MYF(MY_ALLOW_ZERO_PTR)))) |
764 | return NULL; |
765 | *((uint32 *) newptr)= (uint32) length; |
766 | *buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0); |
767 | } |
768 | return *buf; |
769 | } |
770 | |
771 | |
772 | ulonglong mi_safe_mul(ulonglong a, ulonglong b) |
773 | { |
774 | ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */ |
775 | |
776 | if (!a || max_val / a < b) |
777 | return max_val; |
778 | return a*b; |
779 | } |
780 | |
781 | /* Set up functions in structs */ |
782 | |
783 | void mi_setup_functions(register MYISAM_SHARE *share) |
784 | { |
785 | if (share->options & HA_OPTION_COMPRESS_RECORD) |
786 | { |
787 | share->read_record=_mi_read_pack_record; |
788 | share->read_rnd=_mi_read_rnd_pack_record; |
789 | if ((share->options & |
790 | (HA_OPTION_PACK_RECORD | HA_OPTION_NULL_FIELDS)) || |
791 | share->has_varchar_fields) |
792 | share->calc_checksum= mi_checksum; |
793 | else |
794 | share->calc_checksum= mi_static_checksum; |
795 | share->calc_check_checksum= share->calc_checksum; |
796 | if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD)) |
797 | share->calc_checksum=0; /* No checksum */ |
798 | } |
799 | else if (share->options & HA_OPTION_PACK_RECORD) |
800 | { |
801 | share->read_record=_mi_read_dynamic_record; |
802 | share->read_rnd=_mi_read_rnd_dynamic_record; |
803 | share->delete_record=_mi_delete_dynamic_record; |
804 | share->compare_record=_mi_cmp_dynamic_record; |
805 | share->compare_unique=_mi_cmp_dynamic_unique; |
806 | share->calc_checksum= mi_checksum; |
807 | share->calc_check_checksum= share->calc_checksum; |
808 | |
809 | /* add bits used to pack data to pack_reclength for faster allocation */ |
810 | share->base.pack_reclength+= share->base.pack_bits; |
811 | if (share->base.blobs) |
812 | { |
813 | share->update_record=_mi_update_blob_record; |
814 | share->write_record=_mi_write_blob_record; |
815 | } |
816 | else |
817 | { |
818 | share->write_record=_mi_write_dynamic_record; |
819 | share->update_record=_mi_update_dynamic_record; |
820 | } |
821 | } |
822 | else |
823 | { |
824 | share->read_record=_mi_read_static_record; |
825 | share->read_rnd=_mi_read_rnd_static_record; |
826 | share->delete_record=_mi_delete_static_record; |
827 | share->compare_record=_mi_cmp_static_record; |
828 | share->update_record=_mi_update_static_record; |
829 | share->write_record=_mi_write_static_record; |
830 | share->compare_unique=_mi_cmp_static_unique; |
831 | if (share->options & HA_OPTION_NULL_FIELDS) |
832 | share->calc_checksum= mi_checksum; |
833 | else |
834 | share->calc_checksum= mi_static_checksum; |
835 | share->calc_check_checksum= share->calc_checksum; |
836 | } |
837 | share->file_read= mi_nommap_pread; |
838 | share->file_write= mi_nommap_pwrite; |
839 | if (!(share->options & HA_OPTION_CHECKSUM)) |
840 | share->calc_checksum=0; |
841 | return; |
842 | } |
843 | |
844 | |
845 | static void setup_key_functions(register MI_KEYDEF *keyinfo) |
846 | { |
847 | if (keyinfo->key_alg == HA_KEY_ALG_RTREE) |
848 | { |
849 | #ifdef HAVE_RTREE_KEYS |
850 | keyinfo->ck_insert = rtree_insert; |
851 | keyinfo->ck_delete = rtree_delete; |
852 | #else |
853 | DBUG_ASSERT(0); /* mi_open should check it never happens */ |
854 | #endif |
855 | } |
856 | else |
857 | { |
858 | keyinfo->ck_insert = _mi_ck_write; |
859 | keyinfo->ck_delete = _mi_ck_delete; |
860 | } |
861 | if (keyinfo->flag & HA_BINARY_PACK_KEY) |
862 | { /* Simple prefix compression */ |
863 | keyinfo->bin_search=_mi_seq_search; |
864 | keyinfo->get_key=_mi_get_binary_pack_key; |
865 | keyinfo->pack_key=_mi_calc_bin_pack_key_length; |
866 | keyinfo->store_key=_mi_store_bin_pack_key; |
867 | } |
868 | else if (keyinfo->flag & HA_VAR_LENGTH_KEY) |
869 | { |
870 | keyinfo->get_key= _mi_get_pack_key; |
871 | if (keyinfo->seg[0].flag & HA_PACK_KEY) |
872 | { /* Prefix compression */ |
873 | /* |
874 | _mi_prefix_search() compares end-space against ASCII blank (' '). |
875 | It cannot be used for character sets, that do not encode the |
876 | blank character like ASCII does. UCS2 is an example. All |
877 | character sets with a fixed width > 1 or a mimimum width > 1 |
878 | cannot represent blank like ASCII does. In these cases we have |
879 | to use _mi_seq_search() for the search. |
880 | */ |
881 | if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) || |
882 | (keyinfo->seg->flag & HA_NULL_PART) || |
883 | (keyinfo->seg->charset->mbminlen > 1)) |
884 | keyinfo->bin_search=_mi_seq_search; |
885 | else |
886 | keyinfo->bin_search=_mi_prefix_search; |
887 | keyinfo->pack_key=_mi_calc_var_pack_key_length; |
888 | keyinfo->store_key=_mi_store_var_pack_key; |
889 | } |
890 | else |
891 | { |
892 | keyinfo->bin_search=_mi_seq_search; |
893 | keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */ |
894 | keyinfo->store_key=_mi_store_static_key; |
895 | } |
896 | } |
897 | else |
898 | { |
899 | keyinfo->bin_search=_mi_bin_search; |
900 | keyinfo->get_key=_mi_get_static_key; |
901 | keyinfo->pack_key=_mi_calc_static_key_length; |
902 | keyinfo->store_key=_mi_store_static_key; |
903 | } |
904 | return; |
905 | } |
906 | |
907 | |
908 | /* |
909 | Function to save and store the header in the index file (.MYI) |
910 | */ |
911 | |
912 | uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite) |
913 | { |
914 | uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE]; |
915 | uchar *ptr=buff; |
916 | uint i, keys= (uint) state->header.keys, |
917 | key_blocks=state->header.max_block_size_index; |
918 | DBUG_ENTER("mi_state_info_write" ); |
919 | |
920 | memcpy(ptr, &state->header, sizeof(state->header)); |
921 | ptr+=sizeof(state->header); |
922 | |
923 | /* open_count must be first because of _mi_mark_file_changed ! */ |
924 | mi_int2store(ptr,state->open_count); ptr +=2; |
925 | *ptr++= (uchar)state->changed; *ptr++= state->sortkey; |
926 | mi_rowstore(ptr,state->state.records); ptr +=8; |
927 | mi_rowstore(ptr,state->state.del); ptr +=8; |
928 | mi_rowstore(ptr,state->split); ptr +=8; |
929 | mi_sizestore(ptr,state->dellink); ptr +=8; |
930 | mi_sizestore(ptr,state->state.key_file_length); ptr +=8; |
931 | mi_sizestore(ptr,state->state.data_file_length); ptr +=8; |
932 | mi_sizestore(ptr,state->state.empty); ptr +=8; |
933 | mi_sizestore(ptr,state->state.key_empty); ptr +=8; |
934 | mi_int8store(ptr,state->auto_increment); ptr +=8; |
935 | mi_int8store(ptr,(ulonglong) state->state.checksum);ptr +=8; |
936 | mi_int4store(ptr,state->process); ptr +=4; |
937 | mi_int4store(ptr,state->unique); ptr +=4; |
938 | mi_int4store(ptr,state->status); ptr +=4; |
939 | mi_int4store(ptr,state->update_count); ptr +=4; |
940 | |
941 | ptr+=state->state_diff_length; |
942 | |
943 | for (i=0; i < keys; i++) |
944 | { |
945 | mi_sizestore(ptr,state->key_root[i]); ptr +=8; |
946 | } |
947 | for (i=0; i < key_blocks; i++) |
948 | { |
949 | mi_sizestore(ptr,state->key_del[i]); ptr +=8; |
950 | } |
951 | if (pWrite & 2) /* From isamchk */ |
952 | { |
953 | uint key_parts= mi_uint2korr(state->header.key_parts); |
954 | mi_int4store(ptr,state->sec_index_changed); ptr +=4; |
955 | mi_int4store(ptr,state->sec_index_used); ptr +=4; |
956 | mi_int4store(ptr,state->version); ptr +=4; |
957 | mi_int8store(ptr,state->key_map); ptr +=8; |
958 | mi_int8store(ptr,(ulonglong) state->create_time); ptr +=8; |
959 | mi_int8store(ptr,(ulonglong) state->recover_time); ptr +=8; |
960 | mi_int8store(ptr,(ulonglong) state->check_time); ptr +=8; |
961 | mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8; |
962 | for (i=0 ; i < key_parts ; i++) |
963 | { |
964 | mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4; |
965 | } |
966 | } |
967 | |
968 | if (pWrite & 1) |
969 | DBUG_RETURN(mysql_file_pwrite(file, buff, (size_t) (ptr-buff), 0L, |
970 | MYF(MY_NABP | MY_THREADSAFE)) != 0); |
971 | DBUG_RETURN(mysql_file_write(file, buff, (size_t) (ptr-buff), |
972 | MYF(MY_NABP)) != 0); |
973 | } |
974 | |
975 | |
976 | uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state) |
977 | { |
978 | uint i,keys,key_parts,key_blocks; |
979 | memcpy(&state->header, ptr, sizeof(state->header)); |
980 | ptr +=sizeof(state->header); |
981 | keys=(uint) state->header.keys; |
982 | key_parts=mi_uint2korr(state->header.key_parts); |
983 | key_blocks=state->header.max_block_size_index; |
984 | |
985 | state->open_count = mi_uint2korr(ptr); ptr +=2; |
986 | state->changed= *ptr++; |
987 | state->sortkey = (uint) *ptr++; |
988 | state->state.records= mi_rowkorr(ptr); ptr +=8; |
989 | state->state.del = mi_rowkorr(ptr); ptr +=8; |
990 | state->split = mi_rowkorr(ptr); ptr +=8; |
991 | state->dellink= mi_sizekorr(ptr); ptr +=8; |
992 | state->state.key_file_length = mi_sizekorr(ptr); ptr +=8; |
993 | state->state.data_file_length= mi_sizekorr(ptr); ptr +=8; |
994 | state->state.empty = mi_sizekorr(ptr); ptr +=8; |
995 | state->state.key_empty= mi_sizekorr(ptr); ptr +=8; |
996 | state->auto_increment=mi_uint8korr(ptr); ptr +=8; |
997 | state->state.checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8; |
998 | state->process= mi_uint4korr(ptr); ptr +=4; |
999 | state->unique = mi_uint4korr(ptr); ptr +=4; |
1000 | state->status = mi_uint4korr(ptr); ptr +=4; |
1001 | state->update_count=mi_uint4korr(ptr); ptr +=4; |
1002 | |
1003 | ptr+= state->state_diff_length; |
1004 | |
1005 | if (!state->rec_per_key_part) |
1006 | { |
1007 | if (!my_multi_malloc(MY_WME, |
1008 | &state->rec_per_key_part,sizeof(long)*key_parts, |
1009 | &state->key_root, keys*sizeof(my_off_t), |
1010 | &state->key_del, key_blocks*sizeof(my_off_t), |
1011 | NullS)) |
1012 | return(0); |
1013 | } |
1014 | |
1015 | for (i=0; i < keys; i++) |
1016 | { |
1017 | state->key_root[i]= mi_sizekorr(ptr); ptr +=8; |
1018 | } |
1019 | for (i=0; i < key_blocks; i++) |
1020 | { |
1021 | state->key_del[i] = mi_sizekorr(ptr); ptr +=8; |
1022 | } |
1023 | state->sec_index_changed = mi_uint4korr(ptr); ptr +=4; |
1024 | state->sec_index_used = mi_uint4korr(ptr); ptr +=4; |
1025 | state->version = mi_uint4korr(ptr); ptr +=4; |
1026 | state->key_map = mi_uint8korr(ptr); ptr +=8; |
1027 | state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8; |
1028 | state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8; |
1029 | state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8; |
1030 | state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8; |
1031 | for (i=0 ; i < key_parts ; i++) |
1032 | { |
1033 | state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4; |
1034 | } |
1035 | return ptr; |
1036 | } |
1037 | |
1038 | |
1039 | uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead) |
1040 | { |
1041 | uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE]; |
1042 | |
1043 | if (!myisam_single_user) |
1044 | { |
1045 | if (pRead) |
1046 | { |
1047 | if (mysql_file_pread(file, buff, state->state_length, 0L, MYF(MY_NABP))) |
1048 | return 1; |
1049 | } |
1050 | else if (mysql_file_read(file, buff, state->state_length, MYF(MY_NABP))) |
1051 | return 1; |
1052 | mi_state_info_read(buff, state); |
1053 | } |
1054 | return 0; |
1055 | } |
1056 | |
1057 | |
1058 | /**************************************************************************** |
1059 | ** store and read of MI_BASE_INFO |
1060 | ****************************************************************************/ |
1061 | |
1062 | uint mi_base_info_write(File file, MI_BASE_INFO *base) |
1063 | { |
1064 | uchar buff[MI_BASE_INFO_SIZE], *ptr=buff; |
1065 | |
1066 | mi_sizestore(ptr,base->keystart); ptr +=8; |
1067 | mi_sizestore(ptr,base->max_data_file_length); ptr +=8; |
1068 | mi_sizestore(ptr,base->max_key_file_length); ptr +=8; |
1069 | mi_rowstore(ptr,base->records); ptr +=8; |
1070 | mi_rowstore(ptr,base->reloc); ptr +=8; |
1071 | mi_int4store(ptr,base->mean_row_length); ptr +=4; |
1072 | mi_int4store(ptr,base->reclength); ptr +=4; |
1073 | mi_int4store(ptr,base->pack_reclength); ptr +=4; |
1074 | mi_int4store(ptr,base->min_pack_length); ptr +=4; |
1075 | mi_int4store(ptr,base->max_pack_length); ptr +=4; |
1076 | mi_int4store(ptr,base->min_block_length); ptr +=4; |
1077 | mi_int4store(ptr,base->fields); ptr +=4; |
1078 | mi_int4store(ptr,base->pack_fields); ptr +=4; |
1079 | *ptr++=base->rec_reflength; |
1080 | *ptr++=base->key_reflength; |
1081 | *ptr++=base->keys; |
1082 | *ptr++=base->auto_key; |
1083 | mi_int2store(ptr,base->pack_bits); ptr +=2; |
1084 | mi_int2store(ptr,base->blobs); ptr +=2; |
1085 | mi_int2store(ptr,base->max_key_block_length); ptr +=2; |
1086 | mi_int2store(ptr,base->max_key_length); ptr +=2; |
1087 | mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2; |
1088 | *ptr++= base->extra_alloc_procent; |
1089 | bzero(ptr,13); ptr +=13; /* extra */ |
1090 | return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; |
1091 | } |
1092 | |
1093 | |
1094 | uchar *mi_n_base_info_read(uchar *ptr, MI_BASE_INFO *base) |
1095 | { |
1096 | base->keystart = mi_sizekorr(ptr); ptr +=8; |
1097 | base->max_data_file_length = mi_sizekorr(ptr); ptr +=8; |
1098 | base->max_key_file_length = mi_sizekorr(ptr); ptr +=8; |
1099 | base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8; |
1100 | base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8; |
1101 | base->mean_row_length = mi_uint4korr(ptr); ptr +=4; |
1102 | base->reclength = mi_uint4korr(ptr); ptr +=4; |
1103 | base->pack_reclength = mi_uint4korr(ptr); ptr +=4; |
1104 | base->min_pack_length = mi_uint4korr(ptr); ptr +=4; |
1105 | base->max_pack_length = mi_uint4korr(ptr); ptr +=4; |
1106 | base->min_block_length = mi_uint4korr(ptr); ptr +=4; |
1107 | base->fields = mi_uint4korr(ptr); ptr +=4; |
1108 | base->pack_fields = mi_uint4korr(ptr); ptr +=4; |
1109 | |
1110 | base->rec_reflength = *ptr++; |
1111 | base->key_reflength = *ptr++; |
1112 | base->keys= *ptr++; |
1113 | base->auto_key= *ptr++; |
1114 | base->pack_bits = mi_uint2korr(ptr); ptr +=2; |
1115 | base->blobs = mi_uint2korr(ptr); ptr +=2; |
1116 | base->max_key_block_length= mi_uint2korr(ptr); ptr +=2; |
1117 | base->max_key_length = mi_uint2korr(ptr); ptr +=2; |
1118 | base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2; |
1119 | base->extra_alloc_procent = *ptr++; |
1120 | |
1121 | ptr+=13; |
1122 | return ptr; |
1123 | } |
1124 | |
1125 | /*-------------------------------------------------------------------------- |
1126 | mi_keydef |
1127 | ---------------------------------------------------------------------------*/ |
1128 | |
1129 | uint mi_keydef_write(File file, MI_KEYDEF *keydef) |
1130 | { |
1131 | uchar buff[MI_KEYDEF_SIZE]; |
1132 | uchar *ptr=buff; |
1133 | |
1134 | *ptr++ = (uchar) keydef->keysegs; |
1135 | *ptr++ = keydef->key_alg; /* Rtree or Btree */ |
1136 | mi_int2store(ptr,keydef->flag); ptr +=2; |
1137 | mi_int2store(ptr,keydef->block_length); ptr +=2; |
1138 | mi_int2store(ptr,keydef->keylength); ptr +=2; |
1139 | mi_int2store(ptr,keydef->minlength); ptr +=2; |
1140 | mi_int2store(ptr,keydef->maxlength); ptr +=2; |
1141 | return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; |
1142 | } |
1143 | |
1144 | uchar *mi_keydef_read(uchar *ptr, MI_KEYDEF *keydef) |
1145 | { |
1146 | keydef->keysegs = (uint) *ptr++; |
1147 | keydef->key_alg = *ptr++; /* Rtree or Btree */ |
1148 | |
1149 | keydef->flag = mi_uint2korr(ptr); ptr +=2; |
1150 | keydef->block_length = mi_uint2korr(ptr); ptr +=2; |
1151 | keydef->keylength = mi_uint2korr(ptr); ptr +=2; |
1152 | keydef->minlength = mi_uint2korr(ptr); ptr +=2; |
1153 | keydef->maxlength = mi_uint2korr(ptr); ptr +=2; |
1154 | keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1; |
1155 | keydef->underflow_block_length=keydef->block_length/3; |
1156 | keydef->version = 0; /* Not saved */ |
1157 | keydef->parser = &ft_default_parser; |
1158 | keydef->ftkey_nr = 0; |
1159 | return ptr; |
1160 | } |
1161 | |
1162 | /*************************************************************************** |
1163 | ** mi_keyseg |
1164 | ***************************************************************************/ |
1165 | |
1166 | int mi_keyseg_write(File file, const HA_KEYSEG *keyseg) |
1167 | { |
1168 | uchar buff[HA_KEYSEG_SIZE]; |
1169 | uchar *ptr=buff; |
1170 | ulong pos; |
1171 | |
1172 | *ptr++= keyseg->type; |
1173 | *ptr++= keyseg->language & 0xFF; /* Collation ID, low byte */ |
1174 | *ptr++= keyseg->null_bit; |
1175 | *ptr++= keyseg->bit_start; |
1176 | *ptr++= keyseg->language >> 8; /* Collation ID, high byte */ |
1177 | *ptr++= keyseg->bit_length; |
1178 | mi_int2store(ptr,keyseg->flag); ptr+=2; |
1179 | mi_int2store(ptr,keyseg->length); ptr+=2; |
1180 | mi_int4store(ptr,keyseg->start); ptr+=4; |
1181 | pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos; |
1182 | mi_int4store(ptr, pos); |
1183 | ptr+=4; |
1184 | |
1185 | return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; |
1186 | } |
1187 | |
1188 | |
1189 | uchar *mi_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg) |
1190 | { |
1191 | keyseg->type = *ptr++; |
1192 | keyseg->language = *ptr++; |
1193 | keyseg->null_bit = *ptr++; |
1194 | keyseg->bit_start = *ptr++; |
1195 | keyseg->language += ((uint16) (*ptr++)) << 8; |
1196 | keyseg->bit_length = *ptr++; |
1197 | keyseg->flag = mi_uint2korr(ptr); ptr +=2; |
1198 | keyseg->length = mi_uint2korr(ptr); ptr +=2; |
1199 | keyseg->start = mi_uint4korr(ptr); ptr +=4; |
1200 | keyseg->null_pos = mi_uint4korr(ptr); ptr +=4; |
1201 | keyseg->charset=0; /* Will be filled in later */ |
1202 | if (keyseg->null_bit) |
1203 | /* We adjust bit_pos if null_bit is last in the byte */ |
1204 | keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == (1 << 7))); |
1205 | else |
1206 | { |
1207 | keyseg->bit_pos= (uint16)keyseg->null_pos; |
1208 | keyseg->null_pos= 0; |
1209 | } |
1210 | return ptr; |
1211 | } |
1212 | |
1213 | /*-------------------------------------------------------------------------- |
1214 | mi_uniquedef |
1215 | ---------------------------------------------------------------------------*/ |
1216 | |
1217 | uint mi_uniquedef_write(File file, MI_UNIQUEDEF *def) |
1218 | { |
1219 | uchar buff[MI_UNIQUEDEF_SIZE]; |
1220 | uchar *ptr=buff; |
1221 | |
1222 | mi_int2store(ptr,def->keysegs); ptr+=2; |
1223 | *ptr++= (uchar) def->key; |
1224 | *ptr++ = (uchar) def->null_are_equal; |
1225 | |
1226 | return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; |
1227 | } |
1228 | |
1229 | uchar *mi_uniquedef_read(uchar *ptr, MI_UNIQUEDEF *def) |
1230 | { |
1231 | def->keysegs = mi_uint2korr(ptr); |
1232 | def->key = ptr[2]; |
1233 | def->null_are_equal=ptr[3]; |
1234 | return ptr+4; /* 1 extra byte */ |
1235 | } |
1236 | |
1237 | /*************************************************************************** |
1238 | ** MI_COLUMNDEF |
1239 | ***************************************************************************/ |
1240 | |
1241 | uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo) |
1242 | { |
1243 | uchar buff[MI_COLUMNDEF_SIZE]; |
1244 | uchar *ptr=buff; |
1245 | |
1246 | mi_int2store(ptr,recinfo->type); ptr +=2; |
1247 | mi_int2store(ptr,recinfo->length); ptr +=2; |
1248 | *ptr++ = recinfo->null_bit; |
1249 | mi_int2store(ptr,recinfo->null_pos); ptr+= 2; |
1250 | return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; |
1251 | } |
1252 | |
1253 | uchar *mi_recinfo_read(uchar *ptr, MI_COLUMNDEF *recinfo) |
1254 | { |
1255 | recinfo->type= mi_sint2korr(ptr); ptr +=2; |
1256 | recinfo->length=mi_uint2korr(ptr); ptr +=2; |
1257 | recinfo->null_bit= (uint8) *ptr++; |
1258 | recinfo->null_pos=mi_uint2korr(ptr); ptr +=2; |
1259 | return ptr; |
1260 | } |
1261 | |
1262 | /************************************************************************** |
1263 | Open data file. |
1264 | We can't use dup() here as the data file descriptors need to have different |
1265 | active seek-positions. |
1266 | *************************************************************************/ |
1267 | |
1268 | int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share) |
1269 | { |
1270 | myf flags= MY_WME | (share->mode & O_NOFOLLOW ? MY_NOSYMLINKS: 0); |
1271 | DEBUG_SYNC_C("mi_open_datafile" ); |
1272 | info->dfile= mysql_file_open(mi_key_file_dfile, share->data_file_name, |
1273 | share->mode | O_SHARE, MYF(flags)); |
1274 | return info->dfile >= 0 ? 0 : 1; |
1275 | } |
1276 | |
1277 | |
1278 | int mi_open_keyfile(MYISAM_SHARE *share) |
1279 | { |
1280 | if ((share->kfile= mysql_file_open(mi_key_file_kfile, |
1281 | share->unique_file_name, |
1282 | share->mode | O_SHARE | O_NOFOLLOW, |
1283 | MYF(MY_NOSYMLINKS | MY_WME))) < 0) |
1284 | return 1; |
1285 | return 0; |
1286 | } |
1287 | |
1288 | |
1289 | /* |
1290 | Disable all indexes. |
1291 | |
1292 | SYNOPSIS |
1293 | mi_disable_indexes() |
1294 | info A pointer to the MyISAM storage engine MI_INFO struct. |
1295 | |
1296 | DESCRIPTION |
1297 | Disable all indexes. |
1298 | |
1299 | RETURN |
1300 | 0 ok |
1301 | */ |
1302 | |
1303 | int mi_disable_indexes(MI_INFO *info) |
1304 | { |
1305 | MYISAM_SHARE *share= info->s; |
1306 | |
1307 | mi_clear_all_keys_active(share->state.key_map); |
1308 | return 0; |
1309 | } |
1310 | |
1311 | |
1312 | /* |
1313 | Enable all indexes |
1314 | |
1315 | SYNOPSIS |
1316 | mi_enable_indexes() |
1317 | info A pointer to the MyISAM storage engine MI_INFO struct. |
1318 | |
1319 | DESCRIPTION |
1320 | Enable all indexes. The indexes might have been disabled |
1321 | by mi_disable_index() before. |
1322 | The function works only if both data and indexes are empty, |
1323 | otherwise a repair is required. |
1324 | To be sure, call handler::delete_all_rows() before. |
1325 | |
1326 | RETURN |
1327 | 0 ok |
1328 | HA_ERR_CRASHED data or index is non-empty. |
1329 | */ |
1330 | |
1331 | int mi_enable_indexes(MI_INFO *info) |
1332 | { |
1333 | int error= 0; |
1334 | MYISAM_SHARE *share= info->s; |
1335 | |
1336 | if (share->state.state.data_file_length || |
1337 | (share->state.state.key_file_length != share->base.keystart)) |
1338 | { |
1339 | mi_print_error(info->s, HA_ERR_CRASHED); |
1340 | error= HA_ERR_CRASHED; |
1341 | } |
1342 | else |
1343 | mi_set_all_keys_active(share->state.key_map, share->base.keys); |
1344 | return error; |
1345 | } |
1346 | |
1347 | |
1348 | /* |
1349 | Test if indexes are disabled. |
1350 | |
1351 | SYNOPSIS |
1352 | mi_indexes_are_disabled() |
1353 | info A pointer to the MyISAM storage engine MI_INFO struct. |
1354 | |
1355 | DESCRIPTION |
1356 | Test if indexes are disabled. |
1357 | |
1358 | RETURN |
1359 | 0 indexes are not disabled |
1360 | 1 all indexes are disabled |
1361 | 2 non-unique indexes are disabled |
1362 | */ |
1363 | |
1364 | int mi_indexes_are_disabled(MI_INFO *info) |
1365 | { |
1366 | MYISAM_SHARE *share= info->s; |
1367 | |
1368 | /* |
1369 | No keys or all are enabled. keys is the number of keys. Left shifted |
1370 | gives us only one bit set. When decreased by one, gives us all all bits |
1371 | up to this one set and it gets unset. |
1372 | */ |
1373 | if (!share->base.keys || |
1374 | (mi_is_all_keys_active(share->state.key_map, share->base.keys))) |
1375 | return 0; |
1376 | |
1377 | /* All are disabled */ |
1378 | if (mi_is_any_key_active(share->state.key_map)) |
1379 | return 1; |
1380 | |
1381 | /* |
1382 | We have keys. Some enabled, some disabled. |
1383 | Don't check for any non-unique disabled but return directly 2 |
1384 | */ |
1385 | return 2; |
1386 | } |
1387 | |