1 /*****************************************************************************
2
3 Copyright (c) 2000, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2008, 2009 Google Inc.
5 Copyright (c) 2009, Percona Inc.
6 Copyright (c) 2012, Facebook Inc.
7
8 Portions of this file contain modifications contributed and copyrighted by
9 Google, Inc. Those modifications are gratefully acknowledged and are described
10 briefly in the InnoDB documentation. The contributions by Google are
11 incorporated with their permission, and subject to the conditions contained in
12 the file COPYING.Google.
13
14 Portions of this file contain modifications contributed and copyrighted
15 by Percona Inc.. Those modifications are
16 gratefully acknowledged and are described briefly in the InnoDB
17 documentation. The contributions by Percona Inc. are incorporated with
18 their permission, and subject to the conditions contained in the file
19 COPYING.Percona.
20
21 This program is free software; you can redistribute it and/or modify
22 it under the terms of the GNU General Public License, version 2.0,
23 as published by the Free Software Foundation.
24
25 This program is also distributed with certain software (including
26 but not limited to OpenSSL) that is licensed under separate terms,
27 as designated in a particular file or component or in included license
28 documentation. The authors of MySQL hereby grant you an additional
29 permission to link the program and your derivative works with the
30 separately licensed software that they have included with MySQL.
31
32 This program is distributed in the hope that it will be useful,
33 but WITHOUT ANY WARRANTY; without even the implied warranty of
34 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 GNU General Public License, version 2.0, for more details.
36
37 You should have received a copy of the GNU General Public License along with
38 this program; if not, write to the Free Software Foundation, Inc.,
39 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
40
41 *****************************************************************************/
42
43 #define MYSQL_SERVER
44
45 #include <sql_table.h> // explain_filename, nz2, EXPLAIN_PARTITIONS_AS_COMMENT,
46 // EXPLAIN_FILENAME_MAX_EXTRA_LENGTH
47
48 #include <sql_acl.h> // PROCESS_ACL
49 #include <debug_sync.h> // DEBUG_SYNC
50 #include <my_base.h> // HA_OPTION_*
51 #include <mysys_err.h>
52 #include <mysql/innodb_priv.h>
53 #include <mysql/thread_pool_priv.h>
54 #include <my_check_opt.h>
55
56 /** @file ha_innodb.cc */
57
58 /* Include necessary InnoDB headers */
59 #include "univ.i"
60 #include "buf0dump.h"
61 #include "buf0lru.h"
62 #include "buf0flu.h"
63 #include "buf0dblwr.h"
64 #include "btr0sea.h"
65 #include "os0file.h"
66 #include "os0thread.h"
67 #include "srv0start.h"
68 #include "srv0srv.h"
69 #include "trx0roll.h"
70 #include "trx0trx.h"
71
72 #include "trx0sys.h"
73 #include "mtr0mtr.h"
74 #include "rem0types.h"
75 #include "row0ins.h"
76 #include "row0mysql.h"
77 #include "row0sel.h"
78 #include "row0upd.h"
79 #include "log0log.h"
80 #include "log0online.h"
81 #include "lock0lock.h"
82 #include "dict0crea.h"
83 #include "btr0cur.h"
84 #include "btr0btr.h"
85 #include "fsp0fsp.h"
86 #include "sync0sync.h"
87 #include "fil0fil.h"
88 #include "trx0xa.h"
89 #include "row0merge.h"
90 #include "dict0boot.h"
91 #include "dict0stats.h"
92 #include "dict0stats_bg.h"
93 #include "ha_prototypes.h"
94 #include "ut0mem.h"
95 #include "ibuf0ibuf.h"
96 #include "dict0dict.h"
97 #include "srv0mon.h"
98 #include "api0api.h"
99 #include "api0misc.h"
100 #include "pars0pars.h"
101 #include "fts0fts.h"
102 #include "fts0types.h"
103 #include "row0import.h"
104 #include "row0quiesce.h"
105 #ifdef UNIV_DEBUG
106 #include "trx0purge.h"
107 #endif /* UNIV_DEBUG */
108 #include "fts0priv.h"
109 #include "page0zip.h"
110
111 enum_tx_isolation thd_get_trx_isolation(const THD* thd);
112
113 #include "ha_innodb.h"
114 #include "i_s.h"
115 #include "xtradb_i_s.h"
116
117 # ifndef MYSQL_PLUGIN_IMPORT
118 # define MYSQL_PLUGIN_IMPORT /* nothing */
119 # endif /* MYSQL_PLUGIN_IMPORT */
120
121 /** to protect innobase_open_files */
122 static mysql_mutex_t innobase_share_mutex;
123 /** to force correct commit order in binlog */
124 static ulong commit_threads = 0;
125 static mysql_cond_t commit_cond;
126 static mysql_mutex_t commit_cond_m;
127 static bool innodb_inited = 0;
128
129 #define INSIDE_HA_INNOBASE_CC
130
131 #define EQ_CURRENT_THD(thd) ((thd) == current_thd)
132
133 static struct handlerton* innodb_hton_ptr;
134
135 static const long AUTOINC_OLD_STYLE_LOCKING = 0;
136 static const long AUTOINC_NEW_STYLE_LOCKING = 1;
137 static const long AUTOINC_NO_LOCKING = 2;
138
139 static long innobase_mirrored_log_groups;
140 static long innobase_log_buffer_size;
141 static long innobase_additional_mem_pool_size;
142 static long innobase_file_io_threads;
143 static long innobase_open_files;
144 static long innobase_autoinc_lock_mode;
145 static ulong innobase_commit_concurrency = 0;
146 static ulong innobase_read_io_threads;
147 static ulong innobase_write_io_threads;
148 static long innobase_buffer_pool_instances = 1;
149
150 static ulong innobase_log_block_size;
151
152 static long long innobase_buffer_pool_size, innobase_log_file_size;
153
154 /** Percentage of the buffer pool to reserve for 'old' blocks.
155 Connected to buf_LRU_old_ratio. */
156 static uint innobase_old_blocks_pct;
157
158 /** Maximum on-disk size of change buffer in terms of percentage
159 of the buffer pool. */
160 static uint innobase_change_buffer_max_size = CHANGE_BUFFER_DEFAULT_SIZE;
161
162 /* The default values for the following char* start-up parameters
163 are determined in innobase_init below: */
164
165 static char* innobase_data_home_dir = NULL;
166 static char* innobase_data_file_path = NULL;
167 static char* innobase_file_format_name = NULL;
168 static char* innobase_change_buffering = NULL;
169 static char* innobase_enable_monitor_counter = NULL;
170 static char* innobase_disable_monitor_counter = NULL;
171 static char* innobase_reset_monitor_counter = NULL;
172 static char* innobase_reset_all_monitor_counter = NULL;
173
174 /* The highest file format being used in the database. The value can be
175 set by user, however, it will be adjusted to the newer file format if
176 a table of such format is created/opened. */
177 static char* innobase_file_format_max = NULL;
178
179 static char* innobase_file_flush_method = NULL;
180
181 /* This variable can be set in the server configure file, specifying
182 stopword table to be used */
183 static char* innobase_server_stopword_table = NULL;
184
185 /* Below we have boolean-valued start-up parameters, and their default
186 values */
187
188 static ulong innobase_fast_shutdown = 1;
189 static my_bool innobase_file_format_check = TRUE;
190 #ifdef UNIV_LOG_ARCHIVE
191 static my_bool innobase_log_archive = FALSE;
192 static char* innobase_log_arch_dir = NULL;
193 #endif /* UNIV_LOG_ARCHIVE */
194 static my_bool innobase_use_atomic_writes = FALSE;
195 static my_bool innobase_use_doublewrite = TRUE;
196 static my_bool innobase_use_checksums = TRUE;
197 static my_bool innobase_locks_unsafe_for_binlog = FALSE;
198 static my_bool innobase_rollback_on_timeout = FALSE;
199 static my_bool innobase_create_status_file = FALSE;
200 static my_bool innobase_stats_on_metadata = TRUE;
201 static my_bool innobase_large_prefix = FALSE;
202 static my_bool innodb_optimize_fulltext_only = FALSE;
203
204 static char* internal_innobase_data_file_path = NULL;
205
206 static char* innodb_version_str = (char*) INNODB_VERSION_STR;
207
208 /** Possible values for system variable "innodb_stats_method". The values
209 are defined the same as its corresponding MyISAM system variable
210 "myisam_stats_method"(see "myisam_stats_method_names"), for better usability */
211 static const char* innodb_stats_method_names[] = {
212 "nulls_equal",
213 "nulls_unequal",
214 "nulls_ignored",
215 NullS
216 };
217
218 /** Used to define an enumerate type of the system variable innodb_stats_method.
219 This is the same as "myisam_stats_method_typelib" */
220 static TYPELIB innodb_stats_method_typelib = {
221 array_elements(innodb_stats_method_names) - 1,
222 "innodb_stats_method_typelib",
223 innodb_stats_method_names,
224 NULL
225 };
226
227 /** Possible values for system variables "innodb_checksum_algorithm" and
228 "innodb_log_checksum_algorithm". */
229 static const char* innodb_checksum_algorithm_names[] = {
230 "crc32",
231 "strict_crc32",
232 "innodb",
233 "strict_innodb",
234 "none",
235 "strict_none",
236 NullS
237 };
238
239 /** Used to define an enumerate type of the system variables
240 innodb_checksum_algorithm and innodb_log_checksum_algorithm. */
241 static TYPELIB innodb_checksum_algorithm_typelib = {
242 array_elements(innodb_checksum_algorithm_names) - 1,
243 "innodb_checksum_algorithm_typelib",
244 innodb_checksum_algorithm_names,
245 NULL
246 };
247
248 /** Possible values for system variable "innodb_cleaner_lsn_age_factor". */
249 static const char* innodb_cleaner_lsn_age_factor_names[] = {
250 "legacy",
251 "high_checkpoint",
252 NullS
253 };
254
255 /** Enumeration for innodb_cleaner_lsn_age_factor. */
256 static TYPELIB innodb_cleaner_lsn_age_factor_typelib = {
257 array_elements(innodb_cleaner_lsn_age_factor_names) - 1,
258 "innodb_cleaner_lsn_age_factor_typelib",
259 innodb_cleaner_lsn_age_factor_names,
260 NULL
261 };
262
263 /** Possible values for system variable "innodb_foreground_preflush". */
264 static const char* innodb_foreground_preflush_names[] = {
265 "sync_preflush",
266 "exponential_backoff",
267 NullS
268 };
269
270 /* Enumeration for innodb_foreground_preflush. */
271 static TYPELIB innodb_foreground_preflush_typelib = {
272 array_elements(innodb_foreground_preflush_names) - 1,
273 "innodb_foreground_preflush_typelib",
274 innodb_foreground_preflush_names,
275 NULL
276 };
277
278 /** Possible values for system variable "innodb_empty_free_list_algorithm". */
279 static const char* innodb_empty_free_list_algorithm_names[] = {
280 "legacy",
281 "backoff",
282 NullS
283 };
284
285 /** Enumeration for innodb_empty_free_list_algorithm. */
286 static TYPELIB innodb_empty_free_list_algorithm_typelib = {
287 array_elements(innodb_empty_free_list_algorithm_names) - 1,
288 "innodb_empty_free_list_algorithm_typelib",
289 innodb_empty_free_list_algorithm_names,
290 NULL
291 };
292
293 /* The following counter is used to convey information to InnoDB
294 about server activity: in case of normal DML ops it is not
295 sensible to call srv_active_wake_master_thread after each
296 operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */
297
298 #define INNOBASE_WAKE_INTERVAL 32
299 static ulong innobase_active_counter = 0;
300
301 static hash_table_t* innobase_open_tables;
302
303 /** Allowed values of innodb_change_buffering */
304 static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
305 "none", /* IBUF_USE_NONE */
306 "inserts", /* IBUF_USE_INSERT */
307 "deletes", /* IBUF_USE_DELETE_MARK */
308 "changes", /* IBUF_USE_INSERT_DELETE_MARK */
309 "purges", /* IBUF_USE_DELETE */
310 "all" /* IBUF_USE_ALL */
311 };
312
313 /* Call back function array defined by MySQL and used to
314 retrieve FTS results. */
315 const struct _ft_vft ft_vft_result = {NULL,
316 innobase_fts_find_ranking,
317 innobase_fts_close_ranking,
318 innobase_fts_retrieve_ranking,
319 NULL};
320
321 const struct _ft_vft_ext ft_vft_ext_result = {innobase_fts_get_version,
322 innobase_fts_flags,
323 innobase_fts_retrieve_docid,
324 innobase_fts_count_matches};
325
326 #ifdef HAVE_PSI_INTERFACE
327 /* Keys to register pthread mutexes/cond in the current file with
328 performance schema */
329 static mysql_pfs_key_t innobase_share_mutex_key;
330 static mysql_pfs_key_t commit_cond_mutex_key;
331 static mysql_pfs_key_t commit_cond_key;
332
333 static PSI_mutex_info all_pthread_mutexes[] = {
334 {&commit_cond_mutex_key, "commit_cond_mutex", 0},
335 {&innobase_share_mutex_key, "innobase_share_mutex", 0}
336 };
337
338 static PSI_cond_info all_innodb_conds[] = {
339 {&commit_cond_key, "commit_cond", 0}
340 };
341
342 # ifdef UNIV_PFS_MUTEX
343 /* all_innodb_mutexes array contains mutexes that are
344 performance schema instrumented if "UNIV_PFS_MUTEX"
345 is defined */
346 static PSI_mutex_info all_innodb_mutexes[] = {
347 {&autoinc_mutex_key, "autoinc_mutex", 0},
348 # ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK
349 {&buffer_block_mutex_key, "buffer_block_mutex", 0},
350 # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */
351 {&buf_pool_zip_mutex_key, "buf_pool_zip_mutex", 0},
352 {&buf_pool_LRU_list_mutex_key, "buf_pool_LRU_list_mutex", 0},
353 {&buf_pool_free_list_mutex_key, "buf_pool_free_list_mutex", 0},
354 {&buf_pool_zip_free_mutex_key, "buf_pool_zip_free_mutex", 0},
355 {&buf_pool_zip_hash_mutex_key, "buf_pool_zip_hash_mutex", 0},
356 {&buf_pool_flush_state_mutex_key, "buf_pool_flush_state_mutex", 0},
357 {&cache_last_read_mutex_key, "cache_last_read_mutex", 0},
358 {&dict_foreign_err_mutex_key, "dict_foreign_err_mutex", 0},
359 {&dict_sys_mutex_key, "dict_sys_mutex", 0},
360 {&file_format_max_mutex_key, "file_format_max_mutex", 0},
361 {&fil_system_mutex_key, "fil_system_mutex", 0},
362 {&flush_list_mutex_key, "flush_list_mutex", 0},
363 {&fts_bg_threads_mutex_key, "fts_bg_threads_mutex", 0},
364 {&fts_delete_mutex_key, "fts_delete_mutex", 0},
365 {&fts_optimize_mutex_key, "fts_optimize_mutex", 0},
366 {&fts_doc_id_mutex_key, "fts_doc_id_mutex", 0},
367 {&fts_pll_tokenize_mutex_key, "fts_pll_tokenize_mutex", 0},
368 {&log_flush_order_mutex_key, "log_flush_order_mutex", 0},
369 {&hash_table_mutex_key, "hash_table_mutex", 0},
370 {&ibuf_bitmap_mutex_key, "ibuf_bitmap_mutex", 0},
371 {&ibuf_mutex_key, "ibuf_mutex", 0},
372 {&ibuf_pessimistic_insert_mutex_key,
373 "ibuf_pessimistic_insert_mutex", 0},
374 # ifndef HAVE_ATOMIC_BUILTINS
375 {&server_mutex_key, "server_mutex", 0},
376 # endif /* !HAVE_ATOMIC_BUILTINS */
377 {&log_bmp_sys_mutex_key, "log_bmp_sys_mutex", 0},
378 {&log_sys_mutex_key, "log_sys_mutex", 0},
379 # ifdef UNIV_MEM_DEBUG
380 {&mem_hash_mutex_key, "mem_hash_mutex", 0},
381 # endif /* UNIV_MEM_DEBUG */
382 {&mem_pool_mutex_key, "mem_pool_mutex", 0},
383 {&mutex_list_mutex_key, "mutex_list_mutex", 0},
384 {&page_zip_stat_per_index_mutex_key, "page_zip_stat_per_index_mutex", 0},
385 {&purge_sys_bh_mutex_key, "purge_sys_bh_mutex", 0},
386 {&recv_sys_mutex_key, "recv_sys_mutex", 0},
387 {&recv_writer_mutex_key, "recv_writer_mutex", 0},
388 {&rseg_mutex_key, "rseg_mutex", 0},
389 # ifdef UNIV_SYNC_DEBUG
390 {&rw_lock_debug_mutex_key, "rw_lock_debug_mutex", 0},
391 # endif /* UNIV_SYNC_DEBUG */
392 {&rw_lock_list_mutex_key, "rw_lock_list_mutex", 0},
393 {&rw_lock_mutex_key, "rw_lock_mutex", 0},
394 {&srv_dict_tmpfile_mutex_key, "srv_dict_tmpfile_mutex", 0},
395 {&srv_innodb_monitor_mutex_key, "srv_innodb_monitor_mutex", 0},
396 {&srv_misc_tmpfile_mutex_key, "srv_misc_tmpfile_mutex", 0},
397 {&srv_monitor_file_mutex_key, "srv_monitor_file_mutex", 0},
398 # ifdef UNIV_SYNC_DEBUG
399 {&sync_thread_mutex_key, "sync_thread_mutex", 0},
400 # endif /* UNIV_SYNC_DEBUG */
401 {&buf_dblwr_mutex_key, "buf_dblwr_mutex", 0},
402 {&trx_undo_mutex_key, "trx_undo_mutex", 0},
403 {&srv_sys_mutex_key, "srv_sys_mutex", 0},
404 {&lock_sys_mutex_key, "lock_mutex", 0},
405 {&lock_sys_wait_mutex_key, "lock_wait_mutex", 0},
406 {&trx_mutex_key, "trx_mutex", 0},
407 {&srv_sys_tasks_mutex_key, "srv_threads_mutex", 0},
408 /* mutex with os_fast_mutex_ interfaces */
409 # ifndef PFS_SKIP_EVENT_MUTEX
410 {&event_os_mutex_key, "event_os_mutex", 0},
411 # endif /* PFS_SKIP_EVENT_MUTEX */
412 {&os_mutex_key, "os_mutex", 0},
413 #ifndef HAVE_ATOMIC_BUILTINS
414 {&srv_conc_mutex_key, "srv_conc_mutex", 0},
415 #endif /* !HAVE_ATOMIC_BUILTINS */
416 #ifndef HAVE_ATOMIC_BUILTINS_64
417 {&monitor_mutex_key, "monitor_mutex", 0},
418 #endif /* !HAVE_ATOMIC_BUILTINS_64 */
419 {&ut_list_mutex_key, "ut_list_mutex", 0},
420 {&trx_sys_mutex_key, "trx_sys_mutex", 0},
421 {&zip_pad_mutex_key, "zip_pad_mutex", 0},
422 };
423 # endif /* UNIV_PFS_MUTEX */
424
425 # ifdef UNIV_PFS_RWLOCK
426 /* all_innodb_rwlocks array contains rwlocks that are
427 performance schema instrumented if "UNIV_PFS_RWLOCK"
428 is defined */
429 static PSI_rwlock_info all_innodb_rwlocks[] = {
430 # ifdef UNIV_LOG_ARCHIVE
431 {&archive_lock_key, "archive_lock", 0},
432 # endif /* UNIV_LOG_ARCHIVE */
433 {&btr_search_latch_key, "btr_search_latch", 0},
434 # ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK
435 {&buf_block_lock_key, "buf_block_lock", 0},
436 # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */
437 # ifdef UNIV_SYNC_DEBUG
438 {&buf_block_debug_latch_key, "buf_block_debug_latch", 0},
439 # endif /* UNIV_SYNC_DEBUG */
440 {&dict_operation_lock_key, "dict_operation_lock", 0},
441 {&fil_space_latch_key, "fil_space_latch", 0},
442 {&checkpoint_lock_key, "checkpoint_lock", 0},
443 {&fts_cache_rw_lock_key, "fts_cache_rw_lock", 0},
444 {&fts_cache_init_rw_lock_key, "fts_cache_init_rw_lock", 0},
445 {&trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0},
446 {&trx_purge_latch_key, "trx_purge_latch", 0},
447 {&index_tree_rw_lock_key, "index_tree_rw_lock", 0},
448 {&index_online_log_key, "index_online_log", 0},
449 {&dict_table_stats_key, "dict_table_stats", 0},
450 {&hash_table_rw_lock_key, "hash_table_locks", 0}
451 };
452 # endif /* UNIV_PFS_RWLOCK */
453
454 # ifdef UNIV_PFS_THREAD
455 /* all_innodb_threads array contains threads that are
456 performance schema instrumented if "UNIV_PFS_THREAD"
457 is defined */
458 static PSI_thread_info all_innodb_threads[] = {
459 {&trx_rollback_clean_thread_key, "trx_rollback_clean_thread", 0},
460 {&io_handler_thread_key, "io_handler_thread", 0},
461 {&srv_lock_timeout_thread_key, "srv_lock_timeout_thread", 0},
462 {&srv_error_monitor_thread_key, "srv_error_monitor_thread", 0},
463 {&srv_monitor_thread_key, "srv_monitor_thread", 0},
464 {&srv_master_thread_key, "srv_master_thread", 0},
465 {&srv_purge_thread_key, "srv_purge_thread", 0},
466 {&buf_page_cleaner_thread_key, "page_cleaner_thread", 0},
467 {&buf_lru_manager_thread_key, "lru_manager_thread", 0},
468 {&recv_writer_thread_key, "recv_writer_thread", 0},
469 {&srv_log_tracking_thread_key, "srv_redo_log_follow_thread", 0}
470 };
471 # endif /* UNIV_PFS_THREAD */
472
473 # ifdef UNIV_PFS_IO
474 /* all_innodb_files array contains the type of files that are
475 performance schema instrumented if "UNIV_PFS_IO" is defined */
476 static PSI_file_info all_innodb_files[] = {
477 {&innodb_file_data_key, "innodb_data_file", 0},
478 {&innodb_file_log_key, "innodb_log_file", 0},
479 {&innodb_file_temp_key, "innodb_temp_file", 0},
480 {&innodb_file_bmp_key, "innodb_bmp_file", 0}
481 };
482 # endif /* UNIV_PFS_IO */
483 #endif /* HAVE_PSI_INTERFACE */
484
485 /** Always normalize table name to lower case on Windows */
486 #ifdef __WIN__
487 #define normalize_table_name(norm_name, name) \
488 normalize_table_name_low(norm_name, name, TRUE)
489 #else
490 #define normalize_table_name(norm_name, name) \
491 normalize_table_name_low(norm_name, name, FALSE)
492 #endif /* __WIN__ */
493
494 /** Set up InnoDB API callback function array */
495 ib_cb_t innodb_api_cb[] = {
496 (ib_cb_t) ib_cursor_open_table,
497 (ib_cb_t) ib_cursor_read_row,
498 (ib_cb_t) ib_cursor_insert_row,
499 (ib_cb_t) ib_cursor_delete_row,
500 (ib_cb_t) ib_cursor_update_row,
501 (ib_cb_t) ib_cursor_moveto,
502 (ib_cb_t) ib_cursor_first,
503 (ib_cb_t) ib_cursor_next,
504 (ib_cb_t) ib_cursor_last,
505 (ib_cb_t) ib_cursor_set_match_mode,
506 (ib_cb_t) ib_sec_search_tuple_create,
507 (ib_cb_t) ib_clust_read_tuple_create,
508 (ib_cb_t) ib_tuple_delete,
509 (ib_cb_t) ib_tuple_copy,
510 (ib_cb_t) ib_tuple_read_u8,
511 (ib_cb_t) ib_tuple_write_u8,
512 (ib_cb_t) ib_tuple_read_u16,
513 (ib_cb_t) ib_tuple_write_u16,
514 (ib_cb_t) ib_tuple_read_u32,
515 (ib_cb_t) ib_tuple_write_u32,
516 (ib_cb_t) ib_tuple_read_u64,
517 (ib_cb_t) ib_tuple_write_u64,
518 (ib_cb_t) ib_tuple_read_i8,
519 (ib_cb_t) ib_tuple_write_i8,
520 (ib_cb_t) ib_tuple_read_i16,
521 (ib_cb_t) ib_tuple_write_i16,
522 (ib_cb_t) ib_tuple_read_i32,
523 (ib_cb_t) ib_tuple_write_i32,
524 (ib_cb_t) ib_tuple_read_i64,
525 (ib_cb_t) ib_tuple_write_i64,
526 (ib_cb_t) ib_tuple_get_n_cols,
527 (ib_cb_t) ib_col_set_value,
528 (ib_cb_t) ib_col_get_value,
529 (ib_cb_t) ib_col_get_meta,
530 (ib_cb_t) ib_trx_begin,
531 (ib_cb_t) ib_trx_commit,
532 (ib_cb_t) ib_trx_rollback,
533 (ib_cb_t) ib_trx_start,
534 (ib_cb_t) ib_trx_release,
535 (ib_cb_t) ib_trx_state,
536 (ib_cb_t) ib_cursor_lock,
537 (ib_cb_t) ib_cursor_close,
538 (ib_cb_t) ib_cursor_new_trx,
539 (ib_cb_t) ib_cursor_reset,
540 (ib_cb_t) ib_open_table_by_name,
541 (ib_cb_t) ib_col_get_name,
542 (ib_cb_t) ib_table_truncate,
543 (ib_cb_t) ib_cursor_open_index_using_name,
544 (ib_cb_t) ib_close_thd,
545 (ib_cb_t) ib_cfg_get_cfg,
546 (ib_cb_t) ib_cursor_set_memcached_sync,
547 (ib_cb_t) ib_cursor_set_cluster_access,
548 (ib_cb_t) ib_cursor_commit_trx,
549 (ib_cb_t) ib_cfg_trx_level,
550 (ib_cb_t) ib_tuple_get_n_user_cols,
551 (ib_cb_t) ib_cursor_set_lock_mode,
552 (ib_cb_t) ib_cursor_clear_trx,
553 (ib_cb_t) ib_get_idx_field_name,
554 (ib_cb_t) ib_trx_get_start_time,
555 (ib_cb_t) ib_cfg_bk_commit_interval,
556 (ib_cb_t) ib_cursor_stmt_begin,
557 (ib_cb_t) ib_trx_read_only
558 };
559
560 /**Check whether valid argument given to innobase_*_stopword_table.
561 This function is registered as a callback with MySQL.
562 @param[in] thd thread handle
563 @param[in] var pointer to system variable
564 @param[out] save immediate result for update function
565 @param[in] value incoming string
566 @return 0 for valid stopword table */
567 static
568 int
569 innodb_stopword_table_validate(
570 /*===========================*/
571 THD* thd,
572 struct st_mysql_sys_var* var,
573 void* save,
574 struct st_mysql_value* value);
575
576 /** Validate passed-in "value" is a valid directory name.
577 This function is registered as a callback with MySQL.
578 @param[in,out] thd thread handle
579 @param[in] var pointer to system variable
580 @param[out] save immediate result for update
581 @param[in] value incoming string
582 @return 0 for valid name */
583 static
584 int
innodb_tmpdir_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)585 innodb_tmpdir_validate(
586 THD* thd,
587 struct st_mysql_sys_var* var,
588 void* save,
589 struct st_mysql_value* value)
590 {
591
592 char* alter_tmp_dir;
593 char* innodb_tmp_dir;
594 char buff[OS_FILE_MAX_PATH];
595 int len = sizeof(buff);
596 char tmp_abs_path[FN_REFLEN + 2];
597
598 ut_ad(save != NULL);
599 ut_ad(value != NULL);
600
601 if (check_global_access(thd, FILE_ACL)) {
602 push_warning_printf(
603 thd, Sql_condition::WARN_LEVEL_WARN,
604 ER_WRONG_ARGUMENTS,
605 "InnoDB: FILE Permissions required");
606 *static_cast<const char**>(save) = NULL;
607 return(1);
608 }
609
610 alter_tmp_dir = (char*) value->val_str(value, buff, &len);
611
612 if (!alter_tmp_dir) {
613 *static_cast<const char**>(save) = alter_tmp_dir;
614 return(0);
615 }
616
617 if (strlen(alter_tmp_dir) > FN_REFLEN) {
618 push_warning_printf(
619 thd, Sql_condition::WARN_LEVEL_WARN,
620 ER_WRONG_ARGUMENTS,
621 "Path length should not exceed %d bytes", FN_REFLEN);
622 *static_cast<const char**>(save) = NULL;
623 return(1);
624 }
625
626 my_realpath(tmp_abs_path, alter_tmp_dir, 0);
627 size_t tmp_abs_len = strlen(tmp_abs_path);
628
629 if (my_access(tmp_abs_path, F_OK)) {
630
631 push_warning_printf(
632 thd, Sql_condition::WARN_LEVEL_WARN,
633 ER_WRONG_ARGUMENTS,
634 "InnoDB: Path doesn't exist.");
635 *static_cast<const char**>(save) = NULL;
636 return(1);
637 } else if (my_access(tmp_abs_path, R_OK | W_OK)) {
638 push_warning_printf(
639 thd, Sql_condition::WARN_LEVEL_WARN,
640 ER_WRONG_ARGUMENTS,
641 "InnoDB: Server doesn't have permission in "
642 "the given location.");
643 *static_cast<const char**>(save) = NULL;
644 return(1);
645 }
646
647 MY_STAT stat_info_dir;
648
649 if (my_stat(tmp_abs_path, &stat_info_dir, MYF(0))) {
650 if ((stat_info_dir.st_mode & S_IFDIR) != S_IFDIR) {
651
652 push_warning_printf(
653 thd, Sql_condition::WARN_LEVEL_WARN,
654 ER_WRONG_ARGUMENTS,
655 "Given path is not a directory. ");
656 *static_cast<const char**>(save) = NULL;
657 return(1);
658 }
659 }
660
661 if (!is_mysql_datadir_path(tmp_abs_path)) {
662
663 push_warning_printf(
664 thd, Sql_condition::WARN_LEVEL_WARN,
665 ER_WRONG_ARGUMENTS,
666 "InnoDB: Path Location should not be same as "
667 "mysql data directory location.");
668 *static_cast<const char**>(save) = NULL;
669 return(1);
670 }
671
672 innodb_tmp_dir = static_cast<char*>(
673 thd_memdup(thd, tmp_abs_path, tmp_abs_len + 1));
674 *static_cast<const char**>(save) = innodb_tmp_dir;
675 return(0);
676 }
677
678 /** "GEN_CLUST_INDEX" is the name reserved for InnoDB default
679 system clustered index when there is no primary key. */
680 const char innobase_index_reserve_name[] = "GEN_CLUST_INDEX";
681 /************************************************************//**
682 Synchronously read and parse the redo log up to the last
683 checkpoint to write the changed page bitmap.
684 @return 0 to indicate success. Current implementation cannot fail. */
685 static
686 my_bool
687 innobase_flush_changed_page_bitmaps();
688 /*==================================*/
689 /************************************************************//**
690 Delete all the bitmap files for data less than the specified LSN.
691 If called with lsn == 0 (i.e. set by RESET request) or
692 IB_ULONGLONG_MAX, restart the bitmap file sequence, otherwise
693 continue it.
694 @return 0 to indicate success, 1 for failure. */
695 static
696 my_bool
697 innobase_purge_changed_page_bitmaps(
698 /*================================*/
699 ulonglong lsn); /*!< in: LSN to purge files up to */
700
701
702 /*****************************************************************//**
703 Check whether this is a fake change transaction.
704 @return TRUE if a fake change transaction */
705 static
706 my_bool
707 innobase_is_fake_change(
708 /*====================*/
709 handlerton *hton, /*!< in: InnoDB handlerton */
710 THD* thd); /*!< in: MySQL thread handle of the user for
711 whom the transaction is being committed */
712
713 /** Empty free list algorithm.
714 Checks if buffer pool is big enough to enable backoff algorithm.
715 InnoDB empty free list algorithm backoff requires free pages
716 from LRU for the best performance.
717 buf_LRU_buf_pool_running_out cancels query if 1/4 of
718 buffer pool belongs to LRU or freelist.
719 At the same time buf_flush_LRU_list_batch
720 keeps up to BUF_LRU_MIN_LEN in LRU.
721 In order to avoid deadlock baclkoff requires buffer pool
722 to be at least 4*BUF_LRU_MIN_LEN,
723 but flush peformance is bad because of trashing
724 and additional BUF_LRU_MIN_LEN pages are requested.
725 @param[in] algorithm desired algorithm from srv_empty_free_list_t
726 @return true if it's possible to enable backoff. */
727 static inline
728 bool
innodb_empty_free_list_algorithm_allowed(srv_empty_free_list_t algorithm)729 innodb_empty_free_list_algorithm_allowed(
730 srv_empty_free_list_t algorithm)
731 {
732 long long buf_pool_pages = srv_buf_pool_size / srv_page_size
733 / srv_buf_pool_instances;
734
735 return(buf_pool_pages >= BUF_LRU_MIN_LEN * (4 + 1)
736 || algorithm != SRV_EMPTY_FREE_LIST_BACKOFF);
737 }
738
739 /** Get the list of foreign keys referencing a specified table
740 table.
741 @param thd The thread handle
742 @param path Path to the table
743 @param f_key_list[out] The list of foreign keys
744
745 @return error code or zero for success */
746 static
747 int
748 innobase_get_parent_fk_list(
749 THD* thd,
750 const char* path,
751 List<FOREIGN_KEY_INFO>* f_key_list);
752
753 /******************************************************************//**
754 Maps a MySQL trx isolation level code to the InnoDB isolation level code
755 @return InnoDB isolation level */
756 static inline
757 ulint
758 innobase_map_isolation_level(
759 /*=========================*/
760 enum_tx_isolation iso); /*!< in: MySQL isolation level code */
761
762 static const char innobase_hton_name[]= "InnoDB";
763
764 static MYSQL_THDVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
765 "Enable InnoDB support for the XA two-phase commit",
766 /* check_func */ NULL, /* update_func */ NULL,
767 /* default */ TRUE);
768
769 static MYSQL_THDVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
770 "Enable InnoDB locking in LOCK TABLES",
771 /* check_func */ NULL, /* update_func */ NULL,
772 /* default */ TRUE);
773
774 static MYSQL_THDVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
775 "Use strict mode when evaluating create options.",
776 NULL, NULL, FALSE);
777
778 static MYSQL_THDVAR_BOOL(ft_enable_stopword, PLUGIN_VAR_OPCMDARG,
779 "Create FTS index with stopword.",
780 NULL, NULL,
781 /* default */ TRUE);
782
783 static MYSQL_THDVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
784 "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
785 NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
786
787 static MYSQL_THDVAR_STR(ft_user_stopword_table,
788 PLUGIN_VAR_OPCMDARG|PLUGIN_VAR_MEMALLOC,
789 "User supplied stopword table name, effective in the session level.",
790 innodb_stopword_table_validate, NULL, NULL);
791
792 static MYSQL_THDVAR_ULONG(flush_log_at_trx_commit, PLUGIN_VAR_OPCMDARG,
793 "Set to 0 (write and flush once per second),"
794 " 1 (write and flush at each commit)"
795 " or 2 (write at commit, flush once per second).",
796 NULL, NULL, 1, 0, 2, 0);
797
798 static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG,
799 "In the transaction after enabled, UPDATE, INSERT and DELETE only move the cursor to the records "
800 "and do nothing other operations (no changes, no ibuf, no undo, no transaction log) in the transaction. "
801 "This is to cause replication prefetch IO. ATTENTION: the transaction started after enabled is affected.",
802 NULL, NULL, FALSE);
803
804 static MYSQL_THDVAR_STR(tmpdir,
805 PLUGIN_VAR_OPCMDARG|PLUGIN_VAR_MEMALLOC,
806 "Directory for temporary non-tablespace files.",
807 innodb_tmpdir_validate, NULL, NULL);
808
809 static SHOW_VAR innodb_status_variables[]= {
810 {"buffer_pool_dump_status",
811 (char*) &export_vars.innodb_buffer_pool_dump_status, SHOW_CHAR},
812 {"buffer_pool_load_status",
813 (char*) &export_vars.innodb_buffer_pool_load_status, SHOW_CHAR},
814 {"background_log_sync",
815 (char*) &export_vars.innodb_background_log_sync, SHOW_LONG},
816 {"buffer_pool_pages_data",
817 (char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
818 {"buffer_pool_bytes_data",
819 (char*) &export_vars.innodb_buffer_pool_bytes_data, SHOW_LONG},
820 {"buffer_pool_pages_dirty",
821 (char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
822 {"buffer_pool_bytes_dirty",
823 (char*) &export_vars.innodb_buffer_pool_bytes_dirty, SHOW_LONG},
824 {"buffer_pool_pages_flushed",
825 (char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
826 {"buffer_pool_pages_LRU_flushed",
827 (char*) &export_vars.innodb_buffer_pool_pages_LRU_flushed, SHOW_LONG},
828 {"buffer_pool_pages_free",
829 (char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
830 #ifdef UNIV_DEBUG
831 {"buffer_pool_pages_latched",
832 (char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
833 #endif /* UNIV_DEBUG */
834 {"buffer_pool_pages_made_not_young",
835 (char*) &export_vars.innodb_buffer_pool_pages_made_not_young, SHOW_LONG},
836 {"buffer_pool_pages_made_young",
837 (char*) &export_vars.innodb_buffer_pool_pages_made_young, SHOW_LONG},
838 {"buffer_pool_pages_misc",
839 (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
840 {"buffer_pool_pages_old",
841 (char*) &export_vars.innodb_buffer_pool_pages_old, SHOW_LONG},
842 {"buffer_pool_pages_total",
843 (char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
844 {"buffer_pool_read_ahead_rnd",
845 (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
846 {"buffer_pool_read_ahead",
847 (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG},
848 {"buffer_pool_read_ahead_evicted",
849 (char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG},
850 {"buffer_pool_read_requests",
851 (char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
852 {"buffer_pool_reads",
853 (char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
854 {"buffer_pool_wait_free",
855 (char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
856 {"buffer_pool_write_requests",
857 (char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
858 {"checkpoint_age",
859 (char*) &export_vars.innodb_checkpoint_age, SHOW_LONG},
860 {"checkpoint_max_age",
861 (char*) &export_vars.innodb_checkpoint_max_age, SHOW_LONG},
862 {"data_fsyncs",
863 (char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
864 {"data_pending_fsyncs",
865 (char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
866 {"data_pending_reads",
867 (char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
868 {"data_pending_writes",
869 (char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
870 {"data_read",
871 (char*) &export_vars.innodb_data_read, SHOW_LONG},
872 {"data_reads",
873 (char*) &export_vars.innodb_data_reads, SHOW_LONG},
874 {"data_writes",
875 (char*) &export_vars.innodb_data_writes, SHOW_LONG},
876 {"data_written",
877 (char*) &export_vars.innodb_data_written, SHOW_LONG},
878 {"dblwr_pages_written",
879 (char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
880 {"dblwr_writes",
881 (char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
882 {"deadlocks",
883 (char*) &export_vars.innodb_deadlocks, SHOW_LONG},
884 {"have_atomic_builtins",
885 (char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
886 {"history_list_length",
887 (char*) &export_vars.innodb_history_list_length, SHOW_LONG},
888 {"ibuf_discarded_delete_marks",
889 (char*) &export_vars.innodb_ibuf_discarded_delete_marks, SHOW_LONG},
890 {"ibuf_discarded_deletes",
891 (char*) &export_vars.innodb_ibuf_discarded_deletes, SHOW_LONG},
892 {"ibuf_discarded_inserts",
893 (char*) &export_vars.innodb_ibuf_discarded_inserts, SHOW_LONG},
894 {"ibuf_free_list",
895 (char*) &export_vars.innodb_ibuf_free_list, SHOW_LONG},
896 {"ibuf_merged_delete_marks",
897 (char*) &export_vars.innodb_ibuf_merged_delete_marks, SHOW_LONG},
898 {"ibuf_merged_deletes",
899 (char*) &export_vars.innodb_ibuf_merged_deletes, SHOW_LONG},
900 {"ibuf_merged_inserts",
901 (char*) &export_vars.innodb_ibuf_merged_inserts, SHOW_LONG},
902 {"ibuf_merges",
903 (char*) &export_vars.innodb_ibuf_merges, SHOW_LONG},
904 {"ibuf_segment_size",
905 (char*) &export_vars.innodb_ibuf_segment_size, SHOW_LONG},
906 {"ibuf_size",
907 (char*) &export_vars.innodb_ibuf_size, SHOW_LONG},
908 {"log_waits",
909 (char*) &export_vars.innodb_log_waits, SHOW_LONG},
910 {"log_write_requests",
911 (char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
912 {"log_writes",
913 (char*) &export_vars.innodb_log_writes, SHOW_LONG},
914 {"lsn_current",
915 (char*) &export_vars.innodb_lsn_current, SHOW_LONGLONG},
916 {"lsn_flushed",
917 (char*) &export_vars.innodb_lsn_flushed, SHOW_LONGLONG},
918 {"lsn_last_checkpoint",
919 (char*) &export_vars.innodb_lsn_last_checkpoint, SHOW_LONGLONG},
920 {"master_thread_active_loops",
921 (char*) &export_vars.innodb_master_thread_active_loops, SHOW_LONG},
922 {"master_thread_idle_loops",
923 (char*) &export_vars.innodb_master_thread_idle_loops, SHOW_LONG},
924 {"max_trx_id",
925 (char*) &export_vars.innodb_max_trx_id, SHOW_LONGLONG},
926 {"mem_adaptive_hash",
927 (char*) &export_vars.innodb_mem_adaptive_hash, SHOW_LONG},
928 {"mem_dictionary",
929 (char*) &export_vars.innodb_mem_dictionary, SHOW_LONG},
930 {"mem_total",
931 (char*) &export_vars.innodb_mem_total, SHOW_LONG},
932 {"mutex_os_waits",
933 (char*) &export_vars.innodb_mutex_os_waits, SHOW_LONGLONG},
934 {"mutex_spin_rounds",
935 (char*) &export_vars.innodb_mutex_spin_rounds, SHOW_LONGLONG},
936 {"mutex_spin_waits",
937 (char*) &export_vars.innodb_mutex_spin_waits, SHOW_LONGLONG},
938 {"oldest_view_low_limit_trx_id",
939 (char*) &export_vars.innodb_oldest_view_low_limit_trx_id, SHOW_LONGLONG},
940 {"os_log_fsyncs",
941 (char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
942 {"os_log_pending_fsyncs",
943 (char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
944 {"os_log_pending_writes",
945 (char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
946 {"os_log_written",
947 (char*) &export_vars.innodb_os_log_written, SHOW_LONGLONG},
948 {"page_size",
949 (char*) &export_vars.innodb_page_size, SHOW_LONG},
950 {"pages_created",
951 (char*) &export_vars.innodb_pages_created, SHOW_LONG},
952 {"pages_read",
953 (char*) &export_vars.innodb_pages_read, SHOW_LONG},
954 {"pages_written",
955 (char*) &export_vars.innodb_pages_written, SHOW_LONG},
956 {"purge_trx_id",
957 (char*) &export_vars.innodb_purge_trx_id, SHOW_LONGLONG},
958 {"purge_undo_no",
959 (char*) &export_vars.innodb_purge_undo_no, SHOW_LONGLONG},
960 {"row_lock_current_waits",
961 (char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
962 {"current_row_locks",
963 (char*) &export_vars.innodb_current_row_locks, SHOW_LONG},
964 {"row_lock_time",
965 (char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
966 {"row_lock_time_avg",
967 (char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
968 {"row_lock_time_max",
969 (char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
970 {"row_lock_waits",
971 (char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
972 {"rows_deleted",
973 (char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
974 {"rows_inserted",
975 (char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
976 {"rows_read",
977 (char*) &export_vars.innodb_rows_read, SHOW_LONG},
978 {"rows_updated",
979 (char*) &export_vars.innodb_rows_updated, SHOW_LONG},
980 {"num_open_files",
981 (char*) &export_vars.innodb_num_open_files, SHOW_LONG},
982 {"read_views_memory",
983 (char*) &export_vars.innodb_read_views_memory, SHOW_LONG},
984 {"descriptors_memory",
985 (char*) &export_vars.innodb_descriptors_memory, SHOW_LONG},
986 {"s_lock_os_waits",
987 (char*) &export_vars.innodb_s_lock_os_waits, SHOW_LONGLONG},
988 {"s_lock_spin_rounds",
989 (char*) &export_vars.innodb_s_lock_spin_rounds, SHOW_LONGLONG},
990 {"s_lock_spin_waits",
991 (char*) &export_vars.innodb_s_lock_spin_waits, SHOW_LONGLONG},
992 {"truncated_status_writes",
993 (char*) &export_vars.innodb_truncated_status_writes, SHOW_LONG},
994 {"available_undo_logs",
995 (char*) &export_vars.innodb_available_undo_logs, SHOW_LONG},
996 #ifdef UNIV_DEBUG
997 {"purge_trx_id_age",
998 (char*) &export_vars.innodb_purge_trx_id_age, SHOW_LONG},
999 {"purge_view_trx_id_age",
1000 (char*) &export_vars.innodb_purge_view_trx_id_age, SHOW_LONG},
1001 #endif /* UNIV_DEBUG */
1002 {"x_lock_os_waits",
1003 (char*) &export_vars.innodb_x_lock_os_waits, SHOW_LONGLONG},
1004 {"x_lock_spin_rounds",
1005 (char*) &export_vars.innodb_x_lock_spin_rounds, SHOW_LONGLONG},
1006 {"x_lock_spin_waits",
1007 (char*) &export_vars.innodb_x_lock_spin_waits, SHOW_LONGLONG},
1008 {"secondary_index_triggered_cluster_reads",
1009 (char*) &export_vars.innodb_sec_rec_cluster_reads, SHOW_LONG},
1010 {"secondary_index_triggered_cluster_reads_avoided",
1011 (char*) &export_vars.innodb_sec_rec_cluster_reads_avoided, SHOW_LONG},
1012 {"buffered_aio_submitted",
1013 (char*) &export_vars.innodb_buffered_aio_submitted, SHOW_LONG},
1014
1015 {"scan_pages_contiguous",
1016 (char*) &export_vars.innodb_fragmentation_stats.scan_pages_contiguous,
1017 SHOW_LONG},
1018 {"scan_pages_disjointed",
1019 (char*) &export_vars.innodb_fragmentation_stats.scan_pages_disjointed,
1020 SHOW_LONG},
1021 {"scan_pages_total_seek_distance",
1022 (char*) &export_vars.innodb_fragmentation_stats.scan_pages_total_seek_distance,
1023 SHOW_LONG},
1024 {"scan_data_size",
1025 (char*) &export_vars.innodb_fragmentation_stats.scan_data_size,
1026 SHOW_LONG},
1027 {"scan_deleted_recs_size",
1028 (char*) &export_vars.innodb_fragmentation_stats.scan_deleted_recs_size,
1029 SHOW_LONG},
1030 {NullS, NullS, SHOW_LONG}
1031 };
1032
1033 /************************************************************************//**
1034 Handling the shared INNOBASE_SHARE structure that is needed to provide table
1035 locking. Register the table name if it doesn't exist in the hash table. */
1036 static
1037 INNOBASE_SHARE*
1038 get_share(
1039 /*======*/
1040 const char* table_name); /*!< in: table to lookup */
1041
1042 /************************************************************************//**
1043 Free the shared object that was registered with get_share(). */
1044 static
1045 void
1046 free_share(
1047 /*=======*/
1048 INNOBASE_SHARE* share); /*!< in/own: share to free */
1049
1050 /*****************************************************************//**
1051 Frees a possible InnoDB trx object associated with the current THD.
1052 @return 0 or error number */
1053 static
1054 int
1055 innobase_close_connection(
1056 /*======================*/
1057 handlerton* hton, /*!< in/out: Innodb handlerton */
1058 THD* thd); /*!< in: MySQL thread handle for
1059 which to close the connection */
1060
1061 /*****************************************************************//**
1062 Cancel any pending lock request associated with the current THD. */
1063 static
1064 void
1065 innobase_kill_connection(
1066 /*======================*/
1067 handlerton* hton, /*!< in: innobase handlerton */
1068 THD* thd); /*!< in: handle to the MySQL thread being killed */
1069
1070 /*****************************************************************//**
1071 Commits a transaction in an InnoDB database or marks an SQL statement
1072 ended.
1073 @return 0 */
1074 static
1075 int
1076 innobase_commit(
1077 /*============*/
1078 handlerton* hton, /*!< in/out: Innodb handlerton */
1079 THD* thd, /*!< in: MySQL thread handle of the
1080 user for whom the transaction should
1081 be committed */
1082 bool commit_trx); /*!< in: true - commit transaction
1083 false - the current SQL statement
1084 ended */
1085
1086 /*****************************************************************//**
1087 Rolls back a transaction to a savepoint.
1088 @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
1089 given name */
1090 static
1091 int
1092 innobase_rollback(
1093 /*==============*/
1094 handlerton* hton, /*!< in/out: Innodb handlerton */
1095 THD* thd, /*!< in: handle to the MySQL thread
1096 of the user whose transaction should
1097 be rolled back */
1098 bool rollback_trx); /*!< in: TRUE - rollback entire
1099 transaction FALSE - rollback the current
1100 statement only */
1101
1102 /*****************************************************************//**
1103 Rolls back a transaction to a savepoint.
1104 @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
1105 given name */
1106 static
1107 int
1108 innobase_rollback_to_savepoint(
1109 /*===========================*/
1110 handlerton* hton, /*!< in/out: InnoDB handlerton */
1111 THD* thd, /*!< in: handle to the MySQL thread of
1112 the user whose XA transaction should
1113 be rolled back to savepoint */
1114 void* savepoint); /*!< in: savepoint data */
1115
1116 /*****************************************************************//**
1117 Check whether innodb state allows to safely release MDL locks after
1118 rollback to savepoint.
1119 @return true if it is safe, false if its not safe. */
1120 static
1121 bool
1122 innobase_rollback_to_savepoint_can_release_mdl(
1123 /*===========================================*/
1124 handlerton* hton, /*!< in/out: InnoDB handlerton */
1125 THD* thd); /*!< in: handle to the MySQL thread of
1126 the user whose XA transaction should
1127 be rolled back to savepoint */
1128
1129 /*****************************************************************//**
1130 Sets a transaction savepoint.
1131 @return always 0, that is, always succeeds */
1132 static
1133 int
1134 innobase_savepoint(
1135 /*===============*/
1136 handlerton* hton, /*!< in/out: InnoDB handlerton */
1137 THD* thd, /*!< in: handle to the MySQL thread of
1138 the user's XA transaction for which
1139 we need to take a savepoint */
1140 void* savepoint); /*!< in: savepoint data */
1141
1142 /*****************************************************************//**
1143 Release transaction savepoint name.
1144 @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
1145 given name */
1146 static
1147 int
1148 innobase_release_savepoint(
1149 /*=======================*/
1150 handlerton* hton, /*!< in/out: handlerton for Innodb */
1151 THD* thd, /*!< in: handle to the MySQL thread
1152 of the user whose transaction's
1153 savepoint should be released */
1154 void* savepoint); /*!< in: savepoint data */
1155
1156 /************************************************************************//**
1157 Function for constructing an InnoDB table handler instance. */
1158 static
1159 handler*
1160 innobase_create_handler(
1161 /*====================*/
1162 handlerton* hton, /*!< in/out: handlerton for Innodb */
1163 TABLE_SHARE* table,
1164 MEM_ROOT* mem_root);
1165
1166 /** @brief Initialize the default value of innodb_commit_concurrency.
1167
1168 Once InnoDB is running, the innodb_commit_concurrency must not change
1169 from zero to nonzero. (Bug #42101)
1170
1171 The initial default value is 0, and without this extra initialization,
1172 SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
1173 to 0, even if it was initially set to nonzero at the command line
1174 or configuration file. */
1175 static
1176 void
1177 innobase_commit_concurrency_init_default();
1178 /*=======================================*/
1179
1180 /** @brief Initialize the default and max value of innodb_undo_logs.
1181
1182 Once InnoDB is running, the default value and the max value of
1183 innodb_undo_logs must be equal to the available undo logs,
1184 given by srv_available_undo_logs. */
1185 static
1186 void
1187 innobase_undo_logs_init_default_max();
1188 /*==================================*/
1189
1190 /************************************************************//**
1191 Validate the file format name and return its corresponding id.
1192 @return valid file format id */
1193 static
1194 uint
1195 innobase_file_format_name_lookup(
1196 /*=============================*/
1197 const char* format_name); /*!< in: pointer to file format
1198 name */
1199 /************************************************************//**
1200 Validate the file format check config parameters, as a side effect it
1201 sets the srv_max_file_format_at_startup variable.
1202 @return the format_id if valid config value, otherwise, return -1 */
1203 static
1204 int
1205 innobase_file_format_validate_and_set(
1206 /*==================================*/
1207 const char* format_max); /*!< in: parameter value */
1208
1209 /*******************************************************************//**
1210 This function is used to prepare an X/Open XA distributed transaction.
1211 @return 0 or error number */
1212 static
1213 int
1214 innobase_xa_prepare(
1215 /*================*/
1216 handlerton* hton, /*!< in: InnoDB handlerton */
1217 THD* thd, /*!< in: handle to the MySQL thread of
1218 the user whose XA transaction should
1219 be prepared */
1220 bool all); /*!< in: true - prepare transaction
1221 false - the current SQL statement
1222 ended */
1223 /*******************************************************************//**
1224 This function is used to recover X/Open XA distributed transactions.
1225 @return number of prepared transactions stored in xid_list */
1226 static
1227 int
1228 innobase_xa_recover(
1229 /*================*/
1230 handlerton* hton, /*!< in: InnoDB handlerton */
1231 XID* xid_list, /*!< in/out: prepared transactions */
1232 uint len); /*!< in: number of slots in xid_list */
1233 /*******************************************************************//**
1234 This function is used to commit one X/Open XA distributed transaction
1235 which is in the prepared state
1236 @return 0 or error number */
1237 static
1238 int
1239 innobase_commit_by_xid(
1240 /*===================*/
1241 handlerton* hton, /*!< in: InnoDB handlerton */
1242 XID* xid); /*!< in: X/Open XA transaction
1243 identification */
1244 /*******************************************************************//**
1245 This function is used to rollback one X/Open XA distributed transaction
1246 which is in the prepared state
1247 @return 0 or error number */
1248 static
1249 int
1250 innobase_rollback_by_xid(
1251 /*=====================*/
1252 handlerton* hton, /*!< in: InnoDB handlerton */
1253 XID* xid); /*!< in: X/Open XA transaction
1254 identification */
1255 /*******************************************************************//**
1256 Create a consistent view for a cursor based on current transaction
1257 which is created if the corresponding MySQL thread still lacks one.
1258 This consistent view is then used inside of MySQL when accessing records
1259 using a cursor.
1260 @return pointer to cursor view or NULL */
1261 static
1262 void*
1263 innobase_create_cursor_view(
1264 /*========================*/
1265 handlerton* hton, /*!< in: innobase hton */
1266 THD* thd); /*!< in: user thread handle */
1267 /*******************************************************************//**
1268 Set the given consistent cursor view to a transaction which is created
1269 if the corresponding MySQL thread still lacks one. If the given
1270 consistent cursor view is NULL global read view of a transaction is
1271 restored to a transaction read view. */
1272 static
1273 void
1274 innobase_set_cursor_view(
1275 /*=====================*/
1276 handlerton* hton, /*!< in: handlerton of Innodb */
1277 THD* thd, /*!< in: user thread handle */
1278 void* curview); /*!< in: Consistent cursor view to
1279 be set */
1280 /*******************************************************************//**
1281 Close the given consistent cursor view of a transaction and restore
1282 global read view to a transaction read view. Transaction is created if the
1283 corresponding MySQL thread still lacks one. */
1284 static
1285 void
1286 innobase_close_cursor_view(
1287 /*=======================*/
1288 handlerton* hton, /*!< in: handlerton of Innodb */
1289 THD* thd, /*!< in: user thread handle */
1290 void* curview); /*!< in: Consistent read view to be
1291 closed */
1292 /*****************************************************************//**
1293 Removes all tables in the named database inside InnoDB. */
1294 static
1295 void
1296 innobase_drop_database(
1297 /*===================*/
1298 handlerton* hton, /*!< in: handlerton of Innodb */
1299 char* path); /*!< in: database path; inside InnoDB
1300 the name of the last directory in
1301 the path is used as the database name:
1302 for example, in 'mysql/data/test' the
1303 database name is 'test' */
1304 /*******************************************************************//**
1305 Closes an InnoDB database. */
1306 static
1307 int
1308 innobase_end(
1309 /*=========*/
1310 handlerton* hton, /* in: Innodb handlerton */
1311 ha_panic_function type);
1312
1313 /*****************************************************************//**
1314 Stores the current binlog coordinates in the trx system header. */
1315 static
1316 int
1317 innobase_store_binlog_info(
1318 /*=======================*/
1319 handlerton* hton, /*!< in: InnoDB handlerton */
1320 THD* thd); /*!< in: MySQL thread handle */
1321
1322 /*****************************************************************//**
1323 Creates an InnoDB transaction struct for the thd if it does not yet have one.
1324 Starts a new InnoDB transaction if a transaction is not yet started. And
1325 assigns a new snapshot for a consistent read if the transaction does not yet
1326 have one.
1327 @return 0 */
1328 static
1329 int
1330 innobase_start_trx_and_assign_read_view(
1331 /*====================================*/
1332 handlerton* hton, /* in: Innodb handlerton */
1333 THD* thd); /* in: MySQL thread handle of the
1334 user for whom the transaction should
1335 be committed */
1336 /*****************************************************************//**
1337 Creates an InnoDB transaction struct for the thd if it does not yet have one.
1338 Starts a new InnoDB transaction if a transaction is not yet started. And
1339 clones snapshot for a consistent read from another session, if it has one.
1340 @return 0 */
1341 static
1342 int
1343 innobase_start_trx_and_clone_read_view(
1344 /*====================================*/
1345 handlerton* hton, /* in: Innodb handlerton */
1346 THD* thd, /* in: MySQL thread handle of the
1347 user for whom the transaction should
1348 be committed */
1349 THD* from_thd); /* in: MySQL thread handle of the
1350 user session from which the consistent
1351 read should be cloned */
1352 /****************************************************************//**
1353 Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
1354 the logs, and the name of this function should be innobase_checkpoint.
1355 @return TRUE if error */
1356 static
1357 bool
1358 innobase_flush_logs(
1359 /*================*/
1360 handlerton* hton); /*!< in: InnoDB handlerton */
1361
1362 /************************************************************************//**
1363 Implements the SHOW ENGINE INNODB STATUS command. Sends the output of the
1364 InnoDB Monitor to the client.
1365 @return 0 on success */
1366 static
1367 int
1368 innodb_show_status(
1369 /*===============*/
1370 handlerton* hton, /*!< in: the innodb handlerton */
1371 THD* thd, /*!< in: the MySQL query thread of
1372 the caller */
1373 stat_print_fn* stat_print);
1374 /************************************************************************//**
1375 Return 0 on success and non-zero on failure. Note: the bool return type
1376 seems to be abused here, should be an int. */
1377 static
1378 bool
1379 innobase_show_status(
1380 /*=================*/
1381 handlerton* hton, /*!< in: the innodb handlerton */
1382 THD* thd, /*!< in: the MySQL query thread of
1383 the caller */
1384 stat_print_fn* stat_print,
1385 enum ha_stat_type stat_type);
1386
1387 /*****************************************************************//**
1388 Commits a transaction in an InnoDB database. */
1389 static
1390 void
1391 innobase_commit_low(
1392 /*================*/
1393 trx_t* trx); /*!< in: transaction handle */
1394
1395 /****************************************************************//**
1396 Parse and enable InnoDB monitor counters during server startup.
1397 User can enable monitor counters/groups by specifying
1398 "loose-innodb_monitor_enable = monitor_name1;monitor_name2..."
1399 in server configuration file or at the command line. */
1400 static
1401 void
1402 innodb_enable_monitor_at_startup(
1403 /*=============================*/
1404 char* str); /*!< in: monitor counter enable list */
1405
1406 /*********************************************************************
1407 Normalizes a table name string. A normalized name consists of the
1408 database name catenated to '/' and table name. An example:
1409 test/mytable. On Windows normalization puts both the database name and the
1410 table name always to lower case if "set_lower_case" is set to TRUE. */
1411 static
1412 void
1413 normalize_table_name_low(
1414 /*=====================*/
1415 char* norm_name, /* out: normalized name as a
1416 null-terminated string */
1417 const char* name, /* in: table name string */
1418 ibool set_lower_case); /* in: TRUE if we want to set
1419 name to lower case */
1420
1421 /*****************************************************************//**
1422 Checks if the filename name is reserved in InnoDB.
1423 @return true if the name is reserved */
1424 static
1425 bool
1426 innobase_check_reserved_file_name(
1427 /*===================*/
1428 handlerton* hton, /*!< in: handlerton of Innodb */
1429 const char* name); /*!< in: Name of the database */
1430
1431
1432 /** Creates a new compression dictionary. */
1433 static
1434 handler_create_zip_dict_result
1435 innobase_create_zip_dict(
1436 handlerton* hton, /*!< in: innobase handlerton */
1437 THD* thd, /*!< in: handle to the MySQL thread */
1438 const char* name, /*!< in: zip dictionary name */
1439 ulint* name_len,
1440 /*!< in/out: zip dictionary name length */
1441 const char* data, /*!< in: zip dictionary data */
1442 ulint* data_len);
1443 /*!< in/out: zip dictionary data length */
1444
1445 /** Drops a existing compression dictionary. */
1446 static
1447 handler_drop_zip_dict_result
1448 innobase_drop_zip_dict(
1449 handlerton* hton, /*!< in: innobase handlerton */
1450 THD* thd, /*!< in: handle to the MySQL thread */
1451 const char* name, /*!< in: zip dictionary name */
1452 ulint* name_len);
1453 /*!< in/out: zip dictionary name length */
1454
1455 /*************************************************************//**
1456 Removes old archived transaction log files.
1457 @return true on error */
innobase_purge_archive_logs(handlerton * hton,time_t before_date,const char * to_filename)1458 static bool innobase_purge_archive_logs(
1459 handlerton *hton, /*!< in: InnoDB handlerton */
1460 time_t before_date, /*!< in: all files modified
1461 before timestamp should be removed */
1462 const char* to_filename) /*!< in: this and earler files
1463 should be removed */
1464 {
1465 ulint err= DB_ERROR;
1466 if (before_date > 0) {
1467 err= purge_archived_logs(before_date, 0);
1468 } else if (to_filename) {
1469 if (is_prefix(to_filename, IB_ARCHIVED_LOGS_PREFIX)) {
1470 unsigned long long log_file_lsn = strtoll(to_filename
1471 + IB_ARCHIVED_LOGS_PREFIX_LEN,
1472 NULL, 10);
1473 if (log_file_lsn > 0 && log_file_lsn < ULLONG_MAX) {
1474 err= purge_archived_logs(0, log_file_lsn);
1475 }
1476 }
1477 }
1478 return (err != DB_SUCCESS);
1479 }
1480
1481 /** Sync innodb_kill_idle_transaction and kill_idle_transaction values.
1482
1483 @param[in,out] thd thread handle
1484 @param[in] var pointer to system variable
1485 @param[out] var_ptr where the formal string goes
1486 @param[in] save immediate result from check function */
innodb_kill_idle_transaction_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)1487 static void innodb_kill_idle_transaction_update(
1488 THD* thd,
1489 struct st_mysql_sys_var* var,
1490 void* var_ptr,
1491 const void* save)
1492 {
1493 ulong in_val = *static_cast<const long*>(save);
1494 kill_idle_transaction_timeout= in_val;
1495 srv_kill_idle_transaction= in_val;
1496 }
1497
1498 /*************************************************************//**
1499 Check for a valid value of innobase_commit_concurrency.
1500 @return 0 for valid innodb_commit_concurrency */
1501 static
1502 int
innobase_commit_concurrency_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)1503 innobase_commit_concurrency_validate(
1504 /*=================================*/
1505 THD* thd, /*!< in: thread handle */
1506 struct st_mysql_sys_var* var, /*!< in: pointer to system
1507 variable */
1508 void* save, /*!< out: immediate result
1509 for update function */
1510 struct st_mysql_value* value) /*!< in: incoming string */
1511 {
1512 long long intbuf;
1513 ulong commit_concurrency;
1514
1515 DBUG_ENTER("innobase_commit_concurrency_validate");
1516
1517 if (value->val_int(value, &intbuf)) {
1518 /* The value is NULL. That is invalid. */
1519 DBUG_RETURN(1);
1520 }
1521
1522 *reinterpret_cast<ulong*>(save) = commit_concurrency
1523 = static_cast<ulong>(intbuf);
1524
1525 /* Allow the value to be updated, as long as it remains zero
1526 or nonzero. */
1527 DBUG_RETURN(!(!commit_concurrency == !innobase_commit_concurrency));
1528 }
1529
1530 /*******************************************************************//**
1531 Function for constructing an InnoDB table handler instance. */
1532 static
1533 handler*
innobase_create_handler(handlerton * hton,TABLE_SHARE * table,MEM_ROOT * mem_root)1534 innobase_create_handler(
1535 /*====================*/
1536 handlerton* hton, /*!< in: InnoDB handlerton */
1537 TABLE_SHARE* table,
1538 MEM_ROOT* mem_root)
1539 {
1540 return(new (mem_root) ha_innobase(hton, table));
1541 }
1542
1543 /* General functions */
1544
1545 /*************************************************************//**
1546 Check that a page_size is correct for InnoDB. If correct, set the
1547 associated page_size_shift which is the power of 2 for this page size.
1548 @return an associated page_size_shift if valid, 0 if invalid. */
1549 inline
1550 int
innodb_page_size_validate(ulong page_size)1551 innodb_page_size_validate(
1552 /*======================*/
1553 ulong page_size) /*!< in: Page Size to evaluate */
1554 {
1555 ulong n;
1556
1557 DBUG_ENTER("innodb_page_size_validate");
1558
1559 for (n = UNIV_PAGE_SIZE_SHIFT_MIN;
1560 n <= UNIV_PAGE_SIZE_SHIFT_MAX;
1561 n++) {
1562 if (page_size == (ulong) (1 << n)) {
1563 DBUG_RETURN(n);
1564 }
1565 }
1566
1567 DBUG_RETURN(0);
1568 }
1569
1570 /******************************************************************//**
1571 Returns true if the thread is the replication thread on the slave
1572 server. Used in srv_conc_enter_innodb() to determine if the thread
1573 should be allowed to enter InnoDB - the replication thread is treated
1574 differently than other threads. Also used in
1575 srv_conc_force_exit_innodb().
1576 @return true if thd is the replication thread */
1577 UNIV_INTERN
1578 ibool
thd_is_replication_slave_thread(THD * thd)1579 thd_is_replication_slave_thread(
1580 /*============================*/
1581 THD* thd) /*!< in: thread handle */
1582 {
1583 return((ibool) thd_slave_thread(thd));
1584 }
1585
1586 /******************************************************************//**
1587 Gets information on the durability property requested by thread.
1588 Used when writing either a prepare or commit record to the log
1589 buffer. @return the durability property. */
1590 UNIV_INTERN
1591 enum durability_properties
thd_requested_durability(const THD * thd)1592 thd_requested_durability(
1593 /*=====================*/
1594 const THD* thd) /*!< in: thread handle */
1595 {
1596 return(thd_get_durability_property(thd));
1597 }
1598
1599 /******************************************************************//**
1600 Returns true if transaction should be flagged as read-only.
1601 @return true if the thd is marked as read-only */
1602 UNIV_INTERN
1603 ibool
thd_trx_is_read_only(THD * thd)1604 thd_trx_is_read_only(
1605 /*=================*/
1606 THD* thd) /*!< in: thread handle */
1607 {
1608 return(thd != 0 && thd_tx_is_read_only(thd));
1609 }
1610
1611 /******************************************************************//**
1612 Check if the transaction is an auto-commit transaction. TRUE also
1613 implies that it is a SELECT (read-only) transaction.
1614 @return true if the transaction is an auto commit read-only transaction. */
1615 UNIV_INTERN
1616 ibool
thd_trx_is_auto_commit(THD * thd)1617 thd_trx_is_auto_commit(
1618 /*===================*/
1619 THD* thd) /*!< in: thread handle, can be NULL */
1620 {
1621 return(thd != NULL
1622 && !thd_test_options(
1623 thd,
1624 OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)
1625 && thd_is_select(thd));
1626 }
1627
1628 /******************************************************************//**
1629 Save some CPU by testing the value of srv_thread_concurrency in inline
1630 functions. */
1631 static inline
1632 void
innobase_srv_conc_enter_innodb(trx_t * trx)1633 innobase_srv_conc_enter_innodb(
1634 /*===========================*/
1635 trx_t* trx) /*!< in: transaction handle */
1636 {
1637 if (srv_thread_concurrency) {
1638 if (trx->n_tickets_to_enter_innodb > 0) {
1639
1640 /* If trx has 'free tickets' to enter the engine left,
1641 then use one such ticket */
1642
1643 --trx->n_tickets_to_enter_innodb;
1644
1645 } else if (trx->mysql_thd != NULL
1646 && thd_is_replication_slave_thread(trx->mysql_thd)) {
1647
1648 UT_WAIT_FOR(
1649 srv_conc_get_active_threads()
1650 < srv_thread_concurrency,
1651 srv_replication_delay * 1000);
1652
1653 } else {
1654 srv_conc_enter_innodb(trx);
1655 }
1656 }
1657 }
1658
1659 /******************************************************************//**
1660 Note that the thread wants to leave InnoDB only if it doesn't have
1661 any spare tickets. */
1662 static inline
1663 void
innobase_srv_conc_exit_innodb(trx_t * trx)1664 innobase_srv_conc_exit_innodb(
1665 /*==========================*/
1666 trx_t* trx) /*!< in: transaction handle */
1667 {
1668 #ifdef UNIV_SYNC_DEBUG
1669 ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
1670 #endif /* UNIV_SYNC_DEBUG */
1671
1672 /* This is to avoid making an unnecessary function call. */
1673 if (trx->declared_to_be_inside_innodb
1674 && trx->n_tickets_to_enter_innodb == 0) {
1675
1676 srv_conc_force_exit_innodb(trx);
1677 }
1678 }
1679
1680 /******************************************************************//**
1681 Force a thread to leave InnoDB even if it has spare tickets. */
1682 static inline
1683 void
innobase_srv_conc_force_exit_innodb(trx_t * trx)1684 innobase_srv_conc_force_exit_innodb(
1685 /*================================*/
1686 trx_t* trx) /*!< in: transaction handle */
1687 {
1688 #ifdef UNIV_SYNC_DEBUG
1689 ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
1690 #endif /* UNIV_SYNC_DEBUG */
1691
1692 /* This is to avoid making an unnecessary function call. */
1693 if (trx->declared_to_be_inside_innodb) {
1694 srv_conc_force_exit_innodb(trx);
1695 }
1696 }
1697
1698 /******************************************************************//**
1699 Returns the NUL terminated value of glob_hostname.
1700 @return pointer to glob_hostname. */
1701 UNIV_INTERN
1702 const char*
server_get_hostname()1703 server_get_hostname()
1704 /*=================*/
1705 {
1706 return(glob_hostname);
1707 }
1708
1709 /******************************************************************//**
1710 Returns true if the transaction this thread is processing has edited
1711 non-transactional tables. Used by the deadlock detector when deciding
1712 which transaction to rollback in case of a deadlock - we try to avoid
1713 rolling back transactions that have edited non-transactional tables.
1714 @return true if non-transactional tables have been edited */
1715 UNIV_INTERN
1716 ibool
thd_has_edited_nontrans_tables(THD * thd)1717 thd_has_edited_nontrans_tables(
1718 /*===========================*/
1719 THD* thd) /*!< in: thread handle */
1720 {
1721 return((ibool) thd_non_transactional_update(thd));
1722 }
1723
1724 /******************************************************************//**
1725 Returns true if the thread is executing a SELECT statement.
1726 @return true if thd is executing SELECT */
1727 UNIV_INTERN
1728 ibool
thd_is_select(const THD * thd)1729 thd_is_select(
1730 /*==========*/
1731 const THD* thd) /*!< in: thread handle */
1732 {
1733 return(thd_sql_command(thd) == SQLCOM_SELECT);
1734 }
1735
1736 /******************************************************************//**
1737 Returns true if the thread supports XA,
1738 global value of innodb_supports_xa if thd is NULL.
1739 @return true if thd has XA support */
1740 UNIV_INTERN
1741 ibool
thd_supports_xa(THD * thd)1742 thd_supports_xa(
1743 /*============*/
1744 THD* thd) /*!< in: thread handle, or NULL to query
1745 the global innodb_supports_xa */
1746 {
1747 return(THDVAR(thd, support_xa));
1748 }
1749
1750 /** Get the value of innodb_tmpdir.
1751 @param[in] thd thread handle, or NULL to query
1752 the global innodb_tmpdir.
1753 @retval NULL if innodb_tmpdir="" */
1754 UNIV_INTERN
1755 const char*
thd_innodb_tmpdir(THD * thd)1756 thd_innodb_tmpdir(
1757 THD* thd)
1758 {
1759 #ifdef UNIV_SYNC_DEBUG
1760 ut_ad(!sync_thread_levels_nonempty_trx(false));
1761 #endif /* UNIV_SYNC_DEBUG */
1762
1763 const char* tmp_dir = THDVAR(thd, tmpdir);
1764 if (tmp_dir != NULL && *tmp_dir == '\0') {
1765 tmp_dir = NULL;
1766 }
1767
1768 return(tmp_dir);
1769 }
1770 /******************************************************************//**
1771 Check the status of fake changes mode (innodb_fake_changes)
1772 @return true if fake change mode is enabled. */
1773 UNIV_INTERN
1774 ibool
thd_fake_changes(THD * thd)1775 thd_fake_changes(
1776 /*=============*/
1777 THD* thd) /*!< in: thread handle, or NULL to query
1778 the global innodb_supports_xa */
1779 {
1780 return(THDVAR((THD*) thd, fake_changes));
1781 }
1782
1783 /******************************************************************//**
1784 Returns the lock wait timeout for the current connection.
1785 @return the lock wait timeout, in seconds */
1786 UNIV_INTERN
1787 ulong
thd_lock_wait_timeout(THD * thd)1788 thd_lock_wait_timeout(
1789 /*==================*/
1790 THD* thd) /*!< in: thread handle, or NULL to query
1791 the global innodb_lock_wait_timeout */
1792 {
1793 /* According to <mysql/plugin.h>, passing thd == NULL
1794 returns the global value of the session variable. */
1795 return(THDVAR(thd, lock_wait_timeout));
1796 }
1797
1798 /******************************************************************//**
1799 Set the time waited for the lock for the current query. */
1800 UNIV_INTERN
1801 void
thd_set_lock_wait_time(THD * thd,ulint value)1802 thd_set_lock_wait_time(
1803 /*===================*/
1804 THD* thd, /*!< in/out: thread handle */
1805 ulint value) /*!< in: time waited for the lock */
1806 {
1807 if (thd) {
1808 thd_storage_lock_wait(thd, value);
1809 }
1810 }
1811
1812 /******************************************************************//**
1813 */
1814 UNIV_INTERN
1815 ulong
thd_flush_log_at_trx_commit(THD * thd)1816 thd_flush_log_at_trx_commit(
1817 /*================================*/
1818 THD* thd)
1819 {
1820 return(THDVAR(thd, flush_log_at_trx_commit));
1821 }
1822
1823 /******************************************************************//**
1824 Returns true if expand_fast_index_creation is enabled for the current
1825 session.
1826 @return the value of the server's expand_fast_index_creation variable */
1827 UNIV_INTERN
1828 ibool
thd_expand_fast_index_creation(void * thd)1829 thd_expand_fast_index_creation(
1830 /*================================*/
1831 void* thd)
1832 {
1833 return((ibool) (((THD*) thd)->variables.expand_fast_index_creation));
1834 }
1835
1836 /********************************************************************//**
1837 Obtain the InnoDB transaction of a MySQL thread.
1838 @return reference to transaction pointer */
1839 MY_ATTRIBUTE((warn_unused_result, nonnull))
1840 static inline
1841 trx_t*&
thd_to_trx(THD * thd)1842 thd_to_trx(
1843 /*=======*/
1844 THD* thd) /*!< in: MySQL thread */
1845 {
1846 return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr));
1847 }
1848
1849 my_bool
is_fake_change_enabled(THD * thd)1850 ha_innobase::is_fake_change_enabled(THD* thd)
1851 {
1852 trx_t* trx = thd_to_trx(thd);
1853 return(trx && UNIV_UNLIKELY(trx->fake_changes));
1854 }
1855
1856 /********************************************************************//**
1857 In XtraDB it is impossible for a transaction to own a search latch outside of
1858 InnoDB code, so there is nothing to release on demand. We keep this function to
1859 simplify maintenance.
1860 @return 0 */
1861 static
1862 int
innobase_release_temporary_latches(handlerton * hton MY_ATTRIBUTE ((unused)),THD * thd MY_ATTRIBUTE ((unused)))1863 innobase_release_temporary_latches(
1864 /*===============================*/
1865 handlerton* hton MY_ATTRIBUTE((unused)), /*!< in: handlerton */
1866 THD* thd MY_ATTRIBUTE((unused))) /*!< in: MySQL thread */
1867 {
1868 #ifdef UNIV_DEBUG
1869 DBUG_ASSERT(hton == innodb_hton_ptr);
1870
1871 if (!innodb_inited || thd == NULL) {
1872
1873 return(0);
1874 }
1875
1876 trx_t* trx = thd_to_trx(thd);
1877
1878 if (trx != NULL) {
1879 #ifdef UNIV_SYNC_DEBUG
1880 ut_ad(!btr_search_own_any());
1881 #endif
1882 trx_search_latch_release_if_reserved(trx);
1883 }
1884 #endif
1885
1886 return(0);
1887 }
1888
1889 /********************************************************************//**
1890 Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
1891 time calls srv_active_wake_master_thread. This function should be used
1892 when a single database operation may introduce a small need for
1893 server utility activity, like checkpointing. */
1894 static inline
1895 void
innobase_active_small(void)1896 innobase_active_small(void)
1897 /*=======================*/
1898 {
1899 innobase_active_counter++;
1900
1901 if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
1902 srv_active_wake_master_thread();
1903 }
1904 }
1905
1906 /********************************************************************//**
1907 Converts an InnoDB error code to a MySQL error code and also tells to MySQL
1908 about a possible transaction rollback inside InnoDB caused by a lock wait
1909 timeout or a deadlock.
1910 @return MySQL error code */
1911 static
1912 int
convert_error_code_to_mysql(dberr_t error,ulint flags,THD * thd)1913 convert_error_code_to_mysql(
1914 /*========================*/
1915 dberr_t error, /*!< in: InnoDB error code */
1916 ulint flags, /*!< in: InnoDB table flags, or 0 */
1917 THD* thd) /*!< in: user thread handle or NULL */
1918 {
1919 switch (error) {
1920 case DB_SUCCESS:
1921 return(0);
1922
1923 case DB_INTERRUPTED:
1924 thd_set_kill_status(thd ? thd : thd_get_current_thd());
1925 return(-1);
1926
1927 case DB_FOREIGN_EXCEED_MAX_CASCADE:
1928 ut_ad(thd);
1929 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1930 HA_ERR_ROW_IS_REFERENCED,
1931 "InnoDB: Cannot delete/update "
1932 "rows with cascading foreign key "
1933 "constraints that exceed max "
1934 "depth of %d. Please "
1935 "drop extra constraints and try "
1936 "again", DICT_FK_MAX_RECURSIVE_LOAD);
1937
1938 /* fall through */
1939
1940 case DB_ERROR:
1941 default:
1942 return(-1); /* unspecified error */
1943
1944 case DB_DUPLICATE_KEY:
1945 /* Be cautious with returning this error, since
1946 mysql could re-enter the storage layer to get
1947 duplicated key info, the operation requires a
1948 valid table handle and/or transaction information,
1949 which might not always be available in the error
1950 handling stage. */
1951 return(HA_ERR_FOUND_DUPP_KEY);
1952
1953 case DB_READ_ONLY:
1954 if(srv_force_recovery) {
1955 return(HA_ERR_INNODB_FORCED_RECOVERY);
1956 }
1957 return(HA_ERR_TABLE_READONLY);
1958
1959 case DB_FOREIGN_DUPLICATE_KEY:
1960 return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1961
1962 case DB_MISSING_HISTORY:
1963 return(HA_ERR_TABLE_DEF_CHANGED);
1964
1965 case DB_RECORD_NOT_FOUND:
1966 return(HA_ERR_NO_ACTIVE_RECORD);
1967
1968 case DB_DEADLOCK:
1969 /* Since we rolled back the whole transaction, we must
1970 tell it also to MySQL so that MySQL knows to empty the
1971 cached binlog for this transaction */
1972
1973 if (thd) {
1974 thd_mark_transaction_to_rollback(thd, TRUE);
1975 }
1976
1977 return(HA_ERR_LOCK_DEADLOCK);
1978
1979 case DB_LOCK_WAIT_TIMEOUT:
1980 /* Starting from 5.0.13, we let MySQL just roll back the
1981 latest SQL statement in a lock wait timeout. Previously, we
1982 rolled back the whole transaction. */
1983
1984 if (thd) {
1985 thd_mark_transaction_to_rollback(
1986 thd, (bool) row_rollback_on_timeout);
1987 }
1988
1989 return(HA_ERR_LOCK_WAIT_TIMEOUT);
1990
1991 case DB_NO_REFERENCED_ROW:
1992 return(HA_ERR_NO_REFERENCED_ROW);
1993
1994 case DB_ROW_IS_REFERENCED:
1995 return(HA_ERR_ROW_IS_REFERENCED);
1996
1997 case DB_CANNOT_ADD_CONSTRAINT:
1998 case DB_CHILD_NO_INDEX:
1999 case DB_PARENT_NO_INDEX:
2000 return(HA_ERR_CANNOT_ADD_FOREIGN);
2001
2002 case DB_CANNOT_DROP_CONSTRAINT:
2003
2004 return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
2005 misleading, a new MySQL error
2006 code should be introduced */
2007
2008 case DB_CORRUPTION:
2009 return(HA_ERR_CRASHED);
2010
2011 case DB_OUT_OF_FILE_SPACE:
2012 return(HA_ERR_RECORD_FILE_FULL);
2013
2014 case DB_TEMP_FILE_WRITE_FAILURE:
2015 return(HA_ERR_TEMP_FILE_WRITE_FAILURE);
2016
2017 case DB_TABLE_IN_FK_CHECK:
2018 return(HA_ERR_TABLE_IN_FK_CHECK);
2019
2020 case DB_TABLE_IS_BEING_USED:
2021 return(HA_ERR_WRONG_COMMAND);
2022
2023 case DB_TABLESPACE_DELETED:
2024 case DB_TABLE_NOT_FOUND:
2025 return(HA_ERR_NO_SUCH_TABLE);
2026
2027 case DB_TABLESPACE_NOT_FOUND:
2028 return(HA_ERR_NO_SUCH_TABLE);
2029
2030 case DB_TOO_BIG_RECORD: {
2031 /* If prefix is true then a 768-byte prefix is stored
2032 locally for BLOB fields. Refer to dict_table_get_format() */
2033 bool prefix = (dict_tf_get_format(flags) == UNIV_FORMAT_A);
2034 my_printf_error(ER_TOO_BIG_ROWSIZE,
2035 "Row size too large (> %lu). Changing some columns "
2036 "to TEXT or BLOB %smay help. In current row "
2037 "format, BLOB prefix of %d bytes is stored inline.",
2038 MYF(0),
2039 page_get_free_space_of_empty(flags &
2040 DICT_TF_COMPACT) / 2,
2041 prefix ? "or using ROW_FORMAT=DYNAMIC "
2042 "or ROW_FORMAT=COMPRESSED ": "",
2043 prefix ? DICT_MAX_FIXED_COL_LEN : 0);
2044 return(HA_ERR_TO_BIG_ROW);
2045 }
2046
2047
2048 case DB_TOO_BIG_FOR_REDO:
2049 my_printf_error(ER_TOO_BIG_ROWSIZE, "%s" , MYF(0),
2050 "The size of BLOB/TEXT data inserted"
2051 " in one transaction is greater than"
2052 " 10% of redo log size. Increase the"
2053 " redo log size using innodb_log_file_size.");
2054 return(HA_ERR_TO_BIG_ROW);
2055
2056 case DB_TOO_BIG_INDEX_COL:
2057 my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0),
2058 DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags));
2059 return(HA_ERR_INDEX_COL_TOO_LONG);
2060
2061 case DB_NO_SAVEPOINT:
2062 return(HA_ERR_NO_SAVEPOINT);
2063
2064 case DB_LOCK_TABLE_FULL:
2065 /* Since we rolled back the whole transaction, we must
2066 tell it also to MySQL so that MySQL knows to empty the
2067 cached binlog for this transaction */
2068
2069 if (thd) {
2070 thd_mark_transaction_to_rollback(thd, TRUE);
2071 }
2072
2073 return(HA_ERR_LOCK_TABLE_FULL);
2074
2075 case DB_FTS_INVALID_DOCID:
2076 return(HA_FTS_INVALID_DOCID);
2077 case DB_FTS_EXCEED_RESULT_CACHE_LIMIT:
2078 return(HA_ERR_FTS_EXCEED_RESULT_CACHE_LIMIT);
2079 case DB_TOO_MANY_CONCURRENT_TRXS:
2080 return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
2081 case DB_UNSUPPORTED:
2082 return(HA_ERR_UNSUPPORTED);
2083 case DB_INDEX_CORRUPT:
2084 return(HA_ERR_INDEX_CORRUPT);
2085 case DB_UNDO_RECORD_TOO_BIG:
2086 return(HA_ERR_UNDO_REC_TOO_BIG);
2087 case DB_OUT_OF_MEMORY:
2088 return(HA_ERR_OUT_OF_MEM);
2089 case DB_TABLESPACE_EXISTS:
2090 return(HA_ERR_TABLESPACE_EXISTS);
2091 case DB_IDENTIFIER_TOO_LONG:
2092 return(HA_ERR_INTERNAL_ERROR);
2093 case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
2094 return(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE);
2095 case DB_FTS_TOO_MANY_NESTED_EXP:
2096 return(HA_ERR_FTS_TOO_MANY_NESTED_EXP);
2097 }
2098 }
2099
2100 /*************************************************************//**
2101 Prints info of a THD object (== user session thread) to the given file. */
2102 UNIV_INTERN
2103 void
innobase_mysql_print_thd(FILE * f,THD * thd,uint max_query_len)2104 innobase_mysql_print_thd(
2105 /*=====================*/
2106 FILE* f, /*!< in: output stream */
2107 THD* thd, /*!< in: MySQL THD object */
2108 uint max_query_len) /*!< in: max query length to print, or 0 to
2109 use the default max length */
2110 {
2111 char buffer[1024];
2112
2113 fputs(thd_security_context(thd, buffer, sizeof buffer,
2114 max_query_len), f);
2115 putc('\n', f);
2116 }
2117
2118 /******************************************************************//**
2119 Get the error message format string.
2120 @return the format string or 0 if not found. */
2121 UNIV_INTERN
2122 const char*
innobase_get_err_msg(int error_code)2123 innobase_get_err_msg(
2124 /*=================*/
2125 int error_code) /*!< in: MySQL error code */
2126 {
2127 return(my_get_err_msg(error_code));
2128 }
2129
2130 /******************************************************************//**
2131 Get the variable length bounds of the given character set. */
2132 UNIV_INTERN
2133 void
innobase_get_cset_width(ulint cset,ulint * mbminlen,ulint * mbmaxlen)2134 innobase_get_cset_width(
2135 /*====================*/
2136 ulint cset, /*!< in: MySQL charset-collation code */
2137 ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
2138 ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
2139 {
2140 CHARSET_INFO* cs;
2141 ut_ad(cset <= MAX_CHAR_COLL_NUM);
2142 ut_ad(mbminlen);
2143 ut_ad(mbmaxlen);
2144
2145 cs = all_charsets[cset];
2146 if (cs) {
2147 *mbminlen = cs->mbminlen;
2148 *mbmaxlen = cs->mbmaxlen;
2149 ut_ad(*mbminlen < DATA_MBMAX);
2150 ut_ad(*mbmaxlen < DATA_MBMAX);
2151 } else {
2152 THD* thd = current_thd;
2153
2154 if (thd && thd_sql_command(thd) == SQLCOM_DROP_TABLE) {
2155
2156 /* Fix bug#46256: allow tables to be dropped if the
2157 collation is not found, but issue a warning. */
2158 if ((log_warnings)
2159 && (cset != 0)){
2160
2161 sql_print_warning(
2162 "Unknown collation #%lu.", cset);
2163 }
2164 } else {
2165
2166 ut_a(cset == 0);
2167 }
2168
2169 *mbminlen = *mbmaxlen = 0;
2170 }
2171 }
2172
2173 /******************************************************************//**
2174 Converts an identifier to a table name. */
2175 UNIV_INTERN
2176 void
innobase_convert_from_table_id(struct charset_info_st * cs,char * to,const char * from,ulint len)2177 innobase_convert_from_table_id(
2178 /*===========================*/
2179 struct charset_info_st* cs, /*!< in: the 'from' character set */
2180 char* to, /*!< out: converted identifier */
2181 const char* from, /*!< in: identifier to convert */
2182 ulint len) /*!< in: length of 'to', in bytes */
2183 {
2184 uint errors;
2185
2186 strconvert(cs, from, &my_charset_filename, to, (uint) len, &errors);
2187 }
2188
2189 /**********************************************************************
2190 Check if the length of the identifier exceeds the maximum allowed.
2191 return true when length of identifier is too long. */
2192 UNIV_INTERN
2193 my_bool
innobase_check_identifier_length(const char * id)2194 innobase_check_identifier_length(
2195 /*=============================*/
2196 const char* id) /* in: FK identifier to check excluding the
2197 database portion. */
2198 {
2199 int well_formed_error = 0;
2200 CHARSET_INFO *cs = system_charset_info;
2201 DBUG_ENTER("innobase_check_identifier_length");
2202
2203 size_t len = cs->cset->well_formed_len(
2204 cs, id, id + strlen(id),
2205 NAME_CHAR_LEN, &well_formed_error);
2206
2207 if (well_formed_error || len == NAME_CHAR_LEN) {
2208 my_error(ER_TOO_LONG_IDENT, MYF(0), id);
2209 DBUG_RETURN(true);
2210 }
2211 DBUG_RETURN(false);
2212 }
2213
2214 /******************************************************************//**
2215 Converts an identifier to UTF-8. */
2216 UNIV_INTERN
2217 void
innobase_convert_from_id(struct charset_info_st * cs,char * to,const char * from,ulint len)2218 innobase_convert_from_id(
2219 /*=====================*/
2220 struct charset_info_st* cs, /*!< in: the 'from' character set */
2221 char* to, /*!< out: converted identifier */
2222 const char* from, /*!< in: identifier to convert */
2223 ulint len) /*!< in: length of 'to', in bytes */
2224 {
2225 uint errors;
2226
2227 strconvert(cs, from, system_charset_info, to, (uint) len, &errors);
2228 }
2229
2230 /******************************************************************//**
2231 Compares NUL-terminated UTF-8 strings case insensitively.
2232 @return 0 if a=b, <0 if a<b, >1 if a>b */
2233 UNIV_INTERN
2234 int
innobase_strcasecmp(const char * a,const char * b)2235 innobase_strcasecmp(
2236 /*================*/
2237 const char* a, /*!< in: first string to compare */
2238 const char* b) /*!< in: second string to compare */
2239 {
2240 if (!a) {
2241 if (!b) {
2242 return(0);
2243 } else {
2244 return(-1);
2245 }
2246 } else if (!b) {
2247 return(1);
2248 }
2249
2250 return(my_strcasecmp(system_charset_info, a, b));
2251 }
2252
2253 /******************************************************************//**
2254 Compares NUL-terminated UTF-8 strings case insensitively. The
2255 second string contains wildcards.
2256 @return 0 if a match is found, 1 if not */
2257 UNIV_INTERN
2258 int
innobase_wildcasecmp(const char * a,const char * b)2259 innobase_wildcasecmp(
2260 /*=================*/
2261 const char* a, /*!< in: string to compare */
2262 const char* b) /*!< in: wildcard string to compare */
2263 {
2264 return(wild_case_compare(system_charset_info, a, b));
2265 }
2266
2267 /******************************************************************//**
2268 Strip dir name from a full path name and return only the file name
2269 @return file name or "null" if no file name */
2270 UNIV_INTERN
2271 const char*
innobase_basename(const char * path_name)2272 innobase_basename(
2273 /*==============*/
2274 const char* path_name) /*!< in: full path name */
2275 {
2276 const char* name = base_name(path_name);
2277
2278 return((name) ? name : "null");
2279 }
2280
2281 /******************************************************************//**
2282 Makes all characters in a NUL-terminated UTF-8 string lower case. */
2283 UNIV_INTERN
2284 void
innobase_casedn_str(char * a)2285 innobase_casedn_str(
2286 /*================*/
2287 char* a) /*!< in/out: string to put in lower case */
2288 {
2289 my_casedn_str(system_charset_info, a);
2290 }
2291
2292 /**********************************************************************//**
2293 Determines the connection character set.
2294 @return connection character set */
2295 UNIV_INTERN
2296 struct charset_info_st*
innobase_get_charset(THD * mysql_thd)2297 innobase_get_charset(
2298 /*=================*/
2299 THD* mysql_thd) /*!< in: MySQL thread handle */
2300 {
2301 return(thd_charset(mysql_thd));
2302 }
2303
2304 /**********************************************************************//**
2305 Determines the current SQL statement.
2306 @return SQL statement string */
2307 UNIV_INTERN
2308 const char*
innobase_get_stmt(THD * thd,size_t * length)2309 innobase_get_stmt(
2310 /*==============*/
2311 THD* thd, /*!< in: MySQL thread handle */
2312 size_t* length) /*!< out: length of the SQL statement */
2313 {
2314 LEX_STRING* stmt;
2315
2316 stmt = thd_query_string(thd);
2317 *length = stmt->length;
2318 return(stmt->str);
2319 }
2320
2321 /**********************************************************************//**
2322 Get the current setting of the table_def_size global parameter. We do
2323 a dirty read because for one there is no synchronization object and
2324 secondly there is little harm in doing so even if we get a torn read.
2325 @return value of table_def_size */
2326 UNIV_INTERN
2327 ulint
innobase_get_table_cache_size(void)2328 innobase_get_table_cache_size(void)
2329 /*===============================*/
2330 {
2331 return(table_def_size);
2332 }
2333
2334 /**********************************************************************//**
2335 Get the current setting of the lower_case_table_names global parameter from
2336 mysqld.cc. We do a dirty read because for one there is no synchronization
2337 object and secondly there is little harm in doing so even if we get a torn
2338 read.
2339 @return value of lower_case_table_names */
2340 UNIV_INTERN
2341 ulint
innobase_get_lower_case_table_names(void)2342 innobase_get_lower_case_table_names(void)
2343 /*=====================================*/
2344 {
2345 return(lower_case_table_names);
2346 }
2347 /** return one of the tmpdir path
2348 @return tmpdir path*/
2349 UNIV_INTERN
2350 char*
innobase_mysql_tmpdir(void)2351 innobase_mysql_tmpdir(void) { return (mysql_tmpdir); }
2352
2353 /** Create a temporary file in the location specified by the parameter
2354 path. If the path is null, then it will be created in tmpdir.
2355 @param[in] path location for creating temporary file
2356 @return temporary file descriptor, or < 0 on error */
2357 UNIV_INTERN
2358 int
innobase_mysql_tmpfile(const char * path)2359 innobase_mysql_tmpfile(
2360 const char* path)
2361 {
2362 int fd2 = -1;
2363 File fd;
2364
2365 DBUG_EXECUTE_IF(
2366 "innobase_tmpfile_creation_failure",
2367 return(-1);
2368 );
2369
2370 if (path == NULL) {
2371 fd = mysql_tmpfile("ib");
2372 } else {
2373 fd = mysql_tmpfile_path(path, "ib");
2374 }
2375
2376 if (fd >= 0) {
2377 /* Copy the file descriptor, so that the additional resources
2378 allocated by create_temp_file() can be freed by invoking
2379 my_close().
2380
2381 Because the file descriptor returned by this function
2382 will be passed to fdopen(), it will be closed by invoking
2383 fclose(), which in turn will invoke close() instead of
2384 my_close(). */
2385
2386 #ifdef _WIN32
2387 /* Note that on Windows, the integer returned by mysql_tmpfile
2388 has no relation to C runtime file descriptor. Here, we need
2389 to call my_get_osfhandle to get the HANDLE and then convert it
2390 to C runtime filedescriptor. */
2391 {
2392 HANDLE hFile = my_get_osfhandle(fd);
2393 HANDLE hDup;
2394 BOOL bOK = DuplicateHandle(
2395 GetCurrentProcess(),
2396 hFile, GetCurrentProcess(),
2397 &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
2398 if (bOK) {
2399 fd2 = _open_osfhandle((intptr_t) hDup, 0);
2400 } else {
2401 my_osmaperr(GetLastError());
2402 fd2 = -1;
2403 }
2404 }
2405 #else
2406 fd2 = dup(fd);
2407 #endif
2408 if (fd2 < 0) {
2409 char errbuf[MYSYS_STRERROR_SIZE];
2410 DBUG_PRINT("error",("Got error %d on dup",fd2));
2411 my_errno=errno;
2412 my_error(EE_OUT_OF_FILERESOURCES,
2413 MYF(ME_BELL+ME_WAITTANG),
2414 "ib*", my_errno,
2415 my_strerror(errbuf, sizeof(errbuf), my_errno));
2416 }
2417 my_close(fd, MYF(MY_WME));
2418 }
2419 return(fd2);
2420 }
2421
2422 /*********************************************************************//**
2423 Wrapper around MySQL's copy_and_convert function.
2424 @return number of bytes copied to 'to' */
2425 UNIV_INTERN
2426 ulint
innobase_convert_string(void * to,ulint to_length,CHARSET_INFO * to_cs,const void * from,ulint from_length,CHARSET_INFO * from_cs,uint * errors)2427 innobase_convert_string(
2428 /*====================*/
2429 void* to, /*!< out: converted string */
2430 ulint to_length, /*!< in: number of bytes reserved
2431 for the converted string */
2432 CHARSET_INFO* to_cs, /*!< in: character set to convert to */
2433 const void* from, /*!< in: string to convert */
2434 ulint from_length, /*!< in: number of bytes to convert */
2435 CHARSET_INFO* from_cs, /*!< in: character set to convert
2436 from */
2437 uint* errors) /*!< out: number of errors encountered
2438 during the conversion */
2439 {
2440 return(copy_and_convert(
2441 (char*) to, (uint32) to_length, to_cs,
2442 (const char*) from, (uint32) from_length, from_cs,
2443 errors));
2444 }
2445
2446 /*******************************************************************//**
2447 Formats the raw data in "data" (in InnoDB on-disk format) that is of
2448 type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "charset_coll" and writes
2449 the result to "buf". The result is converted to "system_charset_info".
2450 Not more than "buf_size" bytes are written to "buf".
2451 The result is always NUL-terminated (provided buf_size > 0) and the
2452 number of bytes that were written to "buf" is returned (including the
2453 terminating NUL).
2454 @return number of bytes that were written */
2455 UNIV_INTERN
2456 ulint
innobase_raw_format(const char * data,ulint data_len,ulint charset_coll,char * buf,ulint buf_size)2457 innobase_raw_format(
2458 /*================*/
2459 const char* data, /*!< in: raw data */
2460 ulint data_len, /*!< in: raw data length
2461 in bytes */
2462 ulint charset_coll, /*!< in: charset collation */
2463 char* buf, /*!< out: output buffer */
2464 ulint buf_size) /*!< in: output buffer size
2465 in bytes */
2466 {
2467 /* XXX we use a hard limit instead of allocating
2468 but_size bytes from the heap */
2469 CHARSET_INFO* data_cs;
2470 char buf_tmp[8192];
2471 ulint buf_tmp_used;
2472 uint num_errors;
2473
2474 data_cs = all_charsets[charset_coll];
2475
2476 buf_tmp_used = innobase_convert_string(buf_tmp, sizeof(buf_tmp),
2477 system_charset_info,
2478 data, data_len, data_cs,
2479 &num_errors);
2480
2481 return(ut_str_sql_format(buf_tmp, buf_tmp_used, buf, buf_size));
2482 }
2483
2484 /*********************************************************************//**
2485 Compute the next autoinc value.
2486
2487 For MySQL replication the autoincrement values can be partitioned among
2488 the nodes. The offset is the start or origin of the autoincrement value
2489 for a particular node. For n nodes the increment will be n and the offset
2490 will be in the interval [1, n]. The formula tries to allocate the next
2491 value for a particular node.
2492
2493 Note: This function is also called with increment set to the number of
2494 values we want to reserve for multi-value inserts e.g.,
2495
2496 INSERT INTO T VALUES(), (), ();
2497
2498 innobase_next_autoinc() will be called with increment set to 3 where
2499 autoinc_lock_mode != TRADITIONAL because we want to reserve 3 values for
2500 the multi-value INSERT above.
2501 @return the next value */
2502 UNIV_INTERN
2503 ulonglong
innobase_next_autoinc(ulonglong current,ulonglong need,ulonglong step,ulonglong offset,ulonglong max_value)2504 innobase_next_autoinc(
2505 /*==================*/
2506 ulonglong current, /*!< in: Current value */
2507 ulonglong need, /*!< in: count of values needed */
2508 ulonglong step, /*!< in: AUTOINC increment step */
2509 ulonglong offset, /*!< in: AUTOINC offset */
2510 ulonglong max_value) /*!< in: max value for type */
2511 {
2512 ulonglong next_value;
2513 ulonglong block = need * step;
2514
2515 /* Should never be 0. */
2516 ut_a(need > 0);
2517 ut_a(block > 0);
2518 ut_a(max_value > 0);
2519
2520 /* According to MySQL documentation, if the offset is greater than
2521 the step then the offset is ignored. */
2522 if (offset > block) {
2523 offset = 0;
2524 }
2525
2526 /* Check for overflow. Current can be > max_value if the value is
2527 in reality a negative value.The visual studio compilers converts
2528 large double values automatically into unsigned long long datatype
2529 maximum value */
2530
2531 if (block >= max_value
2532 || offset > max_value
2533 || current >= max_value
2534 || max_value - offset <= offset) {
2535
2536 next_value = max_value;
2537 } else {
2538 ut_a(max_value > current);
2539
2540 ulonglong free = max_value - current;
2541
2542 if (free < offset || free - offset <= block) {
2543 next_value = max_value;
2544 } else {
2545 next_value = 0;
2546 }
2547 }
2548
2549 if (next_value == 0) {
2550 ulonglong next;
2551
2552 if (current > offset) {
2553 next = (current - offset) / step;
2554 } else {
2555 next = (offset - current) / step;
2556 }
2557
2558 ut_a(max_value > next);
2559 next_value = next * step;
2560 /* Check for multiplication overflow. */
2561 ut_a(next_value >= next);
2562 ut_a(max_value > next_value);
2563
2564 /* Check for overflow */
2565 if (max_value - next_value >= block) {
2566
2567 next_value += block;
2568
2569 if (max_value - next_value >= offset) {
2570 next_value += offset;
2571 } else {
2572 next_value = max_value;
2573 }
2574 } else {
2575 next_value = max_value;
2576 }
2577 }
2578
2579 ut_a(next_value != 0);
2580 ut_a(next_value <= max_value);
2581
2582 return(next_value);
2583 }
2584
2585 /*********************************************************************//**
2586 Initializes some fields in an InnoDB transaction object. */
2587 static
2588 void
innobase_trx_init(THD * thd,trx_t * trx)2589 innobase_trx_init(
2590 /*==============*/
2591 THD* thd, /*!< in: user thread handle */
2592 trx_t* trx) /*!< in/out: InnoDB transaction handle */
2593 {
2594 DBUG_ENTER("innobase_trx_init");
2595 DBUG_ASSERT(EQ_CURRENT_THD(thd));
2596 DBUG_ASSERT(thd == trx->mysql_thd);
2597
2598 trx->check_foreigns = !thd_test_options(
2599 thd, OPTION_NO_FOREIGN_KEY_CHECKS);
2600
2601 trx->check_unique_secondary = !thd_test_options(
2602 thd, OPTION_RELAXED_UNIQUE_CHECKS);
2603
2604 /* Transaction on start caches the fake_changes state and uses it for
2605 complete transaction lifetime.
2606 There are some APIs that doesn't need an active transaction object
2607 but transaction object are just use as a cache object/data carrier.
2608 Before using transaction object for such APIs refresh the state of
2609 fake_changes. */
2610 if (trx->state == TRX_STATE_NOT_STARTED) {
2611 trx->fake_changes = thd_fake_changes(thd);
2612 }
2613
2614 #ifdef EXTENDED_SLOWLOG
2615 if (thd_log_slow_verbosity(thd) & (1ULL << SLOG_V_INNODB)) {
2616 trx->take_stats = TRUE;
2617 } else {
2618 trx->take_stats = FALSE;
2619 }
2620 #else
2621 trx->take_stats = FALSE;
2622 #endif
2623
2624 DBUG_VOID_RETURN;
2625 }
2626
2627 /*********************************************************************//**
2628 Allocates an InnoDB transaction for a MySQL handler object for DML.
2629 @return InnoDB transaction handle */
2630 UNIV_INTERN
2631 trx_t*
innobase_trx_allocate(THD * thd)2632 innobase_trx_allocate(
2633 /*==================*/
2634 THD* thd) /*!< in: user thread handle */
2635 {
2636 trx_t* trx;
2637
2638 DBUG_ENTER("innobase_trx_allocate");
2639 DBUG_ASSERT(thd != NULL);
2640 DBUG_ASSERT(EQ_CURRENT_THD(thd));
2641
2642 trx = trx_allocate_for_mysql();
2643
2644 trx->mysql_thd = thd;
2645
2646 innobase_trx_init(thd, trx);
2647
2648 DBUG_RETURN(trx);
2649 }
2650
2651 /*********************************************************************//**
2652 Gets the InnoDB transaction handle for a MySQL handler object, creates
2653 an InnoDB transaction struct if the corresponding MySQL thread struct still
2654 lacks one.
2655 @return InnoDB transaction handle */
2656 static inline
2657 trx_t*
check_trx_exists(THD * thd)2658 check_trx_exists(
2659 /*=============*/
2660 THD* thd) /*!< in: user thread handle */
2661 {
2662 trx_t*& trx = thd_to_trx(thd);
2663
2664 ut_ad(EQ_CURRENT_THD(thd));
2665
2666 if (trx == NULL) {
2667 trx = innobase_trx_allocate(thd);
2668 } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
2669 mem_analyze_corruption(trx);
2670 ut_error;
2671 }
2672
2673 innobase_trx_init(thd, trx);
2674
2675 return(trx);
2676 }
2677
2678 /*************************************************************************
2679 Gets current trx. */
2680 trx_t*
innobase_get_trx()2681 innobase_get_trx()
2682 {
2683 THD *thd=current_thd;
2684 if (likely(thd != 0)) {
2685 trx_t*& trx = thd_to_trx(thd);
2686 return(trx);
2687 } else {
2688 return(NULL);
2689 }
2690 }
2691
2692 ibool
innobase_get_slow_log()2693 innobase_get_slow_log()
2694 {
2695 #ifdef EXTENDED_SLOWLOG
2696 return((ibool) thd_opt_slow_log());
2697 #else
2698 return(FALSE);
2699 #endif
2700 }
2701
2702 /*********************************************************************//**
2703 Note that a transaction has been registered with MySQL.
2704 @return true if transaction is registered with MySQL 2PC coordinator */
2705 static inline
2706 bool
trx_is_registered_for_2pc(const trx_t * trx)2707 trx_is_registered_for_2pc(
2708 /*=========================*/
2709 const trx_t* trx) /* in: transaction */
2710 {
2711 return(trx->is_registered == 1);
2712 }
2713
2714 /*********************************************************************//**
2715 Note that a transaction has been registered with MySQL 2PC coordinator. */
2716 static inline
2717 void
trx_register_for_2pc(trx_t * trx)2718 trx_register_for_2pc(
2719 /*==================*/
2720 trx_t* trx) /* in: transaction */
2721 {
2722 trx->is_registered = 1;
2723 ut_ad(trx->owns_prepare_mutex == 0);
2724 }
2725
2726 /*********************************************************************//**
2727 Note that a transaction has been deregistered. */
2728 static inline
2729 void
trx_deregister_from_2pc(trx_t * trx)2730 trx_deregister_from_2pc(
2731 /*====================*/
2732 trx_t* trx) /* in: transaction */
2733 {
2734 trx->is_registered = 0;
2735 trx->owns_prepare_mutex = 0;
2736 }
2737
2738 /*********************************************************************//**
2739 Check if transaction is started.
2740 @reutrn true if transaction is in state started */
2741 static
2742 bool
trx_is_started(trx_t * trx)2743 trx_is_started(
2744 /*===========*/
2745 trx_t* trx) /* in: transaction */
2746 {
2747 return(trx->state != TRX_STATE_NOT_STARTED);
2748 }
2749
2750 /****************************************************************//**
2751 Update log_checksum_algorithm_ptr with a pointer to the function corresponding
2752 to a given checksum algorithm. */
2753 static
2754 void
innodb_log_checksum_func_update(ulint algorithm)2755 innodb_log_checksum_func_update(
2756 /*============================*/
2757 ulint algorithm) /*!< in: algorithm */
2758 {
2759 switch (algorithm) {
2760 case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
2761 case SRV_CHECKSUM_ALGORITHM_INNODB:
2762 log_checksum_algorithm_ptr=log_block_calc_checksum_innodb;
2763 break;
2764 case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
2765 case SRV_CHECKSUM_ALGORITHM_CRC32:
2766 log_checksum_algorithm_ptr=log_block_calc_checksum_crc32;
2767 break;
2768 case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
2769 case SRV_CHECKSUM_ALGORITHM_NONE:
2770 log_checksum_algorithm_ptr=log_block_calc_checksum_none;
2771 break;
2772 default:
2773 ut_a(0);
2774 }
2775 }
2776
2777 /****************************************************************//**
2778 On update hook for the innodb_log_checksum_algorithm variable. */
2779 static
2780 void
innodb_log_checksum_algorithm_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)2781 innodb_log_checksum_algorithm_update(
2782 /*=================================*/
2783 THD* thd, /*!< in: thread handle */
2784 struct st_mysql_sys_var* var, /*!< in: pointer to
2785 system variable */
2786 void* var_ptr,/*!< out: where the
2787 formal string goes */
2788 const void* save) /*!< in: immediate result
2789 from check function */
2790 {
2791 srv_checksum_algorithm_t algorithm;
2792
2793 algorithm = (srv_checksum_algorithm_t)
2794 (*static_cast<const ulong*>(save));
2795
2796 /* Make sure we are the only log user */
2797 mutex_enter(&log_sys->mutex);
2798
2799 innodb_log_checksum_func_update(algorithm);
2800
2801 srv_log_checksum_algorithm = algorithm;
2802
2803 mutex_exit(&log_sys->mutex);
2804 }
2805
2806 /*********************************************************************//**
2807 Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object.
2808 Those flags are stored in .frm file and end up in the MySQL table object,
2809 but are frequently used inside InnoDB so we keep their copies into the
2810 InnoDB table object. */
2811 UNIV_INTERN
2812 void
innobase_copy_frm_flags_from_create_info(dict_table_t * innodb_table,const HA_CREATE_INFO * create_info)2813 innobase_copy_frm_flags_from_create_info(
2814 /*=====================================*/
2815 dict_table_t* innodb_table, /*!< in/out: InnoDB table */
2816 const HA_CREATE_INFO* create_info) /*!< in: create info */
2817 {
2818 ibool ps_on;
2819 ibool ps_off;
2820
2821 if (dict_table_is_temporary(innodb_table)) {
2822 /* Temp tables do not use persistent stats. */
2823 ps_on = FALSE;
2824 ps_off = TRUE;
2825 } else {
2826 ps_on = create_info->table_options
2827 & HA_OPTION_STATS_PERSISTENT;
2828 ps_off = create_info->table_options
2829 & HA_OPTION_NO_STATS_PERSISTENT;
2830 }
2831
2832 dict_stats_set_persistent(innodb_table, ps_on, ps_off);
2833
2834 dict_stats_auto_recalc_set(
2835 innodb_table,
2836 create_info->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON,
2837 create_info->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF);
2838
2839 innodb_table->stats_sample_pages = create_info->stats_sample_pages;
2840 }
2841
2842 /*********************************************************************//**
2843 Copy table flags from MySQL's TABLE_SHARE into an InnoDB table object.
2844 Those flags are stored in .frm file and end up in the MySQL table object,
2845 but are frequently used inside InnoDB so we keep their copies into the
2846 InnoDB table object. */
2847 UNIV_INTERN
2848 void
innobase_copy_frm_flags_from_table_share(dict_table_t * innodb_table,const TABLE_SHARE * table_share)2849 innobase_copy_frm_flags_from_table_share(
2850 /*=====================================*/
2851 dict_table_t* innodb_table, /*!< in/out: InnoDB table */
2852 const TABLE_SHARE* table_share) /*!< in: table share */
2853 {
2854 ibool ps_on;
2855 ibool ps_off;
2856
2857 if (dict_table_is_temporary(innodb_table)) {
2858 /* Temp tables do not use persistent stats */
2859 ps_on = FALSE;
2860 ps_off = TRUE;
2861 } else {
2862 ps_on = table_share->db_create_options
2863 & HA_OPTION_STATS_PERSISTENT;
2864 ps_off = table_share->db_create_options
2865 & HA_OPTION_NO_STATS_PERSISTENT;
2866 }
2867
2868 dict_stats_set_persistent(innodb_table, ps_on, ps_off);
2869
2870 dict_stats_auto_recalc_set(
2871 innodb_table,
2872 table_share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON,
2873 table_share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF);
2874
2875 innodb_table->stats_sample_pages = table_share->stats_sample_pages;
2876 }
2877
2878 /*********************************************************************//**
2879 Construct ha_innobase handler. */
2880 UNIV_INTERN
ha_innobase(handlerton * hton,TABLE_SHARE * table_arg)2881 ha_innobase::ha_innobase(
2882 /*=====================*/
2883 handlerton* hton,
2884 TABLE_SHARE* table_arg)
2885 :handler(hton, table_arg),
2886 int_table_flags(HA_REC_NOT_IN_SEQ |
2887 HA_NULL_IN_KEY |
2888 HA_CAN_INDEX_BLOBS |
2889 HA_CAN_SQL_HANDLER |
2890 HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
2891 HA_PRIMARY_KEY_IN_READ_INDEX |
2892 HA_BINLOG_ROW_CAPABLE |
2893 HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
2894 HA_TABLE_SCAN_ON_INDEX | HA_CAN_FULLTEXT |
2895 HA_CAN_FULLTEXT_EXT | HA_CAN_EXPORT | HA_ONLINE_ANALYZE),
2896 start_of_scan(0),
2897 num_write_row(0)
2898 {}
2899
2900 /*********************************************************************//**
2901 Destruct ha_innobase handler. */
2902 UNIV_INTERN
~ha_innobase()2903 ha_innobase::~ha_innobase()
2904 /*======================*/
2905 {
2906 }
2907
2908 /*********************************************************************//**
2909 Updates the user_thd field in a handle and also allocates a new InnoDB
2910 transaction handle if needed, and updates the transaction fields in the
2911 prebuilt struct. */
2912 UNIV_INTERN inline
2913 void
update_thd(THD * thd)2914 ha_innobase::update_thd(
2915 /*====================*/
2916 THD* thd) /*!< in: thd to use the handle */
2917 {
2918 trx_t* trx;
2919
2920 DBUG_ENTER("ha_innobase::update_thd");
2921 DBUG_PRINT("ha_innobase::update_thd", ("user_thd: %p -> %p",
2922 user_thd, thd));
2923
2924 /* The table should have been opened in ha_innobase::open(). */
2925 DBUG_ASSERT(prebuilt->table->n_ref_count > 0);
2926
2927 trx = check_trx_exists(thd);
2928
2929 if (prebuilt->trx != trx) {
2930
2931 row_update_prebuilt_trx(prebuilt, trx);
2932 }
2933
2934 user_thd = thd;
2935 DBUG_VOID_RETURN;
2936 }
2937
2938 /*********************************************************************//**
2939 Updates the user_thd field in a handle and also allocates a new InnoDB
2940 transaction handle if needed, and updates the transaction fields in the
2941 prebuilt struct. */
2942 UNIV_INTERN
2943 void
update_thd()2944 ha_innobase::update_thd()
2945 /*=====================*/
2946 {
2947 THD* thd = ha_thd();
2948
2949 ut_ad(EQ_CURRENT_THD(thd));
2950 update_thd(thd);
2951 }
2952
2953 /*********************************************************************//**
2954 Registers an InnoDB transaction with the MySQL 2PC coordinator, so that
2955 the MySQL XA code knows to call the InnoDB prepare and commit, or rollback
2956 for the transaction. This MUST be called for every transaction for which
2957 the user may call commit or rollback. Calling this several times to register
2958 the same transaction is allowed, too. This function also registers the
2959 current SQL statement. */
2960 static inline
2961 void
innobase_register_trx(handlerton * hton,THD * thd,trx_t * trx)2962 innobase_register_trx(
2963 /*==================*/
2964 handlerton* hton, /* in: Innobase handlerton */
2965 THD* thd, /* in: MySQL thd (connection) object */
2966 trx_t* trx) /* in: transaction to register */
2967 {
2968 trans_register_ha(thd, FALSE, hton);
2969
2970 if (!trx_is_registered_for_2pc(trx)
2971 && thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2972
2973 trans_register_ha(thd, TRUE, hton);
2974 }
2975
2976 trx_register_for_2pc(trx);
2977 }
2978
2979 /* BACKGROUND INFO: HOW THE MYSQL QUERY CACHE WORKS WITH INNODB
2980 ------------------------------------------------------------
2981
2982 1) The use of the query cache for TBL is disabled when there is an
2983 uncommitted change to TBL.
2984
2985 2) When a change to TBL commits, InnoDB stores the current value of
2986 its global trx id counter, let us denote it by INV_TRX_ID, to the table object
2987 in the InnoDB data dictionary, and does only allow such transactions whose
2988 id <= INV_TRX_ID to use the query cache.
2989
2990 3) When InnoDB does an INSERT/DELETE/UPDATE to a table TBL, or an implicit
2991 modification because an ON DELETE CASCADE, we invalidate the MySQL query cache
2992 of TBL immediately.
2993
2994 How this is implemented inside InnoDB:
2995
2996 1) Since every modification always sets an IX type table lock on the InnoDB
2997 table, it is easy to check if there can be uncommitted modifications for a
2998 table: just check if there are locks in the lock list of the table.
2999
3000 2) When a transaction inside InnoDB commits, it reads the global trx id
3001 counter and stores the value INV_TRX_ID to the tables on which it had a lock.
3002
3003 3) If there is an implicit table change from ON DELETE CASCADE or SET NULL,
3004 InnoDB calls an invalidate method for the MySQL query cache for that table.
3005
3006 How this is implemented inside sql_cache.cc:
3007
3008 1) The query cache for an InnoDB table TBL is invalidated immediately at an
3009 INSERT/UPDATE/DELETE, just like in the case of MyISAM. No need to delay
3010 invalidation to the transaction commit.
3011
3012 2) To store or retrieve a value from the query cache of an InnoDB table TBL,
3013 any query must first ask InnoDB's permission. We must pass the thd as a
3014 parameter because InnoDB will look at the trx id, if any, associated with
3015 that thd. Also the full_name which is used as key to search for the table
3016 object. The full_name is a string containing the normalized path to the
3017 table in the canonical format.
3018
3019 3) Use of the query cache for InnoDB tables is now allowed also when
3020 AUTOCOMMIT==0 or we are inside BEGIN ... COMMIT. Thus transactions no longer
3021 put restrictions on the use of the query cache.
3022 */
3023
3024 /******************************************************************//**
3025 The MySQL query cache uses this to check from InnoDB if the query cache at
3026 the moment is allowed to operate on an InnoDB table. The SQL query must
3027 be a non-locking SELECT.
3028
3029 The query cache is allowed to operate on certain query only if this function
3030 returns TRUE for all tables in the query.
3031
3032 If thd is not in the autocommit state, this function also starts a new
3033 transaction for thd if there is no active trx yet, and assigns a consistent
3034 read view to it if there is no read view yet.
3035
3036 Why a deadlock of threads is not possible: the query cache calls this function
3037 at the start of a SELECT processing. Then the calling thread cannot be
3038 holding any InnoDB semaphores. The calling thread is holding the
3039 query cache mutex, and this function will reserve the InnoDB trx_sys->mutex.
3040 Thus, the 'rank' in sync0sync.h of the MySQL query cache mutex is above
3041 the InnoDB trx_sys->mutex.
3042 @return TRUE if permitted, FALSE if not; note that the value FALSE
3043 does not mean we should invalidate the query cache: invalidation is
3044 called explicitly */
3045 static
3046 my_bool
innobase_query_caching_of_table_permitted(THD * thd,char * full_name,uint full_name_len,ulonglong * unused)3047 innobase_query_caching_of_table_permitted(
3048 /*======================================*/
3049 THD* thd, /*!< in: thd of the user who is trying to
3050 store a result to the query cache or
3051 retrieve it */
3052 char* full_name, /*!< in: normalized path to the table */
3053 uint full_name_len, /*!< in: length of the normalized path
3054 to the table */
3055 ulonglong *unused) /*!< unused for this engine */
3056 {
3057 ibool is_autocommit;
3058 trx_t* trx;
3059 char norm_name[1000];
3060
3061 ut_a(full_name_len < 999);
3062
3063 trx = check_trx_exists(thd);
3064
3065 if (trx->isolation_level == TRX_ISO_SERIALIZABLE) {
3066 /* In the SERIALIZABLE mode we add LOCK IN SHARE MODE to every
3067 plain SELECT if AUTOCOMMIT is not on. */
3068
3069 return((my_bool)FALSE);
3070 }
3071
3072 if (UNIV_UNLIKELY(trx->has_search_latch)) {
3073 sql_print_error("The calling thread is holding the adaptive "
3074 "search, latch though calling "
3075 "innobase_query_caching_of_table_permitted.");
3076 trx_print(stderr, trx, 1024);
3077 }
3078
3079 trx_search_latch_release_if_reserved(trx);
3080
3081 innobase_srv_conc_force_exit_innodb(trx);
3082
3083 if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
3084
3085 is_autocommit = TRUE;
3086 } else {
3087 is_autocommit = FALSE;
3088
3089 }
3090
3091 if (is_autocommit && trx->n_mysql_tables_in_use == 0) {
3092 /* We are going to retrieve the query result from the query
3093 cache. This cannot be a store operation to the query cache
3094 because then MySQL would have locks on tables already.
3095
3096 TODO: if the user has used LOCK TABLES to lock the table,
3097 then we open a transaction in the call of row_.. below.
3098 That trx can stay open until UNLOCK TABLES. The same problem
3099 exists even if we do not use the query cache. MySQL should be
3100 modified so that it ALWAYS calls some cleanup function when
3101 the processing of a query ends!
3102
3103 We can imagine we instantaneously serialize this consistent
3104 read trx to the current trx id counter. If trx2 would have
3105 changed the tables of a query result stored in the cache, and
3106 trx2 would have already committed, making the result obsolete,
3107 then trx2 would have already invalidated the cache. Thus we
3108 can trust the result in the cache is ok for this query. */
3109
3110 return((my_bool)TRUE);
3111 }
3112
3113 /* Normalize the table name to InnoDB format */
3114 normalize_table_name(norm_name, full_name);
3115
3116 innobase_register_trx(innodb_hton_ptr, thd, trx);
3117
3118 if (row_search_check_if_query_cache_permitted(trx, norm_name)) {
3119
3120 /* printf("Query cache for %s permitted\n", norm_name); */
3121
3122 return((my_bool)TRUE);
3123 }
3124
3125 /* printf("Query cache for %s NOT permitted\n", norm_name); */
3126
3127 return((my_bool)FALSE);
3128 }
3129
3130 /*****************************************************************//**
3131 Invalidates the MySQL query cache for the table. */
3132 UNIV_INTERN
3133 void
innobase_invalidate_query_cache(trx_t * trx,const char * full_name,ulint full_name_len)3134 innobase_invalidate_query_cache(
3135 /*============================*/
3136 trx_t* trx, /*!< in: transaction which
3137 modifies the table */
3138 const char* full_name, /*!< in: concatenation of
3139 database name, null char NUL,
3140 table name, null char NUL;
3141 NOTE that in Windows this is
3142 always in LOWER CASE! */
3143 ulint full_name_len) /*!< in: full name length where
3144 also the null chars count */
3145 {
3146 /* Note that the sync0sync.h rank of the query cache mutex is just
3147 above the InnoDB trx_sys_t->lock. The caller of this function must
3148 not have latches of a lower rank. */
3149
3150 #ifdef HAVE_QUERY_CACHE
3151 char qcache_key_name[2 * (NAME_LEN + 1)];
3152 size_t tabname_len;
3153 size_t dbname_len;
3154
3155 /* Construct the key("db-name\0table$name\0") for the query cache using
3156 the path name("db@002dname\0table@0024name\0") of the table in its
3157 canonical form. */
3158 dbname_len = filename_to_tablename(full_name, qcache_key_name,
3159 sizeof(qcache_key_name));
3160 tabname_len = filename_to_tablename(full_name + strlen(full_name) + 1,
3161 qcache_key_name + dbname_len + 1,
3162 sizeof(qcache_key_name)
3163 - dbname_len - 1);
3164
3165 /* Argument TRUE below means we are using transactions */
3166 mysql_query_cache_invalidate4(trx->mysql_thd,
3167 qcache_key_name,
3168 (dbname_len + tabname_len + 2),
3169 TRUE);
3170 #endif
3171 }
3172
3173 /*****************************************************************//**
3174 Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
3175 and quote it if needed.
3176 @return pointer to the end of buf */
3177 static
3178 char*
innobase_convert_identifier(char * buf,ulint buflen,const char * id,ulint idlen,THD * thd,ibool file_id)3179 innobase_convert_identifier(
3180 /*========================*/
3181 char* buf, /*!< out: buffer for converted identifier */
3182 ulint buflen, /*!< in: length of buf, in bytes */
3183 const char* id, /*!< in: identifier to convert */
3184 ulint idlen, /*!< in: length of id, in bytes */
3185 THD* thd, /*!< in: MySQL connection thread, or NULL */
3186 ibool file_id)/*!< in: TRUE=id is a table or database name;
3187 FALSE=id is an UTF-8 string */
3188 {
3189 const char* s = id;
3190 int q;
3191
3192 char nz[MAX_TABLE_NAME_LEN + 1];
3193 char nz2[MAX_TABLE_NAME_LEN + 1];
3194
3195 if (file_id) {
3196
3197 /* Decode the table name. The MySQL function expects
3198 a NUL-terminated string. The input and output strings
3199 buffers must not be shared. */
3200 ut_a(idlen <= MAX_TABLE_NAME_LEN);
3201 memcpy(nz, id, idlen);
3202 nz[idlen] = 0;
3203
3204 s = nz2;
3205 idlen = explain_filename(thd, nz, nz2, sizeof nz2,
3206 EXPLAIN_PARTITIONS_AS_COMMENT);
3207 goto no_quote;
3208 }
3209
3210 /* See if the identifier needs to be quoted. */
3211 if (UNIV_UNLIKELY(!thd)) {
3212 q = '"';
3213 } else {
3214 q = get_quote_char_for_identifier(thd, s, (int) idlen);
3215 }
3216
3217 if (q == EOF) {
3218 no_quote:
3219 if (UNIV_UNLIKELY(idlen > buflen)) {
3220 idlen = buflen;
3221 }
3222 memcpy(buf, s, idlen);
3223 return(buf + idlen);
3224 }
3225
3226 /* Quote the identifier. */
3227 if (buflen < 2) {
3228 return(buf);
3229 }
3230
3231 *buf++ = q;
3232 buflen--;
3233
3234 for (; idlen; idlen--) {
3235 int c = *s++;
3236 if (UNIV_UNLIKELY(c == q)) {
3237 if (UNIV_UNLIKELY(buflen < 3)) {
3238 break;
3239 }
3240
3241 *buf++ = c;
3242 *buf++ = c;
3243 buflen -= 2;
3244 } else {
3245 if (UNIV_UNLIKELY(buflen < 2)) {
3246 break;
3247 }
3248
3249 *buf++ = c;
3250 buflen--;
3251 }
3252 }
3253
3254 *buf++ = q;
3255 return(buf);
3256 }
3257
3258 /*****************************************************************//**
3259 Convert a table or index name to the MySQL system_charset_info (UTF-8)
3260 and quote it if needed.
3261 @return pointer to the end of buf */
3262 UNIV_INTERN
3263 char*
innobase_convert_name(char * buf,ulint buflen,const char * id,ulint idlen,THD * thd,ibool table_id)3264 innobase_convert_name(
3265 /*==================*/
3266 char* buf, /*!< out: buffer for converted identifier */
3267 ulint buflen, /*!< in: length of buf, in bytes */
3268 const char* id, /*!< in: identifier to convert */
3269 ulint idlen, /*!< in: length of id, in bytes */
3270 THD* thd, /*!< in: MySQL connection thread, or NULL */
3271 ibool table_id)/*!< in: TRUE=id is a table or database name;
3272 FALSE=id is an index name */
3273 {
3274 char* s = buf;
3275 const char* bufend = buf + buflen;
3276
3277 if (table_id) {
3278 const char* slash = (const char*) memchr(id, '/', idlen);
3279 if (!slash) {
3280
3281 goto no_db_name;
3282 }
3283
3284 /* Print the database name and table name separately. */
3285 s = innobase_convert_identifier(s, bufend - s, id, slash - id,
3286 thd, TRUE);
3287 if (UNIV_LIKELY(s < bufend)) {
3288 *s++ = '.';
3289 s = innobase_convert_identifier(s, bufend - s,
3290 slash + 1, idlen
3291 - (slash - id) - 1,
3292 thd, TRUE);
3293 }
3294 } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
3295 /* Temporary index name (smart ALTER TABLE) */
3296 const char temp_index_suffix[]= "--temporary--";
3297
3298 s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
3299 thd, FALSE);
3300 if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
3301 memcpy(s, temp_index_suffix,
3302 sizeof temp_index_suffix - 1);
3303 s += sizeof temp_index_suffix - 1;
3304 }
3305 } else {
3306 no_db_name:
3307 s = innobase_convert_identifier(buf, buflen, id, idlen,
3308 thd, table_id);
3309 }
3310
3311 return(s);
3312 }
3313
3314 /*****************************************************************//**
3315 A wrapper function of innobase_convert_name(), convert a table or
3316 index name to the MySQL system_charset_info (UTF-8) and quote it if needed.
3317 @return pointer to the end of buf */
3318 UNIV_INTERN
3319 void
innobase_format_name(char * buf,ulint buflen,const char * name,ibool is_index_name)3320 innobase_format_name(
3321 /*==================*/
3322 char* buf, /*!< out: buffer for converted identifier */
3323 ulint buflen, /*!< in: length of buf, in bytes */
3324 const char* name, /*!< in: index or table name to format */
3325 ibool is_index_name) /*!< in: index name */
3326 {
3327 const char* bufend;
3328
3329 bufend = innobase_convert_name(buf, buflen, name, strlen(name),
3330 NULL, !is_index_name);
3331
3332 ut_ad((ulint) (bufend - buf) < buflen);
3333
3334 buf[bufend - buf] = '\0';
3335 }
3336
3337 /**********************************************************************//**
3338 Determines if the currently running transaction has been interrupted.
3339 @return TRUE if interrupted */
3340 UNIV_INTERN
3341 ibool
trx_is_interrupted(const trx_t * trx)3342 trx_is_interrupted(
3343 /*===============*/
3344 const trx_t* trx) /*!< in: transaction */
3345 {
3346 return(trx && trx->mysql_thd && thd_killed(trx->mysql_thd));
3347 }
3348
3349 /**********************************************************************//**
3350 Determines if the currently running transaction is in strict mode.
3351 @return TRUE if strict */
3352 UNIV_INTERN
3353 ibool
trx_is_strict(trx_t * trx)3354 trx_is_strict(
3355 /*==========*/
3356 trx_t* trx) /*!< in: transaction */
3357 {
3358 return(trx && trx->mysql_thd && THDVAR(trx->mysql_thd, strict_mode));
3359 }
3360
3361 /**************************************************************//**
3362 Resets some fields of a prebuilt struct. The template is used in fast
3363 retrieval of just those column values MySQL needs in its processing. */
3364 inline
3365 void
reset_template(void)3366 ha_innobase::reset_template(void)
3367 /*=============================*/
3368 {
3369 ut_ad(prebuilt->magic_n == ROW_PREBUILT_ALLOCATED);
3370 ut_ad(prebuilt->magic_n2 == prebuilt->magic_n);
3371
3372 /* Force table to be freed in close_thread_table(). */
3373 DBUG_EXECUTE_IF("free_table_in_fts_query",
3374 if (prebuilt->in_fts_query) {
3375 table->m_needs_reopen = true;
3376 }
3377 );
3378
3379 prebuilt->keep_other_fields_on_keyread = 0;
3380 prebuilt->read_just_key = 0;
3381 prebuilt->in_fts_query = 0;
3382 prebuilt->end_range = false;
3383 /* Reset index condition pushdown state. */
3384 if (prebuilt->idx_cond) {
3385 prebuilt->idx_cond = NULL;
3386 prebuilt->idx_cond_n_cols = 0;
3387 /* Invalidate prebuilt->mysql_template
3388 in ha_innobase::write_row(). */
3389 prebuilt->template_type = ROW_MYSQL_NO_TEMPLATE;
3390 }
3391 }
3392
3393 /*****************************************************************//**
3394 Call this when you have opened a new table handle in HANDLER, before you
3395 call index_read_idx() etc. Actually, we can let the cursor stay open even
3396 over a transaction commit! Then you should call this before every operation,
3397 fetch next etc. This function inits the necessary things even after a
3398 transaction commit. */
3399 UNIV_INTERN
3400 void
init_table_handle_for_HANDLER(void)3401 ha_innobase::init_table_handle_for_HANDLER(void)
3402 /*============================================*/
3403 {
3404 /* If current thd does not yet have a trx struct, create one.
3405 If the current handle does not yet have a prebuilt struct, create
3406 one. Update the trx pointers in the prebuilt struct. Normally
3407 this operation is done in external_lock. */
3408
3409 update_thd(ha_thd());
3410
3411 /* Initialize the prebuilt struct much like it would be inited in
3412 external_lock */
3413
3414 trx_search_latch_release_if_reserved(prebuilt->trx);
3415
3416 innobase_srv_conc_force_exit_innodb(prebuilt->trx);
3417
3418 /* If the transaction is not started yet, start it */
3419
3420 trx_start_if_not_started_xa(prebuilt->trx);
3421
3422 /* Assign a read view if the transaction does not have it yet */
3423
3424 trx_assign_read_view(prebuilt->trx);
3425
3426 innobase_register_trx(ht, user_thd, prebuilt->trx);
3427
3428 /* We did the necessary inits in this function, no need to repeat them
3429 in row_search_for_mysql */
3430
3431 prebuilt->sql_stat_start = FALSE;
3432
3433 /* We let HANDLER always to do the reads as consistent reads, even
3434 if the trx isolation level would have been specified as SERIALIZABLE */
3435
3436 prebuilt->select_lock_type = LOCK_NONE;
3437 prebuilt->stored_select_lock_type = LOCK_NONE;
3438
3439 /* Always fetch all columns in the index record */
3440
3441 prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
3442
3443 /* We want always to fetch all columns in the whole row? Or do
3444 we???? */
3445
3446 prebuilt->used_in_HANDLER = TRUE;
3447 reset_template();
3448 }
3449
3450 /*********************************************************************//**
3451 Opens an InnoDB database.
3452 @return 0 on success, error code on failure */
3453 static
3454 int
innobase_init(void * p)3455 innobase_init(
3456 /*==========*/
3457 void *p) /*!< in: InnoDB handlerton */
3458 {
3459 static char current_dir[3]; /*!< Set if using current lib */
3460 int err;
3461 bool ret;
3462 char *default_path;
3463 uint format_id;
3464 ulong num_pll_degree;
3465
3466 DBUG_ENTER("innobase_init");
3467 handlerton *innobase_hton= (handlerton*) p;
3468 innodb_hton_ptr = innobase_hton;
3469
3470 innobase_hton->state = SHOW_OPTION_YES;
3471 innobase_hton->db_type= DB_TYPE_INNODB;
3472 innobase_hton->savepoint_offset = sizeof(trx_named_savept_t);
3473 innobase_hton->close_connection = innobase_close_connection;
3474 innobase_hton->savepoint_set = innobase_savepoint;
3475 innobase_hton->savepoint_rollback = innobase_rollback_to_savepoint;
3476 innobase_hton->savepoint_rollback_can_release_mdl =
3477 innobase_rollback_to_savepoint_can_release_mdl;
3478 innobase_hton->savepoint_release = innobase_release_savepoint;
3479 innobase_hton->commit = innobase_commit;
3480 innobase_hton->rollback = innobase_rollback;
3481 innobase_hton->prepare = innobase_xa_prepare;
3482 innobase_hton->recover = innobase_xa_recover;
3483 innobase_hton->commit_by_xid = innobase_commit_by_xid;
3484 innobase_hton->rollback_by_xid = innobase_rollback_by_xid;
3485 innobase_hton->create_cursor_read_view = innobase_create_cursor_view;
3486 innobase_hton->set_cursor_read_view = innobase_set_cursor_view;
3487 innobase_hton->close_cursor_read_view = innobase_close_cursor_view;
3488 innobase_hton->create = innobase_create_handler;
3489 innobase_hton->drop_database = innobase_drop_database;
3490 innobase_hton->panic = innobase_end;
3491
3492 innobase_hton->start_consistent_snapshot =
3493 innobase_start_trx_and_assign_read_view;
3494 innobase_hton->clone_consistent_snapshot =
3495 innobase_start_trx_and_clone_read_view;
3496
3497 innobase_hton->store_binlog_info =
3498 innobase_store_binlog_info;
3499
3500 innobase_hton->flush_logs = innobase_flush_logs;
3501 innobase_hton->show_status = innobase_show_status;
3502 innobase_hton->flags = HTON_SUPPORTS_EXTENDED_KEYS |
3503 HTON_SUPPORTS_ONLINE_BACKUPS | HTON_SUPPORTS_FOREIGN_KEYS |
3504 HTON_SUPPORTS_COMPRESSED_COLUMNS;
3505
3506 innobase_hton->release_temporary_latches =
3507 innobase_release_temporary_latches;
3508 innobase_hton->purge_archive_logs = innobase_purge_archive_logs;
3509
3510 innobase_hton->data = &innodb_api_cb;
3511 innobase_hton->is_reserved_db_name= innobase_check_reserved_file_name;
3512 innobase_hton->flush_changed_page_bitmaps
3513 = innobase_flush_changed_page_bitmaps;
3514 innobase_hton->purge_changed_page_bitmaps
3515 = innobase_purge_changed_page_bitmaps;
3516 innobase_hton->is_fake_change = innobase_is_fake_change;
3517 innobase_hton->get_parent_fk_list = innobase_get_parent_fk_list;
3518
3519 innobase_hton->kill_connection = innobase_kill_connection;
3520
3521 innobase_hton->create_zip_dict = innobase_create_zip_dict;
3522 innobase_hton->drop_zip_dict = innobase_drop_zip_dict;
3523
3524 ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
3525
3526 #ifndef DBUG_OFF
3527 static const char test_filename[] = "-@";
3528 char test_tablename[sizeof test_filename
3529 + sizeof(srv_mysql50_table_name_prefix) - 1];
3530 if ((sizeof(test_tablename)) - 1
3531 != filename_to_tablename(test_filename,
3532 test_tablename,
3533 sizeof(test_tablename), true)
3534 || strncmp(test_tablename,
3535 srv_mysql50_table_name_prefix,
3536 sizeof(srv_mysql50_table_name_prefix) - 1)
3537 || strcmp(test_tablename
3538 + sizeof(srv_mysql50_table_name_prefix) - 1,
3539 test_filename)) {
3540
3541 sql_print_error("tablename encoding has been changed");
3542
3543 goto error;
3544 }
3545 #endif /* DBUG_OFF */
3546
3547 srv_log_block_size = 0;
3548 if (innobase_log_block_size != (1 << 9)) { /*!=512*/
3549 uint n_shift;
3550
3551 fprintf(stderr,
3552 "InnoDB: Warning: innodb_log_block_size has been "
3553 "changed from default value 512. (###EXPERIMENTAL### "
3554 "operation)\n");
3555 for (n_shift = 9; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX;
3556 n_shift++) {
3557 if (innobase_log_block_size == ((ulong)1 << n_shift)) {
3558 srv_log_block_size = (1 << n_shift);
3559 fprintf(stderr,
3560 "InnoDB: The log block size is set to "
3561 ULINTPF ".\n",srv_log_block_size);
3562 break;
3563 }
3564 }
3565 } else {
3566 srv_log_block_size = 512;
3567 }
3568 ut_ad (srv_log_block_size >= OS_MIN_LOG_BLOCK_SIZE);
3569
3570 if (!srv_log_block_size) {
3571 fprintf(stderr,
3572 "InnoDB: Error: %lu is not a valid value for "
3573 "innodb_log_block_size.\n"
3574 "InnoDB: Error: A valid value for "
3575 "innodb_log_block_size is\n"
3576 "InnoDB: Error: a power of 2 from 512 to 16384.\n",
3577 innobase_log_block_size);
3578 goto error;
3579 }
3580
3581 /* Check that values don't overflow on 32-bit systems. */
3582 if (sizeof(ulint) == 4) {
3583 if (innobase_buffer_pool_size > UINT_MAX32) {
3584 sql_print_error(
3585 "innobase_buffer_pool_size can't be over 4GB"
3586 " on 32-bit systems");
3587
3588 goto error;
3589 }
3590 }
3591
3592 os_innodb_umask = (ulint) my_umask;
3593
3594 /* First calculate the default path for innodb_data_home_dir etc.,
3595 in case the user has not given any value.
3596
3597 Note that when using the embedded server, the datadirectory is not
3598 necessarily the current directory of this program. */
3599
3600 if (mysqld_embedded) {
3601 default_path = mysql_real_data_home;
3602 fil_path_to_mysql_datadir = mysql_real_data_home;
3603 } else {
3604 /* It's better to use current lib, to keep paths short */
3605 current_dir[0] = FN_CURLIB;
3606 current_dir[1] = FN_LIBCHAR;
3607 current_dir[2] = 0;
3608 default_path = current_dir;
3609 }
3610
3611 ut_a(default_path);
3612
3613 /* Set InnoDB initialization parameters according to the values
3614 read from MySQL .cnf file */
3615
3616 /*--------------- Data files -------------------------*/
3617
3618 /* The default dir for data files is the datadir of MySQL */
3619
3620 srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
3621 default_path);
3622
3623 /* Set default InnoDB data file size to 12 MB and let it be
3624 auto-extending. Thus users can use InnoDB in >= 4.0 without having
3625 to specify any startup options. */
3626
3627 if (!innobase_data_file_path) {
3628 innobase_data_file_path = (char*) "ibdata1:12M:autoextend";
3629 }
3630
3631 /* Since InnoDB edits the argument in the next call, we make another
3632 copy of it: */
3633
3634 internal_innobase_data_file_path = my_strdup(innobase_data_file_path,
3635 MYF(MY_FAE));
3636
3637 ret = (bool) srv_parse_data_file_paths_and_sizes(
3638 internal_innobase_data_file_path);
3639 if (ret == FALSE) {
3640 sql_print_error(
3641 "InnoDB: syntax error in innodb_data_file_path"
3642 " or size specified is less than 1 megabyte");
3643 mem_free_and_error:
3644 srv_free_paths_and_sizes();
3645 my_free(internal_innobase_data_file_path);
3646 goto error;
3647 }
3648
3649 /* -------------- All log files ---------------------------*/
3650
3651 /* The default dir for log files is the datadir of MySQL */
3652
3653 if (!srv_log_group_home_dir) {
3654 srv_log_group_home_dir = default_path;
3655 }
3656
3657 #ifdef UNIV_LOG_ARCHIVE
3658 if (!innobase_log_arch_dir) {
3659 innobase_log_arch_dir = srv_log_group_home_dir;
3660 }
3661 srv_arch_dir = innobase_log_arch_dir;
3662 #endif /* UNIG_LOG_ARCHIVE */
3663
3664 srv_normalize_path_for_win(srv_log_group_home_dir);
3665
3666 if (strchr(srv_log_group_home_dir, ';')) {
3667 sql_print_error("syntax error in innodb_log_group_home_dir");
3668 goto mem_free_and_error;
3669 }
3670
3671 if (innobase_mirrored_log_groups == 1) {
3672 sql_print_warning(
3673 "innodb_mirrored_log_groups is an unimplemented "
3674 "feature and the variable will be completely "
3675 "removed in a future version.");
3676 }
3677
3678 if (innobase_mirrored_log_groups > 1) {
3679 sql_print_error(
3680 "innodb_mirrored_log_groups is an unimplemented feature and "
3681 "the variable will be completely removed in a future version. "
3682 "Using values other than 1 is not supported.");
3683 goto mem_free_and_error;
3684 }
3685
3686 if (innobase_mirrored_log_groups == 0) {
3687 /* To throw a deprecation warning message when the option is
3688 passed, the default was changed to '0' (as a workaround). Since
3689 the only value accepted for this option is '1', reset it to 1 */
3690 innobase_mirrored_log_groups = 1;
3691 }
3692
3693 /* Validate the file format by animal name */
3694 if (innobase_file_format_name != NULL) {
3695
3696 format_id = innobase_file_format_name_lookup(
3697 innobase_file_format_name);
3698
3699 if (format_id > UNIV_FORMAT_MAX) {
3700
3701 sql_print_error("InnoDB: wrong innodb_file_format.");
3702
3703 goto mem_free_and_error;
3704 }
3705 } else {
3706 /* Set it to the default file format id. Though this
3707 should never happen. */
3708 format_id = 0;
3709 }
3710
3711 srv_file_format = format_id;
3712
3713 /* Given the type of innobase_file_format_name we have little
3714 choice but to cast away the constness from the returned name.
3715 innobase_file_format_name is used in the MySQL set variable
3716 interface and so can't be const. */
3717
3718 innobase_file_format_name =
3719 (char*) trx_sys_file_format_id_to_name(format_id);
3720
3721 /* Check innobase_file_format_check variable */
3722 if (!innobase_file_format_check) {
3723
3724 /* Set the value to disable checking. */
3725 srv_max_file_format_at_startup = UNIV_FORMAT_MAX + 1;
3726
3727 } else {
3728
3729 /* Set the value to the lowest supported format. */
3730 srv_max_file_format_at_startup = UNIV_FORMAT_MIN;
3731 }
3732
3733 /* Did the user specify a format name that we support?
3734 As a side effect it will update the variable
3735 srv_max_file_format_at_startup */
3736 if (innobase_file_format_validate_and_set(
3737 innobase_file_format_max) < 0) {
3738
3739 sql_print_error("InnoDB: invalid "
3740 "innodb_file_format_max value: "
3741 "should be any value up to %s or its "
3742 "equivalent numeric id",
3743 trx_sys_file_format_id_to_name(
3744 UNIV_FORMAT_MAX));
3745
3746 goto mem_free_and_error;
3747 }
3748
3749 if (innobase_change_buffering) {
3750 ulint use;
3751
3752 for (use = 0;
3753 use < UT_ARR_SIZE(innobase_change_buffering_values);
3754 use++) {
3755 if (!innobase_strcasecmp(
3756 innobase_change_buffering,
3757 innobase_change_buffering_values[use])) {
3758 ibuf_use = (ibuf_use_t) use;
3759 goto innobase_change_buffering_inited_ok;
3760 }
3761 }
3762
3763 sql_print_error("InnoDB: invalid value "
3764 "innodb_change_buffering=%s",
3765 innobase_change_buffering);
3766 goto mem_free_and_error;
3767 }
3768
3769 innobase_change_buffering_inited_ok:
3770 ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
3771 innobase_change_buffering = (char*)
3772 innobase_change_buffering_values[ibuf_use];
3773
3774 /* Check that interdependent parameters have sane values. */
3775 if (srv_max_buf_pool_modified_pct < srv_max_dirty_pages_pct_lwm) {
3776 sql_print_warning("InnoDB: innodb_max_dirty_pages_pct_lwm"
3777 " cannot be set higher than"
3778 " innodb_max_dirty_pages_pct.\n"
3779 "InnoDB: Setting"
3780 " innodb_max_dirty_pages_pct_lwm to %lu\n",
3781 srv_max_buf_pool_modified_pct);
3782
3783 srv_max_dirty_pages_pct_lwm = srv_max_buf_pool_modified_pct;
3784 }
3785
3786 if (srv_max_io_capacity == SRV_MAX_IO_CAPACITY_DUMMY_DEFAULT) {
3787
3788 if (srv_io_capacity >= SRV_MAX_IO_CAPACITY_LIMIT / 2) {
3789 /* Avoid overflow. */
3790 srv_max_io_capacity = SRV_MAX_IO_CAPACITY_LIMIT;
3791 } else {
3792 /* The user has not set the value. We should
3793 set it based on innodb_io_capacity. */
3794 srv_max_io_capacity = static_cast<ulong>(
3795 ut_max(2 * srv_io_capacity, 2000));
3796 }
3797
3798 } else if (srv_max_io_capacity < srv_io_capacity) {
3799 sql_print_warning("InnoDB: innodb_io_capacity"
3800 " cannot be set higher than"
3801 " innodb_io_capacity_max.\n"
3802 "InnoDB: Setting"
3803 " innodb_io_capacity to %lu\n",
3804 srv_max_io_capacity);
3805
3806 srv_io_capacity = srv_max_io_capacity;
3807 }
3808
3809 if (!is_filename_allowed(srv_buf_dump_filename,
3810 strlen(srv_buf_dump_filename), FALSE)) {
3811 sql_print_error("InnoDB: innodb_buffer_pool_filename"
3812 " cannot have colon (:) in the file name.");
3813 goto mem_free_and_error;
3814 }
3815
3816 /* --------------------------------------------------*/
3817
3818 srv_file_flush_method_str = innobase_file_flush_method;
3819
3820 srv_log_file_size = (ib_uint64_t) innobase_log_file_size;
3821
3822 #ifdef UNIV_LOG_ARCHIVE
3823 srv_log_archive_on = (ulint) innobase_log_archive;
3824 #endif /* UNIV_LOG_ARCHIVE */
3825
3826 /* Check that the value of system variable innodb_page_size was
3827 set correctly. Its value was put into srv_page_size. If valid,
3828 return the associated srv_page_size_shift.*/
3829 srv_page_size_shift = innodb_page_size_validate(srv_page_size);
3830 if (!srv_page_size_shift) {
3831 sql_print_error("InnoDB: Invalid page size=%lu.\n",
3832 srv_page_size);
3833 goto mem_free_and_error;
3834 }
3835 if (UNIV_PAGE_SIZE_DEF != srv_page_size) {
3836 ut_print_timestamp(stderr);
3837 fprintf(stderr,
3838 " InnoDB: innodb-page-size has been changed"
3839 " from the default value %d to %lu.\n",
3840 UNIV_PAGE_SIZE_DEF, srv_page_size);
3841 }
3842
3843 srv_log_buffer_size = (ulint) innobase_log_buffer_size;
3844
3845 if (innobase_buffer_pool_instances == 0) {
3846 innobase_buffer_pool_instances = 8;
3847
3848 #if defined(__WIN__) && !defined(_WIN64)
3849 if (innobase_buffer_pool_size > 1331 * 1024 * 1024) {
3850 innobase_buffer_pool_instances
3851 = ut_min(MAX_BUFFER_POOLS,
3852 (long) (innobase_buffer_pool_size
3853 / (128 * 1024 * 1024)));
3854 }
3855 #endif /* defined(__WIN__) && !defined(_WIN64) */
3856 }
3857 srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
3858 srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances;
3859
3860 srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
3861
3862 if (innobase_additional_mem_pool_size
3863 != 8*1024*1024L /* the default */ ) {
3864
3865 ut_print_timestamp(stderr);
3866 fprintf(stderr,
3867 " InnoDB: Warning: Using "
3868 "innodb_additional_mem_pool_size is DEPRECATED. "
3869 "This option may be removed in future releases, "
3870 "together with the option innodb_use_sys_malloc "
3871 "and with the InnoDB's internal memory "
3872 "allocator.\n");
3873 }
3874
3875 if (!srv_use_sys_malloc ) {
3876 ut_print_timestamp(stderr);
3877 fprintf(stderr,
3878 " InnoDB: Warning: Setting "
3879 "innodb_use_sys_malloc to FALSE is DEPRECATED. "
3880 "This option may be removed in future releases, "
3881 "together with the InnoDB's internal memory "
3882 "allocator.\n");
3883 }
3884
3885 srv_n_file_io_threads = (ulint) innobase_file_io_threads;
3886 srv_n_read_io_threads = (ulint) innobase_read_io_threads;
3887 srv_n_write_io_threads = (ulint) innobase_write_io_threads;
3888
3889 srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
3890
3891 if (!innobase_use_checksums) {
3892 ut_print_timestamp(stderr);
3893 fprintf(stderr,
3894 " InnoDB: Warning: Setting "
3895 "innodb_checksums to OFF is DEPRECATED. "
3896 "This option may be removed in future releases. "
3897 "You should set innodb_checksum_algorithm=NONE "
3898 "instead.\n");
3899 srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_NONE;
3900 }
3901
3902 innodb_log_checksum_func_update(srv_log_checksum_algorithm);
3903
3904 #ifdef HAVE_LARGE_PAGES
3905 if ((os_use_large_pages = (ibool) my_use_large_pages)) {
3906 os_large_page_size = (ulint) opt_large_page_size;
3907 }
3908 #endif
3909
3910 row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
3911
3912 srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
3913 if (innobase_locks_unsafe_for_binlog) {
3914 ut_print_timestamp(stderr);
3915 fprintf(stderr,
3916 " InnoDB: Warning: Using "
3917 "innodb_locks_unsafe_for_binlog is DEPRECATED. "
3918 "This option may be removed in future releases. "
3919 "Please use READ COMMITTED transaction isolation "
3920 "level instead, see " REFMAN "set-transaction.html.\n");
3921 }
3922
3923 if (innobase_open_files < 10) {
3924 innobase_open_files = 300;
3925 if (srv_file_per_table && table_cache_size > 300) {
3926 innobase_open_files = table_cache_size;
3927 }
3928 }
3929
3930 if (innobase_open_files > (long) open_files_limit) {
3931 fprintf(stderr,
3932 "innodb_open_files should not be greater"
3933 " than the open_files_limit.\n");
3934 if (innobase_open_files > (long) table_cache_size) {
3935 innobase_open_files = table_cache_size;
3936 }
3937 }
3938
3939 srv_max_n_open_files = (ulint) innobase_open_files;
3940 srv_innodb_status = (ibool) innobase_create_status_file;
3941
3942 srv_print_verbose_log = mysqld_embedded ? 0 : 1;
3943
3944 /* Round up fts_sort_pll_degree to nearest power of 2 number */
3945 for (num_pll_degree = 1;
3946 num_pll_degree < fts_sort_pll_degree;
3947 num_pll_degree <<= 1) {
3948
3949 /* No op */
3950 }
3951
3952 fts_sort_pll_degree = num_pll_degree;
3953
3954 /* Store the default charset-collation number of this MySQL
3955 installation */
3956
3957 data_mysql_default_charset_coll = (ulint) default_charset_info->number;
3958
3959 ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL ==
3960 my_charset_latin1.number);
3961 ut_a(DATA_MYSQL_BINARY_CHARSET_COLL == my_charset_bin.number);
3962
3963 /* Store the latin1_swedish_ci character ordering table to InnoDB. For
3964 non-latin1_swedish_ci charsets we use the MySQL comparison functions,
3965 and consequently we do not need to know the ordering internally in
3966 InnoDB. */
3967
3968 ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci"));
3969 srv_latin1_ordering = my_charset_latin1.sort_order;
3970
3971 innobase_commit_concurrency_init_default();
3972
3973 /* Do not enable backoff algorithm for small buffer pool. */
3974 if (!innodb_empty_free_list_algorithm_allowed(
3975 static_cast<srv_empty_free_list_t>(
3976 srv_empty_free_list_algorithm))) {
3977 sql_print_information(
3978 "InnoDB: innodb_empty_free_list_algorithm "
3979 "has been changed to legacy "
3980 "because of small buffer pool size. "
3981 "In order to use backoff, "
3982 "increase buffer pool at least up to 20MB.\n");
3983 srv_empty_free_list_algorithm
3984 = SRV_EMPTY_FREE_LIST_LEGACY;
3985 }
3986
3987 srv_use_atomic_writes = (ibool) innobase_use_atomic_writes;
3988 if (innobase_use_atomic_writes) {
3989 ib_logf(IB_LOG_LEVEL_INFO, "using atomic writes.");
3990
3991 /* Force doublewrite buffer off, atomic writes replace it. */
3992 if (srv_use_doublewrite_buf) {
3993 ib_logf(IB_LOG_LEVEL_INFO, "switching off doublewrite "
3994 "buffer because of atomic writes.");
3995 innobase_use_doublewrite = FALSE;
3996 srv_use_doublewrite_buf = FALSE;
3997 }
3998
3999 /* Force O_DIRECT on Unixes (on Windows writes are always
4000 unbuffered)*/
4001 #ifndef _WIN32
4002 if(!innobase_file_flush_method ||
4003 !strstr(innobase_file_flush_method, "O_DIRECT")) {
4004 innobase_file_flush_method =
4005 srv_file_flush_method_str = (char*)"O_DIRECT";
4006 ib_logf(IB_LOG_LEVEL_INFO,
4007 "using O_DIRECT due to atomic writes.");
4008 }
4009 #endif
4010 #ifdef HAVE_POSIX_FALLOCATE
4011 /* Due to a bug in directFS, using atomics needs
4012 posix_fallocate() to extend the file, because pwrite() past the
4013 end of the file won't work */
4014 srv_use_posix_fallocate = TRUE;
4015 #endif
4016 }
4017
4018 #ifdef HAVE_PSI_INTERFACE
4019 /* Register keys with MySQL performance schema */
4020 int count;
4021
4022 count = array_elements(all_pthread_mutexes);
4023 mysql_mutex_register("innodb", all_pthread_mutexes, count);
4024
4025 # ifdef UNIV_PFS_MUTEX
4026 count = array_elements(all_innodb_mutexes);
4027 mysql_mutex_register("innodb", all_innodb_mutexes, count);
4028 # endif /* UNIV_PFS_MUTEX */
4029
4030 # ifdef UNIV_PFS_RWLOCK
4031 count = array_elements(all_innodb_rwlocks);
4032 mysql_rwlock_register("innodb", all_innodb_rwlocks, count);
4033 # endif /* UNIV_PFS_MUTEX */
4034
4035 # ifdef UNIV_PFS_THREAD
4036 count = array_elements(all_innodb_threads);
4037 mysql_thread_register("innodb", all_innodb_threads, count);
4038 # endif /* UNIV_PFS_THREAD */
4039
4040 # ifdef UNIV_PFS_IO
4041 count = array_elements(all_innodb_files);
4042 mysql_file_register("innodb", all_innodb_files, count);
4043 # endif /* UNIV_PFS_IO */
4044
4045 count = array_elements(all_innodb_conds);
4046 mysql_cond_register("innodb", all_innodb_conds, count);
4047 #endif /* HAVE_PSI_INTERFACE */
4048
4049 /* Since we in this module access directly the fields of a trx
4050 struct, and due to different headers and flags it might happen that
4051 ib_mutex_t has a different size in this module and in InnoDB
4052 modules, we check at run time that the size is the same in
4053 these compilation modules. */
4054
4055 err = innobase_start_or_create_for_mysql();
4056
4057 if (err != DB_SUCCESS) {
4058 goto mem_free_and_error;
4059 }
4060
4061 /* Adjust the innodb_undo_logs config object */
4062 innobase_undo_logs_init_default_max();
4063
4064 innobase_old_blocks_pct = static_cast<uint>(
4065 buf_LRU_old_ratio_update(innobase_old_blocks_pct, TRUE));
4066
4067 ibuf_max_size_update(innobase_change_buffer_max_size);
4068
4069 innobase_open_tables = hash_create(200);
4070 mysql_mutex_init(innobase_share_mutex_key,
4071 &innobase_share_mutex,
4072 MY_MUTEX_INIT_FAST);
4073 mysql_mutex_init(commit_cond_mutex_key,
4074 &commit_cond_m, MY_MUTEX_INIT_FAST);
4075 mysql_cond_init(commit_cond_key, &commit_cond, NULL);
4076 innodb_inited= 1;
4077 #ifdef MYSQL_DYNAMIC_PLUGIN
4078 if (innobase_hton != p) {
4079 innobase_hton = reinterpret_cast<handlerton*>(p);
4080 *innobase_hton = *innodb_hton_ptr;
4081 }
4082 #endif /* MYSQL_DYNAMIC_PLUGIN */
4083
4084 /* Get the current high water mark format. */
4085 innobase_file_format_max = (char*) trx_sys_file_format_max_get();
4086
4087 /* Currently, monitor counter information are not persistent. */
4088 memset(monitor_set_tbl, 0, sizeof monitor_set_tbl);
4089
4090 memset(innodb_counter_value, 0, sizeof innodb_counter_value);
4091
4092 /* Do this as late as possible so server is fully starts up,
4093 since we might get some initial stats if user choose to turn
4094 on some counters from start up */
4095 if (innobase_enable_monitor_counter) {
4096 innodb_enable_monitor_at_startup(
4097 innobase_enable_monitor_counter);
4098 }
4099
4100 /* Turn on monitor counters that are default on */
4101 srv_mon_default_on();
4102
4103 #ifndef UNIV_HOTBACKUP
4104 #ifdef _WIN32
4105 if (ut_win_init_time()) {
4106 goto mem_free_and_error;
4107 }
4108 #endif /* _WIN32 */
4109 #endif /* !UNIV_HOTBACKUP */
4110
4111 DBUG_RETURN(FALSE);
4112 error:
4113 DBUG_RETURN(TRUE);
4114 }
4115
4116 /*******************************************************************//**
4117 Closes an InnoDB database.
4118 @return TRUE if error */
4119 static
4120 int
innobase_end(handlerton * hton,ha_panic_function type MY_ATTRIBUTE ((unused)))4121 innobase_end(
4122 /*=========*/
4123 handlerton* hton, /*!< in/out: InnoDB handlerton */
4124 ha_panic_function type MY_ATTRIBUTE((unused)))
4125 /*!< in: ha_panic() parameter */
4126 {
4127 int err= 0;
4128
4129 DBUG_ENTER("innobase_end");
4130 DBUG_ASSERT(hton == innodb_hton_ptr);
4131
4132 if (innodb_inited) {
4133
4134 srv_fast_shutdown = (ulint) innobase_fast_shutdown;
4135
4136 innodb_inited = 0;
4137 hash_table_free(innobase_open_tables);
4138 innobase_open_tables = NULL;
4139 if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
4140 err = 1;
4141 }
4142 srv_free_paths_and_sizes();
4143 my_free(internal_innobase_data_file_path);
4144 mysql_mutex_destroy(&innobase_share_mutex);
4145 mysql_mutex_destroy(&commit_cond_m);
4146 mysql_cond_destroy(&commit_cond);
4147 }
4148
4149 DBUG_RETURN(err);
4150 }
4151
4152 /****************************************************************//**
4153 Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
4154 the logs, and the name of this function should be innobase_checkpoint.
4155 @return TRUE if error */
4156 static
4157 bool
innobase_flush_logs(handlerton * hton)4158 innobase_flush_logs(
4159 /*================*/
4160 handlerton* hton) /*!< in/out: InnoDB handlerton */
4161 {
4162 bool result = 0;
4163
4164 DBUG_ENTER("innobase_flush_logs");
4165 DBUG_ASSERT(hton == innodb_hton_ptr);
4166
4167 if (!srv_read_only_mode) {
4168 log_buffer_flush_to_disk();
4169 }
4170
4171 DBUG_RETURN(result);
4172 }
4173
4174 /************************************************************//**
4175 Synchronously read and parse the redo log up to the last
4176 checkpoint to write the changed page bitmap.
4177 @return 0 to indicate success. Current implementation cannot fail. */
4178 static
4179 my_bool
innobase_flush_changed_page_bitmaps()4180 innobase_flush_changed_page_bitmaps()
4181 /*=================================*/
4182 {
4183 if (srv_track_changed_pages) {
4184 os_event_reset(srv_checkpoint_completed_event);
4185 log_online_follow_redo_log();
4186 }
4187 return FALSE;
4188 }
4189
4190 /************************************************************//**
4191 Delete all the bitmap files for data less than the specified LSN.
4192 If called with lsn == IB_ULONGLONG_MAX (i.e. set by RESET request),
4193 restart the bitmap file sequence, otherwise continue it.
4194 @return 0 to indicate success, 1 for failure. */
4195 static
4196 my_bool
innobase_purge_changed_page_bitmaps(ulonglong lsn)4197 innobase_purge_changed_page_bitmaps(
4198 /*================================*/
4199 ulonglong lsn) /*!< in: LSN to purge files up to */
4200 {
4201 return (my_bool)log_online_purge_changed_page_bitmaps(lsn);
4202 }
4203
4204 /** Creates a new compression dictionary. */
4205 static
4206 handler_create_zip_dict_result
innobase_create_zip_dict(handlerton * hton,THD * thd,const char * name,ulint * name_len,const char * data,ulint * data_len)4207 innobase_create_zip_dict(
4208 handlerton* hton, /*!< in: innobase handlerton */
4209 THD* thd, /*!< in: handle to the MySQL thread */
4210 const char* name, /*!< in: zip dictionary name */
4211 ulint* name_len,
4212 /*!< in/out: zip dictionary name length */
4213 const char* data, /*!< in: zip dictionary data */
4214 ulint* data_len)
4215 /*!< in/out: zip dictionary data length */
4216 {
4217 handler_create_zip_dict_result result =
4218 HA_CREATE_ZIP_DICT_UNKNOWN_ERROR;
4219
4220 DBUG_ENTER("innobase_create_zip_dict");
4221 DBUG_ASSERT(hton == innodb_hton_ptr);
4222
4223 if (UNIV_UNLIKELY(high_level_read_only)) {
4224 DBUG_RETURN(HA_CREATE_ZIP_DICT_READ_ONLY);
4225 }
4226
4227 if (UNIV_UNLIKELY(THDVAR(NULL, fake_changes))) {
4228 DBUG_RETURN(HA_CREATE_ZIP_DICT_FAKE_CHANGES);
4229 }
4230
4231 if (UNIV_UNLIKELY(*name_len > ZIP_DICT_MAX_NAME_LENGTH)) {
4232 *name_len = ZIP_DICT_MAX_NAME_LENGTH;
4233 DBUG_RETURN(HA_CREATE_ZIP_DICT_NAME_TOO_LONG);
4234 }
4235
4236 if (UNIV_UNLIKELY(*data_len > ZIP_DICT_MAX_DATA_LENGTH)) {
4237 *data_len = ZIP_DICT_MAX_DATA_LENGTH;
4238 DBUG_RETURN(HA_CREATE_ZIP_DICT_DATA_TOO_LONG);
4239 }
4240
4241 switch (dict_create_zip_dict(name, *name_len, data, *data_len)) {
4242 case DB_SUCCESS:
4243 result = HA_CREATE_ZIP_DICT_OK;
4244 break;
4245 case DB_DUPLICATE_KEY:
4246 result = HA_CREATE_ZIP_DICT_ALREADY_EXISTS;
4247 break;
4248 case DB_OUT_OF_MEMORY:
4249 result = HA_CREATE_ZIP_DICT_OUT_OF_MEMORY;
4250 break;
4251 case DB_OUT_OF_FILE_SPACE:
4252 result = HA_CREATE_ZIP_DICT_OUT_OF_FILE_SPACE;
4253 break;
4254 case DB_TOO_MANY_CONCURRENT_TRXS:
4255 result = HA_CREATE_ZIP_DICT_TOO_MANY_CONCURRENT_TRXS;
4256 break;
4257 default:
4258 ut_ad(0);
4259 result = HA_CREATE_ZIP_DICT_UNKNOWN_ERROR;
4260 }
4261 DBUG_RETURN(result);
4262 }
4263
4264 /** Drops a existing compression dictionary. */
4265 static
4266 handler_drop_zip_dict_result
innobase_drop_zip_dict(handlerton * hton,THD * thd,const char * name,ulint * name_len)4267 innobase_drop_zip_dict(
4268 handlerton* hton, /*!< in: innobase handlerton */
4269 THD* thd, /*!< in: handle to the MySQL thread */
4270 const char* name, /*!< in: zip dictionary name */
4271 ulint* name_len)
4272 /*!< in/out: zip dictionary name length */
4273 {
4274 handler_drop_zip_dict_result result = HA_DROP_ZIP_DICT_UNKNOWN_ERROR;
4275
4276 DBUG_ENTER("innobase_drop_zip_dict");
4277 DBUG_ASSERT(hton == innodb_hton_ptr);
4278
4279 if (UNIV_UNLIKELY(high_level_read_only)) {
4280 DBUG_RETURN(HA_DROP_ZIP_DICT_READ_ONLY);
4281 }
4282
4283 if (UNIV_UNLIKELY(THDVAR(NULL, fake_changes))) {
4284 DBUG_RETURN(HA_DROP_ZIP_DICT_FAKE_CHANGES);
4285 }
4286
4287 switch (dict_drop_zip_dict(name, *name_len)) {
4288 case DB_SUCCESS:
4289 result = HA_DROP_ZIP_DICT_OK;
4290 break;
4291 case DB_RECORD_NOT_FOUND:
4292 result = HA_DROP_ZIP_DICT_DOES_NOT_EXIST;
4293 break;
4294 case DB_ROW_IS_REFERENCED:
4295 result = HA_DROP_ZIP_DICT_IS_REFERENCED;
4296 break;
4297 case DB_OUT_OF_MEMORY:
4298 result = HA_DROP_ZIP_DICT_OUT_OF_MEMORY;
4299 break;
4300 case DB_OUT_OF_FILE_SPACE:
4301 result = HA_DROP_ZIP_DICT_OUT_OF_FILE_SPACE;
4302 break;
4303 case DB_TOO_MANY_CONCURRENT_TRXS:
4304 result = HA_DROP_ZIP_DICT_TOO_MANY_CONCURRENT_TRXS;
4305 break;
4306 default:
4307 ut_ad(0);
4308 result = HA_DROP_ZIP_DICT_UNKNOWN_ERROR;
4309 }
4310 DBUG_RETURN(result);
4311 }
4312
4313 /*****************************************************************//**
4314 Check whether this is a fake change transaction.
4315 @return TRUE if a fake change transaction */
4316 static
4317 my_bool
innobase_is_fake_change(handlerton * hton MY_ATTRIBUTE ((unused)),THD * thd)4318 innobase_is_fake_change(
4319 /*====================*/
4320 handlerton *hton MY_ATTRIBUTE((unused)),
4321 /*!< in: InnoDB handlerton */
4322 THD* thd) /*!< in: MySQL thread handle of the user for
4323 whom the transaction is being committed */
4324 {
4325 trx_t* trx = check_trx_exists(thd);
4326 return UNIV_UNLIKELY(trx->fake_changes);
4327 }
4328
4329 /*****************************************************************//**
4330 Commits a transaction in an InnoDB database. */
4331 static
4332 void
innobase_commit_low(trx_t * trx)4333 innobase_commit_low(
4334 /*================*/
4335 trx_t* trx) /*!< in: transaction handle */
4336 {
4337 if (trx_is_started(trx)) {
4338
4339 trx_commit_for_mysql(trx);
4340 }
4341 }
4342
4343 /*****************************************************************//**
4344 Stores the current binlog coordinates in the trx system header. */
4345 static
4346 int
innobase_store_binlog_info(handlerton * hton,THD * thd)4347 innobase_store_binlog_info(
4348 /*=======================*/
4349 handlerton* hton, /*!< in: InnoDB handlerton */
4350 THD* thd) /*!< in: MySQL thread handle */
4351 {
4352 const char* file_name;
4353 unsigned long long pos;
4354 mtr_t mtr;
4355
4356 DBUG_ENTER("innobase_store_binlog_info");
4357
4358 thd_binlog_pos(thd, &file_name, &pos);
4359
4360 mtr_start(&mtr);
4361
4362 trx_sys_update_mysql_binlog_offset(file_name, pos,
4363 TRX_SYS_MYSQL_LOG_INFO, &mtr);
4364
4365 mtr_commit(&mtr);
4366
4367 innobase_flush_logs(hton);
4368
4369 DBUG_RETURN(0);
4370 }
4371
4372 /*****************************************************************//**
4373 Creates an InnoDB transaction struct for the thd if it does not yet have one.
4374 Starts a new InnoDB transaction if a transaction is not yet started. And
4375 assigns a new snapshot for a consistent read if the transaction does not yet
4376 have one.
4377 @return 0 */
4378 static
4379 int
innobase_start_trx_and_assign_read_view(handlerton * hton,THD * thd)4380 innobase_start_trx_and_assign_read_view(
4381 /*====================================*/
4382 handlerton* hton, /*!< in: Innodb handlerton */
4383 THD* thd) /*!< in: MySQL thread handle of the user for
4384 whom the transaction should be committed */
4385 {
4386 trx_t* trx;
4387
4388 DBUG_ENTER("innobase_start_trx_and_assign_read_view");
4389 DBUG_ASSERT(hton == innodb_hton_ptr);
4390
4391 /* Create a new trx struct for thd, if it does not yet have one */
4392
4393 trx = check_trx_exists(thd);
4394
4395 /* This is just to play safe: release a possible FIFO ticket and
4396 search latch. Since we can potentially reserve the trx_sys->mutex,
4397 we have to release the search system latch first to obey the latching
4398 order. */
4399
4400 trx_search_latch_release_if_reserved(trx);
4401
4402 innobase_srv_conc_force_exit_innodb(trx);
4403
4404 /* If the transaction is not started yet, start it */
4405
4406 trx_start_if_not_started_xa(trx);
4407
4408 /* Assign a read view if the transaction does not have it yet.
4409 Do this only if transaction is using REPEATABLE READ isolation
4410 level. */
4411 trx->isolation_level = innobase_map_isolation_level(
4412 thd_get_trx_isolation(thd));
4413
4414 if (trx->isolation_level == TRX_ISO_REPEATABLE_READ) {
4415 trx_assign_read_view(trx);
4416 } else {
4417 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4418 HA_ERR_UNSUPPORTED,
4419 "InnoDB: WITH CONSISTENT SNAPSHOT "
4420 "was ignored because this phrase "
4421 "can only be used with "
4422 "REPEATABLE READ isolation level.");
4423 }
4424
4425 /* Set the MySQL flag to mark that there is an active transaction */
4426
4427 innobase_register_trx(hton, current_thd, trx);
4428
4429 DBUG_RETURN(0);
4430 }
4431
4432
4433 /*****************************************************************//**
4434 Creates an InnoDB transaction struct for the thd if it does not yet have one.
4435 Starts a new InnoDB transaction if a transaction is not yet started. And
4436 clones snapshot for a consistent read from another session, if it has one.
4437 @return 0 */
4438 static
4439 int
innobase_start_trx_and_clone_read_view(handlerton * hton,THD * thd,THD * from_thd)4440 innobase_start_trx_and_clone_read_view(
4441 /*====================================*/
4442 handlerton* hton, /* in: Innodb handlerton */
4443 THD* thd, /* in: MySQL thread handle of the
4444 user for whom the transaction should
4445 be committed */
4446 THD* from_thd) /* in: MySQL thread handle of the
4447 user session from which the consistent
4448 read should be cloned */
4449 {
4450 trx_t* trx;
4451 trx_t* from_trx;
4452
4453 DBUG_ENTER("innobase_start_trx_and_clone_read_view");
4454 DBUG_ASSERT(hton == innodb_hton_ptr);
4455
4456 /* Get transaction handle from the donor session */
4457
4458 from_trx = thd_to_trx(from_thd);
4459
4460 if (!from_trx) {
4461 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4462 HA_ERR_UNSUPPORTED,
4463 "InnoDB: WITH CONSISTENT SNAPSHOT "
4464 "FROM SESSION was ignored because the "
4465 "specified session does not have an open "
4466 "transaction inside InnoDB.");
4467
4468 DBUG_RETURN(0);
4469 }
4470
4471 /* Create a new trx struct for thd, if it does not yet have one */
4472
4473 trx = check_trx_exists(thd);
4474
4475 /* This is just to play safe: release a possible FIFO ticket and
4476 search latch. Since we can potentially reserve the trx_sys->mutex,
4477 we have to release the search system latch first to obey the latching
4478 order. */
4479
4480 trx_search_latch_release_if_reserved(trx);
4481
4482 innobase_srv_conc_force_exit_innodb(trx);
4483
4484 /* If the transaction is not started yet, start it */
4485
4486 trx_start_if_not_started_xa(trx);
4487
4488 /* Clone the read view from the donor transaction. Do this only if
4489 transaction is using REPEATABLE READ isolation level. */
4490 trx->isolation_level = innobase_map_isolation_level(
4491 thd_get_trx_isolation(thd));
4492
4493 if (trx->isolation_level != TRX_ISO_REPEATABLE_READ) {
4494
4495 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4496 HA_ERR_UNSUPPORTED,
4497 "InnoDB: WITH CONSISTENT SNAPSHOT "
4498 "was ignored because this phrase "
4499 "can only be used with "
4500 "REPEATABLE READ isolation level.");
4501 } else {
4502
4503 lock_mutex_enter();
4504 mutex_enter(&trx_sys->mutex);
4505 trx_mutex_enter(from_trx);
4506
4507 if (!trx_clone_read_view(trx, from_trx)) {
4508
4509 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4510 HA_ERR_UNSUPPORTED,
4511 "InnoDB: WITH CONSISTENT SNAPSHOT "
4512 "FROM SESSION was ignored because "
4513 "the target transaction has not been "
4514 "assigned a read view.");
4515 }
4516
4517 trx_mutex_exit(from_trx);
4518 mutex_exit(&trx_sys->mutex);
4519 lock_mutex_exit();
4520 }
4521
4522 /* Set the MySQL flag to mark that there is an active transaction */
4523
4524 innobase_register_trx(hton, current_thd, trx);
4525
4526 DBUG_RETURN(0);
4527 }
4528
4529 /*****************************************************************//**
4530 Commits a transaction in an InnoDB database or marks an SQL statement
4531 ended.
4532 @return 0 */
4533 static
4534 int
innobase_commit(handlerton * hton,THD * thd,bool commit_trx)4535 innobase_commit(
4536 /*============*/
4537 handlerton* hton, /*!< in: Innodb handlerton */
4538 THD* thd, /*!< in: MySQL thread handle of the
4539 user for whom the transaction should
4540 be committed */
4541 bool commit_trx) /*!< in: true - commit transaction
4542 false - the current SQL statement
4543 ended */
4544 {
4545 trx_t* trx;
4546
4547 DBUG_ENTER("innobase_commit");
4548 DBUG_ASSERT(hton == innodb_hton_ptr);
4549 DBUG_PRINT("trans", ("ending transaction"));
4550
4551 trx = check_trx_exists(thd);
4552
4553 /* Since we will reserve the trx_sys->mutex, we have to release
4554 the search system latch first to obey the latching order. */
4555
4556 /* No-op in XtraDB */
4557 trx_search_latch_release_if_reserved(trx);
4558
4559 /* If fake-changes mode = ON then allow
4560 SELECT (they are read-only) and
4561 CREATE ... SELECT * from table (Well this doesn't open up DDL for InnoDB
4562 as ha_innobase::create will return appropriate error if fake-change = ON
4563 but if create is trying to use other SE and SELECT is executing on
4564 InnoDB table then we allow SELECT to proceed.
4565 Ideally, statement like this should be marked CREATE_SELECT like
4566 INSERT_SELECT but unfortunately it doesn't). */
4567 if (UNIV_UNLIKELY(trx->fake_changes
4568 && (thd_sql_command(thd) != SQLCOM_SELECT
4569 && thd_sql_command(thd) != SQLCOM_CREATE_TABLE)
4570 && (commit_trx || (!thd_test_options(thd,
4571 OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))))) {
4572
4573 /* rollback implicitly */
4574 innobase_rollback(hton, thd, commit_trx);
4575
4576 /* because debug assertion code complains, if something left */
4577 thd->get_stmt_da()->reset_diagnostics_area();
4578
4579 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
4580 }
4581 /* Transaction is deregistered only in a commit or a rollback. If
4582 it is deregistered we know there cannot be resources to be freed
4583 and we could return immediately. For the time being, we play safe
4584 and do the cleanup though there should be nothing to clean up. */
4585
4586 if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
4587
4588 sql_print_error("Transaction not registered for MySQL 2PC, "
4589 "but transaction is active");
4590 }
4591
4592 if (commit_trx
4593 || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
4594
4595 DBUG_EXECUTE_IF("crash_innodb_before_commit",
4596 DBUG_SUICIDE(););
4597
4598 /* We were instructed to commit the whole transaction, or
4599 this is an SQL statement end and autocommit is on */
4600
4601 /* We need current binlog position for mysqlbackup to work. */
4602 retry:
4603 if (innobase_commit_concurrency > 0) {
4604 mysql_mutex_lock(&commit_cond_m);
4605 commit_threads++;
4606
4607 if (commit_threads > innobase_commit_concurrency) {
4608 commit_threads--;
4609 mysql_cond_wait(&commit_cond,
4610 &commit_cond_m);
4611 mysql_mutex_unlock(&commit_cond_m);
4612 goto retry;
4613 }
4614 else {
4615 mysql_mutex_unlock(&commit_cond_m);
4616 }
4617 }
4618
4619 /* The following call read the binary log position of
4620 the transaction being committed.
4621
4622 Binary logging of other engines is not relevant to
4623 InnoDB as all InnoDB requires is that committing
4624 InnoDB transactions appear in the same order in the
4625 MySQL binary log as they appear in InnoDB logs, which
4626 is guaranteed by the server.
4627
4628 If the binary log is not enabled, or the transaction
4629 is not written to the binary log, the file name will
4630 be a NULL pointer. */
4631 unsigned long long pos;
4632 thd_binlog_pos(thd, &trx->mysql_log_file_name, &pos);
4633 trx->mysql_log_offset= static_cast<ib_int64_t>(pos);
4634 /* Don't do write + flush right now. For group commit
4635 to work we want to do the flush later. */
4636 trx->flush_log_later = TRUE;
4637 innobase_commit_low(trx);
4638 trx->flush_log_later = FALSE;
4639
4640 if (innobase_commit_concurrency > 0) {
4641 mysql_mutex_lock(&commit_cond_m);
4642 commit_threads--;
4643 mysql_cond_signal(&commit_cond);
4644 mysql_mutex_unlock(&commit_cond_m);
4645 }
4646
4647 trx_deregister_from_2pc(trx);
4648
4649 /* Now do a write + flush of logs. */
4650 trx_commit_complete_for_mysql(trx);
4651 } else {
4652 /* We just mark the SQL statement ended and do not do a
4653 transaction commit */
4654
4655 /* If we had reserved the auto-inc lock for some
4656 table in this SQL statement we release it now */
4657
4658 lock_unlock_table_autoinc(trx);
4659
4660 /* Store the current undo_no of the transaction so that we
4661 know where to roll back if we have to roll back the next
4662 SQL statement */
4663
4664 trx_mark_sql_stat_end(trx);
4665 }
4666
4667 trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
4668
4669 /* This is a statement level variable. */
4670 trx->fts_next_doc_id = 0;
4671
4672 innobase_srv_conc_force_exit_innodb(trx);
4673
4674 DBUG_RETURN(0);
4675 }
4676
4677 /*****************************************************************//**
4678 Rolls back a transaction or the latest SQL statement.
4679 @return 0 or error number */
4680 static
4681 int
innobase_rollback(handlerton * hton,THD * thd,bool rollback_trx)4682 innobase_rollback(
4683 /*==============*/
4684 handlerton* hton, /*!< in: Innodb handlerton */
4685 THD* thd, /*!< in: handle to the MySQL thread
4686 of the user whose transaction should
4687 be rolled back */
4688 bool rollback_trx) /*!< in: TRUE - rollback entire
4689 transaction FALSE - rollback the current
4690 statement only */
4691 {
4692 dberr_t error;
4693 trx_t* trx;
4694
4695 DBUG_ENTER("innobase_rollback");
4696 DBUG_ASSERT(hton == innodb_hton_ptr);
4697 DBUG_PRINT("trans", ("aborting transaction"));
4698
4699 trx = check_trx_exists(thd);
4700
4701 /* Release a possible FIFO ticket and search latch. Since we will
4702 reserve the trx_sys->mutex, we have to release the search system
4703 latch first to obey the latching order. */
4704
4705 trx_search_latch_release_if_reserved(trx);
4706
4707 innobase_srv_conc_force_exit_innodb(trx);
4708
4709 trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
4710
4711 /* If we had reserved the auto-inc lock for some table (if
4712 we come here to roll back the latest SQL statement) we
4713 release it now before a possibly lengthy rollback */
4714
4715 lock_unlock_table_autoinc(trx);
4716
4717 /* This is a statement level variable. */
4718 trx->fts_next_doc_id = 0;
4719
4720 if (rollback_trx
4721 || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
4722
4723 error = trx_rollback_for_mysql(trx);
4724 trx_deregister_from_2pc(trx);
4725 } else {
4726 error = trx_rollback_last_sql_stat_for_mysql(trx);
4727 }
4728
4729 DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
4730 }
4731
4732 /*****************************************************************//**
4733 Rolls back a transaction
4734 @return 0 or error number */
4735 static
4736 int
innobase_rollback_trx(trx_t * trx)4737 innobase_rollback_trx(
4738 /*==================*/
4739 trx_t* trx) /*!< in: transaction */
4740 {
4741 dberr_t error = DB_SUCCESS;
4742
4743 DBUG_ENTER("innobase_rollback_trx");
4744 DBUG_PRINT("trans", ("aborting transaction"));
4745
4746 /* Release a possible FIFO ticket and search latch. Since we will
4747 reserve the trx_sys->mutex, we have to release the search system
4748 latch first to obey the latching order. */
4749
4750 trx_search_latch_release_if_reserved(trx);
4751
4752 innobase_srv_conc_force_exit_innodb(trx);
4753
4754 /* If we had reserved the auto-inc lock for some table (if
4755 we come here to roll back the latest SQL statement) we
4756 release it now before a possibly lengthy rollback */
4757
4758 lock_unlock_table_autoinc(trx);
4759
4760 if (!trx->read_only) {
4761 error = trx_rollback_for_mysql(trx);
4762 }
4763
4764 DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
4765 }
4766
4767 /*****************************************************************//**
4768 Rolls back a transaction to a savepoint.
4769 @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
4770 given name */
4771 static
4772 int
innobase_rollback_to_savepoint(handlerton * hton,THD * thd,void * savepoint)4773 innobase_rollback_to_savepoint(
4774 /*===========================*/
4775 handlerton* hton, /*!< in: Innodb handlerton */
4776 THD* thd, /*!< in: handle to the MySQL thread
4777 of the user whose transaction should
4778 be rolled back to savepoint */
4779 void* savepoint) /*!< in: savepoint data */
4780 {
4781 ib_int64_t mysql_binlog_cache_pos;
4782 dberr_t error;
4783 trx_t* trx;
4784 char name[64];
4785
4786 DBUG_ENTER("innobase_rollback_to_savepoint");
4787 DBUG_ASSERT(hton == innodb_hton_ptr);
4788
4789 trx = check_trx_exists(thd);
4790
4791 /* Release a possible FIFO ticket and search latch. Since we will
4792 reserve the trx_sys->mutex, we have to release the search system
4793 latch first to obey the latching order. */
4794
4795 trx_search_latch_release_if_reserved(trx);
4796
4797 innobase_srv_conc_force_exit_innodb(trx);
4798
4799 /* TODO: use provided savepoint data area to store savepoint data */
4800
4801 longlong2str((ulint) savepoint, name, 36);
4802
4803 error = trx_rollback_to_savepoint_for_mysql(
4804 trx, name, &mysql_binlog_cache_pos);
4805
4806 if (error == DB_SUCCESS && trx->fts_trx != NULL) {
4807 fts_savepoint_rollback(trx, name);
4808 }
4809
4810 DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
4811 }
4812
4813 /*****************************************************************//**
4814 Check whether innodb state allows to safely release MDL locks after
4815 rollback to savepoint.
4816 When binlog is on, MDL locks acquired after savepoint unit are not
4817 released if there are any locks held in InnoDB.
4818 @return true if it is safe, false if its not safe. */
4819 static
4820 bool
innobase_rollback_to_savepoint_can_release_mdl(handlerton * hton,THD * thd)4821 innobase_rollback_to_savepoint_can_release_mdl(
4822 /*===========================================*/
4823 handlerton* hton, /*!< in: InnoDB handlerton */
4824 THD* thd) /*!< in: handle to the MySQL thread
4825 of the user whose transaction should
4826 be rolled back to savepoint */
4827 {
4828 trx_t* trx;
4829
4830 DBUG_ENTER("innobase_rollback_to_savepoint_can_release_mdl");
4831 DBUG_ASSERT(hton == innodb_hton_ptr);
4832
4833 trx = check_trx_exists(thd);
4834 ut_ad(trx);
4835
4836 /* If transaction has not acquired any locks then it is safe
4837 to release MDL after rollback to savepoint */
4838 if (!(UT_LIST_GET_LEN(trx->lock.trx_locks))) {
4839 DBUG_RETURN(true);
4840 }
4841
4842 DBUG_RETURN(false);
4843 }
4844
4845 /*****************************************************************//**
4846 Release transaction savepoint name.
4847 @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
4848 given name */
4849 static
4850 int
innobase_release_savepoint(handlerton * hton,THD * thd,void * savepoint)4851 innobase_release_savepoint(
4852 /*=======================*/
4853 handlerton* hton, /*!< in: handlerton for Innodb */
4854 THD* thd, /*!< in: handle to the MySQL thread
4855 of the user whose transaction's
4856 savepoint should be released */
4857 void* savepoint) /*!< in: savepoint data */
4858 {
4859 dberr_t error;
4860 trx_t* trx;
4861 char name[64];
4862
4863 DBUG_ENTER("innobase_release_savepoint");
4864 DBUG_ASSERT(hton == innodb_hton_ptr);
4865
4866 trx = check_trx_exists(thd);
4867
4868 /* TODO: use provided savepoint data area to store savepoint data */
4869
4870 longlong2str((ulint) savepoint, name, 36);
4871
4872 error = trx_release_savepoint_for_mysql(trx, name);
4873
4874 if (error == DB_SUCCESS && trx->fts_trx != NULL) {
4875 fts_savepoint_release(trx, name);
4876 }
4877
4878 DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
4879 }
4880
4881 /*****************************************************************//**
4882 Sets a transaction savepoint.
4883 @return always 0, that is, always succeeds */
4884 static
4885 int
innobase_savepoint(handlerton * hton,THD * thd,void * savepoint)4886 innobase_savepoint(
4887 /*===============*/
4888 handlerton* hton, /*!< in: handle to the Innodb handlerton */
4889 THD* thd, /*!< in: handle to the MySQL thread */
4890 void* savepoint) /*!< in: savepoint data */
4891 {
4892 dberr_t error;
4893 trx_t* trx;
4894
4895 DBUG_ENTER("innobase_savepoint");
4896 DBUG_ASSERT(hton == innodb_hton_ptr);
4897
4898 /* In the autocommit mode there is no sense to set a savepoint
4899 (unless we are in sub-statement), so SQL layer ensures that
4900 this method is never called in such situation. */
4901
4902 trx = check_trx_exists(thd);
4903
4904 /* Release a possible FIFO ticket and search latch. Since we will
4905 reserve the trx_sys->mutex, we have to release the search system
4906 latch first to obey the latching order. */
4907
4908 trx_search_latch_release_if_reserved(trx);
4909
4910 innobase_srv_conc_force_exit_innodb(trx);
4911
4912 /* Cannot happen outside of transaction */
4913 DBUG_ASSERT(trx_is_registered_for_2pc(trx));
4914
4915 /* TODO: use provided savepoint data area to store savepoint data */
4916 char name[64];
4917 longlong2str((ulint) savepoint,name,36);
4918
4919 error = trx_savepoint_for_mysql(trx, name, (ib_int64_t)0);
4920
4921 if (error == DB_SUCCESS && trx->fts_trx != NULL) {
4922 fts_savepoint_take(trx, trx->fts_trx, name);
4923 }
4924
4925 DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
4926 }
4927
4928 /*****************************************************************//**
4929 Frees a possible InnoDB trx object associated with the current THD.
4930 @return 0 or error number */
4931 static
4932 int
innobase_close_connection(handlerton * hton,THD * thd)4933 innobase_close_connection(
4934 /*======================*/
4935 handlerton* hton, /*!< in: innobase handlerton */
4936 THD* thd) /*!< in: handle to the MySQL thread of the user
4937 whose resources should be free'd */
4938 {
4939 trx_t* trx;
4940
4941 DBUG_ENTER("innobase_close_connection");
4942 DBUG_ASSERT(hton == innodb_hton_ptr);
4943 trx = thd_to_trx(thd);
4944
4945 ut_a(trx);
4946
4947 if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
4948
4949 sql_print_error("Transaction not registered for MySQL 2PC, "
4950 "but transaction is active");
4951 }
4952
4953 if (trx_is_started(trx) && log_warnings) {
4954
4955 sql_print_warning(
4956 "MySQL is closing a connection that has an active "
4957 "InnoDB transaction. " TRX_ID_FMT " row modifications "
4958 "will roll back.",
4959 trx->undo_no);
4960 }
4961
4962 innobase_rollback_trx(trx);
4963
4964 trx_free_for_mysql(trx);
4965
4966 DBUG_RETURN(0);
4967 }
4968
4969 /*****************************************************************//**
4970 Frees a possible InnoDB trx object associated with the current THD.
4971 @return 0 or error number */
4972 UNIV_INTERN
4973 int
innobase_close_thd(THD * thd)4974 innobase_close_thd(
4975 /*===============*/
4976 THD* thd) /*!< in: handle to the MySQL thread of the user
4977 whose resources should be free'd */
4978 {
4979 trx_t* trx = thd_to_trx(thd);
4980
4981 if (!trx) {
4982 return(0);
4983 }
4984
4985 return(innobase_close_connection(innodb_hton_ptr, thd));
4986 }
4987
4988 /*************************************************************************//**
4989 ** InnoDB database tables
4990 *****************************************************************************/
4991
4992 /****************************************************************//**
4993 Get the record format from the data dictionary.
4994 @return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
4995 ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
4996 UNIV_INTERN
4997 enum row_type
get_row_type() const4998 ha_innobase::get_row_type() const
4999 /*=============================*/
5000 {
5001 if (prebuilt && prebuilt->table) {
5002 const ulint flags = prebuilt->table->flags;
5003
5004 switch (dict_tf_get_rec_format(flags)) {
5005 case REC_FORMAT_REDUNDANT:
5006 return(ROW_TYPE_REDUNDANT);
5007 case REC_FORMAT_COMPACT:
5008 return(ROW_TYPE_COMPACT);
5009 case REC_FORMAT_COMPRESSED:
5010 return(ROW_TYPE_COMPRESSED);
5011 case REC_FORMAT_DYNAMIC:
5012 return(ROW_TYPE_DYNAMIC);
5013 }
5014 }
5015 ut_ad(0);
5016 return(ROW_TYPE_NOT_USED);
5017 }
5018
5019 /*****************************************************************//**
5020 Cancel any pending lock request associated with the current THD. */
5021 static
5022 void
innobase_kill_connection(handlerton * hton,THD * thd)5023 innobase_kill_connection(
5024 /*======================*/
5025 handlerton* hton, /*!< in: innobase handlerton */
5026 THD* thd) /*!< in: handle to the MySQL thread being killed */
5027 {
5028 trx_t* trx;
5029
5030 DBUG_ENTER("innobase_kill_connection");
5031 DBUG_ASSERT(hton == innodb_hton_ptr);
5032
5033 lock_mutex_enter();
5034
5035 trx = thd_to_trx(thd);
5036
5037 if (trx)
5038 {
5039 trx_mutex_enter(trx);
5040
5041 /* Cancel a pending lock request. */
5042 if (trx->lock.wait_lock)
5043 lock_cancel_waiting_and_release(trx->lock.wait_lock);
5044
5045 trx_mutex_exit(trx);
5046 }
5047
5048 lock_mutex_exit();
5049
5050 DBUG_VOID_RETURN;
5051 }
5052
5053
5054
5055 /****************************************************************//**
5056 Get the table flags to use for the statement.
5057 @return table flags */
5058 UNIV_INTERN
5059 handler::Table_flags
table_flags() const5060 ha_innobase::table_flags() const
5061 /*============================*/
5062 {
5063 /* Need to use tx_isolation here since table flags is (also)
5064 called before prebuilt is inited. */
5065 ulong const tx_isolation = thd_tx_isolation(ha_thd());
5066
5067 if (tx_isolation <= ISO_READ_COMMITTED) {
5068 return(int_table_flags);
5069 }
5070
5071 return(int_table_flags | HA_BINLOG_STMT_CAPABLE);
5072 }
5073
5074 /****************************************************************//**
5075 Gives the file extension of an InnoDB single-table tablespace. */
5076 static const char* ha_innobase_exts[] = {
5077 ".ibd",
5078 ".isl",
5079 NullS
5080 };
5081
5082 /****************************************************************//**
5083 Returns the table type (storage engine name).
5084 @return table type */
5085 UNIV_INTERN
5086 const char*
table_type() const5087 ha_innobase::table_type() const
5088 /*===========================*/
5089 {
5090 return(innobase_hton_name);
5091 }
5092
5093 /****************************************************************//**
5094 Returns the index type.
5095 @return index type */
5096 UNIV_INTERN
5097 const char*
index_type(uint keynr)5098 ha_innobase::index_type(
5099 /*====================*/
5100 uint keynr) /*!< : index number */
5101 {
5102 dict_index_t* index = innobase_get_index(keynr);
5103
5104 if (index && index->type & DICT_FTS) {
5105 return("FULLTEXT");
5106 } else {
5107 return("BTREE");
5108 }
5109 }
5110
5111 /****************************************************************//**
5112 Returns the table file name extension.
5113 @return file extension string */
5114 UNIV_INTERN
5115 const char**
bas_ext() const5116 ha_innobase::bas_ext() const
5117 /*========================*/
5118 {
5119 return(ha_innobase_exts);
5120 }
5121
5122 /****************************************************************//**
5123 Returns the operations supported for indexes.
5124 @return flags of supported operations */
5125 UNIV_INTERN
5126 ulong
index_flags(uint key,uint,bool) const5127 ha_innobase::index_flags(
5128 /*=====================*/
5129 uint key,
5130 uint,
5131 bool) const
5132 {
5133 return((table_share->key_info[key].algorithm == HA_KEY_ALG_FULLTEXT)
5134 ? 0
5135 : (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER
5136 | HA_READ_RANGE | HA_KEYREAD_ONLY
5137 | HA_DO_INDEX_COND_PUSHDOWN));
5138 }
5139
5140 /****************************************************************//**
5141 Returns the maximum number of keys.
5142 @return MAX_KEY */
5143 UNIV_INTERN
5144 uint
max_supported_keys() const5145 ha_innobase::max_supported_keys() const
5146 /*===================================*/
5147 {
5148 return(MAX_KEY);
5149 }
5150
5151 /****************************************************************//**
5152 Returns the maximum key length.
5153 @return maximum supported key length, in bytes */
5154 UNIV_INTERN
5155 uint
max_supported_key_length() const5156 ha_innobase::max_supported_key_length() const
5157 /*=========================================*/
5158 {
5159 /* An InnoDB page must store >= 2 keys; a secondary key record
5160 must also contain the primary key value. Therefore, if both
5161 the primary key and the secondary key are at this maximum length,
5162 it must be less than 1/4th of the free space on a page including
5163 record overhead.
5164
5165 MySQL imposes its own limit to this number; MAX_KEY_LENGTH = 3072.
5166
5167 For page sizes = 16k, InnoDB historically reported 3500 bytes here,
5168 But the MySQL limit of 3072 was always used through the handler
5169 interface. */
5170
5171 switch (UNIV_PAGE_SIZE) {
5172 case 4096:
5173 return(768);
5174 case 8192:
5175 return(1536);
5176 default:
5177 return(3500);
5178 }
5179 }
5180
5181 /****************************************************************//**
5182 Returns the key map of keys that are usable for scanning.
5183 @return key_map_full */
5184 UNIV_INTERN
5185 const key_map*
keys_to_use_for_scanning()5186 ha_innobase::keys_to_use_for_scanning()
5187 /*===================================*/
5188 {
5189 return(&key_map_full);
5190 }
5191
5192 /****************************************************************//**
5193 Determines if table caching is supported.
5194 @return HA_CACHE_TBL_ASKTRANSACT */
5195 UNIV_INTERN
5196 uint8
table_cache_type()5197 ha_innobase::table_cache_type()
5198 /*===========================*/
5199 {
5200 return(HA_CACHE_TBL_ASKTRANSACT);
5201 }
5202
5203 /****************************************************************//**
5204 Determines if the primary key is clustered index.
5205 @return true */
5206 UNIV_INTERN
5207 bool
primary_key_is_clustered()5208 ha_innobase::primary_key_is_clustered()
5209 /*===================================*/
5210 {
5211 return(true);
5212 }
5213
5214 /*****************************************************************//**
5215 Normalizes a table name string. A normalized name consists of the
5216 database name catenated to '/' and table name. Example: test/mytable.
5217 On Windows normalization puts both the database name and the
5218 table name always to lower case if "set_lower_case" is set to TRUE. */
5219 static
5220 void
normalize_table_name_low(char * norm_name,const char * name,ibool set_lower_case)5221 normalize_table_name_low(
5222 /*=====================*/
5223 char* norm_name, /*!< out: normalized name as a
5224 null-terminated string */
5225 const char* name, /*!< in: table name string */
5226 ibool set_lower_case) /*!< in: TRUE if we want to set name
5227 to lower case */
5228 {
5229 char* name_ptr;
5230 ulint name_len;
5231 char* db_ptr;
5232 ulint db_len;
5233 char* ptr;
5234 ulint norm_len;
5235
5236 /* Scan name from the end */
5237
5238 ptr = strend(name) - 1;
5239
5240 /* seek to the last path separator */
5241 while (ptr >= name && *ptr != '\\' && *ptr != '/') {
5242 ptr--;
5243 }
5244
5245 name_ptr = ptr + 1;
5246 name_len = strlen(name_ptr);
5247
5248 /* skip any number of path separators */
5249 while (ptr >= name && (*ptr == '\\' || *ptr == '/')) {
5250 ptr--;
5251 }
5252
5253 DBUG_ASSERT(ptr >= name);
5254
5255 /* seek to the last but one path separator or one char before
5256 the beginning of name */
5257 db_len = 0;
5258 while (ptr >= name && *ptr != '\\' && *ptr != '/') {
5259 ptr--;
5260 db_len++;
5261 }
5262
5263 db_ptr = ptr + 1;
5264
5265 norm_len = db_len + name_len + sizeof "/";
5266 ut_a(norm_len < FN_REFLEN - 1);
5267
5268 memcpy(norm_name, db_ptr, db_len);
5269
5270 norm_name[db_len] = '/';
5271
5272 /* Copy the name and null-byte. */
5273 memcpy(norm_name + db_len + 1, name_ptr, name_len + 1);
5274
5275 if (set_lower_case) {
5276 innobase_casedn_str(norm_name);
5277 }
5278 }
5279
5280 #if !defined(DBUG_OFF)
5281 /*********************************************************************
5282 Test normalize_table_name_low(). */
5283 static
5284 void
test_normalize_table_name_low()5285 test_normalize_table_name_low()
5286 /*===========================*/
5287 {
5288 char norm_name[FN_REFLEN];
5289 const char* test_data[][2] = {
5290 /* input, expected result */
5291 {"./mysqltest/t1", "mysqltest/t1"},
5292 {"./test/#sql-842b_2", "test/#sql-842b_2"},
5293 {"./test/#sql-85a3_10", "test/#sql-85a3_10"},
5294 {"./test/#sql2-842b-2", "test/#sql2-842b-2"},
5295 {"./test/bug29807", "test/bug29807"},
5296 {"./test/foo", "test/foo"},
5297 {"./test/innodb_bug52663", "test/innodb_bug52663"},
5298 {"./test/t", "test/t"},
5299 {"./test/t1", "test/t1"},
5300 {"./test/t10", "test/t10"},
5301 {"/a/b/db/table", "db/table"},
5302 {"/a/b/db///////table", "db/table"},
5303 {"/a/b////db///////table", "db/table"},
5304 {"/var/tmp/mysqld.1/#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
5305 {"db/table", "db/table"},
5306 {"ddd/t", "ddd/t"},
5307 {"d/ttt", "d/ttt"},
5308 {"d/t", "d/t"},
5309 {".\\mysqltest\\t1", "mysqltest/t1"},
5310 {".\\test\\#sql-842b_2", "test/#sql-842b_2"},
5311 {".\\test\\#sql-85a3_10", "test/#sql-85a3_10"},
5312 {".\\test\\#sql2-842b-2", "test/#sql2-842b-2"},
5313 {".\\test\\bug29807", "test/bug29807"},
5314 {".\\test\\foo", "test/foo"},
5315 {".\\test\\innodb_bug52663", "test/innodb_bug52663"},
5316 {".\\test\\t", "test/t"},
5317 {".\\test\\t1", "test/t1"},
5318 {".\\test\\t10", "test/t10"},
5319 {"C:\\a\\b\\db\\table", "db/table"},
5320 {"C:\\a\\b\\db\\\\\\\\\\\\\\table", "db/table"},
5321 {"C:\\a\\b\\\\\\\\db\\\\\\\\\\\\\\table", "db/table"},
5322 {"C:\\var\\tmp\\mysqld.1\\#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
5323 {"db\\table", "db/table"},
5324 {"ddd\\t", "ddd/t"},
5325 {"d\\ttt", "d/ttt"},
5326 {"d\\t", "d/t"},
5327 };
5328
5329 for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) {
5330 printf("test_normalize_table_name_low(): "
5331 "testing \"%s\", expected \"%s\"... ",
5332 test_data[i][0], test_data[i][1]);
5333
5334 normalize_table_name_low(norm_name, test_data[i][0], FALSE);
5335
5336 if (strcmp(norm_name, test_data[i][1]) == 0) {
5337 printf("ok\n");
5338 } else {
5339 printf("got \"%s\"\n", norm_name);
5340 ut_error;
5341 }
5342 }
5343 }
5344
5345 /*********************************************************************
5346 Test ut_format_name(). */
5347 static
5348 void
test_ut_format_name()5349 test_ut_format_name()
5350 /*=================*/
5351 {
5352 char buf[NAME_LEN * 3];
5353
5354 struct {
5355 const char* name;
5356 ibool is_table;
5357 ulint buf_size;
5358 const char* expected;
5359 } test_data[] = {
5360 {"test/t1", TRUE, sizeof(buf), "\"test\".\"t1\""},
5361 {"test/t1", TRUE, 12, "\"test\".\"t1\""},
5362 {"test/t1", TRUE, 11, "\"test\".\"t1"},
5363 {"test/t1", TRUE, 10, "\"test\".\"t"},
5364 {"test/t1", TRUE, 9, "\"test\".\""},
5365 {"test/t1", TRUE, 8, "\"test\"."},
5366 {"test/t1", TRUE, 7, "\"test\""},
5367 {"test/t1", TRUE, 6, "\"test"},
5368 {"test/t1", TRUE, 5, "\"tes"},
5369 {"test/t1", TRUE, 4, "\"te"},
5370 {"test/t1", TRUE, 3, "\"t"},
5371 {"test/t1", TRUE, 2, "\""},
5372 {"test/t1", TRUE, 1, ""},
5373 {"test/t1", TRUE, 0, "BUF_NOT_CHANGED"},
5374 {"table", TRUE, sizeof(buf), "\"table\""},
5375 {"ta'le", TRUE, sizeof(buf), "\"ta'le\""},
5376 {"ta\"le", TRUE, sizeof(buf), "\"ta\"\"le\""},
5377 {"ta`le", TRUE, sizeof(buf), "\"ta`le\""},
5378 {"index", FALSE, sizeof(buf), "\"index\""},
5379 {"ind/ex", FALSE, sizeof(buf), "\"ind/ex\""},
5380 };
5381
5382 for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) {
5383
5384 memcpy(buf, "BUF_NOT_CHANGED", strlen("BUF_NOT_CHANGED") + 1);
5385
5386 char* ret;
5387
5388 ret = ut_format_name(test_data[i].name,
5389 test_data[i].is_table,
5390 buf,
5391 test_data[i].buf_size);
5392
5393 ut_a(ret == buf);
5394
5395 if (strcmp(buf, test_data[i].expected) == 0) {
5396 fprintf(stderr,
5397 "ut_format_name(%s, %s, buf, %lu), "
5398 "expected %s, OK\n",
5399 test_data[i].name,
5400 test_data[i].is_table ? "TRUE" : "FALSE",
5401 test_data[i].buf_size,
5402 test_data[i].expected);
5403 } else {
5404 fprintf(stderr,
5405 "ut_format_name(%s, %s, buf, %lu), "
5406 "expected %s, ERROR: got %s\n",
5407 test_data[i].name,
5408 test_data[i].is_table ? "TRUE" : "FALSE",
5409 test_data[i].buf_size,
5410 test_data[i].expected,
5411 buf);
5412 ut_error;
5413 }
5414 }
5415 }
5416 #endif /* !DBUG_OFF */
5417
5418 /********************************************************************//**
5419 Get the upper limit of the MySQL integral and floating-point type.
5420 @return maximum allowed value for the field */
5421 UNIV_INTERN
5422 ulonglong
innobase_get_int_col_max_value(const Field * field)5423 innobase_get_int_col_max_value(
5424 /*===========================*/
5425 const Field* field) /*!< in: MySQL field */
5426 {
5427 ulonglong max_value = 0;
5428
5429 switch (field->key_type()) {
5430 /* TINY */
5431 case HA_KEYTYPE_BINARY:
5432 max_value = 0xFFULL;
5433 break;
5434 case HA_KEYTYPE_INT8:
5435 max_value = 0x7FULL;
5436 break;
5437 /* SHORT */
5438 case HA_KEYTYPE_USHORT_INT:
5439 max_value = 0xFFFFULL;
5440 break;
5441 case HA_KEYTYPE_SHORT_INT:
5442 max_value = 0x7FFFULL;
5443 break;
5444 /* MEDIUM */
5445 case HA_KEYTYPE_UINT24:
5446 max_value = 0xFFFFFFULL;
5447 break;
5448 case HA_KEYTYPE_INT24:
5449 max_value = 0x7FFFFFULL;
5450 break;
5451 /* LONG */
5452 case HA_KEYTYPE_ULONG_INT:
5453 max_value = 0xFFFFFFFFULL;
5454 break;
5455 case HA_KEYTYPE_LONG_INT:
5456 max_value = 0x7FFFFFFFULL;
5457 break;
5458 /* BIG */
5459 case HA_KEYTYPE_ULONGLONG:
5460 max_value = 0xFFFFFFFFFFFFFFFFULL;
5461 break;
5462 case HA_KEYTYPE_LONGLONG:
5463 max_value = 0x7FFFFFFFFFFFFFFFULL;
5464 break;
5465 case HA_KEYTYPE_FLOAT:
5466 /* We use the maximum as per IEEE754-2008 standard, 2^24 */
5467 max_value = 0x1000000ULL;
5468 break;
5469 case HA_KEYTYPE_DOUBLE:
5470 /* We use the maximum as per IEEE754-2008 standard, 2^53 */
5471 max_value = 0x20000000000000ULL;
5472 break;
5473 default:
5474 ut_error;
5475 }
5476
5477 return(max_value);
5478 }
5479
5480 /*******************************************************************//**
5481 This function checks whether the index column information
5482 is consistent between KEY info from mysql and that from innodb index.
5483 @return TRUE if all column types match. */
5484 static
5485 ibool
innobase_match_index_columns(const KEY * key_info,const dict_index_t * index_info)5486 innobase_match_index_columns(
5487 /*=========================*/
5488 const KEY* key_info, /*!< in: Index info
5489 from mysql */
5490 const dict_index_t* index_info) /*!< in: Index info
5491 from Innodb */
5492 {
5493 const KEY_PART_INFO* key_part;
5494 const KEY_PART_INFO* key_end;
5495 const dict_field_t* innodb_idx_fld;
5496 const dict_field_t* innodb_idx_fld_end;
5497
5498 DBUG_ENTER("innobase_match_index_columns");
5499
5500 /* Check whether user defined index column count matches */
5501 if (key_info->user_defined_key_parts !=
5502 index_info->n_user_defined_cols) {
5503 DBUG_RETURN(FALSE);
5504 }
5505
5506 key_part = key_info->key_part;
5507 key_end = key_part + key_info->user_defined_key_parts;
5508 innodb_idx_fld = index_info->fields;
5509 innodb_idx_fld_end = index_info->fields + index_info->n_fields;
5510
5511 /* Check each index column's datatype. We do not check
5512 column name because there exists case that index
5513 column name got modified in mysql but such change does not
5514 propagate to InnoDB.
5515 One hidden assumption here is that the index column sequences
5516 are matched up between those in mysql and Innodb. */
5517 for (; key_part != key_end; ++key_part) {
5518 ulint col_type;
5519 ibool is_unsigned;
5520 ulint mtype = innodb_idx_fld->col->mtype;
5521
5522 /* Need to translate to InnoDB column type before
5523 comparison. */
5524 col_type = get_innobase_type_from_mysql_type(&is_unsigned,
5525 key_part->field);
5526
5527 /* Ignore Innodb specific system columns. */
5528 while (mtype == DATA_SYS) {
5529 innodb_idx_fld++;
5530
5531 if (innodb_idx_fld >= innodb_idx_fld_end) {
5532 DBUG_RETURN(FALSE);
5533 }
5534 }
5535
5536 if (col_type != mtype) {
5537 /* Column Type mismatches */
5538 DBUG_RETURN(FALSE);
5539 }
5540
5541 innodb_idx_fld++;
5542 }
5543
5544 DBUG_RETURN(TRUE);
5545 }
5546
5547 /*******************************************************************//**
5548 This function builds a translation table in INNOBASE_SHARE
5549 structure for fast index location with mysql array number from its
5550 table->key_info structure. This also provides the necessary translation
5551 between the key order in mysql key_info and Innodb ib_table->indexes if
5552 they are not fully matched with each other.
5553 Note we do not have any mutex protecting the translation table
5554 building based on the assumption that there is no concurrent
5555 index creation/drop and DMLs that requires index lookup. All table
5556 handle will be closed before the index creation/drop.
5557 @return TRUE if index translation table built successfully */
5558 UNIV_INTERN
5559 ibool
innobase_build_index_translation(const TABLE * table,dict_table_t * ib_table,INNOBASE_SHARE * share)5560 innobase_build_index_translation(
5561 /*=============================*/
5562 const TABLE* table, /*!< in: table in MySQL data
5563 dictionary */
5564 dict_table_t* ib_table,/*!< in: table in Innodb data
5565 dictionary */
5566 INNOBASE_SHARE* share) /*!< in/out: share structure
5567 where index translation table
5568 will be constructed in. */
5569 {
5570 ulint mysql_num_index;
5571 ulint ib_num_index;
5572 dict_index_t** index_mapping;
5573 ibool ret = TRUE;
5574
5575 DBUG_ENTER("innobase_build_index_translation");
5576
5577 mutex_enter(&dict_sys->mutex);
5578
5579 mysql_num_index = table->s->keys;
5580 ib_num_index = UT_LIST_GET_LEN(ib_table->indexes);
5581
5582 index_mapping = share->idx_trans_tbl.index_mapping;
5583
5584 /* If there exists inconsistency between MySQL and InnoDB dictionary
5585 (metadata) information, the number of index defined in MySQL
5586 could exceed that in InnoDB, do not build index translation
5587 table in such case */
5588 if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
5589 ret = FALSE;
5590 goto func_exit;
5591 }
5592
5593 /* If index entry count is non-zero, nothing has
5594 changed since last update, directly return TRUE */
5595 if (share->idx_trans_tbl.index_count) {
5596 /* Index entry count should still match mysql_num_index */
5597 ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
5598 goto func_exit;
5599 }
5600
5601 /* The number of index increased, rebuild the mapping table */
5602 if (mysql_num_index > share->idx_trans_tbl.array_size) {
5603 index_mapping = (dict_index_t**) my_realloc(index_mapping,
5604 mysql_num_index *
5605 sizeof(*index_mapping),
5606 MYF(MY_ALLOW_ZERO_PTR));
5607
5608 if (!index_mapping) {
5609 /* Report an error if index_mapping continues to be
5610 NULL and mysql_num_index is a non-zero value */
5611 sql_print_error("InnoDB: fail to allocate memory for "
5612 "index translation table. Number of "
5613 "Index:%lu, array size:%lu",
5614 mysql_num_index,
5615 share->idx_trans_tbl.array_size);
5616 ret = FALSE;
5617 goto func_exit;
5618 }
5619
5620 share->idx_trans_tbl.array_size = mysql_num_index;
5621 }
5622
5623 /* For each index in the mysql key_info array, fetch its
5624 corresponding InnoDB index pointer into index_mapping
5625 array. */
5626 for (ulint count = 0; count < mysql_num_index; count++) {
5627
5628 /* Fetch index pointers into index_mapping according to mysql
5629 index sequence */
5630 index_mapping[count] = dict_table_get_index_on_name(
5631 ib_table, table->key_info[count].name);
5632
5633 if (!index_mapping[count]) {
5634 sql_print_error("Cannot find index %s in InnoDB "
5635 "index dictionary.",
5636 table->key_info[count].name);
5637 ret = FALSE;
5638 goto func_exit;
5639 }
5640
5641 /* Double check fetched index has the same
5642 column info as those in mysql key_info. */
5643 if (!innobase_match_index_columns(&table->key_info[count],
5644 index_mapping[count])) {
5645 sql_print_error("Found index %s whose column info "
5646 "does not match that of MySQL.",
5647 table->key_info[count].name);
5648 ret = FALSE;
5649 goto func_exit;
5650 }
5651 }
5652
5653 /* Successfully built the translation table */
5654 share->idx_trans_tbl.index_count = mysql_num_index;
5655
5656 func_exit:
5657 if (!ret) {
5658 /* Build translation table failed. */
5659 my_free(index_mapping);
5660
5661 share->idx_trans_tbl.array_size = 0;
5662 share->idx_trans_tbl.index_count = 0;
5663 index_mapping = NULL;
5664 }
5665
5666 share->idx_trans_tbl.index_mapping = index_mapping;
5667
5668 mutex_exit(&dict_sys->mutex);
5669
5670 DBUG_RETURN(ret);
5671 }
5672
5673 /** This function checks if all the compression dictionaries referenced
5674 in table->fields exist in SYS_ZIP_DICT InnoDB system table.
5675 @return true if all referenced dictionaries exist */
5676 UNIV_INTERN
5677 bool
innobase_check_zip_dicts(const TABLE * table,ulint * dict_ids,trx_t * trx,const char ** err_dict_name)5678 innobase_check_zip_dicts(
5679 const TABLE* table, /*!< in: table in MySQL data
5680 dictionary */
5681 ulint* dict_ids, /*!< out: identified zip dict ids
5682 (at least n_fields long) */
5683 trx_t* trx, /*!< in: transaction */
5684 const char** err_dict_name) /*!< out: the name of the
5685 zip_dict which does not exist. */
5686 {
5687 DBUG_ENTER("innobase_check_zip_dicts");
5688
5689 bool res = true;
5690 dberr_t err = DB_SUCCESS;
5691 const size_t n_fields = table->s->fields;
5692
5693 Field* field_ptr;
5694 for (size_t field_idx = 0; err == DB_SUCCESS && field_idx < n_fields;
5695 ++field_idx)
5696 {
5697 field_ptr = table->field[field_idx];
5698 if (field_ptr->has_associated_compression_dictionary()) {
5699 err = dict_create_get_zip_dict_id_by_name(
5700 field_ptr->zip_dict_name.str,
5701 field_ptr->zip_dict_name.length,
5702 &dict_ids[field_idx],
5703 trx);
5704 ut_a(err == DB_SUCCESS || err == DB_RECORD_NOT_FOUND);
5705 }
5706 else {
5707 dict_ids[field_idx] = ULINT_UNDEFINED;
5708 }
5709
5710 }
5711
5712 if (err != DB_SUCCESS) {
5713 res = false;
5714 *err_dict_name = field_ptr->zip_dict_name.str;
5715 }
5716
5717 DBUG_RETURN(res);
5718 }
5719
5720 /** This function creates compression dictionary references in
5721 SYS_ZIP_DICT_COLS InnoDB system table for table_id based on info
5722 in table->fields and provided zip dict ids. */
5723 UNIV_INTERN
5724 void
innobase_create_zip_dict_references(const TABLE * table,table_id_t ib_table_id,ulint * zip_dict_ids,trx_t * trx)5725 innobase_create_zip_dict_references(
5726 const TABLE* table, /*!< in: table in MySQL data
5727 dictionary */
5728 table_id_t ib_table_id, /*!< in: table ID in Innodb data
5729 dictionary */
5730 ulint* zip_dict_ids, /*!< in: zip dict ids
5731 (at least n_fields long) */
5732 trx_t* trx) /*!< in: transaction */
5733 {
5734 DBUG_ENTER("innobase_create_zip_dict_references");
5735
5736 dberr_t err = DB_SUCCESS;
5737 const size_t n_fields = table->s->fields;
5738
5739 for (size_t field_idx = 0; err == DB_SUCCESS && field_idx < n_fields;
5740 ++field_idx)
5741 {
5742 if (zip_dict_ids[field_idx] != ULINT_UNDEFINED) {
5743 err = dict_create_add_zip_dict_reference(ib_table_id,
5744 table->field[field_idx]->field_index,
5745 zip_dict_ids[field_idx], trx);
5746 ut_a(err == DB_SUCCESS);
5747 }
5748 }
5749
5750 DBUG_VOID_RETURN;
5751 }
5752
5753 /*******************************************************************//**
5754 This function uses index translation table to quickly locate the
5755 requested index structure.
5756 Note we do not have mutex protection for the index translatoin table
5757 access, it is based on the assumption that there is no concurrent
5758 translation table rebuild (fter create/drop index) and DMLs that
5759 require index lookup.
5760 @return dict_index_t structure for requested index. NULL if
5761 fail to locate the index structure. */
5762 static
5763 dict_index_t*
innobase_index_lookup(INNOBASE_SHARE * share,uint keynr)5764 innobase_index_lookup(
5765 /*==================*/
5766 INNOBASE_SHARE* share, /*!< in: share structure for index
5767 translation table. */
5768 uint keynr) /*!< in: index number for the requested
5769 index */
5770 {
5771 if (!share->idx_trans_tbl.index_mapping
5772 || keynr >= share->idx_trans_tbl.index_count) {
5773 return(NULL);
5774 }
5775
5776 return(share->idx_trans_tbl.index_mapping[keynr]);
5777 }
5778
5779 /************************************************************************
5780 Set the autoinc column max value. This should only be called once from
5781 ha_innobase::open(). Therefore there's no need for a covering lock. */
5782 UNIV_INTERN
5783 void
innobase_initialize_autoinc()5784 ha_innobase::innobase_initialize_autoinc()
5785 /*======================================*/
5786 {
5787 ulonglong auto_inc;
5788 const Field* field = table->found_next_number_field;
5789
5790 if (field != NULL) {
5791 auto_inc = innobase_get_int_col_max_value(field);
5792 } else {
5793 /* We have no idea what's been passed in to us as the
5794 autoinc column. We set it to the 0, effectively disabling
5795 updates to the table. */
5796 auto_inc = 0;
5797
5798 ut_print_timestamp(stderr);
5799 fprintf(stderr, " InnoDB: Unable to determine the AUTOINC "
5800 "column name\n");
5801 }
5802
5803 if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
5804 /* If the recovery level is set so high that writes
5805 are disabled we force the AUTOINC counter to 0
5806 value effectively disabling writes to the table.
5807 Secondly, we avoid reading the table in case the read
5808 results in failure due to a corrupted table/index.
5809
5810 We will not return an error to the client, so that the
5811 tables can be dumped with minimal hassle. If an error
5812 were returned in this case, the first attempt to read
5813 the table would fail and subsequent SELECTs would succeed. */
5814 auto_inc = 0;
5815 } else if (field == NULL) {
5816 /* This is a far more serious error, best to avoid
5817 opening the table and return failure. */
5818 my_error(ER_AUTOINC_READ_FAILED, MYF(0));
5819 } else {
5820 dict_index_t* index;
5821 const char* col_name;
5822 ib_uint64_t read_auto_inc;
5823 ulint err;
5824
5825 update_thd(ha_thd());
5826
5827 ut_a(prebuilt->trx == thd_to_trx(user_thd));
5828
5829 col_name = field->field_name;
5830 index = innobase_get_index(table->s->next_number_index);
5831
5832 /* Execute SELECT MAX(col_name) FROM TABLE; */
5833 err = row_search_max_autoinc(index, col_name, &read_auto_inc);
5834
5835 switch (err) {
5836 case DB_SUCCESS: {
5837 ulonglong col_max_value;
5838
5839 col_max_value = innobase_get_int_col_max_value(field);
5840
5841 /* At the this stage we do not know the increment
5842 nor the offset, so use a default increment of 1. */
5843
5844 auto_inc = innobase_next_autoinc(
5845 read_auto_inc, 1, 1, 0, col_max_value);
5846
5847 break;
5848 }
5849 case DB_RECORD_NOT_FOUND:
5850 ut_print_timestamp(stderr);
5851 fprintf(stderr, " InnoDB: MySQL and InnoDB data "
5852 "dictionaries are out of sync.\n"
5853 "InnoDB: Unable to find the AUTOINC column "
5854 "%s in the InnoDB table %s.\n"
5855 "InnoDB: We set the next AUTOINC column "
5856 "value to 0,\n"
5857 "InnoDB: in effect disabling the AUTOINC "
5858 "next value generation.\n"
5859 "InnoDB: You can either set the next "
5860 "AUTOINC value explicitly using ALTER TABLE\n"
5861 "InnoDB: or fix the data dictionary by "
5862 "recreating the table.\n",
5863 col_name, index->table->name);
5864
5865 /* This will disable the AUTOINC generation. */
5866 auto_inc = 0;
5867
5868 /* We want the open to succeed, so that the user can
5869 take corrective action. ie. reads should succeed but
5870 updates should fail. */
5871 err = DB_SUCCESS;
5872 break;
5873 default:
5874 /* row_search_max_autoinc() should only return
5875 one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
5876 ut_error;
5877 }
5878 }
5879
5880 dict_table_autoinc_initialize(prebuilt->table, auto_inc);
5881 }
5882
5883 /*****************************************************************//**
5884 Creates and opens a handle to a table which already exists in an InnoDB
5885 database.
5886 @return 1 if error, 0 if success */
5887 UNIV_INTERN
5888 int
open(const char * name,int mode,uint test_if_locked)5889 ha_innobase::open(
5890 /*==============*/
5891 const char* name, /*!< in: table name */
5892 int mode, /*!< in: not used */
5893 uint test_if_locked) /*!< in: not used */
5894 {
5895 dict_table_t* ib_table;
5896 char norm_name[FN_REFLEN];
5897 THD* thd;
5898 char* is_part = NULL;
5899 ibool par_case_name_set = FALSE;
5900 char par_case_name[FN_REFLEN];
5901 dict_err_ignore_t ignore_err = DICT_ERR_IGNORE_NONE;
5902
5903 DBUG_ENTER("ha_innobase::open");
5904
5905 UT_NOT_USED(mode);
5906 UT_NOT_USED(test_if_locked);
5907
5908 thd = ha_thd();
5909
5910 /* No-op in XtraDB */
5911 innobase_release_temporary_latches(ht, thd);
5912
5913 normalize_table_name(norm_name, name);
5914
5915 user_thd = NULL;
5916
5917 if (!(share=get_share(name))) {
5918
5919 DBUG_RETURN(1);
5920 }
5921
5922 if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt &&
5923 srv_pass_corrupt_table <= 1)) {
5924 free_share(share);
5925
5926 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
5927 }
5928
5929 /* Will be allocated if it is needed in ::update_row() */
5930 upd_buf = NULL;
5931 upd_buf_size = 0;
5932
5933 /* We look for pattern #P# to see if the table is partitioned
5934 MySQL table. */
5935 #ifdef __WIN__
5936 is_part = strstr(norm_name, "#p#");
5937 #else
5938 is_part = strstr(norm_name, "#P#");
5939 #endif /* __WIN__ */
5940
5941 /* Check whether FOREIGN_KEY_CHECKS is set to 0. If so, the table
5942 can be opened even if some FK indexes are missing. If not, the table
5943 can't be opened in the same situation */
5944 if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
5945 ignore_err = DICT_ERR_IGNORE_FK_NOKEY;
5946 }
5947
5948 /* Get pointer to a table object in InnoDB dictionary cache */
5949 ib_table = dict_table_open_on_name(norm_name, FALSE, TRUE, ignore_err);
5950
5951 if (ib_table
5952 && ((!DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID)
5953 && table->s->fields != dict_table_get_n_user_cols(ib_table))
5954 || (DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID)
5955 && (table->s->fields
5956 != dict_table_get_n_user_cols(ib_table) - 1)))) {
5957 ib_logf(IB_LOG_LEVEL_WARN,
5958 "table %s contains %lu user defined columns "
5959 "in InnoDB, but %lu columns in MySQL. Please "
5960 "check INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and "
5961 REFMAN "innodb-troubleshooting.html "
5962 "for how to resolve it",
5963 norm_name, (ulong) dict_table_get_n_user_cols(ib_table),
5964 (ulong) table->s->fields);
5965
5966 /* Mark this table as corrupted, so the drop table
5967 or force recovery can still use it, but not others. */
5968 ib_table->corrupted = true;
5969 dict_table_close(ib_table, FALSE, FALSE);
5970 ib_table = NULL;
5971 is_part = NULL;
5972 }
5973
5974 if (UNIV_UNLIKELY(ib_table && ib_table->is_corrupt &&
5975 srv_pass_corrupt_table <= 1)) {
5976 free_share(share);
5977 my_free(upd_buf);
5978 upd_buf = NULL;
5979 upd_buf_size = 0;
5980
5981 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
5982 }
5983
5984 share->ib_table = ib_table;
5985
5986 if (NULL == ib_table) {
5987 if (is_part) {
5988 /* MySQL partition engine hard codes the file name
5989 separator as "#P#". The text case is fixed even if
5990 lower_case_table_names is set to 1 or 2. This is true
5991 for sub-partition names as well. InnoDB always
5992 normalises file names to lower case on Windows, this
5993 can potentially cause problems when copying/moving
5994 tables between platforms.
5995
5996 1) If boot against an installation from Windows
5997 platform, then its partition table name could
5998 be in lower case in system tables. So we will
5999 need to check lower case name when load table.
6000
6001 2) If we boot an installation from other case
6002 sensitive platform in Windows, we might need to
6003 check the existence of table name without lower
6004 case in the system table. */
6005 if (innobase_get_lower_case_table_names() == 1) {
6006
6007 if (!par_case_name_set) {
6008 #ifndef __WIN__
6009 /* Check for the table using lower
6010 case name, including the partition
6011 separator "P" */
6012 strcpy(par_case_name, norm_name);
6013 innobase_casedn_str(par_case_name);
6014 #else
6015 /* On Windows platfrom, check
6016 whether there exists table name in
6017 system table whose name is
6018 not being normalized to lower case */
6019 normalize_table_name_low(
6020 par_case_name, name, FALSE);
6021 #endif
6022 par_case_name_set = TRUE;
6023 }
6024
6025 ib_table = dict_table_open_on_name(
6026 par_case_name, FALSE, TRUE,
6027 ignore_err);
6028 }
6029
6030 if (ib_table) {
6031 #ifndef __WIN__
6032 sql_print_warning("Partition table %s opened "
6033 "after converting to lower "
6034 "case. The table may have "
6035 "been moved from a case "
6036 "in-sensitive file system. "
6037 "Please recreate table in "
6038 "the current file system\n",
6039 norm_name);
6040 #else
6041 sql_print_warning("Partition table %s opened "
6042 "after skipping the step to "
6043 "lower case the table name. "
6044 "The table may have been "
6045 "moved from a case sensitive "
6046 "file system. Please "
6047 "recreate table in the "
6048 "current file system\n",
6049 norm_name);
6050 #endif
6051 goto table_opened;
6052 }
6053 }
6054
6055 if (is_part) {
6056 sql_print_error("Failed to open table %s.\n",
6057 norm_name);
6058 }
6059
6060 ib_logf(IB_LOG_LEVEL_WARN,
6061 "Cannot open table %s from the internal data "
6062 "dictionary of InnoDB though the .frm file "
6063 "for the table exists. See "
6064 REFMAN "innodb-troubleshooting.html for how "
6065 "you can resolve the problem.", norm_name);
6066
6067 free_share(share);
6068 my_errno = ENOENT;
6069
6070 DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
6071 }
6072
6073 table_opened:
6074
6075 innobase_copy_frm_flags_from_table_share(ib_table, table->s);
6076
6077 dict_stats_init(ib_table);
6078
6079 MONITOR_INC(MONITOR_TABLE_OPEN);
6080
6081 bool no_tablespace;
6082
6083 if (dict_table_is_discarded(ib_table)) {
6084
6085 ib_senderrf(thd,
6086 IB_LOG_LEVEL_WARN, ER_TABLESPACE_DISCARDED,
6087 table->s->table_name.str);
6088
6089 /* Allow an open because a proper DISCARD should have set
6090 all the flags and index root page numbers to FIL_NULL that
6091 should prevent any DML from running but it should allow DDL
6092 operations. */
6093
6094 no_tablespace = false;
6095
6096 } else if (ib_table->ibd_file_missing) {
6097
6098 ib_senderrf(
6099 thd, IB_LOG_LEVEL_WARN,
6100 ER_TABLESPACE_MISSING, norm_name);
6101
6102 /* This means we have no idea what happened to the tablespace
6103 file, best to play it safe. */
6104
6105 no_tablespace = true;
6106 } else {
6107 no_tablespace = false;
6108 }
6109
6110 if (!thd_tablespace_op(thd) && no_tablespace) {
6111 free_share(share);
6112 my_errno = ENOENT;
6113
6114 dict_table_close(ib_table, FALSE, FALSE);
6115
6116 DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
6117 }
6118
6119 prebuilt = row_create_prebuilt(ib_table, table->s->reclength);
6120
6121 prebuilt->default_rec = table->s->default_values;
6122 ut_ad(prebuilt->default_rec);
6123
6124 prebuilt->mysql_handler = this;
6125
6126 /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
6127 primary_key = table->s->primary_key;
6128 key_used_on_scan = primary_key;
6129
6130 if (!innobase_build_index_translation(table, ib_table, share)) {
6131 sql_print_error("Build InnoDB index translation table for"
6132 " Table %s failed", name);
6133 }
6134
6135 /* Allocate a buffer for a 'row reference'. A row reference is
6136 a string of bytes of length ref_length which uniquely specifies
6137 a row in our table. Note that MySQL may also compare two row
6138 references for equality by doing a simple memcmp on the strings
6139 of length ref_length! */
6140
6141 if (!row_table_got_default_clust_index(ib_table)) {
6142
6143 prebuilt->clust_index_was_generated = FALSE;
6144
6145 if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
6146 sql_print_error("Table %s has a primary key in "
6147 "InnoDB data dictionary, but not "
6148 "in MySQL!", name);
6149
6150 /* This mismatch could cause further problems
6151 if not attended, bring this to the user's attention
6152 by printing a warning in addition to log a message
6153 in the errorlog */
6154 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6155 ER_NO_SUCH_INDEX,
6156 "InnoDB: Table %s has a "
6157 "primary key in InnoDB data "
6158 "dictionary, but not in "
6159 "MySQL!", name);
6160
6161 /* If primary_key >= MAX_KEY, its (primary_key)
6162 value could be out of bound if continue to index
6163 into key_info[] array. Find InnoDB primary index,
6164 and assign its key_length to ref_length.
6165 In addition, since MySQL indexes are sorted starting
6166 with primary index, unique index etc., initialize
6167 ref_length to the first index key length in
6168 case we fail to find InnoDB cluster index.
6169
6170 Please note, this will not resolve the primary
6171 index mismatch problem, other side effects are
6172 possible if users continue to use the table.
6173 However, we allow this table to be opened so
6174 that user can adopt necessary measures for the
6175 mismatch while still being accessible to the table
6176 date. */
6177 if (!table->key_info) {
6178 ut_ad(!table->s->keys);
6179 ref_length = 0;
6180 } else {
6181 ref_length = table->key_info[0].key_length;
6182 }
6183
6184 /* Find corresponding cluster index
6185 key length in MySQL's key_info[] array */
6186 for (uint i = 0; i < table->s->keys; i++) {
6187 dict_index_t* index;
6188 index = innobase_get_index(i);
6189 if (dict_index_is_clust(index)) {
6190 ref_length =
6191 table->key_info[i].key_length;
6192 }
6193 }
6194 } else {
6195 /* MySQL allocates the buffer for ref.
6196 key_info->key_length includes space for all key
6197 columns + one byte for each column that may be
6198 NULL. ref_length must be as exact as possible to
6199 save space, because all row reference buffers are
6200 allocated based on ref_length. */
6201
6202 ref_length = table->key_info[primary_key].key_length;
6203 }
6204 } else {
6205 if (primary_key != MAX_KEY) {
6206 sql_print_error(
6207 "Table %s has no primary key in InnoDB data "
6208 "dictionary, but has one in MySQL! If you "
6209 "created the table with a MySQL version < "
6210 "3.23.54 and did not define a primary key, "
6211 "but defined a unique key with all non-NULL "
6212 "columns, then MySQL internally treats that "
6213 "key as the primary key. You can fix this "
6214 "error by dump + DROP + CREATE + reimport "
6215 "of the table.", name);
6216
6217 /* This mismatch could cause further problems
6218 if not attended, bring this to the user attention
6219 by printing a warning in addition to log a message
6220 in the errorlog */
6221 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6222 ER_NO_SUCH_INDEX,
6223 "InnoDB: Table %s has no "
6224 "primary key in InnoDB data "
6225 "dictionary, but has one in "
6226 "MySQL!", name);
6227 }
6228
6229 prebuilt->clust_index_was_generated = TRUE;
6230
6231 ref_length = DATA_ROW_ID_LEN;
6232
6233 /* If we automatically created the clustered index, then
6234 MySQL does not know about it, and MySQL must NOT be aware
6235 of the index used on scan, to make it avoid checking if we
6236 update the column of the index. That is why we assert below
6237 that key_used_on_scan is the undefined value MAX_KEY.
6238 The column is the row id in the automatical generation case,
6239 and it will never be updated anyway. */
6240
6241 if (key_used_on_scan != MAX_KEY) {
6242 sql_print_warning(
6243 "Table %s key_used_on_scan is %lu even "
6244 "though there is no primary key inside "
6245 "InnoDB.", name, (ulong) key_used_on_scan);
6246 }
6247 }
6248
6249 /* Index block size in InnoDB: used by MySQL in query optimization */
6250 stats.block_size = UNIV_PAGE_SIZE;
6251
6252 /* Init table lock structure */
6253 thr_lock_data_init(&share->lock,&lock,(void*) 0);
6254
6255 if (prebuilt->table) {
6256 /* We update the highest file format in the system table
6257 space, if this table has higher file format setting. */
6258
6259 trx_sys_file_format_max_upgrade(
6260 (const char**) &innobase_file_format_max,
6261 dict_table_get_format(prebuilt->table));
6262 }
6263
6264 /* Only if the table has an AUTOINC column. */
6265 if (prebuilt->table != NULL
6266 && !prebuilt->table->ibd_file_missing
6267 && table->found_next_number_field != NULL) {
6268 dict_table_autoinc_lock(prebuilt->table);
6269
6270 /* Since a table can already be "open" in InnoDB's internal
6271 data dictionary, we only init the autoinc counter once, the
6272 first time the table is loaded. We can safely reuse the
6273 autoinc value from a previous MySQL open. */
6274 if (dict_table_autoinc_read(prebuilt->table) == 0) {
6275
6276 innobase_initialize_autoinc();
6277 }
6278
6279 dict_table_autoinc_unlock(prebuilt->table);
6280 }
6281
6282 info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
6283
6284 DBUG_RETURN(0);
6285 }
6286
6287 UNIV_INTERN
6288 handler*
clone(const char * name,MEM_ROOT * mem_root)6289 ha_innobase::clone(
6290 /*===============*/
6291 const char* name, /*!< in: table name */
6292 MEM_ROOT* mem_root) /*!< in: memory context */
6293 {
6294 ha_innobase* new_handler;
6295
6296 DBUG_ENTER("ha_innobase::clone");
6297
6298 new_handler = static_cast<ha_innobase*>(handler::clone(name,
6299 mem_root));
6300 if (new_handler) {
6301 DBUG_ASSERT(new_handler->prebuilt != NULL);
6302
6303 new_handler->prebuilt->select_lock_type
6304 = prebuilt->select_lock_type;
6305 }
6306
6307 DBUG_RETURN(new_handler);
6308 }
6309
6310 UNIV_INTERN
6311 uint
max_supported_key_part_length() const6312 ha_innobase::max_supported_key_part_length() const
6313 /*==============================================*/
6314 {
6315 /* A table format specific index column length check will be performed
6316 at ha_innobase::add_index() and row_create_index_for_mysql() */
6317 return(innobase_large_prefix
6318 ? REC_VERSION_56_MAX_INDEX_COL_LEN
6319 : REC_ANTELOPE_MAX_INDEX_COL_LEN - 1);
6320 }
6321
6322 /******************************************************************//**
6323 Closes a handle to an InnoDB table.
6324 @return 0 */
6325 UNIV_INTERN
6326 int
close()6327 ha_innobase::close()
6328 /*================*/
6329 {
6330 THD* thd;
6331
6332 DBUG_ENTER("ha_innobase::close");
6333
6334 thd = ha_thd();
6335
6336 /* No-op in XtraDB */
6337 innobase_release_temporary_latches(ht, thd);
6338
6339 row_prebuilt_free(prebuilt, FALSE);
6340
6341 if (upd_buf != NULL) {
6342 ut_ad(upd_buf_size != 0);
6343 my_free(upd_buf);
6344 upd_buf = NULL;
6345 upd_buf_size = 0;
6346 }
6347
6348 free_share(share);
6349
6350 MONITOR_INC(MONITOR_TABLE_CLOSE);
6351
6352 /* Tell InnoDB server that there might be work for
6353 utility threads: */
6354
6355 srv_active_wake_master_thread();
6356
6357 DBUG_RETURN(0);
6358 }
6359
6360 /* The following accessor functions should really be inside MySQL code! */
6361
6362 /**************************************************************//**
6363 Gets field offset for a field in a table.
6364 @return offset */
6365 static inline
6366 uint
get_field_offset(const TABLE * table,const Field * field)6367 get_field_offset(
6368 /*=============*/
6369 const TABLE* table, /*!< in: MySQL table object */
6370 const Field* field) /*!< in: MySQL field object */
6371 {
6372 return((uint) (field->ptr - table->record[0]));
6373 }
6374
6375 /*************************************************************//**
6376 InnoDB uses this function to compare two data fields for which the data type
6377 is such that we must use MySQL code to compare them. NOTE that the prototype
6378 of this function is in rem0cmp.cc in InnoDB source code! If you change this
6379 function, remember to update the prototype there!
6380 @return 1, 0, -1, if a is greater, equal, less than b, respectively */
6381 UNIV_INTERN
6382 int
innobase_mysql_cmp(int mysql_type,uint charset_number,const unsigned char * a,unsigned int a_length,const unsigned char * b,unsigned int b_length)6383 innobase_mysql_cmp(
6384 /*===============*/
6385 int mysql_type, /*!< in: MySQL type */
6386 uint charset_number, /*!< in: number of the charset */
6387 const unsigned char* a, /*!< in: data field */
6388 unsigned int a_length, /*!< in: data field length,
6389 not UNIV_SQL_NULL */
6390 const unsigned char* b, /*!< in: data field */
6391 unsigned int b_length) /*!< in: data field length,
6392 not UNIV_SQL_NULL */
6393 {
6394 CHARSET_INFO* charset;
6395 enum_field_types mysql_tp;
6396 int ret;
6397
6398 DBUG_ASSERT(a_length != UNIV_SQL_NULL);
6399 DBUG_ASSERT(b_length != UNIV_SQL_NULL);
6400
6401 mysql_tp = (enum_field_types) mysql_type;
6402
6403 switch (mysql_tp) {
6404
6405 case MYSQL_TYPE_BIT:
6406 case MYSQL_TYPE_STRING:
6407 case MYSQL_TYPE_VAR_STRING:
6408 case MYSQL_TYPE_TINY_BLOB:
6409 case MYSQL_TYPE_MEDIUM_BLOB:
6410 case MYSQL_TYPE_BLOB:
6411 case MYSQL_TYPE_LONG_BLOB:
6412 case MYSQL_TYPE_VARCHAR:
6413 /* Use the charset number to pick the right charset struct for
6414 the comparison. Since the MySQL function get_charset may be
6415 slow before Bar removes the mutex operation there, we first
6416 look at 2 common charsets directly. */
6417
6418 if (charset_number == default_charset_info->number) {
6419 charset = default_charset_info;
6420 } else if (charset_number == my_charset_latin1.number) {
6421 charset = &my_charset_latin1;
6422 } else {
6423 charset = get_charset(charset_number, MYF(MY_WME));
6424
6425 if (charset == NULL) {
6426 sql_print_error("InnoDB needs charset %lu for doing "
6427 "a comparison, but MySQL cannot "
6428 "find that charset.",
6429 (ulong) charset_number);
6430 ut_a(0);
6431 }
6432 }
6433
6434 /* Starting from 4.1.3, we use strnncollsp() in comparisons of
6435 non-latin1_swedish_ci strings. NOTE that the collation order
6436 changes then: 'b\0\0...' is ordered BEFORE 'b ...'. Users
6437 having indexes on such data need to rebuild their tables! */
6438
6439 ret = charset->coll->strnncollsp(
6440 charset, a, a_length, b, b_length, 0);
6441
6442 if (ret < 0) {
6443 return(-1);
6444 } else if (ret > 0) {
6445 return(1);
6446 } else {
6447 return(0);
6448 }
6449 default:
6450 ut_error;
6451 }
6452
6453 return(0);
6454 }
6455
6456
6457 /*************************************************************//**
6458 Get the next token from the given string and store it in *token. */
6459 UNIV_INTERN
6460 CHARSET_INFO*
innobase_get_fts_charset(int mysql_type,uint charset_number)6461 innobase_get_fts_charset(
6462 /*=====================*/
6463 int mysql_type, /*!< in: MySQL type */
6464 uint charset_number) /*!< in: number of the charset */
6465 {
6466 enum_field_types mysql_tp;
6467 CHARSET_INFO* charset;
6468
6469 mysql_tp = (enum_field_types) mysql_type;
6470
6471 switch (mysql_tp) {
6472
6473 case MYSQL_TYPE_BIT:
6474 case MYSQL_TYPE_STRING:
6475 case MYSQL_TYPE_VAR_STRING:
6476 case MYSQL_TYPE_TINY_BLOB:
6477 case MYSQL_TYPE_MEDIUM_BLOB:
6478 case MYSQL_TYPE_BLOB:
6479 case MYSQL_TYPE_LONG_BLOB:
6480 case MYSQL_TYPE_VARCHAR:
6481 /* Use the charset number to pick the right charset struct for
6482 the comparison. Since the MySQL function get_charset may be
6483 slow before Bar removes the mutex operation there, we first
6484 look at 2 common charsets directly. */
6485
6486 if (charset_number == default_charset_info->number) {
6487 charset = default_charset_info;
6488 } else if (charset_number == my_charset_latin1.number) {
6489 charset = &my_charset_latin1;
6490 } else {
6491 charset = get_charset(charset_number, MYF(MY_WME));
6492
6493 if (charset == NULL) {
6494 sql_print_error("InnoDB needs charset %lu for doing "
6495 "a comparison, but MySQL cannot "
6496 "find that charset.",
6497 (ulong) charset_number);
6498 ut_a(0);
6499 }
6500 }
6501 break;
6502 default:
6503 ut_error;
6504 }
6505
6506 return(charset);
6507 }
6508
6509 /*************************************************************//**
6510 InnoDB uses this function to compare two data fields for which the data type
6511 is such that we must use MySQL code to compare them. NOTE that the prototype
6512 of this function is in rem0cmp.c in InnoDB source code! If you change this
6513 function, remember to update the prototype there!
6514 @return 1, 0, -1, if a is greater, equal, less than b, respectively */
6515 UNIV_INTERN
6516 int
innobase_mysql_cmp_prefix(int mysql_type,uint charset_number,const unsigned char * a,unsigned int a_length,const unsigned char * b,unsigned int b_length)6517 innobase_mysql_cmp_prefix(
6518 /*======================*/
6519 int mysql_type, /*!< in: MySQL type */
6520 uint charset_number, /*!< in: number of the charset */
6521 const unsigned char* a, /*!< in: data field */
6522 unsigned int a_length, /*!< in: data field length,
6523 not UNIV_SQL_NULL */
6524 const unsigned char* b, /*!< in: data field */
6525 unsigned int b_length) /*!< in: data field length,
6526 not UNIV_SQL_NULL */
6527 {
6528 CHARSET_INFO* charset;
6529 int result;
6530
6531 charset = innobase_get_fts_charset(mysql_type, charset_number);
6532
6533 result = ha_compare_text(charset, (uchar*) a, a_length,
6534 (uchar*) b, b_length, 1, 0);
6535
6536 return(result);
6537 }
6538 /******************************************************************//**
6539 compare two character string according to their charset. */
6540 UNIV_INTERN
6541 int
innobase_fts_text_cmp(const void * cs,const void * p1,const void * p2)6542 innobase_fts_text_cmp(
6543 /*==================*/
6544 const void* cs, /*!< in: Character set */
6545 const void* p1, /*!< in: key */
6546 const void* p2) /*!< in: node */
6547 {
6548 const CHARSET_INFO* charset = (const CHARSET_INFO*) cs;
6549 const fts_string_t* s1 = (const fts_string_t*) p1;
6550 const fts_string_t* s2 = (const fts_string_t*) p2;
6551
6552 return(ha_compare_text(
6553 charset, s1->f_str, static_cast<uint>(s1->f_len),
6554 s2->f_str, static_cast<uint>(s2->f_len), 0, 0));
6555 }
6556 /******************************************************************//**
6557 compare two character string case insensitively according to their charset. */
6558 UNIV_INTERN
6559 int
innobase_fts_text_case_cmp(const void * cs,const void * p1,const void * p2)6560 innobase_fts_text_case_cmp(
6561 /*=======================*/
6562 const void* cs, /*!< in: Character set */
6563 const void* p1, /*!< in: key */
6564 const void* p2) /*!< in: node */
6565 {
6566 const CHARSET_INFO* charset = (const CHARSET_INFO*) cs;
6567 const fts_string_t* s1 = (const fts_string_t*) p1;
6568 const fts_string_t* s2 = (const fts_string_t*) p2;
6569 ulint newlen;
6570
6571 my_casedn_str(charset, (char*) s2->f_str);
6572
6573 newlen = strlen((const char*) s2->f_str);
6574
6575 return(ha_compare_text(
6576 charset, s1->f_str, static_cast<uint>(s1->f_len),
6577 s2->f_str, static_cast<uint>(newlen), 0, 0));
6578 }
6579 /******************************************************************//**
6580 Get the first character's code position for FTS index partition. */
6581 UNIV_INTERN
6582 ulint
innobase_strnxfrm(const CHARSET_INFO * cs,const uchar * str,const ulint len)6583 innobase_strnxfrm(
6584 /*==============*/
6585 const CHARSET_INFO*
6586 cs, /*!< in: Character set */
6587 const uchar* str, /*!< in: string */
6588 const ulint len) /*!< in: string length */
6589 {
6590 uchar mystr[2];
6591 ulint value;
6592
6593 if (!str || len == 0) {
6594 return(0);
6595 }
6596
6597 my_strnxfrm(cs, (uchar*) mystr, 2, str, len);
6598
6599 value = mach_read_from_2(mystr);
6600
6601 if (value > 255) {
6602 value = value / 256;
6603 }
6604
6605 return(value);
6606 }
6607
6608 /******************************************************************//**
6609 compare two character string according to their charset. */
6610 UNIV_INTERN
6611 int
innobase_fts_text_cmp_prefix(const void * cs,const void * p1,const void * p2)6612 innobase_fts_text_cmp_prefix(
6613 /*=========================*/
6614 const void* cs, /*!< in: Character set */
6615 const void* p1, /*!< in: prefix key */
6616 const void* p2) /*!< in: value to compare */
6617 {
6618 const CHARSET_INFO* charset = (const CHARSET_INFO*) cs;
6619 const fts_string_t* s1 = (const fts_string_t*) p1;
6620 const fts_string_t* s2 = (const fts_string_t*) p2;
6621 int result;
6622
6623 result = ha_compare_text(
6624 charset, s2->f_str, static_cast<uint>(s2->f_len),
6625 s1->f_str, static_cast<uint>(s1->f_len), 1, 0);
6626
6627 /* We switched s1, s2 position in ha_compare_text. So we need
6628 to negate the result */
6629 return(-result);
6630 }
6631
6632 /******************************************************************//**
6633 Makes all characters in a string lower case. */
6634 UNIV_INTERN
6635 size_t
innobase_fts_casedn_str(CHARSET_INFO * cs,char * src,size_t src_len,char * dst,size_t dst_len)6636 innobase_fts_casedn_str(
6637 /*====================*/
6638 CHARSET_INFO* cs, /*!< in: Character set */
6639 char* src, /*!< in: string to put in lower case */
6640 size_t src_len,/*!< in: input string length */
6641 char* dst, /*!< in: buffer for result string */
6642 size_t dst_len)/*!< in: buffer size */
6643 {
6644 if (cs->casedn_multiply == 1) {
6645 memcpy(dst, src, src_len);
6646 dst[src_len] = 0;
6647 my_casedn_str(cs, dst);
6648
6649 return(strlen(dst));
6650 } else {
6651 return(cs->cset->casedn(cs, src, src_len, dst, dst_len));
6652 }
6653 }
6654
6655 #define true_word_char(c, ch) ((c) & (_MY_U | _MY_L | _MY_NMR) || (ch) == '_')
6656
6657 #define misc_word_char(X) 0
6658
6659 /*************************************************************//**
6660 Get the next token from the given string and store it in *token.
6661 It is mostly copied from MyISAM's doc parsing function ft_simple_get_word()
6662 @return length of string processed */
6663 UNIV_INTERN
6664 ulint
innobase_mysql_fts_get_token(CHARSET_INFO * cs,const byte * start,const byte * end,fts_string_t * token,ulint * offset)6665 innobase_mysql_fts_get_token(
6666 /*=========================*/
6667 CHARSET_INFO* cs, /*!< in: Character set */
6668 const byte* start, /*!< in: start of text */
6669 const byte* end, /*!< in: one character past end of
6670 text */
6671 fts_string_t* token, /*!< out: token's text */
6672 ulint* offset) /*!< out: offset to token,
6673 measured as characters from
6674 'start' */
6675 {
6676 int mbl;
6677 const uchar* doc = start;
6678
6679 ut_a(cs);
6680
6681 token->f_n_char = token->f_len = 0;
6682 token->f_str = NULL;
6683
6684 for (;;) {
6685
6686 if (doc >= end) {
6687 return(doc - start);
6688 }
6689
6690 int ctype;
6691
6692 mbl = cs->cset->ctype(
6693 cs, &ctype, doc, (const uchar*) end);
6694
6695 if (true_word_char(ctype, *doc)) {
6696 break;
6697 }
6698
6699 doc += mbl > 0 ? mbl : (mbl < 0 ? -mbl : 1);
6700 }
6701
6702 ulint mwc = 0;
6703 ulint length = 0;
6704
6705 token->f_str = const_cast<byte*>(doc);
6706
6707 while (doc < end) {
6708
6709 int ctype;
6710
6711 mbl = cs->cset->ctype(
6712 cs, &ctype, (uchar*) doc, (uchar*) end);
6713 if (true_word_char(ctype, *doc)) {
6714 mwc = 0;
6715 } else if (!misc_word_char(*doc) || mwc) {
6716 break;
6717 } else {
6718 ++mwc;
6719 }
6720
6721 ++length;
6722
6723 doc += mbl > 0 ? mbl : (mbl < 0 ? -mbl : 1);
6724 }
6725
6726 token->f_len = (uint) (doc - token->f_str) - mwc;
6727 token->f_n_char = length;
6728
6729 return(doc - start);
6730 }
6731
6732 /**************************************************************//**
6733 Converts a MySQL type to an InnoDB type. Note that this function returns
6734 the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
6735 VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
6736 @return DATA_BINARY, DATA_VARCHAR, ... */
6737 UNIV_INTERN
6738 ulint
get_innobase_type_from_mysql_type(ulint * unsigned_flag,const void * f)6739 get_innobase_type_from_mysql_type(
6740 /*==============================*/
6741 ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
6742 'unsigned type';
6743 at least ENUM and SET,
6744 and unsigned integer
6745 types are 'unsigned types' */
6746 const void* f) /*!< in: MySQL Field */
6747 {
6748 const class Field* field = reinterpret_cast<const class Field*>(f);
6749
6750 /* The following asserts try to check that the MySQL type code fits in
6751 8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
6752 the type */
6753
6754 DBUG_ASSERT((ulint)MYSQL_TYPE_STRING < 256);
6755 DBUG_ASSERT((ulint)MYSQL_TYPE_VAR_STRING < 256);
6756 DBUG_ASSERT((ulint)MYSQL_TYPE_DOUBLE < 256);
6757 DBUG_ASSERT((ulint)MYSQL_TYPE_FLOAT < 256);
6758 DBUG_ASSERT((ulint)MYSQL_TYPE_DECIMAL < 256);
6759
6760 if (field->flags & UNSIGNED_FLAG) {
6761
6762 *unsigned_flag = DATA_UNSIGNED;
6763 } else {
6764 *unsigned_flag = 0;
6765 }
6766
6767 if (field->real_type() == MYSQL_TYPE_ENUM
6768 || field->real_type() == MYSQL_TYPE_SET) {
6769
6770 /* MySQL has field->type() a string type for these, but the
6771 data is actually internally stored as an unsigned integer
6772 code! */
6773
6774 *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
6775 flag set to zero, even though
6776 internally this is an unsigned
6777 integer type */
6778 return(DATA_INT);
6779 }
6780
6781 switch (field->type()) {
6782 /* NOTE that we only allow string types in DATA_MYSQL and
6783 DATA_VARMYSQL */
6784 case MYSQL_TYPE_VAR_STRING: /* old <= 4.1 VARCHAR */
6785 case MYSQL_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
6786 if (field->binary()) {
6787 return(DATA_BINARY);
6788 } else if (strcmp(field->charset()->name,
6789 "latin1_swedish_ci") == 0) {
6790 return(DATA_VARCHAR);
6791 } else {
6792 return(DATA_VARMYSQL);
6793 }
6794 case MYSQL_TYPE_BIT:
6795 case MYSQL_TYPE_STRING: if (field->binary()) {
6796
6797 return(DATA_FIXBINARY);
6798 } else if (strcmp(field->charset()->name,
6799 "latin1_swedish_ci") == 0) {
6800 return(DATA_CHAR);
6801 } else {
6802 return(DATA_MYSQL);
6803 }
6804 case MYSQL_TYPE_NEWDECIMAL:
6805 return(DATA_FIXBINARY);
6806 case MYSQL_TYPE_LONG:
6807 case MYSQL_TYPE_LONGLONG:
6808 case MYSQL_TYPE_TINY:
6809 case MYSQL_TYPE_SHORT:
6810 case MYSQL_TYPE_INT24:
6811 case MYSQL_TYPE_DATE:
6812 case MYSQL_TYPE_YEAR:
6813 case MYSQL_TYPE_NEWDATE:
6814 return(DATA_INT);
6815 case MYSQL_TYPE_TIME:
6816 case MYSQL_TYPE_DATETIME:
6817 case MYSQL_TYPE_TIMESTAMP:
6818 switch (field->real_type()) {
6819 case MYSQL_TYPE_TIME:
6820 case MYSQL_TYPE_DATETIME:
6821 case MYSQL_TYPE_TIMESTAMP:
6822 return(DATA_INT);
6823 default: /* Fall through */
6824 DBUG_ASSERT((ulint)MYSQL_TYPE_DECIMAL < 256);
6825 case MYSQL_TYPE_TIME2:
6826 case MYSQL_TYPE_DATETIME2:
6827 case MYSQL_TYPE_TIMESTAMP2:
6828 return(DATA_FIXBINARY);
6829 }
6830 case MYSQL_TYPE_FLOAT:
6831 return(DATA_FLOAT);
6832 case MYSQL_TYPE_DOUBLE:
6833 return(DATA_DOUBLE);
6834 case MYSQL_TYPE_DECIMAL:
6835 return(DATA_DECIMAL);
6836 case MYSQL_TYPE_GEOMETRY:
6837 case MYSQL_TYPE_TINY_BLOB:
6838 case MYSQL_TYPE_MEDIUM_BLOB:
6839 case MYSQL_TYPE_BLOB:
6840 case MYSQL_TYPE_LONG_BLOB:
6841 return(DATA_BLOB);
6842 case MYSQL_TYPE_NULL:
6843 /* MySQL currently accepts "NULL" datatype, but will
6844 reject such datatype in the next release. We will cope
6845 with it and not trigger assertion failure in 5.1 */
6846 break;
6847 default:
6848 ut_error;
6849 }
6850
6851 return(0);
6852 }
6853
6854 /*******************************************************************//**
6855 Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
6856 storage format. */
6857 static inline
6858 void
innobase_write_to_2_little_endian(byte * buf,ulint val)6859 innobase_write_to_2_little_endian(
6860 /*==============================*/
6861 byte* buf, /*!< in: where to store */
6862 ulint val) /*!< in: value to write, must be < 64k */
6863 {
6864 ut_a(val < 256 * 256);
6865
6866 buf[0] = (byte)(val & 0xFF);
6867 buf[1] = (byte)(val / 256);
6868 }
6869
6870 /*******************************************************************//**
6871 Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
6872 storage format.
6873 @return value */
6874 static inline
6875 uint
innobase_read_from_2_little_endian(const uchar * buf)6876 innobase_read_from_2_little_endian(
6877 /*===============================*/
6878 const uchar* buf) /*!< in: from where to read */
6879 {
6880 return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))));
6881 }
6882
6883 /*******************************************************************//**
6884 Stores a key value for a row to a buffer.
6885 @return key value length as stored in buff */
6886 UNIV_INTERN
6887 uint
store_key_val_for_row(uint keynr,char * buff,uint buff_len,const uchar * record)6888 ha_innobase::store_key_val_for_row(
6889 /*===============================*/
6890 uint keynr, /*!< in: key number */
6891 char* buff, /*!< in/out: buffer for the key value (in MySQL
6892 format) */
6893 uint buff_len,/*!< in: buffer length */
6894 const uchar* record)/*!< in: row in MySQL format */
6895 {
6896 KEY* key_info = table->key_info + keynr;
6897 KEY_PART_INFO* key_part = key_info->key_part;
6898 KEY_PART_INFO* end =
6899 key_part + key_info->user_defined_key_parts;
6900 char* buff_start = buff;
6901 enum_field_types mysql_type;
6902 Field* field;
6903 ibool is_null;
6904
6905 DBUG_ENTER("store_key_val_for_row");
6906
6907 /* The format for storing a key field in MySQL is the following:
6908
6909 1. If the column can be NULL, then in the first byte we put 1 if the
6910 field value is NULL, 0 otherwise.
6911
6912 2. If the column is of a BLOB type (it must be a column prefix field
6913 in this case), then we put the length of the data in the field to the
6914 next 2 bytes, in the little-endian format. If the field is SQL NULL,
6915 then these 2 bytes are set to 0. Note that the length of data in the
6916 field is <= column prefix length.
6917
6918 3. In a column prefix field, prefix_len next bytes are reserved for
6919 data. In a normal field the max field length next bytes are reserved
6920 for data. For a VARCHAR(n) the max field length is n. If the stored
6921 value is the SQL NULL then these data bytes are set to 0.
6922
6923 4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
6924 in the MySQL row format, the length is stored in 1 or 2 bytes,
6925 depending on the maximum allowed length. But in the MySQL key value
6926 format, the length always takes 2 bytes.
6927
6928 We have to zero-fill the buffer so that MySQL is able to use a
6929 simple memcmp to compare two key values to determine if they are
6930 equal. MySQL does this to compare contents of two 'ref' values. */
6931
6932 memset(buff, 0, buff_len);
6933
6934 for (; key_part != end; key_part++) {
6935 is_null = FALSE;
6936
6937 if (key_part->null_bit) {
6938 if (record[key_part->null_offset]
6939 & key_part->null_bit) {
6940 *buff = 1;
6941 is_null = TRUE;
6942 } else {
6943 *buff = 0;
6944 }
6945 buff++;
6946 }
6947
6948 field = key_part->field;
6949 mysql_type = field->type();
6950
6951 if (mysql_type == MYSQL_TYPE_VARCHAR) {
6952 /* >= 5.0.3 true VARCHAR */
6953 ulint lenlen;
6954 ulint len;
6955 const byte* data;
6956 ulint key_len;
6957 ulint true_len;
6958 const CHARSET_INFO* cs;
6959 int error=0;
6960
6961 key_len = key_part->length;
6962
6963 if (is_null) {
6964 buff += key_len + 2;
6965
6966 continue;
6967 }
6968 cs = field->charset();
6969
6970 lenlen = (ulint)
6971 (((Field_varstring*) field)->length_bytes);
6972
6973 data = row_mysql_read_true_varchar(&len,
6974 (byte*) (record
6975 + (ulint) get_field_offset(table, field)),
6976 lenlen);
6977
6978 true_len = len;
6979
6980 /* For multi byte character sets we need to calculate
6981 the true length of the key */
6982
6983 if (len > 0 && cs->mbmaxlen > 1) {
6984 true_len = (ulint) cs->cset->well_formed_len(cs,
6985 (const char*) data,
6986 (const char*) data + len,
6987 (uint) (key_len / cs->mbmaxlen),
6988 &error);
6989 }
6990
6991 /* In a column prefix index, we may need to truncate
6992 the stored value: */
6993
6994 if (true_len > key_len) {
6995 true_len = key_len;
6996 }
6997
6998 /* The length in a key value is always stored in 2
6999 bytes */
7000
7001 row_mysql_store_true_var_len((byte*) buff, true_len, 2);
7002 buff += 2;
7003
7004 memcpy(buff, data, true_len);
7005
7006 /* Note that we always reserve the maximum possible
7007 length of the true VARCHAR in the key value, though
7008 only len first bytes after the 2 length bytes contain
7009 actual data. The rest of the space was reset to zero
7010 in the memset() call above. */
7011
7012 buff += key_len;
7013
7014 } else if (mysql_type == MYSQL_TYPE_TINY_BLOB
7015 || mysql_type == MYSQL_TYPE_MEDIUM_BLOB
7016 || mysql_type == MYSQL_TYPE_BLOB
7017 || mysql_type == MYSQL_TYPE_LONG_BLOB
7018 /* MYSQL_TYPE_GEOMETRY data is treated
7019 as BLOB data in innodb. */
7020 || mysql_type == MYSQL_TYPE_GEOMETRY) {
7021
7022 const CHARSET_INFO* cs;
7023 ulint key_len;
7024 ulint true_len;
7025 int error=0;
7026 ulint blob_len;
7027 const byte* blob_data;
7028
7029 ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
7030
7031 key_len = key_part->length;
7032
7033 if (is_null) {
7034 buff += key_len + 2;
7035
7036 continue;
7037 }
7038
7039 cs = field->charset();
7040
7041 blob_data = row_mysql_read_blob_ref(&blob_len,
7042 (byte*) (record
7043 + (ulint) get_field_offset(table, field)),
7044 (ulint) field->pack_length(),
7045 field->column_format() ==
7046 COLUMN_FORMAT_TYPE_COMPRESSED,
7047 reinterpret_cast<const byte*>(
7048 field->zip_dict_data.str),
7049 field->zip_dict_data.length, prebuilt);
7050
7051 true_len = blob_len;
7052
7053 ut_a(get_field_offset(table, field)
7054 == key_part->offset);
7055
7056 /* For multi byte character sets we need to calculate
7057 the true length of the key */
7058
7059 if (blob_len > 0 && cs->mbmaxlen > 1) {
7060 true_len = (ulint) cs->cset->well_formed_len(cs,
7061 (const char*) blob_data,
7062 (const char*) blob_data
7063 + blob_len,
7064 (uint) (key_len / cs->mbmaxlen),
7065 &error);
7066 }
7067
7068 /* All indexes on BLOB and TEXT are column prefix
7069 indexes, and we may need to truncate the data to be
7070 stored in the key value: */
7071
7072 if (true_len > key_len) {
7073 true_len = key_len;
7074 }
7075
7076 /* MySQL reserves 2 bytes for the length and the
7077 storage of the number is little-endian */
7078
7079 innobase_write_to_2_little_endian(
7080 (byte*) buff, true_len);
7081 buff += 2;
7082
7083 memcpy(buff, blob_data, true_len);
7084
7085 /* Note that we always reserve the maximum possible
7086 length of the BLOB prefix in the key value. */
7087
7088 buff += key_len;
7089 } else {
7090 /* Here we handle all other data types except the
7091 true VARCHAR, BLOB and TEXT. Note that the column
7092 value we store may be also in a column prefix
7093 index. */
7094
7095 const CHARSET_INFO* cs = NULL;
7096 ulint true_len;
7097 ulint key_len;
7098 const uchar* src_start;
7099 int error=0;
7100 enum_field_types real_type;
7101
7102 key_len = key_part->length;
7103
7104 if (is_null) {
7105 buff += key_len;
7106
7107 continue;
7108 }
7109
7110 src_start = record + key_part->offset;
7111 real_type = field->real_type();
7112 true_len = key_len;
7113
7114 /* Character set for the field is defined only
7115 to fields whose type is string and real field
7116 type is not enum or set. For these fields check
7117 if character set is multi byte. */
7118
7119 if (real_type != MYSQL_TYPE_ENUM
7120 && real_type != MYSQL_TYPE_SET
7121 && ( mysql_type == MYSQL_TYPE_VAR_STRING
7122 || mysql_type == MYSQL_TYPE_STRING)) {
7123
7124 cs = field->charset();
7125
7126 /* For multi byte character sets we need to
7127 calculate the true length of the key */
7128
7129 if (key_len > 0 && cs->mbmaxlen > 1) {
7130
7131 true_len = (ulint)
7132 cs->cset->well_formed_len(cs,
7133 (const char*) src_start,
7134 (const char*) src_start
7135 + key_len,
7136 (uint) (key_len
7137 / cs->mbmaxlen),
7138 &error);
7139 }
7140 }
7141
7142 memcpy(buff, src_start, true_len);
7143 buff += true_len;
7144
7145 /* Pad the unused space with spaces. */
7146
7147 if (true_len < key_len) {
7148 ulint pad_len = key_len - true_len;
7149 ut_a(cs != NULL);
7150 ut_a(!(pad_len % cs->mbminlen));
7151
7152 cs->cset->fill(cs, buff, pad_len,
7153 0x20 /* space */);
7154 buff += pad_len;
7155 }
7156 }
7157 }
7158
7159 ut_a(buff <= buff_start + buff_len);
7160
7161 DBUG_RETURN((uint)(buff - buff_start));
7162 }
7163
7164 /**************************************************************//**
7165 Determines if a field is needed in a prebuilt struct 'template'.
7166 @return field to use, or NULL if the field is not needed */
7167 static
7168 const Field*
build_template_needs_field(ibool index_contains,ibool read_just_key,ibool fetch_all_in_key,ibool fetch_primary_key_cols,dict_index_t * index,const TABLE * table,ulint i)7169 build_template_needs_field(
7170 /*=======================*/
7171 ibool index_contains, /*!< in:
7172 dict_index_contains_col_or_prefix(
7173 index, i) */
7174 ibool read_just_key, /*!< in: TRUE when MySQL calls
7175 ha_innobase::extra with the
7176 argument HA_EXTRA_KEYREAD; it is enough
7177 to read just columns defined in
7178 the index (i.e., no read of the
7179 clustered index record necessary) */
7180 ibool fetch_all_in_key,
7181 /*!< in: true=fetch all fields in
7182 the index */
7183 ibool fetch_primary_key_cols,
7184 /*!< in: true=fetch the
7185 primary key columns */
7186 dict_index_t* index, /*!< in: InnoDB index to use */
7187 const TABLE* table, /*!< in: MySQL table object */
7188 ulint i) /*!< in: field index in InnoDB table */
7189 {
7190 const Field* field = table->field[i];
7191
7192 ut_ad(index_contains == dict_index_contains_col_or_prefix(index, i));
7193
7194 if (!index_contains) {
7195 if (read_just_key) {
7196 /* If this is a 'key read', we do not need
7197 columns that are not in the key */
7198
7199 return(NULL);
7200 }
7201 } else if (fetch_all_in_key) {
7202 /* This field is needed in the query */
7203
7204 return(field);
7205 }
7206
7207 if (bitmap_is_set(table->read_set, static_cast<uint>(i))
7208 || bitmap_is_set(table->write_set, static_cast<uint>(i))) {
7209 /* This field is needed in the query */
7210
7211 return(field);
7212 }
7213
7214 if (fetch_primary_key_cols
7215 && dict_table_col_in_clustered_key(index->table, i)) {
7216 /* This field is needed in the query */
7217
7218 return(field);
7219 }
7220
7221 /* This field is not needed in the query, skip it */
7222
7223 return(NULL);
7224 }
7225
7226 /**************************************************************//**
7227 Determines if a field is needed in a prebuilt struct 'template'.
7228 @return whether the field is needed for index condition pushdown */
7229 inline
7230 bool
build_template_needs_field_in_icp(const dict_index_t * index,const row_prebuilt_t * prebuilt,bool contains,ulint i)7231 build_template_needs_field_in_icp(
7232 /*==============================*/
7233 const dict_index_t* index, /*!< in: InnoDB index */
7234 const row_prebuilt_t* prebuilt,/*!< in: row fetch template */
7235 bool contains,/*!< in: whether the index contains
7236 column i */
7237 ulint i) /*!< in: column number */
7238 {
7239 ut_ad(contains == dict_index_contains_col_or_prefix(index, i));
7240
7241 return(index == prebuilt->index
7242 ? contains
7243 : dict_index_contains_col_or_prefix(prebuilt->index, i));
7244 }
7245
7246 /**************************************************************//**
7247 Adds a field to a prebuilt struct 'template'.
7248 @return the field template */
7249 static
7250 mysql_row_templ_t*
build_template_field(row_prebuilt_t * prebuilt,dict_index_t * clust_index,dict_index_t * index,TABLE * table,const Field * field,ulint i)7251 build_template_field(
7252 /*=================*/
7253 row_prebuilt_t* prebuilt, /*!< in/out: template */
7254 dict_index_t* clust_index, /*!< in: InnoDB clustered index */
7255 dict_index_t* index, /*!< in: InnoDB index to use */
7256 TABLE* table, /*!< in: MySQL table object */
7257 const Field* field, /*!< in: field in MySQL table */
7258 ulint i) /*!< in: field index in InnoDB table */
7259 {
7260 mysql_row_templ_t* templ;
7261 const dict_col_t* col;
7262
7263 ut_ad(field == table->field[i]);
7264 ut_ad(clust_index->table == index->table);
7265
7266 col = dict_table_get_nth_col(index->table, i);
7267
7268 templ = prebuilt->mysql_template + prebuilt->n_template++;
7269 UNIV_MEM_INVALID(templ, sizeof *templ);
7270 templ->col_no = i;
7271 templ->clust_rec_field_no = dict_col_get_clust_pos(col, clust_index);
7272 ut_a(templ->clust_rec_field_no != ULINT_UNDEFINED);
7273
7274 if (dict_index_is_clust(index)) {
7275 templ->rec_field_is_prefix = false;
7276 templ->rec_field_no = templ->clust_rec_field_no;
7277 templ->rec_prefix_field_no = ULINT_UNDEFINED;
7278 } else {
7279 /* If we're in a secondary index, keep track of the original
7280 index position even if this is just a prefix index; we will use
7281 this later to avoid a cluster index lookup in some cases.*/
7282
7283 templ->rec_field_no = dict_index_get_nth_col_pos(index, i,
7284 &templ->rec_prefix_field_no);
7285 templ->rec_field_is_prefix
7286 = (templ->rec_field_no == ULINT_UNDEFINED)
7287 && (templ->rec_prefix_field_no != ULINT_UNDEFINED);
7288 #ifdef UNIV_DEBUG
7289 if (templ->rec_prefix_field_no != ULINT_UNDEFINED)
7290 {
7291 const dict_field_t* field = dict_index_get_nth_field(
7292 index,
7293 templ->rec_prefix_field_no);
7294 ut_ad(templ->rec_field_is_prefix
7295 == (field->prefix_len != 0));
7296 } else {
7297 ut_ad(!templ->rec_field_is_prefix);
7298 }
7299 #endif
7300 }
7301
7302 if (field->real_maybe_null()) {
7303 templ->mysql_null_byte_offset =
7304 field->null_offset();
7305
7306 templ->mysql_null_bit_mask = (ulint) field->null_bit;
7307 } else {
7308 templ->mysql_null_bit_mask = 0;
7309 }
7310
7311 templ->mysql_col_offset = (ulint) get_field_offset(table, field);
7312
7313 templ->mysql_col_len = (ulint) field->pack_length();
7314 templ->type = col->mtype;
7315 templ->mysql_type = (ulint) field->type();
7316
7317 if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
7318 templ->mysql_length_bytes = (ulint)
7319 (((Field_varstring*) field)->length_bytes);
7320 }
7321
7322 templ->charset = dtype_get_charset_coll(col->prtype);
7323 templ->mbminlen = dict_col_get_mbminlen(col);
7324 templ->mbmaxlen = dict_col_get_mbmaxlen(col);
7325 templ->is_unsigned = col->prtype & DATA_UNSIGNED;
7326 templ->compressed = (field->column_format()
7327 == COLUMN_FORMAT_TYPE_COMPRESSED);
7328 templ->zip_dict_data = field->zip_dict_data;
7329
7330 if (!dict_index_is_clust(index)
7331 && templ->rec_field_no == ULINT_UNDEFINED) {
7332 prebuilt->need_to_access_clustered = TRUE;
7333 }
7334
7335 if (prebuilt->mysql_prefix_len < templ->mysql_col_offset
7336 + templ->mysql_col_len) {
7337 prebuilt->mysql_prefix_len = templ->mysql_col_offset
7338 + templ->mysql_col_len;
7339 }
7340
7341 if (templ->type == DATA_BLOB) {
7342 prebuilt->templ_contains_blob = TRUE;
7343 }
7344
7345 return(templ);
7346 }
7347
7348 /**************************************************************//**
7349 Builds a 'template' to the prebuilt struct. The template is used in fast
7350 retrieval of just those column values MySQL needs in its processing. */
7351 UNIV_INTERN
7352 void
build_template(bool whole_row)7353 ha_innobase::build_template(
7354 /*========================*/
7355 bool whole_row) /*!< in: true=ROW_MYSQL_WHOLE_ROW,
7356 false=ROW_MYSQL_REC_FIELDS */
7357 {
7358 dict_index_t* index;
7359 dict_index_t* clust_index;
7360 ulint n_fields;
7361 ibool fetch_all_in_key = FALSE;
7362 ibool fetch_primary_key_cols = FALSE;
7363 ulint i;
7364
7365 if (prebuilt->select_lock_type == LOCK_X) {
7366 /* We always retrieve the whole clustered index record if we
7367 use exclusive row level locks, for example, if the read is
7368 done in an UPDATE statement. */
7369
7370 whole_row = true;
7371 } else if (!whole_row) {
7372 if (prebuilt->hint_need_to_fetch_extra_cols
7373 == ROW_RETRIEVE_ALL_COLS) {
7374
7375 /* We know we must at least fetch all columns in the
7376 key, or all columns in the table */
7377
7378 if (prebuilt->read_just_key) {
7379 /* MySQL has instructed us that it is enough
7380 to fetch the columns in the key; looks like
7381 MySQL can set this flag also when there is
7382 only a prefix of the column in the key: in
7383 that case we retrieve the whole column from
7384 the clustered index */
7385
7386 fetch_all_in_key = TRUE;
7387 } else {
7388 whole_row = true;
7389 }
7390 } else if (prebuilt->hint_need_to_fetch_extra_cols
7391 == ROW_RETRIEVE_PRIMARY_KEY) {
7392 /* We must at least fetch all primary key cols. Note
7393 that if the clustered index was internally generated
7394 by InnoDB on the row id (no primary key was
7395 defined), then row_search_for_mysql() will always
7396 retrieve the row id to a special buffer in the
7397 prebuilt struct. */
7398
7399 fetch_primary_key_cols = TRUE;
7400 }
7401 }
7402
7403 clust_index = dict_table_get_first_index(prebuilt->table);
7404
7405 index = whole_row ? clust_index : prebuilt->index;
7406
7407 prebuilt->need_to_access_clustered = (index == clust_index);
7408
7409 /* Either prebuilt->index should be a secondary index, or it
7410 should be the clustered index. */
7411 ut_ad(dict_index_is_clust(index) == (index == clust_index));
7412
7413 /* Below we check column by column if we need to access
7414 the clustered index. */
7415
7416 n_fields = (ulint) table->s->fields; /* number of columns */
7417
7418 if (!prebuilt->mysql_template) {
7419 prebuilt->mysql_template = (mysql_row_templ_t*)
7420 mem_alloc(n_fields * sizeof(mysql_row_templ_t));
7421 }
7422
7423 prebuilt->template_type = whole_row
7424 ? ROW_MYSQL_WHOLE_ROW : ROW_MYSQL_REC_FIELDS;
7425 prebuilt->null_bitmap_len = table->s->null_bytes;
7426
7427 /* Prepare to build prebuilt->mysql_template[]. */
7428 prebuilt->templ_contains_blob = FALSE;
7429 prebuilt->mysql_prefix_len = 0;
7430 prebuilt->n_template = 0;
7431 prebuilt->idx_cond_n_cols = 0;
7432
7433 /* Note that in InnoDB, i is the column number in the table.
7434 MySQL calls columns 'fields'. */
7435
7436 if (active_index != MAX_KEY && active_index == pushed_idx_cond_keyno) {
7437 /* Push down an index condition or an end_range check. */
7438 for (i = 0; i < n_fields; i++) {
7439 const ibool index_contains
7440 = dict_index_contains_col_or_prefix(index, i);
7441
7442 /* Test if an end_range or an index condition
7443 refers to the field. Note that "index" and
7444 "index_contains" may refer to the clustered index.
7445 Index condition pushdown is relative to prebuilt->index
7446 (the index that is being looked up first). */
7447
7448 /* When join_read_always_key() invokes this
7449 code via handler::ha_index_init() and
7450 ha_innobase::index_init(), end_range is not
7451 yet initialized. Because of that, we must
7452 always check for index_contains, instead of
7453 the subset
7454 field->part_of_key.is_set(active_index)
7455 which would be acceptable if end_range==NULL. */
7456 if (build_template_needs_field_in_icp(
7457 index, prebuilt, index_contains, i)) {
7458 /* Needed in ICP */
7459 const Field* field;
7460 mysql_row_templ_t* templ;
7461
7462 if (whole_row) {
7463 field = table->field[i];
7464 } else {
7465 field = build_template_needs_field(
7466 index_contains,
7467 prebuilt->read_just_key,
7468 fetch_all_in_key,
7469 fetch_primary_key_cols,
7470 index, table, i);
7471 if (!field) {
7472 continue;
7473 }
7474 }
7475
7476 templ = build_template_field(
7477 prebuilt, clust_index, index,
7478 table, field, i);
7479 prebuilt->idx_cond_n_cols++;
7480 ut_ad(prebuilt->idx_cond_n_cols
7481 == prebuilt->n_template);
7482
7483 if (index == prebuilt->index) {
7484 templ->icp_rec_field_no
7485 = templ->rec_field_no;
7486 } else {
7487 templ->icp_rec_field_no
7488 = dict_index_get_nth_col_pos(
7489 prebuilt->index, i,
7490 NULL);
7491 }
7492
7493 if (dict_index_is_clust(prebuilt->index)) {
7494 ut_ad(templ->icp_rec_field_no
7495 != ULINT_UNDEFINED);
7496 /* If the primary key includes
7497 a column prefix, use it in
7498 index condition pushdown,
7499 because the condition is
7500 evaluated before fetching any
7501 off-page (externally stored)
7502 columns. */
7503 if (templ->icp_rec_field_no
7504 < prebuilt->index->n_uniq) {
7505 /* This is a key column;
7506 all set. */
7507 continue;
7508 }
7509 } else if (templ->icp_rec_field_no
7510 != ULINT_UNDEFINED) {
7511 continue;
7512 }
7513
7514 /* This is a column prefix index.
7515 The column prefix can be used in
7516 an end_range comparison. */
7517
7518 templ->icp_rec_field_no
7519 = dict_index_get_nth_col_or_prefix_pos(
7520 prebuilt->index, i, TRUE, NULL);
7521 ut_ad(templ->icp_rec_field_no
7522 != ULINT_UNDEFINED);
7523
7524 /* Index condition pushdown can be used on
7525 all columns of a secondary index, and on
7526 the PRIMARY KEY columns. On the clustered
7527 index, it must never be used on other than
7528 PRIMARY KEY columns, because those columns
7529 may be stored off-page, and we will not
7530 fetch externally stored columns before
7531 checking the index condition. */
7532 /* TODO: test the above with an assertion
7533 like this. Note that index conditions are
7534 currently pushed down as part of the
7535 "optimizer phase" while end_range is done
7536 as part of the execution phase. Therefore,
7537 we were unable to use an accurate condition
7538 for end_range in the "if" condition above,
7539 and the following assertion would fail.
7540 ut_ad(!dict_index_is_clust(prebuilt->index)
7541 || templ->rec_field_no
7542 < prebuilt->index->n_uniq);
7543 */
7544 }
7545 }
7546
7547 ut_ad(prebuilt->idx_cond_n_cols > 0);
7548 ut_ad(prebuilt->idx_cond_n_cols == prebuilt->n_template);
7549
7550 /* Include the fields that are not needed in index condition
7551 pushdown. */
7552 for (i = 0; i < n_fields; i++) {
7553 const ibool index_contains
7554 = dict_index_contains_col_or_prefix(index, i);
7555
7556 if (!build_template_needs_field_in_icp(
7557 index, prebuilt, index_contains, i)) {
7558 /* Not needed in ICP */
7559 const Field* field;
7560
7561 if (whole_row) {
7562 field = table->field[i];
7563 } else {
7564 field = build_template_needs_field(
7565 index_contains,
7566 prebuilt->read_just_key,
7567 fetch_all_in_key,
7568 fetch_primary_key_cols,
7569 index, table, i);
7570 if (!field) {
7571 continue;
7572 }
7573 }
7574
7575 build_template_field(prebuilt,
7576 clust_index, index,
7577 table, field, i);
7578 }
7579 }
7580
7581 prebuilt->idx_cond = this;
7582 } else {
7583 /* No index condition pushdown */
7584 prebuilt->idx_cond = NULL;
7585
7586 for (i = 0; i < n_fields; i++) {
7587 const Field* field;
7588
7589 if (whole_row) {
7590 field = table->field[i];
7591 } else {
7592 field = build_template_needs_field(
7593 dict_index_contains_col_or_prefix(
7594 index, i),
7595 prebuilt->read_just_key,
7596 fetch_all_in_key,
7597 fetch_primary_key_cols,
7598 index, table, i);
7599 if (!field) {
7600 continue;
7601 }
7602 }
7603
7604 build_template_field(prebuilt, clust_index, index,
7605 table, field, i);
7606 }
7607 }
7608
7609 if (index != clust_index && prebuilt->need_to_access_clustered) {
7610 /* Change rec_field_no's to correspond to the clustered index
7611 record */
7612 for (i = 0; i < prebuilt->n_template; i++) {
7613
7614 mysql_row_templ_t* templ
7615 = &prebuilt->mysql_template[i];
7616
7617 templ->rec_field_no = templ->clust_rec_field_no;
7618 }
7619 }
7620 }
7621
7622 /********************************************************************//**
7623 This special handling is really to overcome the limitations of MySQL's
7624 binlogging. We need to eliminate the non-determinism that will arise in
7625 INSERT ... SELECT type of statements, since MySQL binlog only stores the
7626 min value of the autoinc interval. Once that is fixed we can get rid of
7627 the special lock handling.
7628 @return DB_SUCCESS if all OK else error code */
7629 UNIV_INTERN
7630 dberr_t
innobase_lock_autoinc(void)7631 ha_innobase::innobase_lock_autoinc(void)
7632 /*====================================*/
7633 {
7634 DBUG_ENTER("ha_innobase::innobase_lock_autoinc");
7635 dberr_t error = DB_SUCCESS;
7636
7637 ut_ad(!srv_read_only_mode);
7638
7639 switch (innobase_autoinc_lock_mode) {
7640 case AUTOINC_NO_LOCKING:
7641 /* Acquire only the AUTOINC mutex. */
7642 dict_table_autoinc_lock(prebuilt->table);
7643 break;
7644
7645 case AUTOINC_NEW_STYLE_LOCKING:
7646 /* For simple (single/multi) row INSERTs, we fallback to the
7647 old style only if another transaction has already acquired
7648 the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
7649 etc. type of statement. */
7650 if (thd_sql_command(user_thd) == SQLCOM_INSERT
7651 || thd_sql_command(user_thd) == SQLCOM_REPLACE) {
7652 dict_table_t* ib_table = prebuilt->table;
7653
7654 /* Acquire the AUTOINC mutex. */
7655 dict_table_autoinc_lock(ib_table);
7656
7657 /* We need to check that another transaction isn't
7658 already holding the AUTOINC lock on the table. */
7659 if (ib_table->n_waiting_or_granted_auto_inc_locks) {
7660 /* Release the mutex to avoid deadlocks. */
7661 dict_table_autoinc_unlock(ib_table);
7662 } else {
7663 break;
7664 }
7665 }
7666 // fallthrough
7667 // to old style locking.
7668
7669 case AUTOINC_OLD_STYLE_LOCKING:
7670 DBUG_EXECUTE_IF("die_if_autoinc_old_lock_style_used",
7671 ut_ad(0););
7672 error = row_lock_table_autoinc_for_mysql(prebuilt);
7673
7674 if (error == DB_SUCCESS) {
7675
7676 /* Acquire the AUTOINC mutex. */
7677 dict_table_autoinc_lock(prebuilt->table);
7678 }
7679 break;
7680
7681 default:
7682 ut_error;
7683 }
7684
7685 DBUG_RETURN(error);
7686 }
7687
7688 /********************************************************************//**
7689 Reset the autoinc value in the table.
7690 @return DB_SUCCESS if all went well else error code */
7691 UNIV_INTERN
7692 dberr_t
innobase_reset_autoinc(ulonglong autoinc)7693 ha_innobase::innobase_reset_autoinc(
7694 /*================================*/
7695 ulonglong autoinc) /*!< in: value to store */
7696 {
7697 dberr_t error;
7698
7699 error = innobase_lock_autoinc();
7700
7701 if (error == DB_SUCCESS) {
7702
7703 dict_table_autoinc_initialize(prebuilt->table, autoinc);
7704
7705 dict_table_autoinc_unlock(prebuilt->table);
7706 }
7707
7708 return(error);
7709 }
7710
7711 /********************************************************************//**
7712 Store the autoinc value in the table. The autoinc value is only set if
7713 it's greater than the existing autoinc value in the table.
7714 @return DB_SUCCESS if all went well else error code */
7715 UNIV_INTERN
7716 dberr_t
innobase_set_max_autoinc(ulonglong auto_inc)7717 ha_innobase::innobase_set_max_autoinc(
7718 /*==================================*/
7719 ulonglong auto_inc) /*!< in: value to store */
7720 {
7721 dberr_t error;
7722
7723 error = innobase_lock_autoinc();
7724
7725 if (error == DB_SUCCESS) {
7726
7727 dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
7728
7729 dict_table_autoinc_unlock(prebuilt->table);
7730 }
7731
7732 return(error);
7733 }
7734
7735 /********************************************************************//**
7736 Stores a row in an InnoDB database, to the table specified in this
7737 handle.
7738 @return error code */
7739 UNIV_INTERN
7740 int
write_row(uchar * record)7741 ha_innobase::write_row(
7742 /*===================*/
7743 uchar* record) /*!< in: a row in MySQL format */
7744 {
7745 dberr_t error;
7746 int error_result= 0;
7747 ibool auto_inc_used= FALSE;
7748 ulint sql_command;
7749 trx_t* trx = thd_to_trx(user_thd);
7750
7751 DBUG_ENTER("ha_innobase::write_row");
7752
7753 if (high_level_read_only) {
7754 ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
7755 DBUG_RETURN(HA_ERR_TABLE_READONLY);
7756 } else if (prebuilt->trx != trx) {
7757 sql_print_error("The transaction object for the table handle "
7758 "is at %p, but for the current thread it is at "
7759 "%p",
7760 (const void*) prebuilt->trx, (const void*) trx);
7761
7762 fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
7763 ut_print_buf(stderr, ((const byte*) prebuilt) - 100, 200);
7764 fputs("\n"
7765 "InnoDB: Dump of 200 bytes around ha_data: ",
7766 stderr);
7767 ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
7768 putc('\n', stderr);
7769 ut_error;
7770 } else if (!trx_is_started(trx)) {
7771 ++trx->will_lock;
7772 }
7773
7774 ha_statistic_increment(&SSV::ha_write_count);
7775
7776 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
7777 DBUG_RETURN(HA_ERR_CRASHED);
7778 }
7779
7780 sql_command = thd_sql_command(user_thd);
7781
7782 if ((sql_command == SQLCOM_ALTER_TABLE
7783 || sql_command == SQLCOM_OPTIMIZE
7784 || sql_command == SQLCOM_CREATE_INDEX
7785 || sql_command == SQLCOM_DROP_INDEX)
7786 && num_write_row >= 10000) {
7787 /* ALTER TABLE is COMMITted at every 10000 copied rows.
7788 The IX table lock for the original table has to be re-issued.
7789 As this method will be called on a temporary table where the
7790 contents of the original table is being copied to, it is
7791 a bit tricky to determine the source table. The cursor
7792 position in the source table need not be adjusted after the
7793 intermediate COMMIT, since writes by other transactions are
7794 being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
7795
7796 dict_table_t* src_table;
7797 enum lock_mode mode;
7798
7799 num_write_row = 0;
7800
7801 /* Commit the transaction. This will release the table
7802 locks, so they have to be acquired again. */
7803
7804 /* Altering an InnoDB table */
7805 /* Get the source table. */
7806 src_table = lock_get_src_table(
7807 prebuilt->trx, prebuilt->table, &mode);
7808 if (!src_table) {
7809 no_commit:
7810 /* Unknown situation: do not commit */
7811 /*
7812 ut_print_timestamp(stderr);
7813 fprintf(stderr,
7814 " InnoDB: ALTER TABLE is holding lock"
7815 " on %lu tables!\n",
7816 prebuilt->trx->mysql_n_tables_locked);
7817 */
7818 ;
7819 } else if (src_table == prebuilt->table) {
7820 /* Source table is not in InnoDB format:
7821 no need to re-acquire locks on it. */
7822
7823 /* Altering to InnoDB format */
7824 innobase_commit(ht, user_thd, 1);
7825 /* Note that this transaction is still active. */
7826 trx_register_for_2pc(prebuilt->trx);
7827 /* We will need an IX lock on the destination table. */
7828 prebuilt->sql_stat_start = TRUE;
7829 } else {
7830 /* Ensure that there are no other table locks than
7831 LOCK_IX and LOCK_AUTO_INC on the destination table. */
7832
7833 if (!lock_is_table_exclusive(prebuilt->table,
7834 prebuilt->trx)) {
7835 goto no_commit;
7836 }
7837
7838 /* Commit the transaction. This will release the table
7839 locks, so they have to be acquired again. */
7840 innobase_commit(ht, user_thd, 1);
7841 /* Note that this transaction is still active. */
7842 trx_register_for_2pc(prebuilt->trx);
7843 /* Re-acquire the table lock on the source table. */
7844 row_lock_table_for_mysql(prebuilt, src_table, mode);
7845 /* We will need an IX lock on the destination table. */
7846 prebuilt->sql_stat_start = TRUE;
7847 }
7848 }
7849
7850 num_write_row++;
7851
7852 /* This is the case where the table has an auto-increment column */
7853 if (table->next_number_field && record == table->record[0]) {
7854
7855 /* Reset the error code before calling
7856 innobase_get_auto_increment(). */
7857 prebuilt->autoinc_error = DB_SUCCESS;
7858
7859 if ((error_result = update_auto_increment())) {
7860 /* We don't want to mask autoinc overflow errors. */
7861
7862 /* Handle the case where the AUTOINC sub-system
7863 failed during initialization. */
7864 if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
7865 error_result = ER_AUTOINC_READ_FAILED;
7866 /* Set the error message to report too. */
7867 my_error(ER_AUTOINC_READ_FAILED, MYF(0));
7868 goto func_exit;
7869 } else if (prebuilt->autoinc_error != DB_SUCCESS) {
7870 error = prebuilt->autoinc_error;
7871 goto report_error;
7872 }
7873
7874 /* MySQL errors are passed straight back. */
7875 goto func_exit;
7876 }
7877
7878 auto_inc_used = TRUE;
7879 }
7880
7881 if (prebuilt->mysql_template == NULL
7882 || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
7883
7884 /* Build the template used in converting quickly between
7885 the two database formats */
7886
7887 build_template(true);
7888 }
7889
7890 innobase_srv_conc_enter_innodb(prebuilt->trx);
7891
7892 error = row_insert_for_mysql((byte*) record, prebuilt);
7893 DEBUG_SYNC(user_thd, "ib_after_row_insert");
7894
7895 /* Handle duplicate key errors */
7896 if (auto_inc_used) {
7897 ulonglong auto_inc;
7898 ulonglong col_max_value;
7899
7900 /* Note the number of rows processed for this statement, used
7901 by get_auto_increment() to determine the number of AUTO-INC
7902 values to reserve. This is only useful for a mult-value INSERT
7903 and is a statement level counter.*/
7904 if (trx->n_autoinc_rows > 0) {
7905 --trx->n_autoinc_rows;
7906 }
7907
7908 /* We need the upper limit of the col type to check for
7909 whether we update the table autoinc counter or not. */
7910 col_max_value = innobase_get_int_col_max_value(
7911 table->next_number_field);
7912
7913 /* Get the value that MySQL attempted to store in the table.*/
7914 auto_inc = table->next_number_field->val_int();
7915
7916 switch (error) {
7917 case DB_DUPLICATE_KEY:
7918
7919 /* A REPLACE command and LOAD DATA INFILE REPLACE
7920 handle a duplicate key error themselves, but we
7921 must update the autoinc counter if we are performing
7922 those statements. */
7923
7924 switch (sql_command) {
7925 case SQLCOM_LOAD:
7926 if (trx->duplicates) {
7927
7928 goto set_max_autoinc;
7929 }
7930 break;
7931
7932 case SQLCOM_REPLACE:
7933 case SQLCOM_INSERT_SELECT:
7934 case SQLCOM_REPLACE_SELECT:
7935 goto set_max_autoinc;
7936
7937 default:
7938 break;
7939 }
7940
7941 break;
7942
7943 case DB_SUCCESS:
7944 /* If the actual value inserted is greater than
7945 the upper limit of the interval, then we try and
7946 update the table upper limit. Note: last_value
7947 will be 0 if get_auto_increment() was not called.*/
7948
7949 if (auto_inc >= prebuilt->autoinc_last_value) {
7950 set_max_autoinc:
7951 /* This should filter out the negative
7952 values set explicitly by the user. */
7953 if (auto_inc <= col_max_value) {
7954 ut_a(prebuilt->autoinc_increment > 0);
7955
7956 ulonglong offset;
7957 ulonglong increment;
7958 dberr_t err;
7959
7960 offset = prebuilt->autoinc_offset;
7961 increment = prebuilt->autoinc_increment;
7962
7963 auto_inc = innobase_next_autoinc(
7964 auto_inc,
7965 1, increment, offset,
7966 col_max_value);
7967
7968 err = innobase_set_max_autoinc(
7969 auto_inc);
7970
7971 if (err != DB_SUCCESS) {
7972 error = err;
7973 }
7974 }
7975 }
7976 break;
7977 default:
7978 break;
7979 }
7980 }
7981
7982 innobase_srv_conc_exit_innodb(prebuilt->trx);
7983
7984 report_error:
7985 if (error == DB_TABLESPACE_DELETED) {
7986 ib_senderrf(
7987 trx->mysql_thd, IB_LOG_LEVEL_ERROR,
7988 ER_TABLESPACE_DISCARDED,
7989 table->s->table_name.str);
7990 }
7991
7992 error_result = convert_error_code_to_mysql(error,
7993 prebuilt->table->flags,
7994 user_thd);
7995
7996 if (error_result == HA_FTS_INVALID_DOCID) {
7997 my_error(HA_FTS_INVALID_DOCID, MYF(0));
7998 }
7999
8000 func_exit:
8001 innobase_active_small();
8002
8003 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
8004 DBUG_RETURN(HA_ERR_CRASHED);
8005 }
8006
8007 DBUG_RETURN(error_result);
8008 }
8009
8010 /**********************************************************************//**
8011 Checks which fields have changed in a row and stores information
8012 of them to an update vector.
8013 @return DB_SUCCESS or error code */
8014 static
8015 dberr_t
calc_row_difference(upd_t * uvect,uchar * old_row,uchar * new_row,TABLE * table,uchar * upd_buff,ulint buff_len,row_prebuilt_t * prebuilt,THD * thd)8016 calc_row_difference(
8017 /*================*/
8018 upd_t* uvect, /*!< in/out: update vector */
8019 uchar* old_row, /*!< in: old row in MySQL format */
8020 uchar* new_row, /*!< in: new row in MySQL format */
8021 TABLE* table, /*!< in: table in MySQL data
8022 dictionary */
8023 uchar* upd_buff, /*!< in: buffer to use */
8024 ulint buff_len, /*!< in: buffer length */
8025 row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
8026 THD* thd) /*!< in: user thread */
8027 {
8028 uchar* original_upd_buff = upd_buff;
8029 Field* field;
8030 enum_field_types field_mysql_type;
8031 uint n_fields;
8032 ulint o_len;
8033 ulint n_len;
8034 ulint col_pack_len;
8035 const byte* new_mysql_row_col;
8036 const byte* o_ptr;
8037 const byte* n_ptr;
8038 byte* buf;
8039 upd_field_t* ufield;
8040 ulint col_type;
8041 ulint n_changed = 0;
8042 dfield_t dfield;
8043 dict_index_t* clust_index;
8044 uint i;
8045 ibool changes_fts_column = FALSE;
8046 ibool changes_fts_doc_col = FALSE;
8047 trx_t* trx = thd_to_trx(thd);
8048 doc_id_t doc_id = FTS_NULL_DOC_ID;
8049
8050 ut_ad(!srv_read_only_mode);
8051
8052 n_fields = table->s->fields;
8053 clust_index = dict_table_get_first_index(prebuilt->table);
8054
8055 /* We use upd_buff to convert changed fields */
8056 buf = (byte*) upd_buff;
8057
8058 for (i = 0; i < n_fields; i++) {
8059 field = table->field[i];
8060
8061 o_ptr = (const byte*) old_row + get_field_offset(table, field);
8062 n_ptr = (const byte*) new_row + get_field_offset(table, field);
8063
8064 /* Use new_mysql_row_col and col_pack_len save the values */
8065
8066 new_mysql_row_col = n_ptr;
8067 col_pack_len = field->pack_length();
8068
8069 o_len = col_pack_len;
8070 n_len = col_pack_len;
8071
8072 /* We use o_ptr and n_ptr to dig up the actual data for
8073 comparison. */
8074
8075 field_mysql_type = field->type();
8076
8077 col_type = prebuilt->table->cols[i].mtype;
8078
8079 switch (col_type) {
8080
8081 case DATA_BLOB:
8082 /* Do not compress blob column while comparing*/
8083 o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len,
8084 false, 0, 0, prebuilt);
8085 n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len,
8086 false, 0, 0, prebuilt);
8087
8088 break;
8089
8090 case DATA_VARCHAR:
8091 case DATA_BINARY:
8092 case DATA_VARMYSQL:
8093 if (field_mysql_type == MYSQL_TYPE_VARCHAR) {
8094 /* This is a >= 5.0.3 type true VARCHAR where
8095 the real payload data length is stored in
8096 1 or 2 bytes */
8097
8098 o_ptr = row_mysql_read_true_varchar(
8099 &o_len, o_ptr,
8100 (ulint)
8101 (((Field_varstring*) field)->length_bytes));
8102
8103 n_ptr = row_mysql_read_true_varchar(
8104 &n_len, n_ptr,
8105 (ulint)
8106 (((Field_varstring*) field)->length_bytes));
8107 }
8108
8109 break;
8110 default:
8111 ;
8112 }
8113
8114 if (field_mysql_type == MYSQL_TYPE_LONGLONG
8115 && prebuilt->table->fts
8116 && innobase_strcasecmp(
8117 field->field_name, FTS_DOC_ID_COL_NAME) == 0) {
8118 doc_id = (doc_id_t) mach_read_from_n_little_endian(
8119 n_ptr, 8);
8120 if (doc_id == 0) {
8121 return(DB_FTS_INVALID_DOCID);
8122 }
8123 }
8124
8125
8126 if (field->real_maybe_null()) {
8127 if (field->is_null_in_record(old_row)) {
8128 o_len = UNIV_SQL_NULL;
8129 }
8130
8131 if (field->is_null_in_record(new_row)) {
8132 n_len = UNIV_SQL_NULL;
8133 }
8134 }
8135
8136 if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
8137 0 != memcmp(o_ptr, n_ptr, o_len))) {
8138 /* The field has changed */
8139
8140 ufield = uvect->fields + n_changed;
8141 UNIV_MEM_INVALID(ufield, sizeof *ufield);
8142
8143 /* Let us use a dummy dfield to make the conversion
8144 from the MySQL column format to the InnoDB format */
8145
8146 if (n_len != UNIV_SQL_NULL) {
8147 dict_col_copy_type(prebuilt->table->cols + i,
8148 dfield_get_type(&dfield));
8149
8150 buf = row_mysql_store_col_in_innobase_format(
8151 &dfield,
8152 (byte*) buf,
8153 TRUE,
8154 new_mysql_row_col,
8155 col_pack_len,
8156 dict_table_is_comp(prebuilt->table),
8157 field->column_format() ==
8158 COLUMN_FORMAT_TYPE_COMPRESSED,
8159 reinterpret_cast<const byte*>(
8160 field->zip_dict_data.str),
8161 field->zip_dict_data.length,
8162 prebuilt);
8163 dfield_copy(&ufield->new_val, &dfield);
8164 } else {
8165 dfield_set_null(&ufield->new_val);
8166 }
8167
8168 ufield->exp = NULL;
8169 ufield->orig_len = 0;
8170 ufield->field_no = dict_col_get_clust_pos(
8171 &prebuilt->table->cols[i], clust_index);
8172 n_changed++;
8173
8174 /* If an FTS indexed column was changed by this
8175 UPDATE then we need to inform the FTS sub-system.
8176
8177 NOTE: Currently we re-index all FTS indexed columns
8178 even if only a subset of the FTS indexed columns
8179 have been updated. That is the reason we are
8180 checking only once here. Later we will need to
8181 note which columns have been updated and do
8182 selective processing. */
8183 if (prebuilt->table->fts != NULL) {
8184 ulint offset;
8185 dict_table_t* innodb_table;
8186
8187 innodb_table = prebuilt->table;
8188
8189 if (!changes_fts_column) {
8190 offset = row_upd_changes_fts_column(
8191 innodb_table, ufield);
8192
8193 if (offset != ULINT_UNDEFINED) {
8194 changes_fts_column = TRUE;
8195 }
8196 }
8197
8198 if (!changes_fts_doc_col) {
8199 changes_fts_doc_col =
8200 row_upd_changes_doc_id(
8201 innodb_table, ufield);
8202 }
8203 }
8204 }
8205 }
8206
8207 /* If the update changes a column with an FTS index on it, we
8208 then add an update column node with a new document id to the
8209 other changes. We piggy back our changes on the normal UPDATE
8210 to reduce processing and IO overhead. */
8211 if (!prebuilt->table->fts) {
8212 trx->fts_next_doc_id = 0;
8213 } else if (changes_fts_column || changes_fts_doc_col) {
8214 dict_table_t* innodb_table = prebuilt->table;
8215
8216 ufield = uvect->fields + n_changed;
8217
8218 if (!DICT_TF2_FLAG_IS_SET(
8219 innodb_table, DICT_TF2_FTS_HAS_DOC_ID)) {
8220
8221 /* If Doc ID is managed by user, and if any
8222 FTS indexed column has been updated, its corresponding
8223 Doc ID must also be updated. Otherwise, return
8224 error */
8225 if (changes_fts_column && !changes_fts_doc_col) {
8226 ut_print_timestamp(stderr);
8227 fprintf(stderr, " InnoDB: A new Doc ID"
8228 " must be supplied while updating"
8229 " FTS indexed columns.\n");
8230 return(DB_FTS_INVALID_DOCID);
8231 }
8232
8233 /* Doc ID must monotonically increase */
8234 ut_ad(innodb_table->fts->cache);
8235 if (doc_id < prebuilt->table->fts->cache->next_doc_id) {
8236 fprintf(stderr,
8237 "InnoDB: FTS Doc ID must be larger than"
8238 " " IB_ID_FMT " for table",
8239 innodb_table->fts->cache->next_doc_id
8240 - 1);
8241 ut_print_name(stderr, trx,
8242 TRUE, innodb_table->name);
8243 putc('\n', stderr);
8244
8245 return(DB_FTS_INVALID_DOCID);
8246 } else if ((doc_id
8247 - prebuilt->table->fts->cache->next_doc_id)
8248 >= FTS_DOC_ID_MAX_STEP) {
8249 fprintf(stderr,
8250 "InnoDB: Doc ID " UINT64PF " is too"
8251 " big. Its difference with largest"
8252 " Doc ID used " UINT64PF " cannot"
8253 " exceed or equal to %d\n",
8254 doc_id,
8255 prebuilt->table->fts->cache->next_doc_id - 1,
8256 FTS_DOC_ID_MAX_STEP);
8257 }
8258
8259
8260 trx->fts_next_doc_id = doc_id;
8261 } else {
8262 /* If the Doc ID is a hidden column, it can't be
8263 changed by user */
8264 ut_ad(!changes_fts_doc_col);
8265
8266 /* Doc ID column is hidden, a new Doc ID will be
8267 generated by following fts_update_doc_id() call */
8268 trx->fts_next_doc_id = 0;
8269 }
8270
8271 fts_update_doc_id(
8272 innodb_table, ufield, &trx->fts_next_doc_id);
8273
8274 ++n_changed;
8275 } else {
8276 /* We have a Doc ID column, but none of FTS indexed
8277 columns are touched, nor the Doc ID column, so set
8278 fts_next_doc_id to UINT64_UNDEFINED, which means do not
8279 update the Doc ID column */
8280 trx->fts_next_doc_id = UINT64_UNDEFINED;
8281 }
8282
8283 uvect->n_fields = n_changed;
8284 uvect->info_bits = 0;
8285
8286 ut_a(buf <= (byte*) original_upd_buff + buff_len);
8287
8288 return(DB_SUCCESS);
8289 }
8290
8291 /**********************************************************************//**
8292 Updates a row given as a parameter to a new value. Note that we are given
8293 whole rows, not just the fields which are updated: this incurs some
8294 overhead for CPU when we check which fields are actually updated.
8295 TODO: currently InnoDB does not prevent the 'Halloween problem':
8296 in a searched update a single row can get updated several times
8297 if its index columns are updated!
8298 @return error number or 0 */
8299 UNIV_INTERN
8300 int
update_row(const uchar * old_row,uchar * new_row)8301 ha_innobase::update_row(
8302 /*====================*/
8303 const uchar* old_row, /*!< in: old row in MySQL format */
8304 uchar* new_row) /*!< in: new row in MySQL format */
8305 {
8306 upd_t* uvect;
8307 dberr_t error;
8308 trx_t* trx = thd_to_trx(user_thd);
8309
8310 DBUG_ENTER("ha_innobase::update_row");
8311
8312 ut_a(prebuilt->trx == trx);
8313
8314 if (high_level_read_only) {
8315 ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
8316 DBUG_RETURN(HA_ERR_TABLE_READONLY);
8317 } else if (!trx_is_started(trx)) {
8318 ++trx->will_lock;
8319 }
8320
8321 if (upd_buf == NULL) {
8322 ut_ad(upd_buf_size == 0);
8323
8324 /* Create a buffer for packing the fields of a record. Why
8325 table->reclength did not work here? Obviously, because char
8326 fields when packed actually became 1 byte longer, when we also
8327 stored the string length as the first byte. */
8328
8329 upd_buf_size = table->s->reclength + table->s->max_key_length
8330 + MAX_REF_PARTS * 3;
8331 upd_buf = (uchar*) my_malloc(upd_buf_size, MYF(MY_WME));
8332 if (upd_buf == NULL) {
8333 upd_buf_size = 0;
8334 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
8335 }
8336 }
8337
8338 ha_statistic_increment(&SSV::ha_update_count);
8339
8340 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
8341 DBUG_RETURN(HA_ERR_CRASHED);
8342 }
8343
8344 if (prebuilt->upd_node) {
8345 uvect = prebuilt->upd_node->update;
8346 } else {
8347 uvect = row_get_prebuilt_update_vector(prebuilt);
8348 }
8349
8350 /* Build an update vector from the modified fields in the rows
8351 (uses upd_buf of the handle) */
8352
8353 error = calc_row_difference(uvect, (uchar*) old_row, new_row, table,
8354 upd_buf, upd_buf_size, prebuilt, user_thd);
8355
8356 if (error != DB_SUCCESS) {
8357 goto func_exit;
8358 }
8359
8360 /* This is not a delete */
8361 prebuilt->upd_node->is_delete = FALSE;
8362
8363 ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
8364
8365 innobase_srv_conc_enter_innodb(trx);
8366
8367 error = row_update_for_mysql((byte*) old_row, prebuilt);
8368
8369 /* We need to do some special AUTOINC handling for the following case:
8370
8371 INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
8372
8373 We need to use the AUTOINC counter that was actually used by
8374 MySQL in the UPDATE statement, which can be different from the
8375 value used in the INSERT statement.*/
8376
8377 if (error == DB_SUCCESS
8378 && table->next_number_field
8379 && new_row == table->record[0]
8380 && thd_sql_command(user_thd) == SQLCOM_INSERT
8381 && trx->duplicates) {
8382
8383 ulonglong auto_inc;
8384 ulonglong col_max_value;
8385
8386 auto_inc = table->next_number_field->val_int();
8387
8388 /* We need the upper limit of the col type to check for
8389 whether we update the table autoinc counter or not. */
8390 col_max_value = innobase_get_int_col_max_value(
8391 table->next_number_field);
8392
8393 if (auto_inc <= col_max_value && auto_inc != 0) {
8394
8395 ulonglong offset;
8396 ulonglong increment;
8397
8398 offset = prebuilt->autoinc_offset;
8399 increment = prebuilt->autoinc_increment;
8400
8401 auto_inc = innobase_next_autoinc(
8402 auto_inc, 1, increment, offset, col_max_value);
8403
8404 error = innobase_set_max_autoinc(auto_inc);
8405 }
8406 }
8407
8408 innobase_srv_conc_exit_innodb(trx);
8409
8410 func_exit:
8411 int err = convert_error_code_to_mysql(error,
8412 prebuilt->table->flags, user_thd);
8413
8414 /* If success and no columns were updated. */
8415 if (err == 0 && uvect->n_fields == 0) {
8416
8417 /* This is the same as success, but instructs
8418 MySQL that the row is not really updated and it
8419 should not increase the count of updated rows.
8420 This is fix for http://bugs.mysql.com/29157 */
8421 err = HA_ERR_RECORD_IS_THE_SAME;
8422 } else if (err == HA_FTS_INVALID_DOCID) {
8423 my_error(HA_FTS_INVALID_DOCID, MYF(0));
8424 }
8425
8426 /* Tell InnoDB server that there might be work for
8427 utility threads: */
8428
8429 innobase_active_small();
8430
8431 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
8432 DBUG_RETURN(HA_ERR_CRASHED);
8433 }
8434
8435 DBUG_RETURN(err);
8436 }
8437
8438 /**********************************************************************//**
8439 Deletes a row given as the parameter.
8440 @return error number or 0 */
8441 UNIV_INTERN
8442 int
delete_row(const uchar * record)8443 ha_innobase::delete_row(
8444 /*====================*/
8445 const uchar* record) /*!< in: a row in MySQL format */
8446 {
8447 dberr_t error;
8448 trx_t* trx = thd_to_trx(user_thd);
8449
8450 DBUG_ENTER("ha_innobase::delete_row");
8451
8452 ut_a(prebuilt->trx == trx);
8453
8454 if (high_level_read_only) {
8455 ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
8456 DBUG_RETURN(HA_ERR_TABLE_READONLY);
8457 } else if (!trx_is_started(trx)) {
8458 ++trx->will_lock;
8459 }
8460
8461 ha_statistic_increment(&SSV::ha_delete_count);
8462
8463 if (UNIV_UNLIKELY(share && share->ib_table
8464 && share->ib_table->is_corrupt)) {
8465 DBUG_RETURN(HA_ERR_CRASHED);
8466 }
8467
8468 if (!prebuilt->upd_node) {
8469 row_get_prebuilt_update_vector(prebuilt);
8470 }
8471
8472 /* This is a delete */
8473
8474 prebuilt->upd_node->is_delete = TRUE;
8475
8476 innobase_srv_conc_enter_innodb(trx);
8477
8478 error = row_update_for_mysql((byte*) record, prebuilt);
8479
8480 innobase_srv_conc_exit_innodb(trx);
8481
8482 /* Tell the InnoDB server that there might be work for
8483 utility threads: */
8484
8485 innobase_active_small();
8486
8487 if (UNIV_UNLIKELY(share && share->ib_table
8488 && share->ib_table->is_corrupt)) {
8489 DBUG_RETURN(HA_ERR_CRASHED);
8490 }
8491
8492 DBUG_RETURN(convert_error_code_to_mysql(
8493 error, prebuilt->table->flags, user_thd));
8494 }
8495
8496 /**********************************************************************//**
8497 Removes a new lock set on a row, if it was not read optimistically. This can
8498 be called after a row has been read in the processing of an UPDATE or a DELETE
8499 query, if the option innodb_locks_unsafe_for_binlog is set. */
8500 UNIV_INTERN
8501 void
unlock_row(void)8502 ha_innobase::unlock_row(void)
8503 /*=========================*/
8504 {
8505 DBUG_ENTER("ha_innobase::unlock_row");
8506
8507 /* Consistent read does not take any locks, thus there is
8508 nothing to unlock. */
8509
8510 if (prebuilt->select_lock_type == LOCK_NONE) {
8511 DBUG_VOID_RETURN;
8512 }
8513
8514 /* Ideally, this assert must be in the beginning of the function.
8515 But there are some calls to this function from the SQL layer when the
8516 transaction is in state TRX_STATE_NOT_STARTED. The check on
8517 prebuilt->select_lock_type above gets around this issue. */
8518 ut_ad(trx_state_eq(prebuilt->trx, TRX_STATE_ACTIVE));
8519
8520 switch (prebuilt->row_read_type) {
8521 case ROW_READ_WITH_LOCKS:
8522 if (!srv_locks_unsafe_for_binlog
8523 && prebuilt->trx->isolation_level
8524 > TRX_ISO_READ_COMMITTED) {
8525 break;
8526 }
8527 /* fall through */
8528 case ROW_READ_TRY_SEMI_CONSISTENT:
8529 row_unlock_for_mysql(prebuilt, FALSE);
8530 break;
8531 case ROW_READ_DID_SEMI_CONSISTENT:
8532 prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
8533 break;
8534 }
8535
8536 DBUG_VOID_RETURN;
8537 }
8538
8539 /* See handler.h and row0mysql.h for docs on this function. */
8540 UNIV_INTERN
8541 bool
was_semi_consistent_read(void)8542 ha_innobase::was_semi_consistent_read(void)
8543 /*=======================================*/
8544 {
8545 return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
8546 }
8547
8548 /* See handler.h and row0mysql.h for docs on this function. */
8549 UNIV_INTERN
8550 void
try_semi_consistent_read(bool yes)8551 ha_innobase::try_semi_consistent_read(bool yes)
8552 /*===========================================*/
8553 {
8554 ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
8555
8556 /* Row read type is set to semi consistent read if this was
8557 requested by the MySQL and either innodb_locks_unsafe_for_binlog
8558 option is used or this session is using READ COMMITTED isolation
8559 level. */
8560
8561 if (yes
8562 && (srv_locks_unsafe_for_binlog
8563 || prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) {
8564 prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
8565 } else {
8566 prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
8567 }
8568 }
8569
8570 /******************************************************************//**
8571 Initializes a handle to use an index.
8572 @return 0 or error number */
8573 UNIV_INTERN
8574 int
index_init(uint keynr,bool sorted)8575 ha_innobase::index_init(
8576 /*====================*/
8577 uint keynr, /*!< in: key (index) number */
8578 bool sorted) /*!< in: 1 if result MUST be sorted according to index */
8579 {
8580 DBUG_ENTER("index_init");
8581
8582 DBUG_RETURN(change_active_index(keynr));
8583 }
8584
8585 /******************************************************************//**
8586 Currently does nothing.
8587 @return 0 */
8588 UNIV_INTERN
8589 int
index_end(void)8590 ha_innobase::index_end(void)
8591 /*========================*/
8592 {
8593 int error = 0;
8594 DBUG_ENTER("index_end");
8595 active_index = MAX_KEY;
8596 in_range_check_pushed_down = FALSE;
8597 ds_mrr.dsmrr_close();
8598 DBUG_RETURN(error);
8599 }
8600
8601 /*********************************************************************//**
8602 Converts a search mode flag understood by MySQL to a flag understood
8603 by InnoDB. */
8604 static inline
8605 ulint
convert_search_mode_to_innobase(enum ha_rkey_function find_flag)8606 convert_search_mode_to_innobase(
8607 /*============================*/
8608 enum ha_rkey_function find_flag)
8609 {
8610 switch (find_flag) {
8611 case HA_READ_KEY_EXACT:
8612 /* this does not require the index to be UNIQUE */
8613 return(PAGE_CUR_GE);
8614 case HA_READ_KEY_OR_NEXT:
8615 return(PAGE_CUR_GE);
8616 case HA_READ_KEY_OR_PREV:
8617 return(PAGE_CUR_LE);
8618 case HA_READ_AFTER_KEY:
8619 return(PAGE_CUR_G);
8620 case HA_READ_BEFORE_KEY:
8621 return(PAGE_CUR_L);
8622 case HA_READ_PREFIX:
8623 return(PAGE_CUR_GE);
8624 case HA_READ_PREFIX_LAST:
8625 return(PAGE_CUR_LE);
8626 case HA_READ_PREFIX_LAST_OR_PREV:
8627 return(PAGE_CUR_LE);
8628 /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
8629 pass a complete-field prefix of a key value as the search
8630 tuple. I.e., it is not allowed that the last field would
8631 just contain n first bytes of the full field value.
8632 MySQL uses a 'padding' trick to convert LIKE 'abc%'
8633 type queries so that it can use as a search tuple
8634 a complete-field-prefix of a key value. Thus, the InnoDB
8635 search mode PAGE_CUR_LE_OR_EXTENDS is never used.
8636 TODO: when/if MySQL starts to use also partial-field
8637 prefixes, we have to deal with stripping of spaces
8638 and comparison of non-latin1 char type fields in
8639 innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
8640 work correctly. */
8641 case HA_READ_MBR_CONTAIN:
8642 case HA_READ_MBR_INTERSECT:
8643 case HA_READ_MBR_WITHIN:
8644 case HA_READ_MBR_DISJOINT:
8645 case HA_READ_MBR_EQUAL:
8646 return(PAGE_CUR_UNSUPP);
8647 /* do not use "default:" in order to produce a gcc warning:
8648 enumeration value '...' not handled in switch
8649 (if -Wswitch or -Wall is used) */
8650 }
8651
8652 my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
8653
8654 return(PAGE_CUR_UNSUPP);
8655 }
8656
8657 /*
8658 BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
8659 ---------------------------------------------------
8660 The following does not cover all the details, but explains how we determine
8661 the start of a new SQL statement, and what is associated with it.
8662
8663 For each table in the database the MySQL interpreter may have several
8664 table handle instances in use, also in a single SQL query. For each table
8665 handle instance there is an InnoDB 'prebuilt' struct which contains most
8666 of the InnoDB data associated with this table handle instance.
8667
8668 A) if the user has not explicitly set any MySQL table level locks:
8669
8670 1) MySQL calls ::external_lock to set an 'intention' table level lock on
8671 the table of the handle instance. There we set
8672 prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
8673 true if we are taking this table handle instance to use in a new SQL
8674 statement issued by the user. We also increment trx->n_mysql_tables_in_use.
8675
8676 2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
8677 instructions to prebuilt->template of the table handle instance in
8678 ::index_read. The template is used to save CPU time in large joins.
8679
8680 3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
8681 allocate a new consistent read view for the trx if it does not yet have one,
8682 or in the case of a locking read, set an InnoDB 'intention' table level
8683 lock on the table.
8684
8685 4) We do the SELECT. MySQL may repeatedly call ::index_read for the
8686 same table handle instance, if it is a join.
8687
8688 5) When the SELECT ends, MySQL removes its intention table level locks
8689 in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
8690 (a) we execute a COMMIT there if the autocommit is on,
8691 (b) we also release possible 'SQL statement level resources' InnoDB may
8692 have for this SQL statement. The MySQL interpreter does NOT execute
8693 autocommit for pure read transactions, though it should. That is why the
8694 table handler in that case has to execute the COMMIT in ::external_lock.
8695
8696 B) If the user has explicitly set MySQL table level locks, then MySQL
8697 does NOT call ::external_lock at the start of the statement. To determine
8698 when we are at the start of a new SQL statement we at the start of
8699 ::index_read also compare the query id to the latest query id where the
8700 table handle instance was used. If it has changed, we know we are at the
8701 start of a new SQL statement. Since the query id can theoretically
8702 overwrap, we use this test only as a secondary way of determining the
8703 start of a new SQL statement. */
8704
8705
8706 /**********************************************************************//**
8707 Positions an index cursor to the index specified in the handle. Fetches the
8708 row if any.
8709 @return 0, HA_ERR_KEY_NOT_FOUND, or error number */
8710 UNIV_INTERN
8711 int
index_read(uchar * buf,const uchar * key_ptr,uint key_len,enum ha_rkey_function find_flag)8712 ha_innobase::index_read(
8713 /*====================*/
8714 uchar* buf, /*!< in/out: buffer for the returned
8715 row */
8716 const uchar* key_ptr, /*!< in: key value; if this is NULL
8717 we position the cursor at the
8718 start or end of index; this can
8719 also contain an InnoDB row id, in
8720 which case key_len is the InnoDB
8721 row id length; the key value can
8722 also be a prefix of a full key value,
8723 and the last column can be a prefix
8724 of a full column */
8725 uint key_len,/*!< in: key value length */
8726 enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
8727 {
8728 ulint mode;
8729 dict_index_t* index;
8730 ulint match_mode = 0;
8731 int error;
8732 dberr_t ret;
8733
8734 DBUG_ENTER("index_read");
8735 DEBUG_SYNC_C("ha_innobase_index_read_begin");
8736
8737 ut_a(prebuilt->trx == thd_to_trx(user_thd));
8738 ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT);
8739
8740 ha_statistic_increment(&SSV::ha_read_key_count);
8741
8742 if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
8743 && share->ib_table && share->ib_table->is_corrupt)) {
8744 DBUG_RETURN(HA_ERR_CRASHED);
8745 }
8746
8747 index = prebuilt->index;
8748
8749 if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) {
8750 prebuilt->index_usable = FALSE;
8751 DBUG_RETURN(HA_ERR_CRASHED);
8752 }
8753 if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
8754 DBUG_RETURN(dict_index_is_corrupted(index)
8755 ? HA_ERR_INDEX_CORRUPT
8756 : HA_ERR_TABLE_DEF_CHANGED);
8757 }
8758
8759 if (index->type & DICT_FTS) {
8760 DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
8761 }
8762
8763 /* Note that if the index for which the search template is built is not
8764 necessarily prebuilt->index, but can also be the clustered index */
8765
8766 if (prebuilt->sql_stat_start) {
8767 build_template(false);
8768 }
8769
8770 if (key_ptr) {
8771 /* Convert the search key value to InnoDB format into
8772 prebuilt->search_tuple */
8773
8774 row_sel_convert_mysql_key_to_innobase(
8775 prebuilt->search_tuple,
8776 prebuilt->srch_key_val1,
8777 prebuilt->srch_key_val_len,
8778 index,
8779 (byte*) key_ptr,
8780 (ulint) key_len,
8781 prebuilt->trx);
8782 DBUG_ASSERT(prebuilt->search_tuple->n_fields > 0);
8783 } else {
8784 /* We position the cursor to the last or the first entry
8785 in the index */
8786
8787 dtuple_set_n_fields(prebuilt->search_tuple, 0);
8788 }
8789
8790 mode = convert_search_mode_to_innobase(find_flag);
8791
8792 match_mode = 0;
8793
8794 if (find_flag == HA_READ_KEY_EXACT) {
8795
8796 match_mode = ROW_SEL_EXACT;
8797
8798 } else if (find_flag == HA_READ_PREFIX
8799 || find_flag == HA_READ_PREFIX_LAST) {
8800
8801 match_mode = ROW_SEL_EXACT_PREFIX;
8802 }
8803
8804 last_match_mode = (uint) match_mode;
8805
8806 if (mode != PAGE_CUR_UNSUPP) {
8807
8808 innobase_srv_conc_enter_innodb(prebuilt->trx);
8809
8810 ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
8811 match_mode, 0);
8812
8813 innobase_srv_conc_exit_innodb(prebuilt->trx);
8814 } else {
8815
8816 ret = DB_UNSUPPORTED;
8817 }
8818
8819 if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
8820 && share->ib_table && share->ib_table->is_corrupt)) {
8821 DBUG_RETURN(HA_ERR_CRASHED);
8822 }
8823
8824 switch (ret) {
8825 case DB_SUCCESS:
8826 error = 0;
8827 table->status = 0;
8828 srv_stats.n_rows_read.add((size_t) prebuilt->trx->id, 1);
8829 break;
8830 case DB_RECORD_NOT_FOUND:
8831 error = HA_ERR_KEY_NOT_FOUND;
8832 table->status = STATUS_NOT_FOUND;
8833 break;
8834 case DB_END_OF_INDEX:
8835 error = HA_ERR_KEY_NOT_FOUND;
8836 table->status = STATUS_NOT_FOUND;
8837 break;
8838 case DB_TABLESPACE_DELETED:
8839
8840 ib_senderrf(
8841 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
8842 ER_TABLESPACE_DISCARDED,
8843 table->s->table_name.str);
8844
8845 table->status = STATUS_NOT_FOUND;
8846 error = HA_ERR_NO_SUCH_TABLE;
8847 break;
8848 case DB_TABLESPACE_NOT_FOUND:
8849
8850 ib_senderrf(
8851 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
8852 ER_TABLESPACE_MISSING, MYF(0),
8853 table->s->table_name.str);
8854
8855 table->status = STATUS_NOT_FOUND;
8856 error = HA_ERR_NO_SUCH_TABLE;
8857 break;
8858 default:
8859 error = convert_error_code_to_mysql(
8860 ret, prebuilt->table->flags, user_thd);
8861
8862 table->status = STATUS_NOT_FOUND;
8863 break;
8864 }
8865
8866 DBUG_RETURN(error);
8867 }
8868
8869 /*******************************************************************//**
8870 The following functions works like index_read, but it find the last
8871 row with the current key value or prefix.
8872 @return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
8873 UNIV_INTERN
8874 int
index_read_last(uchar * buf,const uchar * key_ptr,uint key_len)8875 ha_innobase::index_read_last(
8876 /*=========================*/
8877 uchar* buf, /*!< out: fetched row */
8878 const uchar* key_ptr,/*!< in: key value, or a prefix of a full
8879 key value */
8880 uint key_len)/*!< in: length of the key val or prefix
8881 in bytes */
8882 {
8883 return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
8884 }
8885
8886 /********************************************************************//**
8887 Get the index for a handle. Does not change active index.
8888 @return NULL or index instance. */
8889 UNIV_INTERN
8890 dict_index_t*
innobase_get_index(uint keynr)8891 ha_innobase::innobase_get_index(
8892 /*============================*/
8893 uint keynr) /*!< in: use this index; MAX_KEY means always
8894 clustered index, even if it was internally
8895 generated by InnoDB */
8896 {
8897 KEY* key = 0;
8898 dict_index_t* index = 0;
8899
8900 DBUG_ENTER("innobase_get_index");
8901
8902 if (keynr != MAX_KEY && table->s->keys > 0) {
8903 key = table->key_info + keynr;
8904
8905 index = innobase_index_lookup(share, keynr);
8906
8907 if (index) {
8908 ut_a(ut_strcmp(index->name, key->name) == 0);
8909 } else {
8910 /* Can't find index with keynr in the translation
8911 table. Only print message if the index translation
8912 table exists */
8913 if (share->idx_trans_tbl.index_mapping) {
8914 sql_print_warning("InnoDB could not find "
8915 "index %s key no %u for "
8916 "table %s through its "
8917 "index translation table",
8918 key ? key->name : "NULL",
8919 keynr,
8920 prebuilt->table->name);
8921 }
8922
8923 index = dict_table_get_index_on_name(prebuilt->table,
8924 key->name);
8925 }
8926 } else {
8927 index = dict_table_get_first_index(prebuilt->table);
8928 }
8929
8930 if (!index) {
8931 sql_print_error(
8932 "Innodb could not find key n:o %u with name %s "
8933 "from dict cache for table %s",
8934 keynr, key ? key->name : "NULL",
8935 prebuilt->table->name);
8936 }
8937
8938 DBUG_RETURN(index);
8939 }
8940
8941 /********************************************************************//**
8942 Changes the active index of a handle.
8943 @return 0 or error code */
8944 UNIV_INTERN
8945 int
change_active_index(uint keynr)8946 ha_innobase::change_active_index(
8947 /*=============================*/
8948 uint keynr) /*!< in: use this index; MAX_KEY means always clustered
8949 index, even if it was internally generated by
8950 InnoDB */
8951 {
8952 DBUG_ENTER("change_active_index");
8953
8954 if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
8955 && share->ib_table && share->ib_table->is_corrupt)) {
8956 DBUG_RETURN(HA_ERR_CRASHED);
8957 }
8958
8959 ut_ad(user_thd == ha_thd());
8960 ut_a(prebuilt->trx == thd_to_trx(user_thd));
8961
8962 active_index = keynr;
8963
8964 prebuilt->index = innobase_get_index(keynr);
8965
8966 if (UNIV_UNLIKELY(!prebuilt->index)) {
8967 sql_print_warning("InnoDB: change_active_index(%u) failed",
8968 keynr);
8969 prebuilt->index_usable = FALSE;
8970 DBUG_RETURN(1);
8971 }
8972
8973 prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
8974 prebuilt->index);
8975
8976 if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
8977 if (dict_index_is_corrupted(prebuilt->index)) {
8978 char index_name[MAX_FULL_NAME_LEN + 1];
8979 char table_name[MAX_FULL_NAME_LEN + 1];
8980
8981 innobase_format_name(
8982 index_name, sizeof index_name,
8983 prebuilt->index->name, TRUE);
8984
8985 innobase_format_name(
8986 table_name, sizeof table_name,
8987 prebuilt->index->table->name, FALSE);
8988
8989 push_warning_printf(
8990 user_thd, Sql_condition::WARN_LEVEL_WARN,
8991 HA_ERR_INDEX_CORRUPT,
8992 "InnoDB: Index %s for table %s is"
8993 " marked as corrupted",
8994 index_name, table_name);
8995 DBUG_RETURN(HA_ERR_INDEX_CORRUPT);
8996 } else {
8997 push_warning_printf(
8998 user_thd, Sql_condition::WARN_LEVEL_WARN,
8999 HA_ERR_TABLE_DEF_CHANGED,
9000 "InnoDB: insufficient history for index %u",
9001 keynr);
9002 }
9003
9004 /* The caller seems to ignore this. Thus, we must check
9005 this again in row_search_for_mysql(). */
9006 DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED);
9007 }
9008
9009 ut_a(prebuilt->search_tuple != 0);
9010
9011 dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
9012
9013 dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
9014 prebuilt->index->n_fields);
9015
9016 /* MySQL changes the active index for a handle also during some
9017 queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
9018 and then calculates the sum. Previously we played safe and used
9019 the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
9020 copying. Starting from MySQL-4.1 we use a more efficient flag here. */
9021
9022 build_template(false);
9023
9024 DBUG_RETURN(0);
9025 }
9026
9027 /**********************************************************************//**
9028 Positions an index cursor to the index specified in keynr. Fetches the
9029 row if any.
9030 ??? This is only used to read whole keys ???
9031 @return error number or 0 */
9032 UNIV_INTERN
9033 int
index_read_idx(uchar * buf,uint keynr,const uchar * key,uint key_len,enum ha_rkey_function find_flag)9034 ha_innobase::index_read_idx(
9035 /*========================*/
9036 uchar* buf, /*!< in/out: buffer for the returned
9037 row */
9038 uint keynr, /*!< in: use this index */
9039 const uchar* key, /*!< in: key value; if this is NULL
9040 we position the cursor at the
9041 start or end of index */
9042 uint key_len, /*!< in: key value length */
9043 enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
9044 {
9045 if (change_active_index(keynr)) {
9046
9047 return(1);
9048 }
9049
9050 return(index_read(buf, key, key_len, find_flag));
9051 }
9052
9053 /***********************************************************************//**
9054 Reads the next or previous row from a cursor, which must have previously been
9055 positioned using index_read.
9056 @return 0, HA_ERR_END_OF_FILE, or error number */
9057 UNIV_INTERN
9058 int
general_fetch(uchar * buf,uint direction,uint match_mode)9059 ha_innobase::general_fetch(
9060 /*=======================*/
9061 uchar* buf, /*!< in/out: buffer for next row in MySQL
9062 format */
9063 uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
9064 uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
9065 ROW_SEL_EXACT_PREFIX */
9066 {
9067 dberr_t ret;
9068 int error;
9069
9070 DBUG_ENTER("general_fetch");
9071
9072 if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
9073 && share->ib_table && share->ib_table->is_corrupt)) {
9074 DBUG_RETURN(HA_ERR_CRASHED);
9075 }
9076
9077 ut_a(prebuilt->trx == thd_to_trx(user_thd));
9078
9079 innobase_srv_conc_enter_innodb(prebuilt->trx);
9080
9081 ret = row_search_for_mysql(
9082 (byte*) buf, 0, prebuilt, match_mode, direction);
9083
9084 innobase_srv_conc_exit_innodb(prebuilt->trx);
9085
9086 if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
9087 && share->ib_table && share->ib_table->is_corrupt)) {
9088 DBUG_RETURN(HA_ERR_CRASHED);
9089 }
9090
9091 switch (ret) {
9092 case DB_SUCCESS:
9093 error = 0;
9094 table->status = 0;
9095 srv_stats.n_rows_read.add((size_t) prebuilt->trx->id, 1);
9096 break;
9097 case DB_RECORD_NOT_FOUND:
9098 error = HA_ERR_END_OF_FILE;
9099 table->status = STATUS_NOT_FOUND;
9100 break;
9101 case DB_END_OF_INDEX:
9102 error = HA_ERR_END_OF_FILE;
9103 table->status = STATUS_NOT_FOUND;
9104 break;
9105 case DB_TABLESPACE_DELETED:
9106
9107 ib_senderrf(
9108 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
9109 ER_TABLESPACE_DISCARDED,
9110 table->s->table_name.str);
9111
9112 table->status = STATUS_NOT_FOUND;
9113 error = HA_ERR_NO_SUCH_TABLE;
9114 break;
9115 case DB_TABLESPACE_NOT_FOUND:
9116
9117 ib_senderrf(
9118 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
9119 ER_TABLESPACE_MISSING,
9120 table->s->table_name.str);
9121
9122 table->status = STATUS_NOT_FOUND;
9123 error = HA_ERR_NO_SUCH_TABLE;
9124 break;
9125 default:
9126 error = convert_error_code_to_mysql(
9127 ret, prebuilt->table->flags, user_thd);
9128
9129 table->status = STATUS_NOT_FOUND;
9130 break;
9131 }
9132
9133 DBUG_RETURN(error);
9134 }
9135
9136 /***********************************************************************//**
9137 Reads the next row from a cursor, which must have previously been
9138 positioned using index_read.
9139 @return 0, HA_ERR_END_OF_FILE, or error number */
9140 UNIV_INTERN
9141 int
index_next(uchar * buf)9142 ha_innobase::index_next(
9143 /*====================*/
9144 uchar* buf) /*!< in/out: buffer for next row in MySQL
9145 format */
9146 {
9147 ha_statistic_increment(&SSV::ha_read_next_count);
9148
9149 return(general_fetch(buf, ROW_SEL_NEXT, 0));
9150 }
9151
9152 /*******************************************************************//**
9153 Reads the next row matching to the key value given as the parameter.
9154 @return 0, HA_ERR_END_OF_FILE, or error number */
9155 UNIV_INTERN
9156 int
index_next_same(uchar * buf,const uchar * key,uint keylen)9157 ha_innobase::index_next_same(
9158 /*=========================*/
9159 uchar* buf, /*!< in/out: buffer for the row */
9160 const uchar* key, /*!< in: key value */
9161 uint keylen) /*!< in: key value length */
9162 {
9163 ha_statistic_increment(&SSV::ha_read_next_count);
9164
9165 return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
9166 }
9167
9168 /***********************************************************************//**
9169 Reads the previous row from a cursor, which must have previously been
9170 positioned using index_read.
9171 @return 0, HA_ERR_END_OF_FILE, or error number */
9172 UNIV_INTERN
9173 int
index_prev(uchar * buf)9174 ha_innobase::index_prev(
9175 /*====================*/
9176 uchar* buf) /*!< in/out: buffer for previous row in MySQL format */
9177 {
9178 ha_statistic_increment(&SSV::ha_read_prev_count);
9179
9180 return(general_fetch(buf, ROW_SEL_PREV, 0));
9181 }
9182
9183 /********************************************************************//**
9184 Positions a cursor on the first record in an index and reads the
9185 corresponding row to buf.
9186 @return 0, HA_ERR_END_OF_FILE, or error code */
9187 UNIV_INTERN
9188 int
index_first(uchar * buf)9189 ha_innobase::index_first(
9190 /*=====================*/
9191 uchar* buf) /*!< in/out: buffer for the row */
9192 {
9193 int error;
9194
9195 DBUG_ENTER("index_first");
9196 ha_statistic_increment(&SSV::ha_read_first_count);
9197
9198 error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
9199
9200 /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
9201
9202 if (error == HA_ERR_KEY_NOT_FOUND) {
9203 error = HA_ERR_END_OF_FILE;
9204 }
9205
9206 DBUG_RETURN(error);
9207 }
9208
9209 /********************************************************************//**
9210 Positions a cursor on the last record in an index and reads the
9211 corresponding row to buf.
9212 @return 0, HA_ERR_END_OF_FILE, or error code */
9213 UNIV_INTERN
9214 int
index_last(uchar * buf)9215 ha_innobase::index_last(
9216 /*====================*/
9217 uchar* buf) /*!< in/out: buffer for the row */
9218 {
9219 int error;
9220
9221 DBUG_ENTER("index_last");
9222 ha_statistic_increment(&SSV::ha_read_last_count);
9223
9224 error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
9225
9226 /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
9227
9228 if (error == HA_ERR_KEY_NOT_FOUND) {
9229 error = HA_ERR_END_OF_FILE;
9230 }
9231
9232 DBUG_RETURN(error);
9233 }
9234
9235 /****************************************************************//**
9236 Initialize a table scan.
9237 @return 0 or error number */
9238 UNIV_INTERN
9239 int
rnd_init(bool scan)9240 ha_innobase::rnd_init(
9241 /*==================*/
9242 bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
9243 {
9244 int err;
9245
9246 /* Store the active index value so that we can restore the original
9247 value after a scan */
9248
9249 if (prebuilt->clust_index_was_generated) {
9250 err = change_active_index(MAX_KEY);
9251 } else {
9252 err = change_active_index(primary_key);
9253 }
9254
9255 /* Don't use semi-consistent read in random row reads (by position).
9256 This means we must disable semi_consistent_read if scan is false */
9257
9258 if (!scan) {
9259 try_semi_consistent_read(0);
9260 }
9261
9262 start_of_scan = 1;
9263
9264 return(err);
9265 }
9266
9267 /*****************************************************************//**
9268 Ends a table scan.
9269 @return 0 or error number */
9270 UNIV_INTERN
9271 int
rnd_end(void)9272 ha_innobase::rnd_end(void)
9273 /*======================*/
9274 {
9275 return(index_end());
9276 }
9277
9278 /*****************************************************************//**
9279 Reads the next row in a table scan (also used to read the FIRST row
9280 in a table scan).
9281 @return 0, HA_ERR_END_OF_FILE, or error number */
9282 UNIV_INTERN
9283 int
rnd_next(uchar * buf)9284 ha_innobase::rnd_next(
9285 /*==================*/
9286 uchar* buf) /*!< in/out: returns the row in this buffer,
9287 in MySQL format */
9288 {
9289 int error;
9290
9291 DBUG_ENTER("rnd_next");
9292 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
9293
9294 if (start_of_scan) {
9295 error = index_first(buf);
9296
9297 if (error == HA_ERR_KEY_NOT_FOUND) {
9298 error = HA_ERR_END_OF_FILE;
9299 }
9300
9301 start_of_scan = 0;
9302 } else {
9303 error = general_fetch(buf, ROW_SEL_NEXT, 0);
9304 }
9305
9306 DBUG_RETURN(error);
9307 }
9308
9309 /**********************************************************************//**
9310 Fetches a row from the table based on a row reference.
9311 @return 0, HA_ERR_KEY_NOT_FOUND, or error code */
9312 UNIV_INTERN
9313 int
rnd_pos(uchar * buf,uchar * pos)9314 ha_innobase::rnd_pos(
9315 /*=================*/
9316 uchar* buf, /*!< in/out: buffer for the row */
9317 uchar* pos) /*!< in: primary key value of the row in the
9318 MySQL format, or the row id if the clustered
9319 index was internally generated by InnoDB; the
9320 length of data in pos has to be ref_length */
9321 {
9322 int error;
9323 DBUG_ENTER("rnd_pos");
9324 DBUG_DUMP("key", pos, ref_length);
9325
9326 ha_statistic_increment(&SSV::ha_read_rnd_count);
9327
9328 ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
9329
9330 /* Note that we assume the length of the row reference is fixed
9331 for the table, and it is == ref_length */
9332
9333 error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
9334
9335 if (error) {
9336 DBUG_PRINT("error", ("Got error: %d", error));
9337 }
9338
9339 DBUG_RETURN(error);
9340 }
9341
9342 /**********************************************************************//**
9343 Initialize FT index scan
9344 @return 0 or error number */
9345 UNIV_INTERN
9346 int
ft_init()9347 ha_innobase::ft_init()
9348 /*==================*/
9349 {
9350 DBUG_ENTER("ft_init");
9351
9352 trx_t* trx = check_trx_exists(ha_thd());
9353
9354 /* FTS queries are not treated as autocommit non-locking selects.
9355 This is because the FTS implementation can acquire locks behind
9356 the scenes. This has not been verified but it is safer to treat
9357 them as regular read only transactions for now. */
9358
9359 if (!trx_is_started(trx)) {
9360 ++trx->will_lock;
9361 }
9362
9363 DBUG_RETURN(rnd_init(false));
9364 }
9365
9366 /**********************************************************************//**
9367 Initialize FT index scan
9368 @return FT_INFO structure if successful or NULL */
9369 UNIV_INTERN
9370 FT_INFO*
ft_init_ext(uint flags,uint keynr,String * key)9371 ha_innobase::ft_init_ext(
9372 /*=====================*/
9373 uint flags, /* in: */
9374 uint keynr, /* in: */
9375 String* key) /* in: */
9376 {
9377 trx_t* trx;
9378 dict_table_t* ft_table;
9379 dberr_t error;
9380 byte* query = (byte*) key->ptr();
9381 ulint query_len = key->length();
9382 const CHARSET_INFO* char_set = key->charset();
9383 NEW_FT_INFO* fts_hdl = NULL;
9384 dict_index_t* index;
9385 fts_result_t* result;
9386 char buf_tmp[8192];
9387 ulint buf_tmp_used;
9388 uint num_errors;
9389
9390 if (fts_enable_diag_print) {
9391 fprintf(stderr, "keynr=%u, '%.*s'\n",
9392 keynr, (int) key->length(), (byte*) key->ptr());
9393
9394 if (flags & FT_BOOL) {
9395 fprintf(stderr, "BOOL search\n");
9396 } else {
9397 fprintf(stderr, "NL search\n");
9398 }
9399 }
9400
9401 /* FIXME: utf32 and utf16 are not compatible with some
9402 string function used. So to convert them to uft8 before
9403 proceed. */
9404 if (strcmp(char_set->csname, "utf32") == 0
9405 || strcmp(char_set->csname, "utf16") == 0) {
9406 buf_tmp_used = innobase_convert_string(
9407 buf_tmp, sizeof(buf_tmp) - 1,
9408 &my_charset_utf8_general_ci,
9409 query, query_len, (CHARSET_INFO*) char_set,
9410 &num_errors);
9411
9412 query = (byte*) buf_tmp;
9413 query_len = buf_tmp_used;
9414 query[query_len] = 0;
9415 }
9416
9417 trx = prebuilt->trx;
9418
9419 /* FTS queries are not treated as autocommit non-locking selects.
9420 This is because the FTS implementation can acquire locks behind
9421 the scenes. This has not been verified but it is safer to treat
9422 them as regular read only transactions for now. */
9423
9424 if (!trx_is_started(trx)) {
9425 ++trx->will_lock;
9426 }
9427
9428 ft_table = prebuilt->table;
9429
9430 /* Table does not have an FTS index */
9431 if (!ft_table->fts || ib_vector_is_empty(ft_table->fts->indexes)) {
9432 my_error(ER_TABLE_HAS_NO_FT, MYF(0));
9433 return(NULL);
9434 }
9435
9436 /* If tablespace is discarded, we should return here */
9437 if (dict_table_is_discarded(ft_table)) {
9438 my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->db.str,
9439 table->s->table_name.str);
9440 return(NULL);
9441 }
9442
9443 if (keynr == NO_SUCH_KEY) {
9444 /* FIXME: Investigate the NO_SUCH_KEY usage */
9445 index = (dict_index_t*) ib_vector_getp(ft_table->fts->indexes, 0);
9446 } else {
9447 index = innobase_get_index(keynr);
9448 }
9449
9450 if (!index || index->type != DICT_FTS) {
9451 my_error(ER_TABLE_HAS_NO_FT, MYF(0));
9452 return(NULL);
9453 }
9454
9455 if (!(ft_table->fts->fts_status & ADDED_TABLE_SYNCED)) {
9456 fts_init_index(ft_table, FALSE);
9457
9458 ft_table->fts->fts_status |= ADDED_TABLE_SYNCED;
9459 }
9460
9461 error = fts_query(trx, index, flags, query, query_len, &result);
9462
9463 if (error != DB_SUCCESS) {
9464 my_error(convert_error_code_to_mysql(error, 0, NULL),
9465 MYF(0));
9466 return(NULL);
9467 }
9468
9469 /* Allocate FTS handler, and instantiate it before return */
9470 fts_hdl = static_cast<NEW_FT_INFO*>(my_malloc(sizeof(NEW_FT_INFO),
9471 MYF(0)));
9472
9473 fts_hdl->please = const_cast<_ft_vft*>(&ft_vft_result);
9474 fts_hdl->could_you = const_cast<_ft_vft_ext*>(&ft_vft_ext_result);
9475 fts_hdl->ft_prebuilt = prebuilt;
9476 fts_hdl->ft_result = result;
9477
9478 /* FIXME: Re-evluate the condition when Bug 14469540
9479 is resolved */
9480 prebuilt->in_fts_query = true;
9481
9482 return((FT_INFO*) fts_hdl);
9483 }
9484
9485 /*****************************************************************//**
9486 Copy a cached MySQL row.
9487 If requested, also avoids overwriting non-read columns.
9488 @param[out] buf Row in MySQL format.
9489 @param[in] cached_row Which row to copy.
9490 @param[in] rec_len Record length. */
9491 void
copy_cached_row(uchar * buf,const uchar * cached_row,uint rec_len)9492 ha_innobase::copy_cached_row(
9493 uchar* buf,
9494 const uchar* cached_row,
9495 uint rec_len)
9496 {
9497 if (prebuilt->keep_other_fields_on_keyread) {
9498 row_sel_copy_cached_fields_for_mysql(buf, cached_row,
9499 prebuilt);
9500 } else {
9501 memcpy(buf, cached_row, rec_len);
9502 }
9503 }
9504
9505
9506 /*****************************************************************//**
9507 Set up search tuple for a query through FTS_DOC_ID_INDEX on
9508 supplied Doc ID. This is used by MySQL to retrieve the documents
9509 once the search result (Doc IDs) is available */
9510 static
9511 void
innobase_fts_create_doc_id_key(dtuple_t * tuple,const dict_index_t * index,doc_id_t * doc_id)9512 innobase_fts_create_doc_id_key(
9513 /*===========================*/
9514 dtuple_t* tuple, /* in/out: prebuilt->search_tuple */
9515 const dict_index_t*
9516 index, /* in: index (FTS_DOC_ID_INDEX) */
9517 doc_id_t* doc_id) /* in/out: doc id to search, value
9518 could be changed to storage format
9519 used for search. */
9520 {
9521 doc_id_t temp_doc_id;
9522 dfield_t* dfield = dtuple_get_nth_field(tuple, 0);
9523
9524 ut_a(dict_index_get_n_unique(index) == 1);
9525
9526 dtuple_set_n_fields(tuple, index->n_fields);
9527 dict_index_copy_types(tuple, index, index->n_fields);
9528
9529 #ifdef UNIV_DEBUG
9530 /* The unique Doc ID field should be an eight-bytes integer */
9531 dict_field_t* field = dict_index_get_nth_field(index, 0);
9532 ut_a(field->col->mtype == DATA_INT);
9533 ut_ad(sizeof(*doc_id) == field->fixed_len);
9534 ut_ad(innobase_strcasecmp(index->name, FTS_DOC_ID_INDEX_NAME) == 0);
9535 #endif /* UNIV_DEBUG */
9536
9537 /* Convert to storage byte order */
9538 mach_write_to_8(reinterpret_cast<byte*>(&temp_doc_id), *doc_id);
9539 *doc_id = temp_doc_id;
9540 dfield_set_data(dfield, doc_id, sizeof(*doc_id));
9541
9542 dtuple_set_n_fields_cmp(tuple, 1);
9543
9544 for (ulint i = 1; i < index->n_fields; i++) {
9545 dfield = dtuple_get_nth_field(tuple, i);
9546 dfield_set_null(dfield);
9547 }
9548 }
9549
9550 /**********************************************************************//**
9551 Fetch next result from the FT result set
9552 @return error code */
9553 UNIV_INTERN
9554 int
ft_read(uchar * buf)9555 ha_innobase::ft_read(
9556 /*=================*/
9557 uchar* buf) /*!< in/out: buf contain result row */
9558 {
9559 fts_result_t* result;
9560 int error;
9561 row_prebuilt_t* ft_prebuilt;
9562
9563 ft_prebuilt = ((NEW_FT_INFO*) ft_handler)->ft_prebuilt;
9564
9565 ut_a(ft_prebuilt == prebuilt);
9566
9567 result = ((NEW_FT_INFO*) ft_handler)->ft_result;
9568
9569 if (result->current == NULL) {
9570 /* This is the case where the FTS query did not
9571 contain and matching documents. */
9572 if (result->rankings_by_id != NULL) {
9573 /* Now that we have the complete result, we
9574 need to sort the document ids on their rank
9575 calculation. */
9576
9577 fts_query_sort_result_on_rank(result);
9578
9579 result->current = const_cast<ib_rbt_node_t*>(
9580 rbt_first(result->rankings_by_rank));
9581 } else {
9582 ut_a(result->current == NULL);
9583 }
9584 } else {
9585 result->current = const_cast<ib_rbt_node_t*>(
9586 rbt_next(result->rankings_by_rank, result->current));
9587 }
9588
9589 next_record:
9590
9591 if (result->current != NULL) {
9592 dict_index_t* index;
9593 dtuple_t* tuple = prebuilt->search_tuple;
9594 doc_id_t search_doc_id;
9595
9596 /* If we only need information from result we can return
9597 without fetching the table row */
9598 if (ft_prebuilt->read_just_key) {
9599 table->status= 0;
9600 return(0);
9601 }
9602
9603 index = dict_table_get_index_on_name(
9604 prebuilt->table, FTS_DOC_ID_INDEX_NAME);
9605
9606 /* Must find the index */
9607 ut_a(index);
9608
9609 /* Switch to the FTS doc id index */
9610 prebuilt->index = index;
9611
9612 fts_ranking_t* ranking = rbt_value(
9613 fts_ranking_t, result->current);
9614
9615 search_doc_id = ranking->doc_id;
9616
9617 /* We pass a pointer of search_doc_id because it will be
9618 converted to storage byte order used in the search
9619 tuple. */
9620 innobase_fts_create_doc_id_key(tuple, index, &search_doc_id);
9621
9622 innobase_srv_conc_enter_innodb(prebuilt->trx);
9623
9624 dberr_t ret = row_search_for_mysql(
9625 (byte*) buf, PAGE_CUR_GE, prebuilt, ROW_SEL_EXACT, 0);
9626
9627 innobase_srv_conc_exit_innodb(prebuilt->trx);
9628
9629 switch (ret) {
9630 case DB_SUCCESS:
9631 error = 0;
9632 table->status = 0;
9633 break;
9634 case DB_RECORD_NOT_FOUND:
9635 result->current = const_cast<ib_rbt_node_t*>(
9636 rbt_next(result->rankings_by_rank,
9637 result->current));
9638
9639 if (!result->current) {
9640 /* exhaust the result set, should return
9641 HA_ERR_END_OF_FILE just like
9642 ha_innobase::general_fetch() and/or
9643 ha_innobase::index_first() etc. */
9644 error = HA_ERR_END_OF_FILE;
9645 table->status = STATUS_NOT_FOUND;
9646 } else {
9647 goto next_record;
9648 }
9649 break;
9650 case DB_END_OF_INDEX:
9651 error = HA_ERR_END_OF_FILE;
9652 table->status = STATUS_NOT_FOUND;
9653 break;
9654 case DB_TABLESPACE_DELETED:
9655
9656 ib_senderrf(
9657 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
9658 ER_TABLESPACE_DISCARDED,
9659 table->s->table_name.str);
9660
9661 table->status = STATUS_NOT_FOUND;
9662 error = HA_ERR_NO_SUCH_TABLE;
9663 break;
9664 case DB_TABLESPACE_NOT_FOUND:
9665
9666 ib_senderrf(
9667 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
9668 ER_TABLESPACE_MISSING,
9669 table->s->table_name.str);
9670
9671 table->status = STATUS_NOT_FOUND;
9672 error = HA_ERR_NO_SUCH_TABLE;
9673 break;
9674 default:
9675 error = convert_error_code_to_mysql(
9676 ret, 0, user_thd);
9677
9678 table->status = STATUS_NOT_FOUND;
9679 break;
9680 }
9681
9682 return(error);
9683 }
9684
9685 return(HA_ERR_END_OF_FILE);
9686 }
9687
9688 /*************************************************************************
9689 */
9690
9691 void
ft_end()9692 ha_innobase::ft_end()
9693 {
9694 fprintf(stderr, "ft_end()\n");
9695
9696 rnd_end();
9697 }
9698
9699 /*********************************************************************//**
9700 Stores a reference to the current row to 'ref' field of the handle. Note
9701 that in the case where we have generated the clustered index for the
9702 table, the function parameter is illogical: we MUST ASSUME that 'record'
9703 is the current 'position' of the handle, because if row ref is actually
9704 the row id internally generated in InnoDB, then 'record' does not contain
9705 it. We just guess that the row id must be for the record where the handle
9706 was positioned the last time. */
9707 UNIV_INTERN
9708 void
position(const uchar * record)9709 ha_innobase::position(
9710 /*==================*/
9711 const uchar* record) /*!< in: row in MySQL format */
9712 {
9713 uint len;
9714
9715 ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
9716
9717 if (prebuilt->clust_index_was_generated) {
9718 /* No primary key was defined for the table and we
9719 generated the clustered index from row id: the
9720 row reference will be the row id, not any key value
9721 that MySQL knows of */
9722
9723 len = DATA_ROW_ID_LEN;
9724
9725 memcpy(ref, prebuilt->row_id, len);
9726 } else {
9727 len = store_key_val_for_row(primary_key, (char*) ref,
9728 ref_length, record);
9729 }
9730
9731 /* We assume that the 'ref' value len is always fixed for the same
9732 table. */
9733
9734 if (len != ref_length) {
9735 sql_print_error("Stored ref len is %lu, but table ref len is "
9736 "%lu", (ulong) len, (ulong) ref_length);
9737 }
9738 }
9739
9740 /*****************************************************************//**
9741 Check whether there exist a column named as "FTS_DOC_ID", which is
9742 reserved for InnoDB FTS Doc ID
9743 @return true if there exist a "FTS_DOC_ID" column */
9744 static
9745 bool
create_table_check_doc_id_col(trx_t * trx,const TABLE * form,ulint * doc_id_col)9746 create_table_check_doc_id_col(
9747 /*==========================*/
9748 trx_t* trx, /*!< in: InnoDB transaction handle */
9749 const TABLE* form, /*!< in: information on table
9750 columns and indexes */
9751 ulint* doc_id_col) /*!< out: Doc ID column number if
9752 there exist a FTS_DOC_ID column,
9753 ULINT_UNDEFINED if column is of the
9754 wrong type/name/size */
9755 {
9756 for (ulint i = 0; i < form->s->fields; i++) {
9757 const Field* field;
9758 ulint col_type;
9759 ulint col_len;
9760 ulint unsigned_type;
9761
9762 field = form->field[i];
9763
9764 col_type = get_innobase_type_from_mysql_type(&unsigned_type,
9765 field);
9766
9767 col_len = field->pack_length();
9768
9769 if (innobase_strcasecmp(field->field_name,
9770 FTS_DOC_ID_COL_NAME) == 0) {
9771
9772 /* Note the name is case sensitive due to
9773 our internal query parser */
9774 if (col_type == DATA_INT
9775 && !field->real_maybe_null()
9776 && col_len == sizeof(doc_id_t)
9777 && (strcmp(field->field_name,
9778 FTS_DOC_ID_COL_NAME) == 0)) {
9779 *doc_id_col = i;
9780 } else {
9781 push_warning_printf(
9782 trx->mysql_thd,
9783 Sql_condition::WARN_LEVEL_WARN,
9784 ER_ILLEGAL_HA_CREATE_OPTION,
9785 "InnoDB: FTS_DOC_ID column must be "
9786 "of BIGINT NOT NULL type, and named "
9787 "in all capitalized characters");
9788 my_error(ER_WRONG_COLUMN_NAME, MYF(0),
9789 field->field_name);
9790 *doc_id_col = ULINT_UNDEFINED;
9791 }
9792
9793 return(true);
9794 }
9795 }
9796
9797 return(false);
9798 }
9799
9800 /*****************************************************************//**
9801 Creates a table definition to an InnoDB database. */
9802 static MY_ATTRIBUTE((nonnull, warn_unused_result))
9803 int
create_table_def(trx_t * trx,const TABLE * form,const char * table_name,const char * temp_path,const char * remote_path,ulint flags,ulint flags2)9804 create_table_def(
9805 /*=============*/
9806 trx_t* trx, /*!< in: InnoDB transaction handle */
9807 const TABLE* form, /*!< in: information on table
9808 columns and indexes */
9809 const char* table_name, /*!< in: table name */
9810 const char* temp_path, /*!< in: if this is a table explicitly
9811 created by the user with the
9812 TEMPORARY keyword, then this
9813 parameter is the dir path where the
9814 table should be placed if we create
9815 an .ibd file for it (no .ibd extension
9816 in the path, though). Otherwise this
9817 is a zero length-string */
9818 const char* remote_path, /*!< in: Remote path or zero length-string */
9819 ulint flags, /*!< in: table flags */
9820 ulint flags2) /*!< in: table flags2 */
9821 {
9822 THD* thd = trx->mysql_thd;
9823 dict_table_t* table;
9824 ulint n_cols;
9825 dberr_t err;
9826 ulint col_type;
9827 ulint col_len;
9828 ulint nulls_allowed;
9829 ulint unsigned_type;
9830 ulint binary_type;
9831 ulint long_true_varchar;
9832 ulint compressed;
9833 ulint charset_no;
9834 ulint i;
9835 ulint doc_id_col = 0;
9836 ibool has_doc_id_col = FALSE;
9837 mem_heap_t* heap;
9838
9839 DBUG_ENTER("create_table_def");
9840 DBUG_PRINT("enter", ("table_name: %s", table_name));
9841
9842 DBUG_ASSERT(thd != NULL);
9843
9844 /* MySQL does the name length check. But we do additional check
9845 on the name length here */
9846 const size_t table_name_len = strlen(table_name);
9847 if (table_name_len > MAX_FULL_NAME_LEN) {
9848 push_warning_printf(
9849 thd, Sql_condition::WARN_LEVEL_WARN,
9850 ER_TABLE_NAME,
9851 "InnoDB: Table Name or Database Name is too long");
9852
9853 DBUG_RETURN(ER_TABLE_NAME);
9854 }
9855
9856 if (table_name[table_name_len - 1] == '/') {
9857 push_warning_printf(
9858 thd, Sql_condition::WARN_LEVEL_WARN,
9859 ER_TABLE_NAME,
9860 "InnoDB: Table name is empty");
9861
9862 DBUG_RETURN(ER_WRONG_TABLE_NAME);
9863 }
9864
9865 n_cols = form->s->fields;
9866
9867 /* Check whether there already exists a FTS_DOC_ID column */
9868 if (create_table_check_doc_id_col(trx, form, &doc_id_col)){
9869
9870 /* Raise error if the Doc ID column is of wrong type or name */
9871 if (doc_id_col == ULINT_UNDEFINED) {
9872 trx_commit_for_mysql(trx);
9873
9874 err = DB_ERROR;
9875 goto error_ret;
9876 } else {
9877 has_doc_id_col = TRUE;
9878 }
9879 }
9880
9881 /* We pass 0 as the space id, and determine at a lower level the space
9882 id where to store the table */
9883
9884 if (flags2 & DICT_TF2_FTS) {
9885 /* Adjust for the FTS hidden field */
9886 if (!has_doc_id_col) {
9887 table = dict_mem_table_create(table_name, 0, n_cols + 1,
9888 flags, flags2);
9889
9890 /* Set the hidden doc_id column. */
9891 table->fts->doc_col = n_cols;
9892 } else {
9893 table = dict_mem_table_create(table_name, 0, n_cols,
9894 flags, flags2);
9895 table->fts->doc_col = doc_id_col;
9896 }
9897 } else {
9898 table = dict_mem_table_create(table_name, 0, n_cols,
9899 flags, flags2);
9900 }
9901
9902 if (flags2 & DICT_TF2_TEMPORARY) {
9903 ut_a(strlen(temp_path));
9904 table->dir_path_of_temp_table =
9905 mem_heap_strdup(table->heap, temp_path);
9906 }
9907
9908 if (DICT_TF_HAS_DATA_DIR(flags)) {
9909 ut_a(strlen(remote_path));
9910 table->data_dir_path = mem_heap_strdup(table->heap, remote_path);
9911 } else {
9912 table->data_dir_path = NULL;
9913 }
9914 heap = mem_heap_create(1000);
9915
9916 for (i = 0; i < n_cols; i++) {
9917 Field* field = form->field[i];
9918
9919 col_type = get_innobase_type_from_mysql_type(&unsigned_type,
9920 field);
9921
9922 if (!col_type) {
9923 push_warning_printf(
9924 thd, Sql_condition::WARN_LEVEL_WARN,
9925 ER_CANT_CREATE_TABLE,
9926 "Error creating table '%s' with "
9927 "column '%s'. Please check its "
9928 "column type and try to re-create "
9929 "the table with an appropriate "
9930 "column type.",
9931 table->name, field->field_name);
9932 goto err_col;
9933 }
9934
9935 nulls_allowed = field->real_maybe_null() ? 0 : DATA_NOT_NULL;
9936 binary_type = field->binary() ? DATA_BINARY_TYPE : 0;
9937
9938 charset_no = 0;
9939
9940 if (dtype_is_string_type(col_type)) {
9941
9942 charset_no = (ulint) field->charset()->number;
9943
9944 if (UNIV_UNLIKELY(charset_no > MAX_CHAR_COLL_NUM)) {
9945 /* in data0type.h we assume that the
9946 number fits in one byte in prtype */
9947 push_warning_printf(
9948 thd, Sql_condition::WARN_LEVEL_WARN,
9949 ER_CANT_CREATE_TABLE,
9950 "In InnoDB, charset-collation codes"
9951 " must be below 256."
9952 " Unsupported code %lu.",
9953 (ulong) charset_no);
9954 mem_heap_free(heap);
9955 DBUG_RETURN(ER_CANT_CREATE_TABLE);
9956 }
9957 }
9958
9959 /* we assume in dtype_form_prtype() that this fits in
9960 two bytes */
9961 ut_a(static_cast<uint>(field->type()) <= MAX_CHAR_COLL_NUM);
9962 col_len = field->pack_length();
9963
9964 /* The MySQL pack length contains 1 or 2 bytes length field
9965 for a true VARCHAR. Let us subtract that, so that the InnoDB
9966 column length in the InnoDB data dictionary is the real
9967 maximum byte length of the actual data. */
9968
9969 long_true_varchar = 0;
9970
9971 if (field->type() == MYSQL_TYPE_VARCHAR) {
9972 col_len -= ((Field_varstring*) field)->length_bytes;
9973
9974 if (((Field_varstring*) field)->length_bytes == 2) {
9975 long_true_varchar = DATA_LONG_TRUE_VARCHAR;
9976 }
9977 }
9978
9979 /* Check if the the field has COMPRESSED attribute */
9980 compressed = 0;
9981 if (field->column_format() ==
9982 COLUMN_FORMAT_TYPE_COMPRESSED) {
9983 compressed = DATA_COMPRESSED;
9984 }
9985
9986 /* First check whether the column to be added has a
9987 system reserved name. */
9988 if (dict_col_name_is_reserved(field->field_name)){
9989 my_error(ER_WRONG_COLUMN_NAME, MYF(0),
9990 field->field_name);
9991 err_col:
9992 dict_mem_table_free(table);
9993 mem_heap_free(heap);
9994 trx_commit_for_mysql(trx);
9995
9996 err = DB_ERROR;
9997 goto error_ret;
9998 }
9999
10000 dict_mem_table_add_col(table, heap,
10001 field->field_name,
10002 col_type,
10003 dtype_form_prtype(
10004 (ulint) field->type()
10005 | nulls_allowed | unsigned_type
10006 | binary_type | long_true_varchar
10007 | compressed,
10008 charset_no),
10009 col_len);
10010 }
10011
10012 /* Add the FTS doc_id hidden column. */
10013 if (flags2 & DICT_TF2_FTS && !has_doc_id_col) {
10014 fts_add_doc_id_column(table, heap);
10015 }
10016
10017 err = row_create_table_for_mysql(table, trx, false);
10018
10019 mem_heap_free(heap);
10020
10021 DBUG_EXECUTE_IF("ib_create_err_tablespace_exist",
10022 err = DB_TABLESPACE_EXISTS;);
10023
10024 if (err == DB_DUPLICATE_KEY || err == DB_TABLESPACE_EXISTS) {
10025 char display_name[FN_REFLEN];
10026 char* buf_end = innobase_convert_identifier(
10027 display_name, sizeof(display_name) - 1,
10028 table_name, strlen(table_name),
10029 thd, TRUE);
10030
10031 *buf_end = '\0';
10032
10033 my_error(err == DB_DUPLICATE_KEY
10034 ? ER_TABLE_EXISTS_ERROR
10035 : ER_TABLESPACE_EXISTS, MYF(0), display_name);
10036 }
10037
10038 if (err == DB_SUCCESS && (flags2 & DICT_TF2_FTS)) {
10039 fts_optimize_add_table(table);
10040 }
10041
10042 error_ret:
10043 DBUG_RETURN(convert_error_code_to_mysql(err, flags, thd));
10044 }
10045
10046 /*****************************************************************//**
10047 Creates an index in an InnoDB database. */
10048 static
10049 int
create_index(trx_t * trx,const TABLE * form,ulint flags,const char * table_name,uint key_num)10050 create_index(
10051 /*=========*/
10052 trx_t* trx, /*!< in: InnoDB transaction handle */
10053 const TABLE* form, /*!< in: information on table
10054 columns and indexes */
10055 ulint flags, /*!< in: InnoDB table flags */
10056 const char* table_name, /*!< in: table name */
10057 uint key_num) /*!< in: index number */
10058 {
10059 dict_index_t* index;
10060 int error;
10061 const KEY* key;
10062 ulint ind_type;
10063 ulint* field_lengths;
10064
10065 DBUG_ENTER("create_index");
10066
10067 key = form->key_info + key_num;
10068
10069 /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
10070 ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0);
10071
10072 if (key->flags & HA_FULLTEXT) {
10073 index = dict_mem_index_create(table_name, key->name, 0,
10074 DICT_FTS,
10075 key->user_defined_key_parts);
10076
10077 for (ulint i = 0; i < key->user_defined_key_parts; i++) {
10078 KEY_PART_INFO* key_part = key->key_part + i;
10079 dict_mem_index_add_field(
10080 index, key_part->field->field_name, 0);
10081 }
10082
10083 DBUG_RETURN(convert_error_code_to_mysql(
10084 row_create_index_for_mysql(
10085 index, trx, NULL),
10086 flags, NULL));
10087
10088 }
10089
10090 ind_type = 0;
10091
10092 if (key_num == form->s->primary_key) {
10093 ind_type |= DICT_CLUSTERED;
10094 }
10095
10096 if (key->flags & HA_NOSAME) {
10097 ind_type |= DICT_UNIQUE;
10098 }
10099
10100 field_lengths = (ulint*) my_malloc(
10101 key->user_defined_key_parts * sizeof *
10102 field_lengths, MYF(MY_FAE));
10103
10104 /* We pass 0 as the space id, and determine at a lower level the space
10105 id where to store the table */
10106
10107 index = dict_mem_index_create(table_name, key->name, 0,
10108 ind_type, key->user_defined_key_parts);
10109
10110 for (ulint i = 0; i < key->user_defined_key_parts; i++) {
10111 KEY_PART_INFO* key_part = key->key_part + i;
10112 ulint prefix_len;
10113 ulint col_type;
10114 ulint is_unsigned;
10115
10116
10117 /* (The flag HA_PART_KEY_SEG denotes in MySQL a
10118 column prefix field in an index: we only store a
10119 specified number of first bytes of the column to
10120 the index field.) The flag does not seem to be
10121 properly set by MySQL. Let us fall back on testing
10122 the length of the key part versus the column. */
10123
10124 Field* field = NULL;
10125
10126 for (ulint j = 0; j < form->s->fields; j++) {
10127
10128 field = form->field[j];
10129
10130 if (0 == innobase_strcasecmp(
10131 field->field_name,
10132 key_part->field->field_name)) {
10133 /* Found the corresponding column */
10134
10135 goto found;
10136 }
10137 }
10138
10139 ut_error;
10140 found:
10141 col_type = get_innobase_type_from_mysql_type(
10142 &is_unsigned, key_part->field);
10143
10144 if (DATA_BLOB == col_type
10145 || (key_part->length < field->pack_length()
10146 && field->type() != MYSQL_TYPE_VARCHAR)
10147 || (field->type() == MYSQL_TYPE_VARCHAR
10148 && key_part->length < field->pack_length()
10149 - ((Field_varstring*) field)->length_bytes)) {
10150
10151 switch (col_type) {
10152 default:
10153 prefix_len = key_part->length;
10154 break;
10155 case DATA_INT:
10156 case DATA_FLOAT:
10157 case DATA_DOUBLE:
10158 case DATA_DECIMAL:
10159 sql_print_error(
10160 "MySQL is trying to create a column "
10161 "prefix index field, on an "
10162 "inappropriate data type. Table "
10163 "name %s, column name %s.",
10164 table_name,
10165 key_part->field->field_name);
10166
10167 prefix_len = 0;
10168 }
10169 } else {
10170 prefix_len = 0;
10171 }
10172
10173 field_lengths[i] = key_part->length;
10174
10175 dict_mem_index_add_field(
10176 index, key_part->field->field_name, prefix_len);
10177 }
10178
10179 ut_ad(key->flags & HA_FULLTEXT || !(index->type & DICT_FTS));
10180
10181 /* Even though we've defined max_supported_key_part_length, we
10182 still do our own checking using field_lengths to be absolutely
10183 sure we don't create too long indexes. */
10184
10185 error = convert_error_code_to_mysql(
10186 row_create_index_for_mysql(index, trx, field_lengths),
10187 flags, NULL);
10188
10189 my_free(field_lengths);
10190
10191 DBUG_RETURN(error);
10192 }
10193
10194 /*****************************************************************//**
10195 Creates an index to an InnoDB table when the user has defined no
10196 primary index. */
10197 static
10198 int
create_clustered_index_when_no_primary(trx_t * trx,ulint flags,const char * table_name)10199 create_clustered_index_when_no_primary(
10200 /*===================================*/
10201 trx_t* trx, /*!< in: InnoDB transaction handle */
10202 ulint flags, /*!< in: InnoDB table flags */
10203 const char* table_name) /*!< in: table name */
10204 {
10205 dict_index_t* index;
10206 dberr_t error;
10207
10208 /* We pass 0 as the space id, and determine at a lower level the space
10209 id where to store the table */
10210 index = dict_mem_index_create(table_name,
10211 innobase_index_reserve_name,
10212 0, DICT_CLUSTERED, 0);
10213
10214 error = row_create_index_for_mysql(index, trx, NULL);
10215
10216 return(convert_error_code_to_mysql(error, flags, NULL));
10217 }
10218
10219 /*****************************************************************//**
10220 Return a display name for the row format
10221 @return row format name */
10222 UNIV_INTERN
10223 const char*
get_row_format_name(enum row_type row_format)10224 get_row_format_name(
10225 /*================*/
10226 enum row_type row_format) /*!< in: Row Format */
10227 {
10228 switch (row_format) {
10229 case ROW_TYPE_COMPACT:
10230 return("COMPACT");
10231 case ROW_TYPE_COMPRESSED:
10232 return("COMPRESSED");
10233 case ROW_TYPE_DYNAMIC:
10234 return("DYNAMIC");
10235 case ROW_TYPE_REDUNDANT:
10236 return("REDUNDANT");
10237 case ROW_TYPE_DEFAULT:
10238 return("DEFAULT");
10239 case ROW_TYPE_FIXED:
10240 return("FIXED");
10241 case ROW_TYPE_PAGE:
10242 case ROW_TYPE_NOT_USED:
10243 default:
10244 break;
10245 }
10246 return("NOT USED");
10247 }
10248
10249 /** If file-per-table is missing, issue warning and set ret false */
10250 #define CHECK_ERROR_ROW_TYPE_NEEDS_FILE_PER_TABLE(use_tablespace)\
10251 if (!use_tablespace) { \
10252 push_warning_printf( \
10253 thd, Sql_condition::WARN_LEVEL_WARN, \
10254 ER_ILLEGAL_HA_CREATE_OPTION, \
10255 "InnoDB: ROW_FORMAT=%s requires" \
10256 " innodb_file_per_table.", \
10257 get_row_format_name(row_format)); \
10258 ret = "ROW_FORMAT"; \
10259 }
10260
10261 /** If file-format is Antelope, issue warning and set ret false */
10262 #define CHECK_ERROR_ROW_TYPE_NEEDS_GT_ANTELOPE \
10263 if (srv_file_format < UNIV_FORMAT_B) { \
10264 push_warning_printf( \
10265 thd, Sql_condition::WARN_LEVEL_WARN, \
10266 ER_ILLEGAL_HA_CREATE_OPTION, \
10267 "InnoDB: ROW_FORMAT=%s requires" \
10268 " innodb_file_format > Antelope.", \
10269 get_row_format_name(row_format)); \
10270 ret = "ROW_FORMAT"; \
10271 }
10272
10273
10274 /*****************************************************************//**
10275 Validates the create options. We may build on this function
10276 in future. For now, it checks two specifiers:
10277 KEY_BLOCK_SIZE and ROW_FORMAT
10278 If innodb_strict_mode is not set then this function is a no-op
10279 @return NULL if valid, string if not. */
10280 UNIV_INTERN
10281 const char*
create_options_are_invalid(THD * thd,TABLE * form,HA_CREATE_INFO * create_info,bool use_tablespace)10282 create_options_are_invalid(
10283 /*=======================*/
10284 THD* thd, /*!< in: connection thread. */
10285 TABLE* form, /*!< in: information on table
10286 columns and indexes */
10287 HA_CREATE_INFO* create_info, /*!< in: create info. */
10288 bool use_tablespace) /*!< in: srv_file_per_table */
10289 {
10290 ibool kbs_specified = FALSE;
10291 const char* ret = NULL;
10292 enum row_type row_format = form->s->row_type;
10293
10294 ut_ad(thd != NULL);
10295
10296 /* If innodb_strict_mode is not set don't do any validation. */
10297 if (!(THDVAR(thd, strict_mode))) {
10298 return(NULL);
10299 }
10300
10301 ut_ad(form != NULL);
10302 ut_ad(create_info != NULL);
10303
10304 /* First check if a non-zero KEY_BLOCK_SIZE was specified. */
10305 if (create_info->key_block_size) {
10306 kbs_specified = TRUE;
10307 switch (create_info->key_block_size) {
10308 ulint kbs_max;
10309 case 1:
10310 case 2:
10311 case 4:
10312 case 8:
10313 case 16:
10314 /* Valid KEY_BLOCK_SIZE, check its dependencies. */
10315 if (!use_tablespace) {
10316 push_warning(
10317 thd, Sql_condition::WARN_LEVEL_WARN,
10318 ER_ILLEGAL_HA_CREATE_OPTION,
10319 "InnoDB: KEY_BLOCK_SIZE requires"
10320 " innodb_file_per_table.");
10321 ret = "KEY_BLOCK_SIZE";
10322 }
10323 if (srv_file_format < UNIV_FORMAT_B) {
10324 push_warning(
10325 thd, Sql_condition::WARN_LEVEL_WARN,
10326 ER_ILLEGAL_HA_CREATE_OPTION,
10327 "InnoDB: KEY_BLOCK_SIZE requires"
10328 " innodb_file_format > Antelope.");
10329 ret = "KEY_BLOCK_SIZE";
10330 }
10331
10332 /* The maximum KEY_BLOCK_SIZE (KBS) is 16. But if
10333 UNIV_PAGE_SIZE is smaller than 16k, the maximum
10334 KBS is also smaller. */
10335 kbs_max = ut_min(
10336 1 << (UNIV_PAGE_SSIZE_MAX - 1),
10337 1 << (PAGE_ZIP_SSIZE_MAX - 1));
10338 if (create_info->key_block_size > kbs_max) {
10339 push_warning_printf(
10340 thd, Sql_condition::WARN_LEVEL_WARN,
10341 ER_ILLEGAL_HA_CREATE_OPTION,
10342 "InnoDB: KEY_BLOCK_SIZE=%ld"
10343 " cannot be larger than %ld.",
10344 create_info->key_block_size,
10345 kbs_max);
10346 ret = "KEY_BLOCK_SIZE";
10347 }
10348 break;
10349 default:
10350 push_warning_printf(
10351 thd, Sql_condition::WARN_LEVEL_WARN,
10352 ER_ILLEGAL_HA_CREATE_OPTION,
10353 "InnoDB: invalid KEY_BLOCK_SIZE = %lu."
10354 " Valid values are [1, 2, 4, 8, 16]",
10355 create_info->key_block_size);
10356 ret = "KEY_BLOCK_SIZE";
10357 break;
10358 }
10359 }
10360
10361 /* Check for a valid Innodb ROW_FORMAT specifier and
10362 other incompatibilities. */
10363 switch (row_format) {
10364 case ROW_TYPE_COMPRESSED:
10365 CHECK_ERROR_ROW_TYPE_NEEDS_FILE_PER_TABLE(use_tablespace);
10366 CHECK_ERROR_ROW_TYPE_NEEDS_GT_ANTELOPE;
10367 break;
10368 case ROW_TYPE_DYNAMIC:
10369 CHECK_ERROR_ROW_TYPE_NEEDS_FILE_PER_TABLE(use_tablespace);
10370 CHECK_ERROR_ROW_TYPE_NEEDS_GT_ANTELOPE;
10371 // fallthrough
10372 // since dynamic also shuns KBS
10373 case ROW_TYPE_COMPACT:
10374 case ROW_TYPE_REDUNDANT:
10375 if (kbs_specified) {
10376 push_warning_printf(
10377 thd, Sql_condition::WARN_LEVEL_WARN,
10378 ER_ILLEGAL_HA_CREATE_OPTION,
10379 "InnoDB: cannot specify ROW_FORMAT = %s"
10380 " with KEY_BLOCK_SIZE.",
10381 get_row_format_name(row_format));
10382 ret = "KEY_BLOCK_SIZE";
10383 }
10384 break;
10385 case ROW_TYPE_DEFAULT:
10386 break;
10387 case ROW_TYPE_FIXED:
10388 case ROW_TYPE_PAGE:
10389 case ROW_TYPE_NOT_USED:
10390 default:
10391 push_warning(
10392 thd, Sql_condition::WARN_LEVEL_WARN,
10393 ER_ILLEGAL_HA_CREATE_OPTION, \
10394 "InnoDB: invalid ROW_FORMAT specifier.");
10395 ret = "ROW_TYPE";
10396 break;
10397 }
10398
10399 /* Use DATA DIRECTORY only with file-per-table. */
10400 if (create_info->data_file_name && !use_tablespace) {
10401 push_warning(
10402 thd, Sql_condition::WARN_LEVEL_WARN,
10403 ER_ILLEGAL_HA_CREATE_OPTION,
10404 "InnoDB: DATA DIRECTORY requires"
10405 " innodb_file_per_table.");
10406 ret = "DATA DIRECTORY";
10407 }
10408
10409 /* Do not use DATA DIRECTORY with TEMPORARY TABLE. */
10410 if (create_info->data_file_name
10411 && create_info->options & HA_LEX_CREATE_TMP_TABLE) {
10412 push_warning(
10413 thd, Sql_condition::WARN_LEVEL_WARN,
10414 ER_ILLEGAL_HA_CREATE_OPTION,
10415 "InnoDB: DATA DIRECTORY cannot be used"
10416 " for TEMPORARY tables.");
10417 ret = "DATA DIRECTORY";
10418 }
10419
10420 /* Do not allow INDEX_DIRECTORY */
10421 if (create_info->index_file_name) {
10422 push_warning_printf(
10423 thd, Sql_condition::WARN_LEVEL_WARN,
10424 ER_ILLEGAL_HA_CREATE_OPTION,
10425 "InnoDB: INDEX DIRECTORY is not supported");
10426 ret = "INDEX DIRECTORY";
10427 }
10428
10429 return(ret);
10430 }
10431
10432 /*****************************************************************//**
10433 Update create_info. Used in SHOW CREATE TABLE et al. */
10434 UNIV_INTERN
10435 void
update_create_info(HA_CREATE_INFO * create_info)10436 ha_innobase::update_create_info(
10437 /*============================*/
10438 HA_CREATE_INFO* create_info) /*!< in/out: create info */
10439 {
10440 if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) {
10441 ha_innobase::info(HA_STATUS_AUTO);
10442 create_info->auto_increment_value = stats.auto_increment_value;
10443 }
10444
10445 /* Update the DATA DIRECTORY name from SYS_DATAFILES. */
10446 dict_get_and_save_data_dir_path(prebuilt->table, false);
10447
10448 if (prebuilt->table->data_dir_path) {
10449 create_info->data_file_name = prebuilt->table->data_dir_path;
10450 }
10451 }
10452
10453 /*****************************************************************//**
10454 Initialize the table FTS stopword list
10455 @return TRUE if success */
10456 UNIV_INTERN
10457 ibool
innobase_fts_load_stopword(dict_table_t * table,trx_t * trx,THD * thd)10458 innobase_fts_load_stopword(
10459 /*=======================*/
10460 dict_table_t* table, /*!< in: Table has the FTS */
10461 trx_t* trx, /*!< in: transaction */
10462 THD* thd) /*!< in: current thread */
10463 {
10464 return(fts_load_stopword(table, trx,
10465 innobase_server_stopword_table,
10466 THDVAR(thd, ft_user_stopword_table),
10467 THDVAR(thd, ft_enable_stopword), FALSE));
10468 }
10469
10470 /*****************************************************************//**
10471 Parses the table name into normal name and either temp path or remote path
10472 if needed.
10473 @return 0 if successful, otherwise, error number */
10474 UNIV_INTERN
10475 int
parse_table_name(const char * name,HA_CREATE_INFO * create_info,ulint flags,ulint flags2,char * norm_name,char * temp_path,char * remote_path)10476 ha_innobase::parse_table_name(
10477 /*==========================*/
10478 const char* name, /*!< in/out: table name provided*/
10479 HA_CREATE_INFO* create_info, /*!< in: more information of the
10480 created table, contains also the
10481 create statement string */
10482 ulint flags, /*!< in: flags*/
10483 ulint flags2, /*!< in: flags2*/
10484 char* norm_name, /*!< out: normalized table name */
10485 char* temp_path, /*!< out: absolute path of table */
10486 char* remote_path) /*!< out: remote path of table */
10487 {
10488 THD* thd = ha_thd();
10489 bool use_tablespace = flags2 & DICT_TF2_USE_TABLESPACE;
10490 DBUG_ENTER("ha_innobase::parse_table_name");
10491
10492 #ifdef __WIN__
10493 /* Names passed in from server are in two formats:
10494 1. <database_name>/<table_name>: for normal table creation
10495 2. full path: for temp table creation, or DATA DIRECTORY.
10496
10497 When srv_file_per_table is on and mysqld_embedded is off,
10498 check for full path pattern, i.e.
10499 X:\dir\..., X is a driver letter, or
10500 \\dir1\dir2\..., UNC path
10501 returns error if it is in full path format, but not creating a temp.
10502 table. Currently InnoDB does not support symbolic link on Windows. */
10503
10504 if (use_tablespace
10505 && !mysqld_embedded
10506 && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
10507
10508 if ((name[1] == ':')
10509 || (name[0] == '\\' && name[1] == '\\')) {
10510 sql_print_error("Cannot create table %s\n", name);
10511 DBUG_RETURN(HA_ERR_GENERIC);
10512 }
10513 }
10514 #endif
10515
10516 normalize_table_name(norm_name, name);
10517 temp_path[0] = '\0';
10518 remote_path[0] = '\0';
10519
10520 /* A full path is used for TEMPORARY TABLE and DATA DIRECTORY.
10521 In the case of;
10522 CREATE TEMPORARY TABLE ... DATA DIRECTORY={path} ... ;
10523 We ignore the DATA DIRECTORY. */
10524 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
10525 strncpy(temp_path, name, FN_REFLEN - 1);
10526 }
10527
10528 if (create_info->data_file_name) {
10529 bool ignore = false;
10530
10531 /* Use DATA DIRECTORY only with file-per-table. */
10532 if (!use_tablespace) {
10533 push_warning(
10534 thd, Sql_condition::WARN_LEVEL_WARN,
10535 ER_ILLEGAL_HA_CREATE_OPTION,
10536 "InnoDB: DATA DIRECTORY requires"
10537 " innodb_file_per_table.");
10538 ignore = true;
10539 }
10540
10541 /* Do not use DATA DIRECTORY with TEMPORARY TABLE. */
10542 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
10543 push_warning(
10544 thd, Sql_condition::WARN_LEVEL_WARN,
10545 ER_ILLEGAL_HA_CREATE_OPTION,
10546 "InnoDB: DATA DIRECTORY cannot be"
10547 " used for TEMPORARY tables.");
10548 ignore = true;
10549 }
10550
10551 if (ignore) {
10552 push_warning_printf(
10553 thd, Sql_condition::WARN_LEVEL_WARN,
10554 WARN_OPTION_IGNORED,
10555 ER_DEFAULT(WARN_OPTION_IGNORED),
10556 "DATA DIRECTORY");
10557 } else {
10558 strncpy(remote_path, create_info->data_file_name,
10559 FN_REFLEN - 1);
10560 }
10561 }
10562
10563 if (create_info->index_file_name) {
10564 push_warning_printf(
10565 thd, Sql_condition::WARN_LEVEL_WARN,
10566 WARN_OPTION_IGNORED,
10567 ER_DEFAULT(WARN_OPTION_IGNORED),
10568 "INDEX DIRECTORY");
10569 }
10570
10571 DBUG_RETURN(0);
10572 }
10573
10574 /*****************************************************************//**
10575 Determines InnoDB table flags.
10576 @retval true if successful, false if error */
10577 UNIV_INTERN
10578 bool
innobase_table_flags(const TABLE * form,const HA_CREATE_INFO * create_info,THD * thd,bool use_tablespace,ulint * flags,ulint * flags2)10579 innobase_table_flags(
10580 /*=================*/
10581 const TABLE* form, /*!< in: table */
10582 const HA_CREATE_INFO* create_info, /*!< in: information
10583 on table columns and indexes */
10584 THD* thd, /*!< in: connection */
10585 bool use_tablespace, /*!< in: whether to create
10586 outside system tablespace */
10587 ulint* flags, /*!< out: DICT_TF flags */
10588 ulint* flags2) /*!< out: DICT_TF2 flags */
10589 {
10590 DBUG_ENTER("innobase_table_flags");
10591
10592 const char* fts_doc_id_index_bad = NULL;
10593 bool zip_allowed = true;
10594 ulint zip_ssize = 0;
10595 enum row_type row_format;
10596 rec_format_t innodb_row_format = REC_FORMAT_COMPACT;
10597 bool use_data_dir;
10598
10599 /* Cache the value of innodb_file_format, in case it is
10600 modified by another thread while the table is being created. */
10601 const ulint file_format_allowed = srv_file_format;
10602
10603 *flags = 0;
10604 *flags2 = 0;
10605
10606 /* Check if there are any FTS indexes defined on this table. */
10607 for (uint i = 0; i < form->s->keys; i++) {
10608 const KEY* key = &form->key_info[i];
10609
10610 if (key->flags & HA_FULLTEXT) {
10611 *flags2 |= DICT_TF2_FTS;
10612
10613 /* We don't support FTS indexes in temporary
10614 tables. */
10615 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
10616
10617 my_error(ER_INNODB_NO_FT_TEMP_TABLE, MYF(0));
10618 DBUG_RETURN(false);
10619 }
10620
10621 if (key->flags & HA_USES_PARSER) {
10622 my_error(ER_INNODB_NO_FT_USES_PARSER, MYF(0));
10623 DBUG_RETURN(false);
10624 }
10625
10626 if (fts_doc_id_index_bad) {
10627 goto index_bad;
10628 }
10629 }
10630
10631 if (innobase_strcasecmp(key->name, FTS_DOC_ID_INDEX_NAME)) {
10632 continue;
10633 }
10634
10635 /* Do a pre-check on FTS DOC ID index */
10636 if (!(key->flags & HA_NOSAME)
10637 || strcmp(key->name, FTS_DOC_ID_INDEX_NAME)
10638 || strcmp(key->key_part[0].field->field_name,
10639 FTS_DOC_ID_COL_NAME)) {
10640 fts_doc_id_index_bad = key->name;
10641 }
10642
10643 if (fts_doc_id_index_bad && (*flags2 & DICT_TF2_FTS)) {
10644 index_bad:
10645 my_error(ER_INNODB_FT_WRONG_DOCID_INDEX, MYF(0),
10646 fts_doc_id_index_bad);
10647 DBUG_RETURN(false);
10648 }
10649 }
10650
10651 if (create_info->key_block_size) {
10652 /* The requested compressed page size (key_block_size)
10653 is given in kilobytes. If it is a valid number, store
10654 that value as the number of log2 shifts from 512 in
10655 zip_ssize. Zero means it is not compressed. */
10656 ulint zssize; /* Zip Shift Size */
10657 ulint kbsize; /* Key Block Size */
10658 for (zssize = kbsize = 1;
10659 zssize <= ut_min(UNIV_PAGE_SSIZE_MAX,
10660 PAGE_ZIP_SSIZE_MAX);
10661 zssize++, kbsize <<= 1) {
10662 if (kbsize == create_info->key_block_size) {
10663 zip_ssize = zssize;
10664 break;
10665 }
10666 }
10667
10668 /* Make sure compressed row format is allowed. */
10669 if (!use_tablespace) {
10670 push_warning(
10671 thd, Sql_condition::WARN_LEVEL_WARN,
10672 ER_ILLEGAL_HA_CREATE_OPTION,
10673 "InnoDB: KEY_BLOCK_SIZE requires"
10674 " innodb_file_per_table.");
10675 zip_allowed = FALSE;
10676 }
10677
10678 if (file_format_allowed < UNIV_FORMAT_B) {
10679 push_warning(
10680 thd, Sql_condition::WARN_LEVEL_WARN,
10681 ER_ILLEGAL_HA_CREATE_OPTION,
10682 "InnoDB: KEY_BLOCK_SIZE requires"
10683 " innodb_file_format > Antelope.");
10684 zip_allowed = FALSE;
10685 }
10686
10687 if (!zip_allowed
10688 || zssize > ut_min(UNIV_PAGE_SSIZE_MAX,
10689 PAGE_ZIP_SSIZE_MAX)) {
10690 push_warning_printf(
10691 thd, Sql_condition::WARN_LEVEL_WARN,
10692 ER_ILLEGAL_HA_CREATE_OPTION,
10693 "InnoDB: ignoring KEY_BLOCK_SIZE=%lu.",
10694 create_info->key_block_size);
10695 }
10696 }
10697
10698 row_format = form->s->row_type;
10699
10700 if (zip_ssize && zip_allowed) {
10701 /* if ROW_FORMAT is set to default,
10702 automatically change it to COMPRESSED.*/
10703 if (row_format == ROW_TYPE_DEFAULT) {
10704 row_format = ROW_TYPE_COMPRESSED;
10705 } else if (row_format != ROW_TYPE_COMPRESSED) {
10706 /* ROW_FORMAT other than COMPRESSED
10707 ignores KEY_BLOCK_SIZE. It does not
10708 make sense to reject conflicting
10709 KEY_BLOCK_SIZE and ROW_FORMAT, because
10710 such combinations can be obtained
10711 with ALTER TABLE anyway. */
10712 push_warning_printf(
10713 thd, Sql_condition::WARN_LEVEL_WARN,
10714 ER_ILLEGAL_HA_CREATE_OPTION,
10715 "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
10716 " unless ROW_FORMAT=COMPRESSED.",
10717 create_info->key_block_size);
10718 zip_allowed = FALSE;
10719 }
10720 } else {
10721 /* zip_ssize == 0 means no KEY_BLOCK_SIZE.*/
10722 if (row_format == ROW_TYPE_COMPRESSED && zip_allowed) {
10723 /* ROW_FORMAT=COMPRESSED without KEY_BLOCK_SIZE
10724 implies half the maximum KEY_BLOCK_SIZE(*1k) or
10725 UNIV_PAGE_SIZE, whichever is less. */
10726 zip_ssize = ut_min(UNIV_PAGE_SSIZE_MAX,
10727 PAGE_ZIP_SSIZE_MAX) - 1;
10728 }
10729 }
10730
10731 /* Validate the row format. Correct it if necessary */
10732 switch (row_format) {
10733 case ROW_TYPE_REDUNDANT:
10734 innodb_row_format = REC_FORMAT_REDUNDANT;
10735 break;
10736
10737 case ROW_TYPE_COMPRESSED:
10738 case ROW_TYPE_DYNAMIC:
10739 if (!use_tablespace) {
10740 push_warning_printf(
10741 thd, Sql_condition::WARN_LEVEL_WARN,
10742 ER_ILLEGAL_HA_CREATE_OPTION,
10743 "InnoDB: ROW_FORMAT=%s requires"
10744 " innodb_file_per_table.",
10745 get_row_format_name(row_format));
10746 } else if (file_format_allowed == UNIV_FORMAT_A) {
10747 push_warning_printf(
10748 thd, Sql_condition::WARN_LEVEL_WARN,
10749 ER_ILLEGAL_HA_CREATE_OPTION,
10750 "InnoDB: ROW_FORMAT=%s requires"
10751 " innodb_file_format > Antelope.",
10752 get_row_format_name(row_format));
10753 } else {
10754 innodb_row_format = (row_format == ROW_TYPE_DYNAMIC
10755 ? REC_FORMAT_DYNAMIC
10756 : REC_FORMAT_COMPRESSED);
10757 break;
10758 }
10759 zip_allowed = FALSE;
10760 // fallthrough
10761 // to set row_format = COMPACT
10762 case ROW_TYPE_NOT_USED:
10763 case ROW_TYPE_FIXED:
10764 case ROW_TYPE_PAGE:
10765 default:
10766 push_warning(
10767 thd, Sql_condition::WARN_LEVEL_WARN,
10768 ER_ILLEGAL_HA_CREATE_OPTION,
10769 "InnoDB: assuming ROW_FORMAT=COMPACT.");
10770 // fallthrough
10771 case ROW_TYPE_DEFAULT:
10772 /* If we fell through, set row format to Compact. */
10773 row_format = ROW_TYPE_COMPACT;
10774 // fallthrough
10775 case ROW_TYPE_COMPACT:
10776 break;
10777 }
10778
10779 /* Set the table flags */
10780 if (!zip_allowed) {
10781 zip_ssize = 0;
10782 }
10783
10784 use_data_dir = use_tablespace
10785 && ((create_info->data_file_name != NULL)
10786 && !(create_info->options & HA_LEX_CREATE_TMP_TABLE));
10787
10788 dict_tf_set(flags, innodb_row_format, zip_ssize, use_data_dir);
10789
10790 if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
10791 *flags2 |= DICT_TF2_TEMPORARY;
10792 }
10793
10794 if (use_tablespace) {
10795 *flags2 |= DICT_TF2_USE_TABLESPACE;
10796 }
10797
10798 /* Set the flags2 when create table or alter tables */
10799 *flags2 |= DICT_TF2_FTS_AUX_HEX_NAME;
10800 DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
10801 *flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;);
10802
10803 DBUG_RETURN(true);
10804 }
10805
10806 /*****************************************************************//**
10807 Creates a new table to an InnoDB database.
10808 @return error number */
10809 UNIV_INTERN
10810 int
create(const char * name,TABLE * form,HA_CREATE_INFO * create_info)10811 ha_innobase::create(
10812 /*================*/
10813 const char* name, /*!< in: table name */
10814 TABLE* form, /*!< in: information on table
10815 columns and indexes */
10816 HA_CREATE_INFO* create_info) /*!< in: more information of the
10817 created table, contains also the
10818 create statement string */
10819 {
10820 int error;
10821 trx_t* parent_trx;
10822 trx_t* trx;
10823 int primary_key_no;
10824 uint i;
10825 char norm_name[FN_REFLEN]; /* {database}/{tablename} */
10826 char temp_path[FN_REFLEN]; /* absolute path of temp frm */
10827 char remote_path[FN_REFLEN]; /* absolute path of table */
10828 THD* thd = ha_thd();
10829 ib_int64_t auto_inc_value;
10830
10831 /* Cache the global variable "srv_file_per_table" to a local
10832 variable before using it. Note that "srv_file_per_table"
10833 is not under dict_sys mutex protection, and could be changed
10834 while creating the table. So we read the current value here
10835 and make all further decisions based on this. */
10836 bool use_tablespace = srv_file_per_table;
10837
10838 /* Zip Shift Size - log2 - 9 of compressed page size,
10839 zero for uncompressed */
10840 ulint flags;
10841 ulint flags2;
10842 dict_table_t* innobase_table = NULL;
10843
10844 const char* stmt;
10845 size_t stmt_len;
10846
10847 mem_heap_t* heap = 0;
10848 ulint* zip_dict_ids = 0;
10849 const char* err_zip_dict_name = 0;
10850
10851 DBUG_ENTER("ha_innobase::create");
10852
10853 DBUG_ASSERT(thd != NULL);
10854 DBUG_ASSERT(create_info != NULL);
10855
10856 if (form->s->fields > REC_MAX_N_USER_FIELDS) {
10857 DBUG_RETURN(HA_ERR_TOO_MANY_FIELDS);
10858 } else if (high_level_read_only) {
10859 DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
10860 }
10861
10862 /* Create the table definition in InnoDB */
10863
10864 /* Validate create options if innodb_strict_mode is set. */
10865 if (create_options_are_invalid(
10866 thd, form, create_info, use_tablespace)) {
10867 DBUG_RETURN(HA_WRONG_CREATE_OPTION);
10868 }
10869
10870 if (!innobase_table_flags(form, create_info,
10871 thd, use_tablespace,
10872 &flags, &flags2)) {
10873 DBUG_RETURN(-1);
10874 }
10875
10876 error = parse_table_name(name, create_info, flags, flags2,
10877 norm_name, temp_path, remote_path);
10878 if (error) {
10879 DBUG_RETURN(error);
10880 }
10881
10882 /* Look for a primary key */
10883 primary_key_no = (form->s->primary_key != MAX_KEY ?
10884 (int) form->s->primary_key :
10885 -1);
10886
10887 /* Our function innobase_get_mysql_key_number_for_index assumes
10888 the primary key is always number 0, if it exists */
10889 ut_a(primary_key_no == -1 || primary_key_no == 0);
10890
10891 /* Check for name conflicts (with reserved name) for
10892 any user indices to be created. */
10893 if (innobase_index_name_is_reserved(thd, form->key_info,
10894 form->s->keys)) {
10895 DBUG_RETURN(-1);
10896 }
10897
10898 if (row_is_magic_monitor_table(norm_name)) {
10899 push_warning_printf(thd,
10900 Sql_condition::WARN_LEVEL_WARN,
10901 HA_ERR_WRONG_COMMAND,
10902 "Using the table name %s to enable "
10903 "diagnostic output is deprecated "
10904 "and may be removed in future releases. "
10905 "Use INFORMATION_SCHEMA or "
10906 "PERFORMANCE_SCHEMA tables or "
10907 "SET GLOBAL innodb_status_output=ON.",
10908 dict_remove_db_name(norm_name));
10909
10910 /* Limit innodb monitor access to users with PROCESS privilege.
10911 See http://bugs.mysql.com/32710 why we chose PROCESS. */
10912 if (check_global_access(thd, PROCESS_ACL)) {
10913 DBUG_RETURN(HA_ERR_GENERIC);
10914 }
10915 }
10916
10917 /* Get the transaction associated with the current thd, or create one
10918 if not yet created */
10919
10920 parent_trx = check_trx_exists(thd);
10921
10922 /* In case MySQL calls this in the middle of a SELECT query, release
10923 possible adaptive hash latch to avoid deadlocks of threads */
10924
10925 trx_search_latch_release_if_reserved(parent_trx);
10926
10927 trx = innobase_trx_allocate(thd);
10928
10929 if (UNIV_UNLIKELY(trx->fake_changes)) {
10930 innobase_commit_low(trx);
10931 trx_free_for_mysql(trx);
10932 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
10933 }
10934
10935 /* Latch the InnoDB data dictionary exclusively so that no deadlocks
10936 or lock waits can happen in it during a table create operation.
10937 Drop table etc. do this latching in row0mysql.cc. */
10938
10939 row_mysql_lock_data_dictionary(trx);
10940
10941 heap = mem_heap_create(form->s->fields * sizeof(ulint));
10942 zip_dict_ids = static_cast<ulint*>(
10943 mem_heap_alloc(heap, form->s->fields * sizeof(ulint)));
10944
10945 if (!innobase_check_zip_dicts(form, zip_dict_ids,
10946 trx, &err_zip_dict_name)) {
10947 error = -1;
10948 my_error(ER_COMPRESSION_DICTIONARY_DOES_NOT_EXIST,
10949 MYF(0), err_zip_dict_name);
10950 goto cleanup;
10951 }
10952
10953 error = create_table_def(trx, form, norm_name, temp_path,
10954 remote_path, flags, flags2);
10955 if (error) {
10956 goto cleanup;
10957 }
10958
10959 /* Create the keys */
10960
10961 if (form->s->keys == 0 || primary_key_no == -1) {
10962 /* Create an index which is used as the clustered index;
10963 order the rows by their row id which is internally generated
10964 by InnoDB */
10965
10966 error = create_clustered_index_when_no_primary(
10967 trx, flags, norm_name);
10968 if (error) {
10969 goto cleanup;
10970 }
10971 }
10972
10973 if (primary_key_no != -1) {
10974 /* In InnoDB the clustered index must always be created
10975 first */
10976 if ((error = create_index(trx, form, flags, norm_name,
10977 (uint) primary_key_no))) {
10978 goto cleanup;
10979 }
10980 }
10981
10982 /* Create the ancillary tables that are common to all FTS indexes on
10983 this table. */
10984 if (flags2 & DICT_TF2_FTS) {
10985 enum fts_doc_id_index_enum ret;
10986
10987 innobase_table = dict_table_open_on_name(
10988 norm_name, TRUE, FALSE, DICT_ERR_IGNORE_NONE);
10989
10990 ut_a(innobase_table);
10991
10992 /* Check whether there already exists FTS_DOC_ID_INDEX */
10993 ret = innobase_fts_check_doc_id_index_in_def(
10994 form->s->keys, form->key_info);
10995
10996 switch (ret) {
10997 case FTS_INCORRECT_DOC_ID_INDEX:
10998 push_warning_printf(thd,
10999 Sql_condition::WARN_LEVEL_WARN,
11000 ER_WRONG_NAME_FOR_INDEX,
11001 " InnoDB: Index name %s is reserved"
11002 " for the unique index on"
11003 " FTS_DOC_ID column for FTS"
11004 " Document ID indexing"
11005 " on table %s. Please check"
11006 " the index definition to"
11007 " make sure it is of correct"
11008 " type\n",
11009 FTS_DOC_ID_INDEX_NAME,
11010 innobase_table->name);
11011
11012 if (innobase_table->fts) {
11013 fts_free(innobase_table);
11014 }
11015
11016 dict_table_close(innobase_table, TRUE, FALSE);
11017 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
11018 FTS_DOC_ID_INDEX_NAME);
11019 error = -1;
11020 goto cleanup;
11021 case FTS_EXIST_DOC_ID_INDEX:
11022 case FTS_NOT_EXIST_DOC_ID_INDEX:
11023 break;
11024 }
11025
11026 dberr_t err = fts_create_common_tables(
11027 trx, innobase_table, norm_name,
11028 (ret == FTS_EXIST_DOC_ID_INDEX));
11029
11030 error = convert_error_code_to_mysql(err, 0, NULL);
11031
11032 dict_table_close(innobase_table, TRUE, FALSE);
11033
11034 if (error) {
11035 goto cleanup;
11036 }
11037 }
11038
11039 for (i = 0; i < form->s->keys; i++) {
11040
11041 if (i != static_cast<uint>(primary_key_no)) {
11042
11043 if ((error = create_index(trx, form, flags,
11044 norm_name, i))) {
11045 goto cleanup;
11046 }
11047 }
11048 }
11049
11050 /* Cache all the FTS indexes on this table in the FTS specific
11051 structure. They are used for FTS indexed column update handling. */
11052 if (flags2 & DICT_TF2_FTS) {
11053 fts_t* fts = innobase_table->fts;
11054
11055 ut_a(fts != NULL);
11056
11057 dict_table_get_all_fts_indexes(innobase_table, fts->indexes);
11058 }
11059
11060 /*
11061 Adding compression dictionary <-> compressed table column links
11062 to the SYS_ZIP_DICT_COLS table.
11063 */
11064 ut_a(zip_dict_ids != 0);
11065 {
11066 dict_table_t* local_table = dict_table_open_on_name(
11067 norm_name, TRUE, FALSE, DICT_ERR_IGNORE_NONE);
11068
11069 ut_a(local_table);
11070 table_id_t table_id = local_table->id;
11071 dict_table_close(local_table, TRUE, FALSE);
11072 innobase_create_zip_dict_references(form,
11073 table_id, zip_dict_ids, trx);
11074 }
11075
11076 stmt = innobase_get_stmt(thd, &stmt_len);
11077
11078 if (stmt) {
11079 dberr_t err = row_table_add_foreign_constraints(
11080 trx, stmt, stmt_len, norm_name,
11081 create_info->options & HA_LEX_CREATE_TMP_TABLE);
11082
11083 switch (err) {
11084
11085 case DB_PARENT_NO_INDEX:
11086 push_warning_printf(
11087 thd, Sql_condition::WARN_LEVEL_WARN,
11088 HA_ERR_CANNOT_ADD_FOREIGN,
11089 "Create table '%s' with foreign key constraint"
11090 " failed. There is no index in the referenced"
11091 " table where the referenced columns appear"
11092 " as the first columns.\n", norm_name);
11093 break;
11094
11095 case DB_CHILD_NO_INDEX:
11096 push_warning_printf(
11097 thd, Sql_condition::WARN_LEVEL_WARN,
11098 HA_ERR_CANNOT_ADD_FOREIGN,
11099 "Create table '%s' with foreign key constraint"
11100 " failed. There is no index in the referencing"
11101 " table where referencing columns appear"
11102 " as the first columns.\n", norm_name);
11103 break;
11104 default:
11105 break;
11106 }
11107
11108 error = convert_error_code_to_mysql(err, flags, NULL);
11109
11110 if (error) {
11111 goto cleanup;
11112 }
11113 }
11114
11115 innobase_commit_low(trx);
11116
11117 row_mysql_unlock_data_dictionary(trx);
11118
11119 /* Flush the log to reduce probability that the .frm files and
11120 the InnoDB data dictionary get out-of-sync if the user runs
11121 with innodb_flush_log_at_trx_commit = 0 */
11122
11123 log_buffer_flush_to_disk();
11124
11125 innobase_table = dict_table_open_on_name(
11126 norm_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
11127
11128 DBUG_ASSERT(innobase_table != 0);
11129
11130 innobase_copy_frm_flags_from_create_info(innobase_table, create_info);
11131
11132 dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE);
11133
11134 if (innobase_table) {
11135 /* We update the highest file format in the system table
11136 space, if this table has higher file format setting. */
11137
11138 trx_sys_file_format_max_upgrade(
11139 (const char**) &innobase_file_format_max,
11140 dict_table_get_format(innobase_table));
11141 }
11142
11143 /* Load server stopword into FTS cache */
11144 if (flags2 & DICT_TF2_FTS) {
11145 if (!innobase_fts_load_stopword(innobase_table, NULL, thd)) {
11146 dict_table_close(innobase_table, FALSE, FALSE);
11147 srv_active_wake_master_thread();
11148 trx_free_for_mysql(trx);
11149 DBUG_RETURN(-1);
11150 }
11151 }
11152
11153 /* Note: We can't call update_thd() as prebuilt will not be
11154 setup at this stage and so we use thd. */
11155
11156 /* We need to copy the AUTOINC value from the old table if
11157 this is an ALTER|OPTIMIZE TABLE or CREATE INDEX because CREATE INDEX
11158 does a table copy too. If query was one of :
11159
11160 CREATE TABLE ...AUTO_INCREMENT = x; or
11161 ALTER TABLE...AUTO_INCREMENT = x; or
11162 OPTIMIZE TABLE t; or
11163 CREATE INDEX x on t(...);
11164
11165 Find out a table definition from the dictionary and get
11166 the current value of the auto increment field. Set a new
11167 value to the auto increment field if the value is greater
11168 than the maximum value in the column. */
11169
11170 if (((create_info->used_fields & HA_CREATE_USED_AUTO)
11171 || thd_sql_command(thd) == SQLCOM_ALTER_TABLE
11172 || thd_sql_command(thd) == SQLCOM_OPTIMIZE
11173 || thd_sql_command(thd) == SQLCOM_CREATE_INDEX)
11174 && create_info->auto_increment_value > 0) {
11175
11176 auto_inc_value = create_info->auto_increment_value;
11177
11178 dict_table_autoinc_lock(innobase_table);
11179 dict_table_autoinc_initialize(innobase_table, auto_inc_value);
11180 dict_table_autoinc_unlock(innobase_table);
11181 }
11182
11183 dict_table_close(innobase_table, FALSE, FALSE);
11184
11185 /* Tell the InnoDB server that there might be work for
11186 utility threads: */
11187
11188 srv_active_wake_master_thread();
11189
11190 trx_free_for_mysql(trx);
11191
11192 if (heap != 0)
11193 mem_heap_free(heap);
11194
11195 DBUG_RETURN(0);
11196
11197 cleanup:
11198 trx_rollback_for_mysql(trx);
11199
11200 row_mysql_unlock_data_dictionary(trx);
11201
11202 trx_free_for_mysql(trx);
11203
11204 if (heap != 0)
11205 mem_heap_free(heap);
11206
11207 DBUG_RETURN(error);
11208 }
11209
11210 /*****************************************************************//**
11211 Discards or imports an InnoDB tablespace.
11212 @return 0 == success, -1 == error */
11213 UNIV_INTERN
11214 int
discard_or_import_tablespace(my_bool discard)11215 ha_innobase::discard_or_import_tablespace(
11216 /*======================================*/
11217 my_bool discard) /*!< in: TRUE if discard, else import */
11218 {
11219 dberr_t err;
11220 dict_table_t* dict_table;
11221
11222 DBUG_ENTER("ha_innobase::discard_or_import_tablespace");
11223
11224 ut_a(prebuilt->trx);
11225 ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
11226 ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
11227
11228 if (high_level_read_only) {
11229 DBUG_RETURN(HA_ERR_TABLE_READONLY);
11230 }
11231
11232 if (UNIV_UNLIKELY(prebuilt->trx->fake_changes)) {
11233 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
11234 }
11235
11236 dict_table = prebuilt->table;
11237
11238 if (dict_table->space == TRX_SYS_SPACE) {
11239
11240 ib_senderrf(
11241 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
11242 ER_TABLE_IN_SYSTEM_TABLESPACE,
11243 table->s->table_name.str);
11244
11245 DBUG_RETURN(HA_ERR_TABLE_NEEDS_UPGRADE);
11246 }
11247
11248 trx_start_if_not_started(prebuilt->trx);
11249
11250 /* In case MySQL calls this in the middle of a SELECT query, release
11251 possible adaptive hash latch to avoid deadlocks of threads. */
11252 trx_search_latch_release_if_reserved(prebuilt->trx);
11253
11254 /* Obtain an exclusive lock on the table. */
11255 err = row_mysql_lock_table(
11256 prebuilt->trx, dict_table, LOCK_X,
11257 discard ? "setting table lock for DISCARD TABLESPACE"
11258 : "setting table lock for IMPORT TABLESPACE");
11259
11260 if (err != DB_SUCCESS) {
11261 /* unable to lock the table: do nothing */
11262 } else if (discard) {
11263
11264 /* Discarding an already discarded tablespace should be an
11265 idempotent operation. Also, if the .ibd file is missing the
11266 user may want to set the DISCARD flag in order to IMPORT
11267 a new tablespace. */
11268
11269 if (dict_table->ibd_file_missing) {
11270 ib_senderrf(
11271 prebuilt->trx->mysql_thd,
11272 IB_LOG_LEVEL_WARN, ER_TABLESPACE_MISSING,
11273 table->s->table_name.str);
11274 }
11275
11276 err = row_discard_tablespace_for_mysql(
11277 dict_table->name, prebuilt->trx);
11278
11279 } else if (!dict_table->ibd_file_missing) {
11280 /* Commit the transaction in order to
11281 release the table lock. */
11282 trx_commit_for_mysql(prebuilt->trx);
11283
11284 ib_senderrf(
11285 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
11286 ER_TABLESPACE_EXISTS, table->s->table_name.str);
11287
11288 DBUG_RETURN(HA_ERR_TABLE_EXIST);
11289 } else {
11290 err = row_import_for_mysql(dict_table, prebuilt);
11291
11292 if (err == DB_SUCCESS) {
11293
11294 if (table->found_next_number_field) {
11295 dict_table_autoinc_lock(dict_table);
11296 innobase_initialize_autoinc();
11297 dict_table_autoinc_unlock(dict_table);
11298 }
11299
11300 info(HA_STATUS_TIME
11301 | HA_STATUS_CONST
11302 | HA_STATUS_VARIABLE
11303 | HA_STATUS_AUTO);
11304 }
11305 }
11306
11307 /* Commit the transaction in order to release the table lock. */
11308 trx_commit_for_mysql(prebuilt->trx);
11309
11310 if (err == DB_SUCCESS && !discard
11311 && dict_stats_is_persistent_enabled(dict_table)) {
11312 dberr_t ret;
11313
11314 /* Adjust the persistent statistics. */
11315 ret = dict_stats_update(dict_table,
11316 DICT_STATS_RECALC_PERSISTENT);
11317
11318 if (ret != DB_SUCCESS) {
11319 push_warning_printf(
11320 ha_thd(),
11321 Sql_condition::WARN_LEVEL_WARN,
11322 ER_ALTER_INFO,
11323 "Error updating stats for table '%s'"
11324 " after table rebuild: %s",
11325 dict_table->name, ut_strerr(ret));
11326 }
11327 }
11328
11329 DBUG_RETURN(convert_error_code_to_mysql(err, dict_table->flags, NULL));
11330 }
11331
11332 /*****************************************************************//**
11333 Deletes all rows of an InnoDB table.
11334 @return error number */
11335 UNIV_INTERN
11336 int
truncate()11337 ha_innobase::truncate()
11338 /*===================*/
11339 {
11340 dberr_t err;
11341 int error;
11342
11343 DBUG_ENTER("ha_innobase::truncate");
11344
11345 if (high_level_read_only) {
11346 DBUG_RETURN(HA_ERR_TABLE_READONLY);
11347 }
11348
11349 /* Get the transaction associated with the current thd, or create one
11350 if not yet created, and update prebuilt->trx */
11351
11352 update_thd(ha_thd());
11353
11354 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
11355 DBUG_RETURN(HA_ERR_CRASHED);
11356 }
11357
11358 if (UNIV_UNLIKELY(prebuilt->trx->fake_changes)) {
11359 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
11360 }
11361
11362 if (!trx_is_started(prebuilt->trx)) {
11363 ++prebuilt->trx->will_lock;
11364 }
11365 /* Truncate the table in InnoDB */
11366
11367 err = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
11368
11369 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
11370 DBUG_RETURN(HA_ERR_CRASHED);
11371 }
11372
11373 switch (err) {
11374
11375 case DB_TABLESPACE_DELETED:
11376 case DB_TABLESPACE_NOT_FOUND:
11377 ib_senderrf(
11378 prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
11379 (err == DB_TABLESPACE_DELETED ?
11380 ER_TABLESPACE_DISCARDED : ER_TABLESPACE_MISSING),
11381 table->s->table_name.str);
11382 table->status = STATUS_NOT_FOUND;
11383 error = HA_ERR_NO_SUCH_TABLE;
11384 break;
11385
11386 default:
11387 error = convert_error_code_to_mysql(
11388 err, prebuilt->table->flags,
11389 prebuilt->trx->mysql_thd);
11390 table->status = STATUS_NOT_FOUND;
11391 break;
11392 }
11393 DBUG_RETURN(error);
11394 }
11395
11396 /*****************************************************************//**
11397 Drops a table from an InnoDB database. Before calling this function,
11398 MySQL calls innobase_commit to commit the transaction of the current user.
11399 Then the current user cannot have locks set on the table. Drop table
11400 operation inside InnoDB will remove all locks any user has on the table
11401 inside InnoDB.
11402 @return error number */
11403 UNIV_INTERN
11404 int
delete_table(const char * name)11405 ha_innobase::delete_table(
11406 /*======================*/
11407 const char* name) /*!< in: table name */
11408 {
11409 ulint name_len;
11410 dberr_t err;
11411 trx_t* parent_trx;
11412 trx_t* trx;
11413 THD* thd = ha_thd();
11414 char norm_name[FN_REFLEN];
11415
11416 DBUG_ENTER("ha_innobase::delete_table");
11417
11418 DBUG_EXECUTE_IF(
11419 "test_normalize_table_name_low",
11420 test_normalize_table_name_low();
11421 );
11422 DBUG_EXECUTE_IF(
11423 "test_ut_format_name",
11424 test_ut_format_name();
11425 );
11426
11427 /* Strangely, MySQL passes the table name without the '.frm'
11428 extension, in contrast to ::create */
11429 normalize_table_name(norm_name, name);
11430
11431 if (srv_read_only_mode
11432 || srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
11433 DBUG_RETURN(HA_ERR_TABLE_READONLY);
11434 } else if (row_is_magic_monitor_table(norm_name)
11435 && check_global_access(thd, PROCESS_ACL)) {
11436 DBUG_RETURN(HA_ERR_GENERIC);
11437 }
11438
11439 parent_trx = check_trx_exists(thd);
11440
11441 /* In case MySQL calls this in the middle of a SELECT query, release
11442 possible adaptive hash latch to avoid deadlocks of threads */
11443
11444 trx_search_latch_release_if_reserved(parent_trx);
11445
11446 trx = innobase_trx_allocate(thd);
11447
11448 if (UNIV_UNLIKELY(trx->fake_changes)) {
11449 innobase_commit_low(trx);
11450 trx_free_for_mysql(trx);
11451 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
11452 }
11453
11454 name_len = strlen(name);
11455
11456 ut_a(name_len < 1000);
11457
11458 /* Either the transaction is already flagged as a locking transaction
11459 or it hasn't been started yet. */
11460
11461 ut_a(!trx_is_started(trx) || trx->will_lock > 0);
11462
11463 /* We are doing a DDL operation. */
11464 ++trx->will_lock;
11465 trx->ddl = true;
11466
11467 /* Drop the table in InnoDB */
11468 err = row_drop_table_for_mysql(
11469 norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB);
11470
11471
11472 if (err == DB_TABLE_NOT_FOUND
11473 && innobase_get_lower_case_table_names() == 1) {
11474 char* is_part = NULL;
11475 #ifdef __WIN__
11476 is_part = strstr(norm_name, "#p#");
11477 #else
11478 is_part = strstr(norm_name, "#P#");
11479 #endif /* __WIN__ */
11480
11481 if (is_part) {
11482 char par_case_name[FN_REFLEN];
11483
11484 #ifndef __WIN__
11485 /* Check for the table using lower
11486 case name, including the partition
11487 separator "P" */
11488 strcpy(par_case_name, norm_name);
11489 innobase_casedn_str(par_case_name);
11490 #else
11491 /* On Windows platfrom, check
11492 whether there exists table name in
11493 system table whose name is
11494 not being normalized to lower case */
11495 normalize_table_name_low(
11496 par_case_name, name, FALSE);
11497 #endif
11498 err = row_drop_table_for_mysql(
11499 par_case_name, trx,
11500 thd_sql_command(thd) == SQLCOM_DROP_DB);
11501 }
11502 }
11503
11504 /* Flush the log to reduce probability that the .frm files and
11505 the InnoDB data dictionary get out-of-sync if the user runs
11506 with innodb_flush_log_at_trx_commit = 0 */
11507
11508 log_buffer_flush_to_disk();
11509
11510 innobase_commit_low(trx);
11511
11512 trx_free_for_mysql(trx);
11513
11514 DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL));
11515 }
11516
11517 /*****************************************************************//**
11518 Removes all tables in the named database inside InnoDB. */
11519 static
11520 void
innobase_drop_database(handlerton * hton,char * path)11521 innobase_drop_database(
11522 /*===================*/
11523 handlerton* hton, /*!< in: handlerton of Innodb */
11524 char* path) /*!< in: database path; inside InnoDB the name
11525 of the last directory in the path is used as
11526 the database name: for example, in
11527 'mysql/data/test' the database name is 'test' */
11528 {
11529 ulint len = 0;
11530 trx_t* trx;
11531 char* ptr;
11532 char* namebuf;
11533 THD* thd = current_thd;
11534
11535 /* Get the transaction associated with the current thd, or create one
11536 if not yet created */
11537
11538 DBUG_ASSERT(hton == innodb_hton_ptr);
11539
11540 if (srv_read_only_mode) {
11541 return;
11542 }
11543
11544 /* In the Windows plugin, thd = current_thd is always NULL */
11545 if (thd) {
11546 trx_t* parent_trx = check_trx_exists(thd);
11547
11548 /* In case MySQL calls this in the middle of a SELECT
11549 query, release possible adaptive hash latch to avoid
11550 deadlocks of threads */
11551
11552 trx_search_latch_release_if_reserved(parent_trx);
11553 }
11554
11555 ptr = strend(path) - 2;
11556
11557 while (ptr >= path && *ptr != '\\' && *ptr != '/') {
11558 ptr--;
11559 len++;
11560 }
11561
11562 ptr++;
11563 namebuf = (char*) my_malloc((uint) len + 2, MYF(0));
11564
11565 memcpy(namebuf, ptr, len);
11566 namebuf[len] = '/';
11567 namebuf[len + 1] = '\0';
11568 #ifdef __WIN__
11569 innobase_casedn_str(namebuf);
11570 #endif
11571 trx = innobase_trx_allocate(thd);
11572
11573 if (UNIV_UNLIKELY(trx->fake_changes)) {
11574 my_free(namebuf);
11575 innobase_commit_low(trx);
11576 trx_free_for_mysql(trx);
11577 return; /* ignore */
11578 }
11579
11580 /* Either the transaction is already flagged as a locking transaction
11581 or it hasn't been started yet. */
11582
11583 ut_a(!trx_is_started(trx) || trx->will_lock > 0);
11584
11585 /* We are doing a DDL operation. */
11586 ++trx->will_lock;
11587
11588 row_drop_database_for_mysql(namebuf, trx);
11589
11590 my_free(namebuf);
11591
11592 /* Flush the log to reduce probability that the .frm files and
11593 the InnoDB data dictionary get out-of-sync if the user runs
11594 with innodb_flush_log_at_trx_commit = 0 */
11595
11596 log_buffer_flush_to_disk();
11597
11598 innobase_commit_low(trx);
11599 trx_free_for_mysql(trx);
11600 }
11601
11602 /*********************************************************************//**
11603 Renames an InnoDB table.
11604 @return DB_SUCCESS or error code */
11605 static MY_ATTRIBUTE((nonnull, warn_unused_result))
11606 dberr_t
innobase_rename_table(THD * thd,trx_t * trx,const char * from,const char * to)11607 innobase_rename_table(
11608 /*==================*/
11609 THD* thd, /*!< Connection thread handle */
11610 trx_t* trx, /*!< in: transaction */
11611 const char* from, /*!< in: old name of the table */
11612 const char* to) /*!< in: new name of the table */
11613 {
11614 dberr_t error;
11615 char norm_to[FN_REFLEN];
11616 char norm_from[FN_REFLEN];
11617
11618 DBUG_ENTER("innobase_rename_table");
11619 DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX);
11620
11621 ut_ad(!srv_read_only_mode);
11622
11623 normalize_table_name(norm_to, to);
11624 normalize_table_name(norm_from, from);
11625
11626 DEBUG_SYNC_C("innodb_rename_table_ready");
11627
11628 trx_start_if_not_started(trx);
11629
11630 /* Serialize data dictionary operations with dictionary mutex:
11631 no deadlocks can occur then in these operations. */
11632
11633 row_mysql_lock_data_dictionary(trx);
11634
11635 dict_table_t* table = NULL;
11636 table = dict_table_open_on_name(norm_from, TRUE, FALSE,
11637 DICT_ERR_IGNORE_NONE);
11638
11639 /* Since DICT_BG_YIELD has sleep for 250 milliseconds,
11640 Convert lock_wait_timeout unit from second to 250 milliseconds */
11641 long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4;
11642 if (table != NULL) {
11643 for (dict_index_t* index = dict_table_get_first_index(table);
11644 index != NULL;
11645 index = dict_table_get_next_index(index)) {
11646
11647 if (index->type & DICT_FTS) {
11648 /* Found */
11649 while (index->index_fts_syncing
11650 && !trx_is_interrupted(trx)
11651 && (lock_wait_timeout--) > 0) {
11652 DICT_BG_YIELD(trx);
11653 }
11654 }
11655 }
11656 dict_table_close(table, TRUE, FALSE);
11657 }
11658
11659 /* FTS sync is in progress. We shall timeout this operation */
11660 if (lock_wait_timeout < 0) {
11661 error = DB_LOCK_WAIT_TIMEOUT;
11662 row_mysql_unlock_data_dictionary(trx);
11663 DBUG_RETURN(error);
11664 }
11665
11666 /* Transaction must be flagged as a locking transaction or it hasn't
11667 been started yet. */
11668
11669 ut_a(trx->will_lock > 0);
11670
11671 error = row_rename_table_for_mysql(
11672 norm_from, norm_to, trx, TRUE);
11673
11674 if (error != DB_SUCCESS) {
11675 if (error == DB_TABLE_NOT_FOUND
11676 && innobase_get_lower_case_table_names() == 1) {
11677 char* is_part = NULL;
11678 #ifdef __WIN__
11679 is_part = strstr(norm_from, "#p#");
11680 #else
11681 is_part = strstr(norm_from, "#P#");
11682 #endif /* __WIN__ */
11683
11684 if (is_part) {
11685 char par_case_name[FN_REFLEN];
11686 #ifndef __WIN__
11687 /* Check for the table using lower
11688 case name, including the partition
11689 separator "P" */
11690 strcpy(par_case_name, norm_from);
11691 innobase_casedn_str(par_case_name);
11692 #else
11693 /* On Windows platfrom, check
11694 whether there exists table name in
11695 system table whose name is
11696 not being normalized to lower case */
11697 normalize_table_name_low(
11698 par_case_name, from, FALSE);
11699 #endif
11700 trx_start_if_not_started(trx);
11701 error = row_rename_table_for_mysql(
11702 par_case_name, norm_to, trx, TRUE);
11703 }
11704 }
11705
11706 if (error == DB_SUCCESS) {
11707 #ifndef __WIN__
11708 sql_print_warning("Rename partition table %s "
11709 "succeeds after converting to lower "
11710 "case. The table may have "
11711 "been moved from a case "
11712 "in-sensitive file system.\n",
11713 norm_from);
11714 #else
11715 sql_print_warning("Rename partition table %s "
11716 "succeeds after skipping the step to "
11717 "lower case the table name. "
11718 "The table may have been "
11719 "moved from a case sensitive "
11720 "file system.\n",
11721 norm_from);
11722 #endif /* __WIN__ */
11723 }
11724 }
11725
11726 row_mysql_unlock_data_dictionary(trx);
11727
11728 /* Flush the log to reduce probability that the .frm
11729 files and the InnoDB data dictionary get out-of-sync
11730 if the user runs with innodb_flush_log_at_trx_commit = 0 */
11731
11732 log_buffer_flush_to_disk();
11733
11734 DBUG_RETURN(error);
11735 }
11736
11737 /*********************************************************************//**
11738 Renames an InnoDB table.
11739 @return 0 or error code */
11740 UNIV_INTERN
11741 int
rename_table(const char * from,const char * to)11742 ha_innobase::rename_table(
11743 /*======================*/
11744 const char* from, /*!< in: old name of the table */
11745 const char* to) /*!< in: new name of the table */
11746 {
11747 trx_t* trx;
11748 dberr_t error;
11749 trx_t* parent_trx;
11750 THD* thd = ha_thd();
11751
11752 DBUG_ENTER("ha_innobase::rename_table");
11753
11754 if (high_level_read_only) {
11755 ib_senderrf(thd, IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
11756 DBUG_RETURN(HA_ERR_TABLE_READONLY);
11757 }
11758
11759 /* Get the transaction associated with the current thd, or create one
11760 if not yet created */
11761
11762 parent_trx = check_trx_exists(thd);
11763
11764 /* In case MySQL calls this in the middle of a SELECT query, release
11765 possible adaptive hash latch to avoid deadlocks of threads */
11766
11767 trx_search_latch_release_if_reserved(parent_trx);
11768
11769 trx = innobase_trx_allocate(thd);
11770 if (UNIV_UNLIKELY(trx->fake_changes)) {
11771 innobase_commit_low(trx);
11772 trx_free_for_mysql(trx);
11773 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
11774 }
11775
11776 /* We are doing a DDL operation. */
11777 ++trx->will_lock;
11778 trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
11779
11780 error = innobase_rename_table(thd, trx, from, to);
11781
11782 DEBUG_SYNC(thd, "after_innobase_rename_table");
11783
11784 innobase_commit_low(trx);
11785 trx_free_for_mysql(trx);
11786
11787 if (error == DB_SUCCESS) {
11788 char norm_from[MAX_FULL_NAME_LEN];
11789 char norm_to[MAX_FULL_NAME_LEN];
11790 char errstr[512];
11791 dberr_t ret;
11792
11793 normalize_table_name(norm_from, from);
11794 normalize_table_name(norm_to, to);
11795
11796 ret = dict_stats_rename_table(norm_from, norm_to,
11797 errstr, sizeof(errstr));
11798
11799 if (ret != DB_SUCCESS) {
11800 ut_print_timestamp(stderr);
11801 fprintf(stderr, " InnoDB: %s\n", errstr);
11802
11803 push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
11804 ER_LOCK_WAIT_TIMEOUT, errstr);
11805 }
11806 }
11807
11808 /* Add a special case to handle the Duplicated Key error
11809 and return DB_ERROR instead.
11810 This is to avoid a possible SIGSEGV error from mysql error
11811 handling code. Currently, mysql handles the Duplicated Key
11812 error by re-entering the storage layer and getting dup key
11813 info by calling get_dup_key(). This operation requires a valid
11814 table handle ('row_prebuilt_t' structure) which could no
11815 longer be available in the error handling stage. The suggested
11816 solution is to report a 'table exists' error message (since
11817 the dup key error here is due to an existing table whose name
11818 is the one we are trying to rename to) and return the generic
11819 error code. */
11820 if (error == DB_DUPLICATE_KEY) {
11821 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to);
11822
11823 error = DB_ERROR;
11824 }
11825
11826 else if (error == DB_LOCK_WAIT_TIMEOUT) {
11827 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to);
11828
11829 error = DB_LOCK_WAIT;
11830 }
11831
11832 DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
11833 }
11834
11835 /*********************************************************************//**
11836 Estimates the number of index records in a range.
11837 @return estimated number of rows */
11838 UNIV_INTERN
11839 ha_rows
records_in_range(uint keynr,key_range * min_key,key_range * max_key)11840 ha_innobase::records_in_range(
11841 /*==========================*/
11842 uint keynr, /*!< in: index number */
11843 key_range *min_key, /*!< in: start key value of the
11844 range, may also be 0 */
11845 key_range *max_key) /*!< in: range end key val, may
11846 also be 0 */
11847 {
11848 KEY* key;
11849 dict_index_t* index;
11850 dtuple_t* range_start;
11851 dtuple_t* range_end;
11852 ib_int64_t n_rows;
11853 ulint mode1;
11854 ulint mode2;
11855 mem_heap_t* heap;
11856
11857 DBUG_ENTER("records_in_range");
11858
11859 ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
11860
11861 prebuilt->trx->op_info = (char*)"estimating records in index range";
11862
11863 /* In case MySQL calls this in the middle of a SELECT query, release
11864 possible adaptive hash latch to avoid deadlocks of threads */
11865
11866 trx_search_latch_release_if_reserved(prebuilt->trx);
11867
11868 active_index = keynr;
11869
11870 key = table->key_info + active_index;
11871
11872 index = innobase_get_index(keynr);
11873
11874 /* There exists possibility of not being able to find requested
11875 index due to inconsistency between MySQL and InoDB dictionary info.
11876 Necessary message should have been printed in innobase_get_index() */
11877 if (dict_table_is_discarded(prebuilt->table)) {
11878 n_rows = HA_POS_ERROR;
11879 goto func_exit;
11880 }
11881 if (UNIV_UNLIKELY(!index)) {
11882 n_rows = HA_POS_ERROR;
11883 goto func_exit;
11884 }
11885 if (dict_index_is_corrupted(index)) {
11886 n_rows = HA_ERR_INDEX_CORRUPT;
11887 goto func_exit;
11888 }
11889 if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
11890 n_rows = HA_ERR_TABLE_DEF_CHANGED;
11891 goto func_exit;
11892 }
11893
11894 heap = mem_heap_create(2 * (key->actual_key_parts * sizeof(dfield_t)
11895 + sizeof(dtuple_t)));
11896
11897 range_start = dtuple_create(heap, key->actual_key_parts);
11898 dict_index_copy_types(range_start, index, key->actual_key_parts);
11899
11900 range_end = dtuple_create(heap, key->actual_key_parts);
11901 dict_index_copy_types(range_end, index, key->actual_key_parts);
11902
11903 row_sel_convert_mysql_key_to_innobase(
11904 range_start,
11905 prebuilt->srch_key_val1,
11906 prebuilt->srch_key_val_len,
11907 index,
11908 (byte*) (min_key ? min_key->key :
11909 (const uchar*) 0),
11910 (ulint) (min_key ? min_key->length : 0),
11911 prebuilt->trx);
11912 DBUG_ASSERT(min_key
11913 ? range_start->n_fields > 0
11914 : range_start->n_fields == 0);
11915
11916 row_sel_convert_mysql_key_to_innobase(
11917 range_end,
11918 prebuilt->srch_key_val2,
11919 prebuilt->srch_key_val_len,
11920 index,
11921 (byte*) (max_key ? max_key->key :
11922 (const uchar*) 0),
11923 (ulint) (max_key ? max_key->length : 0),
11924 prebuilt->trx);
11925 DBUG_ASSERT(max_key
11926 ? range_end->n_fields > 0
11927 : range_end->n_fields == 0);
11928
11929 mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
11930 HA_READ_KEY_EXACT);
11931 mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
11932 HA_READ_KEY_EXACT);
11933
11934 if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
11935
11936 n_rows = btr_estimate_n_rows_in_range(index, range_start,
11937 mode1, range_end,
11938 mode2);
11939 } else {
11940
11941 n_rows = HA_POS_ERROR;
11942 }
11943
11944 mem_heap_free(heap);
11945
11946 func_exit:
11947
11948 prebuilt->trx->op_info = (char*)"";
11949
11950 /* The MySQL optimizer seems to believe an estimate of 0 rows is
11951 always accurate and may return the result 'Empty set' based on that.
11952 The accuracy is not guaranteed, and even if it were, for a locking
11953 read we should anyway perform the search to set the next-key lock.
11954 Add 1 to the value to make sure MySQL does not make the assumption! */
11955
11956 if (n_rows == 0) {
11957 n_rows = 1;
11958 }
11959
11960 DBUG_RETURN((ha_rows) n_rows);
11961 }
11962
11963 /*********************************************************************//**
11964 Gives an UPPER BOUND to the number of rows in a table. This is used in
11965 filesort.cc.
11966 @return upper bound of rows */
11967 UNIV_INTERN
11968 ha_rows
estimate_rows_upper_bound()11969 ha_innobase::estimate_rows_upper_bound()
11970 /*====================================*/
11971 {
11972 const dict_index_t* index;
11973 ulonglong estimate;
11974 ulonglong local_data_file_length;
11975 ulint stat_n_leaf_pages;
11976
11977 DBUG_ENTER("estimate_rows_upper_bound");
11978
11979 /* We do not know if MySQL can call this function before calling
11980 external_lock(). To be safe, update the thd of the current table
11981 handle. */
11982
11983 update_thd(ha_thd());
11984
11985 prebuilt->trx->op_info = "calculating upper bound for table rows";
11986
11987 /* In case MySQL calls this in the middle of a SELECT query, release
11988 possible adaptive hash latch to avoid deadlocks of threads */
11989
11990 trx_search_latch_release_if_reserved(prebuilt->trx);
11991
11992 index = dict_table_get_first_index(prebuilt->table);
11993
11994 stat_n_leaf_pages = index->stat_n_leaf_pages;
11995
11996 ut_a(stat_n_leaf_pages > 0);
11997
11998 local_data_file_length =
11999 ((ulonglong) stat_n_leaf_pages) * UNIV_PAGE_SIZE;
12000
12001 /* Calculate a minimum length for a clustered index record and from
12002 that an upper bound for the number of rows. Since we only calculate
12003 new statistics in row0mysql.cc when a table has grown by a threshold
12004 factor, we must add a safety factor 2 in front of the formula below. */
12005
12006 estimate = 2 * local_data_file_length
12007 / dict_index_calc_min_rec_len(index);
12008
12009 prebuilt->trx->op_info = "";
12010
12011 /* Set num_rows less than MERGEBUFF to simulate the case where we do
12012 not have enough space to merge the externally sorted file blocks. */
12013 DBUG_EXECUTE_IF("set_num_rows_lt_MERGEBUFF",
12014 estimate = 2;
12015 DBUG_SET("-d,set_num_rows_lt_MERGEBUFF");
12016 );
12017
12018 DBUG_RETURN((ha_rows) estimate);
12019 }
12020
12021 /*********************************************************************//**
12022 How many seeks it will take to read through the table. This is to be
12023 comparable to the number returned by records_in_range so that we can
12024 decide if we should scan the table or use keys.
12025 @return estimated time measured in disk seeks */
12026 UNIV_INTERN
12027 double
scan_time()12028 ha_innobase::scan_time()
12029 /*====================*/
12030 {
12031 /* Since MySQL seems to favor table scans too much over index
12032 searches, we pretend that a sequential read takes the same time
12033 as a random disk read, that is, we do not divide the following
12034 by 10, which would be physically realistic. */
12035
12036 /* The locking below is disabled for performance reasons. Without
12037 it we could end up returning uninitialized value to the caller,
12038 which in the worst case could make some query plan go bogus or
12039 issue a Valgrind warning. */
12040 #if 0
12041 /* avoid potential lock order violation with dict_table_stats_lock()
12042 below */
12043 update_thd(ha_thd());
12044 trx_search_latch_release_if_reserved(prebuilt->trx);
12045 #endif
12046
12047 ulint stat_clustered_index_size;
12048
12049 #if 0
12050 dict_table_stats_lock(prebuilt->table, RW_S_LATCH);
12051 #endif
12052
12053 ut_a(prebuilt->table->stat_initialized);
12054
12055 stat_clustered_index_size = prebuilt->table->stat_clustered_index_size;
12056
12057 #if 0
12058 dict_table_stats_unlock(prebuilt->table, RW_S_LATCH);
12059 #endif
12060
12061 return((double) stat_clustered_index_size);
12062 }
12063
12064 /******************************************************************//**
12065 Calculate the time it takes to read a set of ranges through an index
12066 This enables us to optimise reads for clustered indexes.
12067 @return estimated time measured in disk seeks */
12068 UNIV_INTERN
12069 double
read_time(uint index,uint ranges,ha_rows rows)12070 ha_innobase::read_time(
12071 /*===================*/
12072 uint index, /*!< in: key number */
12073 uint ranges, /*!< in: how many ranges */
12074 ha_rows rows) /*!< in: estimated number of rows in the ranges */
12075 {
12076 ha_rows total_rows;
12077 double time_for_scan;
12078
12079 if (index != table->s->primary_key) {
12080 /* Not clustered */
12081 return(handler::read_time(index, ranges, rows));
12082 }
12083
12084 if (rows <= 2) {
12085
12086 return((double) rows);
12087 }
12088
12089 /* Assume that the read time is proportional to the scan time for all
12090 rows + at most one seek per range. */
12091
12092 time_for_scan = scan_time();
12093
12094 if ((total_rows = estimate_rows_upper_bound()) < rows) {
12095
12096 return(time_for_scan);
12097 }
12098
12099 return(ranges + (double) rows / (double) total_rows * time_for_scan);
12100 }
12101
12102 /******************************************************************//**
12103 Return the size of the InnoDB memory buffer. */
12104 UNIV_INTERN
12105 longlong
get_memory_buffer_size() const12106 ha_innobase::get_memory_buffer_size() const
12107 /*=======================================*/
12108 {
12109 return(innobase_buffer_pool_size);
12110 }
12111
12112 /*********************************************************************//**
12113 Calculates the key number used inside MySQL for an Innobase index. We will
12114 first check the "index translation table" for a match of the index to get
12115 the index number. If there does not exist an "index translation table",
12116 or not able to find the index in the translation table, then we will fall back
12117 to the traditional way of looping through dict_index_t list to find a
12118 match. In this case, we have to take into account if we generated a
12119 default clustered index for the table
12120 @return the key number used inside MySQL */
12121 static
12122 int
innobase_get_mysql_key_number_for_index(INNOBASE_SHARE * share,const TABLE * table,dict_table_t * ib_table,const dict_index_t * index)12123 innobase_get_mysql_key_number_for_index(
12124 /*====================================*/
12125 INNOBASE_SHARE* share, /*!< in: share structure for index
12126 translation table. */
12127 const TABLE* table, /*!< in: table in MySQL data
12128 dictionary */
12129 dict_table_t* ib_table,/*!< in: table in Innodb data
12130 dictionary */
12131 const dict_index_t* index) /*!< in: index */
12132 {
12133 const dict_index_t* ind;
12134 unsigned int i;
12135
12136 ut_a(index);
12137
12138 /* If index does not belong to the table object of share structure
12139 (ib_table comes from the share structure) search the index->table
12140 object instead */
12141 if (index->table != ib_table) {
12142 i = 0;
12143 ind = dict_table_get_first_index(index->table);
12144
12145 while (index != ind) {
12146 ind = dict_table_get_next_index(ind);
12147 i++;
12148 }
12149
12150 if (row_table_got_default_clust_index(index->table)) {
12151 ut_a(i > 0);
12152 i--;
12153 }
12154
12155 return(i);
12156 }
12157
12158 /* If index translation table exists, we will first check
12159 the index through index translation table for a match. */
12160 if (share->idx_trans_tbl.index_mapping) {
12161 for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
12162 if (share->idx_trans_tbl.index_mapping[i] == index) {
12163 return(i);
12164 }
12165 }
12166
12167 /* Print an error message if we cannot find the index
12168 in the "index translation table". */
12169 if (*index->name != TEMP_INDEX_PREFIX) {
12170 sql_print_error("Cannot find index %s in InnoDB index "
12171 "translation table.", index->name);
12172 }
12173 }
12174
12175 /* If we do not have an "index translation table", or not able
12176 to find the index in the translation table, we'll directly find
12177 matching index with information from mysql TABLE structure and
12178 InnoDB dict_index_t list */
12179 for (i = 0; i < table->s->keys; i++) {
12180 ind = dict_table_get_index_on_name(
12181 ib_table, table->key_info[i].name);
12182
12183 if (index == ind) {
12184 return(i);
12185 }
12186 }
12187
12188 /* Loop through each index of the table and lock them */
12189 for (ind = dict_table_get_first_index(ib_table);
12190 ind != NULL;
12191 ind = dict_table_get_next_index(ind)) {
12192 if (index == ind) {
12193 /* Temp index is internal to InnoDB, that is
12194 not present in the MySQL index list, so no
12195 need to print such mismatch warning. */
12196 if (*(index->name) != TEMP_INDEX_PREFIX) {
12197 sql_print_warning(
12198 "Find index %s in InnoDB index list "
12199 "but not its MySQL index number "
12200 "It could be an InnoDB internal index.",
12201 index->name);
12202 }
12203 return(-1);
12204 }
12205 }
12206
12207 ut_error;
12208
12209 return(-1);
12210 }
12211
12212 /*********************************************************************//**
12213 Calculate Record Per Key value. Need to exclude the NULL value if
12214 innodb_stats_method is set to "nulls_ignored"
12215 @return estimated record per key value */
12216 static
12217 ha_rows
innodb_rec_per_key(dict_index_t * index,ulint i,ha_rows records)12218 innodb_rec_per_key(
12219 /*===============*/
12220 dict_index_t* index, /*!< in: dict_index_t structure */
12221 ulint i, /*!< in: the column we are
12222 calculating rec per key */
12223 ha_rows records) /*!< in: estimated total records */
12224 {
12225 ha_rows rec_per_key;
12226 ib_uint64_t n_diff;
12227
12228 ut_a(index->table->stat_initialized);
12229
12230 ut_ad(i < dict_index_get_n_unique(index));
12231
12232 n_diff = index->stat_n_diff_key_vals[i];
12233
12234 if (n_diff == 0) {
12235
12236 rec_per_key = records;
12237 } else if (srv_innodb_stats_method == SRV_STATS_NULLS_IGNORED) {
12238 ib_uint64_t n_null;
12239 ib_uint64_t n_non_null;
12240
12241 n_non_null = index->stat_n_non_null_key_vals[i];
12242
12243 /* In theory, index->stat_n_non_null_key_vals[i]
12244 should always be less than the number of records.
12245 Since this is statistics value, the value could
12246 have slight discrepancy. But we will make sure
12247 the number of null values is not a negative number. */
12248 if (records < n_non_null) {
12249 n_null = 0;
12250 } else {
12251 n_null = records - n_non_null;
12252 }
12253
12254 /* If the number of NULL values is the same as or
12255 large than that of the distinct values, we could
12256 consider that the table consists mostly of NULL value.
12257 Set rec_per_key to 1. */
12258 if (n_diff <= n_null) {
12259 rec_per_key = 1;
12260 } else {
12261 /* Need to exclude rows with NULL values from
12262 rec_per_key calculation */
12263 rec_per_key = (ha_rows)
12264 ((records - n_null) / (n_diff - n_null));
12265 }
12266 } else {
12267 DEBUG_SYNC_C("after_checking_for_0");
12268 rec_per_key = (ha_rows) (records / n_diff);
12269 }
12270
12271 return(rec_per_key);
12272 }
12273
12274 /*********************************************************************//**
12275 Returns statistics information of the table to the MySQL interpreter,
12276 in various fields of the handle object.
12277 @return HA_ERR_* error code or 0 */
12278 UNIV_INTERN
12279 int
info_low(uint flag,bool is_analyze)12280 ha_innobase::info_low(
12281 /*==================*/
12282 uint flag, /*!< in: what information is requested */
12283 bool is_analyze)
12284 {
12285 dict_table_t* ib_table;
12286 ha_rows rec_per_key;
12287 ib_uint64_t n_rows;
12288 os_file_stat_t stat_info;
12289
12290 DBUG_ENTER("info");
12291
12292 /* If we are forcing recovery at a high level, we will suppress
12293 statistics calculation on tables, because that may crash the
12294 server if an index is badly corrupted. */
12295
12296 /* We do not know if MySQL can call this function before calling
12297 external_lock(). To be safe, update the thd of the current table
12298 handle. */
12299
12300 update_thd(ha_thd());
12301
12302 /* In case MySQL calls this in the middle of a SELECT query, release
12303 possible adaptive hash latch to avoid deadlocks of threads */
12304
12305 prebuilt->trx->op_info = (char*)"returning various info to MySQL";
12306
12307 trx_search_latch_release_if_reserved(prebuilt->trx);
12308
12309 ib_table = prebuilt->table;
12310 DBUG_ASSERT(ib_table->n_ref_count > 0);
12311
12312 if (flag & HA_STATUS_TIME) {
12313 if (is_analyze || innobase_stats_on_metadata) {
12314
12315 dict_stats_upd_option_t opt;
12316 dberr_t ret;
12317
12318 prebuilt->trx->op_info = "updating table statistics";
12319
12320 if (dict_stats_is_persistent_enabled(ib_table)) {
12321
12322 if (is_analyze) {
12323
12324 /* If this table is already queued for
12325 background analyze, remove it from the
12326 queue as we are about to do the same */
12327 if (!srv_read_only_mode) {
12328
12329 dict_mutex_enter_for_mysql();
12330 dict_stats_recalc_pool_del(
12331 ib_table);
12332 dict_mutex_exit_for_mysql();
12333 }
12334
12335 opt = DICT_STATS_RECALC_PERSISTENT;
12336 } else {
12337 /* This is e.g. 'SHOW INDEXES', fetch
12338 the persistent stats from disk. */
12339 opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY;
12340 }
12341 } else {
12342 opt = DICT_STATS_RECALC_TRANSIENT;
12343 }
12344
12345 ut_ad(!mutex_own(&dict_sys->mutex));
12346 ret = dict_stats_update(ib_table, opt);
12347
12348 if (ret != DB_SUCCESS) {
12349 prebuilt->trx->op_info = "";
12350 DBUG_RETURN(HA_ERR_GENERIC);
12351 }
12352
12353 prebuilt->trx->op_info =
12354 "returning various info to MySQL";
12355 }
12356
12357 }
12358
12359 if (flag & HA_STATUS_VARIABLE) {
12360
12361 ulint page_size;
12362 ulint stat_clustered_index_size;
12363 ulint stat_sum_of_other_index_sizes;
12364
12365 if (!(flag & HA_STATUS_NO_LOCK)) {
12366 dict_table_stats_lock(ib_table, RW_S_LATCH);
12367 }
12368
12369 ut_a(ib_table->stat_initialized);
12370
12371 n_rows = ib_table->stat_n_rows;
12372
12373 stat_clustered_index_size
12374 = ib_table->stat_clustered_index_size;
12375
12376 stat_sum_of_other_index_sizes
12377 = ib_table->stat_sum_of_other_index_sizes;
12378
12379 if (!(flag & HA_STATUS_NO_LOCK)) {
12380 dict_table_stats_unlock(ib_table, RW_S_LATCH);
12381 }
12382
12383 /*
12384 The MySQL optimizer seems to assume in a left join that n_rows
12385 is an accurate estimate if it is zero. Of course, it is not,
12386 since we do not have any locks on the rows yet at this phase.
12387 Since SHOW TABLE STATUS seems to call this function with the
12388 HA_STATUS_TIME flag set, while the left join optimizer does not
12389 set that flag, we add one to a zero value if the flag is not
12390 set. That way SHOW TABLE STATUS will show the best estimate,
12391 while the optimizer never sees the table empty. */
12392
12393 if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
12394 n_rows++;
12395 }
12396
12397 /* Fix bug#40386: Not flushing query cache after truncate.
12398 n_rows can not be 0 unless the table is empty, set to 1
12399 instead. The original problem of bug#29507 is actually
12400 fixed in the server code. */
12401 if (thd_sql_command(user_thd) == SQLCOM_TRUNCATE) {
12402
12403 n_rows = 1;
12404
12405 /* We need to reset the prebuilt value too, otherwise
12406 checks for values greater than the last value written
12407 to the table will fail and the autoinc counter will
12408 not be updated. This will force write_row() into
12409 attempting an update of the table's AUTOINC counter. */
12410
12411 prebuilt->autoinc_last_value = 0;
12412 }
12413
12414 page_size = dict_table_zip_size(ib_table);
12415 if (page_size == 0) {
12416 page_size = UNIV_PAGE_SIZE;
12417 }
12418
12419 stats.records = (ha_rows) n_rows;
12420 stats.deleted = 0;
12421 stats.data_file_length
12422 = ((ulonglong) stat_clustered_index_size)
12423 * page_size;
12424 stats.index_file_length
12425 = ((ulonglong) stat_sum_of_other_index_sizes)
12426 * page_size;
12427
12428 /* Since fsp_get_available_space_in_free_extents() is
12429 acquiring latches inside InnoDB, we do not call it if we
12430 are asked by MySQL to avoid locking. Another reason to
12431 avoid the call is that it uses quite a lot of CPU.
12432 See Bug#38185. */
12433 if (flag & HA_STATUS_NO_LOCK
12434 || !(flag & HA_STATUS_VARIABLE_EXTRA)) {
12435 /* We do not update delete_length if no
12436 locking is requested so the "old" value can
12437 remain. delete_length is initialized to 0 in
12438 the ha_statistics' constructor. Also we only
12439 need delete_length to be set when
12440 HA_STATUS_VARIABLE_EXTRA is set */
12441 } else if (UNIV_UNLIKELY
12442 (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
12443 /* Avoid accessing the tablespace if
12444 innodb_crash_recovery is set to a high value. */
12445 stats.delete_length = 0;
12446 } else {
12447 ullint avail_space;
12448
12449 avail_space = fsp_get_available_space_in_free_extents(
12450 ib_table->space);
12451
12452 if (avail_space == ULLINT_UNDEFINED) {
12453 THD* thd;
12454 char errbuf[MYSYS_STRERROR_SIZE];
12455
12456 thd = ha_thd();
12457
12458 push_warning_printf(
12459 thd,
12460 Sql_condition::WARN_LEVEL_WARN,
12461 ER_CANT_GET_STAT,
12462 "InnoDB: Trying to get the free "
12463 "space for table %s but its "
12464 "tablespace has been discarded or "
12465 "the .ibd file is missing. Setting "
12466 "the free space to zero. "
12467 "(errno: %d - %s)",
12468 ib_table->name, errno,
12469 my_strerror(errbuf, sizeof(errbuf),
12470 errno));
12471
12472 stats.delete_length = 0;
12473 } else {
12474 stats.delete_length = avail_space * 1024;
12475 }
12476 }
12477
12478 stats.check_time = 0;
12479 stats.mrr_length_per_rec = ref_length + sizeof(void*);
12480
12481 if (stats.records == 0) {
12482 stats.mean_rec_length = 0;
12483 } else {
12484 stats.mean_rec_length = (ulong)
12485 (stats.data_file_length / stats.records);
12486 }
12487 }
12488
12489 if (flag & HA_STATUS_CONST) {
12490 ulong i;
12491 char path[FN_REFLEN];
12492 /* Verify the number of index in InnoDB and MySQL
12493 matches up. If prebuilt->clust_index_was_generated
12494 holds, InnoDB defines GEN_CLUST_INDEX internally */
12495 ulint num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes)
12496 - prebuilt->clust_index_was_generated;
12497 if (table->s->keys < num_innodb_index) {
12498 /* If there are too many indexes defined
12499 inside InnoDB, ignore those that are being
12500 created, because MySQL will only consider
12501 the fully built indexes here. */
12502
12503 for (const dict_index_t* index
12504 = UT_LIST_GET_FIRST(ib_table->indexes);
12505 index != NULL;
12506 index = UT_LIST_GET_NEXT(indexes, index)) {
12507
12508 /* First, online index creation is
12509 completed inside InnoDB, and then
12510 MySQL attempts to upgrade the
12511 meta-data lock so that it can rebuild
12512 the .frm file. If we get here in that
12513 time frame, dict_index_is_online_ddl()
12514 would not hold and the index would
12515 still not be included in TABLE_SHARE. */
12516 if (*index->name == TEMP_INDEX_PREFIX) {
12517 num_innodb_index--;
12518 }
12519 }
12520
12521 if (table->s->keys < num_innodb_index
12522 && innobase_fts_check_doc_id_index(
12523 ib_table, NULL, NULL)
12524 == FTS_EXIST_DOC_ID_INDEX) {
12525 num_innodb_index--;
12526 }
12527 }
12528
12529 if (table->s->keys != num_innodb_index) {
12530 sql_print_error("InnoDB: Table %s contains %lu "
12531 "indexes inside InnoDB, which "
12532 "is different from the number of "
12533 "indexes %u defined in the MySQL ",
12534 ib_table->name, num_innodb_index,
12535 table->s->keys);
12536 }
12537
12538 if (!(flag & HA_STATUS_NO_LOCK)) {
12539 dict_table_stats_lock(ib_table, RW_S_LATCH);
12540 }
12541
12542 ut_a(ib_table->stat_initialized);
12543
12544 for (i = 0; i < table->s->keys; i++) {
12545 ulong j;
12546 /* We could get index quickly through internal
12547 index mapping with the index translation table.
12548 The identity of index (match up index name with
12549 that of table->key_info[i]) is already verified in
12550 innobase_get_index(). */
12551 dict_index_t* index = innobase_get_index(i);
12552
12553 if (index == NULL) {
12554 sql_print_error("Table %s contains fewer "
12555 "indexes inside InnoDB than "
12556 "are defined in the MySQL "
12557 ".frm file. Have you mixed up "
12558 ".frm files from different "
12559 "installations? See "
12560 REFMAN
12561 "innodb-troubleshooting.html\n",
12562 ib_table->name);
12563 break;
12564 }
12565
12566 for (j = 0; j < table->key_info[i].actual_key_parts; j++) {
12567
12568 if (table->key_info[i].flags & HA_FULLTEXT) {
12569 /* The whole concept has no validity
12570 for FTS indexes. */
12571 table->key_info[i].rec_per_key[j] = 1;
12572 continue;
12573 }
12574
12575 if (j + 1 > index->n_uniq) {
12576 sql_print_error(
12577 "Index %s of %s has %lu columns"
12578 " unique inside InnoDB, but "
12579 "MySQL is asking statistics for"
12580 " %lu columns. Have you mixed "
12581 "up .frm files from different "
12582 "installations? "
12583 "See " REFMAN
12584 "innodb-troubleshooting.html\n",
12585 index->name,
12586 ib_table->name,
12587 (unsigned long)
12588 index->n_uniq, j + 1);
12589 break;
12590 }
12591
12592 rec_per_key = innodb_rec_per_key(
12593 index, j, stats.records);
12594
12595 /* Since MySQL seems to favor table scans
12596 too much over index searches, we pretend
12597 index selectivity is 2 times better than
12598 our estimate: */
12599
12600 rec_per_key = rec_per_key / 2;
12601
12602 if (rec_per_key == 0) {
12603 rec_per_key = 1;
12604 }
12605
12606 table->key_info[i].rec_per_key[j] =
12607 rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
12608 (ulong) rec_per_key;
12609 }
12610 }
12611
12612 if (!(flag & HA_STATUS_NO_LOCK)) {
12613 dict_table_stats_unlock(ib_table, RW_S_LATCH);
12614 }
12615
12616 my_snprintf(path, sizeof(path), "%s/%s%s",
12617 mysql_data_home,
12618 table->s->normalized_path.str,
12619 reg_ext);
12620
12621 unpack_filename(path,path);
12622
12623 /* Note that we do not know the access time of the table,
12624 nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
12625
12626 if (os_file_get_status(path, &stat_info, false) == DB_SUCCESS) {
12627 stats.create_time = (ulong) stat_info.ctime;
12628 }
12629 }
12630
12631 if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
12632
12633 goto func_exit;
12634 }
12635
12636 if (flag & HA_STATUS_ERRKEY) {
12637 const dict_index_t* err_index;
12638
12639 ut_a(prebuilt->trx);
12640 ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
12641
12642 err_index = trx_get_error_info(prebuilt->trx);
12643
12644 if (err_index) {
12645 errkey = innobase_get_mysql_key_number_for_index(
12646 share, table, ib_table, err_index);
12647 } else {
12648 errkey = (unsigned int) (
12649 (prebuilt->trx->error_key_num
12650 == ULINT_UNDEFINED)
12651 ? ~0
12652 : prebuilt->trx->error_key_num);
12653 }
12654 }
12655
12656 if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
12657 stats.auto_increment_value = innobase_peek_autoinc();
12658 }
12659
12660 func_exit:
12661 prebuilt->trx->op_info = (char*)"";
12662
12663 DBUG_RETURN(0);
12664 }
12665
12666 /*********************************************************************//**
12667 Returns statistics information of the table to the MySQL interpreter,
12668 in various fields of the handle object.
12669 @return HA_ERR_* error code or 0 */
12670 UNIV_INTERN
12671 int
info(uint flag)12672 ha_innobase::info(
12673 /*==============*/
12674 uint flag) /*!< in: what information is requested */
12675 {
12676 return(this->info_low(flag, false /* not ANALYZE */));
12677 }
12678
12679 /**********************************************************************//**
12680 Updates index cardinalities of the table, based on random dives into
12681 each index tree. This does NOT calculate exact statistics on the table.
12682 @return HA_ADMIN_* error code or HA_ADMIN_OK */
12683 UNIV_INTERN
12684 int
analyze(THD * thd,HA_CHECK_OPT * check_opt)12685 ha_innobase::analyze(
12686 /*=================*/
12687 THD* thd, /*!< in: connection thread handle */
12688 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
12689 {
12690 int ret;
12691
12692 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
12693 return(HA_ADMIN_CORRUPT);
12694 }
12695
12696 /* Simply call this->info_low() with all the flags
12697 and request recalculation of the statistics */
12698 ret = this->info_low(
12699 HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
12700 true /* this is ANALYZE */);
12701
12702 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
12703 return(HA_ADMIN_CORRUPT);
12704 }
12705
12706 if (ret != 0) {
12707 return(HA_ADMIN_FAILED);
12708 }
12709
12710 return(HA_ADMIN_OK);
12711 }
12712
12713 /**********************************************************************//**
12714 This is mapped to "ALTER TABLE tablename ENGINE=InnoDB", which rebuilds
12715 the table in MySQL. */
12716 UNIV_INTERN
12717 int
optimize(THD * thd,HA_CHECK_OPT * check_opt)12718 ha_innobase::optimize(
12719 /*==================*/
12720 THD* thd, /*!< in: connection thread handle */
12721 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
12722 {
12723 /*FTS-FIXME: Since MySQL doesn't support engine-specific commands,
12724 we have to hijack some existing command in order to be able to test
12725 the new admin commands added in InnoDB's FTS support. For now, we
12726 use MySQL's OPTIMIZE command, normally mapped to ALTER TABLE in
12727 InnoDB (so it recreates the table anew), and map it to OPTIMIZE.
12728
12729 This works OK otherwise, but MySQL locks the entire table during
12730 calls to OPTIMIZE, which is undesirable. */
12731
12732 if (innodb_optimize_fulltext_only) {
12733 if (prebuilt->table->fts && prebuilt->table->fts->cache
12734 && !dict_table_is_discarded(prebuilt->table)) {
12735 fts_sync_table(prebuilt->table, false, true, false);
12736 fts_optimize_table(prebuilt->table);
12737 }
12738 return(HA_ADMIN_OK);
12739 } else {
12740
12741 return(HA_ADMIN_TRY_ALTER);
12742 }
12743 }
12744
12745 /*******************************************************************//**
12746 Tries to check that an InnoDB table is not corrupted. If corruption is
12747 noticed, prints to stderr information about it. In case of corruption
12748 may also assert a failure and crash the server.
12749 @return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
12750 UNIV_INTERN
12751 int
check(THD * thd,HA_CHECK_OPT * check_opt)12752 ha_innobase::check(
12753 /*===============*/
12754 THD* thd, /*!< in: user thread handle */
12755 HA_CHECK_OPT* check_opt) /*!< in: check options */
12756 {
12757 dict_index_t* index;
12758 ulint n_rows;
12759 ulint n_rows_in_table = ULINT_UNDEFINED;
12760 bool is_ok = true;
12761 ulint old_isolation_level;
12762 ibool table_corrupted;
12763
12764 DBUG_ENTER("ha_innobase::check");
12765 DBUG_ASSERT(thd == ha_thd());
12766 ut_a(prebuilt->trx);
12767 ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
12768 ut_a(prebuilt->trx == thd_to_trx(thd));
12769
12770 if (prebuilt->mysql_template == NULL) {
12771 /* Build the template; we will use a dummy template
12772 in index scans done in checking */
12773
12774 build_template(true);
12775 }
12776
12777 if (dict_table_is_discarded(prebuilt->table)) {
12778
12779 ib_senderrf(
12780 thd,
12781 IB_LOG_LEVEL_ERROR,
12782 ER_TABLESPACE_DISCARDED,
12783 table->s->table_name.str);
12784
12785 DBUG_RETURN(HA_ADMIN_CORRUPT);
12786
12787 } else if (prebuilt->table->ibd_file_missing) {
12788
12789 ib_senderrf(
12790 thd, IB_LOG_LEVEL_ERROR,
12791 ER_TABLESPACE_MISSING,
12792 table->s->table_name.str);
12793
12794 DBUG_RETURN(HA_ADMIN_CORRUPT);
12795 }
12796
12797 prebuilt->trx->op_info = "checking table";
12798
12799 old_isolation_level = prebuilt->trx->isolation_level;
12800
12801 /* We must run the index record counts at an isolation level
12802 >= READ COMMITTED, because a dirty read can see a wrong number
12803 of records in some index; to play safe, we use always
12804 REPEATABLE READ here */
12805
12806 prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
12807
12808 /* Check whether the table is already marked as corrupted
12809 before running the check table */
12810 table_corrupted = prebuilt->table->corrupted;
12811
12812 /* Reset table->corrupted bit so that check table can proceed to
12813 do additional check */
12814 prebuilt->table->corrupted = FALSE;
12815
12816 for (index = dict_table_get_first_index(prebuilt->table);
12817 index != NULL;
12818 index = dict_table_get_next_index(index)) {
12819 char index_name[MAX_FULL_NAME_LEN + 1];
12820
12821 /* If this is an index being created or dropped, skip */
12822 if (*index->name == TEMP_INDEX_PREFIX) {
12823 continue;
12824 }
12825
12826 if (!(check_opt->flags & T_QUICK)) {
12827 /* Enlarge the fatal lock wait timeout during
12828 CHECK TABLE. */
12829 os_increment_counter_by_amount(
12830 server_mutex,
12831 srv_fatal_semaphore_wait_threshold,
12832 SRV_SEMAPHORE_WAIT_EXTENSION);
12833 bool valid = btr_validate_index(index, prebuilt->trx);
12834
12835 /* Restore the fatal lock wait timeout after
12836 CHECK TABLE. */
12837 os_decrement_counter_by_amount(
12838 server_mutex,
12839 srv_fatal_semaphore_wait_threshold,
12840 SRV_SEMAPHORE_WAIT_EXTENSION);
12841
12842 if (!valid) {
12843 is_ok = false;
12844
12845 innobase_format_name(
12846 index_name, sizeof index_name,
12847 index->name, TRUE);
12848 push_warning_printf(
12849 thd,
12850 Sql_condition::WARN_LEVEL_WARN,
12851 ER_NOT_KEYFILE,
12852 "InnoDB: The B-tree of"
12853 " index %s is corrupted.",
12854 index_name);
12855 continue;
12856 }
12857 }
12858
12859 /* Instead of invoking change_active_index(), set up
12860 a dummy template for non-locking reads, disabling
12861 access to the clustered index. */
12862 prebuilt->index = index;
12863
12864 prebuilt->index_usable = row_merge_is_index_usable(
12865 prebuilt->trx, prebuilt->index);
12866
12867 if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
12868 innobase_format_name(
12869 index_name, sizeof index_name,
12870 prebuilt->index->name, TRUE);
12871
12872 if (dict_index_is_corrupted(prebuilt->index)) {
12873 push_warning_printf(
12874 user_thd,
12875 Sql_condition::WARN_LEVEL_WARN,
12876 HA_ERR_INDEX_CORRUPT,
12877 "InnoDB: Index %s is marked as"
12878 " corrupted",
12879 index_name);
12880 is_ok = false;
12881 } else {
12882 push_warning_printf(
12883 thd,
12884 Sql_condition::WARN_LEVEL_WARN,
12885 HA_ERR_TABLE_DEF_CHANGED,
12886 "InnoDB: Insufficient history for"
12887 " index %s",
12888 index_name);
12889 }
12890 continue;
12891 }
12892
12893 prebuilt->sql_stat_start = TRUE;
12894 prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
12895 prebuilt->n_template = 0;
12896 prebuilt->need_to_access_clustered = FALSE;
12897
12898 dtuple_set_n_fields(prebuilt->search_tuple, 0);
12899
12900 prebuilt->select_lock_type = LOCK_NONE;
12901
12902 bool check_result
12903 = row_check_index_for_mysql(prebuilt, index, &n_rows);
12904 DBUG_EXECUTE_IF(
12905 "dict_set_index_corrupted",
12906 if (!(index->type & DICT_CLUSTERED)) {
12907 check_result = false;
12908 });
12909 if (!check_result) {
12910 innobase_format_name(
12911 index_name, sizeof index_name,
12912 index->name, TRUE);
12913
12914 push_warning_printf(
12915 thd, Sql_condition::WARN_LEVEL_WARN,
12916 ER_NOT_KEYFILE,
12917 "InnoDB: The B-tree of"
12918 " index %s is corrupted.",
12919 index_name);
12920 is_ok = false;
12921 dict_set_corrupted(
12922 index, prebuilt->trx, "CHECK TABLE-check index");
12923 }
12924
12925 if (thd_killed(user_thd)) {
12926 break;
12927 }
12928
12929 #if 0
12930 fprintf(stderr, "%lu entries in index %s\n", n_rows,
12931 index->name);
12932 #endif
12933
12934 if (index == dict_table_get_first_index(prebuilt->table)) {
12935 n_rows_in_table = n_rows;
12936 } else if (!(index->type & DICT_FTS)
12937 && (n_rows != n_rows_in_table)) {
12938 push_warning_printf(
12939 thd, Sql_condition::WARN_LEVEL_WARN,
12940 ER_NOT_KEYFILE,
12941 "InnoDB: Index '%-.200s' contains %lu"
12942 " entries, should be %lu.",
12943 index->name,
12944 (ulong) n_rows,
12945 (ulong) n_rows_in_table);
12946 is_ok = false;
12947 dict_set_corrupted(
12948 index, prebuilt->trx,
12949 "CHECK TABLE; Wrong count");
12950 }
12951 }
12952
12953 if (table_corrupted) {
12954 /* If some previous operation has marked the table as
12955 corrupted in memory, and has not propagated such to
12956 clustered index, we will do so here */
12957 index = dict_table_get_first_index(prebuilt->table);
12958
12959 if (!dict_index_is_corrupted(index)) {
12960 dict_set_corrupted(
12961 index, prebuilt->trx, "CHECK TABLE");
12962 }
12963 prebuilt->table->corrupted = TRUE;
12964 }
12965
12966 /* Restore the original isolation level */
12967 prebuilt->trx->isolation_level = old_isolation_level;
12968
12969 /* We validate the whole adaptive hash index for all tables
12970 at every CHECK TABLE only when QUICK flag is not present. */
12971
12972 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
12973 if (!(check_opt->flags & T_QUICK) && !btr_search_validate()) {
12974 push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
12975 ER_NOT_KEYFILE,
12976 "InnoDB: The adaptive hash index is corrupted.");
12977 is_ok = false;
12978 }
12979 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
12980
12981 prebuilt->trx->op_info = "";
12982 if (thd_killed(user_thd)) {
12983 thd_set_kill_status(user_thd);
12984 }
12985
12986 if (UNIV_UNLIKELY(prebuilt->table && prebuilt->table->corrupted)) {
12987 DBUG_RETURN(HA_ADMIN_CORRUPT);
12988 }
12989
12990 DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
12991 }
12992
12993 /*************************************************************//**
12994 Adds information about free space in the InnoDB tablespace to a table comment
12995 which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
12996 foreign keys.
12997 @return table comment + InnoDB free space + info on foreign keys */
12998 UNIV_INTERN
12999 char*
update_table_comment(const char * comment)13000 ha_innobase::update_table_comment(
13001 /*==============================*/
13002 const char* comment)/*!< in: table comment defined by user */
13003 {
13004 uint length = (uint) strlen(comment);
13005 char* str;
13006 long flen;
13007
13008 /* We do not know if MySQL can call this function before calling
13009 external_lock(). To be safe, update the thd of the current table
13010 handle. */
13011
13012 if (length > 64000 - 3) {
13013 return((char*) comment); /* string too long */
13014 }
13015
13016 update_thd(ha_thd());
13017
13018 prebuilt->trx->op_info = (char*)"returning table comment";
13019
13020 /* In case MySQL calls this in the middle of a SELECT query, release
13021 possible adaptive hash latch to avoid deadlocks of threads */
13022
13023 trx_search_latch_release_if_reserved(prebuilt->trx);
13024 str = NULL;
13025
13026 /* output the data to a temporary file */
13027
13028 if (!srv_read_only_mode) {
13029
13030 mutex_enter(&srv_dict_tmpfile_mutex);
13031
13032 rewind(srv_dict_tmpfile);
13033
13034 fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
13035 fsp_get_available_space_in_free_extents(
13036 prebuilt->table->space));
13037
13038 dict_print_info_on_foreign_keys(
13039 FALSE, srv_dict_tmpfile, prebuilt->trx,
13040 prebuilt->table);
13041
13042 flen = ftell(srv_dict_tmpfile);
13043
13044 if (flen < 0) {
13045 flen = 0;
13046 } else if (length + flen + 3 > 64000) {
13047 flen = 64000 - 3 - length;
13048 }
13049
13050 /* allocate buffer for the full string, and
13051 read the contents of the temporary file */
13052
13053 str = (char*) my_malloc(length + flen + 3, MYF(0));
13054
13055 if (str) {
13056 char* pos = str + length;
13057 if (length) {
13058 memcpy(str, comment, length);
13059 *pos++ = ';';
13060 *pos++ = ' ';
13061 }
13062 rewind(srv_dict_tmpfile);
13063 flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
13064 pos[flen] = 0;
13065 }
13066
13067 mutex_exit(&srv_dict_tmpfile_mutex);
13068 }
13069
13070 prebuilt->trx->op_info = (char*)"";
13071
13072 return(str ? str : (char*) comment);
13073 }
13074
13075 /*******************************************************************//**
13076 Gets the foreign key create info for a table stored in InnoDB.
13077 @return own: character string in the form which can be inserted to the
13078 CREATE TABLE statement, MUST be freed with
13079 ha_innobase::free_foreign_key_create_info */
13080 UNIV_INTERN
13081 char*
get_foreign_key_create_info(void)13082 ha_innobase::get_foreign_key_create_info(void)
13083 /*==========================================*/
13084 {
13085 long flen;
13086 char* str = 0;
13087
13088 ut_a(prebuilt != NULL);
13089
13090 /* We do not know if MySQL can call this function before calling
13091 external_lock(). To be safe, update the thd of the current table
13092 handle. */
13093
13094 update_thd(ha_thd());
13095
13096 prebuilt->trx->op_info = (char*)"getting info on foreign keys";
13097
13098 /* In case MySQL calls this in the middle of a SELECT query,
13099 release possible adaptive hash latch to avoid
13100 deadlocks of threads */
13101
13102 trx_search_latch_release_if_reserved(prebuilt->trx);
13103
13104 if (!srv_read_only_mode) {
13105 mutex_enter(&srv_dict_tmpfile_mutex);
13106 rewind(srv_dict_tmpfile);
13107
13108 /* Output the data to a temporary file */
13109 dict_print_info_on_foreign_keys(
13110 TRUE, srv_dict_tmpfile, prebuilt->trx,
13111 prebuilt->table);
13112
13113 prebuilt->trx->op_info = (char*)"";
13114
13115 flen = ftell(srv_dict_tmpfile);
13116
13117 if (flen < 0) {
13118 flen = 0;
13119 }
13120
13121 /* Allocate buffer for the string, and
13122 read the contents of the temporary file */
13123
13124 str = (char*) my_malloc(flen + 1, MYF(0));
13125
13126 if (str) {
13127 rewind(srv_dict_tmpfile);
13128 flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
13129 str[flen] = 0;
13130 }
13131
13132 mutex_exit(&srv_dict_tmpfile_mutex);
13133 }
13134
13135 return(str);
13136 }
13137
13138
13139 /***********************************************************************//**
13140 Maps a InnoDB foreign key constraint to a equivalent MySQL foreign key info.
13141 @return pointer to foreign key info */
13142 static
13143 FOREIGN_KEY_INFO*
get_foreign_key_info(THD * thd,dict_foreign_t * foreign)13144 get_foreign_key_info(
13145 /*=================*/
13146 THD* thd, /*!< in: user thread handle */
13147 dict_foreign_t* foreign) /*!< in: foreign key constraint */
13148 {
13149 FOREIGN_KEY_INFO f_key_info;
13150 FOREIGN_KEY_INFO* pf_key_info;
13151 uint i = 0;
13152 ulint len;
13153 char tmp_buff[NAME_LEN+1];
13154 char name_buff[NAME_LEN+1];
13155 const char* ptr;
13156 LEX_STRING* referenced_key_name;
13157 LEX_STRING* name = NULL;
13158
13159 ptr = dict_remove_db_name(foreign->id);
13160 f_key_info.foreign_id = thd_make_lex_string(thd, 0, ptr,
13161 (uint) strlen(ptr), 1);
13162
13163 /* Name format: database name, '/', table name, '\0' */
13164
13165 /* Referenced (parent) database name */
13166 len = dict_get_db_name_len(foreign->referenced_table_name);
13167 ut_a(len < sizeof(tmp_buff));
13168 ut_memcpy(tmp_buff, foreign->referenced_table_name, len);
13169 tmp_buff[len] = 0;
13170
13171 len = filename_to_tablename(tmp_buff, name_buff, sizeof(name_buff));
13172 f_key_info.referenced_db = thd_make_lex_string(
13173 thd, 0, name_buff, static_cast<unsigned int>(len), 1);
13174
13175 /* Referenced (parent) table name */
13176 ptr = dict_remove_db_name(foreign->referenced_table_name);
13177 len = filename_to_tablename(ptr, name_buff, sizeof(name_buff));
13178 f_key_info.referenced_table = thd_make_lex_string(
13179 thd, 0, name_buff, static_cast<unsigned int>(len), 1);
13180
13181 /* Dependent (child) database name */
13182 len = dict_get_db_name_len(foreign->foreign_table_name);
13183 ut_a(len < sizeof(tmp_buff));
13184 ut_memcpy(tmp_buff, foreign->foreign_table_name, len);
13185 tmp_buff[len] = 0;
13186
13187 len = filename_to_tablename(tmp_buff, name_buff, sizeof(name_buff));
13188 f_key_info.foreign_db = thd_make_lex_string(
13189 thd, 0, name_buff, static_cast<unsigned int>(len), 1);
13190
13191 /* Dependent (child) table name */
13192 ptr = dict_remove_db_name(foreign->foreign_table_name);
13193 len = filename_to_tablename(ptr, name_buff, sizeof(name_buff));
13194 f_key_info.foreign_table = thd_make_lex_string(
13195 thd, 0, name_buff, static_cast<unsigned int>(len), 1);
13196
13197 do {
13198 ptr = foreign->foreign_col_names[i];
13199 name = thd_make_lex_string(thd, name, ptr,
13200 (uint) strlen(ptr), 1);
13201 f_key_info.foreign_fields.push_back(name);
13202 ptr = foreign->referenced_col_names[i];
13203 name = thd_make_lex_string(thd, name, ptr,
13204 (uint) strlen(ptr), 1);
13205 f_key_info.referenced_fields.push_back(name);
13206 } while (++i < foreign->n_fields);
13207
13208 if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
13209 len = 7;
13210 ptr = "CASCADE";
13211 } else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
13212 len = 8;
13213 ptr = "SET NULL";
13214 } else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
13215 len = 9;
13216 ptr = "NO ACTION";
13217 } else {
13218 len = 8;
13219 ptr = "RESTRICT";
13220 }
13221
13222 f_key_info.delete_method = thd_make_lex_string(
13223 thd, f_key_info.delete_method, ptr,
13224 static_cast<unsigned int>(len), 1);
13225
13226 if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
13227 len = 7;
13228 ptr = "CASCADE";
13229 } else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
13230 len = 8;
13231 ptr = "SET NULL";
13232 } else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
13233 len = 9;
13234 ptr = "NO ACTION";
13235 } else {
13236 len = 8;
13237 ptr = "RESTRICT";
13238 }
13239
13240 f_key_info.update_method = thd_make_lex_string(
13241 thd, f_key_info.update_method, ptr,
13242 static_cast<unsigned int>(len), 1);
13243
13244 if (foreign->referenced_index && foreign->referenced_index->name) {
13245 referenced_key_name = thd_make_lex_string(thd,
13246 f_key_info.referenced_key_name,
13247 foreign->referenced_index->name,
13248 (uint) strlen(foreign->referenced_index->name),
13249 1);
13250 } else {
13251 referenced_key_name = NULL;
13252 }
13253
13254 f_key_info.referenced_key_name = referenced_key_name;
13255
13256 pf_key_info = (FOREIGN_KEY_INFO*) thd_memdup(thd, &f_key_info,
13257 sizeof(FOREIGN_KEY_INFO));
13258
13259 return(pf_key_info);
13260 }
13261
13262 /** Get the list of foreign keys referencing a specified table
13263 table.
13264 @param thd The thread handle
13265 @param path Path to the table
13266 @param f_key_list[out] The list of foreign keys */
13267 static
13268 void
fill_foreign_key_list(THD * thd,const dict_table_t * table,List<FOREIGN_KEY_INFO> * f_key_list)13269 fill_foreign_key_list(THD* thd,
13270 const dict_table_t* table,
13271 List<FOREIGN_KEY_INFO>* f_key_list)
13272 {
13273 ut_ad(mutex_own(&dict_sys->mutex));
13274
13275 for (dict_foreign_set::iterator it = table->referenced_set.begin();
13276 it != table->referenced_set.end(); ++it) {
13277
13278 dict_foreign_t* foreign = *it;
13279
13280 FOREIGN_KEY_INFO* pf_key_info
13281 = get_foreign_key_info(thd, foreign);
13282 if (pf_key_info) {
13283 f_key_list->push_back(pf_key_info);
13284 }
13285 }
13286 }
13287
13288 /** Get the list of foreign keys referencing a specified table
13289 table.
13290 @param thd The thread handle
13291 @param path Path to the table
13292 @param f_key_list[out] The list of foreign keys
13293
13294 @return error code or zero for success */
13295 static
13296 int
innobase_get_parent_fk_list(THD * thd,const char * path,List<FOREIGN_KEY_INFO> * f_key_list)13297 innobase_get_parent_fk_list(
13298 THD* thd,
13299 const char* path,
13300 List<FOREIGN_KEY_INFO>* f_key_list)
13301 {
13302 ut_a(strlen(path) <= FN_REFLEN);
13303 char norm_name[FN_REFLEN + 1];
13304 normalize_table_name(norm_name, path);
13305
13306 trx_t* parent_trx = check_trx_exists(thd);
13307 parent_trx->op_info = "getting list of referencing foreign keys";
13308 trx_search_latch_release_if_reserved(parent_trx);
13309
13310 mutex_enter(&dict_sys->mutex);
13311
13312 dict_table_t* table
13313 = dict_table_open_on_name(norm_name, TRUE, FALSE,
13314 static_cast<dict_err_ignore_t>(
13315 DICT_ERR_IGNORE_INDEX_ROOT
13316 | DICT_ERR_IGNORE_CORRUPT));
13317 if (!table) {
13318 mutex_exit(&dict_sys->mutex);
13319 return(HA_ERR_NO_SUCH_TABLE);
13320 }
13321
13322 fill_foreign_key_list(thd, table, f_key_list);
13323
13324 dict_table_close(table, TRUE, FALSE);
13325
13326 mutex_exit(&dict_sys->mutex);
13327 parent_trx->op_info = "";
13328 return(0);
13329 }
13330
13331 /*******************************************************************//**
13332 Gets the list of foreign keys in this table.
13333 @return always 0, that is, always succeeds */
13334 UNIV_INTERN
13335 int
get_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)13336 ha_innobase::get_foreign_key_list(
13337 /*==============================*/
13338 THD* thd, /*!< in: user thread handle */
13339 List<FOREIGN_KEY_INFO>* f_key_list) /*!< out: foreign key list */
13340 {
13341 FOREIGN_KEY_INFO* pf_key_info;
13342 dict_foreign_t* foreign;
13343
13344 ut_a(prebuilt != NULL);
13345 update_thd(ha_thd());
13346
13347 prebuilt->trx->op_info = "getting list of foreign keys";
13348
13349 trx_search_latch_release_if_reserved(prebuilt->trx);
13350
13351 mutex_enter(&(dict_sys->mutex));
13352
13353 for (dict_foreign_set::iterator it
13354 = prebuilt->table->foreign_set.begin();
13355 it != prebuilt->table->foreign_set.end();
13356 ++it) {
13357
13358 foreign = *it;
13359
13360 pf_key_info = get_foreign_key_info(thd, foreign);
13361 if (pf_key_info) {
13362 f_key_list->push_back(pf_key_info);
13363 }
13364 }
13365
13366 mutex_exit(&(dict_sys->mutex));
13367
13368 prebuilt->trx->op_info = "";
13369
13370 return(0);
13371 }
13372
13373 /*******************************************************************//**
13374 Gets the set of foreign keys where this table is the referenced table.
13375 @return always 0, that is, always succeeds */
13376 UNIV_INTERN
13377 int
get_parent_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)13378 ha_innobase::get_parent_foreign_key_list(
13379 /*=====================================*/
13380 THD* thd, /*!< in: user thread handle */
13381 List<FOREIGN_KEY_INFO>* f_key_list) /*!< out: foreign key list */
13382 {
13383 ut_a(prebuilt != NULL);
13384 update_thd(ha_thd());
13385
13386 prebuilt->trx->op_info = "getting list of referencing foreign keys";
13387
13388 trx_search_latch_release_if_reserved(prebuilt->trx);
13389
13390 mutex_enter(&(dict_sys->mutex));
13391 fill_foreign_key_list(thd, prebuilt->table, f_key_list);
13392 mutex_exit(&(dict_sys->mutex));
13393
13394 prebuilt->trx->op_info = "";
13395
13396 return(0);
13397 }
13398
13399 /*****************************************************************//**
13400 Checks if ALTER TABLE may change the storage engine of the table.
13401 Changing storage engines is not allowed for tables for which there
13402 are foreign key constraints (parent or child tables).
13403 @return TRUE if can switch engines */
13404 UNIV_INTERN
13405 bool
can_switch_engines(void)13406 ha_innobase::can_switch_engines(void)
13407 /*=================================*/
13408 {
13409 bool can_switch;
13410
13411 DBUG_ENTER("ha_innobase::can_switch_engines");
13412 update_thd();
13413
13414 prebuilt->trx->op_info =
13415 "determining if there are foreign key constraints";
13416 row_mysql_freeze_data_dictionary(prebuilt->trx);
13417
13418 can_switch = prebuilt->table->referenced_set.empty()
13419 && prebuilt->table->foreign_set.empty();
13420
13421 row_mysql_unfreeze_data_dictionary(prebuilt->trx);
13422 prebuilt->trx->op_info = "";
13423
13424 DBUG_RETURN(can_switch);
13425 }
13426
13427 /*******************************************************************//**
13428 Checks if a table is referenced by a foreign key. The MySQL manual states that
13429 a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
13430 delete is then allowed internally to resolve a duplicate key conflict in
13431 REPLACE, not an update.
13432 @return > 0 if referenced by a FOREIGN KEY */
13433 UNIV_INTERN
13434 uint
referenced_by_foreign_key(void)13435 ha_innobase::referenced_by_foreign_key(void)
13436 /*========================================*/
13437 {
13438 if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
13439
13440 return(1);
13441 }
13442
13443 return(0);
13444 }
13445
13446 /*******************************************************************//**
13447 Frees the foreign key create info for a table stored in InnoDB, if it is
13448 non-NULL. */
13449 UNIV_INTERN
13450 void
free_foreign_key_create_info(char * str)13451 ha_innobase::free_foreign_key_create_info(
13452 /*======================================*/
13453 char* str) /*!< in, own: create info string to free */
13454 {
13455 if (str) {
13456 my_free(str);
13457 }
13458 }
13459
13460 /*******************************************************************//**
13461 Tells something additional to the handler about how to do things.
13462 @return 0 or error number */
13463 UNIV_INTERN
13464 int
extra(enum ha_extra_function operation)13465 ha_innobase::extra(
13466 /*===============*/
13467 enum ha_extra_function operation)
13468 /*!< in: HA_EXTRA_FLUSH or some other flag */
13469 {
13470 check_trx_exists(ha_thd());
13471
13472 /* Warning: since it is not sure that MySQL calls external_lock
13473 before calling this function, the trx field in prebuilt can be
13474 obsolete! */
13475
13476 switch (operation) {
13477 case HA_EXTRA_FLUSH:
13478 if (prebuilt->blob_heap) {
13479 row_mysql_prebuilt_free_blob_heap(prebuilt);
13480 }
13481
13482 if (prebuilt->compress_heap) {
13483 row_mysql_prebuilt_free_compress_heap(prebuilt);
13484 }
13485
13486 break;
13487 case HA_EXTRA_RESET_STATE:
13488 reset_template();
13489 thd_to_trx(ha_thd())->duplicates = 0;
13490 break;
13491 case HA_EXTRA_NO_KEYREAD:
13492 prebuilt->read_just_key = 0;
13493 break;
13494 case HA_EXTRA_KEYREAD:
13495 prebuilt->read_just_key = 1;
13496 break;
13497 case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
13498 prebuilt->keep_other_fields_on_keyread = 1;
13499 break;
13500
13501 /* IMPORTANT: prebuilt->trx can be obsolete in
13502 this method, because it is not sure that MySQL
13503 calls external_lock before this method with the
13504 parameters below. We must not invoke update_thd()
13505 either, because the calling threads may change.
13506 CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
13507 case HA_EXTRA_INSERT_WITH_UPDATE:
13508 thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE;
13509 break;
13510 case HA_EXTRA_NO_IGNORE_DUP_KEY:
13511 thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE;
13512 break;
13513 case HA_EXTRA_WRITE_CAN_REPLACE:
13514 thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE;
13515 break;
13516 case HA_EXTRA_WRITE_CANNOT_REPLACE:
13517 thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
13518 break;
13519 default:/* Do nothing */
13520 ;
13521 }
13522
13523 return(0);
13524 }
13525
13526 /******************************************************************//**
13527 */
13528 UNIV_INTERN
13529 int
reset()13530 ha_innobase::reset()
13531 /*================*/
13532 {
13533 if (prebuilt->blob_heap) {
13534 row_mysql_prebuilt_free_blob_heap(prebuilt);
13535 }
13536
13537 if (prebuilt->compress_heap) {
13538 row_mysql_prebuilt_free_compress_heap(prebuilt);
13539 }
13540
13541 reset_template();
13542 ds_mrr.reset();
13543
13544 /* TODO: This should really be reset in reset_template() but for now
13545 it's safer to do it explicitly here. */
13546
13547 /* This is a statement level counter. */
13548 prebuilt->autoinc_last_value = 0;
13549
13550 return(0);
13551 }
13552
13553 /******************************************************************//**
13554 MySQL calls this function at the start of each SQL statement inside LOCK
13555 TABLES. Inside LOCK TABLES the ::external_lock method does not work to
13556 mark SQL statement borders. Note also a special case: if a temporary table
13557 is created inside LOCK TABLES, MySQL has not called external_lock() at all
13558 on that table.
13559 MySQL-5.0 also calls this before each statement in an execution of a stored
13560 procedure. To make the execution more deterministic for binlogging, MySQL-5.0
13561 locks all tables involved in a stored procedure with full explicit table
13562 locks (thd_in_lock_tables(thd) holds in store_lock()) before executing the
13563 procedure.
13564 @return 0 or error code */
13565 UNIV_INTERN
13566 int
start_stmt(THD * thd,thr_lock_type lock_type)13567 ha_innobase::start_stmt(
13568 /*====================*/
13569 THD* thd, /*!< in: handle to the user thread */
13570 thr_lock_type lock_type)
13571 {
13572 trx_t* trx;
13573 DBUG_ENTER("ha_innobase::start_stmt");
13574
13575 update_thd(thd);
13576
13577 trx = prebuilt->trx;
13578
13579 /* Here we release the search latch and the InnoDB thread FIFO ticket
13580 if they were reserved. They should have been released already at the
13581 end of the previous statement, but because inside LOCK TABLES the
13582 lock count method does not work to mark the end of a SELECT statement,
13583 that may not be the case. We MUST release the search latch before an
13584 INSERT, for example. */
13585
13586 trx_search_latch_release_if_reserved(trx);
13587
13588 innobase_srv_conc_force_exit_innodb(trx);
13589
13590 /* Reset the AUTOINC statement level counter for multi-row INSERTs. */
13591 trx->n_autoinc_rows = 0;
13592
13593 prebuilt->sql_stat_start = TRUE;
13594 prebuilt->hint_need_to_fetch_extra_cols = 0;
13595 reset_template();
13596
13597 if (dict_table_is_temporary(prebuilt->table)
13598 && prebuilt->mysql_has_locked
13599 && prebuilt->select_lock_type == LOCK_NONE) {
13600 dberr_t error;
13601
13602 switch (thd_sql_command(thd)) {
13603 case SQLCOM_INSERT:
13604 case SQLCOM_UPDATE:
13605 case SQLCOM_DELETE:
13606 case SQLCOM_REPLACE:
13607 init_table_handle_for_HANDLER();
13608 prebuilt->select_lock_type = LOCK_X;
13609 prebuilt->stored_select_lock_type = LOCK_X;
13610 error = row_lock_table_for_mysql(prebuilt, NULL, 1);
13611
13612 if (error != DB_SUCCESS) {
13613 int st = convert_error_code_to_mysql(
13614 error, 0, thd);
13615 DBUG_RETURN(st);
13616 }
13617 break;
13618 }
13619 }
13620
13621 if (!prebuilt->mysql_has_locked) {
13622 /* This handle is for a temporary table created inside
13623 this same LOCK TABLES; since MySQL does NOT call external_lock
13624 in this case, we must use x-row locks inside InnoDB to be
13625 prepared for an update of a row */
13626
13627 prebuilt->select_lock_type = LOCK_X;
13628
13629 } else if (trx->isolation_level != TRX_ISO_SERIALIZABLE
13630 && thd_sql_command(thd) == SQLCOM_SELECT
13631 && lock_type == TL_READ) {
13632
13633 /* For other than temporary tables, we obtain
13634 no lock for consistent read (plain SELECT). */
13635
13636 prebuilt->select_lock_type = LOCK_NONE;
13637 } else {
13638 /* Not a consistent read: restore the
13639 select_lock_type value. The value of
13640 stored_select_lock_type was decided in:
13641 1) ::store_lock(),
13642 2) ::external_lock(),
13643 3) ::init_table_handle_for_HANDLER(), and
13644 4) ::transactional_table_lock(). */
13645
13646 ut_a(prebuilt->stored_select_lock_type != LOCK_NONE_UNSET);
13647 prebuilt->select_lock_type = prebuilt->stored_select_lock_type;
13648 }
13649
13650 *trx->detailed_error = 0;
13651
13652 innobase_register_trx(ht, thd, trx);
13653
13654 if (!trx_is_started(trx)) {
13655 ++trx->will_lock;
13656 }
13657
13658 DBUG_RETURN(0);
13659 }
13660
13661 /******************************************************************//**
13662 Maps a MySQL trx isolation level code to the InnoDB isolation level code
13663 @return InnoDB isolation level */
13664 static inline
13665 ulint
innobase_map_isolation_level(enum_tx_isolation iso)13666 innobase_map_isolation_level(
13667 /*=========================*/
13668 enum_tx_isolation iso) /*!< in: MySQL isolation level code */
13669 {
13670 switch (iso) {
13671 case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
13672 case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
13673 case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
13674 case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
13675 }
13676
13677 ut_error;
13678
13679 return(0);
13680 }
13681
13682 /******************************************************************//**
13683 As MySQL will execute an external lock for every new table it uses when it
13684 starts to process an SQL statement (an exception is when MySQL calls
13685 start_stmt for the handle) we can use this function to store the pointer to
13686 the THD in the handle. We will also use this function to communicate
13687 to InnoDB that a new SQL statement has started and that we must store a
13688 savepoint to our transaction handle, so that we are able to roll back
13689 the SQL statement in case of an error.
13690 @return 0 */
13691 UNIV_INTERN
13692 int
external_lock(THD * thd,int lock_type)13693 ha_innobase::external_lock(
13694 /*=======================*/
13695 THD* thd, /*!< in: handle to the user thread */
13696 int lock_type) /*!< in: lock type */
13697 {
13698 trx_t* trx;
13699
13700 DBUG_ENTER("ha_innobase::external_lock");
13701 DBUG_PRINT("enter",("lock_type: %d", lock_type));
13702
13703 update_thd(thd);
13704
13705 /* Statement based binlogging does not work in isolation level
13706 READ UNCOMMITTED and READ COMMITTED since the necessary
13707 locks cannot be taken. In this case, we print an
13708 informative error message and return with an error.
13709 Note: decide_logging_format would give the same error message,
13710 except it cannot give the extra details. */
13711
13712 if (lock_type == F_WRLCK
13713 && !(table_flags() & HA_BINLOG_STMT_CAPABLE)
13714 && thd_binlog_format(thd) == BINLOG_FORMAT_STMT
13715 && thd_binlog_filter_ok(thd)
13716 && thd_sqlcom_can_generate_row_events(thd)) {
13717 bool skip = 0;
13718 /* used by test case */
13719 DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;);
13720 if (!skip) {
13721 my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0),
13722 " InnoDB is limited to row-logging when "
13723 "transaction isolation level is "
13724 "READ COMMITTED or READ UNCOMMITTED.");
13725 DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE);
13726 }
13727 }
13728
13729 /* Check for UPDATEs in read-only mode. */
13730 if (srv_read_only_mode
13731 && (thd_sql_command(thd) == SQLCOM_UPDATE
13732 || thd_sql_command(thd) == SQLCOM_INSERT
13733 || thd_sql_command(thd) == SQLCOM_REPLACE
13734 || thd_sql_command(thd) == SQLCOM_DROP_TABLE
13735 || thd_sql_command(thd) == SQLCOM_ALTER_TABLE
13736 || thd_sql_command(thd) == SQLCOM_OPTIMIZE
13737 || (thd_sql_command(thd) == SQLCOM_CREATE_TABLE
13738 && lock_type == F_WRLCK)
13739 || thd_sql_command(thd) == SQLCOM_CREATE_INDEX
13740 || thd_sql_command(thd) == SQLCOM_DROP_INDEX
13741 || thd_sql_command(thd) == SQLCOM_DELETE
13742 || thd_sql_command(thd) ==
13743 SQLCOM_CREATE_COMPRESSION_DICTIONARY
13744 || thd_sql_command(thd) ==
13745 SQLCOM_DROP_COMPRESSION_DICTIONARY)) {
13746
13747 if (thd_sql_command(thd) == SQLCOM_CREATE_TABLE)
13748 {
13749 ib_senderrf(thd, IB_LOG_LEVEL_WARN,
13750 ER_INNODB_READ_ONLY);
13751 DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
13752 } else {
13753 ib_senderrf(thd, IB_LOG_LEVEL_WARN,
13754 ER_READ_ONLY_MODE);
13755 DBUG_RETURN(HA_ERR_TABLE_READONLY);
13756 }
13757
13758 }
13759
13760 trx = prebuilt->trx;
13761
13762 prebuilt->sql_stat_start = TRUE;
13763 prebuilt->hint_need_to_fetch_extra_cols = 0;
13764
13765 reset_template();
13766
13767 switch (prebuilt->table->quiesce) {
13768 case QUIESCE_START:
13769 /* Check for FLUSH TABLE t WITH READ LOCK; */
13770 if (!srv_read_only_mode
13771 && thd_sql_command(thd) == SQLCOM_FLUSH
13772 && lock_type == F_RDLCK) {
13773
13774 row_quiesce_table_start(prebuilt->table, trx);
13775
13776 /* Use the transaction instance to track UNLOCK
13777 TABLES. It can be done via START TRANSACTION; too
13778 implicitly. */
13779
13780 ++trx->flush_tables;
13781 }
13782 break;
13783
13784 case QUIESCE_COMPLETE:
13785 /* Check for UNLOCK TABLES; implicit or explicit
13786 or trx interruption. */
13787 if (trx->flush_tables > 0
13788 && (lock_type == F_UNLCK || trx_is_interrupted(trx))) {
13789
13790 row_quiesce_table_complete(prebuilt->table, trx);
13791
13792 ut_a(trx->flush_tables > 0);
13793 --trx->flush_tables;
13794 }
13795
13796 break;
13797
13798 case QUIESCE_NONE:
13799 break;
13800 }
13801
13802 if (lock_type == F_WRLCK) {
13803
13804 /* If this is a SELECT, then it is in UPDATE TABLE ...
13805 or SELECT ... FOR UPDATE */
13806 prebuilt->select_lock_type = LOCK_X;
13807 prebuilt->stored_select_lock_type = LOCK_X;
13808 }
13809
13810 if (lock_type != F_UNLCK) {
13811 /* MySQL is setting a new table lock */
13812
13813 *trx->detailed_error = 0;
13814
13815 innobase_register_trx(ht, thd, trx);
13816
13817 if (trx->isolation_level == TRX_ISO_SERIALIZABLE
13818 && prebuilt->select_lock_type == LOCK_NONE
13819 && thd_test_options(
13820 thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
13821
13822 /* To get serializable execution, we let InnoDB
13823 conceptually add 'LOCK IN SHARE MODE' to all SELECTs
13824 which otherwise would have been consistent reads. An
13825 exception is consistent reads in the AUTOCOMMIT=1 mode:
13826 we know that they are read-only transactions, and they
13827 can be serialized also if performed as consistent
13828 reads. */
13829
13830 prebuilt->select_lock_type = LOCK_S;
13831 prebuilt->stored_select_lock_type = LOCK_S;
13832 }
13833
13834 /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
13835 TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
13836 an InnoDB table lock if it is released immediately at the end
13837 of LOCK TABLES, and InnoDB's table locks in that case cause
13838 VERY easily deadlocks.
13839
13840 We do not set InnoDB table locks if user has not explicitly
13841 requested a table lock. Note that thd_in_lock_tables(thd)
13842 can hold in some cases, e.g., at the start of a stored
13843 procedure call (SQLCOM_CALL). */
13844
13845 if (prebuilt->select_lock_type != LOCK_NONE) {
13846
13847 if (thd_sql_command(thd) == SQLCOM_LOCK_TABLES
13848 && THDVAR(thd, table_locks)
13849 && thd_test_options(thd, OPTION_NOT_AUTOCOMMIT)
13850 && thd_in_lock_tables(thd)) {
13851
13852 dberr_t error = row_lock_table_for_mysql(
13853 prebuilt, NULL, 0);
13854
13855 if (error != DB_SUCCESS) {
13856 DBUG_RETURN(
13857 convert_error_code_to_mysql(
13858 error, 0, thd));
13859 }
13860 }
13861
13862 trx->mysql_n_tables_locked++;
13863 }
13864
13865 trx->n_mysql_tables_in_use++;
13866 prebuilt->mysql_has_locked = TRUE;
13867
13868 if (!trx_is_started(trx)
13869 && (prebuilt->select_lock_type != LOCK_NONE
13870 || prebuilt->stored_select_lock_type != LOCK_NONE)) {
13871
13872 ++trx->will_lock;
13873 }
13874
13875 DBUG_RETURN(0);
13876 }
13877
13878 /* MySQL is releasing a table lock */
13879
13880 trx->n_mysql_tables_in_use--;
13881 prebuilt->mysql_has_locked = FALSE;
13882
13883 /* Release a possible FIFO ticket and search latch. Since we
13884 may reserve the trx_sys->mutex, we have to release the search
13885 system latch first to obey the latching order. */
13886
13887 trx_search_latch_release_if_reserved(trx);
13888
13889 innobase_srv_conc_force_exit_innodb(trx);
13890
13891 /* If the MySQL lock count drops to zero we know that the current SQL
13892 statement has ended */
13893
13894 if (trx->n_mysql_tables_in_use == 0) {
13895 #ifdef EXTENDED_SLOWLOG
13896 if (UNIV_UNLIKELY(trx->take_stats)) {
13897 increment_thd_innodb_stats(thd,
13898 (unsigned long long) trx->id,
13899 trx->io_reads,
13900 trx->io_read,
13901 trx->io_reads_wait_timer,
13902 trx->lock_que_wait_timer,
13903 trx->innodb_que_wait_timer,
13904 trx->distinct_page_access);
13905
13906 trx->io_reads = 0;
13907 trx->io_read = 0;
13908 trx->io_reads_wait_timer = 0;
13909 trx->lock_que_wait_timer = 0;
13910 trx->innodb_que_wait_timer = 0;
13911 trx->distinct_page_access = 0;
13912 if (trx->distinct_page_access_hash)
13913 memset(trx->distinct_page_access_hash, 0,
13914 DPAH_SIZE);
13915 }
13916 #endif
13917
13918 trx->mysql_n_tables_locked = 0;
13919 prebuilt->used_in_HANDLER = FALSE;
13920
13921 if (!thd_test_options(
13922 thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
13923
13924 if (trx_is_started(trx)) {
13925 innobase_commit(ht, thd, TRUE);
13926 }
13927
13928 } else if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
13929 && trx->global_read_view) {
13930
13931 /* At low transaction isolation levels we let
13932 each consistent read set its own snapshot */
13933
13934 read_view_close_for_mysql(trx);
13935 }
13936 }
13937
13938 if (!trx_is_started(trx)
13939 && (prebuilt->select_lock_type != LOCK_NONE
13940 || prebuilt->stored_select_lock_type != LOCK_NONE)) {
13941
13942 ++trx->will_lock;
13943 }
13944
13945 DBUG_RETURN(0);
13946 }
13947
13948 /******************************************************************//**
13949 With this function MySQL request a transactional lock to a table when
13950 user issued query LOCK TABLES..WHERE ENGINE = InnoDB.
13951 @return error code */
13952 UNIV_INTERN
13953 int
transactional_table_lock(THD * thd,int lock_type)13954 ha_innobase::transactional_table_lock(
13955 /*==================================*/
13956 THD* thd, /*!< in: handle to the user thread */
13957 int lock_type) /*!< in: lock type */
13958 {
13959 trx_t* trx;
13960
13961 DBUG_ENTER("ha_innobase::transactional_table_lock");
13962 DBUG_PRINT("enter",("lock_type: %d", lock_type));
13963
13964 /* We do not know if MySQL can call this function before calling
13965 external_lock(). To be safe, update the thd of the current table
13966 handle. */
13967
13968 update_thd(thd);
13969
13970 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
13971 DBUG_RETURN(HA_ERR_CRASHED);
13972 }
13973
13974 if (!thd_tablespace_op(thd)) {
13975
13976 if (dict_table_is_discarded(prebuilt->table)) {
13977
13978 ib_senderrf(
13979 thd, IB_LOG_LEVEL_ERROR,
13980 ER_TABLESPACE_DISCARDED,
13981 table->s->table_name.str);
13982
13983 } else if (prebuilt->table->ibd_file_missing) {
13984
13985 ib_senderrf(
13986 thd, IB_LOG_LEVEL_ERROR,
13987 ER_TABLESPACE_MISSING,
13988 table->s->table_name.str);
13989 }
13990
13991 DBUG_RETURN(HA_ERR_CRASHED);
13992 }
13993
13994 trx = prebuilt->trx;
13995
13996 prebuilt->sql_stat_start = TRUE;
13997 prebuilt->hint_need_to_fetch_extra_cols = 0;
13998
13999 reset_template();
14000
14001 if (lock_type == F_WRLCK) {
14002 prebuilt->select_lock_type = LOCK_X;
14003 prebuilt->stored_select_lock_type = LOCK_X;
14004 } else if (lock_type == F_RDLCK) {
14005 prebuilt->select_lock_type = LOCK_S;
14006 prebuilt->stored_select_lock_type = LOCK_S;
14007 } else {
14008 ib_logf(IB_LOG_LEVEL_ERROR,
14009 "MySQL is trying to set transactional table lock "
14010 "with corrupted lock type to table %s, lock type "
14011 "%d does not exist.",
14012 table->s->table_name.str, lock_type);
14013
14014 DBUG_RETURN(HA_ERR_CRASHED);
14015 }
14016
14017 /* MySQL is setting a new transactional table lock */
14018
14019 innobase_register_trx(ht, thd, trx);
14020
14021 if (THDVAR(thd, table_locks) && thd_in_lock_tables(thd)) {
14022 dberr_t error;
14023
14024 error = row_lock_table_for_mysql(prebuilt, NULL, 0);
14025
14026 if (error != DB_SUCCESS) {
14027 DBUG_RETURN(
14028 convert_error_code_to_mysql(
14029 error, prebuilt->table->flags, thd));
14030 }
14031
14032 if (thd_test_options(
14033 thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
14034
14035 /* Store the current undo_no of the transaction
14036 so that we know where to roll back if we have
14037 to roll back the next SQL statement */
14038
14039 trx_mark_sql_stat_end(trx);
14040 }
14041 }
14042
14043 DBUG_RETURN(0);
14044 }
14045
14046 /************************************************************************//**
14047 Here we export InnoDB status variables to MySQL. */
14048 static
14049 void
innodb_export_status()14050 innodb_export_status()
14051 /*==================*/
14052 {
14053 if (innodb_inited) {
14054 srv_export_innodb_status();
14055 }
14056 }
14057
14058 /************************************************************************//**
14059 Implements the SHOW ENGINE INNODB STATUS command. Sends the output of the
14060 InnoDB Monitor to the client.
14061 @return 0 on success */
14062 static
14063 int
innodb_show_status(handlerton * hton,THD * thd,stat_print_fn * stat_print)14064 innodb_show_status(
14065 /*===============*/
14066 handlerton* hton, /*!< in: the innodb handlerton */
14067 THD* thd, /*!< in: the MySQL query thread of the caller */
14068 stat_print_fn* stat_print)
14069 {
14070 trx_t* trx;
14071 static const char truncated_msg[] = "... truncated...\n";
14072 const long MAX_STATUS_SIZE = 1048576;
14073 ulint trx_list_start = ULINT_UNDEFINED;
14074 ulint trx_list_end = ULINT_UNDEFINED;
14075 bool ret_val;
14076
14077 DBUG_ENTER("innodb_show_status");
14078 DBUG_ASSERT(hton == innodb_hton_ptr);
14079
14080 /* We don't create the temp files or associated
14081 mutexes in read-only-mode */
14082
14083 if (srv_read_only_mode) {
14084 DBUG_RETURN(0);
14085 }
14086
14087 trx = check_trx_exists(thd);
14088
14089 trx_search_latch_release_if_reserved(trx);
14090
14091 innobase_srv_conc_force_exit_innodb(trx);
14092
14093 /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
14094 bytes of text. */
14095
14096 char* str;
14097 ssize_t flen, usable_len;
14098
14099 mutex_enter(&srv_monitor_file_mutex);
14100 rewind(srv_monitor_file);
14101
14102 srv_printf_innodb_monitor(srv_monitor_file, FALSE,
14103 &trx_list_start, &trx_list_end);
14104
14105 os_file_set_eof(srv_monitor_file);
14106
14107 if ((flen = ftell(srv_monitor_file)) < 0) {
14108 flen = 0;
14109 }
14110
14111 if (flen > MAX_STATUS_SIZE) {
14112 usable_len = MAX_STATUS_SIZE;
14113 srv_truncated_status_writes++;
14114 } else {
14115 usable_len = flen;
14116 }
14117
14118 /* allocate buffer for the string, and
14119 read the contents of the temporary file */
14120
14121 if (!(str = (char*) my_malloc(usable_len + 1, MYF(0)))) {
14122 mutex_exit(&srv_monitor_file_mutex);
14123 DBUG_RETURN(1);
14124 }
14125
14126 rewind(srv_monitor_file);
14127
14128 if (flen < MAX_STATUS_SIZE) {
14129 /* Display the entire output. */
14130 flen = fread(str, 1, flen, srv_monitor_file);
14131 } else if (trx_list_end < (ulint) flen
14132 && trx_list_start < trx_list_end
14133 && trx_list_start + (flen - trx_list_end)
14134 < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
14135
14136 /* Omit the beginning of the list of active transactions. */
14137 ssize_t len = fread(str, 1, trx_list_start, srv_monitor_file);
14138
14139 memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
14140 len += sizeof truncated_msg - 1;
14141 usable_len = (MAX_STATUS_SIZE - 1) - len;
14142 fseek(srv_monitor_file,
14143 static_cast<long>(flen - usable_len), SEEK_SET);
14144 len += fread(str + len, 1, usable_len, srv_monitor_file);
14145 flen = len;
14146 } else {
14147 /* Omit the end of the output. */
14148 flen = fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
14149 }
14150
14151 mutex_exit(&srv_monitor_file_mutex);
14152
14153 ret_val= stat_print(
14154 thd, innobase_hton_name,
14155 static_cast<uint>(strlen(innobase_hton_name)),
14156 STRING_WITH_LEN(""), str, static_cast<uint>(flen));
14157
14158 my_free(str);
14159
14160 DBUG_RETURN(ret_val);
14161 }
14162
14163 /************************************************************************//**
14164 Implements the SHOW MUTEX STATUS command.
14165 @return 0 on success. */
14166 static
14167 int
innodb_mutex_show_status(handlerton * hton,THD * thd,stat_print_fn * stat_print)14168 innodb_mutex_show_status(
14169 /*=====================*/
14170 handlerton* hton, /*!< in: the innodb handlerton */
14171 THD* thd, /*!< in: the MySQL query thread of the
14172 caller */
14173 stat_print_fn* stat_print) /*!< in: function for printing
14174 statistics */
14175 {
14176 char buf1[IO_SIZE];
14177 char buf2[IO_SIZE];
14178 ib_mutex_t* mutex;
14179 rw_lock_t* lock;
14180 ulint block_mutex_oswait_count = 0;
14181 ulint block_lock_oswait_count = 0;
14182 ib_mutex_t* block_mutex = NULL;
14183 rw_lock_t* block_lock = NULL;
14184 #ifdef UNIV_DEBUG
14185 ulint rw_lock_count= 0;
14186 ulint rw_lock_count_spin_loop= 0;
14187 ulint rw_lock_count_spin_rounds= 0;
14188 ulint rw_lock_count_os_wait= 0;
14189 ulint rw_lock_count_os_yield= 0;
14190 ulonglong rw_lock_wait_time= 0;
14191 #endif /* UNIV_DEBUG */
14192 uint buf1len;
14193 uint buf2len;
14194 uint hton_name_len;
14195
14196 hton_name_len = (uint) strlen(innobase_hton_name);
14197
14198 DBUG_ENTER("innodb_mutex_show_status");
14199 DBUG_ASSERT(hton == innodb_hton_ptr);
14200
14201 mutex_enter(&mutex_list_mutex);
14202
14203 for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL;
14204 mutex = UT_LIST_GET_NEXT(list, mutex)) {
14205 if (mutex->count_os_wait == 0) {
14206 continue;
14207 }
14208
14209 if (buf_pool_is_block_mutex(mutex)) {
14210 block_mutex = mutex;
14211 block_mutex_oswait_count += mutex->count_os_wait;
14212 continue;
14213 }
14214
14215 buf1len= (uint) my_snprintf(buf1, sizeof(buf1), "%s",
14216 mutex->cmutex_name);
14217 buf2len= (uint) my_snprintf(buf2, sizeof(buf2), "os_waits=%lu",
14218 (ulong) mutex->count_os_wait);
14219
14220 if (stat_print(thd, innobase_hton_name,
14221 hton_name_len, buf1, buf1len,
14222 buf2, buf2len)) {
14223 mutex_exit(&mutex_list_mutex);
14224 DBUG_RETURN(1);
14225 }
14226 }
14227
14228 if (block_mutex) {
14229 buf1len = (uint) my_snprintf(buf1, sizeof buf1,
14230 "combined %s",
14231 block_mutex->cmutex_name);
14232 buf2len = (uint) my_snprintf(buf2, sizeof buf2,
14233 "os_waits=%lu",
14234 (ulong) block_mutex_oswait_count);
14235
14236 if (stat_print(thd, innobase_hton_name,
14237 hton_name_len, buf1, buf1len,
14238 buf2, buf2len)) {
14239 mutex_exit(&mutex_list_mutex);
14240 DBUG_RETURN(1);
14241 }
14242 }
14243
14244 mutex_exit(&mutex_list_mutex);
14245
14246 mutex_enter(&rw_lock_list_mutex);
14247
14248 for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
14249 lock = UT_LIST_GET_NEXT(list, lock)) {
14250 if (lock->count_os_wait == 0) {
14251 continue;
14252 }
14253
14254 if (buf_pool_is_block_lock(lock)) {
14255 block_lock = lock;
14256 block_lock_oswait_count += lock->count_os_wait;
14257 continue;
14258 }
14259
14260 buf1len = (uint) my_snprintf(
14261 buf1, sizeof buf1, "%s",
14262 lock->lock_name);
14263 buf2len = (uint) my_snprintf(
14264 buf2, sizeof buf2, "os_waits=%lu",
14265 static_cast<ulong>(lock->count_os_wait));
14266
14267 if (stat_print(thd, innobase_hton_name,
14268 hton_name_len, buf1, buf1len,
14269 buf2, buf2len)) {
14270 mutex_exit(&rw_lock_list_mutex);
14271 DBUG_RETURN(1);
14272 }
14273 }
14274
14275 if (block_lock) {
14276 buf1len = (uint) my_snprintf(buf1, sizeof buf1,
14277 "combined %s",
14278 block_lock->lock_name);
14279 buf2len = (uint) my_snprintf(buf2, sizeof buf2,
14280 "os_waits=%lu",
14281 (ulong) block_lock_oswait_count);
14282
14283 if (stat_print(thd, innobase_hton_name,
14284 hton_name_len, buf1, buf1len,
14285 buf2, buf2len)) {
14286 mutex_exit(&rw_lock_list_mutex);
14287 DBUG_RETURN(1);
14288 }
14289 }
14290
14291 mutex_exit(&rw_lock_list_mutex);
14292
14293 #ifdef UNIV_DEBUG
14294 buf2len = static_cast<uint>(my_snprintf(buf2, sizeof buf2,
14295 "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
14296 "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
14297 (ulong) rw_lock_count,
14298 (ulong) rw_lock_count_spin_loop,
14299 (ulong) rw_lock_count_spin_rounds,
14300 (ulong) rw_lock_count_os_wait,
14301 (ulong) rw_lock_count_os_yield,
14302 (ulong) (rw_lock_wait_time / 1000)));
14303
14304 if (stat_print(thd, innobase_hton_name, hton_name_len,
14305 STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
14306 DBUG_RETURN(1);
14307 }
14308 #endif /* UNIV_DEBUG */
14309
14310 /* Success */
14311 DBUG_RETURN(0);
14312 }
14313
14314 /************************************************************************//**
14315 Return 0 on success and non-zero on failure. Note: the bool return type
14316 seems to be abused here, should be an int. */
14317 static
14318 bool
innobase_show_status(handlerton * hton,THD * thd,stat_print_fn * stat_print,enum ha_stat_type stat_type)14319 innobase_show_status(
14320 /*=================*/
14321 handlerton* hton, /*!< in: the innodb handlerton */
14322 THD* thd, /*!< in: the MySQL query thread
14323 of the caller */
14324 stat_print_fn* stat_print,
14325 enum ha_stat_type stat_type)
14326 {
14327 DBUG_ASSERT(hton == innodb_hton_ptr);
14328
14329 switch (stat_type) {
14330 case HA_ENGINE_STATUS:
14331 /* Non-zero return value means there was an error. */
14332 return(innodb_show_status(hton, thd, stat_print) != 0);
14333
14334 case HA_ENGINE_MUTEX:
14335 /* Non-zero return value means there was an error. */
14336 return(innodb_mutex_show_status(hton, thd, stat_print) != 0);
14337
14338 case HA_ENGINE_LOGS:
14339 /* Not handled */
14340 break;
14341 }
14342
14343 /* Success */
14344 return(false);
14345 }
14346
14347 /************************************************************************//**
14348 Handling the shared INNOBASE_SHARE structure that is needed to provide table
14349 locking. Register the table name if it doesn't exist in the hash table. */
14350 static
14351 INNOBASE_SHARE*
get_share(const char * table_name)14352 get_share(
14353 /*======*/
14354 const char* table_name)
14355 {
14356 INNOBASE_SHARE* share;
14357
14358 mysql_mutex_lock(&innobase_share_mutex);
14359
14360 ulint fold = ut_fold_string(table_name);
14361
14362 HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
14363 INNOBASE_SHARE*, share,
14364 ut_ad(share->use_count > 0),
14365 !strcmp(share->table_name, table_name));
14366
14367 if (!share) {
14368
14369 uint length = (uint) strlen(table_name);
14370
14371 /* TODO: invoke HASH_MIGRATE if innobase_open_tables
14372 grows too big */
14373
14374 share = (INNOBASE_SHARE*) my_malloc(sizeof(*share)+length+1,
14375 MYF(MY_FAE | MY_ZEROFILL));
14376
14377 share->table_name = (char*) memcpy(share + 1,
14378 table_name, length + 1);
14379
14380 HASH_INSERT(INNOBASE_SHARE, table_name_hash,
14381 innobase_open_tables, fold, share);
14382
14383 thr_lock_init(&share->lock);
14384
14385 /* Index translation table initialization */
14386 share->idx_trans_tbl.index_mapping = NULL;
14387 share->idx_trans_tbl.index_count = 0;
14388 share->idx_trans_tbl.array_size = 0;
14389 }
14390
14391 share->use_count++;
14392 mysql_mutex_unlock(&innobase_share_mutex);
14393
14394 return(share);
14395 }
14396
14397 /************************************************************************//**
14398 Free the shared object that was registered with get_share(). */
14399 static
14400 void
free_share(INNOBASE_SHARE * share)14401 free_share(
14402 /*=======*/
14403 INNOBASE_SHARE* share) /*!< in/own: table share to free */
14404 {
14405 mysql_mutex_lock(&innobase_share_mutex);
14406
14407 #ifdef UNIV_DEBUG
14408 INNOBASE_SHARE* share2;
14409 ulint fold = ut_fold_string(share->table_name);
14410
14411 HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
14412 INNOBASE_SHARE*, share2,
14413 ut_ad(share->use_count > 0),
14414 !strcmp(share->table_name, share2->table_name));
14415
14416 ut_a(share2 == share);
14417 #endif /* UNIV_DEBUG */
14418
14419 if (!--share->use_count) {
14420 ulint fold = ut_fold_string(share->table_name);
14421
14422 HASH_DELETE(INNOBASE_SHARE, table_name_hash,
14423 innobase_open_tables, fold, share);
14424 thr_lock_delete(&share->lock);
14425
14426 /* Free any memory from index translation table */
14427 my_free(share->idx_trans_tbl.index_mapping);
14428
14429 my_free(share);
14430
14431 /* TODO: invoke HASH_MIGRATE if innobase_open_tables
14432 shrinks too much */
14433 }
14434
14435 mysql_mutex_unlock(&innobase_share_mutex);
14436 }
14437
14438 /*****************************************************************//**
14439 Converts a MySQL table lock stored in the 'lock' field of the handle to
14440 a proper type before storing pointer to the lock into an array of pointers.
14441 MySQL also calls this if it wants to reset some table locks to a not-locked
14442 state during the processing of an SQL query. An example is that during a
14443 SELECT the read lock is released early on the 'const' tables where we only
14444 fetch one row. MySQL does not call this when it releases all locks at the
14445 end of an SQL statement.
14446 @return pointer to the next element in the 'to' array */
14447 UNIV_INTERN
14448 THR_LOCK_DATA**
store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)14449 ha_innobase::store_lock(
14450 /*====================*/
14451 THD* thd, /*!< in: user thread handle */
14452 THR_LOCK_DATA** to, /*!< in: pointer to an array
14453 of pointers to lock structs;
14454 pointer to the 'lock' field
14455 of current handle is stored
14456 next to this array */
14457 enum thr_lock_type lock_type) /*!< in: lock type to store in
14458 'lock'; this may also be
14459 TL_IGNORE */
14460 {
14461 trx_t* trx;
14462
14463 /* Note that trx in this function is NOT necessarily prebuilt->trx
14464 because we call update_thd() later, in ::external_lock()! Failure to
14465 understand this caused a serious memory corruption bug in 5.1.11. */
14466
14467 trx = check_trx_exists(thd);
14468
14469 /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
14470 Be careful to ignore TL_IGNORE if we are going to do something with
14471 only 'real' locks! */
14472
14473 /* If no MySQL table is in use, we need to set the isolation level
14474 of the transaction. */
14475
14476 if (lock_type != TL_IGNORE
14477 && trx->n_mysql_tables_in_use == 0) {
14478 trx->isolation_level = innobase_map_isolation_level(
14479 (enum_tx_isolation) thd_tx_isolation(thd));
14480
14481 if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
14482 && trx->global_read_view) {
14483
14484 /* At low transaction isolation levels we let
14485 each consistent read set its own snapshot */
14486
14487 read_view_close_for_mysql(trx);
14488 }
14489 }
14490
14491 DBUG_ASSERT(EQ_CURRENT_THD(thd));
14492 const bool in_lock_tables = thd_in_lock_tables(thd);
14493 const uint sql_command = thd_sql_command(thd);
14494
14495 if (srv_read_only_mode
14496 && (sql_command == SQLCOM_UPDATE
14497 || sql_command == SQLCOM_INSERT
14498 || sql_command == SQLCOM_REPLACE
14499 || sql_command == SQLCOM_DROP_TABLE
14500 || sql_command == SQLCOM_ALTER_TABLE
14501 || sql_command == SQLCOM_OPTIMIZE
14502 || (sql_command == SQLCOM_CREATE_TABLE
14503 && (lock_type >= TL_WRITE_CONCURRENT_INSERT
14504 && lock_type <= TL_WRITE))
14505 || sql_command == SQLCOM_CREATE_INDEX
14506 || sql_command == SQLCOM_DROP_INDEX
14507 || sql_command == SQLCOM_DELETE
14508 || sql_command == SQLCOM_CREATE_COMPRESSION_DICTIONARY
14509 || sql_command == SQLCOM_DROP_COMPRESSION_DICTIONARY)) {
14510
14511 ib_senderrf(trx->mysql_thd,
14512 IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
14513
14514 } else if (sql_command == SQLCOM_FLUSH
14515 && lock_type == TL_READ_NO_INSERT) {
14516
14517 /* Check for FLUSH TABLES ... WITH READ LOCK */
14518
14519 /* Note: This call can fail, but there is no way to return
14520 the error to the caller. We simply ignore it for now here
14521 and push the error code to the caller where the error is
14522 detected in the function. */
14523
14524 dberr_t err = row_quiesce_set_state(
14525 prebuilt->table, QUIESCE_START, trx);
14526
14527 ut_a(err == DB_SUCCESS || err == DB_UNSUPPORTED);
14528
14529 if (trx->isolation_level == TRX_ISO_SERIALIZABLE) {
14530 prebuilt->select_lock_type = LOCK_S;
14531 prebuilt->stored_select_lock_type = LOCK_S;
14532 } else {
14533 prebuilt->select_lock_type = LOCK_NONE;
14534 prebuilt->stored_select_lock_type = LOCK_NONE;
14535 }
14536
14537 /* Check for DROP TABLE */
14538 } else if (sql_command == SQLCOM_DROP_TABLE) {
14539
14540 /* MySQL calls this function in DROP TABLE though this table
14541 handle may belong to another thd that is running a query. Let
14542 us in that case skip any changes to the prebuilt struct. */
14543
14544 /* Check for LOCK TABLE t1,...,tn WITH SHARED LOCKS */
14545 } else if ((lock_type == TL_READ && in_lock_tables)
14546 || (lock_type == TL_READ_HIGH_PRIORITY && in_lock_tables)
14547 || lock_type == TL_READ_WITH_SHARED_LOCKS
14548 || lock_type == TL_READ_NO_INSERT
14549 || (lock_type != TL_IGNORE
14550 && sql_command != SQLCOM_SELECT)) {
14551
14552 /* The OR cases above are in this order:
14553 1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
14554 are processing a stored procedure or function, or
14555 2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
14556 3) this is a SELECT ... IN SHARE MODE, or
14557 4) we are doing a complex SQL statement like
14558 INSERT INTO ... SELECT ... and the logical logging (MySQL
14559 binlog) requires the use of a locking read, or
14560 MySQL is doing LOCK TABLES ... READ.
14561 5) we let InnoDB do locking reads for all SQL statements that
14562 are not simple SELECTs; note that select_lock_type in this
14563 case may get strengthened in ::external_lock() to LOCK_X.
14564 Note that we MUST use a locking read in all data modifying
14565 SQL statements, because otherwise the execution would not be
14566 serializable, and also the results from the update could be
14567 unexpected if an obsolete consistent read view would be
14568 used. */
14569
14570 /* Use consistent read for checksum table */
14571
14572 if (sql_command == SQLCOM_CHECKSUM
14573 || ((srv_locks_unsafe_for_binlog
14574 || trx->isolation_level <= TRX_ISO_READ_COMMITTED)
14575 && trx->isolation_level != TRX_ISO_SERIALIZABLE
14576 && (lock_type == TL_READ
14577 || lock_type == TL_READ_NO_INSERT)
14578 && (sql_command == SQLCOM_INSERT_SELECT
14579 || sql_command == SQLCOM_REPLACE_SELECT
14580 || sql_command == SQLCOM_UPDATE
14581 || sql_command == SQLCOM_CREATE_TABLE))) {
14582
14583 /* If we either have innobase_locks_unsafe_for_binlog
14584 option set or this session is using READ COMMITTED
14585 isolation level and isolation level of the transaction
14586 is not set to serializable and MySQL is doing
14587 INSERT INTO...SELECT or REPLACE INTO...SELECT
14588 or UPDATE ... = (SELECT ...) or CREATE ...
14589 SELECT... without FOR UPDATE or IN SHARE
14590 MODE in select, then we use consistent read
14591 for select. */
14592
14593 prebuilt->select_lock_type = LOCK_NONE;
14594 prebuilt->stored_select_lock_type = LOCK_NONE;
14595 } else {
14596 prebuilt->select_lock_type = LOCK_S;
14597 prebuilt->stored_select_lock_type = LOCK_S;
14598 }
14599
14600 } else if (lock_type != TL_IGNORE) {
14601
14602 /* We set possible LOCK_X value in external_lock, not yet
14603 here even if this would be SELECT ... FOR UPDATE */
14604
14605 prebuilt->select_lock_type = LOCK_NONE;
14606 prebuilt->stored_select_lock_type = LOCK_NONE;
14607 }
14608
14609 if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
14610
14611 /* Starting from 5.0.7, we weaken also the table locks
14612 set at the start of a MySQL stored procedure call, just like
14613 we weaken the locks set at the start of an SQL statement.
14614 MySQL does set in_lock_tables TRUE there, but in reality
14615 we do not need table locks to make the execution of a
14616 single transaction stored procedure call deterministic
14617 (if it does not use a consistent read). */
14618
14619 if (lock_type == TL_READ
14620 && sql_command == SQLCOM_LOCK_TABLES) {
14621 /* We come here if MySQL is processing LOCK TABLES
14622 ... READ LOCAL. MyISAM under that table lock type
14623 reads the table as it was at the time the lock was
14624 granted (new inserts are allowed, but not seen by the
14625 reader). To get a similar effect on an InnoDB table,
14626 we must use LOCK TABLES ... READ. We convert the lock
14627 type here, so that for InnoDB, READ LOCAL is
14628 equivalent to READ. This will change the InnoDB
14629 behavior in mysqldump, so that dumps of InnoDB tables
14630 are consistent with dumps of MyISAM tables. */
14631
14632 lock_type = TL_READ_NO_INSERT;
14633 }
14634
14635 /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
14636 TABLESPACE or TRUNCATE TABLE then allow multiple
14637 writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
14638 < TL_WRITE_CONCURRENT_INSERT.
14639
14640 We especially allow multiple writers if MySQL is at the
14641 start of a stored procedure call (SQLCOM_CALL) or a
14642 stored function call (MySQL does have in_lock_tables
14643 TRUE there). */
14644
14645 if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
14646 && lock_type <= TL_WRITE)
14647 && !(in_lock_tables
14648 && sql_command == SQLCOM_LOCK_TABLES)
14649 && !thd_tablespace_op(thd)
14650 && sql_command != SQLCOM_TRUNCATE
14651 && sql_command != SQLCOM_OPTIMIZE
14652 && sql_command != SQLCOM_CREATE_TABLE) {
14653
14654 lock_type = TL_WRITE_ALLOW_WRITE;
14655 }
14656
14657 /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
14658 MySQL would use the lock TL_READ_NO_INSERT on t2, and that
14659 would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
14660 to t2. Convert the lock to a normal read lock to allow
14661 concurrent inserts to t2.
14662
14663 We especially allow concurrent inserts if MySQL is at the
14664 start of a stored procedure call (SQLCOM_CALL)
14665 (MySQL does have thd_in_lock_tables() TRUE there). */
14666
14667 if (lock_type == TL_READ_NO_INSERT
14668 && sql_command != SQLCOM_LOCK_TABLES) {
14669
14670 lock_type = TL_READ;
14671 }
14672
14673 lock.type = lock_type;
14674 }
14675
14676 *to++= &lock;
14677
14678 if (!trx_is_started(trx)
14679 && (prebuilt->select_lock_type != LOCK_NONE
14680 || prebuilt->stored_select_lock_type != LOCK_NONE)) {
14681
14682 ++trx->will_lock;
14683 }
14684
14685 return(to);
14686 }
14687
14688 /*********************************************************************//**
14689 Read the next autoinc value. Acquire the relevant locks before reading
14690 the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
14691 on return and all relevant locks acquired.
14692 @return DB_SUCCESS or error code */
14693 UNIV_INTERN
14694 dberr_t
innobase_get_autoinc(ulonglong * value)14695 ha_innobase::innobase_get_autoinc(
14696 /*==============================*/
14697 ulonglong* value) /*!< out: autoinc value */
14698 {
14699 *value = 0;
14700
14701 prebuilt->autoinc_error = innobase_lock_autoinc();
14702
14703 if (prebuilt->autoinc_error == DB_SUCCESS) {
14704
14705 /* Determine the first value of the interval */
14706 *value = dict_table_autoinc_read(prebuilt->table);
14707
14708 /* It should have been initialized during open. */
14709 if (*value == 0) {
14710 prebuilt->autoinc_error = DB_UNSUPPORTED;
14711 dict_table_autoinc_unlock(prebuilt->table);
14712 }
14713 }
14714
14715 return(prebuilt->autoinc_error);
14716 }
14717
14718 /*******************************************************************//**
14719 This function reads the global auto-inc counter. It doesn't use the
14720 AUTOINC lock even if the lock mode is set to TRADITIONAL.
14721 @return the autoinc value */
14722 UNIV_INTERN
14723 ulonglong
innobase_peek_autoinc(void)14724 ha_innobase::innobase_peek_autoinc(void)
14725 /*====================================*/
14726 {
14727 ulonglong auto_inc;
14728 dict_table_t* innodb_table;
14729
14730 ut_a(prebuilt != NULL);
14731 ut_a(prebuilt->table != NULL);
14732
14733 innodb_table = prebuilt->table;
14734
14735 dict_table_autoinc_lock(innodb_table);
14736
14737 auto_inc = dict_table_autoinc_read(innodb_table);
14738
14739 if (auto_inc == 0) {
14740 ut_print_timestamp(stderr);
14741 fprintf(stderr, " InnoDB: AUTOINC next value generation "
14742 "is disabled for '%s'\n", innodb_table->name);
14743 }
14744
14745 dict_table_autoinc_unlock(innodb_table);
14746
14747 return(auto_inc);
14748 }
14749
14750 /*********************************************************************//**
14751 Returns the value of the auto-inc counter in *first_value and ~0 on failure. */
14752 UNIV_INTERN
14753 void
get_auto_increment(ulonglong offset,ulonglong increment,ulonglong nb_desired_values,ulonglong * first_value,ulonglong * nb_reserved_values)14754 ha_innobase::get_auto_increment(
14755 /*============================*/
14756 ulonglong offset, /*!< in: table autoinc offset */
14757 ulonglong increment, /*!< in: table autoinc
14758 increment */
14759 ulonglong nb_desired_values, /*!< in: number of values
14760 reqd */
14761 ulonglong* first_value, /*!< out: the autoinc value */
14762 ulonglong* nb_reserved_values) /*!< out: count of reserved
14763 values */
14764 {
14765 trx_t* trx;
14766 dberr_t error;
14767 ulonglong autoinc = 0;
14768
14769 /* Prepare prebuilt->trx in the table handle */
14770 update_thd(ha_thd());
14771
14772 error = innobase_get_autoinc(&autoinc);
14773
14774 if (error != DB_SUCCESS) {
14775 *first_value = (~(ulonglong) 0);
14776 return;
14777 }
14778
14779 /* This is a hack, since nb_desired_values seems to be accurate only
14780 for the first call to get_auto_increment() for multi-row INSERT and
14781 meaningless for other statements e.g, LOAD etc. Subsequent calls to
14782 this method for the same statement results in different values which
14783 don't make sense. Therefore we store the value the first time we are
14784 called and count down from that as rows are written (see write_row()).
14785 */
14786
14787 trx = prebuilt->trx;
14788
14789 /* Note: We can't rely on *first_value since some MySQL engines,
14790 in particular the partition engine, don't initialize it to 0 when
14791 invoking this method. So we are not sure if it's guaranteed to
14792 be 0 or not. */
14793
14794 /* We need the upper limit of the col type to check for
14795 whether we update the table autoinc counter or not. */
14796 ulonglong col_max_value = innobase_get_int_col_max_value(
14797 table->next_number_field);
14798
14799 /** The following logic is needed to avoid duplicate key error
14800 for autoincrement column.
14801
14802 (1) InnoDB gives the current autoincrement value with respect
14803 to increment and offset value.
14804
14805 (2) Basically it does compute_next_insert_id() logic inside InnoDB
14806 to avoid the current auto increment value changed by handler layer.
14807
14808 (3) It is restricted only for insert operations. */
14809
14810 if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE
14811 && autoinc < col_max_value) {
14812
14813 ulonglong prev_auto_inc = autoinc;
14814
14815 autoinc = ((autoinc - 1) + increment - offset)/ increment;
14816
14817 autoinc = autoinc * increment + offset;
14818
14819 /* If autoinc exceeds the col_max_value then reset
14820 to old autoinc value. Because in case of non-strict
14821 sql mode, boundary value is not considered as error. */
14822
14823 if (autoinc >= col_max_value) {
14824 autoinc = prev_auto_inc;
14825 }
14826
14827 ut_ad(autoinc > 0);
14828 }
14829
14830 /* Called for the first time ? */
14831 if (trx->n_autoinc_rows == 0) {
14832
14833 trx->n_autoinc_rows = (ulint) nb_desired_values;
14834
14835 /* It's possible for nb_desired_values to be 0:
14836 e.g., INSERT INTO T1(C) SELECT C FROM T2; */
14837 if (nb_desired_values == 0) {
14838
14839 trx->n_autoinc_rows = 1;
14840 }
14841
14842 set_if_bigger(*first_value, autoinc);
14843 /* Not in the middle of a mult-row INSERT. */
14844 } else if (prebuilt->autoinc_last_value == 0) {
14845 set_if_bigger(*first_value, autoinc);
14846 /* Check for -ve values. */
14847 } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
14848 /* Set to next logical value. */
14849 ut_a(autoinc > trx->n_autoinc_rows);
14850 *first_value = (autoinc - trx->n_autoinc_rows) - 1;
14851 }
14852
14853 *nb_reserved_values = trx->n_autoinc_rows;
14854
14855 /* With old style AUTOINC locking we only update the table's
14856 AUTOINC counter after attempting to insert the row. */
14857 if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
14858 ulonglong current;
14859 ulonglong next_value;
14860
14861 current = *first_value > col_max_value ? autoinc : *first_value;
14862
14863 /* Compute the last value in the interval */
14864 next_value = innobase_next_autoinc(
14865 current, *nb_reserved_values, increment, offset,
14866 col_max_value);
14867
14868 prebuilt->autoinc_last_value = next_value;
14869
14870 if (prebuilt->autoinc_last_value < *first_value) {
14871 *first_value = (~(ulonglong) 0);
14872 } else {
14873 /* Update the table autoinc variable */
14874 dict_table_autoinc_update_if_greater(
14875 prebuilt->table, prebuilt->autoinc_last_value);
14876 }
14877 } else {
14878 /* This will force write_row() into attempting an update
14879 of the table's AUTOINC counter. */
14880 prebuilt->autoinc_last_value = 0;
14881 }
14882
14883 /* The increment to be used to increase the AUTOINC value, we use
14884 this in write_row() and update_row() to increase the autoinc counter
14885 for columns that are filled by the user. We need the offset and
14886 the increment. */
14887 prebuilt->autoinc_offset = offset;
14888 prebuilt->autoinc_increment = increment;
14889
14890 dict_table_autoinc_unlock(prebuilt->table);
14891 }
14892
14893 /*******************************************************************//**
14894 Reset the auto-increment counter to the given value, i.e. the next row
14895 inserted will get the given value. This is called e.g. after TRUNCATE
14896 is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
14897 returned by storage engines that don't support this operation.
14898 @return 0 or error code */
14899 UNIV_INTERN
14900 int
reset_auto_increment(ulonglong value)14901 ha_innobase::reset_auto_increment(
14902 /*==============================*/
14903 ulonglong value) /*!< in: new value for table autoinc */
14904 {
14905 DBUG_ENTER("ha_innobase::reset_auto_increment");
14906
14907 dberr_t error;
14908
14909 update_thd(ha_thd());
14910
14911 error = row_lock_table_autoinc_for_mysql(prebuilt);
14912
14913 if (error != DB_SUCCESS) {
14914 DBUG_RETURN(convert_error_code_to_mysql(
14915 error, prebuilt->table->flags, user_thd));
14916 }
14917
14918 /* The next value can never be 0. */
14919 if (value == 0) {
14920 value = 1;
14921 }
14922
14923 innobase_reset_autoinc(value);
14924
14925 DBUG_RETURN(0);
14926 }
14927
14928 /*******************************************************************//**
14929 See comment in handler.cc */
14930 UNIV_INTERN
14931 bool
get_error_message(int error,String * buf)14932 ha_innobase::get_error_message(
14933 /*===========================*/
14934 int error,
14935 String* buf)
14936 {
14937 trx_t* trx = check_trx_exists(ha_thd());
14938
14939 buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
14940 system_charset_info);
14941
14942 return(FALSE);
14943 }
14944
14945 /*******************************************************************//**
14946 Retrieves the names of the table and the key for which there was a
14947 duplicate entry in the case of HA_ERR_FOREIGN_DUPLICATE_KEY.
14948
14949 If any of the names is not available, then this method will return
14950 false and will not change any of child_table_name or child_key_name.
14951
14952 @param child_table_name[out] Table name
14953 @param child_table_name_len[in] Table name buffer size
14954 @param child_key_name[out] Key name
14955 @param child_key_name_len[in] Key name buffer size
14956
14957 @retval true table and key names were available
14958 and were written into the corresponding
14959 out parameters.
14960 @retval false table and key names were not available,
14961 the out parameters were not touched.
14962 */
14963 bool
get_foreign_dup_key(char * child_table_name,uint child_table_name_len,char * child_key_name,uint child_key_name_len)14964 ha_innobase::get_foreign_dup_key(
14965 /*=============================*/
14966 char* child_table_name,
14967 uint child_table_name_len,
14968 char* child_key_name,
14969 uint child_key_name_len)
14970 {
14971 const dict_index_t* err_index;
14972
14973 ut_a(prebuilt->trx != NULL);
14974 ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
14975
14976 err_index = trx_get_error_info(prebuilt->trx);
14977
14978 if (err_index == NULL) {
14979 return(false);
14980 }
14981 /* else */
14982
14983 /* copy table name (and convert from filename-safe encoding to
14984 system_charset_info) */
14985 char* p;
14986 p = strchr(err_index->table->name, '/');
14987 /* strip ".../" prefix if any */
14988 if (p != NULL) {
14989 p++;
14990 } else {
14991 p = err_index->table->name;
14992 }
14993 uint len;
14994 len = filename_to_tablename(p, child_table_name, child_table_name_len);
14995 child_table_name[len] = '\0';
14996
14997 /* copy index name */
14998 ut_snprintf(child_key_name, child_key_name_len, "%s", err_index->name);
14999
15000 return(true);
15001 }
15002
15003 /*******************************************************************//**
15004 Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
15005 If there is no explicitly declared non-null unique key or a primary key, then
15006 InnoDB internally uses the row id as the primary key.
15007 @return < 0 if ref1 < ref2, 0 if equal, else > 0 */
15008 UNIV_INTERN
15009 int
cmp_ref(const uchar * ref1,const uchar * ref2)15010 ha_innobase::cmp_ref(
15011 /*=================*/
15012 const uchar* ref1, /*!< in: an (internal) primary key value in the
15013 MySQL key value format */
15014 const uchar* ref2) /*!< in: an (internal) primary key value in the
15015 MySQL key value format */
15016 {
15017 enum_field_types mysql_type;
15018 Field* field;
15019 KEY_PART_INFO* key_part;
15020 KEY_PART_INFO* key_part_end;
15021 uint len1;
15022 uint len2;
15023 int result;
15024
15025 if (prebuilt->clust_index_was_generated) {
15026 /* The 'ref' is an InnoDB row id */
15027
15028 return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
15029 }
15030
15031 /* Do a type-aware comparison of primary key fields. PK fields
15032 are always NOT NULL, so no checks for NULL are performed. */
15033
15034 key_part = table->key_info[table->s->primary_key].key_part;
15035
15036 key_part_end = key_part
15037 + table->key_info[table->s->primary_key].user_defined_key_parts;
15038
15039 for (; key_part != key_part_end; ++key_part) {
15040 field = key_part->field;
15041 mysql_type = field->type();
15042
15043 if (mysql_type == MYSQL_TYPE_TINY_BLOB
15044 || mysql_type == MYSQL_TYPE_MEDIUM_BLOB
15045 || mysql_type == MYSQL_TYPE_BLOB
15046 || mysql_type == MYSQL_TYPE_LONG_BLOB) {
15047
15048 /* In the MySQL key value format, a column prefix of
15049 a BLOB is preceded by a 2-byte length field */
15050
15051 len1 = innobase_read_from_2_little_endian(ref1);
15052 len2 = innobase_read_from_2_little_endian(ref2);
15053
15054 result = ((Field_blob*) field)->cmp(
15055 ref1 + 2, len1, ref2 + 2, len2);
15056 } else {
15057 result = field->key_cmp(ref1, ref2);
15058 }
15059
15060 if (result) {
15061
15062 return(result);
15063 }
15064
15065 ref1 += key_part->store_length;
15066 ref2 += key_part->store_length;
15067 }
15068
15069 return(0);
15070 }
15071
15072 /*******************************************************************//**
15073 Ask InnoDB if a query to a table can be cached.
15074 @return TRUE if query caching of the table is permitted */
15075 UNIV_INTERN
15076 my_bool
register_query_cache_table(THD * thd,char * table_key,uint key_length,qc_engine_callback * call_back,ulonglong * engine_data)15077 ha_innobase::register_query_cache_table(
15078 /*====================================*/
15079 THD* thd, /*!< in: user thread handle */
15080 char* table_key, /*!< in: normalized path to the
15081 table */
15082 uint key_length, /*!< in: length of the normalized
15083 path to the table */
15084 qc_engine_callback*
15085 call_back, /*!< out: pointer to function for
15086 checking if query caching
15087 is permitted */
15088 ulonglong *engine_data) /*!< in/out: data to call_back */
15089 {
15090 *call_back = innobase_query_caching_of_table_permitted;
15091 *engine_data = 0;
15092 return(innobase_query_caching_of_table_permitted(thd, table_key,
15093 key_length,
15094 engine_data));
15095 }
15096
15097 /*******************************************************************//**
15098 Get the bin log name. */
15099 UNIV_INTERN
15100 const char*
get_mysql_bin_log_name()15101 ha_innobase::get_mysql_bin_log_name()
15102 /*=================================*/
15103 {
15104 return(trx_sys_mysql_bin_log_name);
15105 }
15106
15107 /*******************************************************************//**
15108 Get the bin log offset (or file position). */
15109 UNIV_INTERN
15110 ulonglong
get_mysql_bin_log_pos()15111 ha_innobase::get_mysql_bin_log_pos()
15112 /*================================*/
15113 {
15114 /* trx... is ib_int64_t, which is a typedef for a 64-bit integer
15115 (__int64 or longlong) so it's ok to cast it to ulonglong. */
15116
15117 return(trx_sys_mysql_bin_log_pos);
15118 }
15119
15120 /******************************************************************//**
15121 This function is used to find the storage length in bytes of the first n
15122 characters for prefix indexes using a multibyte character set. The function
15123 finds charset information and returns length of prefix_len characters in the
15124 index field in bytes.
15125 @return number of bytes occupied by the first n characters */
15126 UNIV_INTERN
15127 ulint
innobase_get_at_most_n_mbchars(ulint charset_id,ulint prefix_len,ulint data_len,const char * str)15128 innobase_get_at_most_n_mbchars(
15129 /*===========================*/
15130 ulint charset_id, /*!< in: character set id */
15131 ulint prefix_len, /*!< in: prefix length in bytes of the index
15132 (this has to be divided by mbmaxlen to get the
15133 number of CHARACTERS n in the prefix) */
15134 ulint data_len, /*!< in: length of the string in bytes */
15135 const char* str) /*!< in: character string */
15136 {
15137 ulint char_length; /*!< character length in bytes */
15138 ulint n_chars; /*!< number of characters in prefix */
15139 CHARSET_INFO* charset; /*!< charset used in the field */
15140
15141 charset = get_charset((uint) charset_id, MYF(MY_WME));
15142
15143 ut_ad(charset);
15144 ut_ad(charset->mbmaxlen);
15145
15146 /* Calculate how many characters at most the prefix index contains */
15147
15148 n_chars = prefix_len / charset->mbmaxlen;
15149
15150 /* If the charset is multi-byte, then we must find the length of the
15151 first at most n chars in the string. If the string contains less
15152 characters than n, then we return the length to the end of the last
15153 character. */
15154
15155 if (charset->mbmaxlen > 1) {
15156 /* my_charpos() returns the byte length of the first n_chars
15157 characters, or a value bigger than the length of str, if
15158 there were not enough full characters in str.
15159
15160 Why does the code below work:
15161 Suppose that we are looking for n UTF-8 characters.
15162
15163 1) If the string is long enough, then the prefix contains at
15164 least n complete UTF-8 characters + maybe some extra
15165 characters + an incomplete UTF-8 character. No problem in
15166 this case. The function returns the pointer to the
15167 end of the nth character.
15168
15169 2) If the string is not long enough, then the string contains
15170 the complete value of a column, that is, only complete UTF-8
15171 characters, and we can store in the column prefix index the
15172 whole string. */
15173
15174 char_length = my_charpos(charset, str,
15175 str + data_len, (int) n_chars);
15176 if (char_length > data_len) {
15177 char_length = data_len;
15178 }
15179 } else {
15180 if (data_len < prefix_len) {
15181 char_length = data_len;
15182 } else {
15183 char_length = prefix_len;
15184 }
15185 }
15186
15187 return(char_length);
15188 }
15189
15190 /*******************************************************************//**
15191 This function is used to prepare an X/Open XA distributed transaction.
15192 @return 0 or error number */
15193 static
15194 int
innobase_xa_prepare(handlerton * hton,THD * thd,bool prepare_trx)15195 innobase_xa_prepare(
15196 /*================*/
15197 handlerton* hton, /*!< in: InnoDB handlerton */
15198 THD* thd, /*!< in: handle to the MySQL thread of
15199 the user whose XA transaction should
15200 be prepared */
15201 bool prepare_trx) /*!< in: true - prepare transaction
15202 false - the current SQL statement
15203 ended */
15204 {
15205 int error = 0;
15206 trx_t* trx = check_trx_exists(thd);
15207
15208 DBUG_ASSERT(hton == innodb_hton_ptr);
15209
15210 /* we use support_xa value as it was seen at transaction start
15211 time, not the current session variable value. Any possible changes
15212 to the session variable take effect only in the next transaction */
15213 if (!trx->support_xa) {
15214
15215 return(0);
15216 }
15217
15218 if (UNIV_UNLIKELY(trx->fake_changes)) {
15219
15220 if (prepare_trx
15221 || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT
15222 | OPTION_BEGIN))) {
15223
15224 thd->get_stmt_da()->reset_diagnostics_area();
15225 return(HA_ERR_WRONG_COMMAND);
15226 }
15227 return(0);
15228 }
15229
15230 thd_get_xid(thd, (MYSQL_XID*) &trx->xid);
15231
15232 /* Release a possible FIFO ticket and search latch. Since we will
15233 reserve the trx_sys->mutex, we have to release the search system
15234 latch first to obey the latching order. */
15235
15236 trx_search_latch_release_if_reserved(trx);
15237
15238 innobase_srv_conc_force_exit_innodb(trx);
15239
15240 if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
15241
15242 sql_print_error("Transaction not registered for MySQL 2PC, "
15243 "but transaction is active");
15244 }
15245
15246 if (prepare_trx
15247 || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
15248
15249 /* We were instructed to prepare the whole transaction, or
15250 this is an SQL statement end and autocommit is on */
15251
15252 ut_ad(trx_is_registered_for_2pc(trx));
15253
15254 trx_prepare_for_mysql(trx);
15255
15256 DBUG_EXECUTE_IF("crash_innodb_after_prepare",
15257 DBUG_SUICIDE(););
15258
15259 error = 0;
15260 } else {
15261 /* We just mark the SQL statement ended and do not do a
15262 transaction prepare */
15263
15264 /* If we had reserved the auto-inc lock for some
15265 table in this SQL statement we release it now */
15266
15267 lock_unlock_table_autoinc(trx);
15268
15269 /* Store the current undo_no of the transaction so that we
15270 know where to roll back if we have to roll back the next
15271 SQL statement */
15272
15273 trx_mark_sql_stat_end(trx);
15274 }
15275
15276 if (thd_sql_command(thd) != SQLCOM_XA_PREPARE
15277 && (prepare_trx
15278 || !thd_test_options(
15279 thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
15280
15281 /* For mysqlbackup to work the order of transactions in binlog
15282 and InnoDB must be the same. Consider the situation
15283
15284 thread1> prepare; write to binlog; ...
15285 <context switch>
15286 thread2> prepare; write to binlog; commit
15287 thread1> ... commit
15288
15289 The server guarantees that writes to the binary log
15290 and commits are in the same order, so we do not have
15291 to handle this case. */
15292 }
15293
15294 return(error);
15295 }
15296
15297 /*******************************************************************//**
15298 This function is used to recover X/Open XA distributed transactions.
15299 @return number of prepared transactions stored in xid_list */
15300 static
15301 int
innobase_xa_recover(handlerton * hton,XID * xid_list,uint len)15302 innobase_xa_recover(
15303 /*================*/
15304 handlerton* hton, /*!< in: InnoDB handlerton */
15305 XID* xid_list,/*!< in/out: prepared transactions */
15306 uint len) /*!< in: number of slots in xid_list */
15307 {
15308 DBUG_ASSERT(hton == innodb_hton_ptr);
15309
15310 if (len == 0 || xid_list == NULL) {
15311
15312 return(0);
15313 }
15314
15315 return(trx_recover_for_mysql(xid_list, len));
15316 }
15317
15318 /*******************************************************************//**
15319 This function is used to commit one X/Open XA distributed transaction
15320 which is in the prepared state
15321 @return 0 or error number */
15322 static
15323 int
innobase_commit_by_xid(handlerton * hton,XID * xid)15324 innobase_commit_by_xid(
15325 /*===================*/
15326 handlerton* hton,
15327 XID* xid) /*!< in: X/Open XA transaction identification */
15328 {
15329 trx_t* trx;
15330
15331 DBUG_ASSERT(hton == innodb_hton_ptr);
15332
15333 trx = trx_get_trx_by_xid(xid);
15334
15335 if (trx) {
15336 innobase_commit_low(trx);
15337 trx_free_for_background(trx);
15338 return(XA_OK);
15339 } else {
15340 return(XAER_NOTA);
15341 }
15342 }
15343
15344 /*******************************************************************//**
15345 This function is used to rollback one X/Open XA distributed transaction
15346 which is in the prepared state
15347 @return 0 or error number */
15348 static
15349 int
innobase_rollback_by_xid(handlerton * hton,XID * xid)15350 innobase_rollback_by_xid(
15351 /*=====================*/
15352 handlerton* hton, /*!< in: InnoDB handlerton */
15353 XID* xid) /*!< in: X/Open XA transaction
15354 identification */
15355 {
15356 trx_t* trx;
15357
15358 DBUG_ASSERT(hton == innodb_hton_ptr);
15359
15360 trx = trx_get_trx_by_xid(xid);
15361
15362 if (trx) {
15363 int ret = innobase_rollback_trx(trx);
15364 trx_free_for_background(trx);
15365 return(ret);
15366 } else {
15367 return(XAER_NOTA);
15368 }
15369 }
15370
15371 /*******************************************************************//**
15372 Create a consistent view for a cursor based on current transaction
15373 which is created if the corresponding MySQL thread still lacks one.
15374 This consistent view is then used inside of MySQL when accessing records
15375 using a cursor.
15376 @return pointer to cursor view or NULL */
15377 static
15378 void*
innobase_create_cursor_view(handlerton * hton,THD * thd)15379 innobase_create_cursor_view(
15380 /*========================*/
15381 handlerton* hton, /*!< in: innobase hton */
15382 THD* thd) /*!< in: user thread handle */
15383 {
15384 DBUG_ASSERT(hton == innodb_hton_ptr);
15385
15386 return(read_cursor_view_create_for_mysql(check_trx_exists(thd)));
15387 }
15388
15389 /*******************************************************************//**
15390 Close the given consistent cursor view of a transaction and restore
15391 global read view to a transaction read view. Transaction is created if the
15392 corresponding MySQL thread still lacks one. */
15393 static
15394 void
innobase_close_cursor_view(handlerton * hton,THD * thd,void * curview)15395 innobase_close_cursor_view(
15396 /*=======================*/
15397 handlerton* hton, /*!< in: innobase hton */
15398 THD* thd, /*!< in: user thread handle */
15399 void* curview)/*!< in: Consistent read view to be closed */
15400 {
15401 DBUG_ASSERT(hton == innodb_hton_ptr);
15402
15403 read_cursor_view_close_for_mysql(check_trx_exists(thd),
15404 (cursor_view_t*) curview);
15405 }
15406
15407 /*******************************************************************//**
15408 Set the given consistent cursor view to a transaction which is created
15409 if the corresponding MySQL thread still lacks one. If the given
15410 consistent cursor view is NULL global read view of a transaction is
15411 restored to a transaction read view. */
15412 static
15413 void
innobase_set_cursor_view(handlerton * hton,THD * thd,void * curview)15414 innobase_set_cursor_view(
15415 /*=====================*/
15416 handlerton* hton, /*!< in: innobase hton */
15417 THD* thd, /*!< in: user thread handle */
15418 void* curview)/*!< in: Consistent cursor view to be set */
15419 {
15420 DBUG_ASSERT(hton == innodb_hton_ptr);
15421
15422 read_cursor_set_for_mysql(check_trx_exists(thd),
15423 (cursor_view_t*) curview);
15424 }
15425
15426 /*******************************************************************//**
15427 */
15428 UNIV_INTERN
15429 bool
check_if_incompatible_data(HA_CREATE_INFO * info,uint table_changes)15430 ha_innobase::check_if_incompatible_data(
15431 /*====================================*/
15432 HA_CREATE_INFO* info,
15433 uint table_changes)
15434 {
15435 innobase_copy_frm_flags_from_create_info(prebuilt->table, info);
15436
15437 if (table_changes != IS_EQUAL_YES) {
15438
15439 return(COMPATIBLE_DATA_NO);
15440 }
15441
15442 /* Check that auto_increment value was not changed */
15443 if ((info->used_fields & HA_CREATE_USED_AUTO) &&
15444 info->auto_increment_value != 0) {
15445
15446 return(COMPATIBLE_DATA_NO);
15447 }
15448
15449 /* Check that row format didn't change */
15450 if ((info->used_fields & HA_CREATE_USED_ROW_FORMAT)
15451 && info->row_type != get_row_type()) {
15452
15453 return(COMPATIBLE_DATA_NO);
15454 }
15455
15456 /* Specifying KEY_BLOCK_SIZE requests a rebuild of the table. */
15457 if (info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE) {
15458 return(COMPATIBLE_DATA_NO);
15459 }
15460
15461 return(COMPATIBLE_DATA_YES);
15462 }
15463
15464 /** This function reads zip dict-related info from SYS_ZIP_DICT
15465 and SYS_ZIP_DICT_COLS for all columns marked with
15466 COLUMN_FORMAT_TYPE_COMPRESSED flag and updates
15467 zip_dict_name / zip_dict_data for those which have associated
15468 compression dictionaries.
15469
15470 @param part_name Full table name (including partition part).
15471 Must be non-NULL only if called from ha_partition.
15472 */
15473 UNIV_INTERN
15474 void
update_field_defs_with_zip_dict_info(const char * part_name)15475 ha_innobase::update_field_defs_with_zip_dict_info(const char *part_name)
15476 {
15477 DBUG_ENTER("update_field_defs_with_zip_dict_info");
15478 ut_ad(!mutex_own(&dict_sys->mutex));
15479
15480 char norm_name[FN_REFLEN];
15481 normalize_table_name(norm_name,
15482 part_name != 0 ? part_name :
15483 table_share->normalized_path.str);
15484
15485 dict_table_t* ib_table = dict_table_open_on_name(
15486 norm_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
15487
15488 /* if dict_table_open_on_name() returns NULL, then it means that
15489 TABLE_SHARE is populated for a table being created and we can
15490 skip filling zip dict info here */
15491 if (ib_table == 0)
15492 DBUG_VOID_RETURN;
15493
15494 table_id_t ib_table_id = ib_table->id;
15495 dict_table_close(ib_table, FALSE, FALSE);
15496 Field* field;
15497 for (uint i = 0; i < table_share->fields; ++i) {
15498 field = table_share->field[i];
15499 if (field->column_format() ==
15500 COLUMN_FORMAT_TYPE_COMPRESSED) {
15501 bool reference_found = false;
15502 ulint dict_id = 0;
15503 switch (dict_get_dictionary_id_by_key(ib_table_id, i,
15504 &dict_id)) {
15505 case DB_SUCCESS:
15506 reference_found = true;
15507 break;
15508 case DB_RECORD_NOT_FOUND:
15509 reference_found = false;
15510 break;
15511 default:
15512 ut_error;
15513 }
15514 if (reference_found) {
15515 char* local_name = 0;
15516 ulint local_name_len = 0;
15517 char* local_data = 0;
15518 ulint local_data_len = 0;
15519 if (dict_get_dictionary_info_by_id(dict_id,
15520 &local_name, &local_name_len,
15521 &local_data, &local_data_len) !=
15522 DB_SUCCESS) {
15523 ut_error;
15524 }
15525 else {
15526 field->zip_dict_name.str =
15527 local_name;
15528 field->zip_dict_name.length =
15529 local_name_len;
15530 field->zip_dict_data.str =
15531 local_data;
15532 field->zip_dict_data.length =
15533 local_data_len;
15534 }
15535 }
15536 else {
15537 field->zip_dict_name = null_lex_cstr;
15538 field->zip_dict_data = null_lex_cstr;
15539 }
15540 }
15541 }
15542 DBUG_VOID_RETURN;
15543 }
15544
15545 /****************************************************************//**
15546 Update the system variable innodb_io_capacity_max using the "saved"
15547 value. This function is registered as a callback with MySQL. */
15548 static
15549 void
innodb_io_capacity_max_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15550 innodb_io_capacity_max_update(
15551 /*===========================*/
15552 THD* thd, /*!< in: thread handle */
15553 struct st_mysql_sys_var* var, /*!< in: pointer to
15554 system variable */
15555 void* var_ptr,/*!< out: where the
15556 formal string goes */
15557 const void* save) /*!< in: immediate result
15558 from check function */
15559 {
15560 ulong in_val = *static_cast<const ulong*>(save);
15561 if (in_val < srv_io_capacity) {
15562 in_val = srv_io_capacity;
15563 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15564 ER_WRONG_ARGUMENTS,
15565 "innodb_io_capacity_max cannot be"
15566 " set lower than innodb_io_capacity.");
15567 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15568 ER_WRONG_ARGUMENTS,
15569 "Setting innodb_io_capacity_max to %lu",
15570 srv_io_capacity);
15571 }
15572
15573 srv_max_io_capacity = in_val;
15574 }
15575
15576 /****************************************************************//**
15577 Update the system variable innodb_io_capacity using the "saved"
15578 value. This function is registered as a callback with MySQL. */
15579 static
15580 void
innodb_io_capacity_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15581 innodb_io_capacity_update(
15582 /*======================*/
15583 THD* thd, /*!< in: thread handle */
15584 struct st_mysql_sys_var* var, /*!< in: pointer to
15585 system variable */
15586 void* var_ptr,/*!< out: where the
15587 formal string goes */
15588 const void* save) /*!< in: immediate result
15589 from check function */
15590 {
15591 ulong in_val = *static_cast<const ulong*>(save);
15592 if (in_val > srv_max_io_capacity) {
15593 in_val = srv_max_io_capacity;
15594 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15595 ER_WRONG_ARGUMENTS,
15596 "innodb_io_capacity cannot be set"
15597 " higher than innodb_io_capacity_max.");
15598 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15599 ER_WRONG_ARGUMENTS,
15600 "Setting innodb_io_capacity to %lu",
15601 srv_max_io_capacity);
15602 }
15603
15604 srv_io_capacity = in_val;
15605 }
15606
15607 /****************************************************************//**
15608 Update the system variable innodb_log_arch_expire_sec using
15609 the "saved" value. This function is registered as a callback with MySQL. */
15610 static
15611 void
innodb_log_archive_expire_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15612 innodb_log_archive_expire_update(
15613 /*==============================*/
15614 THD* thd, /*!< in: thread handle */
15615 struct st_mysql_sys_var* var, /*!< in: pointer to
15616 system variable */
15617 void* var_ptr, /*!< out: unused */
15618 const void* save) /*!< in: immediate result
15619 from check function */
15620 {
15621 srv_log_arch_expire_sec = *(ulint*) save;
15622 }
15623
15624 static
15625 void
innodb_log_archive_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15626 innodb_log_archive_update(
15627 /*======================*/
15628 THD* thd,
15629 struct st_mysql_sys_var* var,
15630 void* var_ptr,
15631 const void* save)
15632 {
15633 if (srv_read_only_mode)
15634 return;
15635
15636 my_bool in_val = *static_cast<const my_bool*>(save);
15637
15638 if (in_val) {
15639 /* turn archiving on */
15640 srv_log_archive_on = innobase_log_archive = 1;
15641 log_archive_archivelog();
15642 } else {
15643 /* turn archivng off */
15644 srv_log_archive_on = innobase_log_archive = 0;
15645 log_archive_noarchivelog();
15646 }
15647 }
15648
15649 /****************************************************************//**
15650 Update the system variable innodb_max_dirty_pages_pct using the "saved"
15651 value. This function is registered as a callback with MySQL. */
15652 static
15653 void
innodb_max_dirty_pages_pct_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15654 innodb_max_dirty_pages_pct_update(
15655 /*==============================*/
15656 THD* thd, /*!< in: thread handle */
15657 struct st_mysql_sys_var* var, /*!< in: pointer to
15658 system variable */
15659 void* var_ptr,/*!< out: where the
15660 formal string goes */
15661 const void* save) /*!< in: immediate result
15662 from check function */
15663 {
15664 ulong in_val = *static_cast<const ulong*>(save);
15665 if (in_val < srv_max_dirty_pages_pct_lwm) {
15666 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15667 ER_WRONG_ARGUMENTS,
15668 "innodb_max_dirty_pages_pct cannot be"
15669 " set lower than"
15670 " innodb_max_dirty_pages_pct_lwm.");
15671 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15672 ER_WRONG_ARGUMENTS,
15673 "Lowering"
15674 " innodb_max_dirty_page_pct_lwm to %lu",
15675 in_val);
15676
15677 srv_max_dirty_pages_pct_lwm = in_val;
15678 }
15679
15680 srv_max_buf_pool_modified_pct = in_val;
15681 }
15682
15683 /****************************************************************//**
15684 Update the system variable innodb_max_dirty_pages_pct_lwm using the
15685 "saved" value. This function is registered as a callback with MySQL. */
15686 static
15687 void
innodb_max_dirty_pages_pct_lwm_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15688 innodb_max_dirty_pages_pct_lwm_update(
15689 /*==================================*/
15690 THD* thd, /*!< in: thread handle */
15691 struct st_mysql_sys_var* var, /*!< in: pointer to
15692 system variable */
15693 void* var_ptr,/*!< out: where the
15694 formal string goes */
15695 const void* save) /*!< in: immediate result
15696 from check function */
15697 {
15698 ulong in_val = *static_cast<const ulong*>(save);
15699 if (in_val > srv_max_buf_pool_modified_pct) {
15700 in_val = srv_max_buf_pool_modified_pct;
15701 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15702 ER_WRONG_ARGUMENTS,
15703 "innodb_max_dirty_pages_pct_lwm"
15704 " cannot be set higher than"
15705 " innodb_max_dirty_pages_pct.");
15706 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15707 ER_WRONG_ARGUMENTS,
15708 "Setting innodb_max_dirty_page_pct_lwm"
15709 " to %lu",
15710 in_val);
15711 }
15712
15713 srv_max_dirty_pages_pct_lwm = in_val;
15714 }
15715
15716 /************************************************************//**
15717 Validate the file format name and return its corresponding id.
15718 @return valid file format id */
15719 static
15720 uint
innobase_file_format_name_lookup(const char * format_name)15721 innobase_file_format_name_lookup(
15722 /*=============================*/
15723 const char* format_name) /*!< in: pointer to file format name */
15724 {
15725 char* endp;
15726 uint format_id;
15727
15728 ut_a(format_name != NULL);
15729
15730 /* The format name can contain the format id itself instead of
15731 the name and we check for that. */
15732 format_id = (uint) strtoul(format_name, &endp, 10);
15733
15734 /* Check for valid parse. */
15735 if (*endp == '\0' && *format_name != '\0') {
15736
15737 if (format_id <= UNIV_FORMAT_MAX) {
15738
15739 return(format_id);
15740 }
15741 } else {
15742
15743 for (format_id = 0; format_id <= UNIV_FORMAT_MAX;
15744 format_id++) {
15745 const char* name;
15746
15747 name = trx_sys_file_format_id_to_name(format_id);
15748
15749 if (!innobase_strcasecmp(format_name, name)) {
15750
15751 return(format_id);
15752 }
15753 }
15754 }
15755
15756 return(UNIV_FORMAT_MAX + 1);
15757 }
15758
15759 /************************************************************//**
15760 Validate the file format check config parameters, as a side effect it
15761 sets the srv_max_file_format_at_startup variable.
15762 @return the format_id if valid config value, otherwise, return -1 */
15763 static
15764 int
innobase_file_format_validate_and_set(const char * format_max)15765 innobase_file_format_validate_and_set(
15766 /*==================================*/
15767 const char* format_max) /*!< in: parameter value */
15768 {
15769 uint format_id;
15770
15771 format_id = innobase_file_format_name_lookup(format_max);
15772
15773 if (format_id < UNIV_FORMAT_MAX + 1) {
15774 srv_max_file_format_at_startup = format_id;
15775
15776 return((int) format_id);
15777 } else {
15778 return(-1);
15779 }
15780 }
15781
15782 /*************************************************************//**
15783 Check if it is a valid file format. This function is registered as
15784 a callback with MySQL.
15785 @return 0 for valid file format */
15786 static
15787 int
innodb_file_format_name_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)15788 innodb_file_format_name_validate(
15789 /*=============================*/
15790 THD* thd, /*!< in: thread handle */
15791 struct st_mysql_sys_var* var, /*!< in: pointer to system
15792 variable */
15793 void* save, /*!< out: immediate result
15794 for update function */
15795 struct st_mysql_value* value) /*!< in: incoming string */
15796 {
15797 const char* file_format_input;
15798 char buff[STRING_BUFFER_USUAL_SIZE];
15799 int len = sizeof(buff);
15800
15801 ut_a(save != NULL);
15802 ut_a(value != NULL);
15803
15804 file_format_input = value->val_str(value, buff, &len);
15805
15806 if (file_format_input != NULL) {
15807 uint format_id;
15808
15809 format_id = innobase_file_format_name_lookup(
15810 file_format_input);
15811
15812 if (format_id <= UNIV_FORMAT_MAX) {
15813
15814 /* Save a pointer to the name in the
15815 'file_format_name_map' constant array. */
15816 *static_cast<const char**>(save) =
15817 trx_sys_file_format_id_to_name(format_id);
15818
15819 return(0);
15820 }
15821 }
15822
15823 *static_cast<const char**>(save) = NULL;
15824 return(1);
15825 }
15826
15827 /****************************************************************//**
15828 Update the system variable innodb_file_format using the "saved"
15829 value. This function is registered as a callback with MySQL. */
15830 static
15831 void
innodb_file_format_name_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15832 innodb_file_format_name_update(
15833 /*===========================*/
15834 THD* thd, /*!< in: thread handle */
15835 struct st_mysql_sys_var* var, /*!< in: pointer to
15836 system variable */
15837 void* var_ptr, /*!< out: where the
15838 formal string goes */
15839 const void* save) /*!< in: immediate result
15840 from check function */
15841 {
15842 const char* format_name;
15843
15844 ut_a(var_ptr != NULL);
15845 ut_a(save != NULL);
15846
15847 format_name = *static_cast<const char*const*>(save);
15848
15849 if (format_name) {
15850 uint format_id;
15851
15852 format_id = innobase_file_format_name_lookup(format_name);
15853
15854 if (format_id <= UNIV_FORMAT_MAX) {
15855 srv_file_format = format_id;
15856 }
15857 }
15858
15859 *static_cast<const char**>(var_ptr)
15860 = trx_sys_file_format_id_to_name(srv_file_format);
15861 }
15862
15863 /*************************************************************//**
15864 Check if valid argument to innodb_file_format_max. This function
15865 is registered as a callback with MySQL.
15866 @return 0 for valid file format */
15867 static
15868 int
innodb_file_format_max_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)15869 innodb_file_format_max_validate(
15870 /*============================*/
15871 THD* thd, /*!< in: thread handle */
15872 struct st_mysql_sys_var* var, /*!< in: pointer to system
15873 variable */
15874 void* save, /*!< out: immediate result
15875 for update function */
15876 struct st_mysql_value* value) /*!< in: incoming string */
15877 {
15878 const char* file_format_input;
15879 char buff[STRING_BUFFER_USUAL_SIZE];
15880 int len = sizeof(buff);
15881 int format_id;
15882
15883 ut_a(save != NULL);
15884 ut_a(value != NULL);
15885
15886 file_format_input = value->val_str(value, buff, &len);
15887
15888 if (file_format_input != NULL) {
15889
15890 format_id = innobase_file_format_validate_and_set(
15891 file_format_input);
15892
15893 if (format_id >= 0) {
15894 /* Save a pointer to the name in the
15895 'file_format_name_map' constant array. */
15896 *static_cast<const char**>(save) =
15897 trx_sys_file_format_id_to_name(
15898 (uint) format_id);
15899
15900 return(0);
15901
15902 } else {
15903 push_warning_printf(thd,
15904 Sql_condition::WARN_LEVEL_WARN,
15905 ER_WRONG_ARGUMENTS,
15906 "InnoDB: invalid innodb_file_format_max "
15907 "value; can be any format up to %s "
15908 "or equivalent id of %d",
15909 trx_sys_file_format_id_to_name(UNIV_FORMAT_MAX),
15910 UNIV_FORMAT_MAX);
15911 }
15912 }
15913
15914 *static_cast<const char**>(save) = NULL;
15915 return(1);
15916 }
15917
15918 /****************************************************************//**
15919 Update the system variable innodb_file_format_max using the "saved"
15920 value. This function is registered as a callback with MySQL. */
15921 static
15922 void
innodb_file_format_max_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)15923 innodb_file_format_max_update(
15924 /*==========================*/
15925 THD* thd, /*!< in: thread handle */
15926 struct st_mysql_sys_var* var, /*!< in: pointer to
15927 system variable */
15928 void* var_ptr,/*!< out: where the
15929 formal string goes */
15930 const void* save) /*!< in: immediate result
15931 from check function */
15932 {
15933 const char* format_name_in;
15934 const char** format_name_out;
15935 uint format_id;
15936
15937 ut_a(save != NULL);
15938 ut_a(var_ptr != NULL);
15939
15940 format_name_in = *static_cast<const char*const*>(save);
15941
15942 if (!format_name_in) {
15943
15944 return;
15945 }
15946
15947 format_id = innobase_file_format_name_lookup(format_name_in);
15948
15949 if (format_id > UNIV_FORMAT_MAX) {
15950 /* DEFAULT is "on", which is invalid at runtime. */
15951 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15952 ER_WRONG_ARGUMENTS,
15953 "Ignoring SET innodb_file_format=%s",
15954 format_name_in);
15955 return;
15956 }
15957
15958 format_name_out = static_cast<const char**>(var_ptr);
15959
15960 /* Update the max format id in the system tablespace. */
15961 if (trx_sys_file_format_max_set(format_id, format_name_out)) {
15962 ut_print_timestamp(stderr);
15963 fprintf(stderr,
15964 " [Info] InnoDB: the file format in the system "
15965 "tablespace is now set to %s.\n", *format_name_out);
15966 }
15967 }
15968
15969 /**Check whether valid argument given to innobase_*_stopword_table.
15970 This function is registered as a callback with MySQL.
15971 @param[in] thd thread handle
15972 @param[in] var pointer to system variable
15973 @param[out] save immediate result for update function
15974 @param[in] value incoming string
15975 @return 0 for valid stopword table */
15976 static
15977 int
innodb_stopword_table_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)15978 innodb_stopword_table_validate(
15979 THD* thd,
15980 struct st_mysql_sys_var* var,
15981 void* save,
15982 struct st_mysql_value* value)
15983 {
15984 const char* stopword_table_name;
15985 char buff[STRING_BUFFER_USUAL_SIZE];
15986 int len = sizeof(buff);
15987 trx_t* trx;
15988 int ret = 1;
15989
15990 ut_a(save != NULL);
15991 ut_a(value != NULL);
15992
15993 stopword_table_name = value->val_str(value, buff, &len);
15994
15995 if (stopword_table_name != NULL) {
15996 if (stopword_table_name == buff) {
15997 /* Allocate from thd's memroot */
15998 stopword_table_name = thd_strmake(thd,
15999 stopword_table_name,
16000 len);
16001 }
16002 }
16003
16004 trx = check_trx_exists(thd);
16005
16006 row_mysql_lock_data_dictionary(trx);
16007
16008 /* Validate the stopword table's (if supplied) existence and
16009 of the right format */
16010 if (!stopword_table_name
16011 || fts_valid_stopword_table(stopword_table_name)) {
16012 *static_cast<const char**>(save) = stopword_table_name;
16013 ret = 0;
16014 }
16015
16016 row_mysql_unlock_data_dictionary(trx);
16017
16018 return(ret);
16019 }
16020
16021 /** Check whether valid argument given to "innodb_fts_internal_tbl_name"
16022 This function is registered as a callback with MySQL.
16023 @param[in] thd thread handle
16024 @param[in] var pointer to system variable
16025 @param[out] save immediate result for update function
16026 @param[in] value incoming string
16027 @return 0 for valid stopword table */
16028 static
16029 int
innodb_internal_table_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)16030 innodb_internal_table_validate(
16031 THD* thd,
16032 struct st_mysql_sys_var* var,
16033 void* save,
16034 struct st_mysql_value* value)
16035 {
16036 const char* table_name;
16037 char buff[STRING_BUFFER_USUAL_SIZE];
16038 int len = sizeof(buff);
16039 int ret = 1;
16040 dict_table_t* user_table;
16041
16042 ut_a(save != NULL);
16043 ut_a(value != NULL);
16044
16045 table_name = value->val_str(value, buff, &len);
16046
16047 if (!table_name) {
16048 *static_cast<const char**>(save) = NULL;
16049 return(0);
16050 } else if (table_name == buff) {
16051 /* Allocate memory from thd's mem_root */
16052 table_name = thd_strmake(thd, table_name, len);
16053 }
16054
16055 user_table = dict_table_open_on_name(
16056 table_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE);
16057
16058 if (user_table) {
16059 if (dict_table_has_fts_index(user_table)) {
16060 *static_cast<const char**>(save) = table_name;
16061 ret = 0;
16062 }
16063
16064 dict_table_close(user_table, FALSE, TRUE);
16065
16066 DBUG_EXECUTE_IF("innodb_evict_autoinc_table",
16067 mutex_enter(&dict_sys->mutex);
16068 dict_table_remove_from_cache_low(user_table, TRUE);
16069 mutex_exit(&dict_sys->mutex);
16070 );
16071 }
16072
16073 return(ret);
16074 }
16075
16076 /****************************************************************//**
16077 Update the system variable innodb_adaptive_hash_index using the "saved"
16078 value. This function is registered as a callback with MySQL. */
16079 static
16080 void
innodb_adaptive_hash_index_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16081 innodb_adaptive_hash_index_update(
16082 /*==============================*/
16083 THD* thd, /*!< in: thread handle */
16084 struct st_mysql_sys_var* var, /*!< in: pointer to
16085 system variable */
16086 void* var_ptr,/*!< out: where the
16087 formal string goes */
16088 const void* save) /*!< in: immediate result
16089 from check function */
16090 {
16091 if (*(my_bool*) save) {
16092 btr_search_enable();
16093 } else {
16094 btr_search_disable();
16095 }
16096 }
16097
16098 /****************************************************************//**
16099 Update the system variable innodb_cmp_per_index using the "saved"
16100 value. This function is registered as a callback with MySQL. */
16101 static
16102 void
innodb_cmp_per_index_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16103 innodb_cmp_per_index_update(
16104 /*========================*/
16105 THD* thd, /*!< in: thread handle */
16106 struct st_mysql_sys_var* var, /*!< in: pointer to
16107 system variable */
16108 void* var_ptr,/*!< out: where the
16109 formal string goes */
16110 const void* save) /*!< in: immediate result
16111 from check function */
16112 {
16113 /* Reset the stats whenever we enable the table
16114 INFORMATION_SCHEMA.innodb_cmp_per_index. */
16115 if (!srv_cmp_per_index_enabled && *(my_bool*) save) {
16116 page_zip_reset_stat_per_index();
16117 }
16118
16119 srv_cmp_per_index_enabled = !!(*(my_bool*) save);
16120 }
16121
16122 /****************************************************************//**
16123 Update the system variable innodb_old_blocks_pct using the "saved"
16124 value. This function is registered as a callback with MySQL. */
16125 static
16126 void
innodb_old_blocks_pct_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16127 innodb_old_blocks_pct_update(
16128 /*=========================*/
16129 THD* thd, /*!< in: thread handle */
16130 struct st_mysql_sys_var* var, /*!< in: pointer to
16131 system variable */
16132 void* var_ptr,/*!< out: where the
16133 formal string goes */
16134 const void* save) /*!< in: immediate result
16135 from check function */
16136 {
16137 innobase_old_blocks_pct = static_cast<uint>(
16138 buf_LRU_old_ratio_update(
16139 *static_cast<const uint*>(save), TRUE));
16140 }
16141
16142 /****************************************************************//**
16143 Update the system variable innodb_old_blocks_pct using the "saved"
16144 value. This function is registered as a callback with MySQL. */
16145 static
16146 void
innodb_change_buffer_max_size_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16147 innodb_change_buffer_max_size_update(
16148 /*=================================*/
16149 THD* thd, /*!< in: thread handle */
16150 struct st_mysql_sys_var* var, /*!< in: pointer to
16151 system variable */
16152 void* var_ptr,/*!< out: where the
16153 formal string goes */
16154 const void* save) /*!< in: immediate result
16155 from check function */
16156 {
16157 innobase_change_buffer_max_size =
16158 (*static_cast<const uint*>(save));
16159 ibuf_max_size_update(innobase_change_buffer_max_size);
16160 }
16161
16162 #ifdef UNIV_DEBUG
16163 ulong srv_fil_make_page_dirty_debug = 0;
16164 ulong srv_saved_page_number_debug = 0;
16165
16166 /****************************************************************//**
16167 Save an InnoDB page number. */
16168 static
16169 void
innodb_save_page_no(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16170 innodb_save_page_no(
16171 /*================*/
16172 THD* thd, /*!< in: thread handle */
16173 struct st_mysql_sys_var* var, /*!< in: pointer to
16174 system variable */
16175 void* var_ptr,/*!< out: where the
16176 formal string goes */
16177 const void* save) /*!< in: immediate result
16178 from check function */
16179 {
16180 srv_saved_page_number_debug = *static_cast<const ulong*>(save);
16181
16182 ib_logf(IB_LOG_LEVEL_INFO,
16183 "Saving InnoDB page number: %lu",
16184 srv_saved_page_number_debug);
16185 }
16186
16187 /****************************************************************//**
16188 Make the first page of given user tablespace dirty. */
16189 static
16190 void
innodb_make_page_dirty(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16191 innodb_make_page_dirty(
16192 /*===================*/
16193 THD* thd, /*!< in: thread handle */
16194 struct st_mysql_sys_var* var, /*!< in: pointer to
16195 system variable */
16196 void* var_ptr,/*!< out: where the
16197 formal string goes */
16198 const void* save) /*!< in: immediate result
16199 from check function */
16200 {
16201 mtr_t mtr;
16202 ulong space_id = *static_cast<const ulong*>(save);
16203
16204 mtr_start(&mtr);
16205
16206 buf_block_t* block = buf_page_get(
16207 space_id, 0, srv_saved_page_number_debug, RW_X_LATCH, &mtr);
16208
16209 if (block) {
16210 byte* page = block->frame;
16211 ib_logf(IB_LOG_LEVEL_INFO,
16212 "Dirtying page:%lu of space:%lu",
16213 page_get_page_no(page),
16214 page_get_space_id(page));
16215 mlog_write_ulint(page + FIL_PAGE_TYPE,
16216 fil_page_get_type(page),
16217 MLOG_2BYTES, &mtr);
16218 }
16219 mtr_commit(&mtr);
16220 }
16221 #endif // UNIV_DEBUG
16222
16223 /*************************************************************//**
16224 Find the corresponding ibuf_use_t value that indexes into
16225 innobase_change_buffering_values[] array for the input
16226 change buffering option name.
16227 @return corresponding IBUF_USE_* value for the input variable
16228 name, or IBUF_USE_COUNT if not able to find a match */
16229 static
16230 ibuf_use_t
innodb_find_change_buffering_value(const char * input_name)16231 innodb_find_change_buffering_value(
16232 /*===============================*/
16233 const char* input_name) /*!< in: input change buffering
16234 option name */
16235 {
16236 ulint use;
16237
16238 for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
16239 use++) {
16240 /* found a match */
16241 if (!innobase_strcasecmp(
16242 input_name, innobase_change_buffering_values[use])) {
16243 return((ibuf_use_t) use);
16244 }
16245 }
16246
16247 /* Did not find any match */
16248 return(IBUF_USE_COUNT);
16249 }
16250
16251 /*************************************************************//**
16252 Check if it is a valid value of innodb_change_buffering. This function is
16253 registered as a callback with MySQL.
16254 @return 0 for valid innodb_change_buffering */
16255 static
16256 int
innodb_change_buffering_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)16257 innodb_change_buffering_validate(
16258 /*=============================*/
16259 THD* thd, /*!< in: thread handle */
16260 struct st_mysql_sys_var* var, /*!< in: pointer to system
16261 variable */
16262 void* save, /*!< out: immediate result
16263 for update function */
16264 struct st_mysql_value* value) /*!< in: incoming string */
16265 {
16266 const char* change_buffering_input;
16267 char buff[STRING_BUFFER_USUAL_SIZE];
16268 int len = sizeof(buff);
16269
16270 ut_a(save != NULL);
16271 ut_a(value != NULL);
16272
16273 change_buffering_input = value->val_str(value, buff, &len);
16274
16275 if (change_buffering_input != NULL) {
16276 ibuf_use_t use;
16277
16278 use = innodb_find_change_buffering_value(
16279 change_buffering_input);
16280
16281 if (use != IBUF_USE_COUNT) {
16282 /* Find a matching change_buffering option value. */
16283 *static_cast<const char**>(save) =
16284 innobase_change_buffering_values[use];
16285
16286 return(0);
16287 }
16288 }
16289
16290 /* No corresponding change buffering option for user supplied
16291 "change_buffering_input" */
16292 return(1);
16293 }
16294
16295 /****************************************************************//**
16296 Update the system variable innodb_change_buffering using the "saved"
16297 value. This function is registered as a callback with MySQL. */
16298 static
16299 void
innodb_change_buffering_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16300 innodb_change_buffering_update(
16301 /*===========================*/
16302 THD* thd, /*!< in: thread handle */
16303 struct st_mysql_sys_var* var, /*!< in: pointer to
16304 system variable */
16305 void* var_ptr,/*!< out: where the
16306 formal string goes */
16307 const void* save) /*!< in: immediate result
16308 from check function */
16309 {
16310 ibuf_use_t use;
16311
16312 ut_a(var_ptr != NULL);
16313 ut_a(save != NULL);
16314
16315 use = innodb_find_change_buffering_value(
16316 *static_cast<const char*const*>(save));
16317
16318 ut_a(use < IBUF_USE_COUNT);
16319
16320 ibuf_use = use;
16321 *static_cast<const char**>(var_ptr) =
16322 *static_cast<const char*const*>(save);
16323 }
16324
16325 /*************************************************************//**
16326 Just emit a warning that the usage of the variable is deprecated.
16327 @return 0 */
16328 static
16329 void
innodb_stats_sample_pages_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16330 innodb_stats_sample_pages_update(
16331 /*=============================*/
16332 THD* thd, /*!< in: thread handle */
16333 struct st_mysql_sys_var* var, /*!< in: pointer to
16334 system variable */
16335 void* var_ptr,/*!< out: where the
16336 formal string goes */
16337 const void* save) /*!< in: immediate result
16338 from check function */
16339 {
16340 #define STATS_SAMPLE_PAGES_DEPRECATED_MSG \
16341 "Using innodb_stats_sample_pages is deprecated and " \
16342 "the variable may be removed in future releases. " \
16343 "Please use innodb_stats_transient_sample_pages " \
16344 "instead."
16345
16346 push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
16347 HA_ERR_WRONG_COMMAND, STATS_SAMPLE_PAGES_DEPRECATED_MSG);
16348
16349 ut_print_timestamp(stderr);
16350 fprintf(stderr,
16351 " InnoDB: Warning: %s\n",
16352 STATS_SAMPLE_PAGES_DEPRECATED_MSG);
16353
16354 srv_stats_transient_sample_pages =
16355 *static_cast<const unsigned long long*>(save);
16356 }
16357
16358 /****************************************************************//**
16359 Update the monitor counter according to the "set_option", turn
16360 on/off or reset specified monitor counter. */
16361 static
16362 void
innodb_monitor_set_option(const monitor_info_t * monitor_info,mon_option_t set_option)16363 innodb_monitor_set_option(
16364 /*======================*/
16365 const monitor_info_t* monitor_info,/*!< in: monitor info for the monitor
16366 to set */
16367 mon_option_t set_option) /*!< in: Turn on/off reset the
16368 counter */
16369 {
16370 monitor_id_t monitor_id = monitor_info->monitor_id;
16371
16372 /* If module type is MONITOR_GROUP_MODULE, it cannot be
16373 turned on/off individually. It should never use this
16374 function to set options */
16375 ut_a(!(monitor_info->monitor_type & MONITOR_GROUP_MODULE));
16376
16377 switch (set_option) {
16378 case MONITOR_TURN_ON:
16379 MONITOR_ON(monitor_id);
16380 MONITOR_INIT(monitor_id);
16381 MONITOR_SET_START(monitor_id);
16382
16383 /* If the monitor to be turned on uses
16384 exisitng monitor counter (status variable),
16385 make special processing to remember existing
16386 counter value. */
16387 if (monitor_info->monitor_type
16388 & MONITOR_EXISTING) {
16389 srv_mon_process_existing_counter(
16390 monitor_id, MONITOR_TURN_ON);
16391 }
16392 break;
16393
16394 case MONITOR_TURN_OFF:
16395 if (monitor_info->monitor_type & MONITOR_EXISTING) {
16396 srv_mon_process_existing_counter(
16397 monitor_id, MONITOR_TURN_OFF);
16398 }
16399
16400 MONITOR_OFF(monitor_id);
16401 MONITOR_SET_OFF(monitor_id);
16402 break;
16403
16404 case MONITOR_RESET_VALUE:
16405 srv_mon_reset(monitor_id);
16406 break;
16407
16408 case MONITOR_RESET_ALL_VALUE:
16409 srv_mon_reset_all(monitor_id);
16410 break;
16411
16412 default:
16413 ut_error;
16414 }
16415 }
16416
16417 /****************************************************************//**
16418 Find matching InnoDB monitor counters and update their status
16419 according to the "set_option", turn on/off or reset specified
16420 monitor counter. */
16421 static
16422 void
innodb_monitor_update_wildcard(const char * name,mon_option_t set_option)16423 innodb_monitor_update_wildcard(
16424 /*===========================*/
16425 const char* name, /*!< in: monitor name to match */
16426 mon_option_t set_option) /*!< in: the set option, whether
16427 to turn on/off or reset the counter */
16428 {
16429 ut_a(name);
16430
16431 for (ulint use = 0; use < NUM_MONITOR; use++) {
16432 ulint type;
16433 monitor_id_t monitor_id = static_cast<monitor_id_t>(use);
16434 monitor_info_t* monitor_info;
16435
16436 if (!innobase_wildcasecmp(
16437 srv_mon_get_name(monitor_id), name)) {
16438 monitor_info = srv_mon_get_info(monitor_id);
16439
16440 type = monitor_info->monitor_type;
16441
16442 /* If the monitor counter is of MONITOR_MODULE
16443 type, skip it. Except for those also marked with
16444 MONITOR_GROUP_MODULE flag, which can be turned
16445 on only as a module. */
16446 if (!(type & MONITOR_MODULE)
16447 && !(type & MONITOR_GROUP_MODULE)) {
16448 innodb_monitor_set_option(monitor_info,
16449 set_option);
16450 }
16451
16452 /* Need to special handle counters marked with
16453 MONITOR_GROUP_MODULE, turn on the whole module if
16454 any one of it comes here. Currently, only
16455 "module_buf_page" is marked with MONITOR_GROUP_MODULE */
16456 if (type & MONITOR_GROUP_MODULE) {
16457 if ((monitor_id >= MONITOR_MODULE_BUF_PAGE)
16458 && (monitor_id < MONITOR_MODULE_OS)) {
16459 if (set_option == MONITOR_TURN_ON
16460 && MONITOR_IS_ON(
16461 MONITOR_MODULE_BUF_PAGE)) {
16462 continue;
16463 }
16464
16465 srv_mon_set_module_control(
16466 MONITOR_MODULE_BUF_PAGE,
16467 set_option);
16468 } else {
16469 /* If new monitor is added with
16470 MONITOR_GROUP_MODULE, it needs
16471 to be added here. */
16472 ut_ad(0);
16473 }
16474 }
16475 }
16476 }
16477 }
16478
16479 /*************************************************************//**
16480 Given a configuration variable name, find corresponding monitor counter
16481 and return its monitor ID if found.
16482 @return monitor ID if found, MONITOR_NO_MATCH if there is no match */
16483 static
16484 ulint
innodb_monitor_id_by_name_get(const char * name)16485 innodb_monitor_id_by_name_get(
16486 /*==========================*/
16487 const char* name) /*!< in: monitor counter namer */
16488 {
16489 ut_a(name);
16490
16491 /* Search for wild character '%' in the name, if
16492 found, we treat it as a wildcard match. We do not search for
16493 single character wildcard '_' since our monitor names already contain
16494 such character. To avoid confusion, we request user must include
16495 at least one '%' character to activate the wildcard search. */
16496 if (strchr(name, '%')) {
16497 return(MONITOR_WILDCARD_MATCH);
16498 }
16499
16500 /* Not wildcard match, check for an exact match */
16501 for (ulint i = 0; i < NUM_MONITOR; i++) {
16502 if (!innobase_strcasecmp(
16503 name, srv_mon_get_name(static_cast<monitor_id_t>(i)))) {
16504 return(i);
16505 }
16506 }
16507
16508 return(MONITOR_NO_MATCH);
16509 }
16510 /*************************************************************//**
16511 Validate that the passed in monitor name matches at least one
16512 monitor counter name with wildcard compare.
16513 @return TRUE if at least one monitor name matches */
16514 static
16515 ibool
innodb_monitor_validate_wildcard_name(const char * name)16516 innodb_monitor_validate_wildcard_name(
16517 /*==================================*/
16518 const char* name) /*!< in: monitor counter namer */
16519 {
16520 for (ulint i = 0; i < NUM_MONITOR; i++) {
16521 if (!innobase_wildcasecmp(
16522 srv_mon_get_name(static_cast<monitor_id_t>(i)), name)) {
16523 return(TRUE);
16524 }
16525 }
16526
16527 return(FALSE);
16528 }
16529 /*************************************************************//**
16530 Validate the passed in monitor name, find and save the
16531 corresponding monitor name in the function parameter "save".
16532 @return 0 if monitor name is valid */
16533 static
16534 int
innodb_monitor_valid_byname(void * save,const char * name)16535 innodb_monitor_valid_byname(
16536 /*========================*/
16537 void* save, /*!< out: immediate result
16538 for update function */
16539 const char* name) /*!< in: incoming monitor name */
16540 {
16541 ulint use;
16542 monitor_info_t* monitor_info;
16543
16544 if (!name) {
16545 return(1);
16546 }
16547
16548 use = innodb_monitor_id_by_name_get(name);
16549
16550 /* No monitor name matches, nor it is wildcard match */
16551 if (use == MONITOR_NO_MATCH) {
16552 return(1);
16553 }
16554
16555 if (use < NUM_MONITOR) {
16556 monitor_info = srv_mon_get_info((monitor_id_t) use);
16557
16558 /* If the monitor counter is marked with
16559 MONITOR_GROUP_MODULE flag, then this counter
16560 cannot be turned on/off individually, instead
16561 it shall be turned on/off as a group using
16562 its module name */
16563 if ((monitor_info->monitor_type & MONITOR_GROUP_MODULE)
16564 && (!(monitor_info->monitor_type & MONITOR_MODULE))) {
16565 sql_print_warning(
16566 "Monitor counter '%s' cannot"
16567 " be turned on/off individually."
16568 " Please use its module name"
16569 " to turn on/off the counters"
16570 " in the module as a group.\n",
16571 name);
16572
16573 return(1);
16574 }
16575
16576 } else {
16577 ut_a(use == MONITOR_WILDCARD_MATCH);
16578
16579 /* For wildcard match, if there is not a single monitor
16580 counter name that matches, treat it as an invalid
16581 value for the system configuration variables */
16582 if (!innodb_monitor_validate_wildcard_name(name)) {
16583 return(1);
16584 }
16585 }
16586
16587 /* Save the configure name for innodb_monitor_update() */
16588 *static_cast<const char**>(save) = name;
16589
16590 return(0);
16591 }
16592 /*************************************************************//**
16593 Validate passed-in "value" is a valid monitor counter name.
16594 This function is registered as a callback with MySQL.
16595 @return 0 for valid name */
16596 static
16597 int
innodb_monitor_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)16598 innodb_monitor_validate(
16599 /*====================*/
16600 THD* thd, /*!< in: thread handle */
16601 struct st_mysql_sys_var* var, /*!< in: pointer to system
16602 variable */
16603 void* save, /*!< out: immediate result
16604 for update function */
16605 struct st_mysql_value* value) /*!< in: incoming string */
16606 {
16607 const char* name;
16608 char* monitor_name;
16609 char buff[STRING_BUFFER_USUAL_SIZE];
16610 int len = sizeof(buff);
16611 int ret;
16612
16613 ut_a(save != NULL);
16614 ut_a(value != NULL);
16615
16616 name = value->val_str(value, buff, &len);
16617
16618 /* monitor_name could point to memory from MySQL
16619 or buff[]. Always dup the name to memory allocated
16620 by InnoDB, so we can access it in another callback
16621 function innodb_monitor_update() and free it appropriately */
16622 if (name) {
16623 monitor_name = my_strdup(name, MYF(0));
16624 } else {
16625 return(1);
16626 }
16627
16628 ret = innodb_monitor_valid_byname(save, monitor_name);
16629
16630 if (ret) {
16631 /* Validation failed */
16632 my_free(monitor_name);
16633 } else {
16634 /* monitor_name will be freed in separate callback function
16635 innodb_monitor_update(). Assert "save" point to
16636 the "monitor_name" variable */
16637 ut_ad(*static_cast<char**>(save) == monitor_name);
16638 }
16639
16640 return(ret);
16641 }
16642
16643 /****************************************************************//**
16644 Update the system variable innodb_enable(disable/reset/reset_all)_monitor
16645 according to the "set_option" and turn on/off or reset specified monitor
16646 counter. */
16647 static
16648 void
innodb_monitor_update(THD * thd,void * var_ptr,const void * save,mon_option_t set_option,ibool free_mem)16649 innodb_monitor_update(
16650 /*==================*/
16651 THD* thd, /*!< in: thread handle */
16652 void* var_ptr, /*!< out: where the
16653 formal string goes */
16654 const void* save, /*!< in: immediate result
16655 from check function */
16656 mon_option_t set_option, /*!< in: the set option,
16657 whether to turn on/off or
16658 reset the counter */
16659 ibool free_mem) /*!< in: whether we will
16660 need to free the memory */
16661 {
16662 monitor_info_t* monitor_info;
16663 ulint monitor_id;
16664 ulint err_monitor = 0;
16665 const char* name;
16666
16667 ut_a(save != NULL);
16668
16669 name = *static_cast<const char*const*>(save);
16670
16671 if (!name) {
16672 monitor_id = MONITOR_DEFAULT_START;
16673 } else {
16674 monitor_id = innodb_monitor_id_by_name_get(name);
16675
16676 /* Double check we have a valid monitor ID */
16677 if (monitor_id == MONITOR_NO_MATCH) {
16678 return;
16679 }
16680 }
16681
16682 if (monitor_id == MONITOR_DEFAULT_START) {
16683 /* If user set the variable to "default", we will
16684 print a message and make this set operation a "noop".
16685 The check is being made here is because "set default"
16686 does not go through validation function */
16687 if (thd) {
16688 push_warning_printf(
16689 thd, Sql_condition::WARN_LEVEL_WARN,
16690 ER_NO_DEFAULT,
16691 "Default value is not defined for "
16692 "this set option. Please specify "
16693 "correct counter or module name.");
16694 } else {
16695 sql_print_error(
16696 "Default value is not defined for "
16697 "this set option. Please specify "
16698 "correct counter or module name.\n");
16699 }
16700
16701 if (var_ptr) {
16702 *(const char**) var_ptr = NULL;
16703 }
16704 } else if (monitor_id == MONITOR_WILDCARD_MATCH) {
16705 innodb_monitor_update_wildcard(name, set_option);
16706 } else {
16707 monitor_info = srv_mon_get_info(
16708 static_cast<monitor_id_t>(monitor_id));
16709
16710 ut_a(monitor_info);
16711
16712 /* If monitor is already truned on, someone could already
16713 collect monitor data, exit and ask user to turn off the
16714 monitor before turn it on again. */
16715 if (set_option == MONITOR_TURN_ON
16716 && MONITOR_IS_ON(monitor_id)) {
16717 err_monitor = monitor_id;
16718 goto exit;
16719 }
16720
16721 if (var_ptr) {
16722 *(const char**) var_ptr = monitor_info->monitor_name;
16723 }
16724
16725 /* Depending on the monitor name is for a module or
16726 a counter, process counters in the whole module or
16727 individual counter. */
16728 if (monitor_info->monitor_type & MONITOR_MODULE) {
16729 srv_mon_set_module_control(
16730 static_cast<monitor_id_t>(monitor_id),
16731 set_option);
16732 } else {
16733 innodb_monitor_set_option(monitor_info, set_option);
16734 }
16735 }
16736 exit:
16737 /* Only if we are trying to turn on a monitor that already
16738 been turned on, we will set err_monitor. Print related
16739 information */
16740 if (err_monitor) {
16741 sql_print_warning("Monitor %s is already enabled.",
16742 srv_mon_get_name((monitor_id_t) err_monitor));
16743 }
16744
16745 if (free_mem && name) {
16746 my_free((void*) name);
16747 }
16748
16749 return;
16750 }
16751
16752 /** Validate if passed-in "value" is a valid value for
16753 innodb_buffer_pool_filename. On Windows, file names with colon (:)
16754 are not allowed.
16755 @param[in] thd thread handle
16756 @param[in] var pointer to system variable
16757 @param[out] save immediate result for update function
16758 @param[in] value incoming string
16759 @return 0 for valid name */
16760 static
16761 int
innodb_srv_buf_dump_filename_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)16762 innodb_srv_buf_dump_filename_validate(
16763 THD* thd,
16764 struct st_mysql_sys_var* var,
16765 void* save,
16766 struct st_mysql_value* value)
16767 {
16768 const char* buf_name;
16769 char buff[OS_FILE_MAX_PATH];
16770 int len= sizeof(buff);
16771
16772 ut_a(save != NULL);
16773 ut_a(value != NULL);
16774
16775 buf_name = value->val_str(value, buff, &len);
16776
16777 if (buf_name == NULL) {
16778 return(1);
16779 }
16780
16781 if (buf_name == buff) {
16782 ut_ad(len <= OS_FILE_MAX_PATH);
16783 /* Allocate from thd's memroot */
16784 buf_name = thd_strmake(thd, buf_name, len);
16785 }
16786
16787 #ifdef __WIN__
16788 if (is_filename_allowed(buf_name, len, FALSE)){
16789 *static_cast<const char**>(save) = buf_name;
16790 return(0);
16791 } else {
16792 push_warning_printf(thd,
16793 Sql_condition::WARN_LEVEL_WARN,
16794 ER_WRONG_ARGUMENTS,
16795 "InnoDB: innodb_buffer_pool_filename "
16796 "cannot have colon (:) in the file name.");
16797 return(1);
16798 }
16799 #else
16800 *static_cast<const char**>(save) = buf_name;
16801 return(0);
16802 #endif
16803 }
16804
16805 #ifdef UNIV_DEBUG
16806 static char* srv_buffer_pool_evict;
16807
16808 /****************************************************************//**
16809 Evict all uncompressed pages of compressed tables from the buffer pool.
16810 Keep the compressed pages in the buffer pool.
16811 @return whether all uncompressed pages were evicted */
16812 static MY_ATTRIBUTE((warn_unused_result))
16813 bool
innodb_buffer_pool_evict_uncompressed(void)16814 innodb_buffer_pool_evict_uncompressed(void)
16815 /*=======================================*/
16816 {
16817 bool all_evicted = true;
16818
16819 for (ulint i = 0; i < srv_buf_pool_instances; i++) {
16820 buf_pool_t* buf_pool = &buf_pool_ptr[i];
16821
16822 mutex_enter(&buf_pool->LRU_list_mutex);
16823
16824 for (buf_block_t* block = UT_LIST_GET_LAST(
16825 buf_pool->unzip_LRU);
16826 block != NULL; ) {
16827 buf_block_t* prev_block = UT_LIST_GET_PREV(
16828 unzip_LRU, block);
16829 ut_ad(buf_block_get_state(block)
16830 == BUF_BLOCK_FILE_PAGE);
16831 ut_ad(block->in_unzip_LRU_list);
16832 ut_ad(block->page.in_LRU_list);
16833
16834 mutex_enter(&block->mutex);
16835 all_evicted = buf_LRU_free_page(&block->page, false);
16836 mutex_exit(&block->mutex);
16837
16838 if (all_evicted) {
16839
16840 mutex_enter(&buf_pool->LRU_list_mutex);
16841 block = UT_LIST_GET_LAST(buf_pool->unzip_LRU);
16842 } else {
16843
16844 block = prev_block;
16845 }
16846 }
16847
16848 mutex_exit(&buf_pool->LRU_list_mutex);
16849 }
16850
16851 return(all_evicted);
16852 }
16853
16854 /****************************************************************//**
16855 Called on SET GLOBAL innodb_buffer_pool_evict=...
16856 Handles some values specially, to evict pages from the buffer pool.
16857 SET GLOBAL innodb_buffer_pool_evict='uncompressed'
16858 evicts all uncompressed page frames of compressed tablespaces. */
16859 static
16860 void
innodb_buffer_pool_evict_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16861 innodb_buffer_pool_evict_update(
16862 /*============================*/
16863 THD* thd, /*!< in: thread handle */
16864 struct st_mysql_sys_var*var, /*!< in: pointer to system variable */
16865 void* var_ptr,/*!< out: ignored */
16866 const void* save) /*!< in: immediate result
16867 from check function */
16868 {
16869 if (const char* op = *static_cast<const char*const*>(save)) {
16870 if (!strcmp(op, "uncompressed")) {
16871 for (uint tries = 0; tries < 10000; tries++) {
16872 if (innodb_buffer_pool_evict_uncompressed()) {
16873 return;
16874 }
16875
16876 os_thread_sleep(10000);
16877 }
16878
16879 /* We failed to evict all uncompressed pages. */
16880 ut_ad(0);
16881 }
16882 }
16883 }
16884 #endif /* UNIV_DEBUG */
16885
16886 /****************************************************************//**
16887 Update the system variable innodb_monitor_enable and enable
16888 specified monitor counter.
16889 This function is registered as a callback with MySQL. */
16890 static
16891 void
innodb_enable_monitor_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16892 innodb_enable_monitor_update(
16893 /*=========================*/
16894 THD* thd, /*!< in: thread handle */
16895 struct st_mysql_sys_var* var, /*!< in: pointer to
16896 system variable */
16897 void* var_ptr,/*!< out: where the
16898 formal string goes */
16899 const void* save) /*!< in: immediate result
16900 from check function */
16901 {
16902 innodb_monitor_update(thd, var_ptr, save, MONITOR_TURN_ON, TRUE);
16903 }
16904
16905 /****************************************************************//**
16906 Update the system variable innodb_monitor_disable and turn
16907 off specified monitor counter. */
16908 static
16909 void
innodb_disable_monitor_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16910 innodb_disable_monitor_update(
16911 /*==========================*/
16912 THD* thd, /*!< in: thread handle */
16913 struct st_mysql_sys_var* var, /*!< in: pointer to
16914 system variable */
16915 void* var_ptr,/*!< out: where the
16916 formal string goes */
16917 const void* save) /*!< in: immediate result
16918 from check function */
16919 {
16920 innodb_monitor_update(thd, var_ptr, save, MONITOR_TURN_OFF, TRUE);
16921 }
16922
16923 /****************************************************************//**
16924 Update the system variable innodb_monitor_reset and reset
16925 specified monitor counter(s).
16926 This function is registered as a callback with MySQL. */
16927 static
16928 void
innodb_reset_monitor_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16929 innodb_reset_monitor_update(
16930 /*========================*/
16931 THD* thd, /*!< in: thread handle */
16932 struct st_mysql_sys_var* var, /*!< in: pointer to
16933 system variable */
16934 void* var_ptr,/*!< out: where the
16935 formal string goes */
16936 const void* save) /*!< in: immediate result
16937 from check function */
16938 {
16939 innodb_monitor_update(thd, var_ptr, save, MONITOR_RESET_VALUE, TRUE);
16940 }
16941
16942 /****************************************************************//**
16943 Update the system variable innodb_monitor_reset_all and reset
16944 all value related monitor counter.
16945 This function is registered as a callback with MySQL. */
16946 static
16947 void
innodb_reset_all_monitor_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)16948 innodb_reset_all_monitor_update(
16949 /*============================*/
16950 THD* thd, /*!< in: thread handle */
16951 struct st_mysql_sys_var* var, /*!< in: pointer to
16952 system variable */
16953 void* var_ptr,/*!< out: where the
16954 formal string goes */
16955 const void* save) /*!< in: immediate result
16956 from check function */
16957 {
16958 innodb_monitor_update(thd, var_ptr, save, MONITOR_RESET_ALL_VALUE,
16959 TRUE);
16960 }
16961
16962 /****************************************************************//**
16963 Parse and enable InnoDB monitor counters during server startup.
16964 User can list the monitor counters/groups to be enable by specifying
16965 "loose-innodb_monitor_enable=monitor_name1;monitor_name2..."
16966 in server configuration file or at the command line. The string
16967 separate could be ";", "," or empty space. */
16968 static
16969 void
innodb_enable_monitor_at_startup(char * str)16970 innodb_enable_monitor_at_startup(
16971 /*=============================*/
16972 char* str) /*!< in/out: monitor counter enable list */
16973 {
16974 static const char* sep = " ;,";
16975 char* last;
16976
16977 ut_a(str);
16978
16979 /* Walk through the string, and separate each monitor counter
16980 and/or counter group name, and calling innodb_monitor_update()
16981 if successfully updated. Please note that the "str" would be
16982 changed by strtok_r() as it walks through it. */
16983 for (char* option = strtok_r(str, sep, &last);
16984 option;
16985 option = strtok_r(NULL, sep, &last)) {
16986 ulint ret;
16987 char* option_name;
16988
16989 ret = innodb_monitor_valid_byname(&option_name, option);
16990
16991 /* The name is validated if ret == 0 */
16992 if (!ret) {
16993 innodb_monitor_update(NULL, NULL, &option,
16994 MONITOR_TURN_ON, FALSE);
16995 } else {
16996 sql_print_warning("Invalid monitor counter"
16997 " name: '%s'", option);
16998 }
16999 }
17000 }
17001
17002 #ifdef UNIV_LINUX
17003
17004 /****************************************************************//**
17005 Update the innodb_sched_priority_cleaner variable and set the thread
17006 priorities accordingly. */
17007 static
17008 void
innodb_sched_priority_cleaner_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)17009 innodb_sched_priority_cleaner_update(
17010 /*=================================*/
17011 THD* thd, /*!< in: thread handle */
17012 struct st_mysql_sys_var* var, /*!< in: pointer to
17013 system variable */
17014 void* var_ptr,/*!< out: where the
17015 formal string goes */
17016 const void* save) /*!< in: immediate result
17017 from check function */
17018 {
17019 ulint priority = *static_cast<const ulint *>(save);
17020 ulint actual_priority;
17021
17022 /* Set the priority for the LRU manager thread */
17023 ut_ad(buf_lru_manager_is_active);
17024 actual_priority = os_thread_set_priority(srv_lru_manager_tid,
17025 priority);
17026 if (UNIV_UNLIKELY(actual_priority != priority)) {
17027
17028 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
17029 ER_WRONG_ARGUMENTS,
17030 "Failed to set the LRU manager thread "
17031 "priority to %lu, "
17032 "the current priority is %lu", priority,
17033 actual_priority);
17034 } else {
17035
17036 srv_sched_priority_cleaner = priority;
17037 }
17038
17039 /* Set the priority for the page cleaner thread */
17040 if (srv_read_only_mode) {
17041
17042 return;
17043 }
17044
17045 ut_ad(buf_page_cleaner_is_active);
17046 actual_priority = os_thread_set_priority(srv_cleaner_tid, priority);
17047 if (UNIV_UNLIKELY(actual_priority != priority)) {
17048
17049 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
17050 ER_WRONG_ARGUMENTS,
17051 "Failed to set the page cleaner thread "
17052 "priority to %lu, "
17053 "the current priority is %lu", priority,
17054 actual_priority);
17055 }
17056 }
17057
17058 #if defined(UNIV_DEBUG) || (UNIV_PERF_DEBUG)
17059
17060 /****************************************************************//**
17061 Update the innodb_sched_priority_purge variable and set the thread
17062 priorities accordingly. */
17063 static
17064 void
innodb_sched_priority_purge_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)17065 innodb_sched_priority_purge_update(
17066 /*===============================*/
17067 THD* thd, /*!< in: thread handle */
17068 struct st_mysql_sys_var* var, /*!< in: pointer to
17069 system variable */
17070 void* var_ptr,/*!< out: where the
17071 formal string goes */
17072 const void* save) /*!< in: immediate result
17073 from check function */
17074 {
17075 ulint priority = *static_cast<const ulint *>(save);
17076
17077 if (srv_read_only_mode) {
17078 return;
17079 }
17080
17081 for (ulint i = 0; i < srv_n_purge_threads; i++) {
17082
17083 ulint actual_priority
17084 = os_thread_set_priority(srv_purge_tids[i], priority);
17085 if (UNIV_UNLIKELY(actual_priority != priority)) {
17086
17087 push_warning_printf(thd,
17088 Sql_condition::WARN_LEVEL_WARN,
17089 ER_WRONG_ARGUMENTS,
17090 "Failed to set the purge "
17091 "thread priority to %lu, the "
17092 "current priority is %lu, "
17093 "aborting priority update",
17094 priority, actual_priority);
17095 return;
17096 }
17097 }
17098
17099 srv_sched_priority_purge = priority;
17100 }
17101
17102 /****************************************************************//**
17103 Update the innodb_sched_priority_io variable and set the thread
17104 priorities accordingly. */
17105 static
17106 void
innodb_sched_priority_io_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)17107 innodb_sched_priority_io_update(
17108 /*============================*/
17109 THD* thd, /*!< in: thread handle */
17110 struct st_mysql_sys_var* var, /*!< in: pointer to
17111 system variable */
17112 void* var_ptr,/*!< out: where the
17113 formal string goes */
17114 const void* save) /*!< in: immediate result
17115 from check function */
17116 {
17117 ulint priority = *static_cast<const ulint *>(save);
17118
17119 for (ulint i = 0; i < srv_n_file_io_threads; i++) {
17120
17121 ulint actual_priority = os_thread_set_priority(srv_io_tids[i],
17122 priority);
17123
17124 if (UNIV_UNLIKELY(actual_priority != priority)) {
17125
17126 push_warning_printf(thd,
17127 Sql_condition::WARN_LEVEL_WARN,
17128 ER_WRONG_ARGUMENTS,
17129 "Failed to set the I/O "
17130 "thread priority to %lu, the "
17131 "current priority is %lu, "
17132 "aborting priority update",
17133 priority, actual_priority);
17134 return;
17135 }
17136 }
17137
17138 srv_sched_priority_io = priority;
17139 }
17140
17141 /****************************************************************//**
17142 Update the innodb_sched_priority_master variable and set the thread
17143 priorities accordingly. */
17144 static
17145 void
innodb_sched_priority_master_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)17146 innodb_sched_priority_master_update(
17147 /*================================*/
17148 THD* thd, /*!< in: thread handle */
17149 struct st_mysql_sys_var* var, /*!< in: pointer to
17150 system variable */
17151 void* var_ptr,/*!< out: where the
17152 formal string goes */
17153 const void* save) /*!< in: immediate result
17154 from check function */
17155 {
17156 ulint priority = *static_cast<const lint *>(save);
17157 ulint actual_priority;
17158
17159 if (srv_read_only_mode) {
17160 return;
17161 }
17162
17163 actual_priority = os_thread_set_priority(srv_master_tid, priority);
17164 if (UNIV_UNLIKELY(actual_priority != priority)) {
17165
17166 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
17167 ER_WRONG_ARGUMENTS,
17168 "Failed to set the master thread "
17169 "priority to %lu, "
17170 "the current priority is %lu", priority,
17171 actual_priority);
17172 } else {
17173
17174 srv_sched_priority_master = priority;
17175 }
17176 }
17177
17178 #endif /* defined(UNIV_DEBUG) || (UNIV_PERF_DEBUG) */
17179
17180 #endif /* UNIV_LINUX */
17181
17182 #ifdef UNIV_DEBUG
17183 /*************************************************************//**
17184 Check if it is a valid value of innodb_track_changed_pages.
17185 Changed pages tracking is not working correctly without initialization
17186 procedure on server startup. The function allows to temporary
17187 disable tracking, but only if the feature was enabled on startup.
17188 This function is registered as a callback with MySQL.
17189 @return 0 for valid innodb_track_changed_pages */
17190 static
17191 int
innodb_track_changed_pages_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)17192 innodb_track_changed_pages_validate(
17193 THD* thd, /*!< in: thread handle */
17194 struct st_mysql_sys_var* var, /*!< in: pointer to system
17195 variable */
17196 void* save, /*!< out: immediate result
17197 for update function */
17198 struct st_mysql_value* value) /*!< in: incoming bool */
17199 {
17200 long long intbuf = 0;
17201
17202 if (value->val_int(value, &intbuf)) {
17203 /* The value is NULL. That is invalid. */
17204 return 1;
17205 }
17206
17207 if (srv_redo_log_thread_started) {
17208 *reinterpret_cast<ulong*>(save)
17209 = static_cast<ulong>(intbuf);
17210 return 0;
17211 }
17212
17213 if (intbuf == srv_track_changed_pages) { // == 0
17214 *reinterpret_cast<ulong*>(save) = srv_track_changed_pages;
17215 return 0;
17216 }
17217
17218 return 1;
17219 }
17220 #endif
17221
17222 /****************************************************************//**
17223 Callback function for accessing the InnoDB variables from MySQL:
17224 SHOW VARIABLES. */
17225 static
17226 int
show_innodb_vars(THD * thd,SHOW_VAR * var,char * buff)17227 show_innodb_vars(
17228 /*=============*/
17229 THD* thd,
17230 SHOW_VAR* var,
17231 char* buff)
17232 {
17233 innodb_export_status();
17234 var->type = SHOW_ARRAY;
17235 var->value = (char*) &innodb_status_variables;
17236
17237 return(0);
17238 }
17239
17240 /****************************************************************//**
17241 This function checks each index name for a table against reserved
17242 system default primary index name 'GEN_CLUST_INDEX'. If a name
17243 matches, this function pushes an warning message to the client,
17244 and returns true.
17245 @return true if the index name matches the reserved name */
17246 UNIV_INTERN
17247 bool
innobase_index_name_is_reserved(THD * thd,const KEY * key_info,ulint num_of_keys)17248 innobase_index_name_is_reserved(
17249 /*============================*/
17250 THD* thd, /*!< in/out: MySQL connection */
17251 const KEY* key_info, /*!< in: Indexes to be created */
17252 ulint num_of_keys) /*!< in: Number of indexes to
17253 be created. */
17254 {
17255 const KEY* key;
17256 uint key_num; /* index number */
17257
17258 for (key_num = 0; key_num < num_of_keys; key_num++) {
17259 key = &key_info[key_num];
17260
17261 if (innobase_strcasecmp(key->name,
17262 innobase_index_reserve_name) == 0) {
17263 /* Push warning to mysql */
17264 push_warning_printf(thd,
17265 Sql_condition::WARN_LEVEL_WARN,
17266 ER_WRONG_NAME_FOR_INDEX,
17267 "Cannot Create Index with name "
17268 "'%s'. The name is reserved "
17269 "for the system default primary "
17270 "index.",
17271 innobase_index_reserve_name);
17272
17273 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
17274 innobase_index_reserve_name);
17275
17276 return(true);
17277 }
17278 }
17279
17280 return(false);
17281 }
17282
17283 /***********************************************************************
17284 Retrieve the FTS Relevance Ranking result for doc with doc_id
17285 of prebuilt->fts_doc_id
17286 @return the relevance ranking value */
17287 UNIV_INTERN
17288 float
innobase_fts_retrieve_ranking(FT_INFO * fts_hdl)17289 innobase_fts_retrieve_ranking(
17290 /*============================*/
17291 FT_INFO * fts_hdl) /*!< in: FTS handler */
17292 {
17293 row_prebuilt_t* ft_prebuilt;
17294 fts_result_t* result;
17295
17296 result = ((NEW_FT_INFO*) fts_hdl)->ft_result;
17297
17298 ft_prebuilt = ((NEW_FT_INFO*) fts_hdl)->ft_prebuilt;
17299
17300 if (ft_prebuilt->read_just_key) {
17301 fts_ranking_t* ranking =
17302 rbt_value(fts_ranking_t, result->current);
17303 return(ranking->rank);
17304 }
17305
17306 /* Retrieve the ranking value for doc_id with value of
17307 prebuilt->fts_doc_id */
17308 return(fts_retrieve_ranking(result, ft_prebuilt->fts_doc_id));
17309 }
17310
17311 /***********************************************************************
17312 Free the memory for the FTS handler */
17313 UNIV_INTERN
17314 void
innobase_fts_close_ranking(FT_INFO * fts_hdl)17315 innobase_fts_close_ranking(
17316 /*=======================*/
17317 FT_INFO * fts_hdl)
17318 {
17319 fts_result_t* result;
17320
17321 result = ((NEW_FT_INFO*) fts_hdl)->ft_result;
17322
17323 fts_query_free_result(result);
17324
17325 my_free((uchar*) fts_hdl);
17326
17327 return;
17328 }
17329
17330 /***********************************************************************
17331 Find and Retrieve the FTS Relevance Ranking result for doc with doc_id
17332 of prebuilt->fts_doc_id
17333 @return the relevance ranking value */
17334 UNIV_INTERN
17335 float
innobase_fts_find_ranking(FT_INFO * fts_hdl,uchar * record,uint len)17336 innobase_fts_find_ranking(
17337 /*======================*/
17338 FT_INFO* fts_hdl, /*!< in: FTS handler */
17339 uchar* record, /*!< in: Unused */
17340 uint len) /*!< in: Unused */
17341 {
17342 row_prebuilt_t* ft_prebuilt;
17343 fts_result_t* result;
17344
17345 ft_prebuilt = ((NEW_FT_INFO*) fts_hdl)->ft_prebuilt;
17346 result = ((NEW_FT_INFO*) fts_hdl)->ft_result;
17347
17348 /* Retrieve the ranking value for doc_id with value of
17349 prebuilt->fts_doc_id */
17350 return(fts_retrieve_ranking(result, ft_prebuilt->fts_doc_id));
17351 }
17352
17353 #ifdef UNIV_DEBUG
17354 static my_bool innodb_purge_run_now = TRUE;
17355 static my_bool innodb_purge_stop_now = TRUE;
17356 static my_bool innodb_log_checkpoint_now = TRUE;
17357 static my_bool innodb_buf_flush_list_now = TRUE;
17358 static my_bool innodb_track_redo_log_now = TRUE;
17359
17360 /****************************************************************//**
17361 Set the purge state to RUN. If purge is disabled then it
17362 is a no-op. This function is registered as a callback with MySQL. */
17363 static
17364 void
purge_run_now_set(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17365 purge_run_now_set(
17366 /*==============*/
17367 THD* thd /*!< in: thread handle */
17368 MY_ATTRIBUTE((unused)),
17369 struct st_mysql_sys_var* var /*!< in: pointer to system
17370 variable */
17371 MY_ATTRIBUTE((unused)),
17372 void* var_ptr /*!< out: where the formal
17373 string goes */
17374 MY_ATTRIBUTE((unused)),
17375 const void* save) /*!< in: immediate result from
17376 check function */
17377 {
17378 if (*(my_bool*) save && trx_purge_state() != PURGE_STATE_DISABLED) {
17379 trx_purge_run();
17380 }
17381 }
17382
17383 /****************************************************************//**
17384 Set the purge state to STOP. If purge is disabled then it
17385 is a no-op. This function is registered as a callback with MySQL. */
17386 static
17387 void
purge_stop_now_set(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17388 purge_stop_now_set(
17389 /*===============*/
17390 THD* thd /*!< in: thread handle */
17391 MY_ATTRIBUTE((unused)),
17392 struct st_mysql_sys_var* var /*!< in: pointer to system
17393 variable */
17394 MY_ATTRIBUTE((unused)),
17395 void* var_ptr /*!< out: where the formal
17396 string goes */
17397 MY_ATTRIBUTE((unused)),
17398 const void* save) /*!< in: immediate result from
17399 check function */
17400 {
17401 if (*(my_bool*) save && trx_purge_state() != PURGE_STATE_DISABLED) {
17402 trx_purge_stop();
17403 }
17404 }
17405
17406 /****************************************************************//**
17407 Force innodb to checkpoint. */
17408 static
17409 void
checkpoint_now_set(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17410 checkpoint_now_set(
17411 /*===============*/
17412 THD* thd /*!< in: thread handle */
17413 MY_ATTRIBUTE((unused)),
17414 struct st_mysql_sys_var* var /*!< in: pointer to system
17415 variable */
17416 MY_ATTRIBUTE((unused)),
17417 void* var_ptr /*!< out: where the formal
17418 string goes */
17419 MY_ATTRIBUTE((unused)),
17420 const void* save) /*!< in: immediate result from
17421 check function */
17422 {
17423 if (*(my_bool*) save) {
17424 while (log_sys->last_checkpoint_lsn < log_sys->lsn) {
17425 log_make_checkpoint_at(LSN_MAX, TRUE);
17426 fil_flush_file_spaces(FIL_LOG);
17427 }
17428 fil_write_flushed_lsn_to_data_files(log_sys->lsn, 0);
17429 fil_flush_file_spaces(FIL_TABLESPACE);
17430 }
17431 }
17432
17433 /****************************************************************//**
17434 Force a dirty pages flush now. */
17435 static
17436 void
buf_flush_list_now_set(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17437 buf_flush_list_now_set(
17438 /*===================*/
17439 THD* thd /*!< in: thread handle */
17440 MY_ATTRIBUTE((unused)),
17441 struct st_mysql_sys_var* var /*!< in: pointer to system
17442 variable */
17443 MY_ATTRIBUTE((unused)),
17444 void* var_ptr /*!< out: where the formal
17445 string goes */
17446 MY_ATTRIBUTE((unused)),
17447 const void* save) /*!< in: immediate result from
17448 check function */
17449 {
17450 if (*(my_bool*) save) {
17451 buf_flush_list(ULINT_MAX, LSN_MAX, NULL);
17452 buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
17453 }
17454 }
17455
17456 /****************************************************************//**
17457 Force log tracker to track the log synchronously. */
17458 static
17459 void
track_redo_log_now_set(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17460 track_redo_log_now_set(
17461 /*===================*/
17462 THD* thd /*!< in: thread handle */
17463 MY_ATTRIBUTE((unused)),
17464 struct st_mysql_sys_var* var /*!< in: pointer to system
17465 variable */
17466 MY_ATTRIBUTE((unused)),
17467 void* var_ptr /*!< out: where the formal
17468 string goes */
17469 MY_ATTRIBUTE((unused)),
17470 const void* save) /*!< in: immediate result from
17471 check function */
17472 {
17473 if (*(my_bool*) save && srv_track_changed_pages) {
17474
17475 log_online_follow_redo_log();
17476 }
17477 }
17478
17479 #endif /* UNIV_DEBUG */
17480
17481 /***********************************************************************
17482 @return version of the extended FTS API */
17483 uint
innobase_fts_get_version()17484 innobase_fts_get_version()
17485 /*======================*/
17486 {
17487 /* Currently this doesn't make much sense as returning
17488 HA_CAN_FULLTEXT_EXT automatically mean this version is supported.
17489 This supposed to ease future extensions. */
17490 return(2);
17491 }
17492
17493 /***********************************************************************
17494 @return Which part of the extended FTS API is supported */
17495 ulonglong
innobase_fts_flags()17496 innobase_fts_flags()
17497 /*================*/
17498 {
17499 return(FTS_ORDERED_RESULT | FTS_DOCID_IN_RESULT);
17500 }
17501
17502
17503 /***********************************************************************
17504 Find and Retrieve the FTS doc_id for the current result row
17505 @return the document ID */
17506 ulonglong
innobase_fts_retrieve_docid(FT_INFO_EXT * fts_hdl)17507 innobase_fts_retrieve_docid(
17508 /*========================*/
17509 FT_INFO_EXT * fts_hdl) /*!< in: FTS handler */
17510 {
17511 row_prebuilt_t* ft_prebuilt;
17512 fts_result_t* result;
17513
17514 ft_prebuilt = ((NEW_FT_INFO *)fts_hdl)->ft_prebuilt;
17515 result = ((NEW_FT_INFO *)fts_hdl)->ft_result;
17516
17517 if (ft_prebuilt->read_just_key) {
17518 fts_ranking_t* ranking =
17519 rbt_value(fts_ranking_t, result->current);
17520 return(ranking->doc_id);
17521 }
17522
17523 return(ft_prebuilt->fts_doc_id);
17524 }
17525
17526
17527 /***********************************************************************
17528 Find and retrieve the size of the current result
17529 @return number of matching rows */
17530 ulonglong
innobase_fts_count_matches(FT_INFO_EXT * fts_hdl)17531 innobase_fts_count_matches(
17532 /*=======================*/
17533 FT_INFO_EXT* fts_hdl) /*!< in: FTS handler */
17534 {
17535 NEW_FT_INFO* handle = (NEW_FT_INFO *) fts_hdl;
17536
17537 if (handle->ft_result->rankings_by_id != 0) {
17538 return rbt_size(handle->ft_result->rankings_by_id);
17539 } else {
17540 return(0);
17541 }
17542 }
17543
17544 /* These variables are never read by InnoDB or changed. They are a kind of
17545 dummies that are needed by the MySQL infrastructure to call
17546 buffer_pool_dump_now(), buffer_pool_load_now() and buffer_pool_load_abort()
17547 by the user by doing:
17548 SET GLOBAL innodb_buffer_pool_dump_now=ON;
17549 SET GLOBAL innodb_buffer_pool_load_now=ON;
17550 SET GLOBAL innodb_buffer_pool_load_abort=ON;
17551 Their values are read by MySQL and displayed to the user when the variables
17552 are queried, e.g.:
17553 SELECT @@innodb_buffer_pool_dump_now;
17554 SELECT @@innodb_buffer_pool_load_now;
17555 SELECT @@innodb_buffer_pool_load_abort; */
17556 static my_bool innodb_buffer_pool_dump_now = FALSE;
17557 static my_bool innodb_buffer_pool_load_now = FALSE;
17558 static my_bool innodb_buffer_pool_load_abort = FALSE;
17559
17560 /****************************************************************//**
17561 Trigger a dump of the buffer pool if innodb_buffer_pool_dump_now is set
17562 to ON. This function is registered as a callback with MySQL. */
17563 static
17564 void
buffer_pool_dump_now(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17565 buffer_pool_dump_now(
17566 /*=================*/
17567 THD* thd /*!< in: thread handle */
17568 MY_ATTRIBUTE((unused)),
17569 struct st_mysql_sys_var* var /*!< in: pointer to system
17570 variable */
17571 MY_ATTRIBUTE((unused)),
17572 void* var_ptr /*!< out: where the formal
17573 string goes */
17574 MY_ATTRIBUTE((unused)),
17575 const void* save) /*!< in: immediate result from
17576 check function */
17577 {
17578 if (*(my_bool*) save && !srv_read_only_mode) {
17579 buf_dump_start();
17580 }
17581 }
17582
17583 /****************************************************************//**
17584 Trigger a load of the buffer pool if innodb_buffer_pool_load_now is set
17585 to ON. This function is registered as a callback with MySQL. */
17586 static
17587 void
buffer_pool_load_now(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17588 buffer_pool_load_now(
17589 /*=================*/
17590 THD* thd /*!< in: thread handle */
17591 MY_ATTRIBUTE((unused)),
17592 struct st_mysql_sys_var* var /*!< in: pointer to system
17593 variable */
17594 MY_ATTRIBUTE((unused)),
17595 void* var_ptr /*!< out: where the formal
17596 string goes */
17597 MY_ATTRIBUTE((unused)),
17598 const void* save) /*!< in: immediate result from
17599 check function */
17600 {
17601 if (*(my_bool*) save && !srv_read_only_mode) {
17602 buf_load_start();
17603 }
17604 }
17605
17606 /****************************************************************//**
17607 Abort a load of the buffer pool if innodb_buffer_pool_load_abort
17608 is set to ON. This function is registered as a callback with MySQL. */
17609 static
17610 void
buffer_pool_load_abort(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save)17611 buffer_pool_load_abort(
17612 /*===================*/
17613 THD* thd /*!< in: thread handle */
17614 MY_ATTRIBUTE((unused)),
17615 struct st_mysql_sys_var* var /*!< in: pointer to system
17616 variable */
17617 MY_ATTRIBUTE((unused)),
17618 void* var_ptr /*!< out: where the formal
17619 string goes */
17620 MY_ATTRIBUTE((unused)),
17621 const void* save) /*!< in: immediate result from
17622 check function */
17623 {
17624 if (*(my_bool*) save) {
17625 buf_load_abort();
17626 }
17627 }
17628
17629 /** Update innodb_status_output or innodb_status_output_locks,
17630 which control InnoDB "status monitor" output to the error log.
17631 @param[in] thd thread handle
17632 @param[in] var system variable
17633 @param[out] var_ptr current value
17634 @param[in] save to-be-assigned value */
17635 static
17636 void
innodb_status_output_update(THD * thd MY_ATTRIBUTE ((unused)),struct st_mysql_sys_var * var MY_ATTRIBUTE ((unused)),void * var_ptr MY_ATTRIBUTE ((unused)),const void * save MY_ATTRIBUTE ((unused)))17637 innodb_status_output_update(
17638 THD* thd MY_ATTRIBUTE((unused)),
17639 struct st_mysql_sys_var* var MY_ATTRIBUTE((unused)),
17640 void* var_ptr MY_ATTRIBUTE((unused)),
17641 const void* save MY_ATTRIBUTE((unused)))
17642 {
17643 *static_cast<my_bool*>(var_ptr) = *static_cast<const my_bool*>(save);
17644 /* The lock timeout monitor thread also takes care of this
17645 output. */
17646 os_event_set(lock_sys->timeout_event);
17647 }
17648
17649 /*************************************************************//**
17650 Empty free list algorithm. This function is registered as
17651 a callback with MySQL.
17652 @return 0 for valid algorithm */
17653 static
17654 int
innodb_srv_empty_free_list_algorithm_validate(THD * thd,struct st_mysql_sys_var * var,void * save,struct st_mysql_value * value)17655 innodb_srv_empty_free_list_algorithm_validate(
17656 /*===========================*/
17657 THD* thd, /*!< in: thread handle */
17658 struct st_mysql_sys_var* var, /*!< in: pointer to system
17659 variable */
17660 void* save, /*!< out: immediate result
17661 for update function */
17662 struct st_mysql_value* value) /*!< in: incoming string */
17663 {
17664 const char* algorithm_name;
17665 char buff[STRING_BUFFER_USUAL_SIZE];
17666 int len = sizeof(buff);
17667 ulint algo;
17668 srv_empty_free_list_t algorithm;
17669
17670 algorithm_name = value->val_str(value, buff, &len);
17671
17672 if (!algorithm_name) {
17673 return(1);
17674 }
17675
17676 for (algo = 0; algo < array_elements(
17677 innodb_empty_free_list_algorithm_names
17678 ) - 1;
17679 algo++) {
17680 if (!innobase_strcasecmp(
17681 algorithm_name,
17682 innodb_empty_free_list_algorithm_names[algo]))
17683 break;
17684 }
17685
17686 if (algo == array_elements( innodb_empty_free_list_algorithm_names) - 1)
17687 return(1);
17688
17689 algorithm = static_cast<srv_empty_free_list_t>(algo);
17690 if (!innodb_empty_free_list_algorithm_allowed(algorithm)) {
17691 sql_print_warning(
17692 "InnoDB: innodb_empty_free_list_algorithm "
17693 "= 'backoff' requires at least"
17694 " 20MB buffer pool instances.\n");
17695 return(1);
17696 }
17697
17698 *reinterpret_cast<ulong*>(save) = static_cast<ulong>(algorithm);
17699 return(0);
17700 }
17701
17702 static SHOW_VAR innodb_status_variables_export[]= {
17703 {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC},
17704 {NullS, NullS, SHOW_LONG}
17705 };
17706
17707 static struct st_mysql_storage_engine innobase_storage_engine=
17708 { MYSQL_HANDLERTON_INTERFACE_VERSION };
17709
17710 /* plugin options */
17711
17712 static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm,
17713 PLUGIN_VAR_RQCMDARG,
17714 "The algorithm InnoDB uses for page checksumming. Possible values are "
17715 "CRC32 (hardware accelerated if the CPU supports it) "
17716 "write crc32, allow any of the other checksums to match when reading; "
17717 "STRICT_CRC32 "
17718 "write crc32, do not allow other algorithms to match when reading; "
17719 "INNODB "
17720 "write a software calculated checksum, allow any other checksums "
17721 "to match when reading; "
17722 "STRICT_INNODB "
17723 "write a software calculated checksum, do not allow other algorithms "
17724 "to match when reading; "
17725 "NONE "
17726 "write a constant magic number, do not do any checksum verification "
17727 "when reading (same as innodb_checksums=OFF); "
17728 "STRICT_NONE "
17729 "write a constant magic number, do not allow values other than that "
17730 "magic number when reading; "
17731 "Files updated when this option is set to crc32 or strict_crc32 will "
17732 "not be readable by MySQL versions older than 5.6.3",
17733 NULL, NULL, SRV_CHECKSUM_ALGORITHM_INNODB,
17734 &innodb_checksum_algorithm_typelib);
17735
17736
17737 static MYSQL_SYSVAR_ENUM(log_checksum_algorithm, srv_log_checksum_algorithm,
17738 PLUGIN_VAR_RQCMDARG,
17739 "The algorithm InnoDB uses for log block checksums. Possible values are "
17740 "CRC32 (hardware accelerated if the CPU supports it) "
17741 "write crc32, allow any of the other checksums to match when reading; "
17742 "STRICT_CRC32 "
17743 "write crc32, do not allow other algorithms to match when reading; "
17744 "INNODB "
17745 "write a software calculated checksum, allow any other checksums "
17746 "to match when reading; "
17747 "STRICT_INNODB "
17748 "write a software calculated checksum, do not allow other algorithms "
17749 "to match when reading; "
17750 "NONE "
17751 "write a constant magic number, do not do any checksum verification "
17752 "when reading (same as innodb_checksums=OFF); "
17753 "STRICT_NONE "
17754 "write a constant magic number, do not allow values other than that "
17755 "magic number when reading; "
17756 "Logs created when this option is set to crc32/strict_crc32/none/strict_none "
17757 "will not be readable by any MySQL version or Percona Server versions that do"
17758 "not support this feature",
17759 NULL, innodb_log_checksum_algorithm_update, SRV_CHECKSUM_ALGORITHM_INNODB,
17760 &innodb_checksum_algorithm_typelib);
17761
17762
17763 static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums,
17764 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
17765 "DEPRECATED. Use innodb_checksum_algorithm=NONE instead of setting "
17766 "this to OFF. "
17767 "Enable InnoDB checksums validation (enabled by default). "
17768 "Disable with --skip-innodb-checksums.",
17769 NULL, NULL, TRUE);
17770
17771 static MYSQL_SYSVAR_ULONG(log_block_size, innobase_log_block_size,
17772 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
17773 "###EXPERIMENTAL###: The log block size of the transaction log file. Changing for created log file is not supported. Use on your own risk!",
17774 NULL, NULL, (1 << 9)/*512*/, OS_MIN_LOG_BLOCK_SIZE,
17775 (1 << UNIV_PAGE_SIZE_SHIFT_MAX), 0);
17776
17777 static MYSQL_SYSVAR_STR(data_home_dir, innobase_data_home_dir,
17778 PLUGIN_VAR_READONLY,
17779 "The common part for InnoDB table spaces.",
17780 NULL, NULL, NULL);
17781
17782 static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
17783 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
17784 "Enable InnoDB doublewrite buffer (enabled by default). "
17785 "Disable with --skip-innodb-doublewrite.",
17786 NULL, NULL, TRUE);
17787
17788 static MYSQL_SYSVAR_BOOL(stats_include_delete_marked,
17789 srv_stats_include_delete_marked,
17790 PLUGIN_VAR_OPCMDARG,
17791 "Scan delete marked records for persistent stat",
17792 NULL, NULL, FALSE);
17793
17794 static MYSQL_SYSVAR_BOOL(use_atomic_writes, innobase_use_atomic_writes,
17795 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
17796 "Prevent partial page writes, via atomic writes (beta). "
17797 "The option is used to prevent partial writes in case of a crash/poweroff, "
17798 "as faster alternative to doublewrite buffer. "
17799 "Currently this option works only "
17800 "on Linux only with FusionIO device, and directFS filesystem.",
17801 NULL, NULL, FALSE);
17802
17803 static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity,
17804 PLUGIN_VAR_RQCMDARG,
17805 "Number of IOPs the server can do. Tunes the background IO rate",
17806 NULL, innodb_io_capacity_update, 200, 100, ~0UL, 0);
17807
17808 static MYSQL_SYSVAR_ULONG(io_capacity_max, srv_max_io_capacity,
17809 PLUGIN_VAR_RQCMDARG,
17810 "Limit to which innodb_io_capacity can be inflated.",
17811 NULL, innodb_io_capacity_max_update,
17812 SRV_MAX_IO_CAPACITY_DUMMY_DEFAULT, 100,
17813 SRV_MAX_IO_CAPACITY_LIMIT, 0);
17814
17815 #ifdef UNIV_DEBUG
17816 static MYSQL_SYSVAR_BOOL(purge_run_now, innodb_purge_run_now,
17817 PLUGIN_VAR_OPCMDARG,
17818 "Set purge state to RUN",
17819 NULL, purge_run_now_set, FALSE);
17820
17821 static MYSQL_SYSVAR_BOOL(purge_stop_now, innodb_purge_stop_now,
17822 PLUGIN_VAR_OPCMDARG,
17823 "Set purge state to STOP",
17824 NULL, purge_stop_now_set, FALSE);
17825
17826 static MYSQL_SYSVAR_BOOL(log_checkpoint_now, innodb_log_checkpoint_now,
17827 PLUGIN_VAR_OPCMDARG,
17828 "Force checkpoint now",
17829 NULL, checkpoint_now_set, FALSE);
17830
17831 static MYSQL_SYSVAR_BOOL(buf_flush_list_now, innodb_buf_flush_list_now,
17832 PLUGIN_VAR_OPCMDARG,
17833 "Force dirty page flush now",
17834 NULL, buf_flush_list_now_set, FALSE);
17835
17836 static MYSQL_SYSVAR_BOOL(track_redo_log_now,
17837 innodb_track_redo_log_now,
17838 PLUGIN_VAR_OPCMDARG,
17839 "Force log tracker to catch up with checkpoint now",
17840 NULL, track_redo_log_now_set, FALSE);
17841
17842 #endif /* UNIV_DEBUG */
17843
17844 static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size,
17845 PLUGIN_VAR_OPCMDARG,
17846 "Number of UNDO log pages to purge in one batch from the history list.",
17847 NULL, NULL,
17848 300, /* Default setting */
17849 1, /* Minimum value */
17850 5000, 0); /* Maximum value */
17851
17852 static MYSQL_SYSVAR_ULONG(purge_threads, srv_n_purge_threads,
17853 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
17854 "Purge threads can be from 1 to 32. Default is 1.",
17855 NULL, NULL,
17856 1, /* Default setting */
17857 1, /* Minimum value */
17858 SRV_MAX_N_PURGE_THREADS, 0); /* Maximum value */
17859
17860 static MYSQL_SYSVAR_ULONG(sync_array_size, srv_sync_array_size,
17861 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
17862 "Size of the mutex/lock wait array.",
17863 NULL, NULL,
17864 1, /* Default setting */
17865 1, /* Minimum value */
17866 1024, 0); /* Maximum value */
17867
17868 static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
17869 PLUGIN_VAR_OPCMDARG,
17870 "Speeds up the shutdown process of the InnoDB storage engine. Possible "
17871 "values are 0, 1 (faster) or 2 (fastest - crash-like).",
17872 NULL, NULL, 1, 0, 2, 0);
17873
17874 static MYSQL_SYSVAR_BOOL(file_per_table, srv_file_per_table,
17875 PLUGIN_VAR_NOCMDARG,
17876 "Stores each InnoDB table to an .ibd file in the database dir.",
17877 NULL, NULL, TRUE);
17878
17879 static MYSQL_SYSVAR_STR(file_format, innobase_file_format_name,
17880 PLUGIN_VAR_RQCMDARG,
17881 "File format to use for new tables in .ibd files.",
17882 innodb_file_format_name_validate,
17883 innodb_file_format_name_update, "Antelope");
17884
17885 /* "innobase_file_format_check" decides whether we would continue
17886 booting the server if the file format stamped on the system
17887 table space exceeds the maximum file format supported
17888 by the server. Can be set during server startup at command
17889 line or configure file, and a read only variable after
17890 server startup */
17891 static MYSQL_SYSVAR_BOOL(file_format_check, innobase_file_format_check,
17892 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
17893 "Whether to perform system file format check.",
17894 NULL, NULL, TRUE);
17895
17896 /* If a new file format is introduced, the file format
17897 name needs to be updated accordingly. Please refer to
17898 file_format_name_map[] defined in trx0sys.cc for the next
17899 file format name. */
17900 static MYSQL_SYSVAR_STR(file_format_max, innobase_file_format_max,
17901 PLUGIN_VAR_OPCMDARG,
17902 "The highest file format in the tablespace.",
17903 innodb_file_format_max_validate,
17904 innodb_file_format_max_update, "Antelope");
17905
17906 static MYSQL_SYSVAR_STR(ft_server_stopword_table, innobase_server_stopword_table,
17907 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
17908 "The user supplied stopword table name.",
17909 innodb_stopword_table_validate,
17910 NULL,
17911 NULL);
17912
17913 static MYSQL_SYSVAR_UINT(flush_log_at_timeout, srv_flush_log_at_timeout,
17914 PLUGIN_VAR_OPCMDARG,
17915 "Write and flush logs every (n) second.",
17916 NULL, NULL, 1, 0, 2700, 0);
17917
17918 /* Changed to the THDVAR */
17919 //static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
17920 // PLUGIN_VAR_OPCMDARG,
17921 // "Set to 0 (write and flush once per second),"
17922 // " 1 (write and flush at each commit)"
17923 // " or 2 (write at commit, flush once per second).",
17924 // NULL, NULL, 1, 0, 2, 0);
17925
17926 static MYSQL_SYSVAR_BOOL(use_global_flush_log_at_trx_commit, srv_use_global_flush_log_at_trx_commit,
17927 PLUGIN_VAR_NOCMDARG,
17928 "Use global innodb_flush_log_at_trx_commit value. (default: ON).",
17929 NULL, NULL, TRUE);
17930
17931 static MYSQL_SYSVAR_STR(flush_method, innobase_file_flush_method,
17932 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
17933 "With which method to flush data.", NULL, NULL, NULL);
17934
17935 static MYSQL_SYSVAR_BOOL(large_prefix, innobase_large_prefix,
17936 PLUGIN_VAR_NOCMDARG,
17937 "Support large index prefix length of REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes.",
17938 NULL, NULL, FALSE);
17939
17940 static MYSQL_SYSVAR_BOOL(force_load_corrupted, srv_load_corrupted,
17941 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
17942 "Force InnoDB to load metadata of corrupted table.",
17943 NULL, NULL, FALSE);
17944
17945 static MYSQL_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog,
17946 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
17947 "DEPRECATED. This option may be removed in future releases. "
17948 "Please use READ COMMITTED transaction isolation level instead. "
17949 "Force InnoDB to not use next-key locking, to use only row-level locking.",
17950 NULL, NULL, FALSE);
17951
17952 static MYSQL_SYSVAR_ULONG(show_verbose_locks, srv_show_verbose_locks,
17953 PLUGIN_VAR_OPCMDARG,
17954 "Whether to show records locked in SHOW INNODB STATUS.",
17955 NULL, NULL, 0, 0, 1, 0);
17956
17957 static MYSQL_SYSVAR_ULONG(show_locks_held, srv_show_locks_held,
17958 PLUGIN_VAR_RQCMDARG,
17959 "Number of locks held to print for each InnoDB transaction in SHOW INNODB STATUS.",
17960 NULL, NULL, 10, 0, 1000, 0);
17961
17962 #ifdef UNIV_LOG_ARCHIVE
17963 static MYSQL_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
17964 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
17965 "Where full logs should be archived.", NULL, NULL, NULL);
17966
17967 static MYSQL_SYSVAR_BOOL(log_archive, innobase_log_archive,
17968 PLUGIN_VAR_OPCMDARG,
17969 "Set to 1 if you want to have logs archived.",
17970 NULL, innodb_log_archive_update, FALSE);
17971 #endif /* UNIV_LOG_ARCHIVE */
17972
17973 static MYSQL_SYSVAR_STR(log_group_home_dir, srv_log_group_home_dir,
17974 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
17975 "Path to InnoDB log files.", NULL, NULL, NULL);
17976
17977 static MYSQL_SYSVAR_ULONG(log_arch_expire_sec,
17978 srv_log_arch_expire_sec, PLUGIN_VAR_OPCMDARG,
17979 "Expiration time for archived innodb transaction logs.",
17980 NULL, innodb_log_archive_expire_update, 0, 0, ~0UL, 0);
17981
17982 static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
17983 PLUGIN_VAR_RQCMDARG,
17984 "Percentage of dirty pages allowed in bufferpool.",
17985 NULL, innodb_max_dirty_pages_pct_update, 75, 0, 99, 0);
17986
17987 static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct_lwm,
17988 srv_max_dirty_pages_pct_lwm,
17989 PLUGIN_VAR_RQCMDARG,
17990 "Percentage of dirty pages at which flushing kicks in.",
17991 NULL, innodb_max_dirty_pages_pct_lwm_update, 0, 0, 99, 0);
17992
17993 static MYSQL_SYSVAR_ULONG(adaptive_flushing_lwm,
17994 srv_adaptive_flushing_lwm,
17995 PLUGIN_VAR_RQCMDARG,
17996 "Percentage of log capacity below which no adaptive flushing happens.",
17997 NULL, NULL, 10, 0, 70, 0);
17998
17999 static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
18000 PLUGIN_VAR_NOCMDARG,
18001 "Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
18002 NULL, NULL, TRUE);
18003
18004 static MYSQL_SYSVAR_ULONG(flushing_avg_loops,
18005 srv_flushing_avg_loops,
18006 PLUGIN_VAR_RQCMDARG,
18007 "Number of iterations over which the background flushing is averaged.",
18008 NULL, NULL, 30, 1, 1000, 0);
18009
18010 static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
18011 PLUGIN_VAR_RQCMDARG,
18012 "Desired maximum length of the purge queue (0 = no limit)",
18013 NULL, NULL, 0, 0, ~0UL, 0);
18014
18015 static MYSQL_SYSVAR_ULONG(max_purge_lag_delay, srv_max_purge_lag_delay,
18016 PLUGIN_VAR_RQCMDARG,
18017 "Maximum delay of user threads in micro-seconds",
18018 NULL, NULL,
18019 0L, /* Default seting */
18020 0L, /* Minimum value */
18021 10000000UL, 0); /* Maximum value */
18022
18023 static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
18024 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
18025 "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
18026 NULL, NULL, FALSE);
18027
18028 static MYSQL_SYSVAR_BOOL(status_file, innobase_create_status_file,
18029 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
18030 "Enable SHOW ENGINE INNODB STATUS output in the innodb_status.<pid> file",
18031 NULL, NULL, FALSE);
18032
18033 static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
18034 PLUGIN_VAR_OPCMDARG,
18035 "Enable statistics gathering for metadata commands such as "
18036 "SHOW TABLE STATUS for tables that use transient statistics (off by default)",
18037 NULL, NULL, FALSE);
18038
18039 static MYSQL_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_transient_sample_pages,
18040 PLUGIN_VAR_RQCMDARG,
18041 "Deprecated, use innodb_stats_transient_sample_pages instead",
18042 NULL, innodb_stats_sample_pages_update, 8, 1, ~0ULL, 0);
18043
18044 static MYSQL_SYSVAR_ULONGLONG(stats_transient_sample_pages,
18045 srv_stats_transient_sample_pages,
18046 PLUGIN_VAR_RQCMDARG,
18047 "The number of leaf index pages to sample when calculating transient "
18048 "statistics (if persistent statistics are not used, default 8)",
18049 NULL, NULL, 8, 1, ~0ULL, 0);
18050
18051 static MYSQL_SYSVAR_BOOL(stats_persistent, srv_stats_persistent,
18052 PLUGIN_VAR_OPCMDARG,
18053 "InnoDB persistent statistics enabled for all tables unless overridden "
18054 "at table level",
18055 NULL, NULL, TRUE);
18056
18057 static MYSQL_SYSVAR_BOOL(stats_auto_recalc, srv_stats_auto_recalc,
18058 PLUGIN_VAR_OPCMDARG,
18059 "InnoDB automatic recalculation of persistent statistics enabled for all "
18060 "tables unless overridden at table level (automatic recalculation is only "
18061 "done when InnoDB decides that the table has changed too much and needs a "
18062 "new statistics)",
18063 NULL, NULL, TRUE);
18064
18065 static MYSQL_SYSVAR_ULONGLONG(stats_persistent_sample_pages,
18066 srv_stats_persistent_sample_pages,
18067 PLUGIN_VAR_RQCMDARG,
18068 "The number of leaf index pages to sample when calculating persistent "
18069 "statistics (by ANALYZE, default 20)",
18070 NULL, NULL, 20, 1, ~0ULL, 0);
18071
18072 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
18073 PLUGIN_VAR_OPCMDARG,
18074 "Enable InnoDB adaptive hash index (enabled by default). "
18075 "Disable with --skip-innodb-adaptive-hash-index.",
18076 NULL, innodb_adaptive_hash_index_update, TRUE);
18077
18078 /* btr_search_index_num is constrained to machine word size for historical
18079 reasons. This limitation can be easily removed later. */
18080 static MYSQL_SYSVAR_ULONG(adaptive_hash_index_partitions, btr_search_index_num,
18081 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18082 "Number of InnoDB adaptive hash index partitions (default 1: disable "
18083 "partitioning)",
18084 NULL, NULL, 1, 1, sizeof(ulint) * 8, 0);
18085
18086 static MYSQL_SYSVAR_ULONG(replication_delay, srv_replication_delay,
18087 PLUGIN_VAR_RQCMDARG,
18088 "Replication thread delay (ms) on the slave server if "
18089 "innodb_thread_concurrency is reached (0 by default)",
18090 NULL, NULL, 0, 0, ~0UL, 0);
18091
18092 static MYSQL_SYSVAR_UINT(compression_level, page_zip_level,
18093 PLUGIN_VAR_RQCMDARG,
18094 "Compression level used for compressed row format. 0 is no compression"
18095 ", 1 is fastest, 9 is best compression and default is 6.",
18096 NULL, NULL, DEFAULT_COMPRESSION_LEVEL, 0, 9, 0);
18097
18098 static MYSQL_SYSVAR_BOOL(log_compressed_pages, page_zip_log_pages,
18099 PLUGIN_VAR_OPCMDARG,
18100 "Enables/disables the logging of entire compressed page images."
18101 " InnoDB logs the compressed pages to prevent corruption if"
18102 " the zlib compression algorithm changes."
18103 " When turned OFF, InnoDB will assume that the zlib"
18104 " compression algorithm doesn't change.",
18105 NULL, NULL, TRUE);
18106
18107 static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
18108 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18109 "DEPRECATED. This option may be removed in future releases, "
18110 "together with the option innodb_use_sys_malloc and with the InnoDB's "
18111 "internal memory allocator. "
18112 "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
18113 NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
18114
18115 static MYSQL_SYSVAR_ULONG(autoextend_increment, srv_auto_extend_increment,
18116 PLUGIN_VAR_RQCMDARG,
18117 "Data file autoextend increment in megabytes",
18118 NULL, NULL, 64L, 1L, 1000L, 0);
18119
18120 static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
18121 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18122 "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
18123 NULL, NULL, 128*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L);
18124
18125 static MYSQL_SYSVAR_BOOL(buffer_pool_populate, srv_numa_interleave,
18126 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18127 "Depricated. This option is temporary alias of --innodb-numa-interleave.",
18128 NULL, NULL, FALSE);
18129
18130 static MYSQL_SYSVAR_ENUM(foreground_preflush, srv_foreground_preflush,
18131 PLUGIN_VAR_OPCMDARG,
18132 "The algorithm InnoDB uses for the query threads at sync preflush. "
18133 "Possible values are "
18134 "SYNC_PREFLUSH: perform a sync preflush as Oracle MySQL; "
18135 "EXPONENTIAL_BACKOFF: (default) wait for the page cleaner flush.",
18136 NULL, NULL, SRV_FOREGROUND_PREFLUSH_EXP_BACKOFF,
18137 &innodb_foreground_preflush_typelib);
18138
18139 #ifdef UNIV_LINUX
18140
18141 static MYSQL_SYSVAR_ULONG(sched_priority_cleaner, srv_sched_priority_cleaner,
18142 PLUGIN_VAR_RQCMDARG,
18143 "Nice value for the cleaner and LRU manager thread scheduling",
18144 NULL, innodb_sched_priority_cleaner_update, 19, 0, 39, 0);
18145
18146 #endif /* UNIV_LINUX */
18147
18148 #if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
18149 static MYSQL_SYSVAR_ULONG(page_hash_locks, srv_n_page_hash_locks,
18150 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
18151 "Number of rw_locks protecting buffer pool page_hash. Rounded up to the next power of 2",
18152 NULL, NULL, 16, 1, MAX_PAGE_HASH_LOCKS, 0);
18153
18154 static MYSQL_SYSVAR_ULONG(doublewrite_batch_size, srv_doublewrite_batch_size,
18155 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
18156 "Number of pages reserved in doublewrite buffer for batch flushing",
18157 NULL, NULL, 120, 1, 127, 0);
18158
18159 #ifdef UNIV_LINUX
18160
18161 static MYSQL_SYSVAR_ULONG(sched_priority_purge, srv_sched_priority_purge,
18162 PLUGIN_VAR_RQCMDARG,
18163 "Nice value for the purge thread scheduling",
18164 NULL, innodb_sched_priority_purge_update, 19, 0, 39, 0);
18165
18166 static MYSQL_SYSVAR_ULONG(sched_priority_io, srv_sched_priority_io,
18167 PLUGIN_VAR_RQCMDARG,
18168 "Nice value for the I/O handler thread scheduling",
18169 NULL, innodb_sched_priority_io_update, 19, 0, 39, 0);
18170
18171 static MYSQL_SYSVAR_ULONG(sched_priority_master, srv_sched_priority_master,
18172 PLUGIN_VAR_RQCMDARG,
18173 "Nice value for the master thread scheduling",
18174 NULL, innodb_sched_priority_master_update, 19, 0, 39, 0);
18175
18176 static MYSQL_SYSVAR_BOOL(priority_purge, srv_purge_thread_priority,
18177 PLUGIN_VAR_OPCMDARG,
18178 "Make purge coordinator and worker threads acquire shared resources with "
18179 "priority", NULL, NULL, FALSE);
18180
18181 static MYSQL_SYSVAR_BOOL(priority_io, srv_io_thread_priority,
18182 PLUGIN_VAR_OPCMDARG,
18183 "Make I/O threads acquire shared resources with priority",
18184 NULL, NULL, FALSE);
18185
18186 static MYSQL_SYSVAR_BOOL(priority_cleaner, srv_cleaner_thread_priority,
18187 PLUGIN_VAR_OPCMDARG,
18188 "Make buffer pool cleaner and LRU manager threads acquire shared resources "
18189 "with priority",
18190 NULL, NULL, FALSE);
18191
18192 static MYSQL_SYSVAR_BOOL(priority_master, srv_master_thread_priority,
18193 PLUGIN_VAR_OPCMDARG,
18194 "Make buffer pool cleaner thread acquire shared resources with priority",
18195 NULL, NULL, FALSE);
18196
18197 #endif /* UNIV_LINUX */
18198
18199 static MYSQL_SYSVAR_ULONG(cleaner_max_lru_time, srv_cleaner_max_lru_time,
18200 PLUGIN_VAR_RQCMDARG,
18201 "The maximum time limit for a single LRU tail flush iteration by the page "
18202 "cleaner thread in miliseconds",
18203 NULL, NULL, 1000, 0, ~0UL, 0);
18204
18205 static MYSQL_SYSVAR_ULONG(cleaner_max_flush_time, srv_cleaner_max_flush_time,
18206 PLUGIN_VAR_RQCMDARG,
18207 "The maximum time limit for a single flush list flush iteration by the page "
18208 "cleaner thread in miliseconds",
18209 NULL, NULL, 1000, 0, ~0UL, 0);
18210
18211 static MYSQL_SYSVAR_ULONG(cleaner_flush_chunk_size,
18212 srv_cleaner_flush_chunk_size,
18213 PLUGIN_VAR_RQCMDARG,
18214 "Divide page cleaner flush list flush batches into chunks of this size",
18215 NULL, NULL, 100, 1, ~0UL, 0);
18216
18217 static MYSQL_SYSVAR_ULONG(cleaner_lru_chunk_size,
18218 srv_cleaner_lru_chunk_size,
18219 PLUGIN_VAR_RQCMDARG,
18220 "Divide page cleaner LRU list flush batches into chunks of this size",
18221 NULL, NULL, 100, 1, ~0UL, 0);
18222
18223 static MYSQL_SYSVAR_ULONG(cleaner_free_list_lwm, srv_cleaner_free_list_lwm,
18224 PLUGIN_VAR_RQCMDARG,
18225 "Page cleaner will keep on flushing the same buffer pool instance if its "
18226 "free list length is below this percentage of innodb_lru_scan_depth",
18227 NULL, NULL, 10, 0, 100, 0);
18228
18229 static MYSQL_SYSVAR_BOOL(cleaner_eviction_factor, srv_cleaner_eviction_factor,
18230 PLUGIN_VAR_OPCMDARG,
18231 "Make page cleaner LRU flushes use evicted instead of flushed page counts "
18232 "for its heuristics",
18233 NULL, NULL, FALSE);
18234
18235 #endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
18236
18237 static MYSQL_SYSVAR_ENUM(cleaner_lsn_age_factor,
18238 srv_cleaner_lsn_age_factor,
18239 PLUGIN_VAR_OPCMDARG,
18240 "The formula for LSN age factor for page cleaner adaptive flushing. "
18241 "LEGACY: Original Oracle MySQL 5.6 formula. "
18242 "HIGH_CHECKPOINT: (the default) Percona Server 5.6 formula.",
18243 NULL, NULL, SRV_CLEANER_LSN_AGE_FACTOR_HIGH_CHECKPOINT,
18244 &innodb_cleaner_lsn_age_factor_typelib);
18245
18246 static MYSQL_SYSVAR_ENUM(empty_free_list_algorithm,
18247 srv_empty_free_list_algorithm,
18248 PLUGIN_VAR_OPCMDARG,
18249 "The algorithm to use for empty free list handling. Allowed values: "
18250 "LEGACY: Original Oracle MySQL 5.6 handling with single page flushes; "
18251 "BACKOFF: (default) Wait until cleaner produces a free page.",
18252 innodb_srv_empty_free_list_algorithm_validate, NULL, SRV_EMPTY_FREE_LIST_BACKOFF,
18253 &innodb_empty_free_list_algorithm_typelib);
18254
18255 static MYSQL_SYSVAR_LONG(buffer_pool_instances, innobase_buffer_pool_instances,
18256 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18257 "Number of buffer pool instances, set to higher value on high-end machines to increase scalability",
18258 NULL, NULL, 0L, 0L, MAX_BUFFER_POOLS, 1L);
18259
18260 static MYSQL_SYSVAR_STR(buffer_pool_filename, srv_buf_dump_filename,
18261 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
18262 "Filename to/from which to dump/load the InnoDB buffer pool",
18263 innodb_srv_buf_dump_filename_validate, NULL, SRV_BUF_DUMP_FILENAME_DEFAULT);
18264
18265 static MYSQL_SYSVAR_BOOL(buffer_pool_dump_now, innodb_buffer_pool_dump_now,
18266 PLUGIN_VAR_RQCMDARG,
18267 "Trigger an immediate dump of the buffer pool into a file named @@innodb_buffer_pool_filename",
18268 NULL, buffer_pool_dump_now, FALSE);
18269
18270 static MYSQL_SYSVAR_BOOL(buffer_pool_dump_at_shutdown, srv_buffer_pool_dump_at_shutdown,
18271 PLUGIN_VAR_RQCMDARG,
18272 "Dump the buffer pool into a file named @@innodb_buffer_pool_filename",
18273 NULL, NULL, FALSE);
18274
18275 #ifdef UNIV_DEBUG
18276 static MYSQL_SYSVAR_STR(buffer_pool_evict, srv_buffer_pool_evict,
18277 PLUGIN_VAR_RQCMDARG,
18278 "Evict pages from the buffer pool",
18279 NULL, innodb_buffer_pool_evict_update, "");
18280 #endif /* UNIV_DEBUG */
18281
18282 static MYSQL_SYSVAR_BOOL(buffer_pool_load_now, innodb_buffer_pool_load_now,
18283 PLUGIN_VAR_RQCMDARG,
18284 "Trigger an immediate load of the buffer pool from a file named @@innodb_buffer_pool_filename",
18285 NULL, buffer_pool_load_now, FALSE);
18286
18287 static MYSQL_SYSVAR_BOOL(buffer_pool_load_abort, innodb_buffer_pool_load_abort,
18288 PLUGIN_VAR_RQCMDARG,
18289 "Abort a currently running load of the buffer pool",
18290 NULL, buffer_pool_load_abort, FALSE);
18291
18292 /* there is no point in changing this during runtime, thus readonly */
18293 static MYSQL_SYSVAR_BOOL(buffer_pool_load_at_startup, srv_buffer_pool_load_at_startup,
18294 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18295 "Load the buffer pool from a file named @@innodb_buffer_pool_filename",
18296 NULL, NULL, FALSE);
18297
18298 static MYSQL_SYSVAR_ULONG(lru_scan_depth, srv_LRU_scan_depth,
18299 PLUGIN_VAR_RQCMDARG,
18300 "How deep to scan LRU to keep it clean",
18301 NULL, NULL, 1024, 100, ~0UL, 0);
18302
18303 static MYSQL_SYSVAR_ULONG(flush_neighbors, srv_flush_neighbors,
18304 PLUGIN_VAR_OPCMDARG,
18305 "Set to 0 (don't flush neighbors from buffer pool),"
18306 " 1 (flush contiguous neighbors from buffer pool)"
18307 " or 2 (flush neighbors from buffer pool),"
18308 " when flushing a block",
18309 NULL, NULL, 1, 0, 2, 0);
18310
18311 static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
18312 PLUGIN_VAR_RQCMDARG,
18313 "Helps in performance tuning in heavily concurrent environments.",
18314 innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
18315
18316 static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
18317 PLUGIN_VAR_RQCMDARG,
18318 "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
18319 NULL, NULL, 5000L, 1L, ~0UL, 0);
18320
18321 static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction,
18322 PLUGIN_VAR_RQCMDARG,
18323 "A deprecated alias of kill_idle_transaction server variable.",
18324 NULL, innodb_kill_idle_transaction_update, 0, 0, LONG_TIMEOUT, 0);
18325
18326 static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
18327 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR,
18328 "Number of file I/O threads in InnoDB.",
18329 NULL, NULL, 4, 4, 64, 0);
18330
18331 static MYSQL_SYSVAR_BOOL(ft_enable_diag_print, fts_enable_diag_print,
18332 PLUGIN_VAR_OPCMDARG,
18333 "Whether to enable additional FTS diagnostic printout ",
18334 NULL, NULL, FALSE);
18335
18336 static MYSQL_SYSVAR_BOOL(disable_sort_file_cache, srv_disable_sort_file_cache,
18337 PLUGIN_VAR_OPCMDARG,
18338 "Whether to disable OS system file cache for sort I/O",
18339 NULL, NULL, FALSE);
18340
18341 static MYSQL_SYSVAR_STR(ft_aux_table, fts_internal_tbl_name,
18342 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_MEMALLOC,
18343 "FTS internal auxiliary table to be checked",
18344 innodb_internal_table_validate,
18345 NULL, NULL);
18346
18347 static MYSQL_SYSVAR_ULONG(ft_cache_size, fts_max_cache_size,
18348 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18349 "InnoDB Fulltext search cache size in bytes",
18350 NULL, NULL, 8000000, 1600000, 80000000, 0);
18351
18352 static MYSQL_SYSVAR_ULONG(ft_total_cache_size, fts_max_total_cache_size,
18353 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18354 "Total memory allocated for InnoDB Fulltext Search cache",
18355 NULL, NULL, 640000000, 32000000, 1600000000, 0);
18356
18357 static MYSQL_SYSVAR_ULONG(ft_result_cache_limit, fts_result_cache_limit,
18358 PLUGIN_VAR_RQCMDARG,
18359 "InnoDB Fulltext search query result cache limit in bytes",
18360 NULL, NULL, 2000000000L, 1000000L, 4294967295UL, 0);
18361
18362 static MYSQL_SYSVAR_ULONG(ft_min_token_size, fts_min_token_size,
18363 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18364 "InnoDB Fulltext search minimum token size in characters",
18365 NULL, NULL, 3, 0, 16, 0);
18366
18367 static MYSQL_SYSVAR_ULONG(ft_max_token_size, fts_max_token_size,
18368 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18369 "InnoDB Fulltext search maximum token size in characters",
18370 NULL, NULL, FTS_MAX_WORD_LEN_IN_CHAR, 10, FTS_MAX_WORD_LEN_IN_CHAR, 0);
18371
18372
18373 static MYSQL_SYSVAR_ULONG(ft_num_word_optimize, fts_num_word_optimize,
18374 PLUGIN_VAR_OPCMDARG,
18375 "InnoDB Fulltext search number of words to optimize for each optimize table call ",
18376 NULL, NULL, 2000, 1000, 10000, 0);
18377
18378 static MYSQL_SYSVAR_ULONG(ft_sort_pll_degree, fts_sort_pll_degree,
18379 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18380 "InnoDB Fulltext search parallel sort degree, will round up to nearest power of 2 number",
18381 NULL, NULL, 2, 1, 16, 0);
18382
18383 static MYSQL_SYSVAR_ULONG(sort_buffer_size, srv_sort_buf_size,
18384 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18385 "Memory buffer size for index creation",
18386 NULL, NULL, 1048576, 65536, 64<<20, 0);
18387
18388 static MYSQL_SYSVAR_ULONGLONG(online_alter_log_max_size, srv_online_max_size,
18389 PLUGIN_VAR_RQCMDARG,
18390 "Maximum modification log file size for online index creation",
18391 NULL, NULL, 128<<20, 65536, ~0ULL, 0);
18392
18393 static MYSQL_SYSVAR_BOOL(optimize_fulltext_only, innodb_optimize_fulltext_only,
18394 PLUGIN_VAR_NOCMDARG,
18395 "Only optimize the Fulltext index of the table",
18396 NULL, NULL, FALSE);
18397
18398 static MYSQL_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
18399 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18400 "Number of background read I/O threads in InnoDB.",
18401 NULL, NULL, 4, 1, 64, 0);
18402
18403 static MYSQL_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
18404 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18405 "Number of background write I/O threads in InnoDB.",
18406 NULL, NULL, 4, 1, 64, 0);
18407
18408 static MYSQL_SYSVAR_ULONG(force_recovery, srv_force_recovery,
18409 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18410 "Helps to save your data in case the disk image of the database becomes corrupt.",
18411 NULL, NULL, 0, 0, 6, 0);
18412
18413 #ifndef DBUG_OFF
18414 static MYSQL_SYSVAR_ULONG(force_recovery_crash, srv_force_recovery_crash,
18415 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18416 "Kills the server during crash recovery.",
18417 NULL, NULL, 0, 0, 10, 0);
18418 #endif /* !DBUG_OFF */
18419
18420 static MYSQL_SYSVAR_ULONG(page_size, srv_page_size,
18421 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
18422 "Page size to use for all InnoDB tablespaces.",
18423 NULL, NULL, UNIV_PAGE_SIZE_DEF,
18424 UNIV_PAGE_SIZE_MIN, UNIV_PAGE_SIZE_MAX, 0);
18425
18426 static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
18427 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18428 "The size of the buffer which InnoDB uses to write log to the log files on disk.",
18429 NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
18430
18431 static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
18432 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18433 "Size of each log file in a log group.",
18434 NULL, NULL, 48*1024*1024L, 1*1024*1024L, LONGLONG_MAX, 1024*1024L);
18435
18436 static MYSQL_SYSVAR_ULONG(log_files_in_group, srv_n_log_files,
18437 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18438 "Number of log files in the log group. InnoDB writes to the files in a circular fashion.",
18439 NULL, NULL, 2, 2, SRV_N_LOG_FILES_MAX, 0);
18440
18441 /* Note that the default and minimum values are set to 0 to
18442 detect if the option is passed and print deprecation message */
18443 static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
18444 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18445 "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
18446 NULL, NULL, 0, 0, 10, 0);
18447
18448 static MYSQL_SYSVAR_UINT(old_blocks_pct, innobase_old_blocks_pct,
18449 PLUGIN_VAR_RQCMDARG,
18450 "Percentage of the buffer pool to reserve for 'old' blocks.",
18451 NULL, innodb_old_blocks_pct_update, 100 * 3 / 8, 5, 95, 0);
18452
18453 static MYSQL_SYSVAR_UINT(old_blocks_time, buf_LRU_old_threshold_ms,
18454 PLUGIN_VAR_RQCMDARG,
18455 "Move blocks to the 'new' end of the buffer pool if the first access"
18456 " was at least this many milliseconds ago."
18457 " The timeout is disabled if 0.",
18458 NULL, NULL, 1000, 0, UINT_MAX32, 0);
18459
18460 static MYSQL_SYSVAR_LONG(open_files, innobase_open_files,
18461 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18462 "How many files at the maximum InnoDB keeps open at the same time.",
18463 NULL, NULL, 0L, 0L, LONG_MAX, 0);
18464
18465 static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
18466 PLUGIN_VAR_RQCMDARG,
18467 "Count of spin-loop rounds in InnoDB mutexes (30 by default)",
18468 NULL, NULL, 30L, 0L, ~0UL, 0);
18469
18470 static MYSQL_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
18471 PLUGIN_VAR_OPCMDARG,
18472 "Maximum delay between polling for a spin lock (6 by default)",
18473 NULL, NULL, 6L, 0L, ~0UL, 0);
18474
18475 static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
18476 PLUGIN_VAR_RQCMDARG,
18477 "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
18478 NULL, NULL, 0, 0, 1000, 0);
18479
18480 #ifdef HAVE_ATOMIC_BUILTINS
18481 static MYSQL_SYSVAR_ULONG(
18482 adaptive_max_sleep_delay, srv_adaptive_max_sleep_delay,
18483 PLUGIN_VAR_RQCMDARG,
18484 "The upper limit of the sleep delay in usec. Value of 0 disables it.",
18485 NULL, NULL,
18486 150000, /* Default setting */
18487 0, /* Minimum value */
18488 1000000, 0); /* Maximum value */
18489 #endif /* HAVE_ATOMIC_BUILTINS */
18490
18491 static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
18492 PLUGIN_VAR_RQCMDARG,
18493 "Time of innodb thread sleeping before joining InnoDB queue (usec). "
18494 "Value 0 disable a sleep",
18495 NULL, NULL,
18496 10000L,
18497 0L,
18498 1000000L, 0);
18499
18500 static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path,
18501 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18502 "Path to individual files and their sizes.",
18503 NULL, NULL, NULL);
18504
18505 static MYSQL_SYSVAR_STR(undo_directory, srv_undo_dir,
18506 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18507 "Directory where undo tablespace files live, this path can be absolute.",
18508 NULL, NULL, ".");
18509
18510 static MYSQL_SYSVAR_ULONG(undo_tablespaces, srv_undo_tablespaces,
18511 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18512 "Number of undo tablespaces to use. ",
18513 NULL, NULL,
18514 0L, /* Default seting */
18515 0L, /* Minimum value */
18516 126L, 0); /* Maximum value */
18517
18518 static MYSQL_SYSVAR_ULONG(undo_logs, srv_undo_logs,
18519 PLUGIN_VAR_OPCMDARG,
18520 "Number of undo logs to use.",
18521 NULL, NULL,
18522 TRX_SYS_N_RSEGS, /* Default setting */
18523 1, /* Minimum value */
18524 TRX_SYS_N_RSEGS, 0); /* Maximum value */
18525
18526 /* Alias for innodb_undo_logs, this config variable is deprecated. */
18527 static MYSQL_SYSVAR_ULONG(rollback_segments, srv_undo_logs,
18528 PLUGIN_VAR_OPCMDARG,
18529 "Number of undo logs to use (deprecated).",
18530 NULL, NULL,
18531 TRX_SYS_N_RSEGS, /* Default setting */
18532 1, /* Minimum value */
18533 TRX_SYS_N_RSEGS, 0); /* Maximum value */
18534
18535 static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
18536 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
18537 "The AUTOINC lock modes supported by InnoDB: "
18538 "0 => Old style AUTOINC locking (for backward"
18539 " compatibility) "
18540 "1 => New style AUTOINC locking "
18541 "2 => No AUTOINC locking (unsafe for SBR)",
18542 NULL, NULL,
18543 AUTOINC_NEW_STYLE_LOCKING, /* Default setting */
18544 AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
18545 AUTOINC_NO_LOCKING, 0); /* Maximum value */
18546
18547 static MYSQL_SYSVAR_STR(version, innodb_version_str,
18548 PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
18549 "Percona-InnoDB-plugin version", NULL, NULL, INNODB_VERSION_STR);
18550
18551 static MYSQL_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
18552 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18553 "DEPRECATED. This option may be removed in future releases, "
18554 "together with the InnoDB's internal memory allocator. "
18555 "Use OS memory allocator instead of InnoDB's internal memory allocator",
18556 NULL, NULL, TRUE);
18557
18558 static MYSQL_SYSVAR_BOOL(use_native_aio, srv_use_native_aio,
18559 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18560 "Use native AIO if supported on this platform.",
18561 NULL, NULL, TRUE);
18562
18563 #ifdef HAVE_LIBNUMA
18564 static MYSQL_SYSVAR_BOOL(numa_interleave, srv_numa_interleave,
18565 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18566 "Use NUMA interleave memory policy to allocate InnoDB buffer pool.",
18567 NULL, NULL, FALSE);
18568 #endif // HAVE_LIBNUMA
18569
18570 static MYSQL_SYSVAR_BOOL(api_enable_binlog, ib_binlog_enabled,
18571 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18572 "Enable binlog for applications direct access InnoDB through InnoDB APIs",
18573 NULL, NULL, FALSE);
18574
18575 static MYSQL_SYSVAR_BOOL(api_enable_mdl, ib_mdl_enabled,
18576 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18577 "Enable MDL for applications direct access InnoDB through InnoDB APIs",
18578 NULL, NULL, FALSE);
18579
18580 static MYSQL_SYSVAR_BOOL(api_disable_rowlock, ib_disable_row_lock,
18581 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
18582 "Disable row lock when direct access InnoDB through InnoDB APIs",
18583 NULL, NULL, FALSE);
18584
18585 static MYSQL_SYSVAR_ULONG(api_trx_level, ib_trx_level_setting,
18586 PLUGIN_VAR_OPCMDARG,
18587 "InnoDB API transaction isolation level",
18588 NULL, NULL,
18589 0, /* Default setting */
18590 0, /* Minimum value */
18591 3, 0); /* Maximum value */
18592
18593 static MYSQL_SYSVAR_ULONG(api_bk_commit_interval, ib_bk_commit_interval,
18594 PLUGIN_VAR_OPCMDARG,
18595 "Background commit interval in seconds",
18596 NULL, NULL,
18597 5, /* Default setting */
18598 1, /* Minimum value */
18599 1024 * 1024 * 1024, 0); /* Maximum value */
18600
18601 static MYSQL_SYSVAR_STR(change_buffering, innobase_change_buffering,
18602 PLUGIN_VAR_RQCMDARG,
18603 "Buffer changes to reduce random access: "
18604 "OFF, ON, inserting, deleting, changing, or purging.",
18605 innodb_change_buffering_validate,
18606 innodb_change_buffering_update, "all");
18607
18608 static MYSQL_SYSVAR_UINT(change_buffer_max_size,
18609 innobase_change_buffer_max_size,
18610 PLUGIN_VAR_RQCMDARG,
18611 "Maximum on-disk size of change buffer in terms of percentage"
18612 " of the buffer pool.",
18613 NULL, innodb_change_buffer_max_size_update,
18614 CHANGE_BUFFER_DEFAULT_SIZE, 0, 50, 0);
18615
18616 static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method,
18617 PLUGIN_VAR_RQCMDARG,
18618 "Specifies how InnoDB index statistics collection code should "
18619 "treat NULLs. Possible values are NULLS_EQUAL (default), "
18620 "NULLS_UNEQUAL and NULLS_IGNORED",
18621 NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib);
18622
18623 static MYSQL_SYSVAR_BOOL(track_changed_pages, srv_track_changed_pages,
18624 PLUGIN_VAR_NOCMDARG
18625 #ifndef UNIV_DEBUG
18626 /* Make this variable dynamic for debug builds to
18627 provide a testcase sync facility */
18628 | PLUGIN_VAR_READONLY
18629 #endif
18630 ,
18631 "Track the redo log for changed pages and output a changed page bitmap",
18632 #ifdef UNIV_DEBUG
18633 innodb_track_changed_pages_validate,
18634 #else
18635 NULL,
18636 #endif
18637 NULL, FALSE);
18638
18639 static MYSQL_SYSVAR_ULONGLONG(max_bitmap_file_size, srv_max_bitmap_file_size,
18640 PLUGIN_VAR_RQCMDARG,
18641 "The maximum size of changed page bitmap files",
18642 NULL, NULL, 100*1024*1024ULL, 4096ULL, ULONGLONG_MAX, 0);
18643
18644 static MYSQL_SYSVAR_ULONGLONG(max_changed_pages, srv_max_changed_pages,
18645 PLUGIN_VAR_RQCMDARG,
18646 "The maximum number of rows for "
18647 "INFORMATION_SCHEMA.INNODB_CHANGED_PAGES table, "
18648 "0 - unlimited",
18649 NULL, NULL, 1000000, 0, ~0ULL, 0);
18650
18651 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
18652 static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
18653 PLUGIN_VAR_RQCMDARG,
18654 "Debug flags for InnoDB change buffering (0=none, 2=crash at merge)",
18655 NULL, NULL, 0, 0, 2, 0);
18656
18657 static MYSQL_SYSVAR_BOOL(disable_background_merge,
18658 srv_ibuf_disable_background_merge,
18659 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_RQCMDARG,
18660 "Disable change buffering merges by the master thread",
18661 NULL, NULL, FALSE);
18662 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
18663
18664 static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead,
18665 PLUGIN_VAR_NOCMDARG,
18666 "Whether to use read ahead for random access within an extent.",
18667 NULL, NULL, FALSE);
18668
18669 static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
18670 PLUGIN_VAR_RQCMDARG,
18671 "Number of pages that must be accessed sequentially for InnoDB to "
18672 "trigger a readahead.",
18673 NULL, NULL, 56, 0, 64, 0);
18674
18675 static MYSQL_SYSVAR_STR(monitor_enable, innobase_enable_monitor_counter,
18676 PLUGIN_VAR_RQCMDARG,
18677 "Turn on a monitor counter",
18678 innodb_monitor_validate,
18679 innodb_enable_monitor_update, NULL);
18680
18681 static MYSQL_SYSVAR_STR(monitor_disable, innobase_disable_monitor_counter,
18682 PLUGIN_VAR_RQCMDARG,
18683 "Turn off a monitor counter",
18684 innodb_monitor_validate,
18685 innodb_disable_monitor_update, NULL);
18686
18687 static MYSQL_SYSVAR_STR(monitor_reset, innobase_reset_monitor_counter,
18688 PLUGIN_VAR_RQCMDARG,
18689 "Reset a monitor counter",
18690 innodb_monitor_validate,
18691 innodb_reset_monitor_update, NULL);
18692
18693 static MYSQL_SYSVAR_STR(monitor_reset_all, innobase_reset_all_monitor_counter,
18694 PLUGIN_VAR_RQCMDARG,
18695 "Reset all values for a monitor counter",
18696 innodb_monitor_validate,
18697 innodb_reset_all_monitor_update, NULL);
18698
18699 static MYSQL_SYSVAR_BOOL(status_output, srv_print_innodb_monitor,
18700 PLUGIN_VAR_OPCMDARG, "Enable InnoDB monitor output to the error log.",
18701 NULL, innodb_status_output_update, FALSE);
18702
18703 static MYSQL_SYSVAR_BOOL(status_output_locks, srv_print_innodb_lock_monitor,
18704 PLUGIN_VAR_OPCMDARG, "Enable InnoDB lock monitor output to the error log."
18705 " Requires innodb_status_output=ON.",
18706 NULL, innodb_status_output_update, FALSE);
18707
18708 static MYSQL_SYSVAR_BOOL(print_all_deadlocks, srv_print_all_deadlocks,
18709 PLUGIN_VAR_OPCMDARG,
18710 "Print all deadlocks to MySQL error log (off by default)",
18711 NULL, NULL, FALSE);
18712
18713 static MYSQL_SYSVAR_BOOL(
18714 print_lock_wait_timeout_info,
18715 srv_print_lock_wait_timeout_info,
18716 PLUGIN_VAR_OPCMDARG,
18717 "Print lock wait timeout info to MySQL error log (off by default)",
18718 NULL, NULL, FALSE);
18719
18720 static MYSQL_SYSVAR_ULONG(compression_failure_threshold_pct,
18721 zip_failure_threshold_pct, PLUGIN_VAR_OPCMDARG,
18722 "If the compression failure rate of a table is greater than this number"
18723 " more padding is added to the pages to reduce the failures. A value of"
18724 " zero implies no padding",
18725 NULL, NULL, 5, 0, 100, 0);
18726
18727 static MYSQL_SYSVAR_ULONG(compression_pad_pct_max,
18728 zip_pad_max, PLUGIN_VAR_OPCMDARG,
18729 "Percentage of empty space on a data page that can be reserved"
18730 " to make the page compressible.",
18731 NULL, NULL, 50, 0, 75, 0);
18732
18733 static MYSQL_SYSVAR_BOOL(read_only, srv_read_only_mode,
18734 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
18735 "Start InnoDB in read only mode (off by default)",
18736 NULL, NULL, FALSE);
18737
18738 static MYSQL_SYSVAR_BOOL(cmp_per_index_enabled, srv_cmp_per_index_enabled,
18739 PLUGIN_VAR_OPCMDARG,
18740 "Enable INFORMATION_SCHEMA.innodb_cmp_per_index, "
18741 "may have negative impact on performance (off by default)",
18742 NULL, innodb_cmp_per_index_update, FALSE);
18743
18744 #ifdef UNIV_DEBUG
18745 static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug,
18746 PLUGIN_VAR_RQCMDARG,
18747 "Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()",
18748 NULL, NULL, 0, 0, 1024, 0);
18749
18750 static MYSQL_SYSVAR_UINT(limit_optimistic_insert_debug,
18751 btr_cur_limit_optimistic_insert_debug, PLUGIN_VAR_RQCMDARG,
18752 "Artificially limit the number of records per B-tree page (0=unlimited).",
18753 NULL, NULL, 0, 0, UINT_MAX32, 0);
18754
18755 static MYSQL_SYSVAR_BOOL(trx_purge_view_update_only_debug,
18756 srv_purge_view_update_only_debug, PLUGIN_VAR_NOCMDARG,
18757 "Pause actual purging any delete-marked records, but merely update the purge view. "
18758 "It is to create artificially the situation the purge view have been updated "
18759 "but the each purges were not done yet.",
18760 NULL, NULL, FALSE);
18761
18762 static MYSQL_SYSVAR_ULONG(fil_make_page_dirty_debug,
18763 srv_fil_make_page_dirty_debug, PLUGIN_VAR_OPCMDARG,
18764 "Make the first page of the given tablespace dirty.",
18765 NULL, innodb_make_page_dirty, 0, 0, UINT_MAX32, 0);
18766
18767 static MYSQL_SYSVAR_ULONG(saved_page_number_debug,
18768 srv_saved_page_number_debug, PLUGIN_VAR_OPCMDARG,
18769 "An InnoDB page number.",
18770 NULL, innodb_save_page_no, 0, 0, UINT_MAX32, 0);
18771 #endif /* UNIV_DEBUG */
18772
18773 static const char *corrupt_table_action_names[]=
18774 {
18775 "assert", /* 0 */
18776 "warn", /* 1 */
18777 "salvage", /* 2 */
18778 NullS
18779 };
18780 static TYPELIB corrupt_table_action_typelib=
18781 {
18782 array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib",
18783 corrupt_table_action_names, NULL
18784 };
18785 static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
18786 PLUGIN_VAR_RQCMDARG,
18787 "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, "
18788 "when used with file_per_table. "
18789 "All file io for the datafile after detected as corrupt are disabled, "
18790 "except for the deletion.",
18791 NULL, NULL, 0, &corrupt_table_action_typelib);
18792
18793 static MYSQL_SYSVAR_BOOL(locking_fake_changes, srv_fake_changes_locks,
18794 PLUGIN_VAR_NOCMDARG,
18795 "###EXPERIMENTAL### if enabled, transactions will get S row locks instead "
18796 "of X locks for fake changes. If disabled, fake change transactions will "
18797 "not take any locks at all.",
18798 NULL, NULL, TRUE);
18799
18800 static MYSQL_SYSVAR_UINT(compressed_columns_zip_level,
18801 srv_compressed_columns_zip_level,
18802 PLUGIN_VAR_RQCMDARG,
18803 "Compression level used for compressed columns. 0 is no compression"
18804 ", 1 is fastest and 9 is best compression. Default is 6.",
18805 NULL, NULL, DEFAULT_COMPRESSION_LEVEL, 0, 9, 0);
18806
18807 static MYSQL_SYSVAR_ULONG(compressed_columns_threshold,
18808 srv_compressed_columns_threshold,
18809 PLUGIN_VAR_RQCMDARG,
18810 "Compress column data if its length exceeds this value. Default is 96",
18811 NULL, NULL, 96, 1, ~0UL, 0);
18812
18813 static struct st_mysql_sys_var* innobase_system_variables[]= {
18814 MYSQL_SYSVAR(log_block_size),
18815 MYSQL_SYSVAR(additional_mem_pool_size),
18816 MYSQL_SYSVAR(api_trx_level),
18817 MYSQL_SYSVAR(api_bk_commit_interval),
18818 MYSQL_SYSVAR(autoextend_increment),
18819 MYSQL_SYSVAR(buffer_pool_size),
18820 MYSQL_SYSVAR(buffer_pool_populate),
18821 MYSQL_SYSVAR(buffer_pool_instances),
18822 MYSQL_SYSVAR(buffer_pool_filename),
18823 MYSQL_SYSVAR(buffer_pool_dump_now),
18824 MYSQL_SYSVAR(buffer_pool_dump_at_shutdown),
18825 #ifdef UNIV_DEBUG
18826 MYSQL_SYSVAR(buffer_pool_evict),
18827 #endif /* UNIV_DEBUG */
18828 MYSQL_SYSVAR(buffer_pool_load_now),
18829 MYSQL_SYSVAR(buffer_pool_load_abort),
18830 MYSQL_SYSVAR(buffer_pool_load_at_startup),
18831 MYSQL_SYSVAR(lru_scan_depth),
18832 MYSQL_SYSVAR(flush_neighbors),
18833 MYSQL_SYSVAR(checksum_algorithm),
18834 MYSQL_SYSVAR(log_checksum_algorithm),
18835 MYSQL_SYSVAR(checksums),
18836 MYSQL_SYSVAR(commit_concurrency),
18837 MYSQL_SYSVAR(concurrency_tickets),
18838 MYSQL_SYSVAR(compression_level),
18839 MYSQL_SYSVAR(kill_idle_transaction),
18840 MYSQL_SYSVAR(data_file_path),
18841 MYSQL_SYSVAR(data_home_dir),
18842 MYSQL_SYSVAR(doublewrite),
18843 MYSQL_SYSVAR(stats_include_delete_marked),
18844 MYSQL_SYSVAR(api_enable_binlog),
18845 MYSQL_SYSVAR(api_enable_mdl),
18846 MYSQL_SYSVAR(api_disable_rowlock),
18847 MYSQL_SYSVAR(use_atomic_writes),
18848 MYSQL_SYSVAR(fast_shutdown),
18849 MYSQL_SYSVAR(file_io_threads),
18850 MYSQL_SYSVAR(read_io_threads),
18851 MYSQL_SYSVAR(write_io_threads),
18852 MYSQL_SYSVAR(file_per_table),
18853 MYSQL_SYSVAR(file_format),
18854 MYSQL_SYSVAR(file_format_check),
18855 MYSQL_SYSVAR(file_format_max),
18856 MYSQL_SYSVAR(flush_log_at_timeout),
18857 MYSQL_SYSVAR(flush_log_at_trx_commit),
18858 MYSQL_SYSVAR(use_global_flush_log_at_trx_commit),
18859 MYSQL_SYSVAR(flush_method),
18860 MYSQL_SYSVAR(force_recovery),
18861 #ifndef DBUG_OFF
18862 MYSQL_SYSVAR(force_recovery_crash),
18863 #endif /* !DBUG_OFF */
18864 MYSQL_SYSVAR(ft_cache_size),
18865 MYSQL_SYSVAR(ft_total_cache_size),
18866 MYSQL_SYSVAR(ft_result_cache_limit),
18867 MYSQL_SYSVAR(ft_enable_stopword),
18868 MYSQL_SYSVAR(ft_max_token_size),
18869 MYSQL_SYSVAR(ft_min_token_size),
18870 MYSQL_SYSVAR(ft_num_word_optimize),
18871 MYSQL_SYSVAR(ft_sort_pll_degree),
18872 MYSQL_SYSVAR(large_prefix),
18873 MYSQL_SYSVAR(force_load_corrupted),
18874 MYSQL_SYSVAR(locks_unsafe_for_binlog),
18875 MYSQL_SYSVAR(lock_wait_timeout),
18876 #ifdef UNIV_LOG_ARCHIVE
18877 MYSQL_SYSVAR(log_arch_dir),
18878 MYSQL_SYSVAR(log_archive),
18879 MYSQL_SYSVAR(log_arch_expire_sec),
18880 #endif /* UNIV_LOG_ARCHIVE */
18881 MYSQL_SYSVAR(page_size),
18882 MYSQL_SYSVAR(log_buffer_size),
18883 MYSQL_SYSVAR(log_file_size),
18884 MYSQL_SYSVAR(log_files_in_group),
18885 MYSQL_SYSVAR(log_group_home_dir),
18886 MYSQL_SYSVAR(log_compressed_pages),
18887 MYSQL_SYSVAR(max_dirty_pages_pct),
18888 MYSQL_SYSVAR(max_dirty_pages_pct_lwm),
18889 MYSQL_SYSVAR(adaptive_flushing_lwm),
18890 MYSQL_SYSVAR(adaptive_flushing),
18891 MYSQL_SYSVAR(flushing_avg_loops),
18892 MYSQL_SYSVAR(max_purge_lag),
18893 MYSQL_SYSVAR(max_purge_lag_delay),
18894 MYSQL_SYSVAR(mirrored_log_groups),
18895 MYSQL_SYSVAR(old_blocks_pct),
18896 MYSQL_SYSVAR(old_blocks_time),
18897 MYSQL_SYSVAR(open_files),
18898 MYSQL_SYSVAR(optimize_fulltext_only),
18899 MYSQL_SYSVAR(rollback_on_timeout),
18900 MYSQL_SYSVAR(ft_aux_table),
18901 MYSQL_SYSVAR(ft_enable_diag_print),
18902 MYSQL_SYSVAR(ft_server_stopword_table),
18903 MYSQL_SYSVAR(ft_user_stopword_table),
18904 MYSQL_SYSVAR(disable_sort_file_cache),
18905 MYSQL_SYSVAR(stats_on_metadata),
18906 MYSQL_SYSVAR(stats_sample_pages),
18907 MYSQL_SYSVAR(stats_transient_sample_pages),
18908 MYSQL_SYSVAR(stats_persistent),
18909 MYSQL_SYSVAR(stats_persistent_sample_pages),
18910 MYSQL_SYSVAR(stats_auto_recalc),
18911 MYSQL_SYSVAR(adaptive_hash_index),
18912 MYSQL_SYSVAR(adaptive_hash_index_partitions),
18913 MYSQL_SYSVAR(stats_method),
18914 MYSQL_SYSVAR(replication_delay),
18915 MYSQL_SYSVAR(status_file),
18916 MYSQL_SYSVAR(strict_mode),
18917 MYSQL_SYSVAR(support_xa),
18918 MYSQL_SYSVAR(sort_buffer_size),
18919 MYSQL_SYSVAR(online_alter_log_max_size),
18920 MYSQL_SYSVAR(sync_spin_loops),
18921 MYSQL_SYSVAR(spin_wait_delay),
18922 MYSQL_SYSVAR(table_locks),
18923 MYSQL_SYSVAR(thread_concurrency),
18924 #ifdef HAVE_ATOMIC_BUILTINS
18925 MYSQL_SYSVAR(adaptive_max_sleep_delay),
18926 #endif /* HAVE_ATOMIC_BUILTINS */
18927 MYSQL_SYSVAR(thread_sleep_delay),
18928 MYSQL_SYSVAR(autoinc_lock_mode),
18929 MYSQL_SYSVAR(show_verbose_locks),
18930 MYSQL_SYSVAR(show_locks_held),
18931 MYSQL_SYSVAR(version),
18932 MYSQL_SYSVAR(use_sys_malloc),
18933 MYSQL_SYSVAR(use_native_aio),
18934 #ifdef HAVE_LIBNUMA
18935 MYSQL_SYSVAR(numa_interleave),
18936 #endif // HAVE_LIBNUMA
18937 MYSQL_SYSVAR(change_buffering),
18938 MYSQL_SYSVAR(change_buffer_max_size),
18939 MYSQL_SYSVAR(track_changed_pages),
18940 MYSQL_SYSVAR(max_bitmap_file_size),
18941 MYSQL_SYSVAR(max_changed_pages),
18942 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
18943 MYSQL_SYSVAR(change_buffering_debug),
18944 MYSQL_SYSVAR(disable_background_merge),
18945 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
18946 MYSQL_SYSVAR(random_read_ahead),
18947 MYSQL_SYSVAR(read_ahead_threshold),
18948 MYSQL_SYSVAR(read_only),
18949 MYSQL_SYSVAR(io_capacity),
18950 MYSQL_SYSVAR(io_capacity_max),
18951 MYSQL_SYSVAR(monitor_enable),
18952 MYSQL_SYSVAR(monitor_disable),
18953 MYSQL_SYSVAR(monitor_reset),
18954 MYSQL_SYSVAR(monitor_reset_all),
18955 MYSQL_SYSVAR(purge_threads),
18956 MYSQL_SYSVAR(purge_batch_size),
18957 #ifdef UNIV_DEBUG
18958 MYSQL_SYSVAR(purge_run_now),
18959 MYSQL_SYSVAR(purge_stop_now),
18960 MYSQL_SYSVAR(log_checkpoint_now),
18961 MYSQL_SYSVAR(buf_flush_list_now),
18962 MYSQL_SYSVAR(track_redo_log_now),
18963 #endif /* UNIV_DEBUG */
18964 #ifdef UNIV_LINUX
18965 MYSQL_SYSVAR(sched_priority_cleaner),
18966 #endif
18967 #if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
18968 MYSQL_SYSVAR(page_hash_locks),
18969 MYSQL_SYSVAR(doublewrite_batch_size),
18970 #ifdef UNIV_LINUX
18971 MYSQL_SYSVAR(sched_priority_purge),
18972 MYSQL_SYSVAR(sched_priority_io),
18973 MYSQL_SYSVAR(sched_priority_master),
18974 MYSQL_SYSVAR(priority_purge),
18975 MYSQL_SYSVAR(priority_io),
18976 MYSQL_SYSVAR(priority_cleaner),
18977 MYSQL_SYSVAR(priority_master),
18978 #endif /* UNIV_LINUX */
18979 MYSQL_SYSVAR(cleaner_max_lru_time),
18980 MYSQL_SYSVAR(cleaner_max_flush_time),
18981 MYSQL_SYSVAR(cleaner_flush_chunk_size),
18982 MYSQL_SYSVAR(cleaner_lru_chunk_size),
18983 MYSQL_SYSVAR(cleaner_free_list_lwm),
18984 MYSQL_SYSVAR(cleaner_eviction_factor),
18985 #endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
18986 MYSQL_SYSVAR(status_output),
18987 MYSQL_SYSVAR(status_output_locks),
18988 MYSQL_SYSVAR(cleaner_lsn_age_factor),
18989 MYSQL_SYSVAR(foreground_preflush),
18990 MYSQL_SYSVAR(empty_free_list_algorithm),
18991 MYSQL_SYSVAR(print_all_deadlocks),
18992 MYSQL_SYSVAR(print_lock_wait_timeout_info),
18993 MYSQL_SYSVAR(cmp_per_index_enabled),
18994 MYSQL_SYSVAR(undo_logs),
18995 MYSQL_SYSVAR(rollback_segments),
18996 MYSQL_SYSVAR(undo_directory),
18997 MYSQL_SYSVAR(undo_tablespaces),
18998 MYSQL_SYSVAR(sync_array_size),
18999 MYSQL_SYSVAR(compression_failure_threshold_pct),
19000 MYSQL_SYSVAR(compression_pad_pct_max),
19001 #ifdef UNIV_DEBUG
19002 MYSQL_SYSVAR(trx_rseg_n_slots_debug),
19003 MYSQL_SYSVAR(limit_optimistic_insert_debug),
19004 MYSQL_SYSVAR(trx_purge_view_update_only_debug),
19005 MYSQL_SYSVAR(fil_make_page_dirty_debug),
19006 MYSQL_SYSVAR(saved_page_number_debug),
19007 #endif /* UNIV_DEBUG */
19008 MYSQL_SYSVAR(corrupt_table_action),
19009 MYSQL_SYSVAR(fake_changes),
19010 MYSQL_SYSVAR(locking_fake_changes),
19011 MYSQL_SYSVAR(tmpdir),
19012 MYSQL_SYSVAR(compressed_columns_zip_level),
19013 MYSQL_SYSVAR(compressed_columns_threshold),
19014 NULL
19015 };
19016
mysql_declare_plugin(innobase)19017 mysql_declare_plugin(innobase)
19018 {
19019 MYSQL_STORAGE_ENGINE_PLUGIN,
19020 &innobase_storage_engine,
19021 innobase_hton_name,
19022 plugin_author,
19023 "Percona-XtraDB, Supports transactions, row-level locking, and foreign keys",
19024 PLUGIN_LICENSE_GPL,
19025 innobase_init, /* Plugin Init */
19026 NULL, /* Plugin Deinit */
19027 INNODB_VERSION_SHORT,
19028 innodb_status_variables_export,/* status variables */
19029 innobase_system_variables, /* system variables */
19030 NULL, /* reserved */
19031 0, /* flags */
19032 },
19033 i_s_xtradb_read_view,
19034 i_s_xtradb_internal_hash_tables,
19035 i_s_xtradb_rseg,
19036 i_s_xtradb_zip_dict,
19037 i_s_xtradb_zip_dict_cols,
19038 i_s_innodb_trx,
19039 i_s_innodb_locks,
19040 i_s_innodb_lock_waits,
19041 i_s_innodb_cmp,
19042 i_s_innodb_cmp_reset,
19043 i_s_innodb_cmpmem,
19044 i_s_innodb_cmpmem_reset,
19045 i_s_innodb_cmp_per_index,
19046 i_s_innodb_cmp_per_index_reset,
19047 i_s_innodb_buffer_page,
19048 i_s_innodb_buffer_page_lru,
19049 i_s_innodb_buffer_stats,
19050 i_s_innodb_metrics,
19051 i_s_innodb_ft_default_stopword,
19052 i_s_innodb_ft_deleted,
19053 i_s_innodb_ft_being_deleted,
19054 i_s_innodb_ft_config,
19055 i_s_innodb_ft_index_cache,
19056 i_s_innodb_ft_index_table,
19057 i_s_innodb_sys_tables,
19058 i_s_innodb_sys_tablestats,
19059 i_s_innodb_sys_indexes,
19060 i_s_innodb_sys_columns,
19061 i_s_innodb_sys_fields,
19062 i_s_innodb_sys_foreign,
19063 i_s_innodb_sys_foreign_cols,
19064 i_s_innodb_sys_tablespaces,
19065 i_s_innodb_sys_datafiles,
19066 i_s_innodb_changed_pages
19067 mysql_declare_plugin_end;
19068
19069 /** @brief Initialize the default value of innodb_commit_concurrency.
19070
19071 Once InnoDB is running, the innodb_commit_concurrency must not change
19072 from zero to nonzero. (Bug #42101)
19073
19074 The initial default value is 0, and without this extra initialization,
19075 SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
19076 to 0, even if it was initially set to nonzero at the command line
19077 or configuration file. */
19078 static
19079 void
innobase_commit_concurrency_init_default()19080 innobase_commit_concurrency_init_default()
19081 /*======================================*/
19082 {
19083 MYSQL_SYSVAR_NAME(commit_concurrency).def_val
19084 = innobase_commit_concurrency;
19085 }
19086
19087 /** @brief Initialize the default and max value of innodb_undo_logs.
19088
19089 Once InnoDB is running, the default value and the max value of
19090 innodb_undo_logs must be equal to the available undo logs,
19091 given by srv_available_undo_logs. */
19092 static
19093 void
innobase_undo_logs_init_default_max()19094 innobase_undo_logs_init_default_max()
19095 /*=================================*/
19096 {
19097 MYSQL_SYSVAR_NAME(undo_logs).max_val
19098 = MYSQL_SYSVAR_NAME(undo_logs).def_val
19099 = static_cast<unsigned long>(srv_available_undo_logs);
19100 }
19101
19102 #ifdef UNIV_COMPILE_TEST_FUNCS
19103
19104 struct innobase_convert_name_test_t {
19105 char* buf;
19106 ulint buflen;
19107 const char* id;
19108 ulint idlen;
19109 void* thd;
19110 ibool file_id;
19111
19112 const char* expected;
19113 };
19114
19115 void
test_innobase_convert_name()19116 test_innobase_convert_name()
19117 {
19118 char buf[1024];
19119 ulint i;
19120
19121 innobase_convert_name_test_t test_input[] = {
19122 {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
19123 {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
19124 {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
19125 {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
19126 {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
19127
19128 {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
19129 {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
19130 {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
19131 {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
19132 {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
19133 {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
19134 {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
19135
19136 {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
19137 "\"#mysql50#ab\"\"cd\""},
19138 {buf, 17, "ab\"cd", 5, NULL, TRUE,
19139 "\"#mysql50#ab\"\"cd\""},
19140 {buf, 16, "ab\"cd", 5, NULL, TRUE,
19141 "\"#mysql50#ab\"\"c\""},
19142 {buf, 15, "ab\"cd", 5, NULL, TRUE,
19143 "\"#mysql50#ab\"\"\""},
19144 {buf, 14, "ab\"cd", 5, NULL, TRUE,
19145 "\"#mysql50#ab\""},
19146 {buf, 13, "ab\"cd", 5, NULL, TRUE,
19147 "\"#mysql50#ab\""},
19148 {buf, 12, "ab\"cd", 5, NULL, TRUE,
19149 "\"#mysql50#a\""},
19150 {buf, 11, "ab\"cd", 5, NULL, TRUE,
19151 "\"#mysql50#\""},
19152 {buf, 10, "ab\"cd", 5, NULL, TRUE,
19153 "\"#mysql50\""},
19154
19155 {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
19156 {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
19157 {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
19158 {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
19159 {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
19160 {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
19161 {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
19162 {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
19163 {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
19164 /* XXX probably "" is a better result in this case
19165 {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
19166 */
19167 {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
19168 };
19169
19170 for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
19171
19172 char* end;
19173 ibool ok = TRUE;
19174 size_t res_len;
19175
19176 fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
19177 test_input[i].buflen,
19178 test_input[i].id,
19179 test_input[i].idlen,
19180 test_input[i].expected);
19181
19182 end = innobase_convert_name(
19183 test_input[i].buf,
19184 test_input[i].buflen,
19185 test_input[i].id,
19186 test_input[i].idlen,
19187 test_input[i].thd,
19188 test_input[i].file_id);
19189
19190 res_len = (size_t) (end - test_input[i].buf);
19191
19192 if (res_len != strlen(test_input[i].expected)) {
19193
19194 fprintf(stderr, "unexpected len of the result: %u, "
19195 "expected: %u\n", (unsigned) res_len,
19196 (unsigned) strlen(test_input[i].expected));
19197 ok = FALSE;
19198 }
19199
19200 if (memcmp(test_input[i].buf,
19201 test_input[i].expected,
19202 strlen(test_input[i].expected)) != 0
19203 || !ok) {
19204
19205 fprintf(stderr, "unexpected result: %.*s, "
19206 "expected: %s\n", (int) res_len,
19207 test_input[i].buf,
19208 test_input[i].expected);
19209 ok = FALSE;
19210 }
19211
19212 if (ok) {
19213 fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
19214 buf);
19215 } else {
19216 fprintf(stderr, "FAILED\n\n");
19217 return;
19218 }
19219 }
19220 }
19221
19222 #endif /* UNIV_COMPILE_TEST_FUNCS */
19223
19224 /****************************************************************************
19225 * DS-MRR implementation
19226 ***************************************************************************/
19227
19228 /**
19229 * Multi Range Read interface, DS-MRR calls
19230 */
19231
19232 int
multi_range_read_init(RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint mode,HANDLER_BUFFER * buf)19233 ha_innobase::multi_range_read_init(
19234 RANGE_SEQ_IF* seq,
19235 void* seq_init_param,
19236 uint n_ranges,
19237 uint mode,
19238 HANDLER_BUFFER* buf)
19239 {
19240 return(ds_mrr.dsmrr_init(this, seq, seq_init_param,
19241 n_ranges, mode, buf));
19242 }
19243
19244 int
multi_range_read_next(char ** range_info)19245 ha_innobase::multi_range_read_next(
19246 char** range_info)
19247 {
19248 return(ds_mrr.dsmrr_next(range_info));
19249 }
19250
19251 ha_rows
multi_range_read_info_const(uint keyno,RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint * bufsz,uint * flags,Cost_estimate * cost)19252 ha_innobase::multi_range_read_info_const(
19253 uint keyno,
19254 RANGE_SEQ_IF* seq,
19255 void* seq_init_param,
19256 uint n_ranges,
19257 uint* bufsz,
19258 uint* flags,
19259 Cost_estimate* cost)
19260 {
19261 /* See comments in ha_myisam::multi_range_read_info_const */
19262 ds_mrr.init(this, table);
19263 return(ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param,
19264 n_ranges, bufsz, flags, cost));
19265 }
19266
19267 ha_rows
multi_range_read_info(uint keyno,uint n_ranges,uint keys,uint * bufsz,uint * flags,Cost_estimate * cost)19268 ha_innobase::multi_range_read_info(
19269 uint keyno,
19270 uint n_ranges,
19271 uint keys,
19272 uint* bufsz,
19273 uint* flags,
19274 Cost_estimate* cost)
19275 {
19276 ds_mrr.init(this, table);
19277 return(ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost));
19278 }
19279
19280
19281 /**
19282 * Index Condition Pushdown interface implementation
19283 */
19284
19285 /*************************************************************//**
19286 InnoDB index push-down condition check
19287 @return ICP_NO_MATCH, ICP_MATCH, or ICP_OUT_OF_RANGE */
19288 UNIV_INTERN
19289 enum icp_result
innobase_index_cond(void * file)19290 innobase_index_cond(
19291 /*================*/
19292 void* file) /*!< in/out: pointer to ha_innobase */
19293 {
19294 DBUG_ENTER("innobase_index_cond");
19295
19296 ha_innobase* h = reinterpret_cast<class ha_innobase*>(file);
19297
19298 DBUG_ASSERT(h->pushed_idx_cond);
19299 DBUG_ASSERT(h->pushed_idx_cond_keyno != MAX_KEY);
19300
19301 if (h->end_range && h->compare_key_icp(h->end_range) > 0) {
19302
19303 /* caller should return HA_ERR_END_OF_FILE already */
19304 DBUG_RETURN(ICP_OUT_OF_RANGE);
19305 }
19306
19307 DBUG_RETURN(h->pushed_idx_cond->val_int() ? ICP_MATCH : ICP_NO_MATCH);
19308 }
19309
19310 /** Attempt to push down an index condition.
19311 * @param[in] keyno MySQL key number
19312 * @param[in] idx_cond Index condition to be checked
19313 * @return Part of idx_cond which the handler will not evaluate
19314 */
19315 UNIV_INTERN
19316 class Item*
idx_cond_push(uint keyno,class Item * idx_cond)19317 ha_innobase::idx_cond_push(
19318 uint keyno,
19319 class Item* idx_cond)
19320 {
19321 DBUG_ENTER("ha_innobase::idx_cond_push");
19322 DBUG_ASSERT(keyno != MAX_KEY);
19323 DBUG_ASSERT(idx_cond != NULL);
19324
19325 pushed_idx_cond = idx_cond;
19326 pushed_idx_cond_keyno = keyno;
19327 in_range_check_pushed_down = TRUE;
19328 /* We will evaluate the condition entirely */
19329 DBUG_RETURN(NULL);
19330 }
19331
19332 /******************************************************************//**
19333 Use this when the args are passed to the format string from
19334 errmsg-utf8.txt directly as is.
19335
19336 Push a warning message to the client, it is a wrapper around:
19337
19338 void push_warning_printf(
19339 THD *thd, Sql_condition::enum_warning_level level,
19340 uint code, const char *format, ...);
19341 */
19342 UNIV_INTERN
19343 void
ib_senderrf(THD * thd,ib_log_level_t level,ib_uint32_t code,...)19344 ib_senderrf(
19345 /*========*/
19346 THD* thd, /*!< in/out: session */
19347 ib_log_level_t level, /*!< in: warning level */
19348 ib_uint32_t code, /*!< MySQL error code */
19349 ...) /*!< Args */
19350 {
19351 char* str;
19352 va_list args;
19353 const char* format = innobase_get_err_msg(code);
19354
19355 /* If the caller wants to push a message to the client then
19356 the caller must pass a valid session handle. */
19357
19358 ut_a(thd != 0);
19359
19360 /* The error code must exist in the errmsg-utf8.txt file. */
19361 ut_a(format != 0);
19362
19363 va_start(args, code);
19364
19365 #ifdef __WIN__
19366 int size = _vscprintf(format, args) + 1;
19367 str = static_cast<char*>(malloc(size));
19368 str[size - 1] = 0x0;
19369 vsnprintf(str, size, format, args);
19370 #elif HAVE_VASPRINTF
19371 int ret;
19372 ret = vasprintf(&str, format, args);
19373 ut_a(ret != -1);
19374 #else
19375 /* Use a fixed length string. */
19376 str = static_cast<char*>(malloc(BUFSIZ));
19377 my_vsnprintf(str, BUFSIZ, format, args);
19378 #endif /* __WIN__ */
19379
19380 Sql_condition::enum_warning_level l;
19381
19382 l = Sql_condition::WARN_LEVEL_NOTE;
19383
19384 switch(level) {
19385 case IB_LOG_LEVEL_INFO:
19386 break;
19387 case IB_LOG_LEVEL_WARN:
19388 l = Sql_condition::WARN_LEVEL_WARN;
19389 break;
19390 case IB_LOG_LEVEL_ERROR:
19391 /* We can't use push_warning_printf(), it is a hard error. */
19392 my_printf_error(code, "%s", MYF(0), str);
19393 break;
19394 case IB_LOG_LEVEL_FATAL:
19395 l = Sql_condition::WARN_LEVEL_END;
19396 break;
19397 }
19398
19399 if (level != IB_LOG_LEVEL_ERROR) {
19400 push_warning_printf(thd, l, code, "InnoDB: %s", str);
19401 }
19402
19403 va_end(args);
19404 free(str);
19405
19406 if (level == IB_LOG_LEVEL_FATAL) {
19407 ut_error;
19408 }
19409 }
19410
19411 /******************************************************************//**
19412 Use this when the args are first converted to a formatted string and then
19413 passed to the format string from errmsg-utf8.txt. The error message format
19414 must be: "Some string ... %s".
19415
19416 Push a warning message to the client, it is a wrapper around:
19417
19418 void push_warning_printf(
19419 THD *thd, Sql_condition::enum_warning_level level,
19420 uint code, const char *format, ...);
19421 */
19422 UNIV_INTERN
19423 void
ib_errf(THD * thd,ib_log_level_t level,ib_uint32_t code,const char * format,...)19424 ib_errf(
19425 /*====*/
19426 THD* thd, /*!< in/out: session */
19427 ib_log_level_t level, /*!< in: warning level */
19428 ib_uint32_t code, /*!< MySQL error code */
19429 const char* format, /*!< printf format */
19430 ...) /*!< Args */
19431 {
19432 char* str;
19433 va_list args;
19434
19435 /* If the caller wants to push a message to the client then
19436 the caller must pass a valid session handle. */
19437
19438 ut_a(thd != 0);
19439 ut_a(format != 0);
19440
19441 va_start(args, format);
19442
19443 #ifdef __WIN__
19444 int size = _vscprintf(format, args) + 1;
19445 str = static_cast<char*>(malloc(size));
19446 str[size - 1] = 0x0;
19447 vsnprintf(str, size, format, args);
19448 #elif HAVE_VASPRINTF
19449 int ret;
19450 ret = vasprintf(&str, format, args);
19451 ut_a(ret != -1);
19452 #else
19453 /* Use a fixed length string. */
19454 str = static_cast<char*>(malloc(BUFSIZ));
19455 my_vsnprintf(str, BUFSIZ, format, args);
19456 #endif /* __WIN__ */
19457
19458 ib_senderrf(thd, level, code, str);
19459
19460 va_end(args);
19461 free(str);
19462 }
19463
19464 /******************************************************************//**
19465 Write a message to the MySQL log, prefixed with "InnoDB: " */
19466 UNIV_INTERN
19467 void
ib_logf(ib_log_level_t level,const char * format,...)19468 ib_logf(
19469 /*====*/
19470 ib_log_level_t level, /*!< in: warning level */
19471 const char* format, /*!< printf format */
19472 ...) /*!< Args */
19473 {
19474 char* str;
19475 va_list args;
19476
19477 va_start(args, format);
19478
19479 #ifdef __WIN__
19480 int size = _vscprintf(format, args) + 1;
19481 str = static_cast<char*>(malloc(size));
19482 str[size - 1] = 0x0;
19483 vsnprintf(str, size, format, args);
19484 #elif HAVE_VASPRINTF
19485 int ret;
19486 ret = vasprintf(&str, format, args);
19487 ut_a(ret != -1);
19488 #else
19489 /* Use a fixed length string. */
19490 str = static_cast<char*>(malloc(BUFSIZ));
19491 my_vsnprintf(str, BUFSIZ, format, args);
19492 #endif /* __WIN__ */
19493
19494 switch(level) {
19495 case IB_LOG_LEVEL_INFO:
19496 sql_print_information("InnoDB: %s", str);
19497 break;
19498 case IB_LOG_LEVEL_WARN:
19499 sql_print_warning("InnoDB: %s", str);
19500 break;
19501 case IB_LOG_LEVEL_ERROR:
19502 sql_print_error("InnoDB: %s", str);
19503 break;
19504 case IB_LOG_LEVEL_FATAL:
19505 sql_print_error("InnoDB: %s", str);
19506 break;
19507 }
19508
19509 va_end(args);
19510 free(str);
19511
19512 if (level == IB_LOG_LEVEL_FATAL) {
19513 ut_error;
19514 }
19515 }
19516
19517 /**********************************************************************
19518 Converts an identifier from my_charset_filename to UTF-8 charset.
19519 @return result string length, as returned by strconvert() */
19520 uint
innobase_convert_to_filename_charset(char * to,const char * from,ulint len)19521 innobase_convert_to_filename_charset(
19522 /*=================================*/
19523 char* to, /* out: converted identifier */
19524 const char* from, /* in: identifier to convert */
19525 ulint len) /* in: length of 'to', in bytes */
19526 {
19527 uint errors;
19528 CHARSET_INFO* cs_to = &my_charset_filename;
19529 CHARSET_INFO* cs_from = system_charset_info;
19530
19531 return(strconvert(
19532 cs_from, from, cs_to, to, static_cast<uint>(len), &errors));
19533 }
19534
19535 /**********************************************************************
19536 Converts an identifier from my_charset_filename to UTF-8 charset.
19537 @return result string length, as returned by strconvert() */
19538 uint
innobase_convert_to_system_charset(char * to,const char * from,ulint len,uint * errors)19539 innobase_convert_to_system_charset(
19540 /*===============================*/
19541 char* to, /* out: converted identifier */
19542 const char* from, /* in: identifier to convert */
19543 ulint len, /* in: length of 'to', in bytes */
19544 uint* errors) /* out: error return */
19545 {
19546 CHARSET_INFO* cs1 = &my_charset_filename;
19547 CHARSET_INFO* cs2 = system_charset_info;
19548
19549 return(strconvert(
19550 cs1, from, cs2, to, static_cast<uint>(len), errors));
19551 }
19552
19553 /**********************************************************************
19554 Issue a warning that the row is too big. */
19555 void
ib_warn_row_too_big(const dict_table_t * table)19556 ib_warn_row_too_big(const dict_table_t* table)
19557 {
19558 /* If prefix is true then a 768-byte prefix is stored
19559 locally for BLOB fields. Refer to dict_table_get_format() */
19560 const bool prefix = (dict_tf_get_format(table->flags)
19561 == UNIV_FORMAT_A);
19562
19563 const ulint free_space = page_get_free_space_of_empty(
19564 table->flags & DICT_TF_COMPACT) / 2;
19565
19566 THD* thd = current_thd;
19567
19568 push_warning_printf(
19569 thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_TO_BIG_ROW,
19570 "Row size too large (> %lu). Changing some columns to TEXT"
19571 " or BLOB %smay help. In current row format, BLOB prefix of"
19572 " %d bytes is stored inline.", free_space
19573 , prefix ? "or using ROW_FORMAT=DYNAMIC or"
19574 " ROW_FORMAT=COMPRESSED ": ""
19575 , prefix ? DICT_MAX_FIXED_COL_LEN : 0);
19576 }
19577
19578 /*****************************************************************//**
19579 Checks if the file name is reserved in InnoDB. Currently
19580 redo log files(ib_logfile*) is reserved.
19581 @return true if the name is reserved */
19582 static
19583 bool
innobase_check_reserved_file_name(handlerton * hton,const char * name)19584 innobase_check_reserved_file_name(
19585 /*===================*/
19586 handlerton* hton, /*!< in: handlerton of Innodb */
19587 const char* name) /*!< in: Name of the database */
19588 {
19589 CHARSET_INFO *ci= system_charset_info;
19590 size_t logname_size = strlen(ib_logfile_basename);
19591
19592 /* Name is smaller than reserved name */
19593 if (strlen(name) < logname_size) {
19594 return (false);
19595 }
19596 /* Do case insensitive comparison for name. */
19597 for (uint i=0; i < logname_size; i++) {
19598 if (my_tolower(ci, name[i]) != ib_logfile_basename[i]){
19599 return (false);
19600 }
19601 }
19602 return (true);
19603 }
19604