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