1/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16/* open an Aria table */
17
18#include "ma_fulltext.h"
19#include "ma_sp_defs.h"
20#include "ma_rt_index.h"
21#include "ma_blockrec.h"
22#include <m_ctype.h>
23#include "ma_crypt.h"
24
25#if defined(MSDOS) || defined(__WIN__)
26#ifdef __WIN__
27#include <fcntl.h>
28#else
29#include <process.h> /* Prototype for getpid */
30#endif
31#endif
32
33static void setup_key_functions(MARIA_KEYDEF *keyinfo);
34static my_bool maria_scan_init_dummy(MARIA_HA *info);
35static void maria_scan_end_dummy(MARIA_HA *info);
36static my_bool maria_once_init_dummy(MARIA_SHARE *, File);
37static my_bool maria_once_end_dummy(MARIA_SHARE *);
38static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base);
39static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state);
40
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(share, pos, end_pos) \
46if (pos > end_pos) \
47{ \
48 _ma_set_fatal_error(share, 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
58MARIA_HA *_ma_test_if_reopen(const char *filename)
59{
60 LIST *pos;
61
62 for (pos=maria_open_list ; pos ; pos=pos->next)
63 {
64 MARIA_HA *info=(MARIA_HA*) pos->data;
65 MARIA_SHARE *share= info->s;
66 if (!strcmp(share->unique_file_name.str,filename) && share->last_version)
67 return info;
68 }
69 return 0;
70}
71
72
73/*
74 Open a new instance of an already opened Maria table
75
76 SYNOPSIS
77 maria_clone_internal()
78 share Share of already open table
79 mode Mode of table (O_RDONLY | O_RDWR)
80 data_file Filedescriptor of data file to use < 0 if one should open
81 open it.
82 internal_table <> 0 if this is an internal temporary table
83
84 RETURN
85 # Maria handler
86 0 Error
87*/
88
89
90static MARIA_HA *maria_clone_internal(MARIA_SHARE *share,
91 int mode, File data_file,
92 uint internal_table)
93{
94 int save_errno;
95 uint errpos;
96 MARIA_HA info,*m_info;
97 my_bitmap_map *changed_fields_bitmap;
98 DBUG_ENTER("maria_clone_internal");
99
100 errpos= 0;
101 bzero((uchar*) &info,sizeof(info));
102
103 if (mode == O_RDWR && share->mode == O_RDONLY)
104 {
105 my_errno=EACCES; /* Can't open in write mode */
106 goto err;
107 }
108 if (data_file >= 0)
109 info.dfile.file= data_file;
110 else if (_ma_open_datafile(&info, share))
111 goto err;
112 errpos= 5;
113
114 /* alloc and set up private structure parts */
115 if (!my_multi_malloc(MY_WME,
116 &m_info,sizeof(MARIA_HA),
117 &info.blobs,sizeof(MARIA_BLOB)*share->base.blobs,
118 &info.buff,(share->base.max_key_block_length*2+
119 share->base.max_key_length),
120 &info.lastkey_buff,share->base.max_key_length*2+1,
121 &info.first_mbr_key, share->base.max_key_length,
122 &info.maria_rtree_recursion_state,
123 share->have_rtree ? 1024 : 0,
124 &changed_fields_bitmap,
125 bitmap_buffer_size(share->base.fields),
126 NullS))
127 goto err;
128 errpos= 6;
129
130 memcpy(info.blobs,share->blobs,sizeof(MARIA_BLOB)*share->base.blobs);
131 info.lastkey_buff2= info.lastkey_buff + share->base.max_key_length;
132 info.last_key.data= info.lastkey_buff;
133
134 info.s=share;
135 info.cur_row.lastpos= HA_OFFSET_ERROR;
136 /* Impossible first index to force initialization in _ma_check_index() */
137 info.lastinx= ~0;
138 info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
139 info.opt_flag=READ_CHECK_USED;
140 info.this_unique= (ulong) info.dfile.file; /* Uniq number in process */
141#ifdef MARIA_EXTERNAL_LOCKING
142 if (share->data_file_type == COMPRESSED_RECORD)
143 info.this_unique= share->state.unique;
144 info.this_loop=0; /* Update counter */
145 info.last_unique= share->state.unique;
146 info.last_loop= share->state.update_count;
147#endif
148 info.errkey= -1;
149 info.page_changed=1;
150 info.keyread_buff= info.buff + share->base.max_key_block_length;
151
152 info.lock_type= F_UNLCK;
153 if (share->options & HA_OPTION_TMP_TABLE)
154 info.lock_type= F_WRLCK;
155
156 _ma_set_data_pagecache_callbacks(&info.dfile, share);
157 my_bitmap_init(&info.changed_fields, changed_fields_bitmap,
158 share->base.fields, 0);
159 if ((*share->init)(&info))
160 goto err;
161
162 /* The following should be big enough for all pinning purposes */
163 if (my_init_dynamic_array(&info.pinned_pages,
164 sizeof(MARIA_PINNED_PAGE),
165 MY_MAX(share->base.blobs*2 + 4,
166 MARIA_MAX_TREE_LEVELS*3), 16, MYF(0)))
167 goto err;
168
169
170 mysql_mutex_lock(&share->intern_lock);
171 info.read_record= share->read_record;
172 share->reopen++;
173 share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
174 if (share->options & HA_OPTION_READ_ONLY_DATA)
175 {
176 info.lock_type=F_RDLCK;
177 share->r_locks++;
178 share->tot_locks++;
179 }
180 if ((share->options & HA_OPTION_DELAY_KEY_WRITE) &&
181 maria_delay_key_write)
182 share->delay_key_write=1;
183
184 if (!share->base.born_transactional) /* For transactional ones ... */
185 {
186 /* ... force crash if no trn given */
187 _ma_set_trn_for_table(&info, &dummy_transaction_object);
188 info.state= &share->state.state; /* Change global values by default */
189 }
190 else
191 {
192 info.state= &share->state.common;
193 *info.state= share->state.state; /* Initial values */
194 }
195 info.state_start= info.state; /* Initial values */
196
197 mysql_mutex_unlock(&share->intern_lock);
198
199 /* Allocate buffer for one record */
200 /* prerequisites: info->rec_buffer == 0 && info->rec_buff_size == 0 */
201 if (_ma_alloc_buffer(&info.rec_buff, &info.rec_buff_size,
202 share->base.default_rec_buff_size))
203 goto err;
204
205 bzero(info.rec_buff, share->base.default_rec_buff_size);
206
207 *m_info=info;
208 thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
209
210 if (share->options & HA_OPTION_TMP_TABLE)
211 m_info->lock.type= TL_WRITE;
212
213 if (!internal_table)
214 {
215 m_info->open_list.data= m_info->share_list.data= (void*) m_info;
216 maria_open_list= list_add(maria_open_list, &m_info->open_list);
217 share->open_list= list_add(share->open_list, &m_info->share_list);
218 }
219 else
220 {
221 /* We don't need to mark internal temporary tables as changed on disk */
222 share->internal_table= 1;
223 share->global_changed= 1;
224 }
225 DBUG_RETURN(m_info);
226
227err:
228 DBUG_PRINT("error", ("error: %d", my_errno));
229 save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
230 if ((save_errno == HA_ERR_CRASHED) ||
231 (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
232 (save_errno == HA_ERR_CRASHED_ON_REPAIR))
233 _ma_report_error(save_errno, &share->open_file_name);
234 switch (errpos) {
235 case 6:
236 (*share->end)(&info);
237 delete_dynamic(&info.pinned_pages);
238 my_free(m_info);
239 /* fall through */
240 case 5:
241 if (data_file < 0)
242 mysql_file_close(info.dfile.file, MYF(0));
243 break;
244 }
245 my_errno=save_errno;
246 DBUG_RETURN (NULL);
247} /* maria_clone_internal */
248
249
250/* Make a clone of a maria table */
251
252MARIA_HA *maria_clone(MARIA_SHARE *share, int mode)
253{
254 MARIA_HA *new_info;
255 mysql_mutex_lock(&THR_LOCK_maria);
256 new_info= maria_clone_internal(share, mode,
257 share->data_file_type == BLOCK_RECORD ?
258 share->bitmap.file.file : -1, 0);
259 mysql_mutex_unlock(&THR_LOCK_maria);
260 return new_info;
261}
262
263
264/******************************************************************************
265 open a MARIA table
266
267 See my_base.h for the handle_locking argument
268 if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
269 is marked crashed or if we are not using locking and the table doesn't
270 have an open count of 0.
271******************************************************************************/
272
273MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
274{
275 int kfile,open_mode,save_errno;
276 uint i,j,len,errpos,head_length,base_pos,keys, realpath_err,
277 key_parts,base_key_parts,unique_key_parts,fulltext_keys,uniques;
278 uint internal_table= MY_TEST(open_flags & HA_OPEN_INTERNAL_TABLE);
279 uint file_version;
280 size_t info_length;
281 char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
282 data_name[FN_REFLEN];
283 uchar *UNINIT_VAR(disk_cache), *disk_pos, *end_pos;
284 MARIA_HA info, *UNINIT_VAR(m_info), *old_info;
285 MARIA_SHARE share_buff,*share;
286 double *rec_per_key_part;
287 ulong *nulls_per_key_part;
288 my_off_t key_root[HA_MAX_POSSIBLE_KEY];
289 ulonglong max_key_file_length, max_data_file_length;
290 my_bool versioning= 1;
291 File data_file= -1;
292 DBUG_ENTER("maria_open");
293
294 kfile= -1;
295 errpos= 0;
296 head_length=sizeof(share_buff.state.header);
297 bzero((uchar*) &info,sizeof(info));
298
299 realpath_err= my_realpath(name_buff, fn_format(org_name, name, "",
300 MARIA_NAME_IEXT,
301 MY_UNPACK_FILENAME),MYF(0));
302 if (realpath_err > 0) /* File not found, no point in looking further. */
303 {
304 DBUG_RETURN(NULL);
305 }
306
307 if (my_is_symlink(org_name) &&
308 (realpath_err || mysys_test_invalid_symlink(name_buff)))
309 {
310 my_errno= HA_WRONG_CREATE_OPTION;
311 DBUG_RETURN(0);
312 }
313
314 old_info= 0;
315 if (!internal_table)
316 mysql_mutex_lock(&THR_LOCK_maria);
317 if ((open_flags & HA_OPEN_COPY) ||
318 (internal_table || !(old_info=_ma_test_if_reopen(name_buff))))
319 {
320 share= &share_buff;
321 bzero((uchar*) &share_buff,sizeof(share_buff));
322 share_buff.state.key_root=key_root;
323 share_buff.pagecache= multi_pagecache_search((uchar*) name_buff,
324 (uint) strlen(name_buff),
325 maria_pagecache);
326
327 DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_open",
328 if (strstr(name, "/t1"))
329 {
330 my_errno= HA_ERR_CRASHED;
331 goto err;
332 });
333 DEBUG_SYNC_C("mi_open_kfile");
334 if ((kfile=mysql_file_open(key_file_kfile, name_buff,
335 (open_mode=O_RDWR) | O_SHARE | O_NOFOLLOW,
336 MYF(MY_NOSYMLINKS))) < 0)
337 {
338 if ((errno != EROFS && errno != EACCES) ||
339 mode != O_RDONLY ||
340 (kfile=mysql_file_open(key_file_kfile, name_buff,
341 (open_mode=O_RDONLY) | O_SHARE | O_NOFOLLOW,
342 MYF(MY_NOSYMLINKS))) < 0)
343 goto err;
344 }
345 share->mode=open_mode;
346 errpos= 1;
347 if (mysql_file_pread(kfile,share->state.header.file_version, head_length,
348 0, MYF(MY_NABP)))
349 {
350 my_errno= HA_ERR_NOT_A_TABLE;
351 goto err;
352 }
353 if (memcmp(share->state.header.file_version, maria_file_magic, 4))
354 {
355 DBUG_PRINT("error",("Wrong header in %s",name_buff));
356 DBUG_DUMP("error_dump", share->state.header.file_version,
357 head_length);
358 my_errno=HA_ERR_NOT_A_TABLE;
359 goto err;
360 }
361 share->options= mi_uint2korr(share->state.header.options);
362 if (share->options &
363 ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
364 HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
365 HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
366 HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
367 HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS |
368 HA_OPTION_PAGE_CHECKSUM))
369 {
370 DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
371 my_errno=HA_ERR_NEW_FILE;
372 goto err;
373 }
374 if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
375 ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
376 {
377 DBUG_PRINT("error", ("table cannot be opened from non-sql layer"));
378 my_errno= HA_ERR_UNSUPPORTED;
379 goto err;
380 }
381 /* Don't call realpath() if the name can't be a link */
382 if (!strcmp(name_buff, org_name) ||
383 my_readlink(index_name, org_name, MYF(0)) == -1)
384 (void) strmov(index_name, org_name);
385 *strrchr(org_name, FN_EXTCHAR)= '\0';
386 (void) fn_format(data_name,org_name,"",MARIA_NAME_DEXT,
387 MY_APPEND_EXT|MY_UNPACK_FILENAME);
388 if (my_is_symlink(data_name))
389 {
390 if (my_realpath(data_name, data_name, MYF(0)))
391 goto err;
392 if (mysys_test_invalid_symlink(data_name))
393 {
394 my_errno= HA_WRONG_CREATE_OPTION;
395 goto err;
396 }
397 share->mode|= O_NOFOLLOW; /* all symlinks are resolved by realpath() */
398 }
399
400 info_length=mi_uint2korr(share->state.header.header_length);
401 base_pos= mi_uint2korr(share->state.header.base_pos);
402
403 /*
404 Allocate space for header information and for data that is too
405 big to keep on stack
406 */
407 if (!(disk_cache= my_malloc(info_length+128, MYF(MY_WME))))
408 {
409 my_errno=ENOMEM;
410 goto err;
411 }
412
413 end_pos=disk_cache+info_length;
414 errpos= 3;
415 if (mysql_file_pread(kfile, disk_cache, info_length, 0L, MYF(MY_NABP)))
416 {
417 _ma_set_fatal_error(share, HA_ERR_CRASHED);
418 goto err;
419 }
420 len=mi_uint2korr(share->state.header.state_info_length);
421 keys= (uint) share->state.header.keys;
422 uniques= (uint) share->state.header.uniques;
423 fulltext_keys= (uint) share->state.header.fulltext_keys;
424 base_key_parts= key_parts= mi_uint2korr(share->state.header.key_parts);
425 unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
426 if (len != MARIA_STATE_INFO_SIZE)
427 {
428 DBUG_PRINT("warning",
429 ("saved_state_info_length: %d state_info_length: %d",
430 len,MARIA_STATE_INFO_SIZE));
431 }
432 share->state_diff_length=len-MARIA_STATE_INFO_SIZE;
433
434 if (!_ma_state_info_read(disk_cache, &share->state))
435 goto err;
436 len= mi_uint2korr(share->state.header.base_info_length);
437 if (len != MARIA_BASE_INFO_SIZE)
438 {
439 DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
440 len,MARIA_BASE_INFO_SIZE));
441 }
442 disk_pos= _ma_base_info_read(disk_cache + base_pos, &share->base);
443 /*
444 Check if old version of Aria file. Version 0 has language
445 stored in header.not_used
446 */
447 file_version= (share->state.header.not_used == 0);
448 if (file_version == 0)
449 share->base.language= share->state.header.not_used;
450
451 share->state.state_length=base_pos;
452 /* For newly opened tables we reset the error-has-been-printed flag */
453 share->state.changed&= ~STATE_CRASHED_PRINTED;
454
455 if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
456 ((share->state.changed & STATE_CRASHED_FLAGS) ||
457 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
458 (my_disable_locking && share->state.open_count))))
459 {
460 DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u "
461 "changed: %u open_count: %u !locking: %d",
462 open_flags, share->state.changed,
463 share->state.open_count, my_disable_locking));
464 my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
465 HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
466 goto err;
467 }
468 if (share->state.open_count)
469 share->open_count_not_zero_on_open= 1;
470
471 /*
472 A transactional table is not usable on this system if:
473 - share->state.create_trid > trnman_get_max_trid()
474 - Critical as trid as stored releativel to create_trid.
475 - uuid is different
476
477 STATE_NOT_MOVABLE is reset when a table is zerofilled
478 (has no LSN's and no trids)
479
480 We can ignore testing uuid if STATE_NOT_MOVABLE is set, as in this
481 case the uuid will be set in _ma_mark_file_changed().
482 */
483 if (share->base.born_transactional &&
484 ((share->state.create_trid > trnman_get_max_trid() &&
485 !maria_in_recovery) ||
486 ((share->state.changed & STATE_NOT_MOVABLE) &&
487 ((!(open_flags & HA_OPEN_IGNORE_MOVED_STATE) &&
488 memcmp(share->base.uuid, maria_uuid, MY_UUID_SIZE))))))
489 {
490 DBUG_PRINT("warning", ("table is moved from another system. uuid_diff: %d create_trid: %lu max_trid: %lu",
491 memcmp(share->base.uuid, maria_uuid,
492 MY_UUID_SIZE) != 0,
493 (ulong) share->state.create_trid,
494 (ulong) trnman_get_max_trid()));
495 if (open_flags & HA_OPEN_FOR_REPAIR)
496 share->state.changed|= STATE_MOVED;
497 else
498 {
499 my_errno= HA_ERR_OLD_FILE;
500 goto err;
501 }
502 }
503
504 /* sanity check */
505 if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
506 {
507 _ma_set_fatal_error(share, HA_ERR_CRASHED);
508 goto err;
509 }
510
511 key_parts+=fulltext_keys*FT_SEGS;
512 if (share->base.max_key_length > _ma_max_key_length() ||
513 keys > MARIA_MAX_KEY || key_parts > MARIA_MAX_KEY * HA_MAX_KEY_SEG)
514 {
515 DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts));
516 my_errno=HA_ERR_UNSUPPORTED;
517 goto err;
518 }
519
520 /* Ensure we have space in the key buffer for transaction id's */
521 if (share->base.born_transactional)
522 share->base.max_key_length= ALIGN_SIZE(share->base.max_key_length +
523 MARIA_MAX_PACK_TRANSID_SIZE);
524
525 /*
526 If page cache is not initialized, then assume we will create the
527 page_cache after the table is opened!
528 This is only used by maria_check to allow it to check/repair tables
529 with different block sizes.
530 */
531 if (share->base.block_size != maria_block_size &&
532 share_buff.pagecache->inited != 0)
533 {
534 DBUG_PRINT("error", ("Wrong block size %u; Expected %u",
535 (uint) share->base.block_size,
536 (uint) maria_block_size));
537 my_errno=HA_ERR_UNSUPPORTED;
538 my_printf_error(my_errno, "Wrong block size %u; Expected %u",
539 MYF(0),
540 (uint) share->base.block_size,
541 (uint) maria_block_size);
542 goto err;
543 }
544
545 /* Correct max_file_length based on length of sizeof(off_t) */
546 max_data_file_length=
547 (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
548 (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
549 (_ma_safe_mul(share->base.pack_reclength,
550 (ulonglong) 1 << (share->base.rec_reflength*8))-1);
551
552 max_key_file_length=
553 _ma_safe_mul(share->base.block_size,
554 ((ulonglong) 1 << (share->base.key_reflength*8))-1);
555#if SIZEOF_OFF_T == 4
556 set_if_smaller(max_data_file_length, INT_MAX32);
557 set_if_smaller(max_key_file_length, INT_MAX32);
558#endif
559 /* For internal temporary tables, max_data_file_length is already set */
560 if (!internal_table || !share->base.max_data_file_length)
561 share->base.max_data_file_length=(my_off_t) max_data_file_length;
562 DBUG_ASSERT(share->base.max_data_file_length);
563 share->base.max_key_file_length=(my_off_t) max_key_file_length;
564
565 if (share->options & HA_OPTION_COMPRESS_RECORD)
566 share->base.max_key_length+=2; /* For safety */
567 /* Add space for node pointer */
568 share->base.max_key_length+= share->base.key_reflength;
569
570 share->unique_file_name.length= strlen(name_buff);
571 share->index_file_name.length= strlen(index_name);
572 share->data_file_name.length= strlen(data_name);
573 share->open_file_name.length= strlen(name);
574 if (!my_multi_malloc(MY_WME,
575 &share,sizeof(*share),
576 &rec_per_key_part,
577 sizeof(double) * key_parts,
578 &nulls_per_key_part,
579 sizeof(long)* key_parts,
580 &share->keyinfo,keys*sizeof(MARIA_KEYDEF),
581 &share->uniqueinfo,uniques*sizeof(MARIA_UNIQUEDEF),
582 &share->keyparts,
583 (key_parts+unique_key_parts+keys+uniques) *
584 sizeof(HA_KEYSEG),
585 &share->columndef,
586 (share->base.fields+1)*sizeof(MARIA_COLUMNDEF),
587 &share->column_nr, share->base.fields*sizeof(uint16),
588 &share->blobs,sizeof(MARIA_BLOB)*share->base.blobs,
589 &share->unique_file_name.str,
590 share->unique_file_name.length+1,
591 &share->index_file_name.str,
592 share->index_file_name.length+1,
593 &share->data_file_name.str,
594 share->data_file_name.length+1,
595 &share->open_file_name.str,
596 share->open_file_name.length+1,
597 &share->state.key_root,keys*sizeof(my_off_t),
598 &share->mmap_lock,sizeof(mysql_rwlock_t),
599 NullS))
600 goto err;
601 errpos= 4;
602
603 *share= share_buff;
604 share->state.rec_per_key_part= rec_per_key_part;
605 share->state.nulls_per_key_part= nulls_per_key_part;
606
607 memcpy((char*) rec_per_key_part,
608 (char*) share_buff.state.rec_per_key_part,
609 sizeof(double)*base_key_parts);
610 memcpy((char*) nulls_per_key_part,
611 (char*) share_buff.state.nulls_per_key_part,
612 sizeof(long)*base_key_parts);
613 memcpy((char*) share->state.key_root,
614 (char*) key_root, sizeof(my_off_t)*keys);
615 strmov(share->unique_file_name.str, name_buff);
616 strmov(share->index_file_name.str, index_name);
617 strmov(share->data_file_name.str, data_name);
618 strmov(share->open_file_name.str, name);
619
620 share->block_size= share->base.block_size; /* Convenience */
621 share->max_index_block_size= share->block_size - KEYPAGE_CHECKSUM_SIZE;
622 share->keypage_header= ((share->base.born_transactional ?
623 LSN_STORE_SIZE + TRANSID_SIZE :
624 0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
625 KEYPAGE_USED_SIZE);
626
627 if (MY_TEST(share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED))
628 {
629 share->keypage_header+= ma_crypt_get_index_page_header_space(share);
630 }
631
632 {
633 HA_KEYSEG *pos=share->keyparts;
634 uint32 ftkey_nr= 1;
635 for (i=0 ; i < keys ; i++)
636 {
637 MARIA_KEYDEF *keyinfo= &share->keyinfo[i];
638 keyinfo->share= share;
639 disk_pos=_ma_keydef_read(disk_pos, keyinfo);
640 keyinfo->key_nr= i;
641
642 /* See ma_delete.cc::underflow() */
643 if (!(keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
644 keyinfo->underflow_block_length= keyinfo->block_length/3;
645 else
646 {
647 /* Packed key, ensure we don't get overflow in underflow() */
648 keyinfo->underflow_block_length=
649 MY_MAX((int) (share->max_index_block_size - keyinfo->maxlength * 3),
650 (int) (share->keypage_header + share->base.key_reflength));
651 set_if_smaller(keyinfo->underflow_block_length,
652 keyinfo->block_length/3);
653 }
654
655 disk_pos_assert(share,
656 disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE,
657 end_pos);
658 if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
659 share->have_rtree= 1;
660 keyinfo->seg=pos;
661 for (j=0 ; j < keyinfo->keysegs; j++,pos++)
662 {
663 disk_pos=_ma_keyseg_read(disk_pos, pos);
664 if (pos->type == HA_KEYTYPE_TEXT ||
665 pos->type == HA_KEYTYPE_VARTEXT1 ||
666 pos->type == HA_KEYTYPE_VARTEXT2)
667 {
668 if (!pos->language)
669 pos->charset=default_charset_info;
670 else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
671 {
672 my_errno=HA_ERR_UNKNOWN_CHARSET;
673 goto err;
674 }
675 }
676 else if (pos->type == HA_KEYTYPE_BINARY)
677 pos->charset= &my_charset_bin;
678 }
679 if (keyinfo->flag & HA_SPATIAL)
680 {
681#ifdef HAVE_SPATIAL
682 uint sp_segs=SPDIMS*2;
683 keyinfo->seg=pos-sp_segs;
684 keyinfo->keysegs--;
685 versioning= 0;
686#else
687 my_errno=HA_ERR_UNSUPPORTED;
688 goto err;
689#endif
690 }
691 else if (keyinfo->flag & HA_FULLTEXT)
692 {
693 versioning= 0;
694 DBUG_ASSERT(fulltext_keys);
695 {
696 uint k;
697 keyinfo->seg=pos;
698 for (k=0; k < FT_SEGS; k++)
699 {
700 *pos= ft_keysegs[k];
701 pos[0].language= pos[-1].language;
702 if (!(pos[0].charset= pos[-1].charset))
703 {
704 _ma_set_fatal_error(share, HA_ERR_CRASHED);
705 goto err;
706 }
707 pos++;
708 }
709 }
710 if (!share->ft2_keyinfo.seg)
711 {
712 memcpy(&share->ft2_keyinfo, keyinfo, sizeof(MARIA_KEYDEF));
713 share->ft2_keyinfo.keysegs=1;
714 share->ft2_keyinfo.flag=0;
715 share->ft2_keyinfo.keylength=
716 share->ft2_keyinfo.minlength=
717 share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
718 share->ft2_keyinfo.seg=pos-1;
719 share->ft2_keyinfo.end=pos;
720 setup_key_functions(& share->ft2_keyinfo);
721 }
722 keyinfo->ftkey_nr= ftkey_nr++;
723 }
724 setup_key_functions(keyinfo);
725 keyinfo->end=pos;
726 pos->type=HA_KEYTYPE_END; /* End */
727 pos->length=share->base.rec_reflength;
728 pos->null_bit=0;
729 pos->flag=0; /* For purify */
730 pos++;
731 }
732 for (i=0 ; i < uniques ; i++)
733 {
734 disk_pos=_ma_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
735 disk_pos_assert(share,
736 disk_pos + share->uniqueinfo[i].keysegs *
737 HA_KEYSEG_SIZE, end_pos);
738 share->uniqueinfo[i].seg=pos;
739 for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
740 {
741 disk_pos=_ma_keyseg_read(disk_pos, pos);
742 if (pos->type == HA_KEYTYPE_TEXT ||
743 pos->type == HA_KEYTYPE_VARTEXT1 ||
744 pos->type == HA_KEYTYPE_VARTEXT2)
745 {
746 if (!pos->language)
747 pos->charset=default_charset_info;
748 else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
749 {
750 my_errno=HA_ERR_UNKNOWN_CHARSET;
751 goto err;
752 }
753 }
754 }
755 share->uniqueinfo[i].end=pos;
756 pos->type=HA_KEYTYPE_END; /* End */
757 pos->null_bit=0;
758 pos->flag=0;
759 pos++;
760 }
761 share->ftkeys= ftkey_nr;
762 }
763 share->data_file_type= share->state.header.data_file_type;
764 share->base_length= (BASE_ROW_HEADER_SIZE +
765 share->base.is_nulls_extended +
766 share->base.null_bytes +
767 share->base.pack_bytes +
768 MY_TEST(share->options & HA_OPTION_CHECKSUM));
769 share->kfile.file= kfile;
770
771 if (open_flags & HA_OPEN_COPY)
772 {
773 /*
774 this instance will be a temporary one used just to create a data
775 file for REPAIR. Don't do logging. This base information will not go
776 to disk.
777 */
778 share->base.born_transactional= FALSE;
779 }
780 if (share->base.born_transactional)
781 {
782 share->page_type= PAGECACHE_LSN_PAGE;
783 if (share->state.create_rename_lsn == LSN_NEEDS_NEW_STATE_LSNS)
784 {
785 /*
786 Was repaired with maria_chk, maybe later maria_pack-ed. Some sort of
787 import into the server. It starts its existence (from the point of
788 view of the server, including server's recovery) now.
789 */
790 if (((open_flags & HA_OPEN_FROM_SQL_LAYER) &&
791 (share->state.changed & STATE_NOT_MOVABLE)) || maria_in_recovery)
792 _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE,
793 trnman_get_min_safe_trid(), TRUE, TRUE);
794 }
795 else if ((!LSN_VALID(share->state.create_rename_lsn) ||
796 !LSN_VALID(share->state.is_of_horizon) ||
797 (cmp_translog_addr(share->state.create_rename_lsn,
798 share->state.is_of_horizon) > 0) ||
799 !LSN_VALID(share->state.skip_redo_lsn) ||
800 (cmp_translog_addr(share->state.create_rename_lsn,
801 share->state.skip_redo_lsn) > 0)) &&
802 !(open_flags & HA_OPEN_FOR_REPAIR))
803 {
804 /*
805 If in Recovery, it will not work. If LSN is invalid and not
806 LSN_NEEDS_NEW_STATE_LSNS, header must be corrupted.
807 In both cases, must repair.
808 */
809 my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
810 HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
811 goto err;
812 }
813 else if (!(open_flags & HA_OPEN_FOR_REPAIR))
814 {
815 /* create_rename_lsn != LSN_NEEDS_NEW_STATE_LSNS */
816 share->state.changed|= STATE_NOT_MOVABLE;
817 }
818 }
819 else
820 share->page_type= PAGECACHE_PLAIN_PAGE;
821 share->now_transactional= share->base.born_transactional;
822
823 /* Use pack_reclength as we don't want to modify base.pack_recklength */
824 if (share->state.header.org_data_file_type == DYNAMIC_RECORD)
825 {
826 /* add bits used to pack data to pack_reclength for faster allocation */
827 share->base.pack_reclength+= share->base.pack_bytes;
828 share->base.extra_rec_buff_size=
829 (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER) + MARIA_SPLIT_LENGTH +
830 MARIA_REC_BUFF_OFFSET);
831 }
832 if (share->data_file_type == COMPRESSED_RECORD)
833 {
834 /* Need some extra bytes for decode_bytes */
835 share->base.extra_rec_buff_size+= 7;
836 }
837 share->base.default_rec_buff_size= MY_MAX(share->base.pack_reclength +
838 share->base.extra_rec_buff_size,
839 share->base.max_key_length);
840
841 disk_pos_assert(share,
842 disk_pos + share->base.fields *MARIA_COLUMNDEF_SIZE,
843 end_pos);
844 for (i= j= 0 ; i < share->base.fields ; i++)
845 {
846 disk_pos=_ma_columndef_read(disk_pos,&share->columndef[i]);
847 share->columndef[i].pack_type=0;
848 share->columndef[i].huff_tree=0;
849 if (share->columndef[i].type == FIELD_BLOB)
850 {
851 share->blobs[j].pack_length=
852 share->columndef[i].length-portable_sizeof_char_ptr;
853 share->blobs[j].offset= share->columndef[i].offset;
854 j++;
855 }
856 if (share->columndef[i].type == FIELD_VARCHAR)
857 share->has_varchar_fields= 1;
858 if (share->columndef[i].null_bit)
859 share->has_null_fields= 1;
860 }
861 share->columndef[i].type= FIELD_LAST; /* End marker */
862 disk_pos= _ma_column_nr_read(disk_pos, share->column_nr,
863 share->base.fields);
864
865 if (MY_TEST(share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED))
866 {
867 if (!(disk_pos= ma_crypt_read(share, disk_pos)))
868 goto err;
869 }
870
871 if ((share->data_file_type == BLOCK_RECORD ||
872 share->data_file_type == COMPRESSED_RECORD))
873 {
874 if (_ma_open_datafile(&info, share))
875 goto err;
876 data_file= info.dfile.file;
877 }
878 errpos= 5;
879
880 if (open_flags & HA_OPEN_DELAY_KEY_WRITE)
881 share->options|= HA_OPTION_DELAY_KEY_WRITE;
882 if (mode == O_RDONLY)
883 share->options|= HA_OPTION_READ_ONLY_DATA;
884 share->is_log_table= FALSE;
885
886 if (open_flags & HA_OPEN_TMP_TABLE ||
887 (share->options & HA_OPTION_TMP_TABLE))
888 {
889 share->options|= HA_OPTION_TMP_TABLE;
890 share->temporary= share->delay_key_write= 1;
891 share->write_flag=MYF(MY_NABP);
892 share->w_locks++; /* We don't have to update status */
893 share->tot_locks++;
894 }
895
896 _ma_set_index_pagecache_callbacks(&share->kfile, share);
897 share->this_process=(ulong) getpid();
898#ifdef MARIA_EXTERNAL_LOCKING
899 share->last_process= share->state.process;
900#endif
901 share->base.key_parts=key_parts;
902 share->base.all_key_parts=key_parts+unique_key_parts;
903 if (!(share->last_version=share->state.version))
904 share->last_version=1; /* Safety */
905 share->rec_reflength=share->base.rec_reflength; /* May be changed */
906 share->base.margin_key_file_length=(share->base.max_key_file_length -
907 (keys ? MARIA_INDEX_BLOCK_MARGIN *
908 share->block_size * keys : 0));
909 my_free(disk_cache);
910 my_free(share_buff.state.rec_per_key_part);
911 disk_cache= 0;
912 share_buff.state.rec_per_key_part= 0;
913
914 _ma_setup_functions(share);
915 max_data_file_length= share->base.max_data_file_length;
916 if ((*share->once_init)(share, info.dfile.file))
917 goto err;
918 if (internal_table)
919 set_if_smaller(share->base.max_data_file_length,
920 max_data_file_length);
921 if (share->now_transactional)
922 {
923 /* Setup initial state that is visible for all */
924 MARIA_STATE_HISTORY_CLOSED *history;
925 if ((history= (MARIA_STATE_HISTORY_CLOSED *)
926 my_hash_search(&maria_stored_state,
927 (uchar*) &share->state.create_rename_lsn, 0)))
928 {
929 /*
930 Move history from hash to share. This is safe to do as we
931 know we are the only one that is using the share.
932 */
933 share->state_history=
934 _ma_remove_not_visible_states(history->state_history, 0, 0);
935 history->state_history= 0;
936 (void) my_hash_delete(&maria_stored_state, (uchar*) history);
937 DBUG_PRINT("info", ("Reading state history. trid: %lu records: %lld",
938 (ulong) share->state_history->trid,
939 share->state_history->state.records));
940 }
941 else
942 {
943 /* Table is not part of any active transaction; Create new history */
944 if (!(share->state_history= (MARIA_STATE_HISTORY *)
945 my_malloc(sizeof(*share->state_history), MYF(MY_WME))))
946 goto err;
947 share->state_history->trid= 0; /* Visible by all */
948 share->state_history->state= share->state.state;
949 share->state_history->next= 0;
950 }
951 }
952 thr_lock_init(&share->lock);
953 mysql_mutex_init(key_SHARE_intern_lock,
954 &share->intern_lock, MY_MUTEX_INIT_FAST);
955 mysql_mutex_init(key_SHARE_key_del_lock,
956 &share->key_del_lock, MY_MUTEX_INIT_FAST);
957 mysql_cond_init(key_SHARE_key_del_cond, &share->key_del_cond, 0);
958 mysql_mutex_init(key_SHARE_close_lock,
959 &share->close_lock, MY_MUTEX_INIT_FAST);
960 for (i=0; i<keys; i++)
961 mysql_rwlock_init(key_KEYINFO_root_lock,
962 &share->keyinfo[i].root_lock);
963 mysql_rwlock_init(key_SHARE_mmap_lock, &share->mmap_lock);
964
965 share->row_is_visible= _ma_row_visible_always;
966 share->lock.get_status= _ma_reset_update_flag;
967 share->lock.start_trans= _ma_start_trans;
968
969 if (!thr_lock_inited)
970 {
971 /* Probably a single threaded program; Don't use concurrent inserts */
972 maria_concurrent_insert=0;
973 }
974 else if (maria_concurrent_insert)
975 {
976 share->non_transactional_concurrent_insert=
977 ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
978 HA_OPTION_COMPRESS_RECORD |
979 HA_OPTION_TEMP_COMPRESS_RECORD)) ||
980 (open_flags & HA_OPEN_TMP_TABLE) ||
981 share->data_file_type == BLOCK_RECORD ||
982 share->have_rtree) ? 0 : 1;
983 if (share->non_transactional_concurrent_insert ||
984 (!share->temporary && share->now_transactional && versioning))
985 {
986 share->lock_key_trees= 1;
987 if (share->data_file_type == BLOCK_RECORD)
988 {
989 DBUG_ASSERT(share->now_transactional);
990 share->have_versioning= 1;
991 share->row_is_visible= _ma_row_visible_transactional_table;
992 share->lock.get_status= _ma_block_get_status;
993 share->lock.check_status= _ma_block_check_status;
994 share->lock.start_trans= _ma_block_start_trans;
995 /*
996 We can for the moment only allow multiple concurrent inserts
997 only if there is no auto-increment key. To lift this restriction
998 we have to:
999 - Extend statement base replication to support auto-increment
1000 intervalls.
1001 - Fix that we allocate auto-increment in intervals and that
1002 it's properly reset if the interval was not used
1003 */
1004 share->lock.allow_multiple_concurrent_insert=
1005 share->base.auto_key == 0;
1006 share->lock_restore_status= 0;
1007 }
1008 else
1009 {
1010 share->row_is_visible= _ma_row_visible_non_transactional_table;
1011 share->lock.get_status= _ma_get_status;
1012 share->lock.copy_status= _ma_copy_status;
1013 share->lock.update_status= _ma_update_status;
1014 share->lock.restore_status= _ma_restore_status;
1015 share->lock.check_status= _ma_check_status;
1016 share->lock_restore_status= _ma_restore_status;
1017 }
1018 }
1019 else if (share->now_transactional)
1020 {
1021 DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
1022 share->lock.start_trans= _ma_block_start_trans_no_versioning;
1023 }
1024 }
1025#ifdef SAFE_MUTEX
1026 if (share->data_file_type == BLOCK_RECORD)
1027 {
1028 /*
1029 We must have internal_lock before bitmap_lock because we call
1030 _ma_flush_table_files() with internal_lock locked.
1031 */
1032 mysql_mutex_lock(&share->intern_lock);
1033 mysql_mutex_lock(&share->bitmap.bitmap_lock);
1034 mysql_mutex_unlock(&share->bitmap.bitmap_lock);
1035 mysql_mutex_unlock(&share->intern_lock);
1036 }
1037#endif
1038 /*
1039 Memory mapping can only be requested after initializing intern_lock.
1040 */
1041 if (open_flags & HA_OPEN_MMAP)
1042 {
1043 info.s= share;
1044 maria_extra(&info, HA_EXTRA_MMAP, 0);
1045 }
1046 }
1047 else
1048 {
1049 share= old_info->s;
1050 if (share->data_file_type == BLOCK_RECORD)
1051 data_file= share->bitmap.file.file; /* Only opened once */
1052 }
1053
1054 if (!(m_info= maria_clone_internal(share, mode, data_file,
1055 internal_table)))
1056 goto err;
1057
1058 if (maria_is_crashed(m_info))
1059 DBUG_PRINT("warning", ("table is crashed: changed: %u",
1060 share->state.changed));
1061
1062 if (!internal_table)
1063 mysql_mutex_unlock(&THR_LOCK_maria);
1064
1065 m_info->open_flags= open_flags;
1066 DBUG_PRINT("exit", ("table: %p name: %s",m_info, name));
1067 DBUG_RETURN(m_info);
1068
1069err:
1070 DBUG_PRINT("error", ("error: %d errpos: %d", my_errno, errpos));
1071 save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
1072 if ((save_errno == HA_ERR_CRASHED) ||
1073 (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
1074 (save_errno == HA_ERR_CRASHED_ON_REPAIR))
1075 {
1076 LEX_STRING tmp_name;
1077 tmp_name.str= (char*) name;
1078 tmp_name.length= strlen(name);
1079 _ma_report_error(save_errno, &tmp_name);
1080 }
1081 switch (errpos) {
1082 case 5:
1083 if (data_file >= 0)
1084 mysql_file_close(data_file, MYF(0));
1085 if (old_info)
1086 break; /* Don't remove open table */
1087 (*share->once_end)(share);
1088 /* fall through */
1089 case 4:
1090 ma_crypt_free(share);
1091 my_free(share);
1092 /* fall through */
1093 case 3:
1094 my_free(disk_cache);
1095 my_free(share_buff.state.rec_per_key_part);
1096 /* fall through */
1097 case 1:
1098 mysql_file_close(kfile,MYF(0));
1099 /* fall through */
1100 case 0:
1101 default:
1102 break;
1103 }
1104 if (!internal_table)
1105 mysql_mutex_unlock(&THR_LOCK_maria);
1106 my_errno= save_errno;
1107 DBUG_RETURN (NULL);
1108} /* maria_open */
1109
1110
1111/*
1112 Reallocate a buffer, if the current buffer is not large enough
1113*/
1114
1115my_bool _ma_alloc_buffer(uchar **old_addr, size_t *old_size,
1116 size_t new_size)
1117{
1118 if (*old_size < new_size)
1119 {
1120 uchar *addr;
1121 if (!(addr= (uchar*) my_realloc(*old_addr, new_size,
1122 MYF(MY_ALLOW_ZERO_PTR))))
1123 return 1;
1124 *old_addr= addr;
1125 *old_size= new_size;
1126 }
1127 return 0;
1128}
1129
1130
1131ulonglong _ma_safe_mul(ulonglong a, ulonglong b)
1132{
1133 ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */
1134
1135 if (!a || max_val / a < b)
1136 return max_val;
1137 return a*b;
1138}
1139
1140 /* Set up functions in structs */
1141
1142void _ma_setup_functions(register MARIA_SHARE *share)
1143{
1144 share->once_init= maria_once_init_dummy;
1145 share->once_end= maria_once_end_dummy;
1146 share->init= maria_scan_init_dummy;
1147 share->end= maria_scan_end_dummy;
1148 share->scan_init= maria_scan_init_dummy;/* Compat. dummy function */
1149 share->scan_end= maria_scan_end_dummy;/* Compat. dummy function */
1150 share->scan_remember_pos= _ma_def_scan_remember_pos;
1151 share->scan_restore_pos= _ma_def_scan_restore_pos;
1152
1153 share->write_record_init= _ma_write_init_default;
1154 share->write_record_abort= _ma_write_abort_default;
1155 share->keypos_to_recpos= _ma_transparent_recpos;
1156 share->recpos_to_keypos= _ma_transparent_recpos;
1157
1158 switch (share->data_file_type) {
1159 case COMPRESSED_RECORD:
1160 share->read_record= _ma_read_pack_record;
1161 share->scan= _ma_read_rnd_pack_record;
1162 share->once_init= _ma_once_init_pack_row;
1163 share->once_end= _ma_once_end_pack_row;
1164 /*
1165 Calculate checksum according to data in the original, not compressed,
1166 row.
1167 */
1168 if (share->state.header.org_data_file_type == STATIC_RECORD &&
1169 ! (share->options & HA_OPTION_NULL_FIELDS))
1170 share->calc_checksum= _ma_static_checksum;
1171 else
1172 share->calc_checksum= _ma_checksum;
1173 share->calc_write_checksum= share->calc_checksum;
1174 break;
1175 case DYNAMIC_RECORD:
1176 share->read_record= _ma_read_dynamic_record;
1177 share->scan= _ma_read_rnd_dynamic_record;
1178 share->delete_record= _ma_delete_dynamic_record;
1179 share->compare_record= _ma_cmp_dynamic_record;
1180 share->compare_unique= _ma_cmp_dynamic_unique;
1181 share->calc_checksum= share->calc_write_checksum= _ma_checksum;
1182 if (share->base.blobs)
1183 {
1184 share->update_record= _ma_update_blob_record;
1185 share->write_record= _ma_write_blob_record;
1186 }
1187 else
1188 {
1189 share->write_record= _ma_write_dynamic_record;
1190 share->update_record= _ma_update_dynamic_record;
1191 }
1192 break;
1193 case STATIC_RECORD:
1194 share->read_record= _ma_read_static_record;
1195 share->scan= _ma_read_rnd_static_record;
1196 share->delete_record= _ma_delete_static_record;
1197 share->compare_record= _ma_cmp_static_record;
1198 share->update_record= _ma_update_static_record;
1199 share->write_record= _ma_write_static_record;
1200 share->compare_unique= _ma_cmp_static_unique;
1201 share->keypos_to_recpos= _ma_static_keypos_to_recpos;
1202 share->recpos_to_keypos= _ma_static_recpos_to_keypos;
1203 if (share->state.header.org_data_file_type == STATIC_RECORD &&
1204 ! (share->options & HA_OPTION_NULL_FIELDS))
1205 share->calc_checksum= _ma_static_checksum;
1206 else
1207 share->calc_checksum= _ma_checksum;
1208 break;
1209 case NO_RECORD:
1210 share->read_record= _ma_read_no_record;
1211 share->scan= _ma_read_rnd_no_record;
1212 share->delete_record= _ma_delete_no_record;
1213 share->update_record= _ma_update_no_record;
1214 share->write_record= _ma_write_no_record;
1215 share->recpos_to_keypos= _ma_no_keypos_to_recpos;
1216 share->keypos_to_recpos= _ma_no_keypos_to_recpos;
1217
1218 /* Abort if following functions are called */
1219 share->compare_record= 0;
1220 share->compare_unique= 0;
1221 share->calc_checksum= 0;
1222 break;
1223 case BLOCK_RECORD:
1224 share->once_init= _ma_once_init_block_record;
1225 share->once_end= _ma_once_end_block_record;
1226 share->init= _ma_init_block_record;
1227 share->end= _ma_end_block_record;
1228 share->write_record_init= _ma_write_init_block_record;
1229 share->write_record_abort= _ma_write_abort_block_record;
1230 share->scan_init= _ma_scan_init_block_record;
1231 share->scan_end= _ma_scan_end_block_record;
1232 share->scan= _ma_scan_block_record;
1233 share->scan_remember_pos= _ma_scan_remember_block_record;
1234 share->scan_restore_pos= _ma_scan_restore_block_record;
1235 share->read_record= _ma_read_block_record;
1236 share->delete_record= _ma_delete_block_record;
1237 share->compare_record= _ma_compare_block_record;
1238 share->update_record= _ma_update_block_record;
1239 share->write_record= _ma_write_block_record;
1240 share->compare_unique= _ma_cmp_block_unique;
1241 share->calc_checksum= _ma_checksum;
1242 share->keypos_to_recpos= _ma_transaction_keypos_to_recpos;
1243 share->recpos_to_keypos= _ma_transaction_recpos_to_keypos;
1244
1245 /*
1246 write_block_record() will calculate the checksum; Tell maria_write()
1247 that it doesn't have to do this.
1248 */
1249 share->calc_write_checksum= 0;
1250 break;
1251 }
1252 share->file_read= _ma_nommap_pread;
1253 share->file_write= _ma_nommap_pwrite;
1254 share->calc_check_checksum= share->calc_checksum;
1255
1256 if (!(share->options & HA_OPTION_CHECKSUM) &&
1257 share->data_file_type != COMPRESSED_RECORD)
1258 share->calc_checksum= share->calc_write_checksum= 0;
1259 return;
1260}
1261
1262
1263static void setup_key_functions(register MARIA_KEYDEF *keyinfo)
1264{
1265 if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
1266 {
1267#ifdef HAVE_RTREE_KEYS
1268 keyinfo->ck_insert = maria_rtree_insert;
1269 keyinfo->ck_delete = maria_rtree_delete;
1270#else
1271 DBUG_ASSERT(0); /* maria_open should check it never happens */
1272#endif
1273 }
1274 else
1275 {
1276 keyinfo->ck_insert = _ma_ck_write;
1277 keyinfo->ck_delete = _ma_ck_delete;
1278 }
1279 if (keyinfo->flag & HA_SPATIAL)
1280 keyinfo->make_key= _ma_sp_make_key;
1281 else
1282 keyinfo->make_key= _ma_make_key;
1283
1284 if (keyinfo->flag & HA_BINARY_PACK_KEY)
1285 { /* Simple prefix compression */
1286 keyinfo->bin_search= _ma_seq_search;
1287 keyinfo->get_key= _ma_get_binary_pack_key;
1288 keyinfo->skip_key= _ma_skip_binary_pack_key;
1289 keyinfo->pack_key= _ma_calc_bin_pack_key_length;
1290 keyinfo->store_key= _ma_store_bin_pack_key;
1291 }
1292 else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
1293 {
1294 keyinfo->get_key= _ma_get_pack_key;
1295 keyinfo->skip_key= _ma_skip_pack_key;
1296 if (keyinfo->seg[0].flag & HA_PACK_KEY)
1297 { /* Prefix compression */
1298 /*
1299 _ma_prefix_search() compares end-space against ASCII blank (' ').
1300 It cannot be used for character sets, that do not encode the
1301 blank character like ASCII does. UCS2 is an example. All
1302 character sets with a fixed width > 1 or a mimimum width > 1
1303 cannot represent blank like ASCII does. In these cases we have
1304 to use _ma_seq_search() for the search.
1305 */
1306 if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
1307 (keyinfo->seg->flag & HA_NULL_PART) ||
1308 keyinfo->seg->charset->mbminlen > 1)
1309 keyinfo->bin_search= _ma_seq_search;
1310 else
1311 keyinfo->bin_search= _ma_prefix_search;
1312 keyinfo->pack_key= _ma_calc_var_pack_key_length;
1313 keyinfo->store_key= _ma_store_var_pack_key;
1314 }
1315 else
1316 {
1317 keyinfo->bin_search= _ma_seq_search;
1318 keyinfo->pack_key= _ma_calc_var_key_length; /* Variable length key */
1319 keyinfo->store_key= _ma_store_static_key;
1320 }
1321 }
1322 else
1323 {
1324 keyinfo->bin_search= _ma_bin_search;
1325 keyinfo->get_key= _ma_get_static_key;
1326 keyinfo->skip_key= _ma_skip_static_key;
1327 keyinfo->pack_key= _ma_calc_static_key_length;
1328 keyinfo->store_key= _ma_store_static_key;
1329 }
1330
1331 /* set keyinfo->write_comp_flag */
1332 if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
1333 keyinfo->write_comp_flag=SEARCH_BIGGER; /* Put after same key */
1334 else if (keyinfo->flag & ( HA_NOSAME | HA_FULLTEXT))
1335 {
1336 keyinfo->write_comp_flag= SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
1337 if (keyinfo->flag & HA_NULL_ARE_EQUAL)
1338 keyinfo->write_comp_flag|= SEARCH_NULL_ARE_EQUAL;
1339 }
1340 else
1341 keyinfo->write_comp_flag= SEARCH_SAME; /* Keys in rec-pos order */
1342 keyinfo->write_comp_flag|= SEARCH_INSERT;
1343 return;
1344}
1345
1346
1347/**
1348 @brief Function to save and store the header in the index file (.MYI)
1349
1350 Operates under MARIA_SHARE::intern_lock if requested.
1351 Sets MARIA_SHARE::MARIA_STATE_INFO::is_of_horizon if transactional table.
1352 Then calls _ma_state_info_write_sub().
1353
1354 @param share table
1355 @param pWrite bitmap: if 1 (MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)
1356 is set my_pwrite() is used otherwise my_write();
1357 if 2 (MA_STATE_INFO_WRITE_FULL_INFO) is set, info
1358 about keys is written (should only be needed
1359 after ALTER TABLE ENABLE/DISABLE KEYS, and
1360 REPAIR/OPTIMIZE); if 4 (MA_STATE_INFO_WRITE_LOCK)
1361 is set, MARIA_SHARE::intern_lock is taken.
1362
1363 @return Operation status
1364 @retval 0 OK
1365 @retval 1 Error
1366*/
1367
1368uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite)
1369{
1370 uint res;
1371 if (share->options & HA_OPTION_READ_ONLY_DATA)
1372 return 0;
1373
1374 if (pWrite & MA_STATE_INFO_WRITE_LOCK)
1375 mysql_mutex_lock(&share->intern_lock);
1376 else if (maria_multi_threaded)
1377 mysql_mutex_assert_owner(&share->intern_lock);
1378 if (share->base.born_transactional && translog_status == TRANSLOG_OK &&
1379 !maria_in_recovery)
1380 {
1381 /*
1382 In a recovery, we want to set is_of_horizon to the LSN of the last
1383 record executed by Recovery, not the current EOF of the log (which
1384 is too new). Recovery does it by itself.
1385 */
1386 share->state.is_of_horizon= translog_get_horizon();
1387 DBUG_PRINT("info", ("is_of_horizon set to LSN " LSN_FMT,
1388 LSN_IN_PARTS(share->state.is_of_horizon)));
1389 }
1390 res= _ma_state_info_write_sub(share->kfile.file, &share->state, pWrite);
1391 if (pWrite & MA_STATE_INFO_WRITE_LOCK)
1392 mysql_mutex_unlock(&share->intern_lock);
1393 /* If open_count != 0 we have to write the state again at close */
1394 share->changed= share->state.open_count != 0;
1395 return res;
1396}
1397
1398
1399/**
1400 @brief Function to save and store the header in the index file (.MYI).
1401
1402 Shortcut to use instead of _ma_state_info_write() when appropriate.
1403
1404 @param file descriptor of the index file to write
1405 @param state state information to write to the file
1406 @param pWrite bitmap: if 1 (MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)
1407 is set my_pwrite() is used otherwise my_write();
1408 if 2 (MA_STATE_INFO_WRITE_FULL_INFO) is set, info
1409 about keys is written (should only be needed
1410 after ALTER TABLE ENABLE/DISABLE KEYS, and
1411 REPAIR/OPTIMIZE).
1412
1413 @notes
1414 For transactional multiuser tables, this function is called
1415 with intern_lock & translog_lock or when the last thread who
1416 is using the table is closing it.
1417 Because of the translog_lock we don't need to have a lock on
1418 key_del_lock.
1419
1420 @return Operation status
1421 @retval 0 OK
1422 @retval 1 Error
1423*/
1424
1425uint _ma_state_info_write_sub(File file, MARIA_STATE_INFO *state, uint pWrite)
1426{
1427 uchar buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
1428 uchar *ptr=buff;
1429 uint i, keys= (uint) state->header.keys;
1430 size_t res;
1431 DBUG_ENTER("_ma_state_info_write_sub");
1432 DBUG_PRINT("info", ("Records: %lld", state->state.records));
1433
1434 memcpy(ptr,&state->header,sizeof(state->header));
1435 ptr+=sizeof(state->header);
1436
1437 /* open_count must be first because of _ma_mark_file_changed ! */
1438 mi_int2store(ptr,state->open_count); ptr+= 2;
1439 /* changed must be second, because of _ma_mark_file_crashed */
1440 mi_int2store(ptr,state->changed); ptr+= 2;
1441
1442 /*
1443 If you change the offset of these LSNs, note that some functions do a
1444 direct write of them without going through this function.
1445 */
1446 lsn_store(ptr, state->create_rename_lsn); ptr+= LSN_STORE_SIZE;
1447 lsn_store(ptr, state->is_of_horizon); ptr+= LSN_STORE_SIZE;
1448 lsn_store(ptr, state->skip_redo_lsn); ptr+= LSN_STORE_SIZE;
1449 mi_rowstore(ptr,state->state.records); ptr+= 8;
1450 mi_rowstore(ptr,state->state.del); ptr+= 8;
1451 mi_rowstore(ptr,state->split); ptr+= 8;
1452 mi_sizestore(ptr,state->dellink); ptr+= 8;
1453 mi_sizestore(ptr,state->first_bitmap_with_space); ptr+= 8;
1454 mi_sizestore(ptr,state->state.key_file_length); ptr+= 8;
1455 mi_sizestore(ptr,state->state.data_file_length); ptr+= 8;
1456 mi_sizestore(ptr,state->state.empty); ptr+= 8;
1457 mi_sizestore(ptr,state->state.key_empty); ptr+= 8;
1458 mi_int8store(ptr,state->auto_increment); ptr+= 8;
1459 mi_int8store(ptr,(ulonglong) state->state.checksum); ptr+= 8;
1460 mi_int8store(ptr,state->create_trid); ptr+= 8;
1461 mi_int4store(ptr,state->status); ptr+= 4;
1462 mi_int4store(ptr,state->update_count); ptr+= 4;
1463 *ptr++= state->sortkey;
1464 *ptr++= 0; /* Reserved */
1465 ptr+= state->state_diff_length;
1466
1467 for (i=0; i < keys; i++)
1468 {
1469 mi_sizestore(ptr,state->key_root[i]); ptr+= 8;
1470 }
1471 mi_sizestore(ptr,state->key_del); ptr+= 8;
1472 if (pWrite & MA_STATE_INFO_WRITE_FULL_INFO) /* From maria_chk */
1473 {
1474 uint key_parts= mi_uint2korr(state->header.key_parts);
1475 mi_int4store(ptr,state->sec_index_changed); ptr+= 4;
1476 mi_int4store(ptr,state->sec_index_used); ptr+= 4;
1477 mi_int4store(ptr,state->version); ptr+= 4;
1478 mi_int8store(ptr,state->key_map); ptr+= 8;
1479 mi_int8store(ptr,(ulonglong) state->create_time); ptr+= 8;
1480 mi_int8store(ptr,(ulonglong) state->recover_time); ptr+= 8;
1481 mi_int8store(ptr,(ulonglong) state->check_time); ptr+= 8;
1482 mi_sizestore(ptr, state->records_at_analyze); ptr+= 8;
1483 /* reserve place for some information per key */
1484 bzero(ptr, keys*4); ptr+= keys*4;
1485 for (i=0 ; i < key_parts ; i++)
1486 {
1487 float8store(ptr, state->rec_per_key_part[i]); ptr+= 8;
1488 mi_int4store(ptr, state->nulls_per_key_part[i]); ptr+= 4;
1489 }
1490 }
1491
1492 res= (pWrite & MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET) ?
1493 mysql_file_pwrite(file, buff, (size_t) (ptr-buff), 0L,
1494 MYF(MY_NABP | MY_THREADSAFE)) :
1495 mysql_file_write(file, buff, (size_t) (ptr-buff),
1496 MYF(MY_NABP));
1497 DBUG_RETURN(res != 0);
1498}
1499
1500
1501static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state)
1502{
1503 uint i,keys,key_parts;
1504 DBUG_ENTER("_ma_state_info_read");
1505
1506 memcpy(&state->header,ptr, sizeof(state->header));
1507 ptr+= sizeof(state->header);
1508 keys= (uint) state->header.keys;
1509 key_parts= mi_uint2korr(state->header.key_parts);
1510
1511 /* Allocate memory for key parts if not already done */
1512 if (!state->rec_per_key_part &&
1513 !my_multi_malloc(MY_WME,
1514 &state->rec_per_key_part,
1515 sizeof(*state->rec_per_key_part) * key_parts,
1516 &state->nulls_per_key_part,
1517 sizeof(*state->nulls_per_key_part) * key_parts,
1518 NullS))
1519 DBUG_RETURN(0);
1520
1521 state->open_count = mi_uint2korr(ptr); ptr+= 2;
1522 state->changed= mi_uint2korr(ptr); ptr+= 2;
1523 state->create_rename_lsn= lsn_korr(ptr); ptr+= LSN_STORE_SIZE;
1524 state->is_of_horizon= lsn_korr(ptr); ptr+= LSN_STORE_SIZE;
1525 state->skip_redo_lsn= lsn_korr(ptr); ptr+= LSN_STORE_SIZE;
1526 state->state.records= mi_rowkorr(ptr); ptr+= 8;
1527 state->state.del = mi_rowkorr(ptr); ptr+= 8;
1528 state->split = mi_rowkorr(ptr); ptr+= 8;
1529 state->dellink= mi_sizekorr(ptr); ptr+= 8;
1530 state->first_bitmap_with_space= mi_sizekorr(ptr); ptr+= 8;
1531 state->state.key_file_length = mi_sizekorr(ptr); ptr+= 8;
1532 state->state.data_file_length= mi_sizekorr(ptr); ptr+= 8;
1533 state->state.empty = mi_sizekorr(ptr); ptr+= 8;
1534 state->state.key_empty= mi_sizekorr(ptr); ptr+= 8;
1535 state->auto_increment=mi_uint8korr(ptr); ptr+= 8;
1536 state->state.checksum=(ha_checksum) mi_uint8korr(ptr);ptr+= 8;
1537 state->create_trid= mi_uint8korr(ptr); ptr+= 8;
1538 state->status = mi_uint4korr(ptr); ptr+= 4;
1539 state->update_count=mi_uint4korr(ptr); ptr+= 4;
1540 state->sortkey= (uint) *ptr++;
1541 ptr++; /* reserved */
1542
1543 ptr+= state->state_diff_length;
1544
1545 for (i=0; i < keys; i++)
1546 {
1547 state->key_root[i]= mi_sizekorr(ptr); ptr+= 8;
1548 }
1549 state->key_del= mi_sizekorr(ptr); ptr+= 8;
1550 state->sec_index_changed = mi_uint4korr(ptr); ptr+= 4;
1551 state->sec_index_used = mi_uint4korr(ptr); ptr+= 4;
1552 state->version = mi_uint4korr(ptr); ptr+= 4;
1553 state->key_map = mi_uint8korr(ptr); ptr+= 8;
1554 state->create_time = (time_t) mi_sizekorr(ptr); ptr+= 8;
1555 state->recover_time =(time_t) mi_sizekorr(ptr); ptr+= 8;
1556 state->check_time = (time_t) mi_sizekorr(ptr); ptr+= 8;
1557 state->records_at_analyze= mi_sizekorr(ptr); ptr+= 8;
1558 ptr+= keys * 4; /* Skip reserved bytes */
1559 for (i=0 ; i < key_parts ; i++)
1560 {
1561 float8get(state->rec_per_key_part[i], ptr); ptr+= 8;
1562 state->nulls_per_key_part[i]= mi_uint4korr(ptr); ptr+= 4;
1563 }
1564
1565 DBUG_PRINT("info", ("Records: %lld", state->state.records));
1566 DBUG_RETURN(ptr);
1567}
1568
1569
1570/**
1571 @brief Fills the state by reading its copy on disk.
1572
1573 Should not be called for transactional tables, as their state on disk is
1574 rarely current and so is often misleading for a reader.
1575 Does nothing in single user mode.
1576
1577 @param file file to read from
1578 @param state state which will be filled
1579*/
1580
1581uint _ma_state_info_read_dsk(File file __attribute__((unused)),
1582 MARIA_STATE_INFO *state __attribute__((unused)))
1583{
1584#ifdef MARIA_EXTERNAL_LOCKING
1585 uchar buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
1586
1587 /* trick to detect transactional tables */
1588 DBUG_ASSERT(state->create_rename_lsn == LSN_IMPOSSIBLE);
1589 if (!maria_single_user)
1590 {
1591 if (mysql_file_pread(file, buff, state->state_length, 0L, MYF(MY_NABP)))
1592 return 1;
1593 _ma_state_info_read(buff, state);
1594 }
1595#endif
1596 return 0;
1597}
1598
1599
1600/****************************************************************************
1601** store and read of MARIA_BASE_INFO
1602****************************************************************************/
1603
1604uint _ma_base_info_write(File file, MARIA_BASE_INFO *base)
1605{
1606 uchar buff[MARIA_BASE_INFO_SIZE], *ptr=buff;
1607
1608 bmove(ptr, maria_uuid, MY_UUID_SIZE);
1609 ptr+= MY_UUID_SIZE;
1610 mi_sizestore(ptr,base->keystart); ptr+= 8;
1611 mi_sizestore(ptr,base->max_data_file_length); ptr+= 8;
1612 mi_sizestore(ptr,base->max_key_file_length); ptr+= 8;
1613 mi_rowstore(ptr,base->records); ptr+= 8;
1614 mi_rowstore(ptr,base->reloc); ptr+= 8;
1615 mi_int4store(ptr,base->mean_row_length); ptr+= 4;
1616 mi_int4store(ptr,base->reclength); ptr+= 4;
1617 mi_int4store(ptr,base->pack_reclength); ptr+= 4;
1618 mi_int4store(ptr,base->min_pack_length); ptr+= 4;
1619 mi_int4store(ptr,base->max_pack_length); ptr+= 4;
1620 mi_int4store(ptr,base->min_block_length); ptr+= 4;
1621 mi_int2store(ptr,base->fields); ptr+= 2;
1622 mi_int2store(ptr,base->fixed_not_null_fields); ptr+= 2;
1623 mi_int2store(ptr,base->fixed_not_null_fields_length); ptr+= 2;
1624 mi_int2store(ptr,base->max_field_lengths); ptr+= 2;
1625 mi_int2store(ptr,base->pack_fields); ptr+= 2;
1626 mi_int2store(ptr,base->extra_options) ptr+= 2;
1627 mi_int2store(ptr,base->null_bytes); ptr+= 2;
1628 mi_int2store(ptr,base->original_null_bytes); ptr+= 2;
1629 mi_int2store(ptr,base->field_offsets); ptr+= 2;
1630 mi_int2store(ptr,base->language); ptr+= 2;
1631 mi_int2store(ptr,base->block_size); ptr+= 2;
1632 *ptr++= base->rec_reflength;
1633 *ptr++= base->key_reflength;
1634 *ptr++= base->keys;
1635 *ptr++= base->auto_key;
1636 *ptr++= base->born_transactional;
1637 *ptr++= 0; /* Reserved */
1638 mi_int2store(ptr,base->pack_bytes); ptr+= 2;
1639 mi_int2store(ptr,base->blobs); ptr+= 2;
1640 mi_int2store(ptr,base->max_key_block_length); ptr+= 2;
1641 mi_int2store(ptr,base->max_key_length); ptr+= 2;
1642 mi_int2store(ptr,base->extra_alloc_bytes); ptr+= 2;
1643 *ptr++= base->extra_alloc_procent;
1644 bzero(ptr,16); ptr+= 16; /* extra */
1645 DBUG_ASSERT((ptr - buff) == MARIA_BASE_INFO_SIZE);
1646 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1647}
1648
1649
1650static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base)
1651{
1652 bmove(base->uuid, ptr, MY_UUID_SIZE); ptr+= MY_UUID_SIZE;
1653 base->keystart= mi_sizekorr(ptr); ptr+= 8;
1654 base->max_data_file_length= mi_sizekorr(ptr); ptr+= 8;
1655 base->max_key_file_length= mi_sizekorr(ptr); ptr+= 8;
1656 base->records= (ha_rows) mi_sizekorr(ptr); ptr+= 8;
1657 base->reloc= (ha_rows) mi_sizekorr(ptr); ptr+= 8;
1658 base->mean_row_length= mi_uint4korr(ptr); ptr+= 4;
1659 base->reclength= mi_uint4korr(ptr); ptr+= 4;
1660 base->pack_reclength= mi_uint4korr(ptr); ptr+= 4;
1661 base->min_pack_length= mi_uint4korr(ptr); ptr+= 4;
1662 base->max_pack_length= mi_uint4korr(ptr); ptr+= 4;
1663 base->min_block_length= mi_uint4korr(ptr); ptr+= 4;
1664 base->fields= mi_uint2korr(ptr); ptr+= 2;
1665 base->fixed_not_null_fields= mi_uint2korr(ptr); ptr+= 2;
1666 base->fixed_not_null_fields_length= mi_uint2korr(ptr);ptr+= 2;
1667 base->max_field_lengths= mi_uint2korr(ptr); ptr+= 2;
1668 base->pack_fields= mi_uint2korr(ptr); ptr+= 2;
1669 base->extra_options= mi_uint2korr(ptr); ptr+= 2;
1670 base->null_bytes= mi_uint2korr(ptr); ptr+= 2;
1671 base->original_null_bytes= mi_uint2korr(ptr); ptr+= 2;
1672 base->field_offsets= mi_uint2korr(ptr); ptr+= 2;
1673 base->language= mi_uint2korr(ptr); ptr+= 2;
1674 base->block_size= mi_uint2korr(ptr); ptr+= 2;
1675
1676 base->rec_reflength= *ptr++;
1677 base->key_reflength= *ptr++;
1678 base->keys= *ptr++;
1679 base->auto_key= *ptr++;
1680 base->born_transactional= *ptr++;
1681 ptr++;
1682 base->pack_bytes= mi_uint2korr(ptr); ptr+= 2;
1683 base->blobs= mi_uint2korr(ptr); ptr+= 2;
1684 base->max_key_block_length= mi_uint2korr(ptr); ptr+= 2;
1685 base->max_key_length= mi_uint2korr(ptr); ptr+= 2;
1686 base->extra_alloc_bytes= mi_uint2korr(ptr); ptr+= 2;
1687 base->extra_alloc_procent= *ptr++;
1688 ptr+= 16;
1689 return ptr;
1690}
1691
1692/*--------------------------------------------------------------------------
1693 maria_keydef
1694---------------------------------------------------------------------------*/
1695
1696my_bool _ma_keydef_write(File file, MARIA_KEYDEF *keydef)
1697{
1698 uchar buff[MARIA_KEYDEF_SIZE];
1699 uchar *ptr=buff;
1700
1701 *ptr++= (uchar) keydef->keysegs;
1702 *ptr++= keydef->key_alg; /* Rtree or Btree */
1703 mi_int2store(ptr,keydef->flag); ptr+= 2;
1704 mi_int2store(ptr,keydef->block_length); ptr+= 2;
1705 mi_int2store(ptr,keydef->keylength); ptr+= 2;
1706 mi_int2store(ptr,keydef->minlength); ptr+= 2;
1707 mi_int2store(ptr,keydef->maxlength); ptr+= 2;
1708 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1709}
1710
1711uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef)
1712{
1713 keydef->keysegs = (uint) *ptr++;
1714 keydef->key_alg = *ptr++; /* Rtree or Btree */
1715
1716 keydef->flag = mi_uint2korr(ptr); ptr+= 2;
1717 keydef->block_length = mi_uint2korr(ptr); ptr+= 2;
1718 keydef->keylength = mi_uint2korr(ptr); ptr+= 2;
1719 keydef->minlength = mi_uint2korr(ptr); ptr+= 2;
1720 keydef->maxlength = mi_uint2korr(ptr); ptr+= 2;
1721 keydef->version = 0; /* Not saved */
1722 keydef->parser = &ft_default_parser;
1723 keydef->ftkey_nr = 0;
1724 return ptr;
1725}
1726
1727/***************************************************************************
1728** maria_keyseg
1729***************************************************************************/
1730
1731my_bool _ma_keyseg_write(File file, const HA_KEYSEG *keyseg)
1732{
1733 uchar buff[HA_KEYSEG_SIZE];
1734 uchar *ptr=buff;
1735 ulong pos;
1736
1737 *ptr++= keyseg->type;
1738 *ptr++= keyseg->language & 0xFF; /* Collation ID, low byte */
1739 *ptr++= keyseg->null_bit;
1740 *ptr++= keyseg->bit_start;
1741 *ptr++= keyseg->language >> 8; /* Collation ID, high byte */
1742 *ptr++= keyseg->bit_length;
1743 mi_int2store(ptr,keyseg->flag); ptr+= 2;
1744 mi_int2store(ptr,keyseg->length); ptr+= 2;
1745 mi_int4store(ptr,keyseg->start); ptr+= 4;
1746 pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
1747 mi_int4store(ptr, pos);
1748 ptr+=4;
1749
1750 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1751}
1752
1753
1754uchar *_ma_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
1755{
1756 keyseg->type = *ptr++;
1757 keyseg->language = *ptr++;
1758 keyseg->null_bit = *ptr++;
1759 keyseg->bit_start = *ptr++;
1760 keyseg->language += ((uint16) (*ptr++)) << 8;
1761 keyseg->bit_length = *ptr++;
1762 keyseg->flag = mi_uint2korr(ptr); ptr+= 2;
1763 keyseg->length = mi_uint2korr(ptr); ptr+= 2;
1764 keyseg->start = mi_uint4korr(ptr); ptr+= 4;
1765 keyseg->null_pos = mi_uint4korr(ptr); ptr+= 4;
1766 keyseg->charset=0; /* Will be filled in later */
1767 if (keyseg->null_bit)
1768 keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
1769 else
1770 {
1771 keyseg->bit_pos= (uint16)keyseg->null_pos;
1772 keyseg->null_pos= 0;
1773 }
1774 return ptr;
1775}
1776
1777/*--------------------------------------------------------------------------
1778 maria_uniquedef
1779---------------------------------------------------------------------------*/
1780
1781my_bool _ma_uniquedef_write(File file, MARIA_UNIQUEDEF *def)
1782{
1783 uchar buff[MARIA_UNIQUEDEF_SIZE];
1784 uchar *ptr=buff;
1785
1786 mi_int2store(ptr,def->keysegs); ptr+=2;
1787 *ptr++= (uchar) def->key;
1788 *ptr++ = (uchar) def->null_are_equal;
1789
1790 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1791}
1792
1793uchar *_ma_uniquedef_read(uchar *ptr, MARIA_UNIQUEDEF *def)
1794{
1795 def->keysegs = mi_uint2korr(ptr);
1796 def->key = ptr[2];
1797 def->null_are_equal=ptr[3];
1798 return ptr+4; /* 1 extra uchar */
1799}
1800
1801/***************************************************************************
1802** MARIA_COLUMNDEF
1803***************************************************************************/
1804
1805my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef)
1806{
1807 uchar buff[MARIA_COLUMNDEF_SIZE];
1808 uchar *ptr=buff;
1809 uint low_offset= (uint) (columndef->offset & 0xffff);
1810 uint high_offset= (uint) (columndef->offset >> 16);
1811
1812 mi_int2store(ptr,(ulong) columndef->column_nr); ptr+= 2;
1813 mi_int2store(ptr, low_offset); ptr+= 2;
1814 mi_int2store(ptr,columndef->type); ptr+= 2;
1815 mi_int2store(ptr,columndef->length); ptr+= 2;
1816 mi_int2store(ptr,columndef->fill_length); ptr+= 2;
1817 mi_int2store(ptr,columndef->null_pos); ptr+= 2;
1818 mi_int2store(ptr,columndef->empty_pos); ptr+= 2;
1819
1820 (*ptr++)= columndef->null_bit;
1821 (*ptr++)= columndef->empty_bit;
1822 mi_int2store(ptr, high_offset); ptr+= 2;
1823 ptr[0]= ptr[1]= 0; ptr+= 2; /* For future */
1824 return mysql_file_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1825}
1826
1827uchar *_ma_columndef_read(uchar *ptr, MARIA_COLUMNDEF *columndef)
1828{
1829 uint high_offset;
1830 columndef->column_nr= mi_uint2korr(ptr); ptr+= 2;
1831 columndef->offset= mi_uint2korr(ptr); ptr+= 2;
1832 columndef->type= mi_sint2korr(ptr); ptr+= 2;
1833 columndef->length= mi_uint2korr(ptr); ptr+= 2;
1834 columndef->fill_length= mi_uint2korr(ptr); ptr+= 2;
1835 columndef->null_pos= mi_uint2korr(ptr); ptr+= 2;
1836 columndef->empty_pos= mi_uint2korr(ptr); ptr+= 2;
1837 columndef->null_bit= (uint8) *ptr++;
1838 columndef->empty_bit= (uint8) *ptr++;
1839 high_offset= mi_uint2korr(ptr); ptr+= 2;
1840 columndef->offset|= ((ulong) high_offset << 16);
1841 ptr+= 2;
1842 return ptr;
1843}
1844
1845my_bool _ma_column_nr_write(File file, uint16 *offsets, uint columns)
1846{
1847 uchar *buff, *ptr, *end;
1848 size_t size= columns*2;
1849 my_bool res;
1850
1851 if (!(buff= (uchar*) my_alloca(size)))
1852 return 1;
1853 for (ptr= buff, end= ptr + size; ptr < end ; ptr+= 2, offsets++)
1854 int2store(ptr, *offsets);
1855 res= mysql_file_write(file, buff, size, MYF(MY_NABP)) != 0;
1856 my_afree(buff);
1857 return res;
1858}
1859
1860
1861uchar *_ma_column_nr_read(uchar *ptr, uint16 *offsets, uint columns)
1862{
1863 uchar *end;
1864 size_t size= columns*2;
1865 for (end= ptr + size; ptr < end ; ptr+=2, offsets++)
1866 *offsets= uint2korr(ptr);
1867 return ptr;
1868}
1869
1870/**
1871 @brief Set callbacks for data pages
1872
1873 @note
1874 We don't use pagecache_file_init here, as we want to keep the
1875 code readable
1876*/
1877
1878void _ma_set_data_pagecache_callbacks(PAGECACHE_FILE *file,
1879 MARIA_SHARE *share)
1880{
1881 pagecache_file_set_null_hooks(file);
1882 file->callback_data= (uchar*) share;
1883 file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
1884 file->post_write_hook= maria_page_write_failure;
1885
1886 if (share->temporary)
1887 {
1888 file->post_read_hook= &maria_page_crc_check_none;
1889 file->pre_write_hook= &maria_page_filler_set_none;
1890 }
1891 else
1892 {
1893 file->post_read_hook= &maria_page_crc_check_data;
1894 if (share->options & HA_OPTION_PAGE_CHECKSUM)
1895 file->pre_write_hook= &maria_page_crc_set_normal;
1896 else
1897 file->pre_write_hook= &maria_page_filler_set_normal;
1898 if (share->now_transactional)
1899 file->flush_log_callback= maria_flush_log_for_page;
1900 }
1901
1902 if (MY_TEST(share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED))
1903 {
1904 ma_crypt_set_data_pagecache_callbacks(file, share);
1905 }
1906}
1907
1908
1909/**
1910 @brief Set callbacks for index pages
1911
1912 @note
1913 We don't use pagecache_file_init here, as we want to keep the
1914 code readable
1915*/
1916
1917void _ma_set_index_pagecache_callbacks(PAGECACHE_FILE *file,
1918 MARIA_SHARE *share)
1919{
1920 pagecache_file_set_null_hooks(file);
1921 file->callback_data= (uchar*) share;
1922 file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
1923 file->post_write_hook= maria_page_write_failure;
1924
1925 if (share->temporary)
1926 {
1927 file->post_read_hook= &maria_page_crc_check_none;
1928 file->pre_write_hook= &maria_page_filler_set_none;
1929 }
1930 else
1931 {
1932 file->post_read_hook= &maria_page_crc_check_index;
1933 if (share->options & HA_OPTION_PAGE_CHECKSUM)
1934 file->pre_write_hook= &maria_page_crc_set_index;
1935 else
1936 file->pre_write_hook= &maria_page_filler_set_normal;
1937
1938 if (share->now_transactional)
1939 file->flush_log_callback= maria_flush_log_for_page;
1940 }
1941
1942 if (MY_TEST(share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED))
1943 {
1944 ma_crypt_set_index_pagecache_callbacks(file, share);
1945 }
1946}
1947
1948
1949/**************************************************************************
1950 Open data file
1951 We can't use dup() here as the data file descriptors need to have different
1952 active seek-positions.
1953*************************************************************************/
1954
1955int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share)
1956{
1957 myf flags= MY_WME | (share->mode & O_NOFOLLOW ? MY_NOSYMLINKS : 0);
1958 DEBUG_SYNC_C("mi_open_datafile");
1959 info->dfile.file= share->bitmap.file.file=
1960 mysql_file_open(key_file_dfile, share->data_file_name.str,
1961 share->mode | O_SHARE, MYF(flags));
1962 return info->dfile.file >= 0 ? 0 : 1;
1963}
1964
1965
1966int _ma_open_keyfile(MARIA_SHARE *share)
1967{
1968 /*
1969 Modifications to share->kfile should be under intern_lock to protect
1970 against a concurrent checkpoint.
1971 */
1972 mysql_mutex_lock(&share->intern_lock);
1973 share->kfile.file= mysql_file_open(key_file_kfile,
1974 share->unique_file_name.str,
1975 share->mode | O_SHARE | O_NOFOLLOW,
1976 MYF(MY_WME | MY_NOSYMLINKS));
1977 mysql_mutex_unlock(&share->intern_lock);
1978 return (share->kfile.file < 0);
1979}
1980
1981
1982/*
1983 Disable all indexes.
1984
1985 SYNOPSIS
1986 maria_disable_indexes()
1987 info A pointer to the MARIA storage engine MARIA_HA struct.
1988
1989 DESCRIPTION
1990 Disable all indexes.
1991
1992 RETURN
1993 0 ok
1994*/
1995
1996int maria_disable_indexes(MARIA_HA *info)
1997{
1998 MARIA_SHARE *share= info->s;
1999
2000 maria_clear_all_keys_active(share->state.key_map);
2001 return 0;
2002}
2003
2004
2005/*
2006 Enable all indexes
2007
2008 SYNOPSIS
2009 maria_enable_indexes()
2010 info A pointer to the MARIA storage engine MARIA_HA struct.
2011
2012 DESCRIPTION
2013 Enable all indexes. The indexes might have been disabled
2014 by maria_disable_index() before.
2015 The function works only if both data and indexes are empty,
2016 otherwise a repair is required.
2017 To be sure, call handler::delete_all_rows() before.
2018
2019 RETURN
2020 0 ok
2021 HA_ERR_CRASHED data or index is non-empty.
2022*/
2023
2024int maria_enable_indexes(MARIA_HA *info)
2025{
2026 int error= 0;
2027 MARIA_SHARE *share= info->s;
2028 DBUG_ENTER("maria_enable_indexes");
2029
2030 if ((share->state.state.data_file_length !=
2031 (share->data_file_type == BLOCK_RECORD ? share->block_size : 0)) ||
2032 (share->state.state.key_file_length != share->base.keystart))
2033 {
2034 DBUG_PRINT("error", ("data_file_length: %lu key_file_length: %lu",
2035 (ulong) share->state.state.data_file_length,
2036 (ulong) share->state.state.key_file_length));
2037 _ma_set_fatal_error(share, HA_ERR_CRASHED);
2038 error= HA_ERR_CRASHED;
2039 }
2040 else
2041 maria_set_all_keys_active(share->state.key_map, share->base.keys);
2042 DBUG_RETURN(error);
2043}
2044
2045
2046/*
2047 Test if indexes are disabled.
2048
2049 SYNOPSIS
2050 maria_indexes_are_disabled()
2051 info A pointer to the MARIA storage engine MARIA_HA struct.
2052
2053 DESCRIPTION
2054 Test if indexes are disabled.
2055
2056 RETURN
2057 0 indexes are not disabled
2058 1 all indexes are disabled
2059 2 non-unique indexes are disabled
2060*/
2061
2062int maria_indexes_are_disabled(MARIA_HA *info)
2063{
2064 MARIA_SHARE *share= info->s;
2065
2066 /*
2067 No keys or all are enabled. keys is the number of keys. Left shifted
2068 gives us only one bit set. When decreased by one, gives us all all bits
2069 up to this one set and it gets unset.
2070 */
2071 if (!share->base.keys ||
2072 (maria_is_all_keys_active(share->state.key_map, share->base.keys)))
2073 return 0;
2074
2075 /* All are disabled */
2076 if (maria_is_any_key_active(share->state.key_map))
2077 return 1;
2078
2079 /*
2080 We have keys. Some enabled, some disabled.
2081 Don't check for any non-unique disabled but return directly 2
2082 */
2083 return 2;
2084}
2085
2086
2087static my_bool maria_scan_init_dummy(MARIA_HA *info __attribute__((unused)))
2088{
2089 return 0;
2090}
2091
2092static void maria_scan_end_dummy(MARIA_HA *info __attribute__((unused)))
2093{
2094}
2095
2096static my_bool maria_once_init_dummy(MARIA_SHARE *share
2097 __attribute__((unused)),
2098 File dfile __attribute__((unused)))
2099{
2100 return 0;
2101}
2102
2103static my_bool maria_once_end_dummy(MARIA_SHARE *share __attribute__((unused)))
2104{
2105 return 0;
2106}
2107