1/* Copyright (C) 2004-2008 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 Copyright (C) 2008-2009 Sun Microsystems, Inc.
3 Copyright (c) 2009, 2017, MariaDB Corporation.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
17
18
19#ifdef USE_PRAGMA_IMPLEMENTATION
20#pragma implementation // gcc: Class implementation
21#endif
22
23#define MYSQL_SERVER 1
24#include <my_global.h>
25#include <m_ctype.h>
26#include <my_dir.h>
27#include <myisampack.h>
28#include <my_bit.h>
29#include "ha_maria.h"
30#include "trnman_public.h"
31#include "trnman.h"
32
33C_MODE_START
34#include "maria_def.h"
35#include "ma_rt_index.h"
36#include "ma_blockrec.h"
37#include "ma_checkpoint.h"
38#include "ma_recovery.h"
39C_MODE_END
40
41//#include "sql_priv.h"
42#include "protocol.h"
43#include "sql_class.h"
44#include "key.h"
45#include "log.h"
46#include "sql_parse.h"
47
48/*
49 Note that in future versions, only *transactional* Maria tables can
50 rollback, so this flag should be up or down conditionally.
51*/
52#ifdef MARIA_CANNOT_ROLLBACK
53#define CANNOT_ROLLBACK_FLAG HA_NO_TRANSACTIONS
54#define trans_register_ha(A, B, C) do { /* nothing */ } while(0)
55#else
56#define CANNOT_ROLLBACK_FLAG 0
57#endif
58#define THD_TRN (*(TRN **)thd_ha_data(thd, maria_hton))
59
60ulong pagecache_division_limit, pagecache_age_threshold, pagecache_file_hash_size;
61ulonglong pagecache_buffer_size;
62const char *zerofill_error_msg=
63 "Table is from another system and must be zerofilled or repaired to be "
64 "usable on this system";
65
66/**
67 As the auto-repair is initiated when opened from the SQL layer
68 (open_unireg_entry(), check_and_repair()), it does not happen when Maria's
69 Recovery internally opens the table to apply log records to it, which is
70 good. It would happen only after Recovery, if the table is still
71 corrupted.
72*/
73ulonglong maria_recover_options= HA_RECOVER_NONE;
74handlerton *maria_hton;
75
76/* bits in maria_recover_options */
77const char *maria_recover_names[]=
78{
79 /*
80 Compared to MyISAM, "default" was renamed to "normal" as it collided with
81 SET var=default which sets to the var's default i.e. what happens when the
82 var is not set i.e. HA_RECOVER_NONE.
83 OFF flag is ignored.
84 */
85 "NORMAL", "BACKUP", "FORCE", "QUICK", "OFF", NullS
86};
87TYPELIB maria_recover_typelib=
88{
89 array_elements(maria_recover_names) - 1, "",
90 maria_recover_names, NULL
91};
92
93const char *maria_stats_method_names[]=
94{
95 "nulls_unequal", "nulls_equal",
96 "nulls_ignored", NullS
97};
98TYPELIB maria_stats_method_typelib=
99{
100 array_elements(maria_stats_method_names) - 1, "",
101 maria_stats_method_names, NULL
102};
103
104/* transactions log purge mode */
105const char *maria_translog_purge_type_names[]=
106{
107 "immediate", "external", "at_flush", NullS
108};
109TYPELIB maria_translog_purge_type_typelib=
110{
111 array_elements(maria_translog_purge_type_names) - 1, "",
112 maria_translog_purge_type_names, NULL
113};
114
115/* transactional log directory sync */
116const char *maria_sync_log_dir_names[]=
117{
118 "NEVER", "NEWFILE", "ALWAYS", NullS
119};
120TYPELIB maria_sync_log_dir_typelib=
121{
122 array_elements(maria_sync_log_dir_names) - 1, "",
123 maria_sync_log_dir_names, NULL
124};
125
126/* transactional log group commit */
127const char *maria_group_commit_names[]=
128{
129 "none", "hard", "soft", NullS
130};
131TYPELIB maria_group_commit_typelib=
132{
133 array_elements(maria_group_commit_names) - 1, "",
134 maria_group_commit_names, NULL
135};
136
137/** Interval between background checkpoints in seconds */
138static ulong checkpoint_interval;
139static void update_checkpoint_interval(MYSQL_THD thd,
140 struct st_mysql_sys_var *var,
141 void *var_ptr, const void *save);
142static void update_maria_group_commit(MYSQL_THD thd,
143 struct st_mysql_sys_var *var,
144 void *var_ptr, const void *save);
145static void update_maria_group_commit_interval(MYSQL_THD thd,
146 struct st_mysql_sys_var *var,
147 void *var_ptr, const void *save);
148/** After that many consecutive recovery failures, remove logs */
149static ulong force_start_after_recovery_failures;
150static void update_log_file_size(MYSQL_THD thd,
151 struct st_mysql_sys_var *var,
152 void *var_ptr, const void *save);
153
154static MYSQL_SYSVAR_ULONG(block_size, maria_block_size,
155 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
156 "Block size to be used for Aria index pages.", 0, 0,
157 MARIA_KEY_BLOCK_LENGTH, MARIA_MIN_KEY_BLOCK_LENGTH,
158 MARIA_MAX_KEY_BLOCK_LENGTH, MARIA_MIN_KEY_BLOCK_LENGTH);
159
160static MYSQL_SYSVAR_ULONG(checkpoint_interval, checkpoint_interval,
161 PLUGIN_VAR_RQCMDARG,
162 "Interval between tries to do an automatic checkpoints. In seconds; 0 means"
163 " 'no automatic checkpoints' which makes sense only for testing.",
164 NULL, update_checkpoint_interval, 30, 0, UINT_MAX, 1);
165
166static MYSQL_SYSVAR_ULONG(checkpoint_log_activity, maria_checkpoint_min_log_activity,
167 PLUGIN_VAR_RQCMDARG,
168 "Number of bytes that the transaction log has to grow between checkpoints before a new "
169 "checkpoint is written to the log.",
170 NULL, NULL, 1024*1024, 0, UINT_MAX, 1);
171
172static MYSQL_SYSVAR_ULONG(force_start_after_recovery_failures,
173 force_start_after_recovery_failures,
174 /*
175 Read-only because setting it on the fly has no useful effect,
176 should be set on command-line.
177 */
178 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
179 "Number of consecutive log recovery failures after which logs will be"
180 " automatically deleted to cure the problem; 0 (the default) disables"
181 " the feature.", NULL, NULL, 0, 0, UINT_MAX8, 1);
182
183static MYSQL_SYSVAR_BOOL(page_checksum, maria_page_checksums, 0,
184 "Maintain page checksums (can be overridden per table "
185 "with PAGE_CHECKSUM clause in CREATE TABLE)", 0, 0, 1);
186
187/* It is only command line argument */
188static MYSQL_SYSVAR_STR(log_dir_path, maria_data_root,
189 PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
190 "Path to the directory where to store transactional log",
191 NULL, NULL, mysql_real_data_home);
192
193
194static MYSQL_SYSVAR_ULONG(log_file_size, log_file_size,
195 PLUGIN_VAR_RQCMDARG,
196 "Limit for transaction log size",
197 NULL, update_log_file_size, TRANSLOG_FILE_SIZE,
198 TRANSLOG_MIN_FILE_SIZE, 0xffffffffL, TRANSLOG_PAGE_SIZE);
199
200static MYSQL_SYSVAR_ENUM(group_commit, maria_group_commit,
201 PLUGIN_VAR_RQCMDARG,
202 "Specifies Aria group commit mode. "
203 "Possible values are \"none\" (no group commit), "
204 "\"hard\" (with waiting to actual commit), "
205 "\"soft\" (no wait for commit (DANGEROUS!!!))",
206 NULL, update_maria_group_commit,
207 TRANSLOG_GCOMMIT_NONE, &maria_group_commit_typelib);
208
209static MYSQL_SYSVAR_ULONG(group_commit_interval, maria_group_commit_interval,
210 PLUGIN_VAR_RQCMDARG,
211 "Interval between commite in microseconds (1/1000000c)."
212 " 0 stands for no waiting"
213 " for other threads to come and do a commit in \"hard\" mode and no"
214 " sync()/commit at all in \"soft\" mode. Option has only an effect"
215 " if aria_group_commit is used",
216 NULL, update_maria_group_commit_interval, 0, 0, UINT_MAX, 1);
217
218static MYSQL_SYSVAR_ENUM(log_purge_type, log_purge_type,
219 PLUGIN_VAR_RQCMDARG,
220 "Specifies how Aria transactional log will be purged",
221 NULL, NULL, TRANSLOG_PURGE_IMMIDIATE,
222 &maria_translog_purge_type_typelib);
223
224static MYSQL_SYSVAR_ULONGLONG(max_sort_file_size,
225 maria_max_temp_length, PLUGIN_VAR_RQCMDARG,
226 "Don't use the fast sort index method to created index if the "
227 "temporary file would get bigger than this.",
228 0, 0, MAX_FILE_SIZE & ~((ulonglong) (1*MB-1)),
229 0, MAX_FILE_SIZE, 1*MB);
230
231static MYSQL_SYSVAR_ULONG(pagecache_age_threshold,
232 pagecache_age_threshold, PLUGIN_VAR_RQCMDARG,
233 "This characterizes the number of hits a hot block has to be untouched "
234 "until it is considered aged enough to be downgraded to a warm block. "
235 "This specifies the percentage ratio of that number of hits to the "
236 "total number of blocks in the page cache.", 0, 0,
237 300, 100, ~ (ulong) 0L, 100);
238
239static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size,
240 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
241 "The size of the buffer used for index blocks for Aria tables. "
242 "Increase this to get better index handling (for all reads and "
243 "multiple writes) to as much as you can afford.", 0, 0,
244 KEY_CACHE_SIZE, 8192*16L, ~(ulonglong) 0, 1);
245
246static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit,
247 PLUGIN_VAR_RQCMDARG,
248 "The minimum percentage of warm blocks in key cache", 0, 0,
249 100, 1, 100, 1);
250
251static MYSQL_SYSVAR_ULONG(pagecache_file_hash_size, pagecache_file_hash_size,
252 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
253 "Number of hash buckets for open and changed files. If you have a lot of Aria "
254 "files open you should increase this for faster flush of changes. A good "
255 "value is probably 1/10 of number of possible open Aria files.", 0,0,
256 512, 128, 16384, 1);
257
258static MYSQL_SYSVAR_SET(recover_options, maria_recover_options, PLUGIN_VAR_OPCMDARG,
259 "Specifies how corrupted tables should be automatically repaired",
260 NULL, NULL, HA_RECOVER_BACKUP|HA_RECOVER_QUICK, &maria_recover_typelib);
261
262static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG,
263 "Number of threads to use when repairing Aria tables. The value of 1 "
264 "disables parallel repair.",
265 0, 0, 1, 1, 128, 1);
266
267static MYSQL_THDVAR_ULONGLONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG,
268 "The buffer that is allocated when sorting the index when doing a "
269 "REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", NULL, NULL,
270 SORT_BUFFER_INIT, MIN_SORT_BUFFER, SIZE_T_MAX, 1);
271
272static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG,
273 "Specifies how Aria index statistics collection code should treat "
274 "NULLs", 0, 0, 0, &maria_stats_method_typelib);
275
276static MYSQL_SYSVAR_ENUM(sync_log_dir, sync_log_dir, PLUGIN_VAR_RQCMDARG,
277 "Controls syncing directory after log file growth and new file "
278 "creation", NULL, NULL, TRANSLOG_SYNC_DIR_NEWFILE,
279 &maria_sync_log_dir_typelib);
280
281#ifdef USE_ARIA_FOR_TMP_TABLES
282#define USE_ARIA_FOR_TMP_TABLES_VAL 1
283#else
284#define USE_ARIA_FOR_TMP_TABLES_VAL 0
285#endif
286my_bool use_maria_for_temp_tables= USE_ARIA_FOR_TMP_TABLES_VAL;
287
288static MYSQL_SYSVAR_BOOL(used_for_temp_tables,
289 use_maria_for_temp_tables, PLUGIN_VAR_READONLY | PLUGIN_VAR_NOCMDOPT,
290 "Whether temporary tables should be MyISAM or Aria", 0, 0,
291 1);
292
293static MYSQL_SYSVAR_BOOL(encrypt_tables, maria_encrypt_tables, PLUGIN_VAR_OPCMDARG,
294 "Encrypt tables (only for tables with ROW_FORMAT=PAGE (default) "
295 "and not FIXED/DYNAMIC)",
296 0, 0, 0);
297
298#ifdef HAVE_PSI_INTERFACE
299
300static PSI_mutex_info all_aria_mutexes[]=
301{
302 { &key_THR_LOCK_maria, "THR_LOCK_maria", PSI_FLAG_GLOBAL},
303 { &key_LOCK_soft_sync, "LOCK_soft_sync", PSI_FLAG_GLOBAL},
304 { &key_LOCK_trn_list, "LOCK_trn_list", PSI_FLAG_GLOBAL},
305 { &key_SHARE_BITMAP_lock, "SHARE::bitmap::bitmap_lock", 0},
306 { &key_SORT_INFO_mutex, "SORT_INFO::mutex", 0},
307 { &key_TRANSLOG_BUFFER_mutex, "TRANSLOG_BUFFER::mutex", 0},
308 { &key_TRANSLOG_DESCRIPTOR_dirty_buffer_mask_lock, "TRANSLOG_DESCRIPTOR::dirty_buffer_mask_lock", 0},
309 { &key_TRANSLOG_DESCRIPTOR_sent_to_disk_lock, "TRANSLOG_DESCRIPTOR::sent_to_disk_lock", 0},
310 { &key_TRANSLOG_DESCRIPTOR_log_flush_lock, "TRANSLOG_DESCRIPTOR::log_flush_lock", 0},
311 { &key_TRANSLOG_DESCRIPTOR_file_header_lock, "TRANSLOG_DESCRIPTOR::file_header_lock", 0},
312 { &key_TRANSLOG_DESCRIPTOR_unfinished_files_lock, "TRANSLOG_DESCRIPTOR::unfinished_files_lock", 0},
313 { &key_TRANSLOG_DESCRIPTOR_purger_lock, "TRANSLOG_DESCRIPTOR::purger_lock", 0},
314 { &key_SHARE_intern_lock, "SHARE::intern_lock", 0},
315 { &key_SHARE_key_del_lock, "SHARE::key_del_lock", 0},
316 { &key_SHARE_close_lock, "SHARE::close_lock", 0},
317 { &key_SERVICE_THREAD_CONTROL_lock, "SERVICE_THREAD_CONTROL::LOCK_control", 0},
318 { &key_TRN_state_lock, "TRN::state_lock", 0},
319 { &key_PAGECACHE_cache_lock, "PAGECACHE::cache_lock", 0}
320};
321
322static PSI_cond_info all_aria_conds[]=
323{
324 { &key_COND_soft_sync, "COND_soft_sync", PSI_FLAG_GLOBAL},
325 { &key_SHARE_key_del_cond, "SHARE::key_del_cond", 0},
326 { &key_SERVICE_THREAD_CONTROL_cond, "SERVICE_THREAD_CONTROL::COND_control", 0},
327 { &key_SORT_INFO_cond, "SORT_INFO::cond", 0},
328 { &key_SHARE_BITMAP_cond, "BITMAP::bitmap_cond", 0},
329 { &key_TRANSLOG_BUFFER_waiting_filling_buffer, "TRANSLOG_BUFFER::waiting_filling_buffer", 0},
330 { &key_TRANSLOG_BUFFER_prev_sent_to_disk_cond, "TRANSLOG_BUFFER::prev_sent_to_disk_cond", 0},
331 { &key_TRANSLOG_DESCRIPTOR_log_flush_cond, "TRANSLOG_DESCRIPTOR::log_flush_cond", 0},
332 { &key_TRANSLOG_DESCRIPTOR_new_goal_cond, "TRANSLOG_DESCRIPTOR::new_goal_cond", 0}
333};
334
335static PSI_rwlock_info all_aria_rwlocks[]=
336{
337 { &key_KEYINFO_root_lock, "KEYINFO::root_lock", 0},
338 { &key_SHARE_mmap_lock, "SHARE::mmap_lock", 0},
339 { &key_TRANSLOG_DESCRIPTOR_open_files_lock, "TRANSLOG_DESCRIPTOR::open_files_lock", 0}
340};
341
342static PSI_thread_info all_aria_threads[]=
343{
344 { &key_thread_checkpoint, "checkpoint_background", PSI_FLAG_GLOBAL},
345 { &key_thread_soft_sync, "soft_sync_background", PSI_FLAG_GLOBAL},
346 { &key_thread_find_all_keys, "thr_find_all_keys", 0}
347};
348
349static PSI_file_info all_aria_files[]=
350{
351 { &key_file_translog, "translog", 0},
352 { &key_file_kfile, "MAI", 0},
353 { &key_file_dfile, "MAD", 0},
354 { &key_file_control, "control", PSI_FLAG_GLOBAL}
355};
356
357static PSI_stage_info *all_aria_stages[]=
358{
359 & stage_waiting_for_a_resource
360};
361
362static void init_aria_psi_keys(void)
363{
364 const char* category= "aria";
365 int count;
366
367 count= array_elements(all_aria_mutexes);
368 mysql_mutex_register(category, all_aria_mutexes, count);
369
370 count= array_elements(all_aria_rwlocks);
371 mysql_rwlock_register(category, all_aria_rwlocks, count);
372
373 count= array_elements(all_aria_conds);
374 mysql_cond_register(category, all_aria_conds, count);
375
376 count= array_elements(all_aria_threads);
377 mysql_thread_register(category, all_aria_threads, count);
378
379 count= array_elements(all_aria_files);
380 mysql_file_register(category, all_aria_files, count);
381
382 count= array_elements(all_aria_stages);
383 mysql_stage_register(category, all_aria_stages, count);
384}
385#else
386#define init_aria_psi_keys() /* no-op */
387#endif /* HAVE_PSI_INTERFACE */
388
389/*****************************************************************************
390** MARIA tables
391*****************************************************************************/
392
393static handler *maria_create_handler(handlerton *hton,
394 TABLE_SHARE * table,
395 MEM_ROOT *mem_root)
396{
397 return new (mem_root) ha_maria(hton, table);
398}
399
400
401// collect errors printed by maria_check routines
402
403static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type,
404 const char *fmt, va_list args)
405{
406 THD *thd= (THD *) param->thd;
407 Protocol *protocol= thd->protocol;
408 size_t length, msg_length;
409 char msgbuf[MYSQL_ERRMSG_SIZE];
410 char name[NAME_LEN * 2 + 2];
411
412 if (param->testflag & T_SUPPRESS_ERR_HANDLING)
413 return;
414
415 msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
416 msgbuf[sizeof(msgbuf) - 1]= 0; // healthy paranoia
417
418 DBUG_PRINT(msg_type, ("message: %s", msgbuf));
419
420 if (!thd->vio_ok())
421 {
422 sql_print_error("%s.%s: %s", param->db_name, param->table_name, msgbuf);
423 return;
424 }
425
426 if (param->testflag &
427 (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | T_AUTO_REPAIR))
428 {
429 my_message(ER_NOT_KEYFILE, msgbuf, MYF(MY_WME));
430 if (thd->variables.log_warnings > 2)
431 sql_print_error("%s.%s: %s", param->db_name, param->table_name, msgbuf);
432 return;
433 }
434 length= (uint) (strxmov(name, param->db_name, ".", param->table_name,
435 NullS) - name);
436 /*
437 TODO: switch from protocol to push_warning here. The main reason we didn't
438 it yet is parallel repair, which threads have no THD object accessible via
439 current_thd.
440
441 Also we likely need to lock mutex here (in both cases with protocol and
442 push_warning).
443 */
444 protocol->prepare_for_resend();
445 protocol->store(name, (uint)length, system_charset_info);
446 protocol->store(param->op_name, system_charset_info);
447 protocol->store(msg_type, system_charset_info);
448 protocol->store(msgbuf, (uint)msg_length, system_charset_info);
449 if (protocol->write())
450 sql_print_error("Failed on my_net_write, writing to stderr instead: %s.%s: %s\n",
451 param->db_name, param->table_name, msgbuf);
452 else if (thd->variables.log_warnings > 2)
453 sql_print_error("%s.%s: %s", param->db_name, param->table_name, msgbuf);
454
455 return;
456}
457
458
459/*
460 Convert TABLE object to Maria key and column definition
461
462 SYNOPSIS
463 table2maria()
464 table_arg in TABLE object.
465 keydef_out out Maria key definition.
466 recinfo_out out Maria column definition.
467 records_out out Number of fields.
468
469 DESCRIPTION
470 This function will allocate and initialize Maria key and column
471 definition for further use in ma_create or for a check for underlying
472 table conformance in merge engine.
473
474 The caller needs to free *recinfo_out after use. Since *recinfo_out
475 and *keydef_out are allocated with a my_multi_malloc, *keydef_out
476 is freed automatically when *recinfo_out is freed.
477
478 RETURN VALUE
479 0 OK
480 # error code
481*/
482
483static int table2maria(TABLE *table_arg, data_file_type row_type,
484 MARIA_KEYDEF **keydef_out,
485 MARIA_COLUMNDEF **recinfo_out, uint *records_out,
486 MARIA_CREATE_INFO *create_info)
487{
488 uint i, j, recpos, minpos, fieldpos, temp_length, length;
489 enum ha_base_keytype type= HA_KEYTYPE_BINARY;
490 uchar *record;
491 KEY *pos;
492 MARIA_KEYDEF *keydef;
493 MARIA_COLUMNDEF *recinfo, *recinfo_pos;
494 HA_KEYSEG *keyseg;
495 TABLE_SHARE *share= table_arg->s;
496 uint options= share->db_options_in_use;
497 DBUG_ENTER("table2maria");
498
499 if (row_type == BLOCK_RECORD)
500 options|= HA_OPTION_PACK_RECORD;
501
502 if (!(my_multi_malloc(MYF(MY_WME),
503 recinfo_out, (share->fields * 2 + 2) * sizeof(MARIA_COLUMNDEF),
504 keydef_out, share->keys * sizeof(MARIA_KEYDEF),
505 &keyseg,
506 (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
507 NullS)))
508 DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
509 keydef= *keydef_out;
510 recinfo= *recinfo_out;
511 pos= table_arg->key_info;
512 for (i= 0; i < share->keys; i++, pos++)
513 {
514 keydef[i].flag= (uint16) (pos->flags & (HA_NOSAME | HA_FULLTEXT |
515 HA_SPATIAL));
516 keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
517 (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
518 pos->algorithm;
519 keydef[i].block_length= pos->block_size;
520 keydef[i].seg= keyseg;
521 keydef[i].keysegs= pos->user_defined_key_parts;
522 for (j= 0; j < pos->user_defined_key_parts; j++)
523 {
524 Field *field= pos->key_part[j].field;
525
526 if (!table_arg->field[field->field_index]->stored_in_db())
527 {
528 my_free(*recinfo_out);
529 my_error(ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN, MYF(0));
530 DBUG_RETURN(HA_ERR_UNSUPPORTED);
531 }
532
533 type= field->key_type();
534 keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
535
536 if (options & HA_OPTION_PACK_KEYS ||
537 (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
538 HA_SPACE_PACK_USED)))
539 {
540 if (pos->key_part[j].length > 8 &&
541 (type == HA_KEYTYPE_TEXT ||
542 type == HA_KEYTYPE_NUM ||
543 (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
544 {
545 /* No blobs here */
546 if (j == 0)
547 keydef[i].flag|= HA_PACK_KEY;
548 if (!(field->flags & ZEROFILL_FLAG) &&
549 (field->type() == MYSQL_TYPE_STRING ||
550 field->type() == MYSQL_TYPE_VAR_STRING ||
551 ((int) (pos->key_part[j].length - field->decimals())) >= 4))
552 keydef[i].seg[j].flag|= HA_SPACE_PACK;
553 }
554 else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
555 keydef[i].flag|= HA_BINARY_PACK_KEY;
556 }
557 keydef[i].seg[j].type= (int) type;
558 keydef[i].seg[j].start= pos->key_part[j].offset;
559 keydef[i].seg[j].length= pos->key_part[j].length;
560 keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_length= 0;
561 keydef[i].seg[j].bit_pos= 0;
562 keydef[i].seg[j].language= field->charset()->number;
563
564 if (field->null_ptr)
565 {
566 keydef[i].seg[j].null_bit= field->null_bit;
567 keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
568 (uchar*) table_arg->record[0]);
569 }
570 else
571 {
572 keydef[i].seg[j].null_bit= 0;
573 keydef[i].seg[j].null_pos= 0;
574 }
575 if (field->type() == MYSQL_TYPE_BLOB ||
576 field->type() == MYSQL_TYPE_GEOMETRY)
577 {
578 keydef[i].seg[j].flag|= HA_BLOB_PART;
579 /* save number of bytes used to pack length */
580 keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
581 portable_sizeof_char_ptr);
582 }
583 else if (field->type() == MYSQL_TYPE_BIT)
584 {
585 keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
586 keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
587 keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
588 (uchar*) table_arg->record[0]);
589 }
590 }
591 keyseg+= pos->user_defined_key_parts;
592 }
593 if (table_arg->found_next_number_field)
594 keydef[share->next_number_index].flag|= HA_AUTO_KEY;
595 record= table_arg->record[0];
596 recpos= 0;
597 recinfo_pos= recinfo;
598 create_info->null_bytes= table_arg->s->null_bytes;
599
600 while (recpos < (uint) share->stored_rec_length)
601 {
602 Field **field, *found= 0;
603 minpos= share->reclength;
604 length= 0;
605
606 for (field= table_arg->field; *field; field++)
607 {
608 if ((fieldpos= (*field)->offset(record)) >= recpos &&
609 fieldpos <= minpos)
610 {
611 /* skip null fields */
612 if (!(temp_length= (*field)->pack_length_in_rec()))
613 continue; /* Skip null-fields */
614 if (! found || fieldpos < minpos ||
615 (fieldpos == minpos && temp_length < length))
616 {
617 minpos= fieldpos;
618 found= *field;
619 length= temp_length;
620 }
621 }
622 }
623 DBUG_PRINT("loop", ("found: %p recpos: %d minpos: %d length: %d",
624 found, recpos, minpos, length));
625 if (!found)
626 break;
627
628 if (found->flags & BLOB_FLAG)
629 recinfo_pos->type= FIELD_BLOB;
630 else if (found->type() == MYSQL_TYPE_TIMESTAMP)
631 recinfo_pos->type= FIELD_NORMAL;
632 else if (found->type() == MYSQL_TYPE_VARCHAR)
633 recinfo_pos->type= FIELD_VARCHAR;
634 else if (!(options & HA_OPTION_PACK_RECORD) ||
635 (found->zero_pack() && (found->flags & PRI_KEY_FLAG)))
636 recinfo_pos->type= FIELD_NORMAL;
637 else if (found->zero_pack())
638 recinfo_pos->type= FIELD_SKIP_ZERO;
639 else
640 recinfo_pos->type= ((length <= 3 ||
641 (found->flags & ZEROFILL_FLAG)) ?
642 FIELD_NORMAL :
643 found->type() == MYSQL_TYPE_STRING ||
644 found->type() == MYSQL_TYPE_VAR_STRING ?
645 FIELD_SKIP_ENDSPACE :
646 FIELD_SKIP_PRESPACE);
647 if (found->null_ptr)
648 {
649 recinfo_pos->null_bit= found->null_bit;
650 recinfo_pos->null_pos= (uint) (found->null_ptr -
651 (uchar*) table_arg->record[0]);
652 }
653 else
654 {
655 recinfo_pos->null_bit= 0;
656 recinfo_pos->null_pos= 0;
657 }
658 (recinfo_pos++)->length= (uint16) length;
659 recpos= minpos + length;
660 DBUG_PRINT("loop", ("length: %d type: %d",
661 recinfo_pos[-1].length,recinfo_pos[-1].type));
662 }
663 *records_out= (uint) (recinfo_pos - recinfo);
664 DBUG_RETURN(0);
665}
666
667
668/*
669 Check for underlying table conformance
670
671 SYNOPSIS
672 maria_check_definition()
673 t1_keyinfo in First table key definition
674 t1_recinfo in First table record definition
675 t1_keys in Number of keys in first table
676 t1_recs in Number of records in first table
677 t2_keyinfo in Second table key definition
678 t2_recinfo in Second table record definition
679 t2_keys in Number of keys in second table
680 t2_recs in Number of records in second table
681 strict in Strict check switch
682
683 DESCRIPTION
684 This function compares two Maria definitions. By intention it was done
685 to compare merge table definition against underlying table definition.
686 It may also be used to compare dot-frm and MAI definitions of Maria
687 table as well to compare different Maria table definitions.
688
689 For merge table it is not required that number of keys in merge table
690 must exactly match number of keys in underlying table. When calling this
691 function for underlying table conformance check, 'strict' flag must be
692 set to false, and converted merge definition must be passed as t1_*.
693
694 Otherwise 'strict' flag must be set to 1 and it is not required to pass
695 converted dot-frm definition as t1_*.
696
697 RETURN VALUE
698 0 - Equal definitions.
699 1 - Different definitions.
700
701 TODO
702 - compare FULLTEXT keys;
703 - compare SPATIAL keys;
704 - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
705 (should be correctly detected in table2maria).
706*/
707
708int maria_check_definition(MARIA_KEYDEF *t1_keyinfo,
709 MARIA_COLUMNDEF *t1_recinfo,
710 uint t1_keys, uint t1_recs,
711 MARIA_KEYDEF *t2_keyinfo,
712 MARIA_COLUMNDEF *t2_recinfo,
713 uint t2_keys, uint t2_recs, bool strict)
714{
715 uint i, j;
716 DBUG_ENTER("maria_check_definition");
717 if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
718 {
719 DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
720 t1_keys, t2_keys));
721 DBUG_RETURN(1);
722 }
723 if (t1_recs != t2_recs)
724 {
725 DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
726 t1_recs, t2_recs));
727 DBUG_RETURN(1);
728 }
729 for (i= 0; i < t1_keys; i++)
730 {
731 HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
732 HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
733 if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
734 continue;
735 else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
736 t2_keyinfo[i].flag & HA_FULLTEXT)
737 {
738 DBUG_PRINT("error", ("Key %d has different definition", i));
739 DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
740 MY_TEST(t1_keyinfo[i].flag & HA_FULLTEXT),
741 MY_TEST(t2_keyinfo[i].flag & HA_FULLTEXT)));
742 DBUG_RETURN(1);
743 }
744 if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
745 continue;
746 else if (t1_keyinfo[i].flag & HA_SPATIAL ||
747 t2_keyinfo[i].flag & HA_SPATIAL)
748 {
749 DBUG_PRINT("error", ("Key %d has different definition", i));
750 DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
751 MY_TEST(t1_keyinfo[i].flag & HA_SPATIAL),
752 MY_TEST(t2_keyinfo[i].flag & HA_SPATIAL)));
753 DBUG_RETURN(1);
754 }
755 if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
756 t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
757 {
758 DBUG_PRINT("error", ("Key %d has different definition", i));
759 DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
760 t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
761 DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
762 t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
763 DBUG_RETURN(1);
764 }
765 for (j= t1_keyinfo[i].keysegs; j--;)
766 {
767 uint8 t1_keysegs_j__type= t1_keysegs[j].type;
768 /*
769 Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
770 always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
771 HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
772 level, we can ignore a mismatch between these types.
773 */
774 if ((t1_keysegs[j].flag & HA_BLOB_PART) &&
775 (t2_keysegs[j].flag & HA_BLOB_PART))
776 {
777 if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
778 (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
779 t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
780 else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
781 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
782 t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
783 }
784
785 if (t1_keysegs_j__type != t2_keysegs[j].type ||
786 t1_keysegs[j].language != t2_keysegs[j].language ||
787 t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
788 t1_keysegs[j].length != t2_keysegs[j].length)
789 {
790 DBUG_PRINT("error", ("Key segment %d (key %d) has different "
791 "definition", j, i));
792 DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
793 "t1_length=%d",
794 t1_keysegs[j].type, t1_keysegs[j].language,
795 t1_keysegs[j].null_bit, t1_keysegs[j].length));
796 DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
797 "t2_length=%d",
798 t2_keysegs[j].type, t2_keysegs[j].language,
799 t2_keysegs[j].null_bit, t2_keysegs[j].length));
800
801 DBUG_RETURN(1);
802 }
803 }
804 }
805
806 for (i= 0; i < t1_recs; i++)
807 {
808 MARIA_COLUMNDEF *t1_rec= &t1_recinfo[i];
809 MARIA_COLUMNDEF *t2_rec= &t2_recinfo[i];
810 /*
811 FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in maria_create,
812 see NOTE1 in ma_create.c
813 */
814 if ((t1_rec->type != t2_rec->type &&
815 !(t1_rec->type == (int) FIELD_SKIP_ZERO &&
816 t1_rec->length == 1 &&
817 t2_rec->type == (int) FIELD_NORMAL)) ||
818 t1_rec->length != t2_rec->length ||
819 t1_rec->null_bit != t2_rec->null_bit)
820 {
821 DBUG_PRINT("error", ("Field %d has different definition", i));
822 DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d",
823 t1_rec->type, t1_rec->length, t1_rec->null_bit));
824 DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d",
825 t2_rec->type, t2_rec->length, t2_rec->null_bit));
826 DBUG_RETURN(1);
827 }
828 }
829 DBUG_RETURN(0);
830}
831
832
833extern "C" {
834
835int _ma_killed_ptr(HA_CHECK *param)
836{
837 if (likely(thd_killed((THD*)param->thd)) == 0)
838 return 0;
839 my_errno= HA_ERR_ABORTED_BY_USER;
840 return 1;
841}
842
843
844/*
845 Report progress to mysqld
846
847 This is a bit more complex than what a normal progress report
848 function normally is.
849
850 The reason is that this is called by enable_index/repair which
851 is one stage in ALTER TABLE and we can't use the external
852 stage/max_stage for this.
853
854 thd_progress_init/thd_progress_next_stage is to be called by
855 high level commands like CHECK TABLE or REPAIR TABLE, not
856 by sub commands like enable_index().
857
858 In ma_check.c it's easier to work with stages than with a total
859 progress, so we use internal stage/max_stage here to keep the
860 code simple.
861*/
862
863void _ma_report_progress(HA_CHECK *param, ulonglong progress,
864 ulonglong max_progress)
865{
866 thd_progress_report((THD*)param->thd,
867 progress + max_progress * param->stage,
868 max_progress * param->max_stage);
869}
870
871
872void _ma_check_print_error(HA_CHECK *param, const char *fmt, ...)
873{
874 va_list args;
875 DBUG_ENTER("_ma_check_print_error");
876 param->error_printed |= 1;
877 param->out_flag |= O_DATA_LOST;
878 if (param->testflag & T_SUPPRESS_ERR_HANDLING)
879 DBUG_VOID_RETURN;
880 va_start(args, fmt);
881 _ma_check_print_msg(param, "error", fmt, args);
882 va_end(args);
883 DBUG_VOID_RETURN;
884}
885
886
887void _ma_check_print_info(HA_CHECK *param, const char *fmt, ...)
888{
889 va_list args;
890 DBUG_ENTER("_ma_check_print_info");
891 va_start(args, fmt);
892 _ma_check_print_msg(param, "info", fmt, args);
893 va_end(args);
894 DBUG_VOID_RETURN;
895}
896
897
898void _ma_check_print_warning(HA_CHECK *param, const char *fmt, ...)
899{
900 va_list args;
901 DBUG_ENTER("_ma_check_print_warning");
902 param->warning_printed= 1;
903 param->out_flag |= O_DATA_LOST;
904 va_start(args, fmt);
905 _ma_check_print_msg(param, "warning", fmt, args);
906 va_end(args);
907 DBUG_VOID_RETURN;
908}
909
910/*
911 Create a transaction object
912
913 SYNOPSIS
914 info Maria handler
915
916 RETURN
917 0 ok
918 # Error number (HA_ERR_OUT_OF_MEM)
919*/
920
921static int maria_create_trn_for_mysql(MARIA_HA *info)
922{
923 THD *thd= ((TABLE*) info->external_ref)->in_use;
924 TRN *trn= THD_TRN;
925 DBUG_ENTER("maria_create_trn_for_mysql");
926
927 if (!trn) /* no transaction yet - open it now */
928 {
929 trn= trnman_new_trn(& thd->transaction.wt);
930 if (unlikely(!trn))
931 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
932 THD_TRN= trn;
933 if (thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
934 trans_register_ha(thd, TRUE, maria_hton);
935 }
936 _ma_set_trn_for_table(info, trn);
937 if (!trnman_increment_locked_tables(trn))
938 {
939 trans_register_ha(thd, FALSE, maria_hton);
940 trnman_new_statement(trn);
941 }
942#ifdef EXTRA_DEBUG
943 if (info->lock_type == F_WRLCK &&
944 ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED))
945 {
946 trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED |
947 TRN_STATE_TABLES_CAN_CHANGE);
948 (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY,
949 (uchar*) thd->query(),
950 thd->query_length());
951 }
952 else
953 {
954 DBUG_PRINT("info", ("lock_type: %d trnman_flags: %u",
955 info->lock_type, trnman_get_flags(trn)));
956 }
957
958#endif
959 DBUG_RETURN(0);
960}
961
962my_bool ma_killed_in_mariadb(MARIA_HA *info)
963{
964 return (((TABLE*) (info->external_ref))->in_use->killed != 0);
965}
966
967} /* extern "C" */
968
969/**
970 Transactional table doing bulk insert with one single UNDO
971 (UNDO_BULK_INSERT) and with repair.
972*/
973#define BULK_INSERT_SINGLE_UNDO_AND_REPAIR 1
974/**
975 Transactional table doing bulk insert with one single UNDO
976 (UNDO_BULK_INSERT) and without repair.
977*/
978#define BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR 2
979/**
980 None of BULK_INSERT_SINGLE_UNDO_AND_REPAIR and
981 BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR.
982*/
983#define BULK_INSERT_NONE 0
984
985ha_maria::ha_maria(handlerton *hton, TABLE_SHARE *table_arg):
986handler(hton, table_arg), file(0),
987int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
988 HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
989 HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
990 HA_FILE_BASED | HA_CAN_GEOMETRY | CANNOT_ROLLBACK_FLAG |
991 HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | HA_CAN_REPAIR |
992 HA_CAN_VIRTUAL_COLUMNS | HA_CAN_EXPORT |
993 HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
994 HA_CAN_TABLES_WITHOUT_ROLLBACK),
995can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE)
996{}
997
998
999handler *ha_maria::clone(const char *name, MEM_ROOT *mem_root)
1000{
1001 ha_maria *new_handler= static_cast <ha_maria *>(handler::clone(name,
1002 mem_root));
1003 if (new_handler)
1004 {
1005 new_handler->file->state= file->state;
1006 /* maria_create_trn_for_mysql() is never called for clone() tables */
1007 new_handler->file->trn= file->trn;
1008 }
1009 return new_handler;
1010}
1011
1012
1013static const char *ha_maria_exts[]=
1014{
1015 MARIA_NAME_IEXT,
1016 MARIA_NAME_DEXT,
1017 NullS
1018};
1019
1020
1021const char *ha_maria::index_type(uint key_number)
1022{
1023 return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
1024 "FULLTEXT" :
1025 (table->key_info[key_number].flags & HA_SPATIAL) ?
1026 "SPATIAL" :
1027 (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
1028 "RTREE" : "BTREE");
1029}
1030
1031
1032ulong ha_maria::index_flags(uint inx, uint part, bool all_parts) const
1033{
1034 ulong flags;
1035 if (table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT)
1036 flags= 0;
1037 else
1038 if ((table_share->key_info[inx].flags & HA_SPATIAL ||
1039 table_share->key_info[inx].algorithm == HA_KEY_ALG_RTREE))
1040 {
1041 /* All GIS scans are non-ROR scans. We also disable IndexConditionPushdown */
1042 flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
1043 HA_READ_ORDER | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
1044 }
1045 else
1046 {
1047 flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
1048 HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN;
1049 }
1050 return flags;
1051}
1052
1053
1054double ha_maria::scan_time()
1055{
1056 if (file->s->data_file_type == BLOCK_RECORD)
1057 return ulonglong2double(stats.data_file_length - file->s->block_size) / MY_MAX(file->s->block_size / 2, IO_SIZE) + 2;
1058 return handler::scan_time();
1059}
1060
1061/*
1062 We need to be able to store at least 2 keys on an index page as the
1063 splitting algorithms depends on this. (With only one key on a page
1064 we also can't use any compression, which may make the index file much
1065 larger)
1066 We use HA_MAX_KEY_LENGTH as this is a stack restriction imposed by the
1067 handler interface. If we want to increase this, we have also to
1068 increase HA_MARIA_KEY_BUFF and MARIA_MAX_KEY_BUFF as the buffer needs
1069 to take be able to store the extra lenght bytes that is part of the stored
1070 key.
1071
1072 We also need to reserve place for a record pointer (8) and 3 bytes
1073 per key segment to store the length of the segment + possible null bytes.
1074 These extra bytes are required here so that maria_create() will surely
1075 accept any keys created which the returned key data storage length.
1076*/
1077
1078uint ha_maria::max_supported_key_length() const
1079{
1080 return maria_max_key_length();
1081}
1082
1083
1084#ifdef HAVE_REPLICATION
1085int ha_maria::net_read_dump(NET * net)
1086{
1087 int data_fd= file->dfile.file;
1088 int error= 0;
1089
1090 mysql_file_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
1091 for (;;)
1092 {
1093 ulong packet_len= my_net_read(net);
1094 if (!packet_len)
1095 break; // end of file
1096 if (packet_len == packet_error)
1097 {
1098 sql_print_error("ha_maria::net_read_dump - read error ");
1099 error= -1;
1100 goto err;
1101 }
1102 if (mysql_file_write(data_fd, (uchar *) net->read_pos, (uint) packet_len,
1103 MYF(MY_WME | MY_FNABP)))
1104 {
1105 error= errno;
1106 goto err;
1107 }
1108 }
1109err:
1110 return error;
1111}
1112
1113
1114int ha_maria::dump(THD * thd, int fd)
1115{
1116 MARIA_SHARE *share= file->s;
1117 NET *net= &thd->net;
1118 uint block_size= share->block_size;
1119 my_off_t bytes_to_read= share->state.state.data_file_length;
1120 int data_fd= file->dfile.file;
1121 uchar *buf= (uchar *) my_malloc(block_size, MYF(MY_WME));
1122 if (!buf)
1123 return ENOMEM;
1124
1125 int error= 0;
1126 mysql_file_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
1127 for (; bytes_to_read > 0;)
1128 {
1129 size_t bytes= mysql_file_read(data_fd, buf, block_size, MYF(MY_WME));
1130 if (bytes == MY_FILE_ERROR)
1131 {
1132 error= errno;
1133 goto err;
1134 }
1135
1136 if (fd >= 0)
1137 {
1138 if (mysql_file_write(fd, buf, bytes, MYF(MY_WME | MY_FNABP)))
1139 {
1140 error= errno ? errno : EPIPE;
1141 goto err;
1142 }
1143 }
1144 else
1145 {
1146 if (my_net_write(net, buf, bytes))
1147 {
1148 error= errno ? errno : EPIPE;
1149 goto err;
1150 }
1151 }
1152 bytes_to_read -= bytes;
1153 }
1154
1155 if (fd < 0)
1156 {
1157 if (my_net_write(net, (uchar*) "", 0))
1158 error= errno ? errno : EPIPE;
1159 net_flush(net);
1160 }
1161
1162err:
1163 my_free(buf);
1164 return error;
1165}
1166#endif /* HAVE_REPLICATION */
1167
1168 /* Name is here without an extension */
1169
1170int ha_maria::open(const char *name, int mode, uint test_if_locked)
1171{
1172 uint i;
1173
1174#ifdef NOT_USED
1175 /*
1176 If the user wants to have memory mapped data files, add an
1177 open_flag. Do not memory map temporary tables because they are
1178 expected to be inserted and thus extended a lot. Memory mapping is
1179 efficient for files that keep their size, but very inefficient for
1180 growing files. Using an open_flag instead of calling ma_extra(...
1181 HA_EXTRA_MMAP ...) after maxs_open() has the advantage that the
1182 mapping is not repeated for every open, but just done on the initial
1183 open, when the MyISAM share is created. Every time the server
1184 requires to open a new instance of a table it calls this method. We
1185 will always supply HA_OPEN_MMAP for a permanent table. However, the
1186 Maria storage engine will ignore this flag if this is a secondary
1187 open of a table that is in use by other threads already (if the
1188 Maria share exists already).
1189 */
1190 if (!(test_if_locked & HA_OPEN_TMP_TABLE) && opt_maria_use_mmap)
1191 test_if_locked|= HA_OPEN_MMAP;
1192#endif
1193
1194 if (maria_recover_options & HA_RECOVER_ANY)
1195 {
1196 /* user asked to trigger a repair if table was not properly closed */
1197 test_if_locked|= HA_OPEN_ABORT_IF_CRASHED;
1198 }
1199
1200 if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
1201 {
1202 if (my_errno == HA_ERR_OLD_FILE)
1203 {
1204 push_warning(current_thd, Sql_condition::WARN_LEVEL_NOTE,
1205 ER_CRASHED_ON_USAGE,
1206 zerofill_error_msg);
1207 }
1208 return (my_errno ? my_errno : -1);
1209 }
1210
1211 file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
1212 /* Set external_ref, mainly for temporary tables */
1213 file->external_ref= (void*) table; // For ma_killed()
1214
1215 if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
1216 maria_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
1217
1218 info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
1219 if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
1220 maria_extra(file, HA_EXTRA_WAIT_LOCK, 0);
1221 if ((data_file_type= file->s->data_file_type) != STATIC_RECORD)
1222 int_table_flags |= HA_REC_NOT_IN_SEQ;
1223 if (!file->s->base.born_transactional)
1224 {
1225 /*
1226 INSERT DELAYED cannot work with transactional tables (because it cannot
1227 stand up to "when client gets ok the data is safe on disk": the record
1228 may not even be inserted). In the future, we could enable it back (as a
1229 client doing INSERT DELAYED knows the specificities; but we then should
1230 make sure to regularly commit in the delayed_insert thread).
1231 */
1232 int_table_flags|= HA_CAN_INSERT_DELAYED;
1233 }
1234 if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1235 int_table_flags |= HA_HAS_NEW_CHECKSUM;
1236
1237 /*
1238 For static size rows, tell MariaDB that we will access all bytes
1239 in the record when writing it. This signals MariaDB to initalize
1240 the full row to ensure we don't get any errors from valgrind and
1241 that all bytes in the row is properly reset.
1242 */
1243 if (file->s->data_file_type == STATIC_RECORD &&
1244 (file->s->has_varchar_fields | file->s->has_null_fields))
1245 int_table_flags|= HA_RECORD_MUST_BE_CLEAN_ON_WRITE;
1246
1247 for (i= 0; i < table->s->keys; i++)
1248 {
1249 plugin_ref parser= table->key_info[i].parser;
1250 if (table->key_info[i].flags & HA_USES_PARSER)
1251 file->s->keyinfo[i].parser=
1252 (struct st_mysql_ftparser *)plugin_decl(parser)->info;
1253 table->key_info[i].block_size= file->s->keyinfo[i].block_length;
1254 }
1255 my_errno= 0;
1256
1257 /* Count statistics of usage for newly open normal files */
1258 if (file->s->reopen == 1 && ! (test_if_locked & HA_OPEN_TMP_TABLE))
1259 {
1260 if (file->s->delay_key_write)
1261 feature_files_opened_with_delayed_keys++;
1262 }
1263
1264 return my_errno;
1265}
1266
1267
1268int ha_maria::close(void)
1269{
1270 MARIA_HA *tmp= file;
1271 if (!tmp)
1272 return 0;
1273 file= 0;
1274 return maria_close(tmp);
1275}
1276
1277
1278int ha_maria::write_row(uchar * buf)
1279{
1280 /*
1281 If we have an auto_increment column and we are writing a changed row
1282 or a new row, then update the auto_increment value in the record.
1283 */
1284 if (table->next_number_field && buf == table->record[0])
1285 {
1286 int error;
1287 if ((error= update_auto_increment()))
1288 return error;
1289 }
1290 return maria_write(file, buf);
1291}
1292
1293
1294int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
1295{
1296 int error;
1297 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1298 MARIA_SHARE *share= file->s;
1299 const char *old_proc_info;
1300 TRN *old_trn= file->trn;
1301
1302 if (!file || !param) return HA_ADMIN_INTERNAL_ERROR;
1303
1304 maria_chk_init(param);
1305 param->thd= thd;
1306 param->op_name= "check";
1307 param->db_name= table->s->db.str;
1308 param->table_name= table->alias.c_ptr();
1309 param->testflag= check_opt->flags | T_CHECK | T_SILENT;
1310 param->stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
1311
1312 if (!(table->db_stat & HA_READ_ONLY))
1313 param->testflag |= T_STATISTICS;
1314 param->using_global_keycache= 1;
1315
1316 if (!maria_is_crashed(file) &&
1317 (((param->testflag & T_CHECK_ONLY_CHANGED) &&
1318 !(share->state.changed & (STATE_CHANGED | STATE_CRASHED_FLAGS |
1319 STATE_IN_REPAIR)) &&
1320 share->state.open_count == 0) ||
1321 ((param->testflag & T_FAST) && (share->state.open_count ==
1322 (uint) (share->global_changed ? 1 :
1323 0)))))
1324 return HA_ADMIN_ALREADY_DONE;
1325
1326 maria_chk_init_for_check(param, file);
1327
1328 if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) ==
1329 STATE_MOVED)
1330 {
1331 _ma_check_print_error(param, "%s", zerofill_error_msg);
1332 return HA_ADMIN_CORRUPT;
1333 }
1334
1335 old_proc_info= thd_proc_info(thd, "Checking status");
1336 thd_progress_init(thd, 3);
1337 error= maria_chk_status(param, file); // Not fatal
1338 /* maria_chk_size() will flush the page cache for this file */
1339 if (maria_chk_size(param, file))
1340 error= 1;
1341 if (!error)
1342 error|= maria_chk_del(param, file, param->testflag);
1343 thd_proc_info(thd, "Checking keys");
1344 thd_progress_next_stage(thd);
1345 if (!error)
1346 error= maria_chk_key(param, file);
1347 thd_proc_info(thd, "Checking data");
1348 thd_progress_next_stage(thd);
1349 if (!error)
1350 {
1351 if ((!(param->testflag & T_QUICK) &&
1352 ((share->options &
1353 (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
1354 (param->testflag & (T_EXTEND | T_MEDIUM)))) || maria_is_crashed(file))
1355 {
1356 ulonglong old_testflag= param->testflag;
1357 param->testflag |= T_MEDIUM;
1358 if (!(error= init_io_cache(&param->read_cache, file->dfile.file,
1359 my_default_record_cache_size, READ_CACHE,
1360 share->pack.header_length, 1, MYF(MY_WME))))
1361 {
1362 error= maria_chk_data_link(param, file,
1363 MY_TEST(param->testflag & T_EXTEND));
1364 end_io_cache(&param->read_cache);
1365 }
1366 param->testflag= old_testflag;
1367 }
1368 }
1369 if (!error)
1370 {
1371 if ((share->state.changed & (STATE_CHANGED |
1372 STATE_CRASHED_FLAGS |
1373 STATE_IN_REPAIR | STATE_NOT_ANALYZED)) ||
1374 (param->testflag & T_STATISTICS) || maria_is_crashed(file))
1375 {
1376 file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1377 mysql_mutex_lock(&share->intern_lock);
1378 DBUG_PRINT("info", ("Reseting crashed state"));
1379 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS |
1380 STATE_IN_REPAIR);
1381 if (!(table->db_stat & HA_READ_ONLY))
1382 error= maria_update_state_info(param, file,
1383 UPDATE_TIME | UPDATE_OPEN_COUNT |
1384 UPDATE_STAT);
1385 mysql_mutex_unlock(&share->intern_lock);
1386 info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
1387 HA_STATUS_CONST);
1388 }
1389 }
1390 else if (!maria_is_crashed(file) && !thd->killed)
1391 {
1392 maria_mark_crashed(file);
1393 file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1394 }
1395
1396 /* Reset trn, that may have been set by repair */
1397 _ma_set_trn_for_table(file, old_trn);
1398 thd_proc_info(thd, old_proc_info);
1399 thd_progress_end(thd);
1400 return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
1401}
1402
1403
1404/*
1405 Analyze the key distribution in the table
1406 As the table may be only locked for read, we have to take into account that
1407 two threads may do an analyze at the same time!
1408*/
1409
1410int ha_maria::analyze(THD *thd, HA_CHECK_OPT * check_opt)
1411{
1412 int error= 0;
1413 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1414 MARIA_SHARE *share= file->s;
1415 const char *old_proc_info;
1416
1417 if (!param)
1418 return HA_ADMIN_INTERNAL_ERROR;
1419
1420 maria_chk_init(param);
1421 param->thd= thd;
1422 param->op_name= "analyze";
1423 param->db_name= table->s->db.str;
1424 param->table_name= table->alias.c_ptr();
1425 param->testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
1426 T_DONT_CHECK_CHECKSUM);
1427 param->using_global_keycache= 1;
1428 param->stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
1429
1430 if (!(share->state.changed & STATE_NOT_ANALYZED))
1431 return HA_ADMIN_ALREADY_DONE;
1432
1433 old_proc_info= thd_proc_info(thd, "Scanning");
1434 thd_progress_init(thd, 1);
1435 error= maria_chk_key(param, file);
1436 if (!error)
1437 {
1438 mysql_mutex_lock(&share->intern_lock);
1439 error= maria_update_state_info(param, file, UPDATE_STAT);
1440 mysql_mutex_unlock(&share->intern_lock);
1441 }
1442 else if (!maria_is_crashed(file) && !thd->killed)
1443 maria_mark_crashed(file);
1444 thd_proc_info(thd, old_proc_info);
1445 thd_progress_end(thd);
1446 return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
1447}
1448
1449int ha_maria::repair(THD * thd, HA_CHECK_OPT *check_opt)
1450{
1451 int error;
1452 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1453 ha_rows start_records;
1454 const char *old_proc_info;
1455
1456 if (!file || !param)
1457 return HA_ADMIN_INTERNAL_ERROR;
1458
1459 maria_chk_init(param);
1460 param->thd= thd;
1461 param->op_name= "repair";
1462 param->testflag= ((check_opt->flags & ~(T_EXTEND)) |
1463 T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
1464 (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
1465 param->sort_buffer_length= THDVAR(thd, sort_buffer_size);
1466 param->backup_time= check_opt->start_time;
1467 start_records= file->state->records;
1468 old_proc_info= thd_proc_info(thd, "Checking table");
1469 thd_progress_init(thd, 1);
1470 while ((error= repair(thd, param, 0)) && param->retry_repair)
1471 {
1472 param->retry_repair= 0;
1473 if (test_all_bits(param->testflag,
1474 (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
1475 {
1476 param->testflag&= ~(T_RETRY_WITHOUT_QUICK | T_QUICK);
1477 /* Ensure we don't loose any rows when retrying without quick */
1478 param->testflag|= T_SAFE_REPAIR;
1479 if (thd->vio_ok())
1480 _ma_check_print_info(param, "Retrying repair without quick");
1481 else
1482 sql_print_information("Retrying repair of: '%s' without quick",
1483 table->s->path.str);
1484 continue;
1485 }
1486 param->testflag &= ~T_QUICK;
1487 if (param->testflag & T_REP_BY_SORT)
1488 {
1489 param->testflag= (param->testflag & ~T_REP_BY_SORT) | T_REP;
1490 if (thd->vio_ok())
1491 _ma_check_print_info(param, "Retrying repair with keycache");
1492 sql_print_information("Retrying repair of: '%s' with keycache",
1493 table->s->path.str);
1494 continue;
1495 }
1496 break;
1497 }
1498 if (!error && start_records != file->state->records &&
1499 !(check_opt->flags & T_VERY_SILENT))
1500 {
1501 char llbuff[22], llbuff2[22];
1502 sql_print_information("Found %s of %s rows when repairing '%s'",
1503 llstr(file->state->records, llbuff),
1504 llstr(start_records, llbuff2),
1505 table->s->path.str);
1506 }
1507 thd_proc_info(thd, old_proc_info);
1508 thd_progress_end(thd);
1509 return error;
1510}
1511
1512int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
1513{
1514 int error;
1515 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1516 TRN *old_trn;
1517 MARIA_SHARE *share= file->s;
1518
1519 if (!file || !param)
1520 return HA_ADMIN_INTERNAL_ERROR;
1521
1522 old_trn= file->trn;
1523 maria_chk_init(param);
1524 param->thd= thd;
1525 param->op_name= "zerofill";
1526 param->testflag= check_opt->flags | T_SILENT | T_ZEROFILL;
1527 param->sort_buffer_length= THDVAR(thd, sort_buffer_size);
1528 error=maria_zerofill(param, file, share->open_file_name.str);
1529
1530 /* Reset trn, that may have been set by repair */
1531 _ma_set_trn_for_table(file, old_trn);
1532
1533 if (!error)
1534 {
1535 TrID create_trid= trnman_get_min_safe_trid();
1536 mysql_mutex_lock(&share->intern_lock);
1537 share->state.changed|= STATE_NOT_MOVABLE;
1538 maria_update_state_info(param, file, UPDATE_TIME | UPDATE_OPEN_COUNT);
1539 _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE, create_trid,
1540 TRUE, TRUE);
1541 mysql_mutex_unlock(&share->intern_lock);
1542 }
1543 return error;
1544}
1545
1546int ha_maria::optimize(THD * thd, HA_CHECK_OPT *check_opt)
1547{
1548 int error;
1549 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1550
1551 if (!file || !param)
1552 return HA_ADMIN_INTERNAL_ERROR;
1553
1554 maria_chk_init(param);
1555 param->thd= thd;
1556 param->op_name= "optimize";
1557 param->testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
1558 T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
1559 param->sort_buffer_length= THDVAR(thd, sort_buffer_size);
1560 thd_progress_init(thd, 1);
1561 if ((error= repair(thd, param, 1)) && param->retry_repair)
1562 {
1563 sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
1564 my_errno, param->db_name, param->table_name);
1565 param->testflag &= ~T_REP_BY_SORT;
1566 error= repair(thd, param, 0);
1567 }
1568 thd_progress_end(thd);
1569 return error;
1570}
1571
1572
1573int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
1574{
1575 int error= 0;
1576 ulonglong local_testflag= param->testflag;
1577 bool optimize_done= !do_optimize, statistics_done= 0, full_repair_done= 0;
1578 const char *old_proc_info= thd->proc_info;
1579 char fixed_name[FN_REFLEN];
1580 MARIA_SHARE *share= file->s;
1581 ha_rows rows= file->state->records;
1582 TRN *old_trn= file->trn;
1583 my_bool locking= 0;
1584 DBUG_ENTER("ha_maria::repair");
1585
1586 /*
1587 Normally this method is entered with a properly opened table. If the
1588 repair fails, it can be repeated with more elaborate options. Under
1589 special circumstances it can happen that a repair fails so that it
1590 closed the data file and cannot re-open it. In this case file->dfile
1591 is set to -1. We must not try another repair without an open data
1592 file. (Bug #25289)
1593 */
1594 if (file->dfile.file == -1)
1595 {
1596 sql_print_information("Retrying repair of: '%s' failed. "
1597 "Please try REPAIR EXTENDED or aria_chk",
1598 table->s->path.str);
1599 DBUG_RETURN(HA_ADMIN_FAILED);
1600 }
1601
1602 /*
1603 If transactions was not enabled for a transactional table then
1604 file->s->status is not up to date. This is needed for repair_by_sort
1605 to work
1606 */
1607 if (share->base.born_transactional && !share->now_transactional)
1608 _ma_copy_nontrans_state_information(file);
1609
1610 param->db_name= table->s->db.str;
1611 param->table_name= table->alias.c_ptr();
1612 param->tmpfile_createflag= O_RDWR | O_TRUNC;
1613 param->using_global_keycache= 1;
1614 param->thd= thd;
1615 param->tmpdir= &mysql_tmpdir_list;
1616 param->out_flag= 0;
1617 share->state.dupp_key= MI_MAX_KEY;
1618 strmov(fixed_name, share->open_file_name.str);
1619
1620 /*
1621 Don't lock tables if we have used LOCK TABLE or if we come from
1622 enable_index()
1623 */
1624 if (!thd->locked_tables_mode && ! (param->testflag & T_NO_LOCKS))
1625 {
1626 locking= 1;
1627 if (maria_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
1628 {
1629 _ma_check_print_error(param, ER_THD(thd, ER_CANT_LOCK), my_errno);
1630 DBUG_RETURN(HA_ADMIN_FAILED);
1631 }
1632 }
1633
1634 if (!do_optimize ||
1635 (((share->data_file_type == BLOCK_RECORD) ?
1636 (share->state.changed & STATE_NOT_OPTIMIZED_ROWS) :
1637 (file->state->del ||
1638 share->state.split != file->state->records)) &&
1639 (!(param->testflag & T_QUICK) ||
1640 (share->state.changed & (STATE_NOT_OPTIMIZED_KEYS |
1641 STATE_NOT_OPTIMIZED_ROWS)))))
1642 {
1643 ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
1644 maria_get_mask_all_keys_active(share->base.keys) :
1645 share->state.key_map);
1646 ulonglong save_testflag= param->testflag;
1647 if (maria_test_if_sort_rep(file, file->state->records, key_map, 0) &&
1648 (local_testflag & T_REP_BY_SORT))
1649 {
1650 local_testflag |= T_STATISTICS;
1651 param->testflag |= T_STATISTICS; // We get this for free
1652 statistics_done= 1;
1653 /* TODO: Remove BLOCK_RECORD test when parallel works with blocks */
1654 if (THDVAR(thd,repair_threads) > 1 &&
1655 share->data_file_type != BLOCK_RECORD)
1656 {
1657 char buf[40];
1658 /* TODO: respect maria_repair_threads variable */
1659 my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
1660 thd_proc_info(thd, buf);
1661 param->testflag|= T_REP_PARALLEL;
1662 error= maria_repair_parallel(param, file, fixed_name,
1663 MY_TEST(param->testflag & T_QUICK));
1664 /* to reset proc_info, as it was pointing to local buffer */
1665 thd_proc_info(thd, "Repair done");
1666 }
1667 else
1668 {
1669 thd_proc_info(thd, "Repair by sorting");
1670 param->testflag|= T_REP_BY_SORT;
1671 error= maria_repair_by_sort(param, file, fixed_name,
1672 MY_TEST(param->testflag & T_QUICK));
1673 }
1674 if (error && file->create_unique_index_by_sort &&
1675 share->state.dupp_key != MAX_KEY)
1676 {
1677 my_errno= HA_ERR_FOUND_DUPP_KEY;
1678 print_keydup_error(table, &table->key_info[share->state.dupp_key],
1679 MYF(0));
1680 }
1681 }
1682 else
1683 {
1684 thd_proc_info(thd, "Repair with keycache");
1685 param->testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL);
1686 error= maria_repair(param, file, fixed_name,
1687 MY_TEST(param->testflag & T_QUICK));
1688 }
1689 param->testflag= save_testflag | (param->testflag & T_RETRY_WITHOUT_QUICK);
1690 optimize_done= 1;
1691 /*
1692 set full_repair_done if we re-wrote all rows and all keys
1693 (and thus removed all transid's from the table
1694 */
1695 full_repair_done= !MY_TEST(param->testflag & T_QUICK);
1696 }
1697 if (!error)
1698 {
1699 if ((local_testflag & T_SORT_INDEX) &&
1700 (share->state.changed & STATE_NOT_SORTED_PAGES))
1701 {
1702 optimize_done= 1;
1703 thd_proc_info(thd, "Sorting index");
1704 error= maria_sort_index(param, file, fixed_name);
1705 }
1706 if (!error && !statistics_done && (local_testflag & T_STATISTICS))
1707 {
1708 if (share->state.changed & STATE_NOT_ANALYZED)
1709 {
1710 optimize_done= 1;
1711 thd_proc_info(thd, "Analyzing");
1712 error= maria_chk_key(param, file);
1713 }
1714 else
1715 local_testflag &= ~T_STATISTICS; // Don't update statistics
1716 }
1717 }
1718 thd_proc_info(thd, "Saving state");
1719 if (full_repair_done && !error &&
1720 !(param->testflag & T_NO_CREATE_RENAME_LSN))
1721 {
1722 /* Set trid (needed if the table was moved from another system) */
1723 share->state.create_trid= trnman_get_min_safe_trid();
1724 }
1725 mysql_mutex_lock(&share->intern_lock);
1726 if (!error)
1727 {
1728 if ((share->state.changed & STATE_CHANGED) || maria_is_crashed(file))
1729 {
1730 DBUG_PRINT("info", ("Reseting crashed state"));
1731 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS |
1732 STATE_IN_REPAIR | STATE_MOVED);
1733 file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1734 }
1735 /*
1736 repair updates share->state.state. Ensure that file->state is up to date
1737 */
1738 if (file->state != &share->state.state)
1739 *file->state= share->state.state;
1740
1741 if (share->base.auto_key)
1742 _ma_update_auto_increment_key(param, file, 1);
1743 if (optimize_done)
1744 error= maria_update_state_info(param, file,
1745 UPDATE_TIME | UPDATE_OPEN_COUNT |
1746 (local_testflag &
1747 T_STATISTICS ? UPDATE_STAT : 0));
1748 /* File is repaired; Mark the file as moved to this system */
1749 (void) _ma_set_uuid(share, 0);
1750
1751 info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
1752 HA_STATUS_CONST);
1753 if (rows != file->state->records && !(param->testflag & T_VERY_SILENT))
1754 {
1755 char llbuff[22], llbuff2[22];
1756 _ma_check_print_warning(param, "Number of rows changed from %s to %s",
1757 llstr(rows, llbuff),
1758 llstr(file->state->records, llbuff2));
1759 }
1760 }
1761 else
1762 {
1763 maria_mark_crashed_on_repair(file);
1764 file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1765 maria_update_state_info(param, file, 0);
1766 }
1767 mysql_mutex_unlock(&share->intern_lock);
1768 thd_proc_info(thd, old_proc_info);
1769 thd_progress_end(thd); // Mark done
1770 if (locking)
1771 maria_lock_database(file, F_UNLCK);
1772
1773 /* Reset trn, that may have been set by repair */
1774 _ma_set_trn_for_table(file, old_trn);
1775 error= error ? HA_ADMIN_FAILED :
1776 (optimize_done ?
1777 (write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED :
1778 HA_ADMIN_OK) : HA_ADMIN_ALREADY_DONE);
1779 DBUG_RETURN(error);
1780}
1781
1782
1783/*
1784 Assign table indexes to a specific key cache.
1785*/
1786
1787int ha_maria::assign_to_keycache(THD * thd, HA_CHECK_OPT *check_opt)
1788{
1789#if 0 && NOT_IMPLEMENTED
1790 PAGECACHE *new_pagecache= check_opt->pagecache;
1791 const char *errmsg= 0;
1792 int error= HA_ADMIN_OK;
1793 ulonglong map;
1794 TABLE_LIST *table_list= table->pos_in_table_list;
1795 DBUG_ENTER("ha_maria::assign_to_keycache");
1796
1797
1798 table->keys_in_use_for_query.clear_all();
1799
1800 if (table_list->process_index_hints(table))
1801 DBUG_RETURN(HA_ADMIN_FAILED);
1802 map= ~(ulonglong) 0;
1803 if (!table->keys_in_use_for_query.is_clear_all())
1804 /* use all keys if there's no list specified by the user through hints */
1805 map= table->keys_in_use_for_query.to_ulonglong();
1806
1807 if ((error= maria_assign_to_pagecache(file, map, new_pagecache)))
1808 {
1809 char buf[STRING_BUFFER_USUAL_SIZE];
1810 my_snprintf(buf, sizeof(buf),
1811 "Failed to flush to index file (errno: %d)", error);
1812 errmsg= buf;
1813 error= HA_ADMIN_CORRUPT;
1814 }
1815
1816 if (error != HA_ADMIN_OK)
1817 {
1818 /* Send error to user */
1819 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1820 if (!param)
1821 return HA_ADMIN_INTERNAL_ERROR;
1822
1823 maria_chk_init(param);
1824 param->thd= thd;
1825 param->op_name= "assign_to_keycache";
1826 param->db_name= table->s->db.str;
1827 param->table_name= table->s->table_name.str;
1828 param->testflag= 0;
1829 _ma_check_print_error(param, errmsg);
1830 }
1831 DBUG_RETURN(error);
1832#else
1833 return HA_ADMIN_NOT_IMPLEMENTED;
1834#endif
1835}
1836
1837
1838/*
1839 Preload pages of the index file for a table into the key cache.
1840*/
1841
1842int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt)
1843{
1844 ulonglong map;
1845 TABLE_LIST *table_list= table->pos_in_table_list;
1846
1847 DBUG_ENTER("ha_maria::preload_keys");
1848
1849 table->keys_in_use_for_query.clear_all();
1850
1851 if (table_list->process_index_hints(table))
1852 DBUG_RETURN(HA_ADMIN_FAILED);
1853
1854 map= ~(ulonglong) 0;
1855 /* Check validity of the index references */
1856 if (!table->keys_in_use_for_query.is_clear_all())
1857 /* use all keys if there's no list specified by the user through hints */
1858 map= table->keys_in_use_for_query.to_ulonglong();
1859
1860 maria_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
1861 (void*) &thd->variables.preload_buff_size);
1862
1863 int error;
1864
1865 if ((error= maria_preload(file, map, table_list->ignore_leaves)))
1866 {
1867 char buf[MYSQL_ERRMSG_SIZE+20];
1868 const char *errmsg;
1869
1870 switch (error) {
1871 case HA_ERR_NON_UNIQUE_BLOCK_SIZE:
1872 errmsg= "Indexes use different block sizes";
1873 break;
1874 case HA_ERR_OUT_OF_MEM:
1875 errmsg= "Failed to allocate buffer";
1876 break;
1877 default:
1878 my_snprintf(buf, sizeof(buf),
1879 "Failed to read from index file (errno: %d)", my_errno);
1880 errmsg= buf;
1881 }
1882
1883 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1884 if (!param)
1885 return HA_ADMIN_INTERNAL_ERROR;
1886
1887 maria_chk_init(param);
1888 param->thd= thd;
1889 param->op_name= "preload_keys";
1890 param->db_name= table->s->db.str;
1891 param->table_name= table->s->table_name.str;
1892 param->testflag= 0;
1893 _ma_check_print_error(param, "%s", errmsg);
1894 DBUG_RETURN(HA_ADMIN_FAILED);
1895 }
1896 DBUG_RETURN(HA_ADMIN_OK);
1897}
1898
1899
1900/*
1901 Disable indexes, making it persistent if requested.
1902
1903 SYNOPSIS
1904 disable_indexes()
1905 mode mode of operation:
1906 HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
1907 HA_KEY_SWITCH_ALL disable all keys
1908 HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
1909 HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
1910
1911 IMPLEMENTATION
1912 HA_KEY_SWITCH_NONUNIQ is not implemented.
1913 HA_KEY_SWITCH_ALL_SAVE is not implemented.
1914
1915 RETURN
1916 0 ok
1917 HA_ERR_WRONG_COMMAND mode not implemented.
1918*/
1919
1920int ha_maria::disable_indexes(uint mode)
1921{
1922 int error;
1923
1924 if (mode == HA_KEY_SWITCH_ALL)
1925 {
1926 /* call a storage engine function to switch the key map */
1927 error= maria_disable_indexes(file);
1928 }
1929 else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1930 {
1931 maria_extra(file, HA_EXTRA_NO_KEYS, 0);
1932 info(HA_STATUS_CONST); // Read new key info
1933 error= 0;
1934 }
1935 else
1936 {
1937 /* mode not implemented */
1938 error= HA_ERR_WRONG_COMMAND;
1939 }
1940 return error;
1941}
1942
1943
1944/*
1945 Enable indexes, making it persistent if requested.
1946
1947 SYNOPSIS
1948 enable_indexes()
1949 mode mode of operation:
1950 HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
1951 HA_KEY_SWITCH_ALL enable all keys
1952 HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
1953 HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
1954
1955 DESCRIPTION
1956 Enable indexes, which might have been disabled by disable_index() before.
1957 The modes without _SAVE work only if both data and indexes are empty,
1958 since the MARIA repair would enable them persistently.
1959 To be sure in these cases, call handler::delete_all_rows() before.
1960
1961 IMPLEMENTATION
1962 HA_KEY_SWITCH_NONUNIQ is not implemented.
1963 HA_KEY_SWITCH_ALL_SAVE is not implemented.
1964
1965 RETURN
1966 0 ok
1967 !=0 Error, among others:
1968 HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
1969 HA_ERR_WRONG_COMMAND mode not implemented.
1970*/
1971
1972int ha_maria::enable_indexes(uint mode)
1973{
1974 int error;
1975 DBUG_PRINT("info", ("ha_maria::enable_indexes mode: %d", mode));
1976 if (maria_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
1977 {
1978 /* All indexes are enabled already. */
1979 return 0;
1980 }
1981
1982 if (mode == HA_KEY_SWITCH_ALL)
1983 {
1984 error= maria_enable_indexes(file);
1985 /*
1986 Do not try to repair on error,
1987 as this could make the enabled state persistent,
1988 but mode==HA_KEY_SWITCH_ALL forbids it.
1989 */
1990 }
1991 else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1992 {
1993 THD *thd= table->in_use;
1994 HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
1995 if (!param)
1996 return HA_ADMIN_INTERNAL_ERROR;
1997
1998 const char *save_proc_info= thd_proc_info(thd, "Creating index");
1999
2000 maria_chk_init(param);
2001 param->op_name= "recreating_index";
2002 param->testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
2003 T_CREATE_MISSING_KEYS | T_SAFE_REPAIR);
2004 /*
2005 Don't lock and unlock table if it's locked.
2006 Normally table should be locked. This test is mostly for safety.
2007 */
2008 if (likely(file->lock_type != F_UNLCK))
2009 param->testflag|= T_NO_LOCKS;
2010
2011 if (file->create_unique_index_by_sort)
2012 param->testflag|= T_CREATE_UNIQUE_BY_SORT;
2013
2014 if (bulk_insert_single_undo == BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR)
2015 {
2016 bulk_insert_single_undo= BULK_INSERT_SINGLE_UNDO_AND_REPAIR;
2017 /*
2018 Don't bump create_rename_lsn, because UNDO_BULK_INSERT
2019 should not be skipped in case of crash during repair.
2020 */
2021 param->testflag|= T_NO_CREATE_RENAME_LSN;
2022 }
2023
2024 param->myf_rw &= ~MY_WAIT_IF_FULL;
2025 param->sort_buffer_length= THDVAR(thd,sort_buffer_size);
2026 param->stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
2027 param->tmpdir= &mysql_tmpdir_list;
2028 if ((error= (repair(thd, param, 0) != HA_ADMIN_OK)) && param->retry_repair)
2029 {
2030 sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, "
2031 "retrying",
2032 my_errno, param->db_name, param->table_name);
2033 /* This should never fail normally */
2034 DBUG_ASSERT(thd->killed != 0);
2035 /* Repairing by sort failed. Now try standard repair method. */
2036 param->testflag &= ~T_REP_BY_SORT;
2037 error= (repair(thd, param, 0) != HA_ADMIN_OK);
2038 /*
2039 If the standard repair succeeded, clear all error messages which
2040 might have been set by the first repair. They can still be seen
2041 with SHOW WARNINGS then.
2042 */
2043 if (!error)
2044 thd->clear_error();
2045 }
2046 info(HA_STATUS_CONST);
2047 thd_proc_info(thd, save_proc_info);
2048 }
2049 else
2050 {
2051 /* mode not implemented */
2052 error= HA_ERR_WRONG_COMMAND;
2053 }
2054 DBUG_EXECUTE_IF("maria_flush_whole_log",
2055 {
2056 DBUG_PRINT("maria_flush_whole_log", ("now"));
2057 translog_flush(translog_get_horizon());
2058 });
2059 DBUG_EXECUTE_IF("maria_crash_enable_index",
2060 {
2061 DBUG_PRINT("maria_crash_enable_index", ("now"));
2062 DBUG_SUICIDE();
2063 });
2064 return error;
2065}
2066
2067
2068/*
2069 Test if indexes are disabled.
2070
2071
2072 SYNOPSIS
2073 indexes_are_disabled()
2074 no parameters
2075
2076
2077 RETURN
2078 0 indexes are not disabled
2079 1 all indexes are disabled
2080 [2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
2081*/
2082
2083int ha_maria::indexes_are_disabled(void)
2084{
2085 return maria_indexes_are_disabled(file);
2086}
2087
2088
2089/*
2090 prepare for a many-rows insert operation
2091 e.g. - disable indexes (if they can be recreated fast) or
2092 activate special bulk-insert optimizations
2093
2094 SYNOPSIS
2095 start_bulk_insert(rows, flags)
2096 rows Rows to be inserted
2097 0 if we don't know
2098 flags Flags to control index creation
2099
2100 NOTICE
2101 Do not forget to call end_bulk_insert() later!
2102*/
2103
2104void ha_maria::start_bulk_insert(ha_rows rows, uint flags)
2105{
2106 DBUG_ENTER("ha_maria::start_bulk_insert");
2107 THD *thd= table->in_use;
2108 MARIA_SHARE *share= file->s;
2109 DBUG_PRINT("info", ("start_bulk_insert: rows %lu", (ulong) rows));
2110
2111 /* don't enable row cache if too few rows */
2112 if (!rows || (rows > MARIA_MIN_ROWS_TO_USE_WRITE_CACHE))
2113 {
2114 ulonglong size= thd->variables.read_buff_size, tmp;
2115 if (rows)
2116 {
2117 if (file->state->records)
2118 {
2119 MARIA_INFO maria_info;
2120 maria_status(file, &maria_info, HA_STATUS_NO_LOCK |HA_STATUS_VARIABLE);
2121 set_if_smaller(size, maria_info.mean_reclength * rows);
2122 }
2123 else if (table->s->avg_row_length)
2124 set_if_smaller(size, (size_t) (table->s->avg_row_length * rows));
2125 }
2126 tmp= (ulong) size; // Safe becasue of limits
2127 maria_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &tmp);
2128 }
2129
2130 can_enable_indexes= (maria_is_all_keys_active(share->state.key_map,
2131 share->base.keys));
2132 bulk_insert_single_undo= BULK_INSERT_NONE;
2133
2134 if (!(specialflag & SPECIAL_SAFE_MODE))
2135 {
2136 /*
2137 Only disable old index if the table was empty and we are inserting
2138 a lot of rows.
2139 We should not do this for only a few rows as this is slower and
2140 we don't want to update the key statistics based of only a few rows.
2141 Index file rebuild requires an exclusive lock, so if versioning is on
2142 don't do it (see how ha_maria::store_lock() tries to predict repair).
2143 We can repair index only if we have an exclusive (TL_WRITE) lock or
2144 if this is inside an ALTER TABLE, in which case lock_type == TL_UNLOCK.
2145
2146 To see if table is empty, we shouldn't rely on the old record
2147 count from our transaction's start (if that old count is 0 but
2148 now there are records in the table, we would wrongly destroy
2149 them). So we need to look at share->state.state.records. As a
2150 safety net for now, we don't remove the test of
2151 file->state->records, because there is uncertainty on what will
2152 happen during repair if the two states disagree.
2153
2154 We also have to check in case of transactional tables that the
2155 user has not used LOCK TABLE on the table twice.
2156 */
2157 if ((file->state->records == 0) &&
2158 (share->state.state.records == 0) && can_enable_indexes &&
2159 (!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES) &&
2160 (file->lock.type == TL_WRITE || file->lock.type == TL_UNLOCK) &&
2161 (!share->have_versioning || !share->now_transactional ||
2162 file->used_tables->use_count == 1))
2163 {
2164 /**
2165 @todo for a single-row INSERT SELECT, we will go into repair, which
2166 is more costly (flushes, syncs) than a row write.
2167 */
2168 if (file->open_flags & HA_OPEN_INTERNAL_TABLE)
2169 {
2170 /* Internal table; If we get a duplicate something is very wrong */
2171 file->update|= HA_STATE_CHANGED;
2172 maria_clear_all_keys_active(file->s->state.key_map);
2173 }
2174 else
2175 {
2176 my_bool all_keys= MY_TEST(flags & HA_CREATE_UNIQUE_INDEX_BY_SORT);
2177 maria_disable_indexes_for_rebuild(file, rows, all_keys);
2178 }
2179 if (share->now_transactional)
2180 {
2181 bulk_insert_single_undo= BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR;
2182 write_log_record_for_bulk_insert(file);
2183 _ma_tmp_disable_logging_for_table(file, TRUE);
2184 /*
2185 Pages currently in the page cache have type PAGECACHE_LSN_PAGE, we
2186 are not allowed to overwrite them with PAGECACHE_PLAIN_PAGE, so
2187 throw them away. It is not losing data, because we just wrote and
2188 forced an UNDO which will for sure empty the table if we crash. The
2189 upcoming unique-key insertions however need a proper index, so we
2190 cannot leave the corrupted on-disk index file, thus we truncate it.
2191 */
2192 maria_delete_all_rows(file);
2193 }
2194 }
2195 else if (!file->bulk_insert &&
2196 (!rows || rows >= MARIA_MIN_ROWS_TO_USE_BULK_INSERT))
2197 {
2198 maria_init_bulk_insert(file,
2199 (size_t) thd->variables.bulk_insert_buff_size,
2200 rows);
2201 }
2202 }
2203 DBUG_VOID_RETURN;
2204}
2205
2206
2207/*
2208 end special bulk-insert optimizations,
2209 which have been activated by start_bulk_insert().
2210
2211 SYNOPSIS
2212 end_bulk_insert()
2213 no arguments
2214
2215 RETURN
2216 0 OK
2217 != 0 Error
2218*/
2219
2220int ha_maria::end_bulk_insert()
2221{
2222 int first_error, error;
2223 my_bool abort= file->s->deleting;
2224 DBUG_ENTER("ha_maria::end_bulk_insert");
2225
2226 if ((first_error= maria_end_bulk_insert(file, abort)))
2227 abort= 1;
2228
2229 if ((error= maria_extra(file, HA_EXTRA_NO_CACHE, 0)))
2230 {
2231 first_error= first_error ? first_error : error;
2232 abort= 1;
2233 }
2234
2235 if (!abort && can_enable_indexes)
2236 if ((error= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE)))
2237 first_error= first_error ? first_error : error;
2238
2239 if (bulk_insert_single_undo != BULK_INSERT_NONE)
2240 {
2241 DBUG_ASSERT(can_enable_indexes);
2242 /*
2243 Table was transactional just before start_bulk_insert().
2244 No need to flush pages if we did a repair (which already flushed).
2245 */
2246 if ((error= _ma_reenable_logging_for_table(file,
2247 bulk_insert_single_undo ==
2248 BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR)))
2249 first_error= first_error ? first_error : error;
2250 bulk_insert_single_undo= BULK_INSERT_NONE; // Safety
2251 }
2252 DBUG_RETURN(first_error);
2253}
2254
2255
2256bool ha_maria::check_and_repair(THD *thd)
2257{
2258 int error, crashed;
2259 HA_CHECK_OPT check_opt;
2260 const CSET_STRING query_backup= thd->query_string;
2261 DBUG_ENTER("ha_maria::check_and_repair");
2262
2263 check_opt.init();
2264 check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
2265
2266 error= 1;
2267 if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) ==
2268 STATE_MOVED)
2269 {
2270 /* Remove error about crashed table */
2271 thd->get_stmt_da()->clear_warning_info(thd->query_id);
2272 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
2273 ER_CRASHED_ON_USAGE,
2274 "Zerofilling moved table %s", table->s->path.str);
2275 sql_print_information("Zerofilling moved table: '%s'",
2276 table->s->path.str);
2277 if (!(error= zerofill(thd, &check_opt)))
2278 DBUG_RETURN(0);
2279 }
2280
2281 /*
2282 if we got this far - the table is crashed.
2283 but don't auto-repair if maria_recover_options is not set
2284 */
2285 if (!maria_recover_options)
2286 DBUG_RETURN(error);
2287
2288 error= 0;
2289 // Don't use quick if deleted rows
2290 if (!file->state->del && (maria_recover_options & HA_RECOVER_QUICK))
2291 check_opt.flags |= T_QUICK;
2292
2293 thd->set_query((char*) table->s->table_name.str,
2294 (uint) table->s->table_name.length, system_charset_info);
2295
2296 if (!(crashed= maria_is_crashed(file)))
2297 {
2298 sql_print_warning("Checking table: '%s'", table->s->path.str);
2299 crashed= check(thd, &check_opt);
2300 }
2301
2302 if (crashed)
2303 {
2304 bool save_log_all_errors;
2305 sql_print_warning("Recovering table: '%s'", table->s->path.str);
2306 save_log_all_errors= thd->log_all_errors;
2307 thd->log_all_errors|= (thd->variables.log_warnings > 2);
2308 check_opt.flags=
2309 ((maria_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
2310 (maria_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
2311 T_AUTO_REPAIR);
2312 if (repair(thd, &check_opt))
2313 error= 1;
2314 thd->log_all_errors= save_log_all_errors;
2315 }
2316 thd->set_query(query_backup);
2317 DBUG_RETURN(error);
2318}
2319
2320
2321bool ha_maria::is_crashed() const
2322{
2323 return (file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED) ||
2324 (my_disable_locking && file->s->state.open_count));
2325}
2326
2327#define CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING(msg) \
2328 do { \
2329 if (file->lock.type == TL_WRITE_CONCURRENT_INSERT && !table->s->sequence) \
2330 { \
2331 my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), msg); \
2332 return 1; \
2333 } \
2334 } while(0)
2335
2336int ha_maria::update_row(const uchar * old_data, const uchar * new_data)
2337{
2338 CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("UPDATE in WRITE CONCURRENT");
2339 return maria_update(file, old_data, new_data);
2340}
2341
2342
2343int ha_maria::delete_row(const uchar * buf)
2344{
2345 CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("DELETE in WRITE CONCURRENT");
2346 return maria_delete(file, buf);
2347}
2348
2349int ha_maria::index_read_map(uchar * buf, const uchar * key,
2350 key_part_map keypart_map,
2351 enum ha_rkey_function find_flag)
2352{
2353 DBUG_ASSERT(inited == INDEX);
2354 int error= maria_rkey(file, buf, active_index, key, keypart_map, find_flag);
2355 return error;
2356}
2357
2358
2359int ha_maria::index_read_idx_map(uchar * buf, uint index, const uchar * key,
2360 key_part_map keypart_map,
2361 enum ha_rkey_function find_flag)
2362{
2363 int error;
2364 /* Use the pushed index condition if it matches the index we're scanning */
2365 end_range= NULL;
2366 if (index == pushed_idx_cond_keyno)
2367 ma_set_index_cond_func(file, handler_index_cond_check, this);
2368
2369 error= maria_rkey(file, buf, index, key, keypart_map, find_flag);
2370
2371 ma_set_index_cond_func(file, NULL, 0);
2372 return error;
2373}
2374
2375
2376int ha_maria::index_read_last_map(uchar * buf, const uchar * key,
2377 key_part_map keypart_map)
2378{
2379 DBUG_ENTER("ha_maria::index_read_last_map");
2380 DBUG_ASSERT(inited == INDEX);
2381 int error= maria_rkey(file, buf, active_index, key, keypart_map,
2382 HA_READ_PREFIX_LAST);
2383 DBUG_RETURN(error);
2384}
2385
2386
2387int ha_maria::index_next(uchar * buf)
2388{
2389 DBUG_ASSERT(inited == INDEX);
2390 int error= maria_rnext(file, buf, active_index);
2391 return error;
2392}
2393
2394
2395int ha_maria::index_prev(uchar * buf)
2396{
2397 DBUG_ASSERT(inited == INDEX);
2398 int error= maria_rprev(file, buf, active_index);
2399 return error;
2400}
2401
2402
2403int ha_maria::index_first(uchar * buf)
2404{
2405 DBUG_ASSERT(inited == INDEX);
2406 int error= maria_rfirst(file, buf, active_index);
2407 return error;
2408}
2409
2410
2411int ha_maria::index_last(uchar * buf)
2412{
2413 DBUG_ASSERT(inited == INDEX);
2414 int error= maria_rlast(file, buf, active_index);
2415 return error;
2416}
2417
2418
2419int ha_maria::index_next_same(uchar * buf,
2420 const uchar *key __attribute__ ((unused)),
2421 uint length __attribute__ ((unused)))
2422{
2423 int error;
2424 DBUG_ASSERT(inited == INDEX);
2425 /*
2426 TODO: Delete this loop in Maria 1.5 as versioning will ensure this never
2427 happens
2428 */
2429 do
2430 {
2431 error= maria_rnext_same(file,buf);
2432 } while (error == HA_ERR_RECORD_DELETED);
2433 return error;
2434}
2435
2436
2437int ha_maria::index_init(uint idx, bool sorted)
2438{
2439 active_index=idx;
2440 if (pushed_idx_cond_keyno == idx)
2441 ma_set_index_cond_func(file, handler_index_cond_check, this);
2442 return 0;
2443}
2444
2445
2446int ha_maria::index_end()
2447{
2448 active_index=MAX_KEY;
2449 ma_set_index_cond_func(file, NULL, 0);
2450 in_range_check_pushed_down= FALSE;
2451 ds_mrr.dsmrr_close();
2452 return 0;
2453}
2454
2455
2456int ha_maria::rnd_init(bool scan)
2457{
2458 if (scan)
2459 return maria_scan_init(file);
2460 return maria_reset(file); // Free buffers
2461}
2462
2463
2464int ha_maria::rnd_end()
2465{
2466 ds_mrr.dsmrr_close();
2467 /* Safe to call even if we don't have started a scan */
2468 maria_scan_end(file);
2469 return 0;
2470}
2471
2472
2473int ha_maria::rnd_next(uchar *buf)
2474{
2475 int error= maria_scan(file, buf);
2476 return error;
2477}
2478
2479
2480int ha_maria::remember_rnd_pos()
2481{
2482 return (*file->s->scan_remember_pos)(file, &remember_pos);
2483}
2484
2485
2486int ha_maria::restart_rnd_next(uchar *buf)
2487{
2488 int error;
2489 if ((error= (*file->s->scan_restore_pos)(file, remember_pos)))
2490 return error;
2491 return rnd_next(buf);
2492}
2493
2494
2495int ha_maria::rnd_pos(uchar *buf, uchar *pos)
2496{
2497 int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length));
2498 return error;
2499}
2500
2501
2502void ha_maria::position(const uchar *record)
2503{
2504 my_off_t row_position= maria_position(file);
2505 my_store_ptr(ref, ref_length, row_position);
2506}
2507
2508
2509int ha_maria::info(uint flag)
2510{
2511 MARIA_INFO maria_info;
2512 char name_buff[FN_REFLEN];
2513
2514 (void) maria_status(file, &maria_info, flag);
2515 if (flag & HA_STATUS_VARIABLE)
2516 {
2517 stats.records= maria_info.records;
2518 stats.deleted= maria_info.deleted;
2519 stats.data_file_length= maria_info.data_file_length;
2520 stats.index_file_length= maria_info.index_file_length;
2521 stats.delete_length= maria_info.delete_length;
2522 stats.check_time= maria_info.check_time;
2523 stats.mean_rec_length= maria_info.mean_reclength;
2524 }
2525 if (flag & HA_STATUS_CONST)
2526 {
2527 TABLE_SHARE *share= table->s;
2528 stats.max_data_file_length= maria_info.max_data_file_length;
2529 stats.max_index_file_length= maria_info.max_index_file_length;
2530 stats.create_time= maria_info.create_time;
2531 ref_length= maria_info.reflength;
2532 share->db_options_in_use= maria_info.options;
2533 stats.block_size= maria_block_size;
2534 stats.mrr_length_per_rec= maria_info.reflength + 8; // 8 = MY_MAX(sizeof(void *))
2535
2536 /* Update share */
2537 share->keys_in_use.set_prefix(share->keys);
2538 share->keys_in_use.intersect_extended(maria_info.key_map);
2539 share->keys_for_keyread.intersect(share->keys_in_use);
2540 share->db_record_offset= maria_info.record_offset;
2541 if (share->key_parts)
2542 {
2543 ulong *to= table->key_info[0].rec_per_key, *end;
2544 double *from= maria_info.rec_per_key;
2545 for (end= to+ share->key_parts ; to < end ; to++, from++)
2546 *to= (ulong) (*from + 0.5);
2547 }
2548
2549 /*
2550 Set data_file_name and index_file_name to point at the symlink value
2551 if table is symlinked (Ie; Real name is not same as generated name)
2552 */
2553 data_file_name= index_file_name= 0;
2554 fn_format(name_buff, file->s->open_file_name.str, "", MARIA_NAME_DEXT,
2555 MY_APPEND_EXT | MY_UNPACK_FILENAME);
2556 if (strcmp(name_buff, maria_info.data_file_name))
2557 data_file_name =maria_info.data_file_name;
2558 fn_format(name_buff, file->s->open_file_name.str, "", MARIA_NAME_IEXT,
2559 MY_APPEND_EXT | MY_UNPACK_FILENAME);
2560 if (strcmp(name_buff, maria_info.index_file_name))
2561 index_file_name=maria_info.index_file_name;
2562 }
2563 if (flag & HA_STATUS_ERRKEY)
2564 {
2565 errkey= maria_info.errkey;
2566 my_store_ptr(dup_ref, ref_length, maria_info.dup_key_pos);
2567 }
2568 if (flag & HA_STATUS_TIME)
2569 stats.update_time= maria_info.update_time;
2570 if (flag & HA_STATUS_AUTO)
2571 stats.auto_increment_value= maria_info.auto_increment;
2572
2573 return 0;
2574}
2575
2576
2577int ha_maria::extra(enum ha_extra_function operation)
2578{
2579 int tmp;
2580 TRN *old_trn= file->trn;
2581 if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
2582 return 0;
2583#ifdef NOT_USED
2584 if (operation == HA_EXTRA_MMAP && !opt_maria_use_mmap)
2585 return 0;
2586#endif
2587
2588 /*
2589 We have to set file->trn here because in some cases we call
2590 extern_lock(F_UNLOCK) (which resets file->trn) followed by maria_close()
2591 without calling commit/rollback in between. If file->trn is not set
2592 we can't remove file->share from the transaction list in the extra() call.
2593
2594 We also ensure that we set file->trn to 0 if THD_TRN is 0 as in
2595 this case we have already freed the trn. This can happen when one
2596 implicit_commit() is called as part of alter table.
2597
2598 table->in_use is not set in the case this is a done as part of closefrm()
2599 as part of drop table.
2600 */
2601
2602 if (file->s->now_transactional && table->in_use &&
2603 (operation == HA_EXTRA_PREPARE_FOR_DROP ||
2604 operation == HA_EXTRA_PREPARE_FOR_RENAME ||
2605 operation == HA_EXTRA_PREPARE_FOR_FORCED_CLOSE))
2606 {
2607 THD *thd= table->in_use;
2608 TRN *trn= THD_TRN;
2609 _ma_set_trn_for_table(file, trn);
2610 }
2611 DBUG_ASSERT(file->s->base.born_transactional || file->trn == 0 ||
2612 file->trn == &dummy_transaction_object);
2613
2614 tmp= maria_extra(file, operation, 0);
2615 file->trn= old_trn; // Reset trn if was used
2616 return tmp;
2617}
2618
2619int ha_maria::reset(void)
2620{
2621 ma_set_index_cond_func(file, NULL, 0);
2622 ds_mrr.dsmrr_close();
2623 if (file->trn)
2624 {
2625 /* Next statement is a new statement. Ensure it's logged */
2626 trnman_set_flags(file->trn,
2627 trnman_get_flags(file->trn) & ~TRN_STATE_INFO_LOGGED);
2628 }
2629 return maria_reset(file);
2630}
2631
2632/* To be used with WRITE_CACHE and EXTRA_CACHE */
2633
2634int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size)
2635{
2636 if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
2637 return 0;
2638 return maria_extra(file, operation, (void*) &cache_size);
2639}
2640
2641
2642int ha_maria::delete_all_rows()
2643{
2644 THD *thd= table->in_use;
2645 TRN *trn= file->trn;
2646 CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("TRUNCATE in WRITE CONCURRENT");
2647#ifdef EXTRA_DEBUG
2648 if (trn && ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED))
2649 {
2650 trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED |
2651 TRN_STATE_TABLES_CAN_CHANGE);
2652 (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY,
2653 (uchar*) thd->query(), thd->query_length());
2654 }
2655#endif
2656 /*
2657 If we are under LOCK TABLES, we have to do a commit as
2658 delete_all_rows() can't be rolled back
2659 */
2660 if (table->in_use->locked_tables_mode && trn &&
2661 trnman_has_locked_tables(trn))
2662 {
2663 int error;
2664 if ((error= implicit_commit(thd, 1)))
2665 return error;
2666 }
2667
2668 /* Note that this can't be rolled back */
2669 return maria_delete_all_rows(file);
2670}
2671
2672
2673int ha_maria::delete_table(const char *name)
2674{
2675 THD *thd= current_thd;
2676 (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
2677 (uchar*) thd->query(), thd->query_length());
2678 return maria_delete_table(name);
2679}
2680
2681
2682/* This is mainly for temporary tables, so no logging necessary */
2683
2684void ha_maria::drop_table(const char *name)
2685{
2686 DBUG_ASSERT(file->s->temporary);
2687 (void) ha_close();
2688 (void) maria_delete_table_files(name, 1, 0);
2689}
2690
2691
2692void ha_maria::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share)
2693{
2694 handler::change_table_ptr(table_arg, share);
2695 if (file)
2696 file->external_ref= table_arg;
2697}
2698
2699
2700int ha_maria::external_lock(THD *thd, int lock_type)
2701{
2702 DBUG_ENTER("ha_maria::external_lock");
2703 file->external_ref= (void*) table; // For ma_killed()
2704 /*
2705 We don't test now_transactional because it may vary between lock/unlock
2706 and thus confuse our reference counting.
2707 It is critical to skip non-transactional tables: user-visible temporary
2708 tables get an external_lock() when read/written for the first time, but no
2709 corresponding unlock (they just stay locked and are later dropped while
2710 locked); if a tmp table was transactional, "SELECT FROM non_tmp, tmp"
2711 would never commit as its "locked_tables" count would stay 1.
2712 When Maria has has_transactions()==TRUE, open_temporary_table()
2713 (sql_base.cc) will use TRANSACTIONAL_TMP_TABLE and thus the
2714 external_lock(F_UNLCK) will happen and we can then allow the user to
2715 create transactional temporary tables.
2716 */
2717 if (file->s->base.born_transactional)
2718 {
2719 /* Transactional table */
2720 if (lock_type != F_UNLCK)
2721 {
2722 if (file->trn)
2723 {
2724 /* This can only happen with tables created with clone() */
2725 trnman_increment_locked_tables(file->trn);
2726 }
2727
2728 if (!thd->transaction.on)
2729 {
2730 /*
2731 No need to log REDOs/UNDOs. If this is an internal temporary table
2732 which will be renamed to a permanent table (like in ALTER TABLE),
2733 the rename happens after unlocking so will be durable (and the table
2734 will get its create_rename_lsn).
2735 Note: if we wanted to enable users to have an old backup and apply
2736 tons of archived logs to roll-forward, we could then not disable
2737 REDOs/UNDOs in this case.
2738 */
2739 DBUG_PRINT("info", ("Disabling logging for table"));
2740 _ma_tmp_disable_logging_for_table(file, TRUE);
2741 }
2742 }
2743 else
2744 {
2745 TRN *trn= THD_TRN;
2746 /* End of transaction */
2747
2748 /*
2749 We always re-enable, don't rely on thd->transaction.on as it is
2750 sometimes reset to true after unlocking (see mysql_truncate() for a
2751 partitioned table based on Maria).
2752 Note that we can come here without having an exclusive lock on the
2753 table, for example in this case:
2754 external_lock(F_(WR|RD)LCK); thr_lock() which fails due to lock
2755 abortion; external_lock(F_UNLCK). Fortunately, the re-enabling happens
2756 only if we were the thread which disabled logging.
2757 */
2758 if (_ma_reenable_logging_for_table(file, TRUE))
2759 DBUG_RETURN(1);
2760 /** @todo zero file->trn also in commit and rollback */
2761 _ma_set_trn_for_table(file, NULL); // Safety
2762 /*
2763 Ensure that file->state points to the current number of rows. This
2764 is needed if someone calls maria_info() without first doing an
2765 external lock of the table
2766 */
2767 file->state= &file->s->state.state;
2768 if (trn)
2769 {
2770 DBUG_PRINT("info",
2771 ("locked_tables: %u", trnman_has_locked_tables(trn)));
2772 DBUG_ASSERT(trnman_has_locked_tables(trn) > 0);
2773 if (trnman_has_locked_tables(trn) &&
2774 !trnman_decrement_locked_tables(trn))
2775 {
2776 /*
2777 OK should not have been sent to client yet (ACID).
2778 This is a bit excessive, ACID requires this only if there are some
2779 changes to commit (rollback shouldn't be tested).
2780 */
2781 DBUG_ASSERT(!thd->get_stmt_da()->is_sent() ||
2782 thd->killed == KILL_CONNECTION);
2783 /* autocommit ? rollback a transaction */
2784#ifdef MARIA_CANNOT_ROLLBACK
2785 if (ma_commit(trn))
2786 DBUG_RETURN(1);
2787 THD_TRN= 0;
2788#else
2789 if (!(thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
2790 {
2791 trnman_rollback_trn(trn);
2792 DBUG_PRINT("info", ("THD_TRN set to 0x0"));
2793 THD_TRN= 0;
2794 }
2795#endif
2796 }
2797 trnman_set_flags(trn, trnman_get_flags(trn) & ~ TRN_STATE_INFO_LOGGED);
2798 }
2799 }
2800 } /* if transactional table */
2801 DBUG_RETURN(maria_lock_database(file, !table->s->tmp_table ?
2802 lock_type : ((lock_type == F_UNLCK) ?
2803 F_UNLCK : F_EXTRA_LCK)));
2804}
2805
2806int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
2807{
2808 TRN *trn;
2809 if (file->s->base.born_transactional)
2810 {
2811 trn= THD_TRN;
2812 DBUG_ASSERT(trn); // this may be called only after external_lock()
2813 DBUG_ASSERT(trnman_has_locked_tables(trn));
2814 DBUG_ASSERT(lock_type != TL_UNLOCK);
2815 DBUG_ASSERT(file->trn == trn);
2816
2817 /*
2818 If there was an implicit commit under this LOCK TABLES by a previous
2819 statement (like a DDL), at least if that previous statement was about a
2820 different ha_maria than 'this' then this->file->trn is a stale
2821 pointer. We fix it:
2822 */
2823 _ma_set_trn_for_table(file, trn);
2824 /*
2825 As external_lock() was already called, don't increment locked_tables.
2826 Note that we call the function below possibly several times when
2827 statement starts (once per table). This is ok as long as that function
2828 does cheap operations. Otherwise, we will need to do it only on first
2829 call to start_stmt().
2830 */
2831 trnman_new_statement(trn);
2832
2833#ifdef EXTRA_DEBUG
2834 if (!(trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED) &&
2835 trnman_get_flags(trn) & TRN_STATE_TABLES_CAN_CHANGE)
2836 {
2837 trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED);
2838 (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY,
2839 (uchar*) thd->query(),
2840 thd->query_length());
2841 }
2842#endif
2843 }
2844 return 0;
2845}
2846
2847
2848/**
2849 Performs an implicit commit of the Maria transaction and creates a new
2850 one.
2851
2852 This can be considered a hack. When Maria loses HA_NO_TRANSACTIONS it will
2853 be participant in the connection's transaction and so the implicit commits
2854 (ha_commit()) (like in end_active_trans()) will do the implicit commit
2855 without need to call this function which can then be removed.
2856
2857 @param thd THD object
2858 @param new_trn if a new transaction should be created; a new
2859 transaction is not needed when we know that the
2860 tables will be unlocked very soon.
2861*/
2862
2863int ha_maria::implicit_commit(THD *thd, bool new_trn)
2864{
2865#ifndef MARIA_CANNOT_ROLLBACK
2866#error this method should be removed
2867#endif
2868 TRN *trn;
2869 int error;
2870 uint locked_tables;
2871 DYNAMIC_ARRAY used_tables;
2872 extern my_bool plugins_are_initialized;
2873
2874 DBUG_ENTER("ha_maria::implicit_commit");
2875 if (!maria_hton || !plugins_are_initialized || !(trn= THD_TRN))
2876 DBUG_RETURN(0);
2877 if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES ||
2878 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
2879 {
2880 /*
2881 No commit inside LOCK TABLES.
2882
2883 Note that we come here only at the end of the top statement
2884 (dispatch_command()), we are never committing inside a sub-statement./
2885 */
2886 DBUG_PRINT("info", ("locked_tables, skipping"));
2887 DBUG_RETURN(0);
2888 }
2889
2890 locked_tables= trnman_has_locked_tables(trn);
2891
2892 if (new_trn && trn && trn->used_tables)
2893 {
2894 MARIA_USED_TABLES *tables;
2895 /*
2896 Save locked tables so that we can move them to another transaction
2897 We are using a dynamic array as locked_tables in some cases can be
2898 smaller than the used_tables list (for example when the server does
2899 early unlock of tables.
2900 */
2901
2902 my_init_dynamic_array2(&used_tables, sizeof(MARIA_SHARE*), (void*) 0,
2903 locked_tables, 8, MYF(MY_THREAD_SPECIFIC));
2904 for (tables= (MARIA_USED_TABLES*) trn->used_tables;
2905 tables;
2906 tables= tables->next)
2907 {
2908 if (tables->share->base.born_transactional)
2909 {
2910 if (insert_dynamic(&used_tables, (uchar*) &tables->share))
2911 {
2912 error= HA_ERR_OUT_OF_MEM;
2913 goto end_and_free;
2914 }
2915 }
2916 }
2917 }
2918 else
2919 bzero(&used_tables, sizeof(used_tables));
2920
2921 error= 0;
2922 if (unlikely(ma_commit(trn)))
2923 error= 1;
2924 if (!new_trn)
2925 {
2926 /*
2927 To be extra safe, we should also reset file->trn for all open
2928 tables as some calls, like extra() may access it. We take care
2929 of this in extra() by resetting file->trn if THD_TRN is 0.
2930 */
2931 THD_TRN= NULL;
2932 goto end;
2933 }
2934 /*
2935 We need to create a new transaction and put it in THD_TRN. Indeed,
2936 tables may be under LOCK TABLES, and so they will start the next
2937 statement assuming they have a trn (see ha_maria::start_stmt()).
2938 */
2939 trn= trnman_new_trn(& thd->transaction.wt);
2940 THD_TRN= trn;
2941 if (unlikely(trn == NULL))
2942 {
2943 error= HA_ERR_OUT_OF_MEM;
2944 goto end_and_free;
2945 }
2946 /*
2947 Move all locked tables to the new transaction
2948 We must do it here as otherwise file->thd and file->state may be
2949 stale pointers. We can't do this in start_stmt() as we don't know
2950 when we should call _ma_setup_live_state() and in some cases, like
2951 in check table, we use the table without calling start_stmt().
2952 */
2953
2954 uint i;
2955 for (i= 0 ; i < used_tables.elements ; i++)
2956 {
2957 MARIA_SHARE *share;
2958 LIST *handlers;
2959
2960 share= *(dynamic_element(&used_tables, i, MARIA_SHARE**));
2961 /* Find table instances that was used in this transaction */
2962 for (handlers= share->open_list; handlers; handlers= handlers->next)
2963 {
2964 MARIA_HA *handler= (MARIA_HA*) handlers->data;
2965 if (handler->external_ref &&
2966 ((TABLE*) handler->external_ref)->in_use == thd)
2967 {
2968 _ma_set_trn_for_table(handler, trn);
2969 /* If handler uses versioning */
2970 if (handler->s->lock_key_trees)
2971 {
2972 if (_ma_setup_live_state(handler))
2973 error= HA_ERR_OUT_OF_MEM;
2974 }
2975 }
2976 }
2977 }
2978 /* This is just a commit, tables stay locked if they were: */
2979 trnman_reset_locked_tables(trn, locked_tables);
2980
2981end_and_free:
2982 delete_dynamic(&used_tables);
2983end:
2984 DBUG_RETURN(error);
2985}
2986
2987
2988THR_LOCK_DATA **ha_maria::store_lock(THD *thd,
2989 THR_LOCK_DATA **to,
2990 enum thr_lock_type lock_type)
2991{
2992 /* Test if we can fix test below */
2993 DBUG_ASSERT(lock_type != TL_UNLOCK &&
2994 (lock_type == TL_IGNORE || file->lock.type == TL_UNLOCK));
2995 if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
2996 {
2997 const enum enum_sql_command sql_command= thd->lex->sql_command;
2998 /*
2999 We have to disable concurrent inserts for INSERT ... SELECT or
3000 INSERT/UPDATE/DELETE with sub queries if we are using statement based
3001 logging. We take the safe route here and disable this for all commands
3002 that only does reading that are not SELECT.
3003 */
3004 if (lock_type <= TL_READ_HIGH_PRIORITY &&
3005 !thd->is_current_stmt_binlog_format_row() &&
3006 (sql_command != SQLCOM_SELECT &&
3007 sql_command != SQLCOM_LOCK_TABLES) &&
3008 (thd->variables.option_bits & OPTION_BIN_LOG) &&
3009 mysql_bin_log.is_open())
3010 lock_type= TL_READ_NO_INSERT;
3011 else if (lock_type == TL_WRITE_CONCURRENT_INSERT)
3012 {
3013 const enum enum_duplicates duplicates= thd->lex->duplicates;
3014 /*
3015 Explanation for the 3 conditions below, in order:
3016
3017 - Bulk insert may use repair, which will cause problems if other
3018 threads try to read/insert to the table: disable versioning.
3019 Note that our read of file->state->records is incorrect, as such
3020 variable may have changed when we come to start_bulk_insert() (worse
3021 case: we see != 0 so allow versioning, start_bulk_insert() sees 0 and
3022 uses repair). This is prevented because start_bulk_insert() will not
3023 try repair if we enabled versioning.
3024 - INSERT SELECT ON DUPLICATE KEY UPDATE comes here with
3025 TL_WRITE_CONCURRENT_INSERT but shouldn't because it can do
3026 update/delete of a row and versioning doesn't support that
3027 - same for LOAD DATA CONCURRENT REPLACE.
3028 */
3029 if ((file->state->records == 0) ||
3030 (sql_command == SQLCOM_INSERT_SELECT && duplicates == DUP_UPDATE) ||
3031 (sql_command == SQLCOM_LOAD && duplicates == DUP_REPLACE))
3032 lock_type= TL_WRITE;
3033 }
3034 file->lock.type= lock_type;
3035 }
3036 *to++= &file->lock;
3037 return to;
3038}
3039
3040
3041void ha_maria::update_create_info(HA_CREATE_INFO *create_info)
3042{
3043 ha_maria::info(HA_STATUS_AUTO | HA_STATUS_CONST);
3044 if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
3045 {
3046 create_info->auto_increment_value= stats.auto_increment_value;
3047 }
3048 create_info->data_file_name= data_file_name;
3049 create_info->index_file_name= index_file_name;
3050 /*
3051 Keep user-specified row_type for ALTER,
3052 but show the actually used one in SHOW
3053 */
3054 if (create_info->row_type != ROW_TYPE_DEFAULT &&
3055 !(thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE))
3056 create_info->row_type= get_row_type();
3057 /*
3058 Show always page checksums, as this can be forced with
3059 maria_page_checksums variable
3060 */
3061 if (create_info->page_checksum == HA_CHOICE_UNDEF)
3062 create_info->page_checksum=
3063 (file->s->options & HA_OPTION_PAGE_CHECKSUM) ? HA_CHOICE_YES :
3064 HA_CHOICE_NO;
3065}
3066
3067
3068enum row_type ha_maria::get_row_type() const
3069{
3070 switch (file->s->data_file_type) {
3071 case STATIC_RECORD: return ROW_TYPE_FIXED;
3072 case DYNAMIC_RECORD: return ROW_TYPE_DYNAMIC;
3073 case BLOCK_RECORD: return ROW_TYPE_PAGE;
3074 case COMPRESSED_RECORD: return ROW_TYPE_COMPRESSED;
3075 default: return ROW_TYPE_NOT_USED;
3076 }
3077}
3078
3079
3080static enum data_file_type maria_row_type(HA_CREATE_INFO *info)
3081{
3082 if (info->transactional == HA_CHOICE_YES)
3083 return BLOCK_RECORD;
3084 switch (info->row_type) {
3085 case ROW_TYPE_FIXED: return STATIC_RECORD;
3086 case ROW_TYPE_DYNAMIC: return DYNAMIC_RECORD;
3087 default: return BLOCK_RECORD;
3088 }
3089}
3090
3091
3092int ha_maria::create(const char *name, TABLE *table_arg,
3093 HA_CREATE_INFO *ha_create_info)
3094{
3095 int error;
3096 uint create_flags= 0, record_count= 0, i;
3097 char buff[FN_REFLEN];
3098 MARIA_KEYDEF *keydef;
3099 MARIA_COLUMNDEF *recinfo;
3100 MARIA_CREATE_INFO create_info;
3101 TABLE_SHARE *share= table_arg->s;
3102 uint options= share->db_options_in_use;
3103 enum data_file_type row_type;
3104 THD *thd= current_thd;
3105 DBUG_ENTER("ha_maria::create");
3106
3107 for (i= 0; i < share->keys; i++)
3108 {
3109 if (table_arg->key_info[i].flags & HA_USES_PARSER)
3110 {
3111 create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
3112 break;
3113 }
3114 }
3115 /* Note: BLOCK_RECORD is used if table is transactional */
3116 row_type= maria_row_type(ha_create_info);
3117 if (ha_create_info->transactional == HA_CHOICE_YES &&
3118 ha_create_info->row_type != ROW_TYPE_PAGE &&
3119 ha_create_info->row_type != ROW_TYPE_NOT_USED &&
3120 ha_create_info->row_type != ROW_TYPE_DEFAULT)
3121 push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
3122 ER_ILLEGAL_HA_CREATE_OPTION,
3123 "Row format set to PAGE because of TRANSACTIONAL=1 option");
3124
3125 if (share->table_type == TABLE_TYPE_SEQUENCE)
3126 {
3127 /* For sequences, the simples record type is appropriate */
3128 row_type= STATIC_RECORD;
3129 ha_create_info->transactional= HA_CHOICE_NO;
3130 }
3131
3132 bzero((char*) &create_info, sizeof(create_info));
3133 if ((error= table2maria(table_arg, row_type, &keydef, &recinfo,
3134 &record_count, &create_info)))
3135 DBUG_RETURN(error); /* purecov: inspected */
3136 create_info.max_rows= share->max_rows;
3137 create_info.reloc_rows= share->min_rows;
3138 create_info.with_auto_increment= share->next_number_key_offset == 0;
3139 create_info.auto_increment= (ha_create_info->auto_increment_value ?
3140 ha_create_info->auto_increment_value -1 :
3141 (ulonglong) 0);
3142 create_info.data_file_length= ((ulonglong) share->max_rows *
3143 share->avg_row_length);
3144 create_info.data_file_name= ha_create_info->data_file_name;
3145 create_info.index_file_name= ha_create_info->index_file_name;
3146 create_info.language= share->table_charset->number;
3147
3148 /*
3149 Table is transactional:
3150 - If the user specify that table is transactional (in this case
3151 row type is forced to BLOCK_RECORD)
3152 - If they specify BLOCK_RECORD without specifying transactional behaviour
3153
3154 Shouldn't this test be pushed down to maria_create()? Because currently,
3155 ma_test1 -T crashes: it creates a table with DYNAMIC_RECORD but has
3156 born_transactional==1, which confuses some recovery-related code.
3157 */
3158 create_info.transactional= (row_type == BLOCK_RECORD &&
3159 ha_create_info->transactional != HA_CHOICE_NO);
3160
3161 if (ha_create_info->tmp_table())
3162 {
3163 create_flags|= HA_CREATE_TMP_TABLE | HA_CREATE_DELAY_KEY_WRITE;
3164 create_info.transactional= 0;
3165 }
3166 if (ha_create_info->options & HA_CREATE_KEEP_FILES)
3167 create_flags|= HA_CREATE_KEEP_FILES;
3168 if (options & HA_OPTION_PACK_RECORD)
3169 create_flags|= HA_PACK_RECORD;
3170 if (options & HA_OPTION_CHECKSUM)
3171 create_flags|= HA_CREATE_CHECKSUM;
3172 if (options & HA_OPTION_DELAY_KEY_WRITE)
3173 create_flags|= HA_CREATE_DELAY_KEY_WRITE;
3174 if ((ha_create_info->page_checksum == HA_CHOICE_UNDEF &&
3175 maria_page_checksums) ||
3176 ha_create_info->page_checksum == HA_CHOICE_YES)
3177 create_flags|= HA_CREATE_PAGE_CHECKSUM;
3178
3179 (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
3180 (uchar*) thd->query(), thd->query_length());
3181
3182 /* TODO: Check that the following fn_format is really needed */
3183 error=
3184 maria_create(fn_format(buff, name, "", "",
3185 MY_UNPACK_FILENAME | MY_APPEND_EXT),
3186 row_type, share->keys, keydef,
3187 record_count, recinfo,
3188 0, (MARIA_UNIQUEDEF *) 0,
3189 &create_info, create_flags);
3190
3191 my_free(recinfo);
3192 DBUG_RETURN(error);
3193}
3194
3195
3196int ha_maria::rename_table(const char *from, const char *to)
3197{
3198 THD *thd= current_thd;
3199 (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
3200 (uchar*) thd->query(), thd->query_length());
3201 return maria_rename(from, to);
3202}
3203
3204
3205void ha_maria::get_auto_increment(ulonglong offset, ulonglong increment,
3206 ulonglong nb_desired_values,
3207 ulonglong *first_value,
3208 ulonglong *nb_reserved_values)
3209{
3210 ulonglong nr;
3211 int error;
3212 uchar key[MARIA_MAX_KEY_BUFF];
3213
3214 if (!table->s->next_number_key_offset)
3215 { // Autoincrement at key-start
3216 ha_maria::info(HA_STATUS_AUTO);
3217 *first_value= stats.auto_increment_value;
3218 /* Maria has only table-level lock for now, so reserves to +inf */
3219 *nb_reserved_values= ULONGLONG_MAX;
3220 return;
3221 }
3222
3223 /* it's safe to call the following if bulk_insert isn't on */
3224 maria_flush_bulk_insert(file, table->s->next_number_index);
3225
3226 (void) extra(HA_EXTRA_KEYREAD);
3227 key_copy(key, table->record[0],
3228 table->key_info + table->s->next_number_index,
3229 table->s->next_number_key_offset);
3230 error= maria_rkey(file, table->record[1], (int) table->s->next_number_index,
3231 key, make_prev_keypart_map(table->s->next_number_keypart),
3232 HA_READ_PREFIX_LAST);
3233 if (error)
3234 nr= 1;
3235 else
3236 {
3237 /* Get data from record[1] */
3238 nr= ((ulonglong) table->next_number_field->
3239 val_int_offset(table->s->rec_buff_length) + 1);
3240 }
3241 extra(HA_EXTRA_NO_KEYREAD);
3242 *first_value= nr;
3243 /*
3244 MySQL needs to call us for next row: assume we are inserting ("a",null)
3245 here, we return 3, and next this statement will want to insert ("b",null):
3246 there is no reason why ("b",3+1) would be the good row to insert: maybe it
3247 already exists, maybe 3+1 is too large...
3248 */
3249 *nb_reserved_values= 1;
3250}
3251
3252
3253/*
3254 Find out how many rows there is in the given range
3255
3256 SYNOPSIS
3257 records_in_range()
3258 inx Index to use
3259 min_key Start of range. Null pointer if from first key
3260 max_key End of range. Null pointer if to last key
3261
3262 NOTES
3263 min_key.flag can have one of the following values:
3264 HA_READ_KEY_EXACT Include the key in the range
3265 HA_READ_AFTER_KEY Don't include key in range
3266
3267 max_key.flag can have one of the following values:
3268 HA_READ_BEFORE_KEY Don't include key in range
3269 HA_READ_AFTER_KEY Include all 'end_key' values in the range
3270
3271 RETURN
3272 HA_POS_ERROR Something is wrong with the index tree.
3273 0 There is no matching keys in the given range
3274 number > 0 There is approximately 'number' matching rows in
3275 the range.
3276*/
3277
3278ha_rows ha_maria::records_in_range(uint inx, key_range *min_key,
3279 key_range *max_key)
3280{
3281 return (ha_rows) maria_records_in_range(file, (int) inx, min_key, max_key);
3282}
3283
3284
3285int ha_maria::ft_read(uchar * buf)
3286{
3287 int error;
3288
3289 if (!ft_handler)
3290 return -1;
3291
3292 thread_safe_increment(table->in_use->status_var.ha_read_next_count,
3293 &LOCK_status); // why ?
3294
3295 error= ft_handler->please->read_next(ft_handler, (char*) buf);
3296
3297 return error;
3298}
3299
3300
3301uint ha_maria::checksum() const
3302{
3303 return (uint) file->state->checksum;
3304}
3305
3306
3307bool ha_maria::check_if_incompatible_data(HA_CREATE_INFO *create_info,
3308 uint table_changes)
3309{
3310 DBUG_ENTER("check_if_incompatible_data");
3311 uint options= table->s->db_options_in_use;
3312 enum ha_choice page_checksum= table->s->page_checksum;
3313
3314 if (page_checksum == HA_CHOICE_UNDEF)
3315 page_checksum= file->s->options & HA_OPTION_PAGE_CHECKSUM ? HA_CHOICE_YES
3316 : HA_CHOICE_NO;
3317
3318 if (create_info->auto_increment_value != stats.auto_increment_value ||
3319 create_info->data_file_name != data_file_name ||
3320 create_info->index_file_name != index_file_name ||
3321 create_info->page_checksum != page_checksum ||
3322 create_info->transactional != table->s->transactional ||
3323 (maria_row_type(create_info) != data_file_type &&
3324 create_info->row_type != ROW_TYPE_DEFAULT) ||
3325 table_changes == IS_EQUAL_NO ||
3326 (table_changes & IS_EQUAL_PACK_LENGTH)) // Not implemented yet
3327 DBUG_RETURN(COMPATIBLE_DATA_NO);
3328
3329 if ((options & (HA_OPTION_CHECKSUM |
3330 HA_OPTION_DELAY_KEY_WRITE)) !=
3331 (create_info->table_options & (HA_OPTION_CHECKSUM |
3332 HA_OPTION_DELAY_KEY_WRITE)))
3333 DBUG_RETURN(COMPATIBLE_DATA_NO);
3334 DBUG_RETURN(COMPATIBLE_DATA_YES);
3335}
3336
3337
3338static int maria_hton_panic(handlerton *hton, ha_panic_function flag)
3339{
3340 /* If no background checkpoints, we need to do one now */
3341 int ret=0;
3342
3343 if (!checkpoint_interval)
3344 ret= ma_checkpoint_execute(CHECKPOINT_FULL, FALSE);
3345
3346 ret|= maria_panic(flag);
3347
3348 maria_hton= 0;
3349 return ret;
3350}
3351
3352
3353static int maria_commit(handlerton *hton __attribute__ ((unused)),
3354 THD *thd, bool all)
3355{
3356 TRN *trn= THD_TRN;
3357 DBUG_ENTER("maria_commit");
3358 trnman_reset_locked_tables(trn, 0);
3359 trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED);
3360
3361 /* statement or transaction ? */
3362 if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
3363 DBUG_RETURN(0); // end of statement
3364 DBUG_PRINT("info", ("THD_TRN set to 0x0"));
3365 THD_TRN= 0;
3366 DBUG_RETURN(ma_commit(trn)); // end of transaction
3367}
3368
3369
3370static int maria_rollback(handlerton *hton __attribute__ ((unused)),
3371 THD *thd, bool all)
3372{
3373 TRN *trn= THD_TRN;
3374 DBUG_ENTER("maria_rollback");
3375 trnman_reset_locked_tables(trn, 0);
3376 /* statement or transaction ? */
3377 if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
3378 {
3379 trnman_rollback_statement(trn);
3380 DBUG_RETURN(0); // end of statement
3381 }
3382 DBUG_PRINT("info", ("THD_TRN set to 0x0"));
3383 THD_TRN= 0;
3384 DBUG_RETURN(trnman_rollback_trn(trn) ?
3385 HA_ERR_OUT_OF_MEM : 0); // end of transaction
3386}
3387
3388
3389
3390/**
3391 @brief flush log handler
3392
3393 @param hton maria handlerton (unused)
3394
3395 @retval FALSE OK
3396 @retval TRUE Error
3397*/
3398
3399bool maria_flush_logs(handlerton *hton)
3400{
3401 return MY_TEST(translog_purge_at_flush());
3402}
3403
3404
3405int maria_checkpoint_state(handlerton *hton, bool disabled)
3406{
3407 maria_checkpoint_disabled= (my_bool) disabled;
3408 return 0;
3409}
3410
3411
3412
3413#define SHOW_MSG_LEN (FN_REFLEN + 20)
3414/**
3415 @brief show status handler
3416
3417 @param hton maria handlerton
3418 @param thd thread handler
3419 @param print print function
3420 @param stat type of status
3421*/
3422
3423bool maria_show_status(handlerton *hton,
3424 THD *thd,
3425 stat_print_fn *print,
3426 enum ha_stat_type stat)
3427{
3428 const LEX_CSTRING *engine_name= hton_name(hton);
3429 switch (stat) {
3430 case HA_ENGINE_LOGS:
3431 {
3432 TRANSLOG_ADDRESS horizon= translog_get_horizon();
3433 uint32 last_file= LSN_FILE_NO(horizon);
3434 uint32 first_needed= translog_get_first_needed_file();
3435 uint32 first_file= translog_get_first_file(horizon);
3436 uint32 i;
3437 const char unknown[]= "unknown";
3438 const char needed[]= "in use";
3439 const char unneeded[]= "free";
3440 char path[FN_REFLEN];
3441
3442 if (first_file == 0)
3443 {
3444 const char error[]= "error";
3445 print(thd, engine_name->str, engine_name->length,
3446 STRING_WITH_LEN(""), error, sizeof(error) - 1);
3447 break;
3448 }
3449
3450 for (i= first_file; i <= last_file; i++)
3451 {
3452 char *file;
3453 const char *status;
3454 size_t length, status_len;
3455 MY_STAT stat_buff, *stat;
3456 const char error[]= "can't stat";
3457 char object[SHOW_MSG_LEN];
3458 file= translog_filename_by_fileno(i, path);
3459 if (!(stat= mysql_file_stat(key_file_translog, file, &stat_buff, MYF(0))))
3460 {
3461 status= error;
3462 status_len= sizeof(error) - 1;
3463 length= my_snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s", file);
3464 }
3465 else
3466 {
3467 if (first_needed == 0)
3468 {
3469 status= unknown;
3470 status_len= sizeof(unknown) - 1;
3471 }
3472 else if (i < first_needed)
3473 {
3474 status= unneeded;
3475 status_len= sizeof(unneeded) - 1;
3476 }
3477 else
3478 {
3479 status= needed;
3480 status_len= sizeof(needed) - 1;
3481 }
3482 length= my_snprintf(object, SHOW_MSG_LEN, "Size %12llu ; %s",
3483 (ulonglong) stat->st_size, file);
3484 }
3485
3486 print(thd, engine_name->str, engine_name->length,
3487 object, length, status, status_len);
3488 }
3489 break;
3490 }
3491 case HA_ENGINE_STATUS:
3492 case HA_ENGINE_MUTEX:
3493 default:
3494 break;
3495 }
3496 return 0;
3497}
3498
3499
3500/**
3501 Callback to delete all logs in directory. This is lower-level than other
3502 functions in ma_loghandler.c which delete logs, as it does not rely on
3503 translog_init() having been called first.
3504
3505 @param directory directory where file is
3506 @param filename base name of the file to delete
3507*/
3508
3509static my_bool translog_callback_delete_all(const char *directory,
3510 const char *filename)
3511{
3512 char complete_name[FN_REFLEN];
3513 fn_format(complete_name, filename, directory, "", MYF(MY_UNPACK_FILENAME));
3514 return mysql_file_delete(key_file_translog, complete_name, MYF(MY_WME));
3515}
3516
3517
3518/**
3519 Helper function for option aria-force-start-after-recovery-failures.
3520 Deletes logs if too many failures. Otherwise, increments the counter of
3521 failures in the control file.
3522 Notice how this has to be called _before_ translog_init() (if log is
3523 corrupted, translog_init() might crash the server, so we need to remove logs
3524 before).
3525
3526 @param log_dir directory where logs to be deleted are
3527*/
3528
3529static int mark_recovery_start(const char* log_dir)
3530{
3531 int res;
3532 DBUG_ENTER("mark_recovery_start");
3533 if (!(maria_recover_options & HA_RECOVER_ANY))
3534 ma_message_no_user(ME_JUST_WARNING, "Please consider using option"
3535 " --aria-recover-options[=...] to automatically check and"
3536 " repair tables when logs are removed by option"
3537 " --aria-force-start-after-recovery-failures=#");
3538 if (recovery_failures >= force_start_after_recovery_failures)
3539 {
3540 /*
3541 Remove logs which cause the problem; keep control file which has
3542 critical info like uuid, max_trid (removing control file may make
3543 correct tables look corrupted!).
3544 */
3545 char msg[100];
3546 res= translog_walk_filenames(log_dir, &translog_callback_delete_all);
3547 my_snprintf(msg, sizeof(msg),
3548 "%s logs after %u consecutive failures of"
3549 " recovery from logs",
3550 (res ? "failed to remove some" : "removed all"),
3551 recovery_failures);
3552 ma_message_no_user((res ? 0 : ME_JUST_WARNING), msg);
3553 }
3554 else
3555 res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
3556 max_trid_in_control_file,
3557 recovery_failures + 1);
3558 DBUG_RETURN(res);
3559}
3560
3561
3562/**
3563 Helper function for option aria-force-start-after-recovery-failures.
3564 Records in the control file that recovery was a success, so that it's not
3565 counted for aria-force-start-after-recovery-failures.
3566*/
3567
3568static int mark_recovery_success(void)
3569{
3570 /* success of recovery, reset recovery_failures: */
3571 int res;
3572 DBUG_ENTER("mark_recovery_success");
3573 res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
3574 max_trid_in_control_file, 0);
3575 DBUG_RETURN(res);
3576}
3577
3578
3579/*
3580 Return 1 if table has changed during the current transaction
3581*/
3582
3583bool ha_maria::is_changed() const
3584{
3585 return file->state->changed;
3586}
3587
3588
3589static int ha_maria_init(void *p)
3590{
3591 int res;
3592 const char *log_dir= maria_data_root;
3593
3594#ifdef HAVE_PSI_INTERFACE
3595 init_aria_psi_keys();
3596#endif
3597
3598 maria_hton= (handlerton *)p;
3599 maria_hton->state= SHOW_OPTION_YES;
3600 maria_hton->db_type= DB_TYPE_ARIA;
3601 maria_hton->create= maria_create_handler;
3602 maria_hton->panic= maria_hton_panic;
3603 maria_hton->tablefile_extensions= ha_maria_exts;
3604 maria_hton->commit= maria_commit;
3605 maria_hton->rollback= maria_rollback;
3606 maria_hton->checkpoint_state= maria_checkpoint_state;
3607#ifdef MARIA_CANNOT_ROLLBACK
3608 maria_hton->commit= 0;
3609#endif
3610 maria_hton->flush_logs= maria_flush_logs;
3611 maria_hton->show_status= maria_show_status;
3612 /* TODO: decide if we support Maria being used for log tables */
3613 maria_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
3614 bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
3615 maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
3616 res= maria_upgrade() || maria_init() || ma_control_file_open(TRUE, TRUE) ||
3617 ((force_start_after_recovery_failures != 0) &&
3618 mark_recovery_start(log_dir)) ||
3619 !init_pagecache(maria_pagecache,
3620 (size_t) pagecache_buffer_size, pagecache_division_limit,
3621 pagecache_age_threshold, maria_block_size, pagecache_file_hash_size,
3622 0) ||
3623 !init_pagecache(maria_log_pagecache,
3624 TRANSLOG_PAGECACHE_SIZE, 0, 0,
3625 TRANSLOG_PAGE_SIZE, 0, 0) ||
3626 translog_init(maria_data_root, log_file_size,
3627 MYSQL_VERSION_ID, server_id, maria_log_pagecache,
3628 TRANSLOG_DEFAULT_FLAGS, 0) ||
3629 maria_recovery_from_log() ||
3630 ((force_start_after_recovery_failures != 0 ||
3631 maria_recovery_changed_data) && mark_recovery_success()) ||
3632 ma_checkpoint_init(checkpoint_interval);
3633 maria_multi_threaded= maria_in_ha_maria= TRUE;
3634 maria_create_trn_hook= maria_create_trn_for_mysql;
3635 maria_pagecache->extra_debug= 1;
3636 maria_assert_if_crashed_table= debug_assert_if_crashed_table;
3637
3638 if (res)
3639 maria_hton= 0;
3640
3641 ma_killed= ma_killed_in_mariadb;
3642
3643 return res ? HA_ERR_INITIALIZATION : 0;
3644}
3645
3646
3647#ifdef HAVE_QUERY_CACHE
3648/**
3649 @brief Register a named table with a call back function to the query cache.
3650
3651 @param thd The thread handle
3652 @param table_key A pointer to the table name in the table cache
3653 @param key_length The length of the table name
3654 @param[out] engine_callback The pointer to the storage engine call back
3655 function, currently 0
3656 @param[out] engine_data Engine data will be set to 0.
3657
3658 @note Despite the name of this function, it is used to check each statement
3659 before it is cached and not to register a table or callback function.
3660
3661 @see handler::register_query_cache_table
3662
3663 @return The error code. The engine_data and engine_callback will be set to 0.
3664 @retval TRUE Success
3665 @retval FALSE An error occurred
3666*/
3667
3668my_bool ha_maria::register_query_cache_table(THD *thd, const char *table_name,
3669 uint table_name_len,
3670 qc_engine_callback
3671 *engine_callback,
3672 ulonglong *engine_data)
3673{
3674 ulonglong actual_data_file_length;
3675 ulonglong current_data_file_length;
3676 DBUG_ENTER("ha_maria::register_query_cache_table");
3677
3678 /*
3679 No call back function is needed to determine if a cached statement
3680 is valid or not.
3681 */
3682 *engine_callback= 0;
3683
3684 /*
3685 No engine data is needed.
3686 */
3687 *engine_data= 0;
3688
3689 if (file->s->now_transactional && file->s->have_versioning)
3690 DBUG_RETURN(file->trn->trid >= file->s->state.last_change_trn);
3691
3692 /*
3693 If a concurrent INSERT has happened just before the currently processed
3694 SELECT statement, the total size of the table is unknown.
3695
3696 To determine if the table size is known, the current thread's snap shot of
3697 the table size with the actual table size are compared.
3698
3699 If the table size is unknown the SELECT statement can't be cached.
3700 */
3701
3702 /*
3703 POSIX visibility rules specify that "2. Whatever memory values a
3704 thread can see when it unlocks a mutex <...> can also be seen by any
3705 thread that later locks the same mutex". In this particular case,
3706 concurrent insert thread had modified the data_file_length in
3707 MYISAM_SHARE before it has unlocked (or even locked)
3708 structure_guard_mutex. So, here we're guaranteed to see at least that
3709 value after we've locked the same mutex. We can see a later value
3710 (modified by some other thread) though, but it's ok, as we only want
3711 to know if the variable was changed, the actual new value doesn't matter
3712 */
3713 actual_data_file_length= file->s->state.state.data_file_length;
3714 current_data_file_length= file->state->data_file_length;
3715
3716 /* Return whether is ok to try to cache current statement. */
3717 DBUG_RETURN(!(file->s->non_transactional_concurrent_insert &&
3718 current_data_file_length != actual_data_file_length));
3719}
3720#endif
3721
3722struct st_mysql_sys_var* system_variables[]= {
3723 MYSQL_SYSVAR(block_size),
3724 MYSQL_SYSVAR(checkpoint_interval),
3725 MYSQL_SYSVAR(checkpoint_log_activity),
3726 MYSQL_SYSVAR(force_start_after_recovery_failures),
3727 MYSQL_SYSVAR(group_commit),
3728 MYSQL_SYSVAR(group_commit_interval),
3729 MYSQL_SYSVAR(log_dir_path),
3730 MYSQL_SYSVAR(log_file_size),
3731 MYSQL_SYSVAR(log_purge_type),
3732 MYSQL_SYSVAR(max_sort_file_size),
3733 MYSQL_SYSVAR(page_checksum),
3734 MYSQL_SYSVAR(pagecache_age_threshold),
3735 MYSQL_SYSVAR(pagecache_buffer_size),
3736 MYSQL_SYSVAR(pagecache_division_limit),
3737 MYSQL_SYSVAR(pagecache_file_hash_size),
3738 MYSQL_SYSVAR(recover_options),
3739 MYSQL_SYSVAR(repair_threads),
3740 MYSQL_SYSVAR(sort_buffer_size),
3741 MYSQL_SYSVAR(stats_method),
3742 MYSQL_SYSVAR(sync_log_dir),
3743 MYSQL_SYSVAR(used_for_temp_tables),
3744 MYSQL_SYSVAR(encrypt_tables),
3745 NULL
3746};
3747
3748
3749/**
3750 @brief Updates the checkpoint interval and restarts the background thread.
3751*/
3752
3753static void update_checkpoint_interval(MYSQL_THD thd,
3754 struct st_mysql_sys_var *var,
3755 void *var_ptr, const void *save)
3756{
3757 ma_checkpoint_end();
3758 ma_checkpoint_init(*(ulong *)var_ptr= (ulong)(*(long *)save));
3759}
3760
3761
3762/**
3763 @brief Updates group commit mode
3764*/
3765
3766static void update_maria_group_commit(MYSQL_THD thd,
3767 struct st_mysql_sys_var *var,
3768 void *var_ptr, const void *save)
3769{
3770 ulong value= (ulong)*((long *)var_ptr);
3771 DBUG_ENTER("update_maria_group_commit");
3772 DBUG_PRINT("enter", ("old value: %lu new value %lu rate %lu",
3773 value, (ulong)(*(long *)save),
3774 maria_group_commit_interval));
3775 /* old value */
3776 switch (value) {
3777 case TRANSLOG_GCOMMIT_NONE:
3778 break;
3779 case TRANSLOG_GCOMMIT_HARD:
3780 translog_hard_group_commit(FALSE);
3781 break;
3782 case TRANSLOG_GCOMMIT_SOFT:
3783 translog_soft_sync(FALSE);
3784 if (maria_group_commit_interval)
3785 translog_soft_sync_end();
3786 break;
3787 default:
3788 DBUG_ASSERT(0); /* impossible */
3789 }
3790 value= *(ulong *)var_ptr= (ulong)(*(long *)save);
3791 translog_sync();
3792 /* new value */
3793 switch (value) {
3794 case TRANSLOG_GCOMMIT_NONE:
3795 break;
3796 case TRANSLOG_GCOMMIT_HARD:
3797 translog_hard_group_commit(TRUE);
3798 break;
3799 case TRANSLOG_GCOMMIT_SOFT:
3800 translog_soft_sync(TRUE);
3801 /* variable change made under global lock so we can just read it */
3802 if (maria_group_commit_interval)
3803 translog_soft_sync_start();
3804 break;
3805 default:
3806 DBUG_ASSERT(0); /* impossible */
3807 }
3808 DBUG_VOID_RETURN;
3809}
3810
3811/**
3812 @brief Updates group commit interval
3813*/
3814
3815static void update_maria_group_commit_interval(MYSQL_THD thd,
3816 struct st_mysql_sys_var *var,
3817 void *var_ptr, const void *save)
3818{
3819 ulong new_value= (ulong)*((long *)save);
3820 ulong *value_ptr= (ulong*) var_ptr;
3821 DBUG_ENTER("update_maria_group_commit_interval");
3822 DBUG_PRINT("enter", ("old value: %lu new value %lu group commit %lu",
3823 *value_ptr, new_value, maria_group_commit));
3824
3825 /* variable change made under global lock so we can just read it */
3826 switch (maria_group_commit) {
3827 case TRANSLOG_GCOMMIT_NONE:
3828 *value_ptr= new_value;
3829 translog_set_group_commit_interval(new_value);
3830 break;
3831 case TRANSLOG_GCOMMIT_HARD:
3832 *value_ptr= new_value;
3833 translog_set_group_commit_interval(new_value);
3834 break;
3835 case TRANSLOG_GCOMMIT_SOFT:
3836 if (*value_ptr)
3837 translog_soft_sync_end();
3838 translog_set_group_commit_interval(new_value);
3839 if ((*value_ptr= new_value))
3840 translog_soft_sync_start();
3841 break;
3842 default:
3843 DBUG_ASSERT(0); /* impossible */
3844 }
3845 DBUG_VOID_RETURN;
3846}
3847
3848/**
3849 @brief Updates the transaction log file limit.
3850*/
3851
3852static void update_log_file_size(MYSQL_THD thd,
3853 struct st_mysql_sys_var *var,
3854 void *var_ptr, const void *save)
3855{
3856 uint32 size= (uint32)((ulong)(*(long *)save));
3857 translog_set_file_size(size);
3858 *(ulong *)var_ptr= size;
3859}
3860
3861
3862SHOW_VAR status_variables[]= {
3863 {"pagecache_blocks_not_flushed", (char*) &maria_pagecache_var.global_blocks_changed, SHOW_LONG},
3864 {"pagecache_blocks_unused", (char*) &maria_pagecache_var.blocks_unused, SHOW_LONG},
3865 {"pagecache_blocks_used", (char*) &maria_pagecache_var.blocks_used, SHOW_LONG},
3866 {"pagecache_read_requests", (char*) &maria_pagecache_var.global_cache_r_requests, SHOW_LONGLONG},
3867 {"pagecache_reads", (char*) &maria_pagecache_var.global_cache_read, SHOW_LONGLONG},
3868 {"pagecache_write_requests", (char*) &maria_pagecache_var.global_cache_w_requests, SHOW_LONGLONG},
3869 {"pagecache_writes", (char*) &maria_pagecache_var.global_cache_write, SHOW_LONGLONG},
3870 {"transaction_log_syncs", (char*) &translog_syncs, SHOW_LONGLONG},
3871 {NullS, NullS, SHOW_LONG}
3872};
3873
3874/****************************************************************************
3875 * Maria MRR implementation: use DS-MRR
3876 ***************************************************************************/
3877
3878int ha_maria::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
3879 uint n_ranges, uint mode,
3880 HANDLER_BUFFER *buf)
3881{
3882 return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf);
3883}
3884
3885int ha_maria::multi_range_read_next(range_id_t *range_info)
3886{
3887 return ds_mrr.dsmrr_next(range_info);
3888}
3889
3890ha_rows ha_maria::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
3891 void *seq_init_param,
3892 uint n_ranges, uint *bufsz,
3893 uint *flags, Cost_estimate *cost)
3894{
3895 /*
3896 This call is here because there is no location where this->table would
3897 already be known.
3898 TODO: consider moving it into some per-query initialization call.
3899 */
3900 ds_mrr.init(this, table);
3901 return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
3902 flags, cost);
3903}
3904
3905ha_rows ha_maria::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
3906 uint key_parts, uint *bufsz,
3907 uint *flags, Cost_estimate *cost)
3908{
3909 ds_mrr.init(this, table);
3910 return ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz, flags, cost);
3911}
3912
3913int ha_maria::multi_range_read_explain_info(uint mrr_mode, char *str,
3914 size_t size)
3915{
3916 return ds_mrr.dsmrr_explain_info(mrr_mode, str, size);
3917}
3918/* MyISAM MRR implementation ends */
3919
3920
3921/* Index condition pushdown implementation*/
3922
3923
3924Item *ha_maria::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
3925{
3926 /*
3927 Check if the key contains a blob field. If it does then MyISAM
3928 should not accept the pushed index condition since MyISAM will not
3929 read the blob field from the index entry during evaluation of the
3930 pushed index condition and the BLOB field might be part of the
3931 range evaluation done by the ICP code.
3932 */
3933 const KEY *key= &table_share->key_info[keyno_arg];
3934
3935 for (uint k= 0; k < key->user_defined_key_parts; ++k)
3936 {
3937 const KEY_PART_INFO *key_part= &key->key_part[k];
3938 if (key_part->key_part_flag & HA_BLOB_PART)
3939 {
3940 /* Let the server handle the index condition */
3941 return idx_cond_arg;
3942 }
3943 }
3944
3945 pushed_idx_cond_keyno= keyno_arg;
3946 pushed_idx_cond= idx_cond_arg;
3947 in_range_check_pushed_down= TRUE;
3948 if (active_index == pushed_idx_cond_keyno)
3949 ma_set_index_cond_func(file, handler_index_cond_check, this);
3950 return NULL;
3951}
3952
3953/**
3954 Find record by unique constrain (used in temporary tables)
3955
3956 @param record (IN|OUT) the record to find
3957 @param constrain_no (IN) number of constrain (for this engine)
3958
3959 @note It is like hp_search but uses function for raw where hp_search
3960 uses functions for index.
3961
3962 @retval 0 OK
3963 @retval 1 Not found
3964 @retval -1 Error
3965*/
3966
3967int ha_maria::find_unique_row(uchar *record, uint constrain_no)
3968{
3969 int rc;
3970 if (file->s->state.header.uniques)
3971 {
3972 DBUG_ASSERT(file->s->state.header.uniques > constrain_no);
3973 MARIA_UNIQUEDEF *def= file->s->uniqueinfo + constrain_no;
3974 ha_checksum unique_hash= _ma_unique_hash(def, record);
3975 rc= _ma_check_unique(file, def, record, unique_hash, HA_OFFSET_ERROR);
3976 if (rc)
3977 {
3978 file->cur_row.lastpos= file->dup_key_pos;
3979 if ((*file->read_record)(file, record, file->cur_row.lastpos))
3980 return -1;
3981 file->update|= HA_STATE_AKTIV; /* Record is read */
3982 }
3983 // invert logic
3984 rc= !MY_TEST(rc);
3985 }
3986 else
3987 {
3988 /*
3989 It is case when just unique index used instead unicue constrain
3990 (conversion from heap table).
3991 */
3992 DBUG_ASSERT(file->s->state.header.keys > constrain_no);
3993 MARIA_KEY key;
3994 file->once_flags|= USE_PACKED_KEYS;
3995 (*file->s->keyinfo[constrain_no].make_key)
3996 (file, &key, constrain_no, file->lastkey_buff2, record, 0, 0);
3997 rc= maria_rkey(file, record, constrain_no, key.data, key.data_length,
3998 HA_READ_KEY_EXACT);
3999 rc= MY_TEST(rc);
4000 }
4001 return rc;
4002}
4003
4004struct st_mysql_storage_engine maria_storage_engine=
4005{ MYSQL_HANDLERTON_INTERFACE_VERSION };
4006
4007maria_declare_plugin(aria)
4008{
4009 MYSQL_STORAGE_ENGINE_PLUGIN,
4010 &maria_storage_engine,
4011 "Aria",
4012 "Monty Program Ab",
4013 "Crash-safe tables with MyISAM heritage",
4014 PLUGIN_LICENSE_GPL,
4015 ha_maria_init, /* Plugin Init */
4016 NULL, /* Plugin Deinit */
4017 0x0105, /* 1.5 */
4018 status_variables, /* status variables */
4019 system_variables, /* system variables */
4020 "1.5", /* string version */
4021 MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
4022}
4023maria_declare_plugin_end;
4024