1 /*****************************************************************************
2 
3 Copyright (c) 2007, 2021, Oracle and/or its affiliates.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8 
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation.  The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License, version 2.0, for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24 
25 *****************************************************************************/
26 
27 /**************************************************//**
28 @file handler/i_s.cc
29 InnoDB INFORMATION SCHEMA tables interface to MySQL.
30 
31 Created July 18, 2007 Vasil Dimov
32 *******************************************************/
33 
34 #include <item.h>
35 #include <item_func.h>
36 #include <item_sum.h>
37 #include <item_cmpfunc.h>
38 
39 #include "ha_prototypes.h"
40 #include <field.h>
41 #include <sql_acl.h>
42 #include <sql_show.h>
43 #include <sql_time.h>
44 #include <debug_sync.h>
45 
46 #include "i_s.h"
47 #include "btr0pcur.h"
48 #include "btr0types.h"
49 #include "dict0dict.h"
50 #include "dict0load.h"
51 #include "buf0buddy.h"
52 #include "buf0buf.h"
53 #include "ibuf0ibuf.h"
54 #include "dict0mem.h"
55 #include "dict0types.h"
56 #include "srv0start.h"
57 #include "srv0srv.h"
58 #include "trx0i_s.h"
59 #include "trx0trx.h"
60 #include "srv0mon.h"
61 #include "fut0fut.h"
62 #include "pars0pars.h"
63 #include "fts0types.h"
64 #include "fts0opt.h"
65 #include "fts0priv.h"
66 #include "log0online.h"
67 #include "btr0btr.h"
68 #include "page0zip.h"
69 #include "fil0crypt.h"
70 #include "fsp0sysspace.h"
71 #include "ut0new.h"
72 #include "dict0crea.h"
73 
74 /** structure associates a name string with a file page type and/or buffer
75 page state. */
76 struct buf_page_desc_t{
77 	const char*	type_str;	/*!< String explain the page
78 					type/state */
79 	ulint		type_value;	/*!< Page type or page state */
80 };
81 
82 /** We also define I_S_PAGE_TYPE_INDEX as the Index Page's position
83 in i_s_page_type[] array */
84 #define I_S_PAGE_TYPE_INDEX		1
85 
86 /** Any unassigned FIL_PAGE_TYPE will be treated as unknown. */
87 #define	I_S_PAGE_TYPE_UNKNOWN		FIL_PAGE_TYPE_UNKNOWN
88 
89 /** R-tree index page */
90 #define	I_S_PAGE_TYPE_RTREE		(FIL_PAGE_TYPE_LAST + 1)
91 
92 /** Change buffer B-tree page */
93 #define	I_S_PAGE_TYPE_IBUF		(FIL_PAGE_TYPE_LAST + 2)
94 
95 #define I_S_PAGE_TYPE_LAST		I_S_PAGE_TYPE_IBUF
96 
97 #define I_S_PAGE_TYPE_BITS		4
98 
99 /* Check if we can hold all page types */
100 #if I_S_PAGE_TYPE_LAST >= 1 << I_S_PAGE_TYPE_BITS
101 # error i_s_page_type[] is too large
102 #endif
103 
104 /** Name string for File Page Types */
105 static buf_page_desc_t	i_s_page_type[] = {
106 	{"ALLOCATED", FIL_PAGE_TYPE_ALLOCATED},
107 	{"INDEX", FIL_PAGE_INDEX},
108 	{"UNDO_LOG", FIL_PAGE_UNDO_LOG},
109 	{"INODE", FIL_PAGE_INODE},
110 	{"IBUF_FREE_LIST", FIL_PAGE_IBUF_FREE_LIST},
111 	{"IBUF_BITMAP", FIL_PAGE_IBUF_BITMAP},
112 	{"SYSTEM", FIL_PAGE_TYPE_SYS},
113 	{"TRX_SYSTEM", FIL_PAGE_TYPE_TRX_SYS},
114 	{"FILE_SPACE_HEADER", FIL_PAGE_TYPE_FSP_HDR},
115 	{"EXTENT_DESCRIPTOR", FIL_PAGE_TYPE_XDES},
116 	{"BLOB", FIL_PAGE_TYPE_BLOB},
117 	{"COMPRESSED_BLOB", FIL_PAGE_TYPE_ZBLOB},
118 	{"COMPRESSED_BLOB2", FIL_PAGE_TYPE_ZBLOB2},
119 	{"UNKNOWN", I_S_PAGE_TYPE_UNKNOWN},
120 	{"RTREE_INDEX", I_S_PAGE_TYPE_RTREE},
121 	{"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
122 };
123 
124 /** This structure defines information we will fetch from pages
125 currently cached in the buffer pool. It will be used to populate
126 table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE */
127 struct buf_page_info_t{
128 	ulint		block_id;	/*!< Buffer Pool block ID */
129 	unsigned	space_id:32;	/*!< Tablespace ID */
130 	unsigned	page_num:32;	/*!< Page number/offset */
131 	unsigned	access_time:32;	/*!< Time of first access */
132 	unsigned	pool_id:MAX_BUFFER_POOLS_BITS;
133 					/*!< Buffer Pool ID. Must be less than
134 					MAX_BUFFER_POOLS */
135 	unsigned	flush_type:2;	/*!< Flush type */
136 	unsigned	io_fix:2;	/*!< type of pending I/O operation */
137 	unsigned	fix_count:19;	/*!< Count of how manyfold this block
138 					is bufferfixed */
139 	unsigned	hashed:1;	/*!< Whether hash index has been
140 					built on this page */
141 	unsigned	is_old:1;	/*!< TRUE if the block is in the old
142 					blocks in buf_pool->LRU_old */
143 	unsigned	freed_page_clock:31; /*!< the value of
144 					buf_pool->freed_page_clock */
145 	unsigned	zip_ssize:PAGE_ZIP_SSIZE_BITS;
146 					/*!< Compressed page size */
147 	unsigned	page_state:BUF_PAGE_STATE_BITS; /*!< Page state */
148 	unsigned	page_type:I_S_PAGE_TYPE_BITS;	/*!< Page type */
149 	unsigned	num_recs:UNIV_PAGE_SIZE_SHIFT_MAX-2;
150 					/*!< Number of records on Page */
151 	unsigned	data_size:UNIV_PAGE_SIZE_SHIFT_MAX;
152 					/*!< Sum of the sizes of the records */
153 	lsn_t		newest_mod;	/*!< Log sequence number of
154 					the youngest modification */
155 	lsn_t		oldest_mod;	/*!< Log sequence number of
156 					the oldest modification */
157 	index_id_t	index_id;	/*!< Index ID if a index page */
158 };
159 
160 /** Maximum number of buffer page info we would cache. */
161 const ulint	MAX_BUF_INFO_CACHED = 10000;
162 
163 #define OK(expr)		\
164 	if ((expr) != 0) {	\
165 		DBUG_RETURN(1);	\
166 	}
167 
168 #define RETURN_IF_INNODB_NOT_STARTED(plugin_name)			\
169 do {									\
170 	if (!srv_was_started) {						\
171 		push_warning_printf(thd, Sql_condition::SL_WARNING,	\
172 				    ER_CANT_FIND_SYSTEM_REC,		\
173 				    "InnoDB: SELECTing from "		\
174 				    "INFORMATION_SCHEMA.%s but "	\
175 				    "the InnoDB storage engine "	\
176 				    "is not installed", plugin_name);	\
177 		DBUG_RETURN(0);						\
178 	}								\
179 } while (0)
180 
181 #if !defined __STRICT_ANSI__ && defined __GNUC__ && !defined __clang__
182 #define STRUCT_FLD(name, value)	name: value
183 #else
184 #define STRUCT_FLD(name, value)	value
185 #endif
186 
187 /* Don't use a static const variable here, as some C++ compilers (notably
188 HPUX aCC: HP ANSI C++ B3910B A.03.65) can't handle it. */
189 #define END_OF_ST_FIELD_INFO \
190 	{STRUCT_FLD(field_name,		NULL), \
191 	 STRUCT_FLD(field_length,	0), \
192 	 STRUCT_FLD(field_type,		MYSQL_TYPE_NULL), \
193 	 STRUCT_FLD(value,		0), \
194 	 STRUCT_FLD(field_flags,	0), \
195 	 STRUCT_FLD(old_name,		""), \
196 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)}
197 
198 /*
199 Use the following types mapping:
200 
201 C type	ST_FIELD_INFO::field_type
202 ---------------------------------
203 long			MYSQL_TYPE_LONGLONG
204 (field_length=MY_INT64_NUM_DECIMAL_DIGITS)
205 
206 long unsigned		MYSQL_TYPE_LONGLONG
207 (field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
208 
209 char*			MYSQL_TYPE_STRING
210 (field_length=n)
211 
212 float			MYSQL_TYPE_FLOAT
213 (field_length=0 is ignored)
214 
215 void*			MYSQL_TYPE_LONGLONG
216 (field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
217 
218 boolean (if else)	MYSQL_TYPE_LONG
219 (field_length=1)
220 
221 time_t			MYSQL_TYPE_DATETIME
222 (field_length=0 ignored)
223 ---------------------------------
224 */
225 
226 /*******************************************************************//**
227 Common function to fill any of the dynamic tables:
228 INFORMATION_SCHEMA.innodb_trx
229 INFORMATION_SCHEMA.innodb_locks
230 INFORMATION_SCHEMA.innodb_lock_waits
231 @return 0 on success */
232 static
233 int
234 trx_i_s_common_fill_table(
235 /*======================*/
236 	THD*		thd,	/*!< in: thread */
237 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
238 	Item*		);	/*!< in: condition (not used) */
239 
240 /*******************************************************************//**
241 Unbind a dynamic INFORMATION_SCHEMA table.
242 @return 0 on success */
243 static
244 int
245 i_s_common_deinit(
246 /*==============*/
247 	void*	p);	/*!< in/out: table schema object */
248 /*******************************************************************//**
249 Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
250 field.
251 @return 0 on success */
252 static
253 int
field_store_time_t(Field * field,time_t time)254 field_store_time_t(
255 /*===============*/
256 	Field*	field,	/*!< in/out: target field for storage */
257 	time_t	time)	/*!< in: value to store */
258 {
259 	MYSQL_TIME	my_time;
260 	struct tm	tm_time;
261 
262 	if (time) {
263 #if 0
264 		/* use this if you are sure that `variables' and `time_zone'
265 		are always initialized */
266 		thd->variables.time_zone->gmt_sec_to_TIME(
267 			&my_time, (my_time_t) time);
268 #else
269 		localtime_r(&time, &tm_time);
270 		localtime_to_TIME(&my_time, &tm_time);
271 		my_time.time_type = MYSQL_TIMESTAMP_DATETIME;
272 #endif
273 	} else {
274 		memset(&my_time, 0, sizeof(my_time));
275 	}
276 
277 	return(field->store_time(&my_time, MYSQL_TIMESTAMP_DATETIME));
278 }
279 
280 /*******************************************************************//**
281 Auxiliary function to store char* value in MYSQL_TYPE_STRING field.
282 @return 0 on success */
283 static
284 int
field_store_string(Field * field,const char * str)285 field_store_string(
286 /*===============*/
287 	Field*		field,	/*!< in/out: target field for storage */
288 	const char*	str)	/*!< in: NUL-terminated utf-8 string,
289 				or NULL */
290 {
291 	int	ret;
292 
293 	if (str != NULL) {
294 
295 		ret = field->store(str, static_cast<uint>(strlen(str)),
296 				   system_charset_info);
297 		field->set_notnull();
298 	} else {
299 
300 		ret = 0; /* success */
301 		field->set_null();
302 	}
303 
304 	return(ret);
305 }
306 
307 /*******************************************************************//**
308 Store the name of an index in a MYSQL_TYPE_VARCHAR field.
309 Handles the names of incomplete secondary indexes.
310 @return 0 on success */
311 static
312 int
field_store_index_name(Field * field,const char * index_name)313 field_store_index_name(
314 /*===================*/
315 	Field*		field,		/*!< in/out: target field for
316 					storage */
317 	const char*	index_name)	/*!< in: NUL-terminated utf-8
318 					index name, possibly starting with
319 					TEMP_INDEX_PREFIX */
320 {
321 	int	ret;
322 
323 	ut_ad(index_name != NULL);
324 	ut_ad(field->real_type() == MYSQL_TYPE_VARCHAR);
325 
326 	/* Since TEMP_INDEX_PREFIX is not a valid UTF8, we need to convert
327 	it to something else. */
328 	if (*index_name == *TEMP_INDEX_PREFIX_STR) {
329 		char	buf[NAME_LEN + 1];
330 		buf[0] = '?';
331 		memcpy(buf + 1, index_name + 1, strlen(index_name));
332 		ret = field->store(
333 			buf, static_cast<uint>(strlen(buf)),
334 			system_charset_info);
335 	} else {
336 		ret = field->store(
337 			index_name, static_cast<uint>(strlen(index_name)),
338 			system_charset_info);
339 	}
340 
341 	field->set_notnull();
342 
343 	return(ret);
344 }
345 
346 /*******************************************************************//**
347 Auxiliary function to store ulint value in MYSQL_TYPE_LONGLONG field.
348 If the value is ULINT_UNDEFINED then the field is set to NULL.
349 @return 0 on success */
350 static
351 int
field_store_ulint(Field * field,ulint n)352 field_store_ulint(
353 /*==============*/
354 	Field*	field,	/*!< in/out: target field for storage */
355 	ulint	n)	/*!< in: value to store */
356 {
357 	int	ret;
358 
359 	if (n != ULINT_UNDEFINED) {
360 
361 		ret = field->store(n, true);
362 		field->set_notnull();
363 	} else {
364 
365 		ret = 0; /* success */
366 		field->set_null();
367 	}
368 
369 	return(ret);
370 }
371 
372 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
373 static ST_FIELD_INFO	innodb_trx_fields_info[] =
374 {
375 #define IDX_TRX_ID		0
376 	{STRUCT_FLD(field_name,		"trx_id"),
377 	 STRUCT_FLD(field_length,	TRX_ID_MAX_LEN + 1),
378 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
379 	 STRUCT_FLD(value,		0),
380 	 STRUCT_FLD(field_flags,	0),
381 	 STRUCT_FLD(old_name,		""),
382 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
383 
384 #define IDX_TRX_STATE		1
385 	{STRUCT_FLD(field_name,		"trx_state"),
386 	 STRUCT_FLD(field_length,	TRX_QUE_STATE_STR_MAX_LEN + 1),
387 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
388 	 STRUCT_FLD(value,		0),
389 	 STRUCT_FLD(field_flags,	0),
390 	 STRUCT_FLD(old_name,		""),
391 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
392 
393 #define IDX_TRX_STARTED		2
394 	{STRUCT_FLD(field_name,		"trx_started"),
395 	 STRUCT_FLD(field_length,	0),
396 	 STRUCT_FLD(field_type,		MYSQL_TYPE_DATETIME),
397 	 STRUCT_FLD(value,		0),
398 	 STRUCT_FLD(field_flags,	0),
399 	 STRUCT_FLD(old_name,		""),
400 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
401 
402 #define IDX_TRX_REQUESTED_LOCK_ID	3
403 	{STRUCT_FLD(field_name,		"trx_requested_lock_id"),
404 	 STRUCT_FLD(field_length,	TRX_I_S_LOCK_ID_MAX_LEN + 1),
405 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
406 	 STRUCT_FLD(value,		0),
407 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
408 	 STRUCT_FLD(old_name,		""),
409 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
410 
411 #define IDX_TRX_WAIT_STARTED	4
412 	{STRUCT_FLD(field_name,		"trx_wait_started"),
413 	 STRUCT_FLD(field_length,	0),
414 	 STRUCT_FLD(field_type,		MYSQL_TYPE_DATETIME),
415 	 STRUCT_FLD(value,		0),
416 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
417 	 STRUCT_FLD(old_name,		""),
418 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
419 
420 #define IDX_TRX_WEIGHT		5
421 	{STRUCT_FLD(field_name,		"trx_weight"),
422 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
423 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
424 	 STRUCT_FLD(value,		0),
425 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
426 	 STRUCT_FLD(old_name,		""),
427 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
428 
429 #define IDX_TRX_MYSQL_THREAD_ID	6
430 	{STRUCT_FLD(field_name,		"trx_mysql_thread_id"),
431 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
432 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
433 	 STRUCT_FLD(value,		0),
434 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
435 	 STRUCT_FLD(old_name,		""),
436 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
437 
438 #define IDX_TRX_QUERY		7
439 	{STRUCT_FLD(field_name,		"trx_query"),
440 	 STRUCT_FLD(field_length,	TRX_I_S_TRX_QUERY_MAX_LEN),
441 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
442 	 STRUCT_FLD(value,		0),
443 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
444 	 STRUCT_FLD(old_name,		""),
445 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
446 
447 #define IDX_TRX_OPERATION_STATE	8
448 	{STRUCT_FLD(field_name,		"trx_operation_state"),
449 	 STRUCT_FLD(field_length,	TRX_I_S_TRX_OP_STATE_MAX_LEN),
450 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
451 	 STRUCT_FLD(value,		0),
452 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
453 	 STRUCT_FLD(old_name,		""),
454 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
455 
456 #define IDX_TRX_TABLES_IN_USE	9
457 	{STRUCT_FLD(field_name,		"trx_tables_in_use"),
458 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
459 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
460 	 STRUCT_FLD(value,		0),
461 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
462 	 STRUCT_FLD(old_name,		""),
463 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
464 
465 #define IDX_TRX_TABLES_LOCKED	10
466 	{STRUCT_FLD(field_name,		"trx_tables_locked"),
467 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
468 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
469 	 STRUCT_FLD(value,		0),
470 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
471 	 STRUCT_FLD(old_name,		""),
472 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
473 
474 #define IDX_TRX_LOCK_STRUCTS	11
475 	{STRUCT_FLD(field_name,		"trx_lock_structs"),
476 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
477 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
478 	 STRUCT_FLD(value,		0),
479 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
480 	 STRUCT_FLD(old_name,		""),
481 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
482 
483 #define IDX_TRX_LOCK_MEMORY_BYTES	12
484 	{STRUCT_FLD(field_name,		"trx_lock_memory_bytes"),
485 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
486 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
487 	 STRUCT_FLD(value,		0),
488 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
489 	 STRUCT_FLD(old_name,		""),
490 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
491 
492 #define IDX_TRX_ROWS_LOCKED	13
493 	{STRUCT_FLD(field_name,		"trx_rows_locked"),
494 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
495 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
496 	 STRUCT_FLD(value,		0),
497 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
498 	 STRUCT_FLD(old_name,		""),
499 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
500 
501 #define IDX_TRX_ROWS_MODIFIED		14
502 	{STRUCT_FLD(field_name,		"trx_rows_modified"),
503 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
504 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
505 	 STRUCT_FLD(value,		0),
506 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
507 	 STRUCT_FLD(old_name,		""),
508 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
509 
510 #define IDX_TRX_CONNCURRENCY_TICKETS	15
511 	{STRUCT_FLD(field_name,		"trx_concurrency_tickets"),
512 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
513 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
514 	 STRUCT_FLD(value,		0),
515 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
516 	 STRUCT_FLD(old_name,		""),
517 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
518 
519 #define IDX_TRX_ISOLATION_LEVEL	16
520 	{STRUCT_FLD(field_name,		"trx_isolation_level"),
521 	 STRUCT_FLD(field_length,	TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN),
522 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
523 	 STRUCT_FLD(value,		0),
524 	 STRUCT_FLD(field_flags,	0),
525 	 STRUCT_FLD(old_name,		""),
526 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
527 
528 #define IDX_TRX_UNIQUE_CHECKS	17
529 	{STRUCT_FLD(field_name,		"trx_unique_checks"),
530 	 STRUCT_FLD(field_length,	1),
531 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
532 	 STRUCT_FLD(value,		1),
533 	 STRUCT_FLD(field_flags,	0),
534 	 STRUCT_FLD(old_name,		""),
535 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
536 
537 #define IDX_TRX_FOREIGN_KEY_CHECKS	18
538 	{STRUCT_FLD(field_name,		"trx_foreign_key_checks"),
539 	 STRUCT_FLD(field_length,	1),
540 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
541 	 STRUCT_FLD(value,		1),
542 	 STRUCT_FLD(field_flags,	0),
543 	 STRUCT_FLD(old_name,		""),
544 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
545 
546 #define IDX_TRX_LAST_FOREIGN_KEY_ERROR	19
547 	{STRUCT_FLD(field_name,		"trx_last_foreign_key_error"),
548 	 STRUCT_FLD(field_length,	TRX_I_S_TRX_FK_ERROR_MAX_LEN),
549 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
550 	 STRUCT_FLD(value,		0),
551 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
552 	 STRUCT_FLD(old_name,		""),
553 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
554 
555 #define IDX_TRX_ADAPTIVE_HASH_LATCHED	20
556 	{STRUCT_FLD(field_name,		"trx_adaptive_hash_latched"),
557 	 STRUCT_FLD(field_length,	1),
558 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
559 	 STRUCT_FLD(value,		0),
560 	 STRUCT_FLD(field_flags,	0),
561 	 STRUCT_FLD(old_name,		""),
562 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
563 
564 #define IDX_TRX_ADAPTIVE_HASH_TIMEOUT	21
565 	{STRUCT_FLD(field_name,		"trx_adaptive_hash_timeout"),
566 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
567 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
568 	 STRUCT_FLD(value,		0),
569 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
570 	 STRUCT_FLD(old_name,		""),
571 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
572 
573 #define IDX_TRX_READ_ONLY		22
574 	{STRUCT_FLD(field_name,		"trx_is_read_only"),
575 	 STRUCT_FLD(field_length,	1),
576 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
577 	 STRUCT_FLD(value,		0),
578 	 STRUCT_FLD(field_flags,	0),
579 	 STRUCT_FLD(old_name,		""),
580 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
581 
582 #define IDX_TRX_AUTOCOMMIT_NON_LOCKING	23
583 	{STRUCT_FLD(field_name,		"trx_autocommit_non_locking"),
584 	 STRUCT_FLD(field_length,	1),
585 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
586 	 STRUCT_FLD(value,		0),
587 	 STRUCT_FLD(field_flags,	0),
588 	 STRUCT_FLD(old_name,		""),
589 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
590 
591 	END_OF_ST_FIELD_INFO
592 };
593 
594 /*******************************************************************//**
595 Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx
596 table with it.
597 @return 0 on success */
598 static
599 int
fill_innodb_trx_from_cache(trx_i_s_cache_t * cache,THD * thd,TABLE * table)600 fill_innodb_trx_from_cache(
601 /*=======================*/
602 	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
603 	THD*			thd,	/*!< in: used to call
604 					schema_table_store_record() */
605 	TABLE*			table)	/*!< in/out: fill this table */
606 {
607 	Field**	fields;
608 	ulint	rows_num;
609 	char	lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
610 	ulint	i;
611 
612 	DBUG_ENTER("fill_innodb_trx_from_cache");
613 
614 	fields = table->field;
615 
616 	rows_num = trx_i_s_cache_get_rows_used(cache,
617 					       I_S_INNODB_TRX);
618 
619 	for (i = 0; i < rows_num; i++) {
620 
621 		i_s_trx_row_t*	row;
622 		char		trx_id[TRX_ID_MAX_LEN + 1];
623 
624 		row = (i_s_trx_row_t*)
625 			trx_i_s_cache_get_nth_row(
626 				cache, I_S_INNODB_TRX, i);
627 
628 		/* trx_id */
629 		ut_snprintf(trx_id, sizeof(trx_id), TRX_ID_FMT, row->trx_id);
630 		OK(field_store_string(fields[IDX_TRX_ID], trx_id));
631 
632 		/* trx_state */
633 		OK(field_store_string(fields[IDX_TRX_STATE],
634 				      row->trx_state));
635 
636 		/* trx_started */
637 		OK(field_store_time_t(fields[IDX_TRX_STARTED],
638 				      (time_t) row->trx_started));
639 
640 		/* trx_requested_lock_id */
641 		/* trx_wait_started */
642 		if (row->trx_wait_started != 0) {
643 
644 			OK(field_store_string(
645 				   fields[IDX_TRX_REQUESTED_LOCK_ID],
646 				   trx_i_s_create_lock_id(
647 					   row->requested_lock_row,
648 					   lock_id, sizeof(lock_id))));
649 			/* field_store_string() sets it no notnull */
650 
651 			OK(field_store_time_t(
652 				   fields[IDX_TRX_WAIT_STARTED],
653 				   (time_t) row->trx_wait_started));
654 			fields[IDX_TRX_WAIT_STARTED]->set_notnull();
655 		} else {
656 
657 			fields[IDX_TRX_REQUESTED_LOCK_ID]->set_null();
658 			fields[IDX_TRX_WAIT_STARTED]->set_null();
659 		}
660 
661 		/* trx_weight */
662 		OK(fields[IDX_TRX_WEIGHT]->store(row->trx_weight, true));
663 
664 		/* trx_mysql_thread_id */
665 		OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
666 			   row->trx_mysql_thread_id, true));
667 
668 		/* trx_query */
669 		if (row->trx_query) {
670 			/* store will do appropriate character set
671 			conversion check */
672 			fields[IDX_TRX_QUERY]->store(
673 				row->trx_query,
674 				static_cast<uint>(strlen(row->trx_query)),
675 				row->trx_query_cs);
676 			fields[IDX_TRX_QUERY]->set_notnull();
677 		} else {
678 			fields[IDX_TRX_QUERY]->set_null();
679 		}
680 
681 		/* trx_operation_state */
682 		OK(field_store_string(fields[IDX_TRX_OPERATION_STATE],
683 				      row->trx_operation_state));
684 
685 		/* trx_tables_in_use */
686 		OK(fields[IDX_TRX_TABLES_IN_USE]->store(
687 			   row->trx_tables_in_use, true));
688 
689 		/* trx_tables_locked */
690 		OK(fields[IDX_TRX_TABLES_LOCKED]->store(
691 			   row->trx_tables_locked, true));
692 
693 		/* trx_lock_structs */
694 		OK(fields[IDX_TRX_LOCK_STRUCTS]->store(
695 			   row->trx_lock_structs, true));
696 
697 		/* trx_lock_memory_bytes */
698 		OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store(
699 			   row->trx_lock_memory_bytes, true));
700 
701 		/* trx_rows_locked */
702 		OK(fields[IDX_TRX_ROWS_LOCKED]->store(
703 			   row->trx_rows_locked, true));
704 
705 		/* trx_rows_modified */
706 		OK(fields[IDX_TRX_ROWS_MODIFIED]->store(
707 			   row->trx_rows_modified, true));
708 
709 		/* trx_concurrency_tickets */
710 		OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store(
711 			   row->trx_concurrency_tickets, true));
712 
713 		/* trx_isolation_level */
714 		OK(field_store_string(fields[IDX_TRX_ISOLATION_LEVEL],
715 				      row->trx_isolation_level));
716 
717 		/* trx_unique_checks */
718 		OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
719 			   row->trx_unique_checks, true));
720 
721 		/* trx_foreign_key_checks */
722 		OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
723 			   row->trx_foreign_key_checks, true));
724 
725 		/* trx_last_foreign_key_error */
726 		OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
727 				      row->trx_foreign_key_error));
728 
729 		/* trx_adaptive_hash_latched */
730 		OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store(
731 			   row->trx_has_search_latch, true));
732 
733 		/* trx_is_read_only*/
734 		OK(fields[IDX_TRX_READ_ONLY]->store(
735 			   row->trx_is_read_only, true));
736 
737 		/* trx_is_autocommit_non_locking */
738 		OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
739 			   (longlong) row->trx_is_autocommit_non_locking,
740 			   true));
741 
742 		OK(schema_table_store_record(thd, table));
743 	}
744 
745 	DBUG_RETURN(0);
746 }
747 
748 /*******************************************************************//**
749 Bind the dynamic table INFORMATION_SCHEMA.innodb_trx
750 @return 0 on success */
751 static
752 int
innodb_trx_init(void * p)753 innodb_trx_init(
754 /*============*/
755 	void*	p)	/*!< in/out: table schema object */
756 {
757 	ST_SCHEMA_TABLE*	schema;
758 
759 	DBUG_ENTER("innodb_trx_init");
760 
761 	schema = (ST_SCHEMA_TABLE*) p;
762 
763 	schema->fields_info = innodb_trx_fields_info;
764 	schema->fill_table = trx_i_s_common_fill_table;
765 
766 	DBUG_RETURN(0);
767 }
768 
769 static struct st_mysql_information_schema	i_s_info =
770 {
771 	MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
772 };
773 
774 struct st_mysql_plugin	i_s_innodb_trx =
775 {
776 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
777 	/* int */
778 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
779 
780 	/* pointer to type-specific plugin descriptor */
781 	/* void* */
782 	STRUCT_FLD(info, &i_s_info),
783 
784 	/* plugin name */
785 	/* const char* */
786 	STRUCT_FLD(name, "INNODB_TRX"),
787 
788 	/* plugin author (for SHOW PLUGINS) */
789 	/* const char* */
790 	STRUCT_FLD(author, plugin_author),
791 
792 	/* general descriptive text (for SHOW PLUGINS) */
793 	/* const char* */
794 	STRUCT_FLD(descr, "InnoDB transactions"),
795 
796 	/* the plugin license (PLUGIN_LICENSE_XXX) */
797 	/* int */
798 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
799 
800 	/* the function to invoke when plugin is loaded */
801 	/* int (*)(void*); */
802 	STRUCT_FLD(init, innodb_trx_init),
803 
804 	/* the function to invoke when plugin is unloaded */
805 	/* int (*)(void*); */
806 	STRUCT_FLD(deinit, i_s_common_deinit),
807 
808 	/* plugin version (for SHOW PLUGINS) */
809 	/* unsigned int */
810 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
811 
812 	/* struct st_mysql_show_var* */
813 	STRUCT_FLD(status_vars, NULL),
814 
815 	/* struct st_mysql_sys_var** */
816 	STRUCT_FLD(system_vars, NULL),
817 
818 	/* reserved for dependency checking */
819 	/* void* */
820 	STRUCT_FLD(__reserved1, NULL),
821 
822 	/* Plugin flags */
823 	/* unsigned long */
824 	STRUCT_FLD(flags, 0UL),
825 };
826 
827 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_locks */
828 static ST_FIELD_INFO	innodb_locks_fields_info[] =
829 {
830 #define IDX_LOCK_ID		0
831 	{STRUCT_FLD(field_name,		"lock_id"),
832 	 STRUCT_FLD(field_length,	TRX_I_S_LOCK_ID_MAX_LEN + 1),
833 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
834 	 STRUCT_FLD(value,		0),
835 	 STRUCT_FLD(field_flags,	0),
836 	 STRUCT_FLD(old_name,		""),
837 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
838 
839 #define IDX_LOCK_TRX_ID		1
840 	{STRUCT_FLD(field_name,		"lock_trx_id"),
841 	 STRUCT_FLD(field_length,	TRX_ID_MAX_LEN + 1),
842 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
843 	 STRUCT_FLD(value,		0),
844 	 STRUCT_FLD(field_flags,	0),
845 	 STRUCT_FLD(old_name,		""),
846 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
847 
848 #define IDX_LOCK_MODE		2
849 	{STRUCT_FLD(field_name,		"lock_mode"),
850 	 /* S[,GAP] X[,GAP] IS[,GAP] IX[,GAP] AUTO_INC UNKNOWN */
851 	 STRUCT_FLD(field_length,	32),
852 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
853 	 STRUCT_FLD(value,		0),
854 	 STRUCT_FLD(field_flags,	0),
855 	 STRUCT_FLD(old_name,		""),
856 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
857 
858 #define IDX_LOCK_TYPE		3
859 	{STRUCT_FLD(field_name,		"lock_type"),
860 	 STRUCT_FLD(field_length,	32 /* RECORD|TABLE|UNKNOWN */),
861 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
862 	 STRUCT_FLD(value,		0),
863 	 STRUCT_FLD(field_flags,	0),
864 	 STRUCT_FLD(old_name,		""),
865 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
866 
867 #define IDX_LOCK_TABLE		4
868 	{STRUCT_FLD(field_name,		"lock_table"),
869 	 STRUCT_FLD(field_length,	1024),
870 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
871 	 STRUCT_FLD(value,		0),
872 	 STRUCT_FLD(field_flags,	0),
873 	 STRUCT_FLD(old_name,		""),
874 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
875 
876 #define IDX_LOCK_INDEX		5
877 	{STRUCT_FLD(field_name,		"lock_index"),
878 	 STRUCT_FLD(field_length,	1024),
879 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
880 	 STRUCT_FLD(value,		0),
881 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
882 	 STRUCT_FLD(old_name,		""),
883 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
884 
885 #define IDX_LOCK_SPACE		6
886 	{STRUCT_FLD(field_name,		"lock_space"),
887 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
888 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
889 	 STRUCT_FLD(value,		0),
890 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
891 	 STRUCT_FLD(old_name,		""),
892 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
893 
894 #define IDX_LOCK_PAGE		7
895 	{STRUCT_FLD(field_name,		"lock_page"),
896 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
897 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
898 	 STRUCT_FLD(value,		0),
899 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
900 	 STRUCT_FLD(old_name,		""),
901 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
902 
903 #define IDX_LOCK_REC		8
904 	{STRUCT_FLD(field_name,		"lock_rec"),
905 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
906 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
907 	 STRUCT_FLD(value,		0),
908 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
909 	 STRUCT_FLD(old_name,		""),
910 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
911 
912 #define IDX_LOCK_DATA		9
913 	{STRUCT_FLD(field_name,		"lock_data"),
914 	 STRUCT_FLD(field_length,	TRX_I_S_LOCK_DATA_MAX_LEN),
915 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
916 	 STRUCT_FLD(value,		0),
917 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
918 	 STRUCT_FLD(old_name,		""),
919 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
920 
921 	END_OF_ST_FIELD_INFO
922 };
923 
924 /*******************************************************************//**
925 Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_locks
926 table with it.
927 @return 0 on success */
928 static
929 int
fill_innodb_locks_from_cache(trx_i_s_cache_t * cache,THD * thd,TABLE * table)930 fill_innodb_locks_from_cache(
931 /*=========================*/
932 	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
933 	THD*			thd,	/*!< in: MySQL client connection */
934 	TABLE*			table)	/*!< in/out: fill this table */
935 {
936 	Field**	fields;
937 	ulint	rows_num;
938 	char	lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
939 	ulint	i;
940 
941 	DBUG_ENTER("fill_innodb_locks_from_cache");
942 
943 	fields = table->field;
944 
945 	rows_num = trx_i_s_cache_get_rows_used(cache,
946 					       I_S_INNODB_LOCKS);
947 
948 	for (i = 0; i < rows_num; i++) {
949 
950 		i_s_locks_row_t*	row;
951 		char			buf[MAX_FULL_NAME_LEN + 1];
952 		const char*		bufend;
953 
954 		char			lock_trx_id[TRX_ID_MAX_LEN + 1];
955 
956 		row = (i_s_locks_row_t*)
957 			trx_i_s_cache_get_nth_row(
958 				cache, I_S_INNODB_LOCKS, i);
959 
960 		/* lock_id */
961 		trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id));
962 		OK(field_store_string(fields[IDX_LOCK_ID],
963 				      lock_id));
964 
965 		/* lock_trx_id */
966 		ut_snprintf(lock_trx_id, sizeof(lock_trx_id),
967 			    TRX_ID_FMT, row->lock_trx_id);
968 		OK(field_store_string(fields[IDX_LOCK_TRX_ID], lock_trx_id));
969 
970 		/* lock_mode */
971 		OK(field_store_string(fields[IDX_LOCK_MODE],
972 				      row->lock_mode));
973 
974 		/* lock_type */
975 		OK(field_store_string(fields[IDX_LOCK_TYPE],
976 				      row->lock_type));
977 
978 		/* lock_table */
979 		bufend = innobase_convert_name(buf, sizeof(buf),
980 					       row->lock_table,
981 					       strlen(row->lock_table),
982 					       thd);
983 		OK(fields[IDX_LOCK_TABLE]->store(
984 			buf, static_cast<size_t>(bufend - buf),
985 			system_charset_info));
986 
987 		/* lock_index */
988 		if (row->lock_index != NULL) {
989 			OK(field_store_index_name(fields[IDX_LOCK_INDEX],
990 						  row->lock_index));
991 		} else {
992 			fields[IDX_LOCK_INDEX]->set_null();
993 		}
994 
995 		/* lock_space */
996 		OK(field_store_ulint(fields[IDX_LOCK_SPACE],
997 				     row->lock_space));
998 
999 		/* lock_page */
1000 		OK(field_store_ulint(fields[IDX_LOCK_PAGE],
1001 				     row->lock_page));
1002 
1003 		/* lock_rec */
1004 		OK(field_store_ulint(fields[IDX_LOCK_REC],
1005 				     row->lock_rec));
1006 
1007 		/* lock_data */
1008 		OK(field_store_string(fields[IDX_LOCK_DATA],
1009 				      row->lock_data));
1010 
1011 		OK(schema_table_store_record(thd, table));
1012 	}
1013 
1014 	DBUG_RETURN(0);
1015 }
1016 
1017 /*******************************************************************//**
1018 Bind the dynamic table INFORMATION_SCHEMA.innodb_locks
1019 @return 0 on success */
1020 static
1021 int
innodb_locks_init(void * p)1022 innodb_locks_init(
1023 /*==============*/
1024 	void*	p)	/*!< in/out: table schema object */
1025 {
1026 	ST_SCHEMA_TABLE*	schema;
1027 
1028 	DBUG_ENTER("innodb_locks_init");
1029 
1030 	schema = (ST_SCHEMA_TABLE*) p;
1031 
1032 	schema->fields_info = innodb_locks_fields_info;
1033 	schema->fill_table = trx_i_s_common_fill_table;
1034 
1035 	DBUG_RETURN(0);
1036 }
1037 
1038 struct st_mysql_plugin	i_s_innodb_locks =
1039 {
1040 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1041 	/* int */
1042 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1043 
1044 	/* pointer to type-specific plugin descriptor */
1045 	/* void* */
1046 	STRUCT_FLD(info, &i_s_info),
1047 
1048 	/* plugin name */
1049 	/* const char* */
1050 	STRUCT_FLD(name, "INNODB_LOCKS"),
1051 
1052 	/* plugin author (for SHOW PLUGINS) */
1053 	/* const char* */
1054 	STRUCT_FLD(author, plugin_author),
1055 
1056 	/* general descriptive text (for SHOW PLUGINS) */
1057 	/* const char* */
1058 	STRUCT_FLD(descr, "InnoDB conflicting locks"),
1059 
1060 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1061 	/* int */
1062 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1063 
1064 	/* the function to invoke when plugin is loaded */
1065 	/* int (*)(void*); */
1066 	STRUCT_FLD(init, innodb_locks_init),
1067 
1068 	/* the function to invoke when plugin is unloaded */
1069 	/* int (*)(void*); */
1070 	STRUCT_FLD(deinit, i_s_common_deinit),
1071 
1072 	/* plugin version (for SHOW PLUGINS) */
1073 	/* unsigned int */
1074 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1075 
1076 	/* struct st_mysql_show_var* */
1077 	STRUCT_FLD(status_vars, NULL),
1078 
1079 	/* struct st_mysql_sys_var** */
1080 	STRUCT_FLD(system_vars, NULL),
1081 
1082 	/* reserved for dependency checking */
1083 	/* void* */
1084 	STRUCT_FLD(__reserved1, NULL),
1085 
1086 	/* Plugin flags */
1087 	/* unsigned long */
1088 	STRUCT_FLD(flags, 0UL),
1089 };
1090 
1091 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */
1092 static ST_FIELD_INFO	innodb_lock_waits_fields_info[] =
1093 {
1094 #define IDX_REQUESTING_TRX_ID	0
1095 	{STRUCT_FLD(field_name,		"requesting_trx_id"),
1096 	 STRUCT_FLD(field_length,	TRX_ID_MAX_LEN + 1),
1097 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1098 	 STRUCT_FLD(value,		0),
1099 	 STRUCT_FLD(field_flags,	0),
1100 	 STRUCT_FLD(old_name,		""),
1101 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1102 
1103 #define IDX_REQUESTED_LOCK_ID	1
1104 	{STRUCT_FLD(field_name,		"requested_lock_id"),
1105 	 STRUCT_FLD(field_length,	TRX_I_S_LOCK_ID_MAX_LEN + 1),
1106 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1107 	 STRUCT_FLD(value,		0),
1108 	 STRUCT_FLD(field_flags,	0),
1109 	 STRUCT_FLD(old_name,		""),
1110 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1111 
1112 #define IDX_BLOCKING_TRX_ID	2
1113 	{STRUCT_FLD(field_name,		"blocking_trx_id"),
1114 	 STRUCT_FLD(field_length,	TRX_ID_MAX_LEN + 1),
1115 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1116 	 STRUCT_FLD(value,		0),
1117 	 STRUCT_FLD(field_flags,	0),
1118 	 STRUCT_FLD(old_name,		""),
1119 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1120 
1121 #define IDX_BLOCKING_LOCK_ID	3
1122 	{STRUCT_FLD(field_name,		"blocking_lock_id"),
1123 	 STRUCT_FLD(field_length,	TRX_I_S_LOCK_ID_MAX_LEN + 1),
1124 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1125 	 STRUCT_FLD(value,		0),
1126 	 STRUCT_FLD(field_flags,	0),
1127 	 STRUCT_FLD(old_name,		""),
1128 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1129 
1130 	END_OF_ST_FIELD_INFO
1131 };
1132 
1133 /*******************************************************************//**
1134 Read data from cache buffer and fill the
1135 INFORMATION_SCHEMA.innodb_lock_waits table with it.
1136 @return 0 on success */
1137 static
1138 int
fill_innodb_lock_waits_from_cache(trx_i_s_cache_t * cache,THD * thd,TABLE * table)1139 fill_innodb_lock_waits_from_cache(
1140 /*==============================*/
1141 	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
1142 	THD*			thd,	/*!< in: used to call
1143 					schema_table_store_record() */
1144 	TABLE*			table)	/*!< in/out: fill this table */
1145 {
1146 	Field**	fields;
1147 	ulint	rows_num;
1148 	char	requested_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
1149 	char	blocking_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
1150 	ulint	i;
1151 
1152 	DBUG_ENTER("fill_innodb_lock_waits_from_cache");
1153 
1154 	fields = table->field;
1155 
1156 	rows_num = trx_i_s_cache_get_rows_used(cache,
1157 					       I_S_INNODB_LOCK_WAITS);
1158 
1159 	for (i = 0; i < rows_num; i++) {
1160 
1161 		i_s_lock_waits_row_t*	row;
1162 
1163 		char	requesting_trx_id[TRX_ID_MAX_LEN + 1];
1164 		char	blocking_trx_id[TRX_ID_MAX_LEN + 1];
1165 
1166 		row = (i_s_lock_waits_row_t*)
1167 			trx_i_s_cache_get_nth_row(
1168 				cache, I_S_INNODB_LOCK_WAITS, i);
1169 
1170 		/* requesting_trx_id */
1171 		ut_snprintf(requesting_trx_id, sizeof(requesting_trx_id),
1172 			    TRX_ID_FMT, row->requested_lock_row->lock_trx_id);
1173 		OK(field_store_string(fields[IDX_REQUESTING_TRX_ID],
1174 				      requesting_trx_id));
1175 
1176 		/* requested_lock_id */
1177 		OK(field_store_string(
1178 			   fields[IDX_REQUESTED_LOCK_ID],
1179 			   trx_i_s_create_lock_id(
1180 				   row->requested_lock_row,
1181 				   requested_lock_id,
1182 				   sizeof(requested_lock_id))));
1183 
1184 		/* blocking_trx_id */
1185 		ut_snprintf(blocking_trx_id, sizeof(blocking_trx_id),
1186 			    TRX_ID_FMT, row->blocking_lock_row->lock_trx_id);
1187 		OK(field_store_string(fields[IDX_BLOCKING_TRX_ID],
1188 				      blocking_trx_id));
1189 
1190 		/* blocking_lock_id */
1191 		OK(field_store_string(
1192 			   fields[IDX_BLOCKING_LOCK_ID],
1193 			   trx_i_s_create_lock_id(
1194 				   row->blocking_lock_row,
1195 				   blocking_lock_id,
1196 				   sizeof(blocking_lock_id))));
1197 
1198 		OK(schema_table_store_record(thd, table));
1199 	}
1200 
1201 	DBUG_RETURN(0);
1202 }
1203 
1204 /*******************************************************************//**
1205 Bind the dynamic table INFORMATION_SCHEMA.innodb_lock_waits
1206 @return 0 on success */
1207 static
1208 int
innodb_lock_waits_init(void * p)1209 innodb_lock_waits_init(
1210 /*===================*/
1211 	void*	p)	/*!< in/out: table schema object */
1212 {
1213 	ST_SCHEMA_TABLE*	schema;
1214 
1215 	DBUG_ENTER("innodb_lock_waits_init");
1216 
1217 	schema = (ST_SCHEMA_TABLE*) p;
1218 
1219 	schema->fields_info = innodb_lock_waits_fields_info;
1220 	schema->fill_table = trx_i_s_common_fill_table;
1221 
1222 	DBUG_RETURN(0);
1223 }
1224 
1225 struct st_mysql_plugin	i_s_innodb_lock_waits =
1226 {
1227 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1228 	/* int */
1229 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1230 
1231 	/* pointer to type-specific plugin descriptor */
1232 	/* void* */
1233 	STRUCT_FLD(info, &i_s_info),
1234 
1235 	/* plugin name */
1236 	/* const char* */
1237 	STRUCT_FLD(name, "INNODB_LOCK_WAITS"),
1238 
1239 	/* plugin author (for SHOW PLUGINS) */
1240 	/* const char* */
1241 	STRUCT_FLD(author, plugin_author),
1242 
1243 	/* general descriptive text (for SHOW PLUGINS) */
1244 	/* const char* */
1245 	STRUCT_FLD(descr, "InnoDB which lock is blocking which"),
1246 
1247 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1248 	/* int */
1249 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1250 
1251 	/* the function to invoke when plugin is loaded */
1252 	/* int (*)(void*); */
1253 	STRUCT_FLD(init, innodb_lock_waits_init),
1254 
1255 	/* the function to invoke when plugin is unloaded */
1256 	/* int (*)(void*); */
1257 	STRUCT_FLD(deinit, i_s_common_deinit),
1258 
1259 	/* plugin version (for SHOW PLUGINS) */
1260 	/* unsigned int */
1261 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1262 
1263 	/* struct st_mysql_show_var* */
1264 	STRUCT_FLD(status_vars, NULL),
1265 
1266 	/* struct st_mysql_sys_var** */
1267 	STRUCT_FLD(system_vars, NULL),
1268 
1269 	/* reserved for dependency checking */
1270 	/* void* */
1271 	STRUCT_FLD(__reserved1, NULL),
1272 
1273 	/* Plugin flags */
1274 	/* unsigned long */
1275 	STRUCT_FLD(flags, 0UL),
1276 };
1277 
1278 /*******************************************************************//**
1279 Common function to fill any of the dynamic tables:
1280 INFORMATION_SCHEMA.innodb_trx
1281 INFORMATION_SCHEMA.innodb_locks
1282 INFORMATION_SCHEMA.innodb_lock_waits
1283 @return 0 on success */
1284 static
1285 int
trx_i_s_common_fill_table(THD * thd,TABLE_LIST * tables,Item *)1286 trx_i_s_common_fill_table(
1287 /*======================*/
1288 	THD*		thd,	/*!< in: thread */
1289 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1290 	Item*		)	/*!< in: condition (not used) */
1291 {
1292 	const char*		table_name;
1293 	int			ret;
1294 	trx_i_s_cache_t*	cache;
1295 
1296 	DBUG_ENTER("trx_i_s_common_fill_table");
1297 
1298 	/* deny access to non-superusers */
1299 	if (check_global_access(thd, PROCESS_ACL)) {
1300 
1301 		DBUG_RETURN(0);
1302 	}
1303 
1304 	/* minimize the number of places where global variables are
1305 	referenced */
1306 	cache = trx_i_s_cache;
1307 
1308 	/* which table we have to fill? */
1309 	table_name = tables->schema_table_name;
1310 	/* or table_name = tables->schema_table->table_name; */
1311 
1312 	RETURN_IF_INNODB_NOT_STARTED(table_name);
1313 
1314 	/* update the cache */
1315 	trx_i_s_cache_start_write(cache);
1316 	trx_i_s_possibly_fetch_data_into_cache(cache);
1317 	trx_i_s_cache_end_write(cache);
1318 
1319 	if (trx_i_s_cache_is_truncated(cache)) {
1320 
1321 		ib::warn() << "Data in " << table_name << " truncated due to"
1322 			" memory limit of " << TRX_I_S_MEM_LIMIT << " bytes";
1323 	}
1324 
1325 	ret = 0;
1326 
1327 	trx_i_s_cache_start_read(cache);
1328 
1329 	if (innobase_strcasecmp(table_name, "innodb_trx") == 0) {
1330 
1331 		if (fill_innodb_trx_from_cache(
1332 			cache, thd, tables->table) != 0) {
1333 
1334 			ret = 1;
1335 		}
1336 
1337 	} else if (innobase_strcasecmp(table_name, "innodb_locks") == 0) {
1338 
1339 		if (fill_innodb_locks_from_cache(
1340 			cache, thd, tables->table) != 0) {
1341 
1342 			ret = 1;
1343 		}
1344 
1345 	} else if (innobase_strcasecmp(table_name, "innodb_lock_waits") == 0) {
1346 
1347 		if (fill_innodb_lock_waits_from_cache(
1348 			cache, thd, tables->table) != 0) {
1349 
1350 			ret = 1;
1351 		}
1352 
1353 	} else {
1354 		ib::error() << "trx_i_s_common_fill_table() was"
1355 			" called to fill unknown table: " << table_name << "."
1356 			" This function only knows how to fill"
1357 			" innodb_trx, innodb_locks and"
1358 			" innodb_lock_waits tables.";
1359 
1360 		ret = 1;
1361 	}
1362 
1363 	trx_i_s_cache_end_read(cache);
1364 
1365 #if 0
1366 	DBUG_RETURN(ret);
1367 #else
1368 	/* if this function returns something else than 0 then a
1369 	deadlock occurs between the mysqld server and mysql client,
1370 	see http://bugs.mysql.com/29900 ; when that bug is resolved
1371 	we can enable the DBUG_RETURN(ret) above */
1372 	ret++;  // silence a gcc46 warning
1373 	DBUG_RETURN(0);
1374 #endif
1375 }
1376 
1377 /* Fields of the dynamic table information_schema.innodb_cmp. */
1378 static ST_FIELD_INFO	i_s_cmp_fields_info[] =
1379 {
1380 	{STRUCT_FLD(field_name,		"page_size"),
1381 	 STRUCT_FLD(field_length,	5),
1382 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1383 	 STRUCT_FLD(value,		0),
1384 	 STRUCT_FLD(field_flags,	0),
1385 	 STRUCT_FLD(old_name,		"Compressed Page Size"),
1386 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1387 
1388 	{STRUCT_FLD(field_name,		"compress_ops"),
1389 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1390 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1391 	 STRUCT_FLD(value,		0),
1392 	 STRUCT_FLD(field_flags,	0),
1393 	 STRUCT_FLD(old_name,		"Total Number of Compressions"),
1394 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1395 
1396 	{STRUCT_FLD(field_name,		"compress_ops_ok"),
1397 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1398 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1399 	 STRUCT_FLD(value,		0),
1400 	 STRUCT_FLD(field_flags,	0),
1401 	 STRUCT_FLD(old_name,		"Total Number of"
1402 					" Successful Compressions"),
1403 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1404 
1405 	{STRUCT_FLD(field_name,		"compress_time"),
1406 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1407 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1408 	 STRUCT_FLD(value,		0),
1409 	 STRUCT_FLD(field_flags,	0),
1410 	 STRUCT_FLD(old_name,		"Total Duration of Compressions,"
1411 		    " in Seconds"),
1412 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1413 
1414 	{STRUCT_FLD(field_name,		"uncompress_ops"),
1415 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1416 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1417 	 STRUCT_FLD(value,		0),
1418 	 STRUCT_FLD(field_flags,	0),
1419 	 STRUCT_FLD(old_name,		"Total Number of Decompressions"),
1420 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1421 
1422 	{STRUCT_FLD(field_name,		"uncompress_time"),
1423 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1424 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1425 	 STRUCT_FLD(value,		0),
1426 	 STRUCT_FLD(field_flags,	0),
1427 	 STRUCT_FLD(old_name,		"Total Duration of Decompressions,"
1428 		    " in Seconds"),
1429 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1430 
1431 	END_OF_ST_FIELD_INFO
1432 };
1433 
1434 
1435 /*******************************************************************//**
1436 Fill the dynamic table information_schema.innodb_cmp or
1437 innodb_cmp_reset.
1438 @return 0 on success, 1 on failure */
1439 static
1440 int
i_s_cmp_fill_low(THD * thd,TABLE_LIST * tables,Item *,ibool reset)1441 i_s_cmp_fill_low(
1442 /*=============*/
1443 	THD*		thd,	/*!< in: thread */
1444 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1445 	Item*		,	/*!< in: condition (ignored) */
1446 	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1447 {
1448 	TABLE*	table	= (TABLE*) tables->table;
1449 	int	status	= 0;
1450 
1451 	DBUG_ENTER("i_s_cmp_fill_low");
1452 
1453 	/* deny access to non-superusers */
1454 	if (check_global_access(thd, PROCESS_ACL)) {
1455 
1456 		DBUG_RETURN(0);
1457 	}
1458 
1459 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
1460 
1461 	for (uint i = 0; i < PAGE_ZIP_SSIZE_MAX; i++) {
1462 		page_zip_stat_t*	zip_stat = &page_zip_stat[i];
1463 
1464 		table->field[0]->store(UNIV_ZIP_SIZE_MIN << i);
1465 
1466 		/* The cumulated counts are not protected by any
1467 		mutex.  Thus, some operation in page0zip.cc could
1468 		increment a counter between the time we read it and
1469 		clear it.  We could introduce mutex protection, but it
1470 		could cause a measureable performance hit in
1471 		page0zip.cc. */
1472 		table->field[1]->store(zip_stat->compressed, true);
1473 		table->field[2]->store(zip_stat->compressed_ok, true);
1474 		table->field[3]->store(zip_stat->compressed_usec / 1000000, true);
1475 		table->field[4]->store(zip_stat->decompressed, true);
1476 		table->field[5]->store(zip_stat->decompressed_usec / 1000000, true);
1477 
1478 		if (reset) {
1479 			new (zip_stat) page_zip_stat_t;
1480 		}
1481 
1482 		if (schema_table_store_record(thd, table)) {
1483 			status = 1;
1484 			break;
1485 		}
1486 	}
1487 
1488 	DBUG_RETURN(status);
1489 }
1490 
1491 /*******************************************************************//**
1492 Fill the dynamic table information_schema.innodb_cmp.
1493 @return 0 on success, 1 on failure */
1494 static
1495 int
i_s_cmp_fill(THD * thd,TABLE_LIST * tables,Item * cond)1496 i_s_cmp_fill(
1497 /*=========*/
1498 	THD*		thd,	/*!< in: thread */
1499 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1500 	Item*		cond)	/*!< in: condition (ignored) */
1501 {
1502 	return(i_s_cmp_fill_low(thd, tables, cond, FALSE));
1503 }
1504 
1505 /*******************************************************************//**
1506 Fill the dynamic table information_schema.innodb_cmp_reset.
1507 @return 0 on success, 1 on failure */
1508 static
1509 int
i_s_cmp_reset_fill(THD * thd,TABLE_LIST * tables,Item * cond)1510 i_s_cmp_reset_fill(
1511 /*===============*/
1512 	THD*		thd,	/*!< in: thread */
1513 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1514 	Item*		cond)	/*!< in: condition (ignored) */
1515 {
1516 	return(i_s_cmp_fill_low(thd, tables, cond, TRUE));
1517 }
1518 
1519 /*******************************************************************//**
1520 Bind the dynamic table information_schema.innodb_cmp.
1521 @return 0 on success */
1522 static
1523 int
i_s_cmp_init(void * p)1524 i_s_cmp_init(
1525 /*=========*/
1526 	void*	p)	/*!< in/out: table schema object */
1527 {
1528 	DBUG_ENTER("i_s_cmp_init");
1529 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1530 
1531 	schema->fields_info = i_s_cmp_fields_info;
1532 	schema->fill_table = i_s_cmp_fill;
1533 
1534 	DBUG_RETURN(0);
1535 }
1536 
1537 /*******************************************************************//**
1538 Bind the dynamic table information_schema.innodb_cmp_reset.
1539 @return 0 on success */
1540 static
1541 int
i_s_cmp_reset_init(void * p)1542 i_s_cmp_reset_init(
1543 /*===============*/
1544 	void*	p)	/*!< in/out: table schema object */
1545 {
1546 	DBUG_ENTER("i_s_cmp_reset_init");
1547 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1548 
1549 	schema->fields_info = i_s_cmp_fields_info;
1550 	schema->fill_table = i_s_cmp_reset_fill;
1551 
1552 	DBUG_RETURN(0);
1553 }
1554 
1555 struct st_mysql_plugin	i_s_innodb_cmp =
1556 {
1557 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1558 	/* int */
1559 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1560 
1561 	/* pointer to type-specific plugin descriptor */
1562 	/* void* */
1563 	STRUCT_FLD(info, &i_s_info),
1564 
1565 	/* plugin name */
1566 	/* const char* */
1567 	STRUCT_FLD(name, "INNODB_CMP"),
1568 
1569 	/* plugin author (for SHOW PLUGINS) */
1570 	/* const char* */
1571 	STRUCT_FLD(author, plugin_author),
1572 
1573 	/* general descriptive text (for SHOW PLUGINS) */
1574 	/* const char* */
1575 	STRUCT_FLD(descr, "Statistics for the InnoDB compression"),
1576 
1577 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1578 	/* int */
1579 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1580 
1581 	/* the function to invoke when plugin is loaded */
1582 	/* int (*)(void*); */
1583 	STRUCT_FLD(init, i_s_cmp_init),
1584 
1585 	/* the function to invoke when plugin is unloaded */
1586 	/* int (*)(void*); */
1587 	STRUCT_FLD(deinit, i_s_common_deinit),
1588 
1589 	/* plugin version (for SHOW PLUGINS) */
1590 	/* unsigned int */
1591 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1592 
1593 	/* struct st_mysql_show_var* */
1594 	STRUCT_FLD(status_vars, NULL),
1595 
1596 	/* struct st_mysql_sys_var** */
1597 	STRUCT_FLD(system_vars, NULL),
1598 
1599 	/* reserved for dependency checking */
1600 	/* void* */
1601 	STRUCT_FLD(__reserved1, NULL),
1602 
1603 	/* Plugin flags */
1604 	/* unsigned long */
1605 	STRUCT_FLD(flags, 0UL),
1606 };
1607 
1608 struct st_mysql_plugin	i_s_innodb_cmp_reset =
1609 {
1610 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1611 	/* int */
1612 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1613 
1614 	/* pointer to type-specific plugin descriptor */
1615 	/* void* */
1616 	STRUCT_FLD(info, &i_s_info),
1617 
1618 	/* plugin name */
1619 	/* const char* */
1620 	STRUCT_FLD(name, "INNODB_CMP_RESET"),
1621 
1622 	/* plugin author (for SHOW PLUGINS) */
1623 	/* const char* */
1624 	STRUCT_FLD(author, plugin_author),
1625 
1626 	/* general descriptive text (for SHOW PLUGINS) */
1627 	/* const char* */
1628 	STRUCT_FLD(descr, "Statistics for the InnoDB compression;"
1629 		   " reset cumulated counts"),
1630 
1631 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1632 	/* int */
1633 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1634 
1635 	/* the function to invoke when plugin is loaded */
1636 	/* int (*)(void*); */
1637 	STRUCT_FLD(init, i_s_cmp_reset_init),
1638 
1639 	/* the function to invoke when plugin is unloaded */
1640 	/* int (*)(void*); */
1641 	STRUCT_FLD(deinit, i_s_common_deinit),
1642 
1643 	/* plugin version (for SHOW PLUGINS) */
1644 	/* unsigned int */
1645 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1646 
1647 	/* struct st_mysql_show_var* */
1648 	STRUCT_FLD(status_vars, NULL),
1649 
1650 	/* struct st_mysql_sys_var** */
1651 	STRUCT_FLD(system_vars, NULL),
1652 
1653 	/* reserved for dependency checking */
1654 	/* void* */
1655 	STRUCT_FLD(__reserved1, NULL),
1656 
1657 	/* Plugin flags */
1658 	/* unsigned long */
1659 	STRUCT_FLD(flags, 0UL),
1660 };
1661 
1662 /* Fields of the dynamic tables
1663 information_schema.innodb_cmp_per_index and
1664 information_schema.innodb_cmp_per_index_reset. */
1665 static ST_FIELD_INFO	i_s_cmp_per_index_fields_info[] =
1666 {
1667 #define IDX_DATABASE_NAME	0
1668 	{STRUCT_FLD(field_name,		"database_name"),
1669 	 STRUCT_FLD(field_length,	192),
1670 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1671 	 STRUCT_FLD(value,		0),
1672 	 STRUCT_FLD(field_flags,	0),
1673 	 STRUCT_FLD(old_name,		""),
1674 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1675 
1676 #define IDX_TABLE_NAME		1
1677 	{STRUCT_FLD(field_name,		"table_name"),
1678 	 STRUCT_FLD(field_length,	192),
1679 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1680 	 STRUCT_FLD(value,		0),
1681 	 STRUCT_FLD(field_flags,	0),
1682 	 STRUCT_FLD(old_name,		""),
1683 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1684 
1685 #define IDX_INDEX_NAME		2
1686 	{STRUCT_FLD(field_name,		"index_name"),
1687 	 STRUCT_FLD(field_length,	192),
1688 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
1689 	 STRUCT_FLD(value,		0),
1690 	 STRUCT_FLD(field_flags,	0),
1691 	 STRUCT_FLD(old_name,		""),
1692 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1693 
1694 #define IDX_COMPRESS_OPS	3
1695 	{STRUCT_FLD(field_name,		"compress_ops"),
1696 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1697 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1698 	 STRUCT_FLD(value,		0),
1699 	 STRUCT_FLD(field_flags,	0),
1700 	 STRUCT_FLD(old_name,		""),
1701 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1702 
1703 #define IDX_COMPRESS_OPS_OK	4
1704 	{STRUCT_FLD(field_name,		"compress_ops_ok"),
1705 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1706 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1707 	 STRUCT_FLD(value,		0),
1708 	 STRUCT_FLD(field_flags,	0),
1709 	 STRUCT_FLD(old_name,		""),
1710 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1711 
1712 #define IDX_COMPRESS_TIME	5
1713 	{STRUCT_FLD(field_name,		"compress_time"),
1714 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1715 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1716 	 STRUCT_FLD(value,		0),
1717 	 STRUCT_FLD(field_flags,	0),
1718 	 STRUCT_FLD(old_name,		""),
1719 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1720 
1721 #define IDX_UNCOMPRESS_OPS	6
1722 	{STRUCT_FLD(field_name,		"uncompress_ops"),
1723 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1724 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1725 	 STRUCT_FLD(value,		0),
1726 	 STRUCT_FLD(field_flags,	0),
1727 	 STRUCT_FLD(old_name,		""),
1728 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1729 
1730 #define IDX_UNCOMPRESS_TIME	7
1731 	{STRUCT_FLD(field_name,		"uncompress_time"),
1732 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
1733 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
1734 	 STRUCT_FLD(value,		0),
1735 	 STRUCT_FLD(field_flags,	0),
1736 	 STRUCT_FLD(old_name,		""),
1737 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
1738 
1739 	END_OF_ST_FIELD_INFO
1740 };
1741 
1742 /*******************************************************************//**
1743 Fill the dynamic table
1744 information_schema.innodb_cmp_per_index or
1745 information_schema.innodb_cmp_per_index_reset.
1746 @return 0 on success, 1 on failure */
1747 static
1748 int
i_s_cmp_per_index_fill_low(THD * thd,TABLE_LIST * tables,Item *,ibool reset)1749 i_s_cmp_per_index_fill_low(
1750 /*=======================*/
1751 	THD*		thd,	/*!< in: thread */
1752 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1753 	Item*		,	/*!< in: condition (ignored) */
1754 	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1755 {
1756 	TABLE*	table = tables->table;
1757 	Field**	fields = table->field;
1758 	int	status = 0;
1759 	int	error;
1760 
1761 	DBUG_ENTER("i_s_cmp_per_index_fill_low");
1762 
1763 	/* deny access to non-superusers */
1764 	if (check_global_access(thd, PROCESS_ACL)) {
1765 
1766 		DBUG_RETURN(0);
1767 	}
1768 
1769 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
1770 
1771 	/* Create a snapshot of the stats so we do not bump into lock
1772 	order violations with dict_sys->mutex below. */
1773 	mutex_enter(&page_zip_stat_per_index_mutex);
1774 	page_zip_stat_per_index_t		snap (page_zip_stat_per_index);
1775 	mutex_exit(&page_zip_stat_per_index_mutex);
1776 
1777 	mutex_enter(&dict_sys->mutex);
1778 
1779 	page_zip_stat_per_index_t::iterator	iter;
1780 	ulint					i;
1781 
1782 	for (iter = snap.begin(), i = 0; iter != snap.end(); iter++, i++) {
1783 
1784 		char		name[192];
1785 		dict_index_t*	index = dict_index_find_on_id_low(iter->first);
1786 
1787 		if (index != NULL) {
1788 			char	db_utf8[MAX_DB_UTF8_LEN];
1789 			char	table_utf8[MAX_TABLE_UTF8_LEN];
1790 
1791 			dict_fs2utf8(index->table_name,
1792 				     db_utf8, sizeof(db_utf8),
1793 				     table_utf8, sizeof(table_utf8));
1794 
1795 			field_store_string(fields[IDX_DATABASE_NAME], db_utf8);
1796 			field_store_string(fields[IDX_TABLE_NAME], table_utf8);
1797 			field_store_index_name(fields[IDX_INDEX_NAME],
1798 					       index->name);
1799 		} else {
1800 			/* index not found */
1801 			ut_snprintf(name, sizeof(name),
1802 				    "index_id:" IB_ID_FMT, iter->first);
1803 			field_store_string(fields[IDX_DATABASE_NAME],
1804 					   "unknown");
1805 			field_store_string(fields[IDX_TABLE_NAME],
1806 					   "unknown");
1807 			field_store_string(fields[IDX_INDEX_NAME],
1808 					   name);
1809 		}
1810 
1811 		fields[IDX_COMPRESS_OPS]->store(
1812 			   iter->second.compressed, true);
1813 
1814 		fields[IDX_COMPRESS_OPS_OK]->store(
1815 			   iter->second.compressed_ok, true);
1816 
1817 		fields[IDX_COMPRESS_TIME]->store(
1818 			   iter->second.compressed_usec / 1000000, true);
1819 
1820 		fields[IDX_UNCOMPRESS_OPS]->store(
1821 			   iter->second.decompressed, true);
1822 
1823 		fields[IDX_UNCOMPRESS_TIME]->store(
1824 			   iter->second.decompressed_usec / 1000000, true);
1825 
1826 		if ((error = schema_table_store_record2(thd, table, false))) {
1827 			mutex_exit(&dict_sys->mutex);
1828 			if (convert_heap_table_to_ondisk(thd, table, error) != 0) {
1829 				status = 1;
1830 				goto err;
1831 			}
1832 			mutex_enter(&dict_sys->mutex);
1833 		}
1834 
1835 		/* Release and reacquire the dict mutex to allow other
1836 		threads to proceed. This could eventually result in the
1837 		contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
1838 		inconsistent, but it is an acceptable compromise. */
1839 		if (i % 1000 == 0) {
1840 			mutex_exit(&dict_sys->mutex);
1841 			mutex_enter(&dict_sys->mutex);
1842 		}
1843 	}
1844 
1845 	mutex_exit(&dict_sys->mutex);
1846 err:
1847 
1848 	if (reset) {
1849 		page_zip_reset_stat_per_index();
1850 	}
1851 
1852 	DBUG_RETURN(status);
1853 }
1854 
1855 /*******************************************************************//**
1856 Fill the dynamic table information_schema.innodb_cmp_per_index.
1857 @return 0 on success, 1 on failure */
1858 static
1859 int
i_s_cmp_per_index_fill(THD * thd,TABLE_LIST * tables,Item * cond)1860 i_s_cmp_per_index_fill(
1861 /*===================*/
1862 	THD*		thd,	/*!< in: thread */
1863 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1864 	Item*		cond)	/*!< in: condition (ignored) */
1865 {
1866 	return(i_s_cmp_per_index_fill_low(thd, tables, cond, FALSE));
1867 }
1868 
1869 /*******************************************************************//**
1870 Fill the dynamic table information_schema.innodb_cmp_per_index_reset.
1871 @return 0 on success, 1 on failure */
1872 static
1873 int
i_s_cmp_per_index_reset_fill(THD * thd,TABLE_LIST * tables,Item * cond)1874 i_s_cmp_per_index_reset_fill(
1875 /*=========================*/
1876 	THD*		thd,	/*!< in: thread */
1877 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1878 	Item*		cond)	/*!< in: condition (ignored) */
1879 {
1880 	return(i_s_cmp_per_index_fill_low(thd, tables, cond, TRUE));
1881 }
1882 
1883 /*******************************************************************//**
1884 Bind the dynamic table information_schema.innodb_cmp_per_index.
1885 @return 0 on success */
1886 static
1887 int
i_s_cmp_per_index_init(void * p)1888 i_s_cmp_per_index_init(
1889 /*===================*/
1890 	void*	p)	/*!< in/out: table schema object */
1891 {
1892 	DBUG_ENTER("i_s_cmp_init");
1893 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1894 
1895 	schema->fields_info = i_s_cmp_per_index_fields_info;
1896 	schema->fill_table = i_s_cmp_per_index_fill;
1897 
1898 	DBUG_RETURN(0);
1899 }
1900 
1901 /*******************************************************************//**
1902 Bind the dynamic table information_schema.innodb_cmp_per_index_reset.
1903 @return 0 on success */
1904 static
1905 int
i_s_cmp_per_index_reset_init(void * p)1906 i_s_cmp_per_index_reset_init(
1907 /*=========================*/
1908 	void*	p)	/*!< in/out: table schema object */
1909 {
1910 	DBUG_ENTER("i_s_cmp_reset_init");
1911 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1912 
1913 	schema->fields_info = i_s_cmp_per_index_fields_info;
1914 	schema->fill_table = i_s_cmp_per_index_reset_fill;
1915 
1916 	DBUG_RETURN(0);
1917 }
1918 
1919 struct st_mysql_plugin	i_s_innodb_cmp_per_index =
1920 {
1921 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1922 	/* int */
1923 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1924 
1925 	/* pointer to type-specific plugin descriptor */
1926 	/* void* */
1927 	STRUCT_FLD(info, &i_s_info),
1928 
1929 	/* plugin name */
1930 	/* const char* */
1931 	STRUCT_FLD(name, "INNODB_CMP_PER_INDEX"),
1932 
1933 	/* plugin author (for SHOW PLUGINS) */
1934 	/* const char* */
1935 	STRUCT_FLD(author, plugin_author),
1936 
1937 	/* general descriptive text (for SHOW PLUGINS) */
1938 	/* const char* */
1939 	STRUCT_FLD(descr, "Statistics for the InnoDB compression (per index)"),
1940 
1941 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1942 	/* int */
1943 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1944 
1945 	/* the function to invoke when plugin is loaded */
1946 	/* int (*)(void*); */
1947 	STRUCT_FLD(init, i_s_cmp_per_index_init),
1948 
1949 	/* the function to invoke when plugin is unloaded */
1950 	/* int (*)(void*); */
1951 	STRUCT_FLD(deinit, i_s_common_deinit),
1952 
1953 	/* plugin version (for SHOW PLUGINS) */
1954 	/* unsigned int */
1955 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1956 
1957 	/* struct st_mysql_show_var* */
1958 	STRUCT_FLD(status_vars, NULL),
1959 
1960 	/* struct st_mysql_sys_var** */
1961 	STRUCT_FLD(system_vars, NULL),
1962 
1963 	/* reserved for dependency checking */
1964 	/* void* */
1965 	STRUCT_FLD(__reserved1, NULL),
1966 
1967 	/* Plugin flags */
1968 	/* unsigned long */
1969 	STRUCT_FLD(flags, 0UL),
1970 };
1971 
1972 struct st_mysql_plugin	i_s_innodb_cmp_per_index_reset =
1973 {
1974 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1975 	/* int */
1976 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1977 
1978 	/* pointer to type-specific plugin descriptor */
1979 	/* void* */
1980 	STRUCT_FLD(info, &i_s_info),
1981 
1982 	/* plugin name */
1983 	/* const char* */
1984 	STRUCT_FLD(name, "INNODB_CMP_PER_INDEX_RESET"),
1985 
1986 	/* plugin author (for SHOW PLUGINS) */
1987 	/* const char* */
1988 	STRUCT_FLD(author, plugin_author),
1989 
1990 	/* general descriptive text (for SHOW PLUGINS) */
1991 	/* const char* */
1992 	STRUCT_FLD(descr, "Statistics for the InnoDB compression (per index);"
1993 		   " reset cumulated counts"),
1994 
1995 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1996 	/* int */
1997 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1998 
1999 	/* the function to invoke when plugin is loaded */
2000 	/* int (*)(void*); */
2001 	STRUCT_FLD(init, i_s_cmp_per_index_reset_init),
2002 
2003 	/* the function to invoke when plugin is unloaded */
2004 	/* int (*)(void*); */
2005 	STRUCT_FLD(deinit, i_s_common_deinit),
2006 
2007 	/* plugin version (for SHOW PLUGINS) */
2008 	/* unsigned int */
2009 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
2010 
2011 	/* struct st_mysql_show_var* */
2012 	STRUCT_FLD(status_vars, NULL),
2013 
2014 	/* struct st_mysql_sys_var** */
2015 	STRUCT_FLD(system_vars, NULL),
2016 
2017 	/* reserved for dependency checking */
2018 	/* void* */
2019 	STRUCT_FLD(__reserved1, NULL),
2020 
2021 	/* Plugin flags */
2022 	/* unsigned long */
2023 	STRUCT_FLD(flags, 0UL),
2024 };
2025 
2026 /* Fields of the dynamic table information_schema.innodb_cmpmem. */
2027 static ST_FIELD_INFO	i_s_cmpmem_fields_info[] =
2028 {
2029 	{STRUCT_FLD(field_name,		"page_size"),
2030 	 STRUCT_FLD(field_length,	5),
2031 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
2032 	 STRUCT_FLD(value,		0),
2033 	 STRUCT_FLD(field_flags,	0),
2034 	 STRUCT_FLD(old_name,		"Buddy Block Size"),
2035 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2036 
2037 	{STRUCT_FLD(field_name,		"buffer_pool_instance"),
2038 	STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
2039 	STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
2040 	STRUCT_FLD(value,		0),
2041 	STRUCT_FLD(field_flags,		0),
2042 	STRUCT_FLD(old_name,		"Buffer Pool Id"),
2043 	STRUCT_FLD(open_method,		SKIP_OPEN_TABLE)},
2044 
2045 	{STRUCT_FLD(field_name,		"pages_used"),
2046 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
2047 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
2048 	 STRUCT_FLD(value,		0),
2049 	 STRUCT_FLD(field_flags,	0),
2050 	 STRUCT_FLD(old_name,		"Currently in Use"),
2051 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2052 
2053 	{STRUCT_FLD(field_name,		"pages_free"),
2054 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
2055 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
2056 	 STRUCT_FLD(value,		0),
2057 	 STRUCT_FLD(field_flags,	0),
2058 	 STRUCT_FLD(old_name,		"Currently Available"),
2059 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2060 
2061 	{STRUCT_FLD(field_name,		"relocation_ops"),
2062 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2063 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2064 	 STRUCT_FLD(value,		0),
2065 	 STRUCT_FLD(field_flags,	0),
2066 	 STRUCT_FLD(old_name,		"Total Number of Relocations"),
2067 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2068 
2069 	{STRUCT_FLD(field_name,		"relocation_time"),
2070 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
2071 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
2072 	 STRUCT_FLD(value,		0),
2073 	 STRUCT_FLD(field_flags,	0),
2074 	 STRUCT_FLD(old_name,		"Total Duration of Relocations,"
2075 					" in Seconds"),
2076 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2077 
2078 	END_OF_ST_FIELD_INFO
2079 };
2080 
2081 /*******************************************************************//**
2082 Fill the dynamic table information_schema.innodb_cmpmem or
2083 innodb_cmpmem_reset.
2084 @return 0 on success, 1 on failure */
2085 static
2086 int
i_s_cmpmem_fill_low(THD * thd,TABLE_LIST * tables,Item *,ibool reset)2087 i_s_cmpmem_fill_low(
2088 /*================*/
2089 	THD*		thd,	/*!< in: thread */
2090 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2091 	Item*		,	/*!< in: condition (ignored) */
2092 	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
2093 {
2094 	int		status = 0;
2095 	TABLE*	table	= (TABLE*) tables->table;
2096 
2097 	DBUG_ENTER("i_s_cmpmem_fill_low");
2098 
2099 	/* deny access to non-superusers */
2100 	if (check_global_access(thd, PROCESS_ACL)) {
2101 
2102 		DBUG_RETURN(0);
2103 	}
2104 
2105 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
2106 
2107 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
2108 		buf_pool_t*		buf_pool;
2109 		ulint			zip_free_len_local[BUF_BUDDY_SIZES_MAX + 1];
2110 		buf_buddy_stat_t	buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1];
2111 
2112 		status	= 0;
2113 
2114 		buf_pool = buf_pool_from_array(i);
2115 
2116 		/* Save buddy stats for buffer pool in local variables. */
2117 		mutex_enter(&buf_pool->zip_free_mutex);
2118 		for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
2119 
2120 			zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ?
2121 				UT_LIST_GET_LEN(buf_pool->zip_free[x]) : 0;
2122 
2123 			buddy_stat_local[x] = buf_pool->buddy_stat[x];
2124 
2125 			if (reset) {
2126 				/* This is protected by
2127 				buf_pool->zip_free_mutex. */
2128 				buf_pool->buddy_stat[x].relocated = 0;
2129 				buf_pool->buddy_stat[x].relocated_usec = 0;
2130 			}
2131 		}
2132 		mutex_exit(&buf_pool->zip_free_mutex);
2133 
2134 		for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
2135 			buf_buddy_stat_t*	buddy_stat;
2136 
2137 			buddy_stat = &buddy_stat_local[x];
2138 
2139 			table->field[0]->store(BUF_BUDDY_LOW << x);
2140 			table->field[1]->store(i, true);
2141 			os_rmb;
2142 			table->field[2]->store(buddy_stat->used, true);
2143 			table->field[3]->store(zip_free_len_local[x], true);
2144 			table->field[4]->store(buddy_stat->relocated, true);
2145 			table->field[5]->store(
2146 				buddy_stat->relocated_usec / 1000000, true);
2147 
2148 			if (schema_table_store_record(thd, table)) {
2149 				status = 1;
2150 				break;
2151 			}
2152 		}
2153 
2154 		if (status) {
2155 			break;
2156 		}
2157 	}
2158 
2159 	DBUG_RETURN(status);
2160 }
2161 
2162 /*******************************************************************//**
2163 Fill the dynamic table information_schema.innodb_cmpmem.
2164 @return 0 on success, 1 on failure */
2165 static
2166 int
i_s_cmpmem_fill(THD * thd,TABLE_LIST * tables,Item * cond)2167 i_s_cmpmem_fill(
2168 /*============*/
2169 	THD*		thd,	/*!< in: thread */
2170 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2171 	Item*		cond)	/*!< in: condition (ignored) */
2172 {
2173 	return(i_s_cmpmem_fill_low(thd, tables, cond, FALSE));
2174 }
2175 
2176 /*******************************************************************//**
2177 Fill the dynamic table information_schema.innodb_cmpmem_reset.
2178 @return 0 on success, 1 on failure */
2179 static
2180 int
i_s_cmpmem_reset_fill(THD * thd,TABLE_LIST * tables,Item * cond)2181 i_s_cmpmem_reset_fill(
2182 /*==================*/
2183 	THD*		thd,	/*!< in: thread */
2184 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2185 	Item*		cond)	/*!< in: condition (ignored) */
2186 {
2187 	return(i_s_cmpmem_fill_low(thd, tables, cond, TRUE));
2188 }
2189 
2190 /*******************************************************************//**
2191 Bind the dynamic table information_schema.innodb_cmpmem.
2192 @return 0 on success */
2193 static
2194 int
i_s_cmpmem_init(void * p)2195 i_s_cmpmem_init(
2196 /*============*/
2197 	void*	p)	/*!< in/out: table schema object */
2198 {
2199 	DBUG_ENTER("i_s_cmpmem_init");
2200 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2201 
2202 	schema->fields_info = i_s_cmpmem_fields_info;
2203 	schema->fill_table = i_s_cmpmem_fill;
2204 
2205 	DBUG_RETURN(0);
2206 }
2207 
2208 /*******************************************************************//**
2209 Bind the dynamic table information_schema.innodb_cmpmem_reset.
2210 @return 0 on success */
2211 static
2212 int
i_s_cmpmem_reset_init(void * p)2213 i_s_cmpmem_reset_init(
2214 /*==================*/
2215 	void*	p)	/*!< in/out: table schema object */
2216 {
2217 	DBUG_ENTER("i_s_cmpmem_reset_init");
2218 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2219 
2220 	schema->fields_info = i_s_cmpmem_fields_info;
2221 	schema->fill_table = i_s_cmpmem_reset_fill;
2222 
2223 	DBUG_RETURN(0);
2224 }
2225 
2226 struct st_mysql_plugin	i_s_innodb_cmpmem =
2227 {
2228 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2229 	/* int */
2230 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
2231 
2232 	/* pointer to type-specific plugin descriptor */
2233 	/* void* */
2234 	STRUCT_FLD(info, &i_s_info),
2235 
2236 	/* plugin name */
2237 	/* const char* */
2238 	STRUCT_FLD(name, "INNODB_CMPMEM"),
2239 
2240 	/* plugin author (for SHOW PLUGINS) */
2241 	/* const char* */
2242 	STRUCT_FLD(author, plugin_author),
2243 
2244 	/* general descriptive text (for SHOW PLUGINS) */
2245 	/* const char* */
2246 	STRUCT_FLD(descr, "Statistics for the InnoDB compressed buffer pool"),
2247 
2248 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2249 	/* int */
2250 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
2251 
2252 	/* the function to invoke when plugin is loaded */
2253 	/* int (*)(void*); */
2254 	STRUCT_FLD(init, i_s_cmpmem_init),
2255 
2256 	/* the function to invoke when plugin is unloaded */
2257 	/* int (*)(void*); */
2258 	STRUCT_FLD(deinit, i_s_common_deinit),
2259 
2260 	/* plugin version (for SHOW PLUGINS) */
2261 	/* unsigned int */
2262 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
2263 
2264 	/* struct st_mysql_show_var* */
2265 	STRUCT_FLD(status_vars, NULL),
2266 
2267 	/* struct st_mysql_sys_var** */
2268 	STRUCT_FLD(system_vars, NULL),
2269 
2270 	/* reserved for dependency checking */
2271 	/* void* */
2272 	STRUCT_FLD(__reserved1, NULL),
2273 
2274 	/* Plugin flags */
2275 	/* unsigned long */
2276 	STRUCT_FLD(flags, 0UL),
2277 };
2278 
2279 struct st_mysql_plugin	i_s_innodb_cmpmem_reset =
2280 {
2281 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2282 	/* int */
2283 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
2284 
2285 	/* pointer to type-specific plugin descriptor */
2286 	/* void* */
2287 	STRUCT_FLD(info, &i_s_info),
2288 
2289 	/* plugin name */
2290 	/* const char* */
2291 	STRUCT_FLD(name, "INNODB_CMPMEM_RESET"),
2292 
2293 	/* plugin author (for SHOW PLUGINS) */
2294 	/* const char* */
2295 	STRUCT_FLD(author, plugin_author),
2296 
2297 	/* general descriptive text (for SHOW PLUGINS) */
2298 	/* const char* */
2299 	STRUCT_FLD(descr, "Statistics for the InnoDB compressed buffer pool;"
2300 		   " reset cumulated counts"),
2301 
2302 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2303 	/* int */
2304 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
2305 
2306 	/* the function to invoke when plugin is loaded */
2307 	/* int (*)(void*); */
2308 	STRUCT_FLD(init, i_s_cmpmem_reset_init),
2309 
2310 	/* the function to invoke when plugin is unloaded */
2311 	/* int (*)(void*); */
2312 	STRUCT_FLD(deinit, i_s_common_deinit),
2313 
2314 	/* plugin version (for SHOW PLUGINS) */
2315 	/* unsigned int */
2316 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
2317 
2318 	/* struct st_mysql_show_var* */
2319 	STRUCT_FLD(status_vars, NULL),
2320 
2321 	/* struct st_mysql_sys_var** */
2322 	STRUCT_FLD(system_vars, NULL),
2323 
2324 	/* reserved for dependency checking */
2325 	/* void* */
2326 	STRUCT_FLD(__reserved1, NULL),
2327 
2328 	/* Plugin flags */
2329 	/* unsigned long */
2330 	STRUCT_FLD(flags, 0UL),
2331 };
2332 
2333 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_metrics */
2334 static ST_FIELD_INFO	innodb_metrics_fields_info[] =
2335 {
2336 #define	METRIC_NAME		0
2337 	{STRUCT_FLD(field_name,		"NAME"),
2338 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
2339 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
2340 	 STRUCT_FLD(value,		0),
2341 	 STRUCT_FLD(field_flags,	0),
2342 	 STRUCT_FLD(old_name,		""),
2343 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2344 
2345 #define	METRIC_SUBSYS		1
2346 	{STRUCT_FLD(field_name,		"SUBSYSTEM"),
2347 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
2348 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
2349 	 STRUCT_FLD(value,		0),
2350 	 STRUCT_FLD(field_flags,	0),
2351 	 STRUCT_FLD(old_name,		""),
2352 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2353 
2354 #define	METRIC_VALUE_START	2
2355 	{STRUCT_FLD(field_name,		"COUNT"),
2356 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2357 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2358 	 STRUCT_FLD(value,		0),
2359 	 STRUCT_FLD(field_flags,	0),
2360 	 STRUCT_FLD(old_name,		""),
2361 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2362 
2363 #define	METRIC_MAX_VALUE_START	3
2364 	{STRUCT_FLD(field_name,		"MAX_COUNT"),
2365 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2366 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2367 	 STRUCT_FLD(value,		0),
2368 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2369 	 STRUCT_FLD(old_name,		""),
2370 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2371 
2372 #define	METRIC_MIN_VALUE_START	4
2373 	{STRUCT_FLD(field_name,		"MIN_COUNT"),
2374 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2375 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2376 	 STRUCT_FLD(value,		0),
2377 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2378 	 STRUCT_FLD(old_name,		""),
2379 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2380 
2381 #define	METRIC_AVG_VALUE_START	5
2382 	{STRUCT_FLD(field_name,		"AVG_COUNT"),
2383 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
2384 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
2385 	 STRUCT_FLD(value,		0),
2386 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2387 	 STRUCT_FLD(old_name,		""),
2388 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2389 
2390 #define	METRIC_VALUE_RESET	6
2391 	{STRUCT_FLD(field_name,		"COUNT_RESET"),
2392 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2393 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2394 	 STRUCT_FLD(value,		0),
2395 	 STRUCT_FLD(field_flags,	0),
2396 	 STRUCT_FLD(old_name,		""),
2397 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2398 
2399 #define	METRIC_MAX_VALUE_RESET	7
2400 	{STRUCT_FLD(field_name,		"MAX_COUNT_RESET"),
2401 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2402 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2403 	 STRUCT_FLD(value,		0),
2404 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2405 	 STRUCT_FLD(old_name,		""),
2406 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2407 
2408 #define	METRIC_MIN_VALUE_RESET	8
2409 	{STRUCT_FLD(field_name,		"MIN_COUNT_RESET"),
2410 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2411 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2412 	 STRUCT_FLD(value,		0),
2413 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2414 	 STRUCT_FLD(old_name,		""),
2415 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2416 
2417 #define	METRIC_AVG_VALUE_RESET	9
2418 	{STRUCT_FLD(field_name,		"AVG_COUNT_RESET"),
2419 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
2420 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
2421 	 STRUCT_FLD(value,		0),
2422 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2423 	 STRUCT_FLD(old_name,		""),
2424 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2425 
2426 #define	METRIC_START_TIME	10
2427 	{STRUCT_FLD(field_name,		"TIME_ENABLED"),
2428 	 STRUCT_FLD(field_length,	0),
2429 	 STRUCT_FLD(field_type,		MYSQL_TYPE_DATETIME),
2430 	 STRUCT_FLD(value,		0),
2431 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2432 	 STRUCT_FLD(old_name,		""),
2433 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2434 
2435 #define	METRIC_STOP_TIME	11
2436 	{STRUCT_FLD(field_name,		"TIME_DISABLED"),
2437 	 STRUCT_FLD(field_length,	0),
2438 	 STRUCT_FLD(field_type,		MYSQL_TYPE_DATETIME),
2439 	 STRUCT_FLD(value,		0),
2440 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2441 	 STRUCT_FLD(old_name,		""),
2442 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2443 
2444 #define	METRIC_TIME_ELAPSED	12
2445 	{STRUCT_FLD(field_name,		"TIME_ELAPSED"),
2446 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2447 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2448 	 STRUCT_FLD(value,		0),
2449 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2450 	 STRUCT_FLD(old_name,		""),
2451 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2452 
2453 #define	METRIC_RESET_TIME	13
2454 	{STRUCT_FLD(field_name,		"TIME_RESET"),
2455 	 STRUCT_FLD(field_length,	0),
2456 	 STRUCT_FLD(field_type,		MYSQL_TYPE_DATETIME),
2457 	 STRUCT_FLD(value,		0),
2458 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
2459 	 STRUCT_FLD(old_name,		""),
2460 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2461 
2462 #define	METRIC_STATUS		14
2463 	{STRUCT_FLD(field_name,		"STATUS"),
2464 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
2465 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
2466 	 STRUCT_FLD(value,		0),
2467 	 STRUCT_FLD(field_flags,	0),
2468 	 STRUCT_FLD(old_name,		""),
2469 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2470 
2471 #define	METRIC_TYPE		15
2472 	{STRUCT_FLD(field_name,		"TYPE"),
2473 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
2474 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
2475 	 STRUCT_FLD(value,		0),
2476 	 STRUCT_FLD(field_flags,	0),
2477 	 STRUCT_FLD(old_name,		""),
2478 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2479 
2480 #define	METRIC_DESC		16
2481 	{STRUCT_FLD(field_name,		"COMMENT"),
2482 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
2483 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
2484 	 STRUCT_FLD(value,		0),
2485 	 STRUCT_FLD(field_flags,	0),
2486 	 STRUCT_FLD(old_name,		""),
2487 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2488 
2489 	END_OF_ST_FIELD_INFO
2490 };
2491 
2492 /**********************************************************************//**
2493 Fill the information schema metrics table.
2494 @return 0 on success */
2495 static
2496 int
i_s_metrics_fill(THD * thd,TABLE * table_to_fill)2497 i_s_metrics_fill(
2498 /*=============*/
2499 	THD*		thd,		/*!< in: thread */
2500 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
2501 {
2502 	int		count;
2503 	Field**		fields;
2504 	double		time_diff = 0;
2505 	monitor_info_t*	monitor_info;
2506 	mon_type_t	min_val;
2507 	mon_type_t	max_val;
2508 
2509 	DBUG_ENTER("i_s_metrics_fill");
2510 	fields = table_to_fill->field;
2511 
2512 	for (count = 0; count < NUM_MONITOR; count++) {
2513 		monitor_info = srv_mon_get_info((monitor_id_t) count);
2514 
2515 		/* A good place to sanity check the Monitor ID */
2516 		ut_a(count == monitor_info->monitor_id);
2517 
2518 		/* If the item refers to a Module, nothing to fill,
2519 		continue. */
2520 		if ((monitor_info->monitor_type & MONITOR_MODULE)
2521 		    || (monitor_info->monitor_type & MONITOR_HIDDEN)) {
2522 			continue;
2523 		}
2524 
2525 		/* If this is an existing "status variable", and
2526 		its corresponding counter is still on, we need
2527 		to calculate the result from its corresponding
2528 		counter. */
2529 		if (monitor_info->monitor_type & MONITOR_EXISTING
2530 		    && MONITOR_IS_ON(count)) {
2531 			srv_mon_process_existing_counter((monitor_id_t) count,
2532 							 MONITOR_GET_VALUE);
2533 		}
2534 
2535 		/* Fill in counter's basic information */
2536 		OK(field_store_string(fields[METRIC_NAME],
2537 				      monitor_info->monitor_name));
2538 
2539 		OK(field_store_string(fields[METRIC_SUBSYS],
2540 				      monitor_info->monitor_module));
2541 
2542 		OK(field_store_string(fields[METRIC_DESC],
2543 				      monitor_info->monitor_desc));
2544 
2545 		/* Fill in counter values */
2546 		OK(fields[METRIC_VALUE_RESET]->store(
2547 			MONITOR_VALUE(count), FALSE));
2548 
2549 		OK(fields[METRIC_VALUE_START]->store(
2550 			MONITOR_VALUE_SINCE_START(count), FALSE));
2551 
2552 		/* If the max value is MAX_RESERVED, counter max
2553 		value has not been updated. Set the column value
2554 		to NULL. */
2555 		if (MONITOR_MAX_VALUE(count) == MAX_RESERVED
2556 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2557 			fields[METRIC_MAX_VALUE_RESET]->set_null();
2558 		} else {
2559 			OK(fields[METRIC_MAX_VALUE_RESET]->store(
2560 				MONITOR_MAX_VALUE(count), FALSE));
2561 			fields[METRIC_MAX_VALUE_RESET]->set_notnull();
2562 		}
2563 
2564 		/* If the min value is MAX_RESERVED, counter min
2565 		value has not been updated. Set the column value
2566 		to NULL. */
2567 		if (MONITOR_MIN_VALUE(count) == MIN_RESERVED
2568 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2569 			fields[METRIC_MIN_VALUE_RESET]->set_null();
2570 		} else {
2571 			OK(fields[METRIC_MIN_VALUE_RESET]->store(
2572 				MONITOR_MIN_VALUE(count), FALSE));
2573 			fields[METRIC_MIN_VALUE_RESET]->set_notnull();
2574 		}
2575 
2576 		/* Calculate the max value since counter started */
2577 		max_val = srv_mon_calc_max_since_start((monitor_id_t) count);
2578 
2579 		if (max_val == MAX_RESERVED
2580 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2581 			fields[METRIC_MAX_VALUE_START]->set_null();
2582 		} else {
2583 			OK(fields[METRIC_MAX_VALUE_START]->store(
2584 				max_val, FALSE));
2585 			fields[METRIC_MAX_VALUE_START]->set_notnull();
2586 		}
2587 
2588 		/* Calculate the min value since counter started */
2589 		min_val = srv_mon_calc_min_since_start((monitor_id_t) count);
2590 
2591 		if (min_val == MIN_RESERVED
2592 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2593 			fields[METRIC_MIN_VALUE_START]->set_null();
2594 		} else {
2595 			OK(fields[METRIC_MIN_VALUE_START]->store(
2596 				min_val, FALSE));
2597 
2598 			fields[METRIC_MIN_VALUE_START]->set_notnull();
2599 		}
2600 
2601 		/* If monitor has been enabled (no matter it is disabled
2602 		or not now), fill METRIC_START_TIME and METRIC_TIME_ELAPSED
2603 		field */
2604 		if (MONITOR_FIELD(count, mon_start_time)) {
2605 			OK(field_store_time_t(fields[METRIC_START_TIME],
2606 				(time_t)MONITOR_FIELD(count, mon_start_time)));
2607 			fields[METRIC_START_TIME]->set_notnull();
2608 
2609 			/* If monitor is enabled, the TIME_ELAPSED is the
2610 			time difference between current and time when monitor
2611 			is enabled. Otherwise, it is the time difference
2612 			between time when monitor is enabled and time
2613 			when it is disabled */
2614 			if (MONITOR_IS_ON(count)) {
2615 				time_diff = difftime(time(NULL),
2616 					MONITOR_FIELD(count, mon_start_time));
2617 			} else {
2618 				time_diff =  difftime(
2619 					MONITOR_FIELD(count, mon_stop_time),
2620 					MONITOR_FIELD(count, mon_start_time));
2621 			}
2622 
2623 			OK(fields[METRIC_TIME_ELAPSED]->store(
2624 				time_diff));
2625 			fields[METRIC_TIME_ELAPSED]->set_notnull();
2626 		} else {
2627 			fields[METRIC_START_TIME]->set_null();
2628 			fields[METRIC_TIME_ELAPSED]->set_null();
2629 			time_diff = 0;
2630 		}
2631 
2632 		/* Unless MONITOR_NO_AVERAGE is marked, we will need
2633 		to calculate the average value. If this is a monitor set
2634 		owner marked by MONITOR_SET_OWNER, divide
2635 		the value by another counter (number of calls) designated
2636 		by monitor_info->monitor_related_id.
2637 		Otherwise average the counter value by the time between the
2638 		time that the counter is enabled and time it is disabled
2639 		or time it is sampled. */
2640 		if (!(monitor_info->monitor_type & MONITOR_NO_AVERAGE)
2641 		    && (monitor_info->monitor_type & MONITOR_SET_OWNER)
2642 		    && monitor_info->monitor_related_id) {
2643 			mon_type_t	value_start
2644 				 = MONITOR_VALUE_SINCE_START(
2645 					monitor_info->monitor_related_id);
2646 
2647 			if (value_start) {
2648 				OK(fields[METRIC_AVG_VALUE_START]->store(
2649 					MONITOR_VALUE_SINCE_START(count)
2650 					/ value_start, FALSE));
2651 
2652 				fields[METRIC_AVG_VALUE_START]->set_notnull();
2653 			} else {
2654 				fields[METRIC_AVG_VALUE_START]->set_null();
2655 			}
2656 
2657 			if (MONITOR_VALUE(monitor_info->monitor_related_id)) {
2658 				OK(fields[METRIC_AVG_VALUE_RESET]->store(
2659 					MONITOR_VALUE(count)
2660 					/ MONITOR_VALUE(
2661 					monitor_info->monitor_related_id),
2662 					FALSE));
2663 				fields[METRIC_AVG_VALUE_RESET]->set_notnull();
2664 			} else {
2665 				fields[METRIC_AVG_VALUE_RESET]->set_null();
2666 			}
2667 		} else if (!(monitor_info->monitor_type & MONITOR_NO_AVERAGE)
2668 			   && !(monitor_info->monitor_type
2669 				& MONITOR_DISPLAY_CURRENT)) {
2670 			if (time_diff) {
2671 				OK(fields[METRIC_AVG_VALUE_START]->store(
2672 					(double) MONITOR_VALUE_SINCE_START(
2673 						count) / time_diff));
2674 				fields[METRIC_AVG_VALUE_START]->set_notnull();
2675 			} else {
2676 				fields[METRIC_AVG_VALUE_START]->set_null();
2677 			}
2678 
2679 			if (MONITOR_FIELD(count, mon_reset_time)) {
2680 				/* calculate the time difference since last
2681 				reset */
2682 				if (MONITOR_IS_ON(count)) {
2683 					time_diff = difftime(
2684 						time(NULL), MONITOR_FIELD(
2685 							count, mon_reset_time));
2686 				} else {
2687 					time_diff =  difftime(
2688 					MONITOR_FIELD(count, mon_stop_time),
2689 					MONITOR_FIELD(count, mon_reset_time));
2690 				}
2691 			} else {
2692 				time_diff = 0;
2693 			}
2694 
2695 			if (time_diff) {
2696 				OK(fields[METRIC_AVG_VALUE_RESET]->store(
2697 					static_cast<double>(
2698 						MONITOR_VALUE(count) / time_diff)));
2699 				fields[METRIC_AVG_VALUE_RESET]->set_notnull();
2700 			} else {
2701 				fields[METRIC_AVG_VALUE_RESET]->set_null();
2702 			}
2703 		} else {
2704 			fields[METRIC_AVG_VALUE_START]->set_null();
2705 			fields[METRIC_AVG_VALUE_RESET]->set_null();
2706 		}
2707 
2708 
2709 		if (MONITOR_IS_ON(count)) {
2710 			/* If monitor is on, the stop time will set to NULL */
2711 			fields[METRIC_STOP_TIME]->set_null();
2712 
2713 			/* Display latest Monitor Reset Time only if Monitor
2714 			counter is on. */
2715 			if (MONITOR_FIELD(count, mon_reset_time)) {
2716 				OK(field_store_time_t(
2717 					fields[METRIC_RESET_TIME],
2718 					(time_t)MONITOR_FIELD(
2719 						count, mon_reset_time)));
2720 				fields[METRIC_RESET_TIME]->set_notnull();
2721 			} else {
2722 				fields[METRIC_RESET_TIME]->set_null();
2723 			}
2724 
2725 			/* Display the monitor status as "enabled" */
2726 			OK(field_store_string(fields[METRIC_STATUS],
2727 					      "enabled"));
2728 		} else {
2729 			if (MONITOR_FIELD(count, mon_stop_time)) {
2730 				OK(field_store_time_t(fields[METRIC_STOP_TIME],
2731 				(time_t)MONITOR_FIELD(count, mon_stop_time)));
2732 				fields[METRIC_STOP_TIME]->set_notnull();
2733 			} else {
2734 				fields[METRIC_STOP_TIME]->set_null();
2735 			}
2736 
2737 			fields[METRIC_RESET_TIME]->set_null();
2738 
2739 			OK(field_store_string(fields[METRIC_STATUS],
2740 					      "disabled"));
2741 		}
2742 
2743 		if (monitor_info->monitor_type & MONITOR_DISPLAY_CURRENT) {
2744 			OK(field_store_string(fields[METRIC_TYPE],
2745 					      "value"));
2746 		} else if (monitor_info->monitor_type & MONITOR_EXISTING) {
2747 			OK(field_store_string(fields[METRIC_TYPE],
2748 					      "status_counter"));
2749 		} else if (monitor_info->monitor_type & MONITOR_SET_OWNER) {
2750 			OK(field_store_string(fields[METRIC_TYPE],
2751 					      "set_owner"));
2752 		} else if ( monitor_info->monitor_type & MONITOR_SET_MEMBER) {
2753 			OK(field_store_string(fields[METRIC_TYPE],
2754 					      "set_member"));
2755 		} else {
2756 			OK(field_store_string(fields[METRIC_TYPE],
2757 					      "counter"));
2758 		}
2759 
2760 		OK(schema_table_store_record(thd, table_to_fill));
2761 	}
2762 
2763 	DBUG_RETURN(0);
2764 }
2765 
2766 /*******************************************************************//**
2767 Function to fill information schema metrics tables.
2768 @return 0 on success */
2769 static
2770 int
i_s_metrics_fill_table(THD * thd,TABLE_LIST * tables,Item *)2771 i_s_metrics_fill_table(
2772 /*===================*/
2773 	THD*		thd,	/*!< in: thread */
2774 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2775 	Item*		)	/*!< in: condition (not used) */
2776 {
2777 	DBUG_ENTER("i_s_metrics_fill_table");
2778 
2779 	/* deny access to non-superusers */
2780 	if (check_global_access(thd, PROCESS_ACL)) {
2781 		DBUG_RETURN(0);
2782 	}
2783 
2784 	i_s_metrics_fill(thd, tables->table);
2785 
2786 	DBUG_RETURN(0);
2787 }
2788 /*******************************************************************//**
2789 Bind the dynamic table INFORMATION_SCHEMA.innodb_metrics
2790 @return 0 on success */
2791 static
2792 int
innodb_metrics_init(void * p)2793 innodb_metrics_init(
2794 /*================*/
2795 	void*	p)	/*!< in/out: table schema object */
2796 {
2797 	ST_SCHEMA_TABLE*	schema;
2798 
2799 	DBUG_ENTER("innodb_metrics_init");
2800 
2801 	schema = (ST_SCHEMA_TABLE*) p;
2802 
2803 	schema->fields_info = innodb_metrics_fields_info;
2804 	schema->fill_table = i_s_metrics_fill_table;
2805 
2806 	DBUG_RETURN(0);
2807 }
2808 
2809 struct st_mysql_plugin	i_s_innodb_metrics =
2810 {
2811 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2812 	/* int */
2813 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
2814 
2815 	/* pointer to type-specific plugin descriptor */
2816 	/* void* */
2817 	STRUCT_FLD(info, &i_s_info),
2818 
2819 	/* plugin name */
2820 	/* const char* */
2821 	STRUCT_FLD(name, "INNODB_METRICS"),
2822 
2823 	/* plugin author (for SHOW PLUGINS) */
2824 	/* const char* */
2825 	STRUCT_FLD(author, plugin_author),
2826 
2827 	/* general descriptive text (for SHOW PLUGINS) */
2828 	/* const char* */
2829 	STRUCT_FLD(descr, "InnoDB Metrics Info"),
2830 
2831 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2832 	/* int */
2833 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
2834 
2835 	/* the function to invoke when plugin is loaded */
2836 	/* int (*)(void*); */
2837 	STRUCT_FLD(init, innodb_metrics_init),
2838 
2839 	/* the function to invoke when plugin is unloaded */
2840 	/* int (*)(void*); */
2841 	STRUCT_FLD(deinit, i_s_common_deinit),
2842 
2843 	/* plugin version (for SHOW PLUGINS) */
2844 	/* unsigned int */
2845 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
2846 
2847 	/* struct st_mysql_show_var* */
2848 	STRUCT_FLD(status_vars, NULL),
2849 
2850 	/* struct st_mysql_sys_var** */
2851 	STRUCT_FLD(system_vars, NULL),
2852 
2853 	/* reserved for dependency checking */
2854 	/* void* */
2855 	STRUCT_FLD(__reserved1, NULL),
2856 
2857 	/* Plugin flags */
2858 	/* unsigned long */
2859 	STRUCT_FLD(flags, 0UL),
2860 };
2861 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_ft_default_stopword */
2862 static ST_FIELD_INFO	i_s_stopword_fields_info[] =
2863 {
2864 #define STOPWORD_VALUE	0
2865 	{STRUCT_FLD(field_name,		"value"),
2866 	 STRUCT_FLD(field_length,	TRX_ID_MAX_LEN + 1),
2867 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
2868 	 STRUCT_FLD(value,		0),
2869 	 STRUCT_FLD(field_flags,	0),
2870 	 STRUCT_FLD(old_name,		""),
2871 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2872 
2873 	END_OF_ST_FIELD_INFO
2874 };
2875 
2876 /*******************************************************************//**
2877 Fill the dynamic table information_schema.innodb_ft_default_stopword.
2878 @return 0 on success, 1 on failure */
2879 static
2880 int
i_s_stopword_fill(THD * thd,TABLE_LIST * tables,Item *)2881 i_s_stopword_fill(
2882 /*==============*/
2883 	THD*		thd,	/*!< in: thread */
2884 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2885 	Item*		)	/*!< in: condition (not used) */
2886 {
2887 	Field**	fields;
2888 	ulint	i = 0;
2889 	TABLE*	table = (TABLE*) tables->table;
2890 
2891 	DBUG_ENTER("i_s_stopword_fill");
2892 
2893 	fields = table->field;
2894 
2895 	/* Fill with server default stopword list in array
2896 	fts_default_stopword */
2897 	while (fts_default_stopword[i]) {
2898 		OK(field_store_string(fields[STOPWORD_VALUE],
2899 				      fts_default_stopword[i]));
2900 
2901 		OK(schema_table_store_record(thd, table));
2902 		i++;
2903 	}
2904 
2905 	DBUG_RETURN(0);
2906 }
2907 
2908 /*******************************************************************//**
2909 Bind the dynamic table information_schema.innodb_ft_default_stopword.
2910 @return 0 on success */
2911 static
2912 int
i_s_stopword_init(void * p)2913 i_s_stopword_init(
2914 /*==============*/
2915 	void*	p)	/*!< in/out: table schema object */
2916 {
2917 	DBUG_ENTER("i_s_stopword_init");
2918 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2919 
2920 	schema->fields_info = i_s_stopword_fields_info;
2921 	schema->fill_table = i_s_stopword_fill;
2922 
2923 	DBUG_RETURN(0);
2924 }
2925 
2926 struct st_mysql_plugin	i_s_innodb_ft_default_stopword =
2927 {
2928 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2929 	/* int */
2930 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
2931 
2932 	/* pointer to type-specific plugin descriptor */
2933 	/* void* */
2934 	STRUCT_FLD(info, &i_s_info),
2935 
2936 	/* plugin name */
2937 	/* const char* */
2938 	STRUCT_FLD(name, "INNODB_FT_DEFAULT_STOPWORD"),
2939 
2940 	/* plugin author (for SHOW PLUGINS) */
2941 	/* const char* */
2942 	STRUCT_FLD(author, plugin_author),
2943 
2944 	/* general descriptive text (for SHOW PLUGINS) */
2945 	/* const char* */
2946 	STRUCT_FLD(descr, "Default stopword list for InnDB Full Text Search"),
2947 
2948 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2949 	/* int */
2950 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
2951 
2952 	/* the function to invoke when plugin is loaded */
2953 	/* int (*)(void*); */
2954 	STRUCT_FLD(init, i_s_stopword_init),
2955 
2956 	/* the function to invoke when plugin is unloaded */
2957 	/* int (*)(void*); */
2958 	STRUCT_FLD(deinit, i_s_common_deinit),
2959 
2960 	/* plugin version (for SHOW PLUGINS) */
2961 	/* unsigned int */
2962 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
2963 
2964 	/* struct st_mysql_show_var* */
2965 	STRUCT_FLD(status_vars, NULL),
2966 
2967 	/* struct st_mysql_sys_var** */
2968 	STRUCT_FLD(system_vars, NULL),
2969 
2970 	/* reserved for dependency checking */
2971 	/* void* */
2972 	STRUCT_FLD(__reserved1, NULL),
2973 
2974 	/* Plugin flags */
2975 	/* unsigned long */
2976 	STRUCT_FLD(flags, 0UL),
2977 };
2978 
2979 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2980 INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED */
2981 static ST_FIELD_INFO	i_s_fts_doc_fields_info[] =
2982 {
2983 #define	I_S_FTS_DOC_ID			0
2984 	{STRUCT_FLD(field_name,		"DOC_ID"),
2985 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
2986 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
2987 	 STRUCT_FLD(value,		0),
2988 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
2989 	 STRUCT_FLD(old_name,		""),
2990 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
2991 
2992 	END_OF_ST_FIELD_INFO
2993 };
2994 
2995 /*******************************************************************//**
2996 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED or
2997 INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2998 @return 0 on success, 1 on failure */
2999 static
3000 int
i_s_fts_deleted_generic_fill(THD * thd,TABLE_LIST * tables,ibool being_deleted)3001 i_s_fts_deleted_generic_fill(
3002 /*=========================*/
3003 	THD*		thd,		/*!< in: thread */
3004 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
3005 	ibool		being_deleted)	/*!< in: BEING_DELTED table */
3006 {
3007 	Field**			fields;
3008 	TABLE*			table = (TABLE*) tables->table;
3009 	trx_t*			trx;
3010 	fts_table_t		fts_table;
3011 	fts_doc_ids_t*		deleted;
3012 	dict_table_t*		user_table;
3013 
3014 	DBUG_ENTER("i_s_fts_deleted_generic_fill");
3015 
3016 	/* deny access to non-superusers */
3017 	if (check_global_access(thd, PROCESS_ACL)) {
3018 		DBUG_RETURN(0);
3019 	}
3020 
3021 	mysql_mutex_lock(&LOCK_global_system_variables);
3022 
3023 	if (!fts_internal_tbl_name) {
3024 		mysql_mutex_unlock(&LOCK_global_system_variables);
3025 		DBUG_RETURN(0);
3026 	}
3027 
3028 	std::string fts_table_name(fts_internal_tbl_name);
3029 	mysql_mutex_unlock(&LOCK_global_system_variables);
3030 
3031 	if(!fts_table_name.c_str()) {
3032 		DBUG_RETURN(0);
3033 	}
3034 
3035 	/* Prevent DDL to drop fts aux tables. */
3036 	rw_lock_s_lock(dict_operation_lock);
3037 
3038 	user_table = dict_table_open_on_name(
3039 				fts_table_name.c_str(),
3040 				FALSE, FALSE, DICT_ERR_IGNORE_NONE);
3041 
3042 	if (!user_table) {
3043 		rw_lock_s_unlock(dict_operation_lock);
3044 
3045 		DBUG_RETURN(0);
3046 	} else if (!dict_table_has_fts_index(user_table)) {
3047 		dict_table_close(user_table, FALSE, FALSE);
3048 
3049 		rw_lock_s_unlock(dict_operation_lock);
3050 
3051 		DBUG_RETURN(0);
3052 	}
3053 
3054 	deleted = fts_doc_ids_create();
3055 
3056 	trx = trx_allocate_for_background();
3057 	trx->op_info = "Select for FTS DELETE TABLE";
3058 
3059 	FTS_INIT_FTS_TABLE(&fts_table,
3060 			   (being_deleted) ? "BEING_DELETED" : "DELETED",
3061 			   FTS_COMMON_TABLE, user_table);
3062 
3063 	fts_table_fetch_doc_ids(trx, &fts_table, deleted);
3064 
3065 	fields = table->field;
3066 
3067 	for (ulint j = 0; j < ib_vector_size(deleted->doc_ids); ++j) {
3068 		doc_id_t	doc_id;
3069 
3070 		doc_id = *(doc_id_t*) ib_vector_get_const(deleted->doc_ids, j);
3071 
3072 		OK(fields[I_S_FTS_DOC_ID]->store(doc_id, true));
3073 
3074 		OK(schema_table_store_record(thd, table));
3075 	}
3076 
3077 	trx_free_for_background(trx);
3078 
3079 	fts_doc_ids_free(deleted);
3080 
3081 	dict_table_close(user_table, FALSE, FALSE);
3082 
3083 	rw_lock_s_unlock(dict_operation_lock);
3084 
3085 	DBUG_RETURN(0);
3086 }
3087 
3088 /*******************************************************************//**
3089 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
3090 @return 0 on success, 1 on failure */
3091 static
3092 int
i_s_fts_deleted_fill(THD * thd,TABLE_LIST * tables,Item *)3093 i_s_fts_deleted_fill(
3094 /*=================*/
3095 	THD*		thd,	/*!< in: thread */
3096 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
3097 	Item*		)	/*!< in: condition (ignored) */
3098 {
3099 	DBUG_ENTER("i_s_fts_deleted_fill");
3100 
3101 	DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, FALSE));
3102 }
3103 
3104 /*******************************************************************//**
3105 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
3106 @return 0 on success */
3107 static
3108 int
i_s_fts_deleted_init(void * p)3109 i_s_fts_deleted_init(
3110 /*=================*/
3111 	void*	p)	/*!< in/out: table schema object */
3112 {
3113 	DBUG_ENTER("i_s_fts_deleted_init");
3114 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
3115 
3116 	schema->fields_info = i_s_fts_doc_fields_info;
3117 	schema->fill_table = i_s_fts_deleted_fill;
3118 
3119 	DBUG_RETURN(0);
3120 }
3121 
3122 struct st_mysql_plugin	i_s_innodb_ft_deleted =
3123 {
3124 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3125 	/* int */
3126 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
3127 
3128 	/* pointer to type-specific plugin descriptor */
3129 	/* void* */
3130 	STRUCT_FLD(info, &i_s_info),
3131 
3132 	/* plugin name */
3133 	/* const char* */
3134 	STRUCT_FLD(name, "INNODB_FT_DELETED"),
3135 
3136 	/* plugin author (for SHOW PLUGINS) */
3137 	/* const char* */
3138 	STRUCT_FLD(author, plugin_author),
3139 
3140 	/* general descriptive text (for SHOW PLUGINS) */
3141 	/* const char* */
3142 	STRUCT_FLD(descr, "INNODB AUXILIARY FTS DELETED TABLE"),
3143 
3144 	/* the plugin license (PLUGIN_LICENSE_XXX) */
3145 	/* int */
3146 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
3147 
3148 	/* the function to invoke when plugin is loaded */
3149 	/* int (*)(void*); */
3150 	STRUCT_FLD(init, i_s_fts_deleted_init),
3151 
3152 	/* the function to invoke when plugin is unloaded */
3153 	/* int (*)(void*); */
3154 	STRUCT_FLD(deinit, i_s_common_deinit),
3155 
3156 	/* plugin version (for SHOW PLUGINS) */
3157 	/* unsigned int */
3158 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
3159 
3160 	/* struct st_mysql_show_var* */
3161 	STRUCT_FLD(status_vars, NULL),
3162 
3163 	/* struct st_mysql_sys_var** */
3164 	STRUCT_FLD(system_vars, NULL),
3165 
3166 	/* reserved for dependency checking */
3167 	/* void* */
3168 	STRUCT_FLD(__reserved1, NULL),
3169 
3170 	/* Plugin flags */
3171 	/* unsigned long */
3172 	STRUCT_FLD(flags, 0UL),
3173 };
3174 
3175 /*******************************************************************//**
3176 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
3177 @return 0 on success, 1 on failure */
3178 static
3179 int
i_s_fts_being_deleted_fill(THD * thd,TABLE_LIST * tables,Item *)3180 i_s_fts_being_deleted_fill(
3181 /*=======================*/
3182 	THD*		thd,	/*!< in: thread */
3183 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
3184 	Item*		)	/*!< in: condition (ignored) */
3185 {
3186 	DBUG_ENTER("i_s_fts_being_deleted_fill");
3187 
3188 	DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, TRUE));
3189 }
3190 
3191 /*******************************************************************//**
3192 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
3193 @return 0 on success */
3194 static
3195 int
i_s_fts_being_deleted_init(void * p)3196 i_s_fts_being_deleted_init(
3197 /*=======================*/
3198 	void*	p)	/*!< in/out: table schema object */
3199 {
3200 	DBUG_ENTER("i_s_fts_deleted_init");
3201 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
3202 
3203 	schema->fields_info = i_s_fts_doc_fields_info;
3204 	schema->fill_table = i_s_fts_being_deleted_fill;
3205 
3206 	DBUG_RETURN(0);
3207 }
3208 
3209 struct st_mysql_plugin	i_s_innodb_ft_being_deleted =
3210 {
3211 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3212 	/* int */
3213 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
3214 
3215 	/* pointer to type-specific plugin descriptor */
3216 	/* void* */
3217 	STRUCT_FLD(info, &i_s_info),
3218 
3219 	/* plugin name */
3220 	/* const char* */
3221 	STRUCT_FLD(name, "INNODB_FT_BEING_DELETED"),
3222 
3223 	/* plugin author (for SHOW PLUGINS) */
3224 	/* const char* */
3225 	STRUCT_FLD(author, plugin_author),
3226 
3227 	/* general descriptive text (for SHOW PLUGINS) */
3228 	/* const char* */
3229 	STRUCT_FLD(descr, "INNODB AUXILIARY FTS BEING DELETED TABLE"),
3230 
3231 	/* the plugin license (PLUGIN_LICENSE_XXX) */
3232 	/* int */
3233 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
3234 
3235 	/* the function to invoke when plugin is loaded */
3236 	/* int (*)(void*); */
3237 	STRUCT_FLD(init, i_s_fts_being_deleted_init),
3238 
3239 	/* the function to invoke when plugin is unloaded */
3240 	/* int (*)(void*); */
3241 	STRUCT_FLD(deinit, i_s_common_deinit),
3242 
3243 	/* plugin version (for SHOW PLUGINS) */
3244 	/* unsigned int */
3245 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
3246 
3247 	/* struct st_mysql_show_var* */
3248 	STRUCT_FLD(status_vars, NULL),
3249 
3250 	/* struct st_mysql_sys_var** */
3251 	STRUCT_FLD(system_vars, NULL),
3252 
3253 	/* reserved for dependency checking */
3254 	/* void* */
3255 	STRUCT_FLD(__reserved1, NULL),
3256 
3257 	/* Plugin flags */
3258 	/* unsigned long */
3259 	STRUCT_FLD(flags, 0UL),
3260 };
3261 
3262 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED and
3263 INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE */
3264 static ST_FIELD_INFO	i_s_fts_index_fields_info[] =
3265 {
3266 #define	I_S_FTS_WORD			0
3267 	{STRUCT_FLD(field_name,		"WORD"),
3268 	 STRUCT_FLD(field_length,	FTS_MAX_WORD_LEN + 1),
3269 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
3270 	 STRUCT_FLD(value,		0),
3271 	 STRUCT_FLD(field_flags,	0),
3272 	 STRUCT_FLD(old_name,		""),
3273 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
3274 
3275 #define	I_S_FTS_FIRST_DOC_ID		1
3276 	{STRUCT_FLD(field_name,		"FIRST_DOC_ID"),
3277 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
3278 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
3279 	 STRUCT_FLD(value,		0),
3280 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
3281 	 STRUCT_FLD(old_name,		""),
3282 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
3283 
3284 #define	I_S_FTS_LAST_DOC_ID		2
3285 	{STRUCT_FLD(field_name,		"LAST_DOC_ID"),
3286 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
3287 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
3288 	 STRUCT_FLD(value,		0),
3289 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
3290 	 STRUCT_FLD(old_name,		""),
3291 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
3292 
3293 #define	I_S_FTS_DOC_COUNT		3
3294 	{STRUCT_FLD(field_name,		"DOC_COUNT"),
3295 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
3296 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
3297 	 STRUCT_FLD(value,		0),
3298 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
3299 	 STRUCT_FLD(old_name,		""),
3300 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
3301 
3302 #define	I_S_FTS_ILIST_DOC_ID		4
3303 	{STRUCT_FLD(field_name,		"DOC_ID"),
3304 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
3305 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
3306 	 STRUCT_FLD(value,		0),
3307 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
3308 	 STRUCT_FLD(old_name,		""),
3309 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
3310 
3311 #define	I_S_FTS_ILIST_DOC_POS		5
3312 	{STRUCT_FLD(field_name,		"POSITION"),
3313 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
3314 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
3315 	 STRUCT_FLD(value,		0),
3316 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
3317 	 STRUCT_FLD(old_name,		""),
3318 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
3319 
3320 	END_OF_ST_FIELD_INFO
3321 };
3322 
3323 /*******************************************************************//**
3324 Go through the Doc Node and its ilist, fill the dynamic table
3325 INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED for one FTS index on the table.
3326 @return 0 on success, 1 on failure */
3327 static
3328 int
i_s_fts_index_cache_fill_one_index(fts_index_cache_t * index_cache,THD * thd,TABLE_LIST * tables)3329 i_s_fts_index_cache_fill_one_index(
3330 /*===============================*/
3331 	fts_index_cache_t*	index_cache,	/*!< in: FTS index cache */
3332 	THD*			thd,		/*!< in: thread */
3333 	TABLE_LIST*		tables)		/*!< in/out: tables to fill */
3334 {
3335 	TABLE*			table = (TABLE*) tables->table;
3336 	Field**			fields;
3337 	CHARSET_INFO*		index_charset;
3338 	const ib_rbt_node_t*	rbt_node;
3339 	fts_string_t		conv_str;
3340 	uint			dummy_errors;
3341 	char*			word_str;
3342 
3343 	DBUG_ENTER("i_s_fts_index_cache_fill_one_index");
3344 
3345 	fields = table->field;
3346 
3347 	index_charset = index_cache->charset;
3348 	conv_str.f_len = system_charset_info->mbmaxlen
3349 		* FTS_MAX_WORD_LEN_IN_CHAR;
3350 	conv_str.f_str = static_cast<byte*>(ut_malloc_nokey(conv_str.f_len));
3351 	conv_str.f_n_char = 0;
3352 
3353 	/* Go through each word in the index cache */
3354 	for (rbt_node = rbt_first(index_cache->words);
3355 	     rbt_node;
3356 	     rbt_node = rbt_next(index_cache->words, rbt_node)) {
3357 		fts_tokenizer_word_t* word;
3358 
3359 		word = rbt_value(fts_tokenizer_word_t, rbt_node);
3360 
3361 		/* Convert word from index charset to system_charset_info */
3362 		if (index_charset->cset != system_charset_info->cset) {
3363 			conv_str.f_n_char = my_convert(
3364 				reinterpret_cast<char*>(conv_str.f_str),
3365 				static_cast<uint32>(conv_str.f_len),
3366 				system_charset_info,
3367 				reinterpret_cast<char*>(word->text.f_str),
3368 				static_cast<uint32>(word->text.f_len),
3369 				index_charset, &dummy_errors);
3370 			ut_ad(conv_str.f_n_char <= conv_str.f_len);
3371 			conv_str.f_str[conv_str.f_n_char] = 0;
3372 			word_str = reinterpret_cast<char*>(conv_str.f_str);
3373 		} else {
3374 			word_str = reinterpret_cast<char*>(word->text.f_str);
3375 		}
3376 
3377 		/* Decrypt the ilist, and display Dod ID and word position */
3378 		for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
3379 			fts_node_t*	node;
3380 			byte*		ptr;
3381 			ulint		decoded = 0;
3382 			doc_id_t	doc_id = 0;
3383 
3384 			node = static_cast<fts_node_t*> (ib_vector_get(
3385 				word->nodes, i));
3386 
3387 			ptr = node->ilist;
3388 
3389 			while (decoded < node->ilist_size) {
3390 				ulint	pos = fts_decode_vlc(&ptr);
3391 
3392 				doc_id += pos;
3393 
3394 				/* Get position info */
3395 				while (*ptr) {
3396 					pos = fts_decode_vlc(&ptr);
3397 
3398 					OK(field_store_string(
3399 						   fields[I_S_FTS_WORD],
3400 						   word_str));
3401 
3402 					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
3403 						   node->first_doc_id,
3404 						   true));
3405 
3406 					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
3407 						   node->last_doc_id,
3408 						   true));
3409 
3410 					OK(fields[I_S_FTS_DOC_COUNT]->store(
3411 						   node->doc_count, true));
3412 
3413 					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
3414 						   doc_id, true));
3415 
3416 					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
3417 						   pos, true));
3418 
3419 					OK(schema_table_store_record(
3420 						   thd, table));
3421 				}
3422 
3423 				++ptr;
3424 
3425 				decoded = ptr - (byte*) node->ilist;
3426 			}
3427 		}
3428 	}
3429 
3430 	ut_free(conv_str.f_str);
3431 
3432 	DBUG_RETURN(0);
3433 }
3434 /*******************************************************************//**
3435 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED
3436 @return 0 on success, 1 on failure */
3437 static
3438 int
i_s_fts_index_cache_fill(THD * thd,TABLE_LIST * tables,Item *)3439 i_s_fts_index_cache_fill(
3440 /*=====================*/
3441 	THD*		thd,	/*!< in: thread */
3442 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
3443 	Item*		)	/*!< in: condition (ignored) */
3444 {
3445 	dict_table_t*		user_table;
3446 	fts_cache_t*		cache;
3447 
3448 	DBUG_ENTER("i_s_fts_index_cache_fill");
3449 
3450 	/* deny access to non-superusers */
3451 	if (check_global_access(thd, PROCESS_ACL)) {
3452 		DBUG_RETURN(0);
3453 	}
3454 
3455         mysql_mutex_lock(&LOCK_global_system_variables);
3456 
3457         if (!fts_internal_tbl_name) {
3458                 mysql_mutex_unlock(&LOCK_global_system_variables);
3459                 DBUG_RETURN(0);
3460         }
3461 
3462 	std::string fts_table_name(fts_internal_tbl_name);
3463 	mysql_mutex_unlock(&LOCK_global_system_variables);
3464 
3465         if(!fts_table_name.c_str()) {
3466                 DBUG_RETURN(0);
3467         }
3468 
3469 	user_table = dict_table_open_on_name(
3470 		fts_table_name.c_str(), FALSE, FALSE, DICT_ERR_IGNORE_NONE);
3471 
3472 	if (!user_table) {
3473 		DBUG_RETURN(0);
3474 	}
3475 
3476 	if (user_table->fts == NULL || user_table->fts->cache == NULL) {
3477 		dict_table_close(user_table, FALSE, FALSE);
3478 
3479 		DBUG_RETURN(0);
3480 	}
3481 
3482 	cache = user_table->fts->cache;
3483 
3484 	ut_a(cache);
3485 
3486 	/* Check if cache is being synced.
3487 	Note: we wait till cache is being synced. */
3488 	while (cache->sync->in_progress) {
3489 		os_event_wait(cache->sync->event);
3490 	}
3491 
3492 	for (ulint i = 0; i < ib_vector_size(cache->indexes); i++) {
3493 		fts_index_cache_t*      index_cache;
3494 
3495 		index_cache = static_cast<fts_index_cache_t*> (
3496 			ib_vector_get(cache->indexes, i));
3497 
3498 		i_s_fts_index_cache_fill_one_index(index_cache, thd, tables);
3499 	}
3500 
3501 	dict_table_close(user_table, FALSE, FALSE);
3502 
3503 	DBUG_RETURN(0);
3504 }
3505 
3506 /*******************************************************************//**
3507 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE
3508 @return 0 on success */
3509 static
3510 int
i_s_fts_index_cache_init(void * p)3511 i_s_fts_index_cache_init(
3512 /*=====================*/
3513 	void*	p)	/*!< in/out: table schema object */
3514 {
3515 	DBUG_ENTER("i_s_fts_index_cache_init");
3516 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
3517 
3518 	schema->fields_info = i_s_fts_index_fields_info;
3519 	schema->fill_table = i_s_fts_index_cache_fill;
3520 
3521 	DBUG_RETURN(0);
3522 }
3523 
3524 struct st_mysql_plugin	i_s_innodb_ft_index_cache =
3525 {
3526 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3527 	/* int */
3528 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
3529 
3530 	/* pointer to type-specific plugin descriptor */
3531 	/* void* */
3532 	STRUCT_FLD(info, &i_s_info),
3533 
3534 	/* plugin name */
3535 	/* const char* */
3536 	STRUCT_FLD(name, "INNODB_FT_INDEX_CACHE"),
3537 
3538 	/* plugin author (for SHOW PLUGINS) */
3539 	/* const char* */
3540 	STRUCT_FLD(author, plugin_author),
3541 
3542 	/* general descriptive text (for SHOW PLUGINS) */
3543 	/* const char* */
3544 	STRUCT_FLD(descr, "INNODB AUXILIARY FTS INDEX CACHED"),
3545 
3546 	/* the plugin license (PLUGIN_LICENSE_XXX) */
3547 	/* int */
3548 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
3549 
3550 	/* the function to invoke when plugin is loaded */
3551 	/* int (*)(void*); */
3552 	STRUCT_FLD(init, i_s_fts_index_cache_init),
3553 
3554 	/* the function to invoke when plugin is unloaded */
3555 	/* int (*)(void*); */
3556 	STRUCT_FLD(deinit, i_s_common_deinit),
3557 
3558 	/* plugin version (for SHOW PLUGINS) */
3559 	/* unsigned int */
3560 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
3561 
3562 	/* struct st_mysql_show_var* */
3563 	STRUCT_FLD(status_vars, NULL),
3564 
3565 	/* struct st_mysql_sys_var** */
3566 	STRUCT_FLD(system_vars, NULL),
3567 
3568 	/* reserved for dependency checking */
3569 	/* void* */
3570 	STRUCT_FLD(__reserved1, NULL),
3571 
3572 	/* Plugin flags */
3573 	/* unsigned long */
3574 	STRUCT_FLD(flags, 0UL),
3575 };
3576 
3577 /*******************************************************************//**
3578 Go through a FTS index auxiliary table, fetch its rows and fill
3579 FTS word cache structure.
3580 @return DB_SUCCESS on success, otherwise error code */
3581 static
3582 dberr_t
i_s_fts_index_table_fill_selected(dict_index_t * index,ib_vector_t * words,ulint selected,fts_string_t * word)3583 i_s_fts_index_table_fill_selected(
3584 /*==============================*/
3585 	dict_index_t*		index,		/*!< in: FTS index */
3586 	ib_vector_t*		words,		/*!< in/out: vector to hold
3587 						fetched words */
3588 	ulint			selected,	/*!< in: selected FTS index */
3589 	fts_string_t*		word)		/*!< in: word to select */
3590 {
3591 	pars_info_t*		info;
3592 	fts_table_t		fts_table;
3593 	trx_t*			trx;
3594 	que_t*			graph;
3595 	dberr_t			error;
3596 	fts_fetch_t		fetch;
3597 	char			table_name[MAX_FULL_NAME_LEN];
3598 
3599 	info = pars_info_create();
3600 
3601 	fetch.read_arg = words;
3602 	fetch.read_record = fts_optimize_index_fetch_node;
3603 	fetch.total_memory = 0;
3604 
3605 	DBUG_EXECUTE_IF("fts_instrument_result_cache_limit",
3606 	        fts_result_cache_limit = 8192;
3607 	);
3608 
3609 	trx = trx_allocate_for_background();
3610 
3611 	trx->op_info = "fetching FTS index nodes";
3612 
3613 	pars_info_bind_function(info, "my_func", fetch.read_record, &fetch);
3614 	pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len);
3615 
3616 	FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected),
3617 			     FTS_INDEX_TABLE, index);
3618 	fts_get_table_name(&fts_table, table_name);
3619 	pars_info_bind_id(info, true, "table_name", table_name);
3620 
3621 	graph = fts_parse_sql(
3622 		&fts_table, info,
3623 		"DECLARE FUNCTION my_func;\n"
3624 		"DECLARE CURSOR c IS"
3625 		" SELECT word, doc_count, first_doc_id, last_doc_id,"
3626 		" ilist\n"
3627 		" FROM $table_name WHERE word >= :word;\n"
3628 		"BEGIN\n"
3629 		"\n"
3630 		"OPEN c;\n"
3631 		"WHILE 1 = 1 LOOP\n"
3632 		"  FETCH c INTO my_func();\n"
3633 		"  IF c % NOTFOUND THEN\n"
3634 		"    EXIT;\n"
3635 		"  END IF;\n"
3636 		"END LOOP;\n"
3637 		"CLOSE c;");
3638 
3639 	for (;;) {
3640 		error = fts_eval_sql(trx, graph);
3641 
3642 		if (error == DB_SUCCESS) {
3643 			fts_sql_commit(trx);
3644 
3645 			break;
3646 		} else {
3647 			fts_sql_rollback(trx);
3648 
3649 			if (error == DB_LOCK_WAIT_TIMEOUT) {
3650 				ib::warn() << "Lock wait timeout reading"
3651 					" FTS index. Retrying!";
3652 
3653 				trx->error_state = DB_SUCCESS;
3654 			} else {
3655 				ib::error() << "Error occurred while reading"
3656 					" FTS index: " << ut_strerr(error);
3657 				break;
3658 			}
3659 		}
3660 	}
3661 
3662 	mutex_enter(&dict_sys->mutex);
3663 	que_graph_free(graph);
3664 	mutex_exit(&dict_sys->mutex);
3665 
3666 	trx_free_for_background(trx);
3667 
3668 	if (fetch.total_memory >= fts_result_cache_limit) {
3669 		error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT;
3670 	}
3671 
3672 	return(error);
3673 }
3674 
3675 /*******************************************************************//**
3676 Free words. */
3677 static
3678 void
i_s_fts_index_table_free_one_fetch(ib_vector_t * words)3679 i_s_fts_index_table_free_one_fetch(
3680 /*===============================*/
3681 	ib_vector_t*		words)		/*!< in: words fetched */
3682 {
3683 	for (ulint i = 0; i < ib_vector_size(words); i++) {
3684 		fts_word_t*	word;
3685 
3686 		word = static_cast<fts_word_t*>(ib_vector_get(words, i));
3687 
3688 		for (ulint j = 0; j < ib_vector_size(word->nodes); j++) {
3689 			fts_node_t*     node;
3690 
3691 			node = static_cast<fts_node_t*> (ib_vector_get(
3692 				word->nodes, j));
3693 			ut_free(node->ilist);
3694 		}
3695 
3696 		fts_word_free(word);
3697 	}
3698 
3699 	ib_vector_reset(words);
3700 }
3701 
3702 /*******************************************************************//**
3703 Go through words, fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
3704 @return	0 on success, 1 on failure */
3705 static
3706 int
i_s_fts_index_table_fill_one_fetch(CHARSET_INFO * index_charset,THD * thd,TABLE_LIST * tables,ib_vector_t * words,fts_string_t * conv_str,bool has_more)3707 i_s_fts_index_table_fill_one_fetch(
3708 /*===============================*/
3709 	CHARSET_INFO*		index_charset,	/*!< in: FTS index charset */
3710 	THD*			thd,		/*!< in: thread */
3711 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
3712 	ib_vector_t*		words,		/*!< in: words fetched */
3713 	fts_string_t*		conv_str,	/*!< in: string for conversion*/
3714 	bool			has_more)	/*!< in: has more to fetch */
3715 {
3716 	TABLE*			table = (TABLE*) tables->table;
3717 	Field**			fields;
3718 	uint			dummy_errors;
3719 	char*			word_str;
3720 	ulint			words_size;
3721 	int			ret = 0;
3722 
3723 	DBUG_ENTER("i_s_fts_index_table_fill_one_fetch");
3724 
3725 	fields = table->field;
3726 
3727 	words_size = ib_vector_size(words);
3728 	if (has_more) {
3729 		/* the last word is not fetched completely. */
3730 		ut_ad(words_size > 1);
3731 		words_size -= 1;
3732 	}
3733 
3734 	/* Go through each word in the index cache */
3735 	for (ulint i = 0; i < words_size; i++) {
3736 		fts_word_t*	word;
3737 
3738 		word = static_cast<fts_word_t*>(ib_vector_get(words, i));
3739 
3740 		word->text.f_str[word->text.f_len] = 0;
3741 
3742 		/* Convert word from index charset to system_charset_info */
3743 		if (index_charset->cset != system_charset_info->cset) {
3744 			conv_str->f_n_char = my_convert(
3745 				reinterpret_cast<char*>(conv_str->f_str),
3746 				static_cast<uint32>(conv_str->f_len),
3747 				system_charset_info,
3748 				reinterpret_cast<char*>(word->text.f_str),
3749 				static_cast<uint32>(word->text.f_len),
3750 				index_charset, &dummy_errors);
3751 			ut_ad(conv_str->f_n_char <= conv_str->f_len);
3752 			conv_str->f_str[conv_str->f_n_char] = 0;
3753 			word_str = reinterpret_cast<char*>(conv_str->f_str);
3754 		} else {
3755 			word_str = reinterpret_cast<char*>(word->text.f_str);
3756 		}
3757 
3758 		/* Decrypt the ilist, and display Dod ID and word position */
3759 		for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
3760 			fts_node_t*	node;
3761 			byte*		ptr;
3762 			ulint		decoded = 0;
3763 			doc_id_t	doc_id = 0;
3764 
3765 			node = static_cast<fts_node_t*> (ib_vector_get(
3766 				word->nodes, i));
3767 
3768 			ptr = node->ilist;
3769 
3770 			while (decoded < node->ilist_size) {
3771 				ulint	pos = fts_decode_vlc(&ptr);
3772 
3773 				doc_id += pos;
3774 
3775 				/* Get position info */
3776 				while (*ptr) {
3777 					pos = fts_decode_vlc(&ptr);
3778 
3779 					OK(field_store_string(
3780 						   fields[I_S_FTS_WORD],
3781 						   word_str));
3782 
3783 					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
3784 						   node->first_doc_id, true));
3785 
3786 					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
3787 						   node->last_doc_id, true));
3788 
3789 					OK(fields[I_S_FTS_DOC_COUNT]->store(
3790 						   node->doc_count, true));
3791 
3792 					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
3793 						   doc_id, true));
3794 
3795 					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
3796 						   pos, true));
3797 
3798 					OK(schema_table_store_record(
3799 						   thd, table));
3800 				}
3801 
3802 				++ptr;
3803 
3804 				decoded = ptr - (byte*) node->ilist;
3805 			}
3806 		}
3807 	}
3808 
3809 	i_s_fts_index_table_free_one_fetch(words);
3810 
3811 	DBUG_RETURN(ret);
3812 }
3813 
3814 /*******************************************************************//**
3815 Go through a FTS index and its auxiliary tables, fetch rows in each table
3816 and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
3817 @return 0 on success, 1 on failure */
3818 static
3819 int
i_s_fts_index_table_fill_one_index(dict_index_t * index,THD * thd,TABLE_LIST * tables)3820 i_s_fts_index_table_fill_one_index(
3821 /*===============================*/
3822 	dict_index_t*		index,		/*!< in: FTS index */
3823 	THD*			thd,		/*!< in: thread */
3824 	TABLE_LIST*		tables)		/*!< in/out: tables to fill */
3825 {
3826 	ib_vector_t*		words;
3827 	mem_heap_t*		heap;
3828 	CHARSET_INFO*		index_charset;
3829 	fts_string_t		conv_str;
3830 	dberr_t			error;
3831 	int			ret = 0;
3832 
3833 	DBUG_ENTER("i_s_fts_index_table_fill_one_index");
3834 	assert(!dict_index_is_online_ddl(index));
3835 
3836 	heap = mem_heap_create(1024);
3837 
3838 	words = ib_vector_create(ib_heap_allocator_create(heap),
3839 				 sizeof(fts_word_t), 256);
3840 
3841 	index_charset = fts_index_get_charset(index);
3842 	conv_str.f_len = system_charset_info->mbmaxlen
3843 		* FTS_MAX_WORD_LEN_IN_CHAR;
3844 	conv_str.f_str = static_cast<byte*>(ut_malloc_nokey(conv_str.f_len));
3845 	conv_str.f_n_char = 0;
3846 
3847 	/* Iterate through each auxiliary table as described in
3848 	fts_index_selector */
3849 	for (ulint selected = 0; selected < FTS_NUM_AUX_INDEX; selected++) {
3850 		fts_string_t	word;
3851 		bool		has_more = false;
3852 
3853 		word.f_str = NULL;
3854 		word.f_len = 0;
3855 		word.f_n_char = 0;
3856 
3857 		do {
3858 			/* Fetch from index */
3859 			error = i_s_fts_index_table_fill_selected(
3860 				index, words, selected, &word);
3861 
3862 			if (error == DB_SUCCESS) {
3863 				has_more = false;
3864 			} else if (error == DB_FTS_EXCEED_RESULT_CACHE_LIMIT) {
3865 				has_more = true;
3866 			} else {
3867 				i_s_fts_index_table_free_one_fetch(words);
3868 				ret = 1;
3869 				goto func_exit;
3870 			}
3871 
3872 			if (has_more) {
3873 				fts_word_t*	last_word;
3874 
3875 				/* Prepare start point for next fetch */
3876 				last_word = static_cast<fts_word_t*>(ib_vector_last(words));
3877 				ut_ad(last_word != NULL);
3878 				fts_string_dup(&word, &last_word->text, heap);
3879 			}
3880 
3881 			/* Fill into tables */
3882 			ret = i_s_fts_index_table_fill_one_fetch(
3883 				index_charset, thd, tables, words, &conv_str, has_more);
3884 
3885 			if (ret != 0) {
3886 				i_s_fts_index_table_free_one_fetch(words);
3887 				goto func_exit;
3888 			}
3889 		} while (has_more);
3890 	}
3891 
3892 func_exit:
3893 	ut_free(conv_str.f_str);
3894 	mem_heap_free(heap);
3895 
3896 	DBUG_RETURN(ret);
3897 }
3898 /*******************************************************************//**
3899 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
3900 @return 0 on success, 1 on failure */
3901 static
3902 int
i_s_fts_index_table_fill(THD * thd,TABLE_LIST * tables,Item *)3903 i_s_fts_index_table_fill(
3904 /*=====================*/
3905 	THD*		thd,	/*!< in: thread */
3906 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
3907 	Item*		)	/*!< in: condition (ignored) */
3908 {
3909 	dict_table_t*		user_table;
3910 	dict_index_t*		index;
3911 
3912 	DBUG_ENTER("i_s_fts_index_table_fill");
3913 
3914 	/* deny access to non-superusers */
3915 	if (check_global_access(thd, PROCESS_ACL)) {
3916 		DBUG_RETURN(0);
3917 	}
3918 
3919         mysql_mutex_lock(&LOCK_global_system_variables);
3920 
3921         if (!fts_internal_tbl_name) {
3922                 mysql_mutex_unlock(&LOCK_global_system_variables);
3923                 DBUG_RETURN(0);
3924         }
3925 
3926 	std::string fts_table_name(fts_internal_tbl_name);
3927 	mysql_mutex_unlock(&LOCK_global_system_variables);
3928 
3929         if(!fts_table_name.c_str()) {
3930                 DBUG_RETURN(0);
3931         }
3932 
3933 	/* Prevent DDL to drop fts aux tables. */
3934 	rw_lock_s_lock(dict_operation_lock);
3935 
3936 	user_table = dict_table_open_on_name(
3937 		fts_table_name.c_str(), FALSE, FALSE, DICT_ERR_IGNORE_NONE);
3938 
3939 	if (!user_table) {
3940 		rw_lock_s_unlock(dict_operation_lock);
3941 
3942 		DBUG_RETURN(0);
3943 	}
3944 
3945 	for (index = dict_table_get_first_index(user_table);
3946 	     index; index = dict_table_get_next_index(index)) {
3947 		if (index->type & DICT_FTS) {
3948 			i_s_fts_index_table_fill_one_index(index, thd, tables);
3949 		}
3950 	}
3951 
3952 	dict_table_close(user_table, FALSE, FALSE);
3953 
3954 	rw_lock_s_unlock(dict_operation_lock);
3955 
3956 	DBUG_RETURN(0);
3957 }
3958 
3959 /*******************************************************************//**
3960 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
3961 @return 0 on success */
3962 static
3963 int
i_s_fts_index_table_init(void * p)3964 i_s_fts_index_table_init(
3965 /*=====================*/
3966 	void*	p)	/*!< in/out: table schema object */
3967 {
3968 	DBUG_ENTER("i_s_fts_index_table_init");
3969 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
3970 
3971 	schema->fields_info = i_s_fts_index_fields_info;
3972 	schema->fill_table = i_s_fts_index_table_fill;
3973 
3974 	DBUG_RETURN(0);
3975 }
3976 
3977 struct st_mysql_plugin	i_s_innodb_ft_index_table =
3978 {
3979 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3980 	/* int */
3981 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
3982 
3983 	/* pointer to type-specific plugin descriptor */
3984 	/* void* */
3985 	STRUCT_FLD(info, &i_s_info),
3986 
3987 	/* plugin name */
3988 	/* const char* */
3989 	STRUCT_FLD(name, "INNODB_FT_INDEX_TABLE"),
3990 
3991 	/* plugin author (for SHOW PLUGINS) */
3992 	/* const char* */
3993 	STRUCT_FLD(author, plugin_author),
3994 
3995 	/* general descriptive text (for SHOW PLUGINS) */
3996 	/* const char* */
3997 	STRUCT_FLD(descr, "INNODB AUXILIARY FTS INDEX TABLE"),
3998 
3999 	/* the plugin license (PLUGIN_LICENSE_XXX) */
4000 	/* int */
4001 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
4002 
4003 	/* the function to invoke when plugin is loaded */
4004 	/* int (*)(void*); */
4005 	STRUCT_FLD(init, i_s_fts_index_table_init),
4006 
4007 	/* the function to invoke when plugin is unloaded */
4008 	/* int (*)(void*); */
4009 	STRUCT_FLD(deinit, i_s_common_deinit),
4010 
4011 	/* plugin version (for SHOW PLUGINS) */
4012 	/* unsigned int */
4013 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
4014 
4015 	/* struct st_mysql_show_var* */
4016 	STRUCT_FLD(status_vars, NULL),
4017 
4018 	/* struct st_mysql_sys_var** */
4019 	STRUCT_FLD(system_vars, NULL),
4020 
4021 	/* reserved for dependency checking */
4022 	/* void* */
4023 	STRUCT_FLD(__reserved1, NULL),
4024 
4025 	/* Plugin flags */
4026 	/* unsigned long */
4027 	STRUCT_FLD(flags, 0UL),
4028 };
4029 
4030 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG */
4031 static ST_FIELD_INFO	i_s_fts_config_fields_info[] =
4032 {
4033 #define	FTS_CONFIG_KEY			0
4034 	{STRUCT_FLD(field_name,		"KEY"),
4035 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
4036 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
4037 	 STRUCT_FLD(value,		0),
4038 	 STRUCT_FLD(field_flags,	0),
4039 	 STRUCT_FLD(old_name,		""),
4040 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4041 
4042 #define	FTS_CONFIG_VALUE		1
4043 	{STRUCT_FLD(field_name,		"VALUE"),
4044 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
4045 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
4046 	 STRUCT_FLD(value,		0),
4047 	 STRUCT_FLD(field_flags,	0),
4048 	 STRUCT_FLD(old_name,		""),
4049 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4050 
4051 	END_OF_ST_FIELD_INFO
4052 };
4053 
4054 static const char* fts_config_key[] = {
4055 	FTS_OPTIMIZE_LIMIT_IN_SECS,
4056 	FTS_SYNCED_DOC_ID,
4057 	FTS_STOPWORD_TABLE_NAME,
4058 	FTS_USE_STOPWORD,
4059         NULL
4060 };
4061 
4062 /*******************************************************************//**
4063 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
4064 @return 0 on success, 1 on failure */
4065 static
4066 int
i_s_fts_config_fill(THD * thd,TABLE_LIST * tables,Item *)4067 i_s_fts_config_fill(
4068 /*================*/
4069 	THD*		thd,		/*!< in: thread */
4070 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
4071 	Item*		)	/*!< in: condition (ignored) */
4072 {
4073 	Field**			fields;
4074 	TABLE*			table = (TABLE*) tables->table;
4075 	trx_t*			trx;
4076 	fts_table_t		fts_table;
4077 	dict_table_t*		user_table;
4078 	ulint			i = 0;
4079 	dict_index_t*		index = NULL;
4080 	unsigned char		str[FTS_MAX_CONFIG_VALUE_LEN + 1];
4081 
4082 	DBUG_ENTER("i_s_fts_config_fill");
4083 
4084 	/* deny access to non-superusers */
4085 	if (check_global_access(thd, PROCESS_ACL)) {
4086 		DBUG_RETURN(0);
4087 	}
4088 
4089         mysql_mutex_lock(&LOCK_global_system_variables);
4090 
4091         if (!fts_internal_tbl_name) {
4092                 mysql_mutex_unlock(&LOCK_global_system_variables);
4093                 DBUG_RETURN(0);
4094         }
4095 
4096 	std::string fts_table_name(fts_internal_tbl_name);
4097 	mysql_mutex_unlock(&LOCK_global_system_variables);
4098 
4099         if(!fts_table_name.c_str()) {
4100                 DBUG_RETURN(0);
4101         }
4102 
4103 	DEBUG_SYNC_C("i_s_fts_config_fille_check");
4104 
4105 	fields = table->field;
4106 
4107 	/* Prevent DDL to drop fts aux tables. */
4108 	rw_lock_s_lock(dict_operation_lock);
4109 
4110 	user_table = dict_table_open_on_name(
4111 		fts_table_name.c_str(), FALSE, FALSE, DICT_ERR_IGNORE_NONE);
4112 
4113 	if (!user_table) {
4114 		rw_lock_s_unlock(dict_operation_lock);
4115 
4116 		DBUG_RETURN(0);
4117 	} else if (!dict_table_has_fts_index(user_table)) {
4118 		dict_table_close(user_table, FALSE, FALSE);
4119 
4120 		rw_lock_s_unlock(dict_operation_lock);
4121 
4122 		DBUG_RETURN(0);
4123 	}
4124 
4125 	trx = trx_allocate_for_background();
4126 	trx->op_info = "Select for FTS CONFIG TABLE";
4127 
4128 	FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE, user_table);
4129 
4130 	if (!ib_vector_is_empty(user_table->fts->indexes)) {
4131 		index = (dict_index_t*) ib_vector_getp_const(
4132 				user_table->fts->indexes, 0);
4133 		assert(!dict_index_is_online_ddl(index));
4134 	}
4135 
4136 	while (fts_config_key[i]) {
4137 		fts_string_t	value;
4138 		char*		key_name;
4139 		ulint		allocated = FALSE;
4140 
4141 		value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
4142 
4143 		value.f_str = str;
4144 
4145 		if (index
4146 		    && strcmp(fts_config_key[i], FTS_TOTAL_WORD_COUNT) == 0) {
4147 			key_name = fts_config_create_index_param_name(
4148 				fts_config_key[i], index);
4149 			allocated = TRUE;
4150 		} else {
4151 			key_name = (char*) fts_config_key[i];
4152 		}
4153 
4154 		fts_config_get_value(trx, &fts_table, key_name, &value);
4155 
4156 		if (allocated) {
4157 			ut_free(key_name);
4158 		}
4159 
4160 		OK(field_store_string(
4161                         fields[FTS_CONFIG_KEY], fts_config_key[i]));
4162 
4163 		OK(field_store_string(
4164                         fields[FTS_CONFIG_VALUE], (const char*) value.f_str));
4165 
4166 		OK(schema_table_store_record(thd, table));
4167 
4168 		i++;
4169 	}
4170 
4171 	fts_sql_commit(trx);
4172 
4173 	trx_free_for_background(trx);
4174 
4175 	dict_table_close(user_table, FALSE, FALSE);
4176 
4177 	rw_lock_s_unlock(dict_operation_lock);
4178 
4179 	DBUG_RETURN(0);
4180 }
4181 
4182 /*******************************************************************//**
4183 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
4184 @return 0 on success */
4185 static
4186 int
i_s_fts_config_init(void * p)4187 i_s_fts_config_init(
4188 /*=================*/
4189 	void*	p)	/*!< in/out: table schema object */
4190 {
4191 	DBUG_ENTER("i_s_fts_config_init");
4192 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
4193 
4194 	schema->fields_info = i_s_fts_config_fields_info;
4195 	schema->fill_table = i_s_fts_config_fill;
4196 
4197 	DBUG_RETURN(0);
4198 }
4199 
4200 struct st_mysql_plugin	i_s_innodb_ft_config =
4201 {
4202 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
4203 	/* int */
4204 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
4205 
4206 	/* pointer to type-specific plugin descriptor */
4207 	/* void* */
4208 	STRUCT_FLD(info, &i_s_info),
4209 
4210 	/* plugin name */
4211 	/* const char* */
4212 	STRUCT_FLD(name, "INNODB_FT_CONFIG"),
4213 
4214 	/* plugin author (for SHOW PLUGINS) */
4215 	/* const char* */
4216 	STRUCT_FLD(author, plugin_author),
4217 
4218 	/* general descriptive text (for SHOW PLUGINS) */
4219 	/* const char* */
4220 	STRUCT_FLD(descr, "INNODB AUXILIARY FTS CONFIG TABLE"),
4221 
4222 	/* the plugin license (PLUGIN_LICENSE_XXX) */
4223 	/* int */
4224 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
4225 
4226 	/* the function to invoke when plugin is loaded */
4227 	/* int (*)(void*); */
4228 	STRUCT_FLD(init, i_s_fts_config_init),
4229 
4230 	/* the function to invoke when plugin is unloaded */
4231 	/* int (*)(void*); */
4232 	STRUCT_FLD(deinit, i_s_common_deinit),
4233 
4234 	/* plugin version (for SHOW PLUGINS) */
4235 	/* unsigned int */
4236 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
4237 
4238 	/* struct st_mysql_show_var* */
4239 	STRUCT_FLD(status_vars, NULL),
4240 
4241 	/* struct st_mysql_sys_var** */
4242 	STRUCT_FLD(system_vars, NULL),
4243 
4244 	/* reserved for dependency checking */
4245 	/* void* */
4246 	STRUCT_FLD(__reserved1, NULL),
4247 
4248 	/* Plugin flags */
4249 	/* unsigned long */
4250 	STRUCT_FLD(flags, 0UL),
4251 };
4252 
4253 /* Fields of the dynamic table INNODB_TEMP_TABLE_INFO. */
4254 static ST_FIELD_INFO	i_s_innodb_temp_table_info_fields_info[] =
4255 {
4256 #define IDX_TEMP_TABLE_ID		0
4257 	{STRUCT_FLD(field_name,		"TABLE_ID"),
4258 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4259 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4260 	 STRUCT_FLD(value,		0),
4261 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4262 	 STRUCT_FLD(old_name,		""),
4263 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4264 
4265 #define IDX_TEMP_TABLE_NAME		1
4266 	{STRUCT_FLD(field_name,		"NAME"),
4267 	 STRUCT_FLD(field_length,	MAX_TABLE_UTF8_LEN),
4268 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
4269 	 STRUCT_FLD(value,		0),
4270 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
4271 	 STRUCT_FLD(old_name,		""),
4272 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4273 
4274 #define IDX_TEMP_TABLE_N_COLS		2
4275 	{STRUCT_FLD(field_name,		"N_COLS"),
4276 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
4277 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
4278 	 STRUCT_FLD(value,		0),
4279 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4280 	 STRUCT_FLD(old_name,		""),
4281 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4282 
4283 #define IDX_TEMP_TABLE_SPACE_ID		3
4284 	{STRUCT_FLD(field_name,		"SPACE"),
4285 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
4286 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
4287 	 STRUCT_FLD(value,		0),
4288 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4289 	 STRUCT_FLD(old_name,		""),
4290 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4291 
4292 #define IDX_TEMP_TABLE_PTT		4
4293 	{STRUCT_FLD(field_name,		"PER_TABLE_TABLESPACE"),
4294 	 STRUCT_FLD(field_length,	64),
4295 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
4296 	 STRUCT_FLD(value,		0),
4297 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
4298 	 STRUCT_FLD(old_name,		""),
4299 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4300 
4301 #define IDX_TEMP_TABLE_IS_COMPRESSED	5
4302 	{STRUCT_FLD(field_name,		"IS_COMPRESSED"),
4303 	 STRUCT_FLD(field_length,	64),
4304 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
4305 	 STRUCT_FLD(value,		0),
4306 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
4307 	 STRUCT_FLD(old_name,		""),
4308 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4309 	END_OF_ST_FIELD_INFO
4310 };
4311 
4312 struct temp_table_info_t{
4313 	table_id_t	m_table_id;
4314 	char		m_table_name[MAX_TABLE_UTF8_LEN];
4315 	unsigned	m_n_cols;
4316 	unsigned	m_space_id;
4317 	char		m_per_table_tablespace[64];
4318 	char		m_is_compressed[64];
4319 };
4320 
4321 typedef std::vector<temp_table_info_t, ut_allocator<temp_table_info_t> >
4322 	temp_table_info_cache_t;
4323 
4324 /*******************************************************************//**
4325 Fill Information Schema table INNODB_TEMP_TABLE_INFO for a particular
4326 temp-table
4327 @return 0 on success, 1 on failure */
4328 static
4329 int
i_s_innodb_temp_table_info_fill(THD * thd,TABLE_LIST * tables,const temp_table_info_t * info)4330 i_s_innodb_temp_table_info_fill(
4331 /*=============================*/
4332 	THD*				thd,		/*!< in: thread */
4333 	TABLE_LIST*			tables,		/*!< in/out: tables
4334 							to fill */
4335 	const temp_table_info_t*	info)		/*!< in: temp-table
4336 							information */
4337 {
4338 	TABLE*			table;
4339 	Field**			fields;
4340 
4341 	DBUG_ENTER("i_s_innodb_temp_table_info_fill");
4342 
4343 	table = tables->table;
4344 
4345 	fields = table->field;
4346 
4347 	OK(fields[IDX_TEMP_TABLE_ID]->store(info->m_table_id, true));
4348 
4349 	OK(field_store_string(
4350 		   fields[IDX_TEMP_TABLE_NAME], info->m_table_name));
4351 
4352 	OK(fields[IDX_TEMP_TABLE_N_COLS]->store(info->m_n_cols));
4353 
4354 	OK(fields[IDX_TEMP_TABLE_SPACE_ID]->store(info->m_space_id));
4355 
4356 	OK(field_store_string(
4357 		fields[IDX_TEMP_TABLE_PTT], info->m_per_table_tablespace));
4358 
4359 	OK(field_store_string(
4360 		fields[IDX_TEMP_TABLE_IS_COMPRESSED], info->m_is_compressed));
4361 
4362 	DBUG_RETURN(schema_table_store_record(thd, table));
4363 }
4364 
4365 /*******************************************************************//**
4366 Populate current table information to cache */
4367 static
4368 void
innodb_temp_table_populate_cache(const dict_table_t * table,temp_table_info_t * cache)4369 innodb_temp_table_populate_cache(
4370 /*=============================*/
4371 	const dict_table_t*	table,  /*! in: table */
4372 	temp_table_info_t*	cache)  /*! in/out: populate data in this
4373 					cache */
4374 {
4375 	cache->m_table_id = table->id;
4376 
4377 	char	db_utf8[MAX_DB_UTF8_LEN];
4378 	char	table_utf8[MAX_TABLE_UTF8_LEN];
4379 
4380 	dict_fs2utf8(table->name.m_name,
4381 		     db_utf8, sizeof(db_utf8),
4382 		     table_utf8, sizeof(table_utf8));
4383 	strcpy(cache->m_table_name, table_utf8);
4384 
4385 	cache->m_n_cols = table->n_cols;
4386 
4387 	cache->m_space_id = table->space;
4388 
4389 	if (fsp_is_system_temporary(table->space)) {
4390 		strcpy(cache->m_per_table_tablespace, "FALSE");
4391 	} else {
4392 		strcpy(cache->m_per_table_tablespace, "TRUE");
4393 	}
4394 
4395 	if (dict_table_page_size(table).is_compressed()) {
4396 		strcpy(cache->m_is_compressed, "TRUE");
4397 	} else {
4398 		strcpy(cache->m_is_compressed, "FALSE");
4399 	}
4400 }
4401 
4402 /*******************************************************************//**
4403 This function will iterate over all available table and will fill
4404 stats for temp-tables to INNODB_TEMP_TABLE_INFO.
4405 @return 0 on success, 1 on failure */
4406 static
4407 int
i_s_innodb_temp_table_info_fill_table(THD * thd,TABLE_LIST * tables,Item *)4408 i_s_innodb_temp_table_info_fill_table(
4409 /*===================================*/
4410 	THD*		thd,		/*!< in: thread */
4411 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
4412 	Item*		)		/*!< in: condition (ignored) */
4413 {
4414 	int			status	= 0;
4415 	dict_table_t*		table	= NULL;
4416 
4417 	DBUG_ENTER("i_s_innodb_temp_table_info_fill_table");
4418 
4419 	/* Only allow the PROCESS privilege holder to access the stats */
4420 	if (check_global_access(thd, PROCESS_ACL)) {
4421 		DBUG_RETURN(0);
4422 	}
4423 
4424 	/* First populate all temp-table info by acquiring dict_sys->mutex.
4425 	Note: Scan is being done on NON-LRU list which mainly has system
4426 	table entries and temp-table entries. This means 2 things: list
4427 	is smaller so processing would be faster and most of the data
4428 	is relevant */
4429 	temp_table_info_cache_t all_temp_info_cache;
4430 	all_temp_info_cache.reserve(UT_LIST_GET_LEN(dict_sys->table_non_LRU));
4431 
4432 	mutex_enter(&dict_sys->mutex);
4433 	for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
4434 	     table != NULL;
4435 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
4436 
4437 		if (!dict_table_is_temporary(table)) {
4438 			continue;
4439 		}
4440 
4441 		temp_table_info_t current_temp_table_info;
4442 
4443 		innodb_temp_table_populate_cache(
4444 			table, &current_temp_table_info);
4445 
4446 		all_temp_info_cache.push_back(current_temp_table_info);
4447 	}
4448 	mutex_exit(&dict_sys->mutex);
4449 
4450 	/* Now populate the info to MySQL table */
4451 	temp_table_info_cache_t::const_iterator end = all_temp_info_cache.end();
4452 	for (temp_table_info_cache_t::const_iterator it
4453 		= all_temp_info_cache.begin();
4454 	     it != end;
4455 	     it++) {
4456 		status = i_s_innodb_temp_table_info_fill(thd, tables, &(*it));
4457 		if (status) {
4458 			break;
4459 		}
4460 	}
4461 
4462 	DBUG_RETURN(status);
4463 }
4464 
4465 /*******************************************************************//**
4466 Bind the dynamic table INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO.
4467 @return 0 on success, 1 on failure */
4468 static
4469 int
i_s_innodb_temp_table_info_init(void * p)4470 i_s_innodb_temp_table_info_init(
4471 /*=============================*/
4472 	void*	p)	/*!< in/out: table schema object */
4473 {
4474 	ST_SCHEMA_TABLE*	schema;
4475 
4476 	DBUG_ENTER("i_s_innodb_temp_table_info_init");
4477 
4478 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
4479 
4480 	schema->fields_info = i_s_innodb_temp_table_info_fields_info;
4481 	schema->fill_table = i_s_innodb_temp_table_info_fill_table;
4482 
4483 	DBUG_RETURN(0);
4484 }
4485 
4486 struct st_mysql_plugin	i_s_innodb_temp_table_info =
4487 {
4488 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
4489 	/* int */
4490 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
4491 
4492 	/* pointer to type-specific plugin descriptor */
4493 	/* void* */
4494 	STRUCT_FLD(info, &i_s_info),
4495 
4496 	/* plugin name */
4497 	/* const char* */
4498 	STRUCT_FLD(name, "INNODB_TEMP_TABLE_INFO"),
4499 
4500 	/* plugin author (for SHOW PLUGINS) */
4501 	/* const char* */
4502 	STRUCT_FLD(author, plugin_author),
4503 
4504 	/* general descriptive text (for SHOW PLUGINS) */
4505 	/* const char* */
4506 	STRUCT_FLD(descr, "InnoDB Temp Table Stats"),
4507 
4508 	/* the plugin license (PLUGIN_LICENSE_XXX) */
4509 	/* int */
4510 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
4511 
4512 	/* the function to invoke when plugin is loaded */
4513 	/* int (*)(void*); */
4514 	STRUCT_FLD(init, i_s_innodb_temp_table_info_init),
4515 
4516 	/* the function to invoke when plugin is unloaded */
4517 	/* int (*)(void*); */
4518 	STRUCT_FLD(deinit, i_s_common_deinit),
4519 
4520 	/* plugin version (for SHOW PLUGINS) */
4521 	/* unsigned int */
4522 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
4523 
4524 	/* struct st_mysql_show_var* */
4525 	STRUCT_FLD(status_vars, NULL),
4526 
4527 	/* struct st_mysql_sys_var** */
4528 	STRUCT_FLD(system_vars, NULL),
4529 
4530 	/* reserved for dependency checking */
4531 	/* void* */
4532 	STRUCT_FLD(__reserved1, NULL),
4533 
4534 	/* Plugin flags */
4535 	/* unsigned long */
4536 	STRUCT_FLD(flags, 0UL),
4537 };
4538 
4539 /* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */
4540 static ST_FIELD_INFO	i_s_innodb_buffer_stats_fields_info[] =
4541 {
4542 #define IDX_BUF_STATS_POOL_ID		0
4543 	{STRUCT_FLD(field_name,		"POOL_ID"),
4544 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4545 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4546 	 STRUCT_FLD(value,		0),
4547 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4548 	 STRUCT_FLD(old_name,		""),
4549 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4550 
4551 #define IDX_BUF_STATS_POOL_SIZE		1
4552 	{STRUCT_FLD(field_name,		"POOL_SIZE"),
4553 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4554 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4555 	 STRUCT_FLD(value,		0),
4556 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4557 	 STRUCT_FLD(old_name,		""),
4558 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4559 
4560 #define IDX_BUF_STATS_FREE_BUFFERS	2
4561 	{STRUCT_FLD(field_name,		"FREE_BUFFERS"),
4562 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4563 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4564 	 STRUCT_FLD(value,		0),
4565 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4566 	 STRUCT_FLD(old_name,		""),
4567 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4568 
4569 #define IDX_BUF_STATS_LRU_LEN		3
4570 	{STRUCT_FLD(field_name,		"DATABASE_PAGES"),
4571 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4572 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4573 	 STRUCT_FLD(value,		0),
4574 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4575 	 STRUCT_FLD(old_name,		""),
4576 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4577 
4578 #define IDX_BUF_STATS_OLD_LRU_LEN	4
4579 	{STRUCT_FLD(field_name,		"OLD_DATABASE_PAGES"),
4580 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4581 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4582 	 STRUCT_FLD(value,		0),
4583 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4584 	 STRUCT_FLD(old_name,		""),
4585 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4586 
4587 #define IDX_BUF_STATS_FLUSH_LIST_LEN	5
4588 	{STRUCT_FLD(field_name,		"MODIFIED_DATABASE_PAGES"),
4589 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4590 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4591 	 STRUCT_FLD(value,		0),
4592 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4593 	 STRUCT_FLD(old_name,		""),
4594 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4595 
4596 #define IDX_BUF_STATS_PENDING_ZIP	6
4597 	{STRUCT_FLD(field_name,		"PENDING_DECOMPRESS"),
4598 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4599 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4600 	 STRUCT_FLD(value,		0),
4601 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4602 	 STRUCT_FLD(old_name,		""),
4603 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4604 
4605 #define IDX_BUF_STATS_PENDING_READ	7
4606 	{STRUCT_FLD(field_name,		"PENDING_READS"),
4607 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4608 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4609 	 STRUCT_FLD(value,		0),
4610 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4611 	 STRUCT_FLD(old_name,		""),
4612 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4613 
4614 #define IDX_BUF_STATS_FLUSH_LRU		8
4615 	{STRUCT_FLD(field_name,		"PENDING_FLUSH_LRU"),
4616 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4617 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4618 	 STRUCT_FLD(value,		0),
4619 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4620 	 STRUCT_FLD(old_name,		""),
4621 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4622 
4623 #define IDX_BUF_STATS_FLUSH_LIST	9
4624 	{STRUCT_FLD(field_name,		"PENDING_FLUSH_LIST"),
4625 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4626 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4627 	 STRUCT_FLD(value,		0),
4628 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4629 	 STRUCT_FLD(old_name,		""),
4630 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4631 
4632 #define IDX_BUF_STATS_PAGE_YOUNG	10
4633 	{STRUCT_FLD(field_name,		"PAGES_MADE_YOUNG"),
4634 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4635 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4636 	 STRUCT_FLD(value,		0),
4637 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4638 	 STRUCT_FLD(old_name,		""),
4639 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4640 
4641 #define IDX_BUF_STATS_PAGE_NOT_YOUNG	11
4642 	{STRUCT_FLD(field_name,		"PAGES_NOT_MADE_YOUNG"),
4643 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4644 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4645 	 STRUCT_FLD(value,		0),
4646 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4647 	 STRUCT_FLD(old_name,		""),
4648 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4649 
4650 #define	IDX_BUF_STATS_PAGE_YOUNG_RATE	12
4651 	{STRUCT_FLD(field_name,		"PAGES_MADE_YOUNG_RATE"),
4652 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4653 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4654 	 STRUCT_FLD(value,		0),
4655 	 STRUCT_FLD(field_flags,	0),
4656 	 STRUCT_FLD(old_name,		""),
4657 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4658 
4659 #define	IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE 13
4660 	{STRUCT_FLD(field_name,		"PAGES_MADE_NOT_YOUNG_RATE"),
4661 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4662 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4663 	 STRUCT_FLD(value,		0),
4664 	 STRUCT_FLD(field_flags,	0),
4665 	 STRUCT_FLD(old_name,		""),
4666 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4667 
4668 #define IDX_BUF_STATS_PAGE_READ		14
4669 	{STRUCT_FLD(field_name,		"NUMBER_PAGES_READ"),
4670 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4671 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4672 	 STRUCT_FLD(value,		0),
4673 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4674 	 STRUCT_FLD(old_name,		""),
4675 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4676 
4677 #define IDX_BUF_STATS_PAGE_CREATED	15
4678 	{STRUCT_FLD(field_name,		"NUMBER_PAGES_CREATED"),
4679 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4680 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4681 	 STRUCT_FLD(value,		0),
4682 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4683 	 STRUCT_FLD(old_name,		""),
4684 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4685 
4686 #define IDX_BUF_STATS_PAGE_WRITTEN	16
4687 	{STRUCT_FLD(field_name,		"NUMBER_PAGES_WRITTEN"),
4688 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4689 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4690 	 STRUCT_FLD(value,		0),
4691 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4692 	 STRUCT_FLD(old_name,		""),
4693 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4694 
4695 #define	IDX_BUF_STATS_PAGE_READ_RATE	17
4696 	{STRUCT_FLD(field_name,		"PAGES_READ_RATE"),
4697 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4698 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4699 	 STRUCT_FLD(value,		0),
4700 	 STRUCT_FLD(field_flags,	0),
4701 	 STRUCT_FLD(old_name,		""),
4702 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4703 
4704 #define	IDX_BUF_STATS_PAGE_CREATE_RATE	18
4705 	{STRUCT_FLD(field_name,		"PAGES_CREATE_RATE"),
4706 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4707 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4708 	 STRUCT_FLD(value,		0),
4709 	 STRUCT_FLD(field_flags,	0),
4710 	 STRUCT_FLD(old_name,		""),
4711 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4712 
4713 #define	IDX_BUF_STATS_PAGE_WRITTEN_RATE	19
4714 	{STRUCT_FLD(field_name,		"PAGES_WRITTEN_RATE"),
4715 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4716 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4717 	 STRUCT_FLD(value,		0),
4718 	 STRUCT_FLD(field_flags,	0),
4719 	 STRUCT_FLD(old_name,		""),
4720 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4721 
4722 #define IDX_BUF_STATS_GET		20
4723 	{STRUCT_FLD(field_name,		"NUMBER_PAGES_GET"),
4724 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4725 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4726 	 STRUCT_FLD(value,		0),
4727 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4728 	 STRUCT_FLD(old_name,		""),
4729 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4730 
4731 #define IDX_BUF_STATS_HIT_RATE		21
4732 	{STRUCT_FLD(field_name,		"HIT_RATE"),
4733 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4734 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4735 	 STRUCT_FLD(value,		0),
4736 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4737 	 STRUCT_FLD(old_name,		""),
4738 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4739 
4740 #define IDX_BUF_STATS_MADE_YOUNG_PCT	22
4741 	{STRUCT_FLD(field_name,		"YOUNG_MAKE_PER_THOUSAND_GETS"),
4742 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4743 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4744 	 STRUCT_FLD(value,		0),
4745 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4746 	 STRUCT_FLD(old_name,		""),
4747 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4748 
4749 #define IDX_BUF_STATS_NOT_MADE_YOUNG_PCT 23
4750 	{STRUCT_FLD(field_name,		"NOT_YOUNG_MAKE_PER_THOUSAND_GETS"),
4751 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4752 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4753 	 STRUCT_FLD(value,		0),
4754 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4755 	 STRUCT_FLD(old_name,		""),
4756 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4757 
4758 #define IDX_BUF_STATS_READ_AHREAD	24
4759 	{STRUCT_FLD(field_name,		"NUMBER_PAGES_READ_AHEAD"),
4760 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4761 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4762 	 STRUCT_FLD(value,		0),
4763 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4764 	 STRUCT_FLD(old_name,		""),
4765 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4766 
4767 #define IDX_BUF_STATS_READ_AHEAD_EVICTED 25
4768 	{STRUCT_FLD(field_name,		"NUMBER_READ_AHEAD_EVICTED"),
4769 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4770 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4771 	 STRUCT_FLD(value,		0),
4772 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4773 	 STRUCT_FLD(old_name,		""),
4774 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4775 
4776 #define	IDX_BUF_STATS_READ_AHEAD_RATE	26
4777 	{STRUCT_FLD(field_name,		"READ_AHEAD_RATE"),
4778 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4779 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4780 	 STRUCT_FLD(value,		0),
4781 	 STRUCT_FLD(field_flags,	0),
4782 	 STRUCT_FLD(old_name,		""),
4783 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4784 
4785 #define	IDX_BUF_STATS_READ_AHEAD_EVICT_RATE 27
4786 	{STRUCT_FLD(field_name,		"READ_AHEAD_EVICTED_RATE"),
4787 	 STRUCT_FLD(field_length,	MAX_FLOAT_STR_LENGTH),
4788 	 STRUCT_FLD(field_type,		MYSQL_TYPE_FLOAT),
4789 	 STRUCT_FLD(value,		0),
4790 	 STRUCT_FLD(field_flags,	0),
4791 	 STRUCT_FLD(old_name,		""),
4792 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4793 
4794 #define IDX_BUF_STATS_LRU_IO_SUM	28
4795 	{STRUCT_FLD(field_name,		"LRU_IO_TOTAL"),
4796 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4797 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4798 	 STRUCT_FLD(value,		0),
4799 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4800 	 STRUCT_FLD(old_name,		""),
4801 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4802 
4803 #define IDX_BUF_STATS_LRU_IO_CUR	29
4804 	{STRUCT_FLD(field_name,		"LRU_IO_CURRENT"),
4805 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4806 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4807 	 STRUCT_FLD(value,		0),
4808 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4809 	 STRUCT_FLD(old_name,		""),
4810 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4811 
4812 #define IDX_BUF_STATS_UNZIP_SUM		30
4813 	{STRUCT_FLD(field_name,		"UNCOMPRESS_TOTAL"),
4814 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4815 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4816 	 STRUCT_FLD(value,		0),
4817 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4818 	 STRUCT_FLD(old_name,		""),
4819 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4820 
4821 #define IDX_BUF_STATS_UNZIP_CUR		31
4822 	{STRUCT_FLD(field_name,		"UNCOMPRESS_CURRENT"),
4823 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
4824 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
4825 	 STRUCT_FLD(value,		0),
4826 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
4827 	 STRUCT_FLD(old_name,		""),
4828 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
4829 
4830 	END_OF_ST_FIELD_INFO
4831 };
4832 
4833 /*******************************************************************//**
4834 Fill Information Schema table INNODB_BUFFER_POOL_STATS for a particular
4835 buffer pool
4836 @return 0 on success, 1 on failure */
4837 static
4838 int
i_s_innodb_stats_fill(THD * thd,TABLE_LIST * tables,const buf_pool_info_t * info)4839 i_s_innodb_stats_fill(
4840 /*==================*/
4841 	THD*			thd,		/*!< in: thread */
4842 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
4843 	const buf_pool_info_t*	info)		/*!< in: buffer pool
4844 						information */
4845 {
4846 	TABLE*			table;
4847 	Field**			fields;
4848 
4849 	DBUG_ENTER("i_s_innodb_stats_fill");
4850 
4851 	table = tables->table;
4852 
4853 	fields = table->field;
4854 
4855 	OK(fields[IDX_BUF_STATS_POOL_ID]->store(
4856 		   info->pool_unique_id, true));
4857 
4858 	OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(
4859 		   info->pool_size, true));
4860 
4861 	OK(fields[IDX_BUF_STATS_LRU_LEN]->store(
4862 		   info->lru_len, true));
4863 
4864 	OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(
4865 		   info->old_lru_len, true));
4866 
4867 	OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
4868 		   info->free_list_len, true));
4869 
4870 	OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
4871 		   info->flush_list_len, true));
4872 
4873 	OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(
4874 		   info->n_pend_unzip, true));
4875 
4876 	OK(fields[IDX_BUF_STATS_PENDING_READ]->store(
4877 		   info->n_pend_reads, true));
4878 
4879 	OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
4880 		   info->n_pending_flush_lru, true));
4881 
4882 	OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
4883 		   info->n_pending_flush_list, true));
4884 
4885 	OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
4886 		   info->n_pages_made_young, true));
4887 
4888 	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
4889 		   info->n_pages_not_made_young, true));
4890 
4891 	OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
4892 		   info->page_made_young_rate));
4893 
4894 	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
4895 		   info->page_not_made_young_rate));
4896 
4897 	OK(fields[IDX_BUF_STATS_PAGE_READ]->store(
4898 		   info->n_pages_read, true));
4899 
4900 	OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
4901 		   info->n_pages_created, true));
4902 
4903 	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
4904 		   info->n_pages_written, true));
4905 
4906 	OK(fields[IDX_BUF_STATS_GET]->store(
4907 		   info->n_page_gets, true));
4908 
4909 	OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
4910 		   info->pages_read_rate));
4911 
4912 	OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
4913 		   info->pages_created_rate));
4914 
4915 	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
4916 		   info->pages_written_rate));
4917 
4918 	if (info->n_page_get_delta) {
4919 		OK(fields[IDX_BUF_STATS_HIT_RATE]->store(
4920 			   1000 - (1000 * info->page_read_delta
4921 				   / info->n_page_get_delta), true));
4922 
4923 		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
4924 			   1000 * info->young_making_delta
4925 			   / info->n_page_get_delta, true));
4926 
4927 		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
4928 			   1000 * info->not_young_making_delta
4929 			   / info->n_page_get_delta, true));
4930 	} else {
4931 		OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0, true));
4932 		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0, true));
4933 		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0, true));
4934 	}
4935 
4936 	OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(
4937 		   info->n_ra_pages_read, true));
4938 
4939 	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
4940 		   info->n_ra_pages_evicted, true));
4941 
4942 	OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
4943 		   info->pages_readahead_rate));
4944 
4945 	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
4946 		   info->pages_evicted_rate));
4947 
4948 	OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(
4949 		   info->io_sum, true));
4950 
4951 	OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(
4952 		   info->io_cur, true));
4953 
4954 	OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(
4955 		   info->unzip_sum, true));
4956 
4957 	OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(
4958 		   info->unzip_cur, true));
4959 
4960 	DBUG_RETURN(schema_table_store_record(thd, table));
4961 }
4962 
4963 /*******************************************************************//**
4964 This is the function that loops through each buffer pool and fetch buffer
4965 pool stats to information schema  table: I_S_INNODB_BUFFER_POOL_STATS
4966 @return 0 on success, 1 on failure */
4967 static
4968 int
i_s_innodb_buffer_stats_fill_table(THD * thd,TABLE_LIST * tables,Item *)4969 i_s_innodb_buffer_stats_fill_table(
4970 /*===============================*/
4971 	THD*		thd,		/*!< in: thread */
4972 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
4973 	Item*		)		/*!< in: condition (ignored) */
4974 {
4975 	int			status	= 0;
4976 	buf_pool_info_t*	pool_info;
4977 
4978 	DBUG_ENTER("i_s_innodb_buffer_fill_general");
4979 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
4980 
4981 	/* Only allow the PROCESS privilege holder to access the stats */
4982 	if (check_global_access(thd, PROCESS_ACL)) {
4983 		DBUG_RETURN(0);
4984 	}
4985 
4986 	pool_info = (buf_pool_info_t*) ut_zalloc_nokey(
4987 		srv_buf_pool_instances *  sizeof *pool_info);
4988 
4989 	/* Walk through each buffer pool */
4990 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
4991 		buf_pool_t*		buf_pool;
4992 
4993 		buf_pool = buf_pool_from_array(i);
4994 
4995 		/* Fetch individual buffer pool info */
4996 		buf_stats_get_pool_info(buf_pool, i, pool_info);
4997 
4998 		status = i_s_innodb_stats_fill(thd, tables, &pool_info[i]);
4999 
5000 		/* If something goes wrong, break and return */
5001 		if (status) {
5002 			break;
5003 		}
5004 	}
5005 
5006 	ut_free(pool_info);
5007 
5008 	DBUG_RETURN(status);
5009 }
5010 
5011 /*******************************************************************//**
5012 Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS.
5013 @return 0 on success, 1 on failure */
5014 static
5015 int
i_s_innodb_buffer_pool_stats_init(void * p)5016 i_s_innodb_buffer_pool_stats_init(
5017 /*==============================*/
5018 	void*	p)	/*!< in/out: table schema object */
5019 {
5020 	ST_SCHEMA_TABLE*	schema;
5021 
5022 	DBUG_ENTER("i_s_innodb_buffer_pool_stats_init");
5023 
5024 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
5025 
5026 	schema->fields_info = i_s_innodb_buffer_stats_fields_info;
5027 	schema->fill_table = i_s_innodb_buffer_stats_fill_table;
5028 
5029 	DBUG_RETURN(0);
5030 }
5031 
5032 struct st_mysql_plugin	i_s_innodb_buffer_stats =
5033 {
5034 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
5035 	/* int */
5036 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
5037 
5038 	/* pointer to type-specific plugin descriptor */
5039 	/* void* */
5040 	STRUCT_FLD(info, &i_s_info),
5041 
5042 	/* plugin name */
5043 	/* const char* */
5044 	STRUCT_FLD(name, "INNODB_BUFFER_POOL_STATS"),
5045 
5046 	/* plugin author (for SHOW PLUGINS) */
5047 	/* const char* */
5048 	STRUCT_FLD(author, plugin_author),
5049 
5050 	/* general descriptive text (for SHOW PLUGINS) */
5051 	/* const char* */
5052 	STRUCT_FLD(descr, "InnoDB Buffer Pool Statistics Information "),
5053 
5054 	/* the plugin license (PLUGIN_LICENSE_XXX) */
5055 	/* int */
5056 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
5057 
5058 	/* the function to invoke when plugin is loaded */
5059 	/* int (*)(void*); */
5060 	STRUCT_FLD(init, i_s_innodb_buffer_pool_stats_init),
5061 
5062 	/* the function to invoke when plugin is unloaded */
5063 	/* int (*)(void*); */
5064 	STRUCT_FLD(deinit, i_s_common_deinit),
5065 
5066 	/* plugin version (for SHOW PLUGINS) */
5067 	/* unsigned int */
5068 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
5069 
5070 	/* struct st_mysql_show_var* */
5071 	STRUCT_FLD(status_vars, NULL),
5072 
5073 	/* struct st_mysql_sys_var** */
5074 	STRUCT_FLD(system_vars, NULL),
5075 
5076 	/* reserved for dependency checking */
5077 	/* void* */
5078 	STRUCT_FLD(__reserved1, NULL),
5079 
5080 	/* Plugin flags */
5081 	/* unsigned long */
5082 	STRUCT_FLD(flags, 0UL),
5083 };
5084 
5085 /* Fields of the dynamic table INNODB_BUFFER_POOL_PAGE. */
5086 static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
5087 {
5088 #define IDX_BUFFER_POOL_ID		0
5089 	{STRUCT_FLD(field_name,		"POOL_ID"),
5090 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5091 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5092 	 STRUCT_FLD(value,		0),
5093 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5094 	 STRUCT_FLD(old_name,		""),
5095 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5096 
5097 #define IDX_BUFFER_BLOCK_ID		1
5098 	{STRUCT_FLD(field_name,		"BLOCK_ID"),
5099 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5100 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5101 	 STRUCT_FLD(value,		0),
5102 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5103 	 STRUCT_FLD(old_name,		""),
5104 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5105 
5106 #define IDX_BUFFER_PAGE_SPACE		2
5107 	{STRUCT_FLD(field_name,		"SPACE"),
5108 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5109 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5110 	 STRUCT_FLD(value,		0),
5111 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5112 	 STRUCT_FLD(old_name,		""),
5113 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5114 
5115 #define IDX_BUFFER_PAGE_NUM		3
5116 	{STRUCT_FLD(field_name,		"PAGE_NUMBER"),
5117 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5118 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5119 	 STRUCT_FLD(value,		0),
5120 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5121 	 STRUCT_FLD(old_name,		""),
5122 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5123 
5124 #define IDX_BUFFER_PAGE_TYPE		4
5125 	{STRUCT_FLD(field_name,		"PAGE_TYPE"),
5126 	 STRUCT_FLD(field_length,	64),
5127 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5128 	 STRUCT_FLD(value,		0),
5129 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5130 	 STRUCT_FLD(old_name,		""),
5131 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5132 
5133 #define IDX_BUFFER_PAGE_FLUSH_TYPE	5
5134 	{STRUCT_FLD(field_name,		"FLUSH_TYPE"),
5135 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5136 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5137 	 STRUCT_FLD(value,		0),
5138 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5139 	 STRUCT_FLD(old_name,		""),
5140 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5141 
5142 #define IDX_BUFFER_PAGE_FIX_COUNT	6
5143 	{STRUCT_FLD(field_name,		"FIX_COUNT"),
5144 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5145 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5146 	 STRUCT_FLD(value,		0),
5147 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5148 	 STRUCT_FLD(old_name,		""),
5149 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5150 
5151 #define IDX_BUFFER_PAGE_HASHED		7
5152 	{STRUCT_FLD(field_name,		"IS_HASHED"),
5153 	 STRUCT_FLD(field_length,	3),
5154 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5155 	 STRUCT_FLD(value,		0),
5156 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5157 	 STRUCT_FLD(old_name,		""),
5158 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5159 
5160 #define IDX_BUFFER_PAGE_NEWEST_MOD	8
5161 	{STRUCT_FLD(field_name,		"NEWEST_MODIFICATION"),
5162 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5163 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5164 	 STRUCT_FLD(value,		0),
5165 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5166 	 STRUCT_FLD(old_name,		""),
5167 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5168 
5169 #define IDX_BUFFER_PAGE_OLDEST_MOD	9
5170 	{STRUCT_FLD(field_name,		"OLDEST_MODIFICATION"),
5171 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5172 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5173 	 STRUCT_FLD(value,		0),
5174 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5175 	 STRUCT_FLD(old_name,		""),
5176 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5177 
5178 #define IDX_BUFFER_PAGE_ACCESS_TIME	10
5179 	{STRUCT_FLD(field_name,		"ACCESS_TIME"),
5180 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5181 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5182 	 STRUCT_FLD(value,		0),
5183 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5184 	 STRUCT_FLD(old_name,		""),
5185 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5186 
5187 #define IDX_BUFFER_PAGE_TABLE_NAME	11
5188 	{STRUCT_FLD(field_name,		"TABLE_NAME"),
5189 	 STRUCT_FLD(field_length,	1024),
5190 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5191 	 STRUCT_FLD(value,		0),
5192 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5193 	 STRUCT_FLD(old_name,		""),
5194 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5195 
5196 #define IDX_BUFFER_PAGE_INDEX_NAME	12
5197 	{STRUCT_FLD(field_name,		"INDEX_NAME"),
5198 	 STRUCT_FLD(field_length,	1024),
5199 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5200 	 STRUCT_FLD(value,		0),
5201 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5202 	 STRUCT_FLD(old_name,		""),
5203 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5204 
5205 #define IDX_BUFFER_PAGE_NUM_RECS	13
5206 	{STRUCT_FLD(field_name,		"NUMBER_RECORDS"),
5207 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5208 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5209 	 STRUCT_FLD(value,		0),
5210 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5211 	 STRUCT_FLD(old_name,		""),
5212 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5213 
5214 #define IDX_BUFFER_PAGE_DATA_SIZE	14
5215 	{STRUCT_FLD(field_name,		"DATA_SIZE"),
5216 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5217 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5218 	 STRUCT_FLD(value,		0),
5219 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5220 	 STRUCT_FLD(old_name,		""),
5221 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5222 
5223 #define IDX_BUFFER_PAGE_ZIP_SIZE	15
5224 	{STRUCT_FLD(field_name,		"COMPRESSED_SIZE"),
5225 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5226 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5227 	 STRUCT_FLD(value,		0),
5228 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5229 	 STRUCT_FLD(old_name,		""),
5230 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5231 
5232 #define IDX_BUFFER_PAGE_STATE		16
5233 	{STRUCT_FLD(field_name,		"PAGE_STATE"),
5234 	 STRUCT_FLD(field_length,	64),
5235 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5236 	 STRUCT_FLD(value,		0),
5237 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5238 	 STRUCT_FLD(old_name,		""),
5239 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5240 
5241 #define IDX_BUFFER_PAGE_IO_FIX		17
5242 	{STRUCT_FLD(field_name,		"IO_FIX"),
5243 	 STRUCT_FLD(field_length,	64),
5244 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5245 	 STRUCT_FLD(value,		0),
5246 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5247 	 STRUCT_FLD(old_name,		""),
5248 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5249 
5250 #define IDX_BUFFER_PAGE_IS_OLD		18
5251 	{STRUCT_FLD(field_name,		"IS_OLD"),
5252 	 STRUCT_FLD(field_length,	3),
5253 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5254 	 STRUCT_FLD(value,		0),
5255 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5256 	 STRUCT_FLD(old_name,		""),
5257 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5258 
5259 #define IDX_BUFFER_PAGE_FREE_CLOCK	19
5260 	{STRUCT_FLD(field_name,		"FREE_PAGE_CLOCK"),
5261 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5262 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5263 	 STRUCT_FLD(value,		0),
5264 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5265 	 STRUCT_FLD(old_name,		""),
5266 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5267 
5268 	END_OF_ST_FIELD_INFO
5269 };
5270 
5271 /*******************************************************************//**
5272 Fill Information Schema table INNODB_BUFFER_PAGE with information
5273 cached in the buf_page_info_t array
5274 @return 0 on success, 1 on failure */
5275 static
5276 int
i_s_innodb_buffer_page_fill(THD * thd,TABLE_LIST * tables,const buf_page_info_t * info_array,ulint num_page)5277 i_s_innodb_buffer_page_fill(
5278 /*========================*/
5279 	THD*			thd,		/*!< in: thread */
5280 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
5281 	const buf_page_info_t*	info_array,	/*!< in: array cached page
5282 						info */
5283 	ulint			num_page)	/*!< in: number of page info
5284 						cached */
5285 {
5286 	TABLE*			table;
5287 	Field**			fields;
5288 
5289 	DBUG_ENTER("i_s_innodb_buffer_page_fill");
5290 
5291 	table = tables->table;
5292 
5293 	fields = table->field;
5294 
5295 	/* Iterate through the cached array and fill the I_S table rows */
5296 	for (ulint i = 0; i < num_page; i++) {
5297 		const buf_page_info_t*	page_info;
5298 		char			table_name[MAX_FULL_NAME_LEN + 1];
5299 		const char*		table_name_end = NULL;
5300 		const char*		state_str;
5301 		enum buf_page_state	state;
5302 
5303 		page_info = info_array + i;
5304 
5305 		state_str = NULL;
5306 
5307 		OK(fields[IDX_BUFFER_POOL_ID]->store(
5308 			   page_info->pool_id, true));
5309 
5310 		OK(fields[IDX_BUFFER_BLOCK_ID]->store(
5311 			   page_info->block_id, true));
5312 
5313 		OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
5314 			   page_info->space_id, true));
5315 
5316 		OK(fields[IDX_BUFFER_PAGE_NUM]->store(
5317 			   page_info->page_num, true));
5318 
5319 		OK(field_store_string(
5320 			   fields[IDX_BUFFER_PAGE_TYPE],
5321 			   i_s_page_type[page_info->page_type].type_str));
5322 
5323 		OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store(
5324 			   page_info->flush_type));
5325 
5326 		OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
5327 			   page_info->fix_count));
5328 
5329 		if (page_info->hashed) {
5330 			OK(field_store_string(
5331 				   fields[IDX_BUFFER_PAGE_HASHED], "YES"));
5332 		} else {
5333 			OK(field_store_string(
5334 				   fields[IDX_BUFFER_PAGE_HASHED], "NO"));
5335 		}
5336 
5337 		OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
5338 			   page_info->newest_mod, true));
5339 
5340 		OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store(
5341 			   page_info->oldest_mod, true));
5342 
5343 		OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store(
5344 			   page_info->access_time));
5345 
5346 		fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_null();
5347 
5348 		fields[IDX_BUFFER_PAGE_INDEX_NAME]->set_null();
5349 
5350 		/* If this is an index page, fetch the index name
5351 		and table name */
5352 		if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
5353 			const dict_index_t*	index;
5354 
5355 			mutex_enter(&dict_sys->mutex);
5356 			index = dict_index_get_if_in_cache_low(
5357 				page_info->index_id);
5358 
5359 			if (index) {
5360 
5361 				table_name_end = innobase_convert_name(
5362 					table_name, sizeof(table_name),
5363 					index->table_name,
5364 					strlen(index->table_name),
5365 					thd);
5366 
5367 				OK(fields[IDX_BUFFER_PAGE_TABLE_NAME]->store(
5368 					table_name,
5369 					static_cast<size_t>(table_name_end - table_name),
5370 					system_charset_info));
5371 				fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_notnull();
5372 
5373 				OK(field_store_index_name(
5374 					fields[IDX_BUFFER_PAGE_INDEX_NAME],
5375 					index->name));
5376 			}
5377 
5378 			mutex_exit(&dict_sys->mutex);
5379 		}
5380 
5381 		OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store(
5382 			   page_info->num_recs, true));
5383 
5384 		OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store(
5385 			   page_info->data_size, true));
5386 
5387 		OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store(
5388 			   page_info->zip_ssize
5389 			   ? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
5390 			   : 0, true));
5391 
5392 #if BUF_PAGE_STATE_BITS > 3
5393 # error "BUF_PAGE_STATE_BITS > 3, please ensure that all 1<<BUF_PAGE_STATE_BITS values are checked for"
5394 #endif
5395 		state = static_cast<enum buf_page_state>(page_info->page_state);
5396 
5397 		switch (state) {
5398 		/* First three states are for compression pages and
5399 		are not states we would get as we scan pages through
5400 		buffer blocks */
5401 		case BUF_BLOCK_POOL_WATCH:
5402 		case BUF_BLOCK_ZIP_PAGE:
5403 		case BUF_BLOCK_ZIP_DIRTY:
5404 			state_str = NULL;
5405 			break;
5406 		case BUF_BLOCK_NOT_USED:
5407 			state_str = "NOT_USED";
5408 			break;
5409 		case BUF_BLOCK_READY_FOR_USE:
5410 			state_str = "READY_FOR_USE";
5411 			break;
5412 		case BUF_BLOCK_FILE_PAGE:
5413 			state_str = "FILE_PAGE";
5414 			break;
5415 		case BUF_BLOCK_MEMORY:
5416 			state_str = "MEMORY";
5417 			break;
5418 		case BUF_BLOCK_REMOVE_HASH:
5419 			state_str = "REMOVE_HASH";
5420 			break;
5421 		};
5422 
5423 		OK(field_store_string(fields[IDX_BUFFER_PAGE_STATE],
5424 				      state_str));
5425 
5426 		switch (page_info->io_fix) {
5427 		case BUF_IO_NONE:
5428 			OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX],
5429 					      "IO_NONE"));
5430 			break;
5431 		case BUF_IO_READ:
5432 			OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX],
5433 					      "IO_READ"));
5434 			break;
5435 		case BUF_IO_WRITE:
5436 			OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX],
5437 					      "IO_WRITE"));
5438 			break;
5439 		case BUF_IO_PIN:
5440 			OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX],
5441 					      "IO_PIN"));
5442 			break;
5443 		}
5444 
5445 		OK(field_store_string(fields[IDX_BUFFER_PAGE_IS_OLD],
5446 				      (page_info->is_old) ? "YES" : "NO"));
5447 
5448 		OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store(
5449 			   page_info->freed_page_clock, true));
5450 
5451 		if (schema_table_store_record(thd, table)) {
5452 			DBUG_RETURN(1);
5453 		}
5454 	}
5455 
5456 	DBUG_RETURN(0);
5457 }
5458 
5459 /*******************************************************************//**
5460 Set appropriate page type to a buf_page_info_t structure */
5461 static
5462 void
i_s_innodb_set_page_type(buf_page_info_t * page_info,ulint page_type,const byte * frame)5463 i_s_innodb_set_page_type(
5464 /*=====================*/
5465 	buf_page_info_t*page_info,	/*!< in/out: structure to fill with
5466 					scanned info */
5467 	ulint		page_type,	/*!< in: page type */
5468 	const byte*	frame)		/*!< in: buffer frame */
5469 {
5470 	if (fil_page_type_is_index(page_type)) {
5471 		const page_t*	page = (const page_t*) frame;
5472 
5473 		page_info->index_id = btr_page_get_index_id(page);
5474 
5475 		/* FIL_PAGE_INDEX and FIL_PAGE_RTREE are a bit special,
5476 		their values are defined as 17855 and 17854, so we cannot
5477 		use them to index into i_s_page_type[] array, its array index
5478 		in the i_s_page_type[] array is I_S_PAGE_TYPE_INDEX
5479 		(1) for index pages or I_S_PAGE_TYPE_IBUF for
5480 		change buffer index pages */
5481 		if (page_info->index_id
5482 		    == static_cast<index_id_t>(DICT_IBUF_ID_MIN
5483 					       + IBUF_SPACE_ID)) {
5484 			page_info->page_type = I_S_PAGE_TYPE_IBUF;
5485 		} else if (page_type == FIL_PAGE_RTREE) {
5486 			page_info->page_type = I_S_PAGE_TYPE_RTREE;
5487 		} else {
5488 			page_info->page_type = I_S_PAGE_TYPE_INDEX;
5489 		}
5490 
5491 		page_info->data_size = (ulint)(page_header_get_field(
5492 			page, PAGE_HEAP_TOP) - (page_is_comp(page)
5493 						? PAGE_NEW_SUPREMUM_END
5494 						: PAGE_OLD_SUPREMUM_END)
5495 			- page_header_get_field(page, PAGE_GARBAGE));
5496 
5497 		page_info->num_recs = page_get_n_recs(page);
5498 	} else if (page_type > FIL_PAGE_TYPE_LAST) {
5499 		/* Encountered an unknown page type */
5500 		page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
5501 	} else {
5502 		/* Make sure we get the right index into the
5503 		i_s_page_type[] array */
5504 		ut_a(page_type == i_s_page_type[page_type].type_value);
5505 
5506 		page_info->page_type = page_type;
5507 	}
5508 
5509 	if (page_info->page_type == FIL_PAGE_TYPE_ZBLOB
5510 	    || page_info->page_type == FIL_PAGE_TYPE_ZBLOB2) {
5511 		page_info->page_num = mach_read_from_4(
5512 			frame + FIL_PAGE_OFFSET);
5513 		page_info->space_id = mach_read_from_4(
5514 			frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
5515 	}
5516 }
5517 /*******************************************************************//**
5518 Scans pages in the buffer cache, and collect their general information
5519 into the buf_page_info_t array which is zero-filled. So any fields
5520 that are not initialized in the function will default to 0 */
5521 static
5522 void
i_s_innodb_buffer_page_get_info(const buf_page_t * bpage,ulint pool_id,ulint pos,buf_page_info_t * page_info)5523 i_s_innodb_buffer_page_get_info(
5524 /*============================*/
5525 	const buf_page_t*bpage,		/*!< in: buffer pool page to scan */
5526 	ulint		pool_id,	/*!< in: buffer pool id */
5527 	ulint		pos,		/*!< in: buffer block position in
5528 					buffer pool or in the LRU list */
5529 	buf_page_info_t*page_info)	/*!< in: zero filled info structure;
5530 					out: structure filled with scanned
5531 					info */
5532 {
5533 	BPageMutex*	mutex = buf_page_get_mutex(bpage);
5534 
5535 	ut_ad(pool_id < MAX_BUFFER_POOLS);
5536 
5537 	page_info->pool_id = pool_id;
5538 
5539 	page_info->block_id = pos;
5540 
5541 	mutex_enter(mutex);
5542 
5543 	page_info->page_state = buf_page_get_state(bpage);
5544 
5545 	/* Only fetch information for buffers that map to a tablespace,
5546 	that is, buffer page with state BUF_BLOCK_ZIP_PAGE,
5547 	BUF_BLOCK_ZIP_DIRTY or BUF_BLOCK_FILE_PAGE */
5548 	if (buf_page_in_file(bpage)) {
5549 		const byte*	frame;
5550 		ulint		page_type;
5551 
5552 		page_info->space_id = bpage->id.space();
5553 
5554 		page_info->page_num = bpage->id.page_no();
5555 
5556 		page_info->flush_type = bpage->flush_type;
5557 
5558 		page_info->fix_count = bpage->buf_fix_count;
5559 
5560 		page_info->newest_mod = bpage->newest_modification;
5561 
5562 		page_info->oldest_mod = bpage->oldest_modification;
5563 
5564 		page_info->access_time = bpage->access_time;
5565 
5566 		page_info->zip_ssize = bpage->zip.ssize;
5567 
5568 		page_info->io_fix = bpage->io_fix;
5569 
5570 		page_info->is_old = bpage->old;
5571 
5572 		page_info->freed_page_clock = bpage->freed_page_clock;
5573 
5574 		switch (buf_page_get_io_fix(bpage)) {
5575 		case BUF_IO_NONE:
5576 		case BUF_IO_WRITE:
5577 		case BUF_IO_PIN:
5578 			break;
5579 		case BUF_IO_READ:
5580 			page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
5581 			mutex_exit(mutex);
5582 			return;
5583 		}
5584 
5585 		if (page_info->page_state == BUF_BLOCK_FILE_PAGE) {
5586 			const buf_block_t*block;
5587 
5588 			block = reinterpret_cast<const buf_block_t*>(bpage);
5589 			frame = block->frame;
5590 			/* Note: this may be a false positive, that
5591 			is, block->index will not always be set to
5592 			NULL when the last adaptive hash index
5593 			reference is dropped. */
5594 			page_info->hashed = (block->index != NULL);
5595 		} else {
5596 			ut_ad(page_info->zip_ssize);
5597 			frame = bpage->zip.data;
5598 		}
5599 
5600 		page_type = fil_page_get_type(frame);
5601 
5602 		i_s_innodb_set_page_type(page_info, page_type, frame);
5603 	} else {
5604 		page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
5605 	}
5606 
5607 	mutex_exit(mutex);
5608 }
5609 
5610 /*******************************************************************//**
5611 This is the function that goes through each block of the buffer pool
5612 and fetch information to information schema tables: INNODB_BUFFER_PAGE.
5613 @return 0 on success, 1 on failure */
5614 static
5615 int
i_s_innodb_fill_buffer_pool(THD * thd,TABLE_LIST * tables,buf_pool_t * buf_pool,const ulint pool_id)5616 i_s_innodb_fill_buffer_pool(
5617 /*========================*/
5618 	THD*			thd,		/*!< in: thread */
5619 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
5620 	buf_pool_t*		buf_pool,	/*!< in: buffer pool to scan */
5621 	const ulint		pool_id)	/*!< in: buffer pool id */
5622 {
5623 	int			status	= 0;
5624 	mem_heap_t*		heap;
5625 
5626 	DBUG_ENTER("i_s_innodb_fill_buffer_pool");
5627 
5628 	heap = mem_heap_create(10000);
5629 
5630 	/* Go through each chunk of buffer pool. Currently, we only
5631 	have one single chunk for each buffer pool */
5632 	for (ulint n = 0;
5633 	     n < ut_min(buf_pool->n_chunks, buf_pool->n_chunks_new); n++) {
5634 		const buf_block_t*	block;
5635 		ulint			n_blocks;
5636 		buf_page_info_t*	info_buffer;
5637 		ulint			num_page;
5638 		ulint			mem_size;
5639 		ulint			chunk_size;
5640 		ulint			num_to_process = 0;
5641 		ulint			block_id = 0;
5642 
5643 		/* Get buffer block of the nth chunk */
5644 		block = buf_get_nth_chunk_block(buf_pool, n, &chunk_size);
5645 		num_page = 0;
5646 
5647 		while (chunk_size > 0) {
5648 			/* we cache maximum MAX_BUF_INFO_CACHED number of
5649 			buffer page info */
5650 			num_to_process = ut_min(chunk_size,
5651 						MAX_BUF_INFO_CACHED);
5652 
5653 			mem_size = num_to_process * sizeof(buf_page_info_t);
5654 
5655 			/* For each chunk, we'll pre-allocate information
5656 			structures to cache the page information read from
5657 			the buffer pool */
5658 			info_buffer = (buf_page_info_t*) mem_heap_zalloc(
5659 				heap, mem_size);
5660 
5661 			/* GO through each block in the chunk */
5662 			for (n_blocks = num_to_process; n_blocks--; block++) {
5663 				i_s_innodb_buffer_page_get_info(
5664 					&block->page, pool_id, block_id,
5665 					info_buffer + num_page);
5666 				block_id++;
5667 				num_page++;
5668 			}
5669 
5670 			/* Fill in information schema table with information
5671 			just collected from the buffer chunk scan */
5672 			status = i_s_innodb_buffer_page_fill(
5673 				thd, tables, info_buffer,
5674 				num_page);
5675 
5676 			/* If something goes wrong, break and return */
5677 			if (status) {
5678 				break;
5679 			}
5680 
5681 			mem_heap_empty(heap);
5682 			chunk_size -= num_to_process;
5683 			num_page = 0;
5684 		}
5685 	}
5686 
5687 	mem_heap_free(heap);
5688 
5689 	DBUG_RETURN(status);
5690 }
5691 
5692 /*******************************************************************//**
5693 Fill page information for pages in InnoDB buffer pool to the
5694 dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
5695 @return 0 on success, 1 on failure */
5696 static
5697 int
i_s_innodb_buffer_page_fill_table(THD * thd,TABLE_LIST * tables,Item *)5698 i_s_innodb_buffer_page_fill_table(
5699 /*==============================*/
5700 	THD*		thd,		/*!< in: thread */
5701 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
5702 	Item*		)		/*!< in: condition (ignored) */
5703 {
5704 	int	status	= 0;
5705 
5706 	DBUG_ENTER("i_s_innodb_buffer_page_fill_table");
5707 
5708 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
5709 
5710 	/* deny access to user without PROCESS privilege */
5711 	if (check_global_access(thd, PROCESS_ACL)) {
5712 		DBUG_RETURN(0);
5713 	}
5714 
5715 	/* Walk through each buffer pool */
5716 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
5717 		buf_pool_t*	buf_pool;
5718 
5719 		buf_pool = buf_pool_from_array(i);
5720 
5721 		/* Fetch information from pages in this buffer pool,
5722 		and fill the corresponding I_S table */
5723 		status = i_s_innodb_fill_buffer_pool(thd, tables, buf_pool, i);
5724 
5725 		/* If something wrong, break and return */
5726 		if (status) {
5727 			break;
5728 		}
5729 	}
5730 
5731 	DBUG_RETURN(status);
5732 }
5733 
5734 /*******************************************************************//**
5735 Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE.
5736 @return 0 on success, 1 on failure */
5737 static
5738 int
i_s_innodb_buffer_page_init(void * p)5739 i_s_innodb_buffer_page_init(
5740 /*========================*/
5741 	void*	p)	/*!< in/out: table schema object */
5742 {
5743 	ST_SCHEMA_TABLE*	schema;
5744 
5745 	DBUG_ENTER("i_s_innodb_buffer_page_init");
5746 
5747 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
5748 
5749 	schema->fields_info = i_s_innodb_buffer_page_fields_info;
5750 	schema->fill_table = i_s_innodb_buffer_page_fill_table;
5751 
5752 	DBUG_RETURN(0);
5753 }
5754 
5755 struct st_mysql_plugin	i_s_innodb_buffer_page =
5756 {
5757 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
5758 	/* int */
5759 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
5760 
5761 	/* pointer to type-specific plugin descriptor */
5762 	/* void* */
5763 	STRUCT_FLD(info, &i_s_info),
5764 
5765 	/* plugin name */
5766 	/* const char* */
5767 	STRUCT_FLD(name, "INNODB_BUFFER_PAGE"),
5768 
5769 	/* plugin author (for SHOW PLUGINS) */
5770 	/* const char* */
5771 	STRUCT_FLD(author, plugin_author),
5772 
5773 	/* general descriptive text (for SHOW PLUGINS) */
5774 	/* const char* */
5775 	STRUCT_FLD(descr, "InnoDB Buffer Page Information"),
5776 
5777 	/* the plugin license (PLUGIN_LICENSE_XXX) */
5778 	/* int */
5779 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
5780 
5781 	/* the function to invoke when plugin is loaded */
5782 	/* int (*)(void*); */
5783 	STRUCT_FLD(init, i_s_innodb_buffer_page_init),
5784 
5785 	/* the function to invoke when plugin is unloaded */
5786 	/* int (*)(void*); */
5787 	STRUCT_FLD(deinit, i_s_common_deinit),
5788 
5789 	/* plugin version (for SHOW PLUGINS) */
5790 	/* unsigned int */
5791 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
5792 
5793 	/* struct st_mysql_show_var* */
5794 	STRUCT_FLD(status_vars, NULL),
5795 
5796 	/* struct st_mysql_sys_var** */
5797 	STRUCT_FLD(system_vars, NULL),
5798 
5799 	/* reserved for dependency checking */
5800 	/* void* */
5801 	STRUCT_FLD(__reserved1, NULL),
5802 
5803 	/* Plugin flags */
5804 	/* unsigned long */
5805 	STRUCT_FLD(flags, 0UL),
5806 };
5807 
5808 static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
5809 {
5810 #define IDX_BUF_LRU_POOL_ID		0
5811 	{STRUCT_FLD(field_name,		"POOL_ID"),
5812 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5813 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5814 	 STRUCT_FLD(value,		0),
5815 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5816 	 STRUCT_FLD(old_name,		""),
5817 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5818 
5819 #define IDX_BUF_LRU_POS			1
5820 	{STRUCT_FLD(field_name,		"LRU_POSITION"),
5821 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5822 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5823 	 STRUCT_FLD(value,		0),
5824 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5825 	 STRUCT_FLD(old_name,		""),
5826 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5827 
5828 #define IDX_BUF_LRU_PAGE_SPACE		2
5829 	{STRUCT_FLD(field_name,		"SPACE"),
5830 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5831 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5832 	 STRUCT_FLD(value,		0),
5833 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5834 	 STRUCT_FLD(old_name,		""),
5835 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5836 
5837 #define IDX_BUF_LRU_PAGE_NUM		3
5838 	{STRUCT_FLD(field_name,		"PAGE_NUMBER"),
5839 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5840 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5841 	 STRUCT_FLD(value,		0),
5842 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5843 	 STRUCT_FLD(old_name,		""),
5844 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5845 
5846 #define IDX_BUF_LRU_PAGE_TYPE		4
5847 	{STRUCT_FLD(field_name,		"PAGE_TYPE"),
5848 	 STRUCT_FLD(field_length,	64),
5849 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5850 	 STRUCT_FLD(value,		0),
5851 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5852 	 STRUCT_FLD(old_name,		""),
5853 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5854 
5855 #define IDX_BUF_LRU_PAGE_FLUSH_TYPE	5
5856 	{STRUCT_FLD(field_name,		"FLUSH_TYPE"),
5857 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5858 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5859 	 STRUCT_FLD(value,		0),
5860 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5861 	 STRUCT_FLD(old_name,		""),
5862 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5863 
5864 #define IDX_BUF_LRU_PAGE_FIX_COUNT	6
5865 	{STRUCT_FLD(field_name,		"FIX_COUNT"),
5866 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5867 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5868 	 STRUCT_FLD(value,		0),
5869 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5870 	 STRUCT_FLD(old_name,		""),
5871 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5872 
5873 #define IDX_BUF_LRU_PAGE_HASHED		7
5874 	{STRUCT_FLD(field_name,		"IS_HASHED"),
5875 	 STRUCT_FLD(field_length,	3),
5876 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5877 	 STRUCT_FLD(value,		0),
5878 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5879 	 STRUCT_FLD(old_name,		""),
5880 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5881 
5882 #define IDX_BUF_LRU_PAGE_NEWEST_MOD	8
5883 	{STRUCT_FLD(field_name,		"NEWEST_MODIFICATION"),
5884 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5885 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5886 	 STRUCT_FLD(value,		0),
5887 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5888 	 STRUCT_FLD(old_name,		""),
5889 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5890 
5891 #define IDX_BUF_LRU_PAGE_OLDEST_MOD	9
5892 	{STRUCT_FLD(field_name,		"OLDEST_MODIFICATION"),
5893 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5894 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5895 	 STRUCT_FLD(value,		0),
5896 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5897 	 STRUCT_FLD(old_name,		""),
5898 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5899 
5900 #define IDX_BUF_LRU_PAGE_ACCESS_TIME	10
5901 	{STRUCT_FLD(field_name,		"ACCESS_TIME"),
5902 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5903 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5904 	 STRUCT_FLD(value,		0),
5905 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5906 	 STRUCT_FLD(old_name,		""),
5907 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5908 
5909 #define IDX_BUF_LRU_PAGE_TABLE_NAME	11
5910 	{STRUCT_FLD(field_name,		"TABLE_NAME"),
5911 	 STRUCT_FLD(field_length,	1024),
5912 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5913 	 STRUCT_FLD(value,		0),
5914 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5915 	 STRUCT_FLD(old_name,		""),
5916 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5917 
5918 #define IDX_BUF_LRU_PAGE_INDEX_NAME	12
5919 	{STRUCT_FLD(field_name,		"INDEX_NAME"),
5920 	 STRUCT_FLD(field_length,	1024),
5921 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5922 	 STRUCT_FLD(value,		0),
5923 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5924 	 STRUCT_FLD(old_name,		""),
5925 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5926 
5927 #define IDX_BUF_LRU_PAGE_NUM_RECS	13
5928 	{STRUCT_FLD(field_name,		"NUMBER_RECORDS"),
5929 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5930 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5931 	 STRUCT_FLD(value,		0),
5932 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5933 	 STRUCT_FLD(old_name,		""),
5934 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5935 
5936 #define IDX_BUF_LRU_PAGE_DATA_SIZE	14
5937 	{STRUCT_FLD(field_name,		"DATA_SIZE"),
5938 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5939 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5940 	 STRUCT_FLD(value,		0),
5941 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5942 	 STRUCT_FLD(old_name,		""),
5943 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5944 
5945 #define IDX_BUF_LRU_PAGE_ZIP_SIZE	15
5946 	{STRUCT_FLD(field_name,		"COMPRESSED_SIZE"),
5947 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5948 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5949 	 STRUCT_FLD(value,		0),
5950 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5951 	 STRUCT_FLD(old_name,		""),
5952 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5953 
5954 #define IDX_BUF_LRU_PAGE_STATE		16
5955 	{STRUCT_FLD(field_name,		"COMPRESSED"),
5956 	 STRUCT_FLD(field_length,	3),
5957 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5958 	 STRUCT_FLD(value,		0),
5959 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5960 	 STRUCT_FLD(old_name,		""),
5961 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5962 
5963 #define IDX_BUF_LRU_PAGE_IO_FIX		17
5964 	{STRUCT_FLD(field_name,		"IO_FIX"),
5965 	 STRUCT_FLD(field_length,	64),
5966 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5967 	 STRUCT_FLD(value,		0),
5968 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5969 	 STRUCT_FLD(old_name,		""),
5970 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5971 
5972 #define IDX_BUF_LRU_PAGE_IS_OLD		18
5973 	{STRUCT_FLD(field_name,		"IS_OLD"),
5974 	 STRUCT_FLD(field_length,	3),
5975 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
5976 	 STRUCT_FLD(value,		0),
5977 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
5978 	 STRUCT_FLD(old_name,		""),
5979 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5980 
5981 #define IDX_BUF_LRU_PAGE_FREE_CLOCK	19
5982 	{STRUCT_FLD(field_name,		"FREE_PAGE_CLOCK"),
5983 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
5984 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
5985 	 STRUCT_FLD(value,		0),
5986 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
5987 	 STRUCT_FLD(old_name,		""),
5988 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
5989 
5990 	END_OF_ST_FIELD_INFO
5991 };
5992 
5993 /*******************************************************************//**
5994 Fill Information Schema table INNODB_BUFFER_PAGE_LRU with information
5995 cached in the buf_page_info_t array
5996 @return 0 on success, 1 on failure */
5997 static
5998 int
i_s_innodb_buf_page_lru_fill(THD * thd,TABLE_LIST * tables,const buf_page_info_t * info_array,ulint num_page)5999 i_s_innodb_buf_page_lru_fill(
6000 /*=========================*/
6001 	THD*			thd,		/*!< in: thread */
6002 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
6003 	const buf_page_info_t*	info_array,	/*!< in: array cached page
6004 						info */
6005 	ulint			num_page)	/*!< in: number of page info
6006 						 cached */
6007 {
6008 	TABLE*			table;
6009 	Field**			fields;
6010 	mem_heap_t*		heap;
6011 
6012 	DBUG_ENTER("i_s_innodb_buf_page_lru_fill");
6013 
6014 	table = tables->table;
6015 
6016 	fields = table->field;
6017 
6018 	heap = mem_heap_create(1000);
6019 
6020 	/* Iterate through the cached array and fill the I_S table rows */
6021 	for (ulint i = 0; i < num_page; i++) {
6022 		const buf_page_info_t*	page_info;
6023 		char			table_name[MAX_FULL_NAME_LEN + 1];
6024 		const char*		table_name_end = NULL;
6025 		const char*		state_str;
6026 		enum buf_page_state	state;
6027 
6028 		state_str = NULL;
6029 
6030 		page_info = info_array + i;
6031 
6032 		OK(fields[IDX_BUF_LRU_POOL_ID]->store(
6033 			   page_info->pool_id, true));
6034 
6035 		OK(fields[IDX_BUF_LRU_POS]->store(
6036 			   page_info->block_id, true));
6037 
6038 		OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
6039 			   page_info->space_id, true));
6040 
6041 		OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
6042 			   page_info->page_num, true));
6043 
6044 		OK(field_store_string(
6045 			   fields[IDX_BUF_LRU_PAGE_TYPE],
6046 			   i_s_page_type[page_info->page_type].type_str));
6047 
6048 		OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(
6049 			   page_info->flush_type, true));
6050 
6051 		OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
6052 			   page_info->fix_count, true));
6053 
6054 		if (page_info->hashed) {
6055 			OK(field_store_string(
6056 				   fields[IDX_BUF_LRU_PAGE_HASHED], "YES"));
6057 		} else {
6058 			OK(field_store_string(
6059 				   fields[IDX_BUF_LRU_PAGE_HASHED], "NO"));
6060 		}
6061 
6062 		OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
6063 			   page_info->newest_mod, true));
6064 
6065 		OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store(
6066 			   page_info->oldest_mod, true));
6067 
6068 		OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store(
6069 			   page_info->access_time, true));
6070 
6071 		fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_null();
6072 
6073 		fields[IDX_BUF_LRU_PAGE_INDEX_NAME]->set_null();
6074 
6075 		/* If this is an index page, fetch the index name
6076 		and table name */
6077 		if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
6078 			const dict_index_t*	index;
6079 
6080 			mutex_enter(&dict_sys->mutex);
6081 			index = dict_index_get_if_in_cache_low(
6082 				page_info->index_id);
6083 
6084 			if (index) {
6085 
6086 				table_name_end = innobase_convert_name(
6087 					table_name, sizeof(table_name),
6088 					index->table_name,
6089 					strlen(index->table_name),
6090 					thd);
6091 
6092 				OK(fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->store(
6093 					table_name,
6094 					static_cast<size_t>(table_name_end - table_name),
6095 					system_charset_info));
6096 				fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_notnull();
6097 
6098 				OK(field_store_index_name(
6099 					fields[IDX_BUF_LRU_PAGE_INDEX_NAME],
6100 					index->name));
6101 			}
6102 
6103 			mutex_exit(&dict_sys->mutex);
6104 		}
6105 
6106 		OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store(
6107 			   page_info->num_recs, true));
6108 
6109 		OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store(
6110 			   page_info->data_size, true));
6111 
6112 		OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store(
6113 			   page_info->zip_ssize ?
6114 			   512 << page_info->zip_ssize : 0, true));
6115 
6116 		state = static_cast<enum buf_page_state>(page_info->page_state);
6117 
6118 		switch (state) {
6119 		/* Compressed page */
6120 		case BUF_BLOCK_ZIP_PAGE:
6121 		case BUF_BLOCK_ZIP_DIRTY:
6122 			state_str = "YES";
6123 			break;
6124 		/* Uncompressed page */
6125 		case BUF_BLOCK_FILE_PAGE:
6126 			state_str = "NO";
6127 			break;
6128 		/* We should not see following states */
6129 		case BUF_BLOCK_POOL_WATCH:
6130 		case BUF_BLOCK_READY_FOR_USE:
6131 		case BUF_BLOCK_NOT_USED:
6132 		case BUF_BLOCK_MEMORY:
6133 		case BUF_BLOCK_REMOVE_HASH:
6134 			state_str = NULL;
6135 			break;
6136 		};
6137 
6138 		OK(field_store_string(fields[IDX_BUF_LRU_PAGE_STATE],
6139 				      state_str));
6140 
6141 		switch (page_info->io_fix) {
6142 		case BUF_IO_NONE:
6143 			OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX],
6144 					      "IO_NONE"));
6145 			break;
6146 		case BUF_IO_READ:
6147 			OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX],
6148 					      "IO_READ"));
6149 			break;
6150 		case BUF_IO_WRITE:
6151 			OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX],
6152 					      "IO_WRITE"));
6153 			break;
6154 		}
6155 
6156 		OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IS_OLD],
6157 				      (page_info->is_old) ? "YES" : "NO"));
6158 
6159 		OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store(
6160 			   page_info->freed_page_clock, true));
6161 
6162 		if (schema_table_store_record(thd, table)) {
6163 			mem_heap_free(heap);
6164 			DBUG_RETURN(1);
6165 		}
6166 
6167 		mem_heap_empty(heap);
6168 	}
6169 
6170 	mem_heap_free(heap);
6171 
6172 	DBUG_RETURN(0);
6173 }
6174 
6175 /*******************************************************************//**
6176 This is the function that goes through buffer pool's LRU list
6177 and fetch information to INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
6178 @return 0 on success, 1 on failure */
6179 static
6180 int
i_s_innodb_fill_buffer_lru(THD * thd,TABLE_LIST * tables,buf_pool_t * buf_pool,const ulint pool_id)6181 i_s_innodb_fill_buffer_lru(
6182 /*=======================*/
6183 	THD*			thd,		/*!< in: thread */
6184 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
6185 	buf_pool_t*		buf_pool,	/*!< in: buffer pool to scan */
6186 	const ulint		pool_id)	/*!< in: buffer pool id */
6187 {
6188 	int			status = 0;
6189 	buf_page_info_t*	info_buffer;
6190 	ulint			lru_pos = 0;
6191 	const buf_page_t*	bpage;
6192 	ulint			lru_len;
6193 
6194 	DBUG_ENTER("i_s_innodb_fill_buffer_lru");
6195 
6196 	/* Obtain buf_pool->LRU_list_mutex before allocate info_buffer, since
6197 	UT_LIST_GET_LEN(buf_pool->LRU) could change */
6198 	mutex_enter(&buf_pool->LRU_list_mutex);
6199 
6200 	lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
6201 
6202 	/* Print error message if malloc fail */
6203 	info_buffer = (buf_page_info_t*) my_malloc(PSI_INSTRUMENT_ME,
6204 		lru_len * sizeof *info_buffer, MYF(MY_WME));
6205 
6206 	if (!info_buffer) {
6207 		status = 1;
6208 		goto exit;
6209 	}
6210 
6211 	memset(info_buffer, 0, lru_len * sizeof *info_buffer);
6212 
6213 	/* Walk through Pool's LRU list and print the buffer page
6214 	information */
6215 	bpage = UT_LIST_GET_LAST(buf_pool->LRU);
6216 
6217 	while (bpage != NULL) {
6218 		/* Use the same function that collect buffer info for
6219 		INNODB_BUFFER_PAGE to get buffer page info */
6220 		i_s_innodb_buffer_page_get_info(bpage, pool_id, lru_pos,
6221 						(info_buffer + lru_pos));
6222 
6223 		bpage = UT_LIST_GET_PREV(LRU, bpage);
6224 
6225 		lru_pos++;
6226 	}
6227 
6228 	ut_ad(lru_pos == lru_len);
6229 	ut_ad(lru_pos == UT_LIST_GET_LEN(buf_pool->LRU));
6230 
6231 exit:
6232 	mutex_exit(&buf_pool->LRU_list_mutex);
6233 
6234 	if (info_buffer) {
6235 		status = i_s_innodb_buf_page_lru_fill(
6236 			thd, tables, info_buffer, lru_len);
6237 
6238 		my_free(info_buffer);
6239 	}
6240 
6241 	DBUG_RETURN(status);
6242 }
6243 
6244 /*******************************************************************//**
6245 Fill page information for pages in InnoDB buffer pool to the
6246 dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU
6247 @return 0 on success, 1 on failure */
6248 static
6249 int
i_s_innodb_buf_page_lru_fill_table(THD * thd,TABLE_LIST * tables,Item *)6250 i_s_innodb_buf_page_lru_fill_table(
6251 /*===============================*/
6252 	THD*		thd,		/*!< in: thread */
6253 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
6254 	Item*		)		/*!< in: condition (ignored) */
6255 {
6256 	int	status	= 0;
6257 
6258 	DBUG_ENTER("i_s_innodb_buf_page_lru_fill_table");
6259 
6260 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
6261 
6262 	/* deny access to any users that do not hold PROCESS_ACL */
6263 	if (check_global_access(thd, PROCESS_ACL)) {
6264 		DBUG_RETURN(0);
6265 	}
6266 
6267 	/* Walk through each buffer pool */
6268 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
6269 		buf_pool_t*	buf_pool;
6270 
6271 		buf_pool = buf_pool_from_array(i);
6272 
6273 		/* Fetch information from pages in this buffer pool's LRU list,
6274 		and fill the corresponding I_S table */
6275 		status = i_s_innodb_fill_buffer_lru(thd, tables, buf_pool, i);
6276 
6277 		/* If something wrong, break and return */
6278 		if (status) {
6279 			break;
6280 		}
6281 	}
6282 
6283 	DBUG_RETURN(status);
6284 }
6285 
6286 /*******************************************************************//**
6287 Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
6288 @return 0 on success, 1 on failure */
6289 static
6290 int
i_s_innodb_buffer_page_lru_init(void * p)6291 i_s_innodb_buffer_page_lru_init(
6292 /*============================*/
6293 	void*	p)	/*!< in/out: table schema object */
6294 {
6295 	ST_SCHEMA_TABLE*	schema;
6296 
6297 	DBUG_ENTER("i_s_innodb_buffer_page_lru_init");
6298 
6299 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
6300 
6301 	schema->fields_info = i_s_innodb_buf_page_lru_fields_info;
6302 	schema->fill_table = i_s_innodb_buf_page_lru_fill_table;
6303 
6304 	DBUG_RETURN(0);
6305 }
6306 
6307 struct st_mysql_plugin	i_s_innodb_buffer_page_lru =
6308 {
6309 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6310 	/* int */
6311 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
6312 
6313 	/* pointer to type-specific plugin descriptor */
6314 	/* void* */
6315 	STRUCT_FLD(info, &i_s_info),
6316 
6317 	/* plugin name */
6318 	/* const char* */
6319 	STRUCT_FLD(name, "INNODB_BUFFER_PAGE_LRU"),
6320 
6321 	/* plugin author (for SHOW PLUGINS) */
6322 	/* const char* */
6323 	STRUCT_FLD(author, plugin_author),
6324 
6325 	/* general descriptive text (for SHOW PLUGINS) */
6326 	/* const char* */
6327 	STRUCT_FLD(descr, "InnoDB Buffer Page in LRU"),
6328 
6329 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6330 	/* int */
6331 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
6332 
6333 	/* the function to invoke when plugin is loaded */
6334 	/* int (*)(void*); */
6335 	STRUCT_FLD(init, i_s_innodb_buffer_page_lru_init),
6336 
6337 	/* the function to invoke when plugin is unloaded */
6338 	/* int (*)(void*); */
6339 	STRUCT_FLD(deinit, i_s_common_deinit),
6340 
6341 	/* plugin version (for SHOW PLUGINS) */
6342 	/* unsigned int */
6343 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
6344 
6345 	/* struct st_mysql_show_var* */
6346 	STRUCT_FLD(status_vars, NULL),
6347 
6348 	/* struct st_mysql_sys_var** */
6349 	STRUCT_FLD(system_vars, NULL),
6350 
6351 	/* reserved for dependency checking */
6352 	/* void* */
6353 	STRUCT_FLD(__reserved1, NULL),
6354 
6355 	/* Plugin flags */
6356 	/* unsigned long */
6357 	STRUCT_FLD(flags, 0UL),
6358 };
6359 
6360 /*******************************************************************//**
6361 Unbind a dynamic INFORMATION_SCHEMA table.
6362 @return 0 on success */
6363 static
6364 int
i_s_common_deinit(void * p)6365 i_s_common_deinit(
6366 /*==============*/
6367 	void*	p)	/*!< in/out: table schema object */
6368 {
6369 	DBUG_ENTER("i_s_common_deinit");
6370 
6371 	/* Do nothing */
6372 
6373 	DBUG_RETURN(0);
6374 }
6375 
6376 /**  SYS_TABLES  ***************************************************/
6377 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
6378 static ST_FIELD_INFO	innodb_sys_tables_fields_info[] =
6379 {
6380 #define SYS_TABLES_ID			0
6381 	{STRUCT_FLD(field_name,		"TABLE_ID"),
6382 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6383 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6384 	 STRUCT_FLD(value,		0),
6385 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6386 	 STRUCT_FLD(old_name,		""),
6387 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6388 
6389 #define SYS_TABLES_NAME			1
6390 	{STRUCT_FLD(field_name,		"NAME"),
6391 	 STRUCT_FLD(field_length,	MAX_FULL_NAME_LEN + 1),
6392 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
6393 	 STRUCT_FLD(value,		0),
6394 	 STRUCT_FLD(field_flags,	0),
6395 	 STRUCT_FLD(old_name,		""),
6396 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6397 
6398 #define SYS_TABLES_FLAG			2
6399 	{STRUCT_FLD(field_name,		"FLAG"),
6400 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
6401 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
6402 	 STRUCT_FLD(value,		0),
6403 	 STRUCT_FLD(field_flags,	0),
6404 	 STRUCT_FLD(old_name,		""),
6405 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6406 
6407 #define SYS_TABLES_NUM_COLUMN		3
6408 	{STRUCT_FLD(field_name,		"N_COLS"),
6409 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
6410 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
6411 	 STRUCT_FLD(value,		0),
6412 	 STRUCT_FLD(field_flags,	0),
6413 	 STRUCT_FLD(old_name,		""),
6414 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6415 
6416 #define SYS_TABLES_SPACE		4
6417 	{STRUCT_FLD(field_name,		"SPACE"),
6418 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
6419 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
6420 	 STRUCT_FLD(value,		0),
6421 	 STRUCT_FLD(field_flags,	0),
6422 	 STRUCT_FLD(old_name,		""),
6423 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6424 
6425 #define SYS_TABLES_FILE_FORMAT		5
6426 	{STRUCT_FLD(field_name,		"FILE_FORMAT"),
6427 	 STRUCT_FLD(field_length,	10),
6428 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
6429 	 STRUCT_FLD(value,		0),
6430 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
6431 	 STRUCT_FLD(old_name,		""),
6432 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6433 
6434 #define SYS_TABLES_ROW_FORMAT		6
6435 	{STRUCT_FLD(field_name,		"ROW_FORMAT"),
6436 	 STRUCT_FLD(field_length,	12),
6437 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
6438 	 STRUCT_FLD(value,		0),
6439 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
6440 	 STRUCT_FLD(old_name,		""),
6441 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6442 
6443 #define SYS_TABLES_ZIP_PAGE_SIZE	7
6444 	{STRUCT_FLD(field_name,		"ZIP_PAGE_SIZE"),
6445 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
6446 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
6447 	 STRUCT_FLD(value,		0),
6448 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6449 	 STRUCT_FLD(old_name,		""),
6450 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6451 
6452 #define SYS_TABLES_SPACE_TYPE	8
6453 	{STRUCT_FLD(field_name,		"SPACE_TYPE"),
6454 	 STRUCT_FLD(field_length,	10),
6455 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
6456 	 STRUCT_FLD(value,		0),
6457 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
6458 	 STRUCT_FLD(old_name,		""),
6459 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6460 
6461 	END_OF_ST_FIELD_INFO
6462 };
6463 
6464 /**********************************************************************//**
6465 Populate information_schema.innodb_sys_tables table with information
6466 from SYS_TABLES.
6467 @return 0 on success */
6468 static
6469 int
i_s_dict_fill_sys_tables(THD * thd,dict_table_t * table,TABLE * table_to_fill)6470 i_s_dict_fill_sys_tables(
6471 /*=====================*/
6472 	THD*		thd,		/*!< in: thread */
6473 	dict_table_t*	table,		/*!< in: table */
6474 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
6475 {
6476 	Field**			fields;
6477 	ulint			compact = DICT_TF_GET_COMPACT(table->flags);
6478 	ulint			atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(
6479 								table->flags);
6480 	const page_size_t&	page_size = dict_tf_get_page_size(table->flags);
6481 	const char*		file_format;
6482 	const char*		row_format;
6483 	const char*		space_type;
6484 
6485 	file_format = trx_sys_file_format_id_to_name(atomic_blobs);
6486 	if (!compact) {
6487 		row_format = "Redundant";
6488 	} else if (!atomic_blobs) {
6489 		row_format = "Compact";
6490 	} else if (DICT_TF_GET_ZIP_SSIZE(table->flags)) {
6491 		row_format = "Compressed";
6492 	} else {
6493 		row_format = "Dynamic";
6494 	}
6495 
6496 	if (is_system_tablespace(table->space)) {
6497 		space_type = "System";
6498 	} else if (DICT_TF_HAS_SHARED_SPACE(table->flags)) {
6499 		space_type = "General";
6500 	} else {
6501 		space_type = "Single";
6502 	}
6503 
6504 	DBUG_ENTER("i_s_dict_fill_sys_tables");
6505 
6506 	fields = table_to_fill->field;
6507 
6508 	OK(fields[SYS_TABLES_ID]->store(longlong(table->id), TRUE));
6509 
6510 	OK(field_store_string(fields[SYS_TABLES_NAME], table->name.m_name));
6511 
6512 	OK(fields[SYS_TABLES_FLAG]->store(table->flags));
6513 
6514 	OK(fields[SYS_TABLES_NUM_COLUMN]->store(table->n_cols));
6515 
6516 	OK(fields[SYS_TABLES_SPACE]->store(table->space));
6517 
6518 	OK(field_store_string(fields[SYS_TABLES_FILE_FORMAT], file_format));
6519 
6520 	OK(field_store_string(fields[SYS_TABLES_ROW_FORMAT], row_format));
6521 
6522 	OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(page_size.is_compressed()
6523 						   ? page_size.physical()
6524 						   : 0, true));
6525 
6526 	OK(field_store_string(fields[SYS_TABLES_SPACE_TYPE], space_type));
6527 
6528 	OK(schema_table_store_record(thd, table_to_fill));
6529 
6530 	DBUG_RETURN(0);
6531 }
6532 /*******************************************************************//**
6533 Function to go through each record in SYS_TABLES table, and fill the
6534 information_schema.innodb_sys_tables table with related table information
6535 @return 0 on success */
6536 static
6537 int
i_s_sys_tables_fill_table(THD * thd,TABLE_LIST * tables,Item *)6538 i_s_sys_tables_fill_table(
6539 /*======================*/
6540 	THD*		thd,	/*!< in: thread */
6541 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
6542 	Item*		)	/*!< in: condition (not used) */
6543 {
6544 	btr_pcur_t	pcur;
6545 	const rec_t*	rec;
6546 	mem_heap_t*	heap;
6547 	mtr_t		mtr;
6548 
6549 	DBUG_ENTER("i_s_sys_tables_fill_table");
6550 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
6551 
6552 	/* deny access to user without PROCESS_ACL privilege */
6553 	if (check_global_access(thd, PROCESS_ACL)) {
6554 		DBUG_RETURN(0);
6555 	}
6556 
6557 	heap = mem_heap_create(1000);
6558 	mutex_enter(&dict_sys->mutex);
6559 	mtr_start(&mtr);
6560 
6561 	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
6562 
6563 	while (rec) {
6564 		const char*	err_msg;
6565 		dict_table_t*	table_rec;
6566 
6567 		/* Create and populate a dict_table_t structure with
6568 		information from SYS_TABLES row */
6569 		err_msg = dict_process_sys_tables_rec_and_mtr_commit(
6570 			heap, rec, &table_rec,
6571 			DICT_TABLE_LOAD_FROM_RECORD, &mtr);
6572 
6573 		mutex_exit(&dict_sys->mutex);
6574 
6575 		if (!err_msg) {
6576 			i_s_dict_fill_sys_tables(thd, table_rec, tables->table);
6577 		} else {
6578 			push_warning_printf(thd, Sql_condition::SL_WARNING,
6579 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6580 					    err_msg);
6581 		}
6582 
6583 		/* Since dict_process_sys_tables_rec_and_mtr_commit()
6584 		is called with DICT_TABLE_LOAD_FROM_RECORD, the table_rec
6585 		is created in dict_process_sys_tables_rec(), we will
6586 		need to free it */
6587 		if (table_rec) {
6588 			dict_mem_table_free(table_rec);
6589 		}
6590 
6591 		mem_heap_empty(heap);
6592 
6593 		/* Get the next record */
6594 		mutex_enter(&dict_sys->mutex);
6595 		mtr_start(&mtr);
6596 		rec = dict_getnext_system(&pcur, &mtr);
6597 	}
6598 
6599 	mtr_commit(&mtr);
6600 	mutex_exit(&dict_sys->mutex);
6601 	mem_heap_free(heap);
6602 
6603 	DBUG_RETURN(0);
6604 }
6605 
6606 /*******************************************************************//**
6607 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tables
6608 @return 0 on success */
6609 static
6610 int
innodb_sys_tables_init(void * p)6611 innodb_sys_tables_init(
6612 /*===================*/
6613 	void*	p)	/*!< in/out: table schema object */
6614 {
6615 	ST_SCHEMA_TABLE*	schema;
6616 
6617 	DBUG_ENTER("innodb_sys_tables_init");
6618 
6619 	schema = (ST_SCHEMA_TABLE*) p;
6620 
6621 	schema->fields_info = innodb_sys_tables_fields_info;
6622 	schema->fill_table = i_s_sys_tables_fill_table;
6623 
6624 	DBUG_RETURN(0);
6625 }
6626 
6627 struct st_mysql_plugin	i_s_innodb_sys_tables =
6628 {
6629 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6630 	/* int */
6631 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
6632 
6633 	/* pointer to type-specific plugin descriptor */
6634 	/* void* */
6635 	STRUCT_FLD(info, &i_s_info),
6636 
6637 	/* plugin name */
6638 	/* const char* */
6639 	STRUCT_FLD(name, "INNODB_SYS_TABLES"),
6640 
6641 	/* plugin author (for SHOW PLUGINS) */
6642 	/* const char* */
6643 	STRUCT_FLD(author, plugin_author),
6644 
6645 	/* general descriptive text (for SHOW PLUGINS) */
6646 	/* const char* */
6647 	STRUCT_FLD(descr, "InnoDB SYS_TABLES"),
6648 
6649 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6650 	/* int */
6651 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
6652 
6653 	/* the function to invoke when plugin is loaded */
6654 	/* int (*)(void*); */
6655 	STRUCT_FLD(init, innodb_sys_tables_init),
6656 
6657 	/* the function to invoke when plugin is unloaded */
6658 	/* int (*)(void*); */
6659 	STRUCT_FLD(deinit, i_s_common_deinit),
6660 
6661 	/* plugin version (for SHOW PLUGINS) */
6662 	/* unsigned int */
6663 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
6664 
6665 	/* struct st_mysql_show_var* */
6666 	STRUCT_FLD(status_vars, NULL),
6667 
6668 	/* struct st_mysql_sys_var** */
6669 	STRUCT_FLD(system_vars, NULL),
6670 
6671 	/* reserved for dependency checking */
6672 	/* void* */
6673 	STRUCT_FLD(__reserved1, NULL),
6674 
6675 	/* Plugin flags */
6676 	/* unsigned long */
6677 	STRUCT_FLD(flags, 0UL),
6678 };
6679 
6680 /**  SYS_TABLESTATS  ***********************************************/
6681 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
6682 static ST_FIELD_INFO	innodb_sys_tablestats_fields_info[] =
6683 {
6684 #define SYS_TABLESTATS_ID		0
6685 	{STRUCT_FLD(field_name,		"TABLE_ID"),
6686 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6687 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6688 	 STRUCT_FLD(value,		0),
6689 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6690 	 STRUCT_FLD(old_name,		""),
6691 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6692 
6693 #define SYS_TABLESTATS_NAME		1
6694 	{STRUCT_FLD(field_name,		"NAME"),
6695 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
6696 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
6697 	 STRUCT_FLD(value,		0),
6698 	 STRUCT_FLD(field_flags,	0),
6699 	 STRUCT_FLD(old_name,		""),
6700 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6701 
6702 #define SYS_TABLESTATS_INIT		2
6703 	{STRUCT_FLD(field_name,		"STATS_INITIALIZED"),
6704 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
6705 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
6706 	 STRUCT_FLD(value,		0),
6707 	 STRUCT_FLD(field_flags,	0),
6708 	 STRUCT_FLD(old_name,		""),
6709 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6710 
6711 #define SYS_TABLESTATS_NROW		3
6712 	{STRUCT_FLD(field_name,		"NUM_ROWS"),
6713 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6714 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6715 	 STRUCT_FLD(value,		0),
6716 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6717 	 STRUCT_FLD(old_name,		""),
6718 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6719 
6720 #define SYS_TABLESTATS_CLUST_SIZE	4
6721 	{STRUCT_FLD(field_name,		"CLUST_INDEX_SIZE"),
6722 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6723 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6724 	 STRUCT_FLD(value,		0),
6725 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6726 	 STRUCT_FLD(old_name,		""),
6727 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6728 
6729 #define SYS_TABLESTATS_INDEX_SIZE	5
6730 	{STRUCT_FLD(field_name,		"OTHER_INDEX_SIZE"),
6731 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6732 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6733 	 STRUCT_FLD(value,		0),
6734 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6735 	 STRUCT_FLD(old_name,		""),
6736 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6737 
6738 #define SYS_TABLESTATS_MODIFIED		6
6739 	{STRUCT_FLD(field_name,		"MODIFIED_COUNTER"),
6740 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6741 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6742 	 STRUCT_FLD(value,		0),
6743 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6744 	 STRUCT_FLD(old_name,		""),
6745 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6746 
6747 #define SYS_TABLESTATS_AUTONINC		7
6748 	{STRUCT_FLD(field_name,		"AUTOINC"),
6749 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
6750 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
6751 	 STRUCT_FLD(value,		0),
6752 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
6753 	 STRUCT_FLD(old_name,		""),
6754 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6755 
6756 #define SYS_TABLESTATS_TABLE_REF_COUNT	8
6757 	{STRUCT_FLD(field_name,		"REF_COUNT"),
6758 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
6759 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
6760 	 STRUCT_FLD(value,		0),
6761 	 STRUCT_FLD(field_flags,	0),
6762 	 STRUCT_FLD(old_name,		""),
6763 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
6764 
6765 	END_OF_ST_FIELD_INFO
6766 };
6767 
6768 /** Populate information_schema.innodb_sys_tablestats table with information
6769 from SYS_TABLES.
6770 @param[in]	thd		thread ID
6771 @param[in,out]	table		table
6772 @param[in]	ref_count	table reference count
6773 @param[in,out]	table_to_fill	fill this table
6774 @return 0 on success */
6775 static
6776 int
i_s_dict_fill_sys_tablestats(THD * thd,dict_table_t * table,ulint ref_count,TABLE * table_to_fill)6777 i_s_dict_fill_sys_tablestats(
6778 	THD*		thd,
6779 	dict_table_t*	table,
6780 	ulint		ref_count,
6781 	TABLE*		table_to_fill)
6782 {
6783 	Field**		fields;
6784 
6785 	DBUG_ENTER("i_s_dict_fill_sys_tablestats");
6786 
6787 	fields = table_to_fill->field;
6788 
6789 	OK(fields[SYS_TABLESTATS_ID]->store(longlong(table->id), TRUE));
6790 
6791 	OK(field_store_string(fields[SYS_TABLESTATS_NAME],
6792 			      table->name.m_name));
6793 
6794 	dict_table_stats_lock(table, RW_S_LATCH);
6795 
6796 	if (table->stat_initialized) {
6797 		OK(field_store_string(fields[SYS_TABLESTATS_INIT],
6798 				      "Initialized"));
6799 
6800 		OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows,
6801 						      true));
6802 
6803 		OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
6804 			   table->stat_clustered_index_size, true));
6805 
6806 		OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
6807 			   table->stat_sum_of_other_index_sizes, true));
6808 
6809 		OK(fields[SYS_TABLESTATS_MODIFIED]->store(
6810 			   table->stat_modified_counter, true));
6811 	} else {
6812 		OK(field_store_string(fields[SYS_TABLESTATS_INIT],
6813 				      "Uninitialized"));
6814 
6815 		OK(fields[SYS_TABLESTATS_NROW]->store(0, true));
6816 
6817 		OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true));
6818 
6819 		OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true));
6820 
6821 		OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true));
6822 	}
6823 
6824 	dict_table_stats_unlock(table, RW_S_LATCH);
6825 
6826 	OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true));
6827 
6828 	OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(ref_count, true));
6829 
6830 	OK(schema_table_store_record(thd, table_to_fill));
6831 
6832 	DBUG_RETURN(0);
6833 }
6834 
6835 /*******************************************************************//**
6836 Function to go through each record in SYS_TABLES table, and fill the
6837 information_schema.innodb_sys_tablestats table with table statistics
6838 related information
6839 @return 0 on success */
6840 static
6841 int
i_s_sys_tables_fill_table_stats(THD * thd,TABLE_LIST * tables,Item *)6842 i_s_sys_tables_fill_table_stats(
6843 /*============================*/
6844 	THD*		thd,	/*!< in: thread */
6845 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
6846 	Item*		)	/*!< in: condition (not used) */
6847 {
6848 	btr_pcur_t	pcur;
6849 	const rec_t*	rec;
6850 	mem_heap_t*	heap;
6851 	mtr_t		mtr;
6852 
6853 	DBUG_ENTER("i_s_sys_tables_fill_table_stats");
6854 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
6855 
6856 	/* deny access to user without PROCESS_ACL privilege */
6857 	if (check_global_access(thd, PROCESS_ACL)) {
6858 		DBUG_RETURN(0);
6859 	}
6860 
6861 	heap = mem_heap_create(1000);
6862 	mutex_enter(&dict_sys->mutex);
6863 	mtr_start(&mtr);
6864 
6865 	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
6866 
6867 	while (rec) {
6868 		const char*	err_msg;
6869 		dict_table_t*	table_rec;
6870 		ulint		ref_count = 0;
6871 
6872 		/* Fetch the dict_table_t structure corresponding to
6873 		this SYS_TABLES record */
6874 		err_msg = dict_process_sys_tables_rec_and_mtr_commit(
6875 			heap, rec, &table_rec,
6876 			DICT_TABLE_LOAD_FROM_CACHE, &mtr);
6877 
6878 		if (table_rec != NULL) {
6879 			ut_ad(err_msg == NULL);
6880 
6881 			ref_count = table_rec->get_ref_count();
6882 
6883 			/* Protect the dict_table_t object by incrementing
6884 			the reference count. */
6885 			table_rec->acquire();
6886 		}
6887 
6888 		mutex_exit(&dict_sys->mutex);
6889 
6890 		DBUG_EXECUTE_IF("test_sys_tablestats", {
6891 			if (strcmp("test/t1", table_rec->name.m_name) == 0 ) {
6892 				DEBUG_SYNC_C("dict_table_not_protected");
6893 			}});
6894 
6895 		if (table_rec != NULL) {
6896 			i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count,
6897 						     tables->table);
6898 		} else {
6899 			push_warning_printf(thd, Sql_condition::SL_WARNING,
6900 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6901 					    err_msg);
6902 		}
6903 
6904 		mem_heap_empty(heap);
6905 
6906 		/* Get the next record */
6907 		mutex_enter(&dict_sys->mutex);
6908 
6909 		if (table_rec != NULL) {
6910 			table_rec->release();
6911 		}
6912 
6913 		mtr_start(&mtr);
6914 		rec = dict_getnext_system(&pcur, &mtr);
6915 	}
6916 
6917 	mtr_commit(&mtr);
6918 	mutex_exit(&dict_sys->mutex);
6919 	mem_heap_free(heap);
6920 
6921 	DBUG_RETURN(0);
6922 }
6923 
6924 /*******************************************************************//**
6925 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tablestats
6926 @return 0 on success */
6927 static
6928 int
innodb_sys_tablestats_init(void * p)6929 innodb_sys_tablestats_init(
6930 /*=======================*/
6931 	void*	p)	/*!< in/out: table schema object */
6932 {
6933 	ST_SCHEMA_TABLE*	schema;
6934 
6935 	DBUG_ENTER("innodb_sys_tablestats_init");
6936 
6937 	schema = (ST_SCHEMA_TABLE*) p;
6938 
6939 	schema->fields_info = innodb_sys_tablestats_fields_info;
6940 	schema->fill_table = i_s_sys_tables_fill_table_stats;
6941 
6942 	DBUG_RETURN(0);
6943 }
6944 
6945 struct st_mysql_plugin	i_s_innodb_sys_tablestats =
6946 {
6947 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6948 	/* int */
6949 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
6950 
6951 	/* pointer to type-specific plugin descriptor */
6952 	/* void* */
6953 	STRUCT_FLD(info, &i_s_info),
6954 
6955 	/* plugin name */
6956 	/* const char* */
6957 	STRUCT_FLD(name, "INNODB_SYS_TABLESTATS"),
6958 
6959 	/* plugin author (for SHOW PLUGINS) */
6960 	/* const char* */
6961 	STRUCT_FLD(author, plugin_author),
6962 
6963 	/* general descriptive text (for SHOW PLUGINS) */
6964 	/* const char* */
6965 	STRUCT_FLD(descr, "InnoDB SYS_TABLESTATS"),
6966 
6967 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6968 	/* int */
6969 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
6970 
6971 	/* the function to invoke when plugin is loaded */
6972 	/* int (*)(void*); */
6973 	STRUCT_FLD(init, innodb_sys_tablestats_init),
6974 
6975 	/* the function to invoke when plugin is unloaded */
6976 	/* int (*)(void*); */
6977 	STRUCT_FLD(deinit, i_s_common_deinit),
6978 
6979 	/* plugin version (for SHOW PLUGINS) */
6980 	/* unsigned int */
6981 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
6982 
6983 	/* struct st_mysql_show_var* */
6984 	STRUCT_FLD(status_vars, NULL),
6985 
6986 	/* struct st_mysql_sys_var** */
6987 	STRUCT_FLD(system_vars, NULL),
6988 
6989 	/* reserved for dependency checking */
6990 	/* void* */
6991 	STRUCT_FLD(__reserved1, NULL),
6992 
6993 	/* Plugin flags */
6994 	/* unsigned long */
6995 	STRUCT_FLD(flags, 0UL),
6996 };
6997 
6998 /**  SYS_INDEXES  **************************************************/
6999 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
7000 static ST_FIELD_INFO	innodb_sysindex_fields_info[] =
7001 {
7002 #define SYS_INDEX_ID		0
7003 	{STRUCT_FLD(field_name,		"INDEX_ID"),
7004 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
7005 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
7006 	 STRUCT_FLD(value,		0),
7007 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7008 	 STRUCT_FLD(old_name,		""),
7009 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7010 
7011 #define SYS_INDEX_NAME		1
7012 	{STRUCT_FLD(field_name,		"NAME"),
7013 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
7014 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
7015 	 STRUCT_FLD(value,		0),
7016 	 STRUCT_FLD(field_flags,	0),
7017 	 STRUCT_FLD(old_name,		""),
7018 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7019 
7020 #define SYS_INDEX_TABLE_ID	2
7021 	{STRUCT_FLD(field_name,		"TABLE_ID"),
7022 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
7023 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
7024 	 STRUCT_FLD(value,		0),
7025 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7026 	 STRUCT_FLD(old_name,		""),
7027 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7028 
7029 #define SYS_INDEX_TYPE		3
7030 	{STRUCT_FLD(field_name,		"TYPE"),
7031 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7032 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7033 	 STRUCT_FLD(value,		0),
7034 	 STRUCT_FLD(field_flags,	0),
7035 	 STRUCT_FLD(old_name,		""),
7036 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7037 
7038 #define SYS_INDEX_NUM_FIELDS	4
7039 	{STRUCT_FLD(field_name,		"N_FIELDS"),
7040 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7041 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7042 	 STRUCT_FLD(value,		0),
7043 	 STRUCT_FLD(field_flags,	0),
7044 	 STRUCT_FLD(old_name,		""),
7045 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7046 
7047 #define SYS_INDEX_PAGE_NO	5
7048 	{STRUCT_FLD(field_name,		"PAGE_NO"),
7049 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7050 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7051 	 STRUCT_FLD(value,		0),
7052 	 STRUCT_FLD(field_flags,	0),
7053 	 STRUCT_FLD(old_name,		""),
7054 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7055 
7056 #define SYS_INDEX_SPACE		6
7057 	{STRUCT_FLD(field_name,		"SPACE"),
7058 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7059 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7060 	 STRUCT_FLD(value,		0),
7061 	 STRUCT_FLD(field_flags,	0),
7062 	 STRUCT_FLD(old_name,		""),
7063 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7064 
7065 #define SYS_INDEX_MERGE_THRESHOLD 7
7066 	{STRUCT_FLD(field_name,		"MERGE_THRESHOLD"),
7067 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7068 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7069 	 STRUCT_FLD(value,		0),
7070 	 STRUCT_FLD(field_flags,	0),
7071 	 STRUCT_FLD(old_name,		""),
7072 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7073 
7074 	END_OF_ST_FIELD_INFO
7075 };
7076 
7077 /**********************************************************************//**
7078 Function to populate the information_schema.innodb_sys_indexes table with
7079 collected index information
7080 @return 0 on success */
7081 static
7082 int
i_s_dict_fill_sys_indexes(THD * thd,table_id_t table_id,dict_index_t * index,TABLE * table_to_fill)7083 i_s_dict_fill_sys_indexes(
7084 /*======================*/
7085 	THD*		thd,		/*!< in: thread */
7086 	table_id_t	table_id,	/*!< in: table id */
7087 	dict_index_t*	index,		/*!< in: populated dict_index_t
7088 					struct with index info */
7089 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
7090 {
7091 	Field**		fields;
7092 
7093 	DBUG_ENTER("i_s_dict_fill_sys_indexes");
7094 
7095 	fields = table_to_fill->field;
7096 
7097 	OK(field_store_index_name(fields[SYS_INDEX_NAME], index->name));
7098 
7099 	OK(fields[SYS_INDEX_ID]->store(longlong(index->id), true));
7100 
7101 	OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), true));
7102 
7103 	OK(fields[SYS_INDEX_TYPE]->store(index->type));
7104 
7105 	OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields));
7106 
7107 	/* FIL_NULL is ULINT32_UNDEFINED */
7108 	if (index->page == FIL_NULL) {
7109 		OK(fields[SYS_INDEX_PAGE_NO]->store(-1));
7110 	} else {
7111 		OK(fields[SYS_INDEX_PAGE_NO]->store(index->page));
7112 	}
7113 
7114 	OK(fields[SYS_INDEX_SPACE]->store(index->space));
7115 
7116 	OK(fields[SYS_INDEX_MERGE_THRESHOLD]->store(index->merge_threshold));
7117 
7118 	OK(schema_table_store_record(thd, table_to_fill));
7119 
7120 	DBUG_RETURN(0);
7121 }
7122 /*******************************************************************//**
7123 Function to go through each record in SYS_INDEXES table, and fill the
7124 information_schema.innodb_sys_indexes table with related index information
7125 @return 0 on success */
7126 static
7127 int
i_s_sys_indexes_fill_table(THD * thd,TABLE_LIST * tables,Item *)7128 i_s_sys_indexes_fill_table(
7129 /*=======================*/
7130 	THD*		thd,	/*!< in: thread */
7131 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7132 	Item*		)	/*!< in: condition (not used) */
7133 {
7134 	btr_pcur_t		pcur;
7135 	const rec_t*		rec;
7136 	mem_heap_t*		heap;
7137 	mtr_t			mtr;
7138 
7139 	DBUG_ENTER("i_s_sys_indexes_fill_table");
7140 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
7141 
7142 	/* deny access to user without PROCESS_ACL privilege */
7143 	if (check_global_access(thd, PROCESS_ACL)) {
7144 		DBUG_RETURN(0);
7145 	}
7146 
7147 	heap = mem_heap_create(1000);
7148 	mutex_enter(&dict_sys->mutex);
7149 	mtr_start(&mtr);
7150 
7151 	/* Start scan the SYS_INDEXES table */
7152 	rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
7153 
7154 	/* Process each record in the table */
7155 	while (rec) {
7156 		const char*	err_msg;
7157 		table_id_t	table_id;
7158 		dict_index_t	index_rec;
7159 
7160 		/* Populate a dict_index_t structure with information from
7161 		a SYS_INDEXES row */
7162 		err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec,
7163 						       &table_id);
7164 
7165 		mtr_commit(&mtr);
7166 		mutex_exit(&dict_sys->mutex);
7167 
7168 		if (!err_msg) {
7169 			i_s_dict_fill_sys_indexes(thd, table_id, &index_rec,
7170 						 tables->table);
7171 		} else {
7172 			push_warning_printf(thd, Sql_condition::SL_WARNING,
7173 					    ER_CANT_FIND_SYSTEM_REC, "%s",
7174 					    err_msg);
7175 		}
7176 
7177 		mem_heap_empty(heap);
7178 
7179 		/* Get the next record */
7180 		mutex_enter(&dict_sys->mutex);
7181 		mtr_start(&mtr);
7182 		rec = dict_getnext_system(&pcur, &mtr);
7183 	}
7184 
7185 	mtr_commit(&mtr);
7186 	mutex_exit(&dict_sys->mutex);
7187 	mem_heap_free(heap);
7188 
7189 	DBUG_RETURN(0);
7190 }
7191 /*******************************************************************//**
7192 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_indexes
7193 @return 0 on success */
7194 static
7195 int
innodb_sys_indexes_init(void * p)7196 innodb_sys_indexes_init(
7197 /*====================*/
7198 	void*	p)	/*!< in/out: table schema object */
7199 {
7200 	ST_SCHEMA_TABLE*	schema;
7201 
7202 	DBUG_ENTER("innodb_sys_indexes_init");
7203 
7204 	schema = (ST_SCHEMA_TABLE*) p;
7205 
7206 	schema->fields_info = innodb_sysindex_fields_info;
7207 	schema->fill_table = i_s_sys_indexes_fill_table;
7208 
7209 	DBUG_RETURN(0);
7210 }
7211 
7212 struct st_mysql_plugin	i_s_innodb_sys_indexes =
7213 {
7214 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7215 	/* int */
7216 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
7217 
7218 	/* pointer to type-specific plugin descriptor */
7219 	/* void* */
7220 	STRUCT_FLD(info, &i_s_info),
7221 
7222 	/* plugin name */
7223 	/* const char* */
7224 	STRUCT_FLD(name, "INNODB_SYS_INDEXES"),
7225 
7226 	/* plugin author (for SHOW PLUGINS) */
7227 	/* const char* */
7228 	STRUCT_FLD(author, plugin_author),
7229 
7230 	/* general descriptive text (for SHOW PLUGINS) */
7231 	/* const char* */
7232 	STRUCT_FLD(descr, "InnoDB SYS_INDEXES"),
7233 
7234 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7235 	/* int */
7236 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
7237 
7238 	/* the function to invoke when plugin is loaded */
7239 	/* int (*)(void*); */
7240 	STRUCT_FLD(init, innodb_sys_indexes_init),
7241 
7242 	/* the function to invoke when plugin is unloaded */
7243 	/* int (*)(void*); */
7244 	STRUCT_FLD(deinit, i_s_common_deinit),
7245 
7246 	/* plugin version (for SHOW PLUGINS) */
7247 	/* unsigned int */
7248 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
7249 
7250 	/* struct st_mysql_show_var* */
7251 	STRUCT_FLD(status_vars, NULL),
7252 
7253 	/* struct st_mysql_sys_var** */
7254 	STRUCT_FLD(system_vars, NULL),
7255 
7256 	/* reserved for dependency checking */
7257 	/* void* */
7258 	STRUCT_FLD(__reserved1, NULL),
7259 
7260 	/* Plugin flags */
7261 	/* unsigned long */
7262 	STRUCT_FLD(flags, 0UL),
7263 };
7264 
7265 /**  SYS_COLUMNS  **************************************************/
7266 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_COLUMNS */
7267 static ST_FIELD_INFO	innodb_sys_columns_fields_info[] =
7268 {
7269 #define SYS_COLUMN_TABLE_ID		0
7270 	{STRUCT_FLD(field_name,		"TABLE_ID"),
7271 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
7272 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
7273 	 STRUCT_FLD(value,		0),
7274 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7275 	 STRUCT_FLD(old_name,		""),
7276 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7277 
7278 #define SYS_COLUMN_NAME		1
7279 	{STRUCT_FLD(field_name,		"NAME"),
7280 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
7281 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
7282 	 STRUCT_FLD(value,		0),
7283 	 STRUCT_FLD(field_flags,	0),
7284 	 STRUCT_FLD(old_name,		""),
7285 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7286 
7287 #define SYS_COLUMN_POSITION	2
7288 	{STRUCT_FLD(field_name,		"POS"),
7289 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
7290 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
7291 	 STRUCT_FLD(value,		0),
7292 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7293 	 STRUCT_FLD(old_name,		""),
7294 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7295 
7296 #define SYS_COLUMN_MTYPE		3
7297 	{STRUCT_FLD(field_name,		"MTYPE"),
7298 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7299 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7300 	 STRUCT_FLD(value,		0),
7301 	 STRUCT_FLD(field_flags,	0),
7302 	 STRUCT_FLD(old_name,		""),
7303 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7304 
7305 #define SYS_COLUMN__PRTYPE	4
7306 	{STRUCT_FLD(field_name,		"PRTYPE"),
7307 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7308 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7309 	 STRUCT_FLD(value,		0),
7310 	 STRUCT_FLD(field_flags,	0),
7311 	 STRUCT_FLD(old_name,		""),
7312 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7313 
7314 #define SYS_COLUMN_COLUMN_LEN	5
7315 	{STRUCT_FLD(field_name,		"LEN"),
7316 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7317 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7318 	 STRUCT_FLD(value,		0),
7319 	 STRUCT_FLD(field_flags,	0),
7320 	 STRUCT_FLD(old_name,		""),
7321 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7322 
7323 	END_OF_ST_FIELD_INFO
7324 };
7325 
7326 /**********************************************************************//**
7327 Function to populate the information_schema.innodb_sys_columns with
7328 related column information
7329 @return 0 on success */
7330 static
7331 int
i_s_dict_fill_sys_columns(THD * thd,table_id_t table_id,const char * col_name,dict_col_t * column,ulint nth_v_col,TABLE * table_to_fill)7332 i_s_dict_fill_sys_columns(
7333 /*======================*/
7334 	THD*		thd,		/*!< in: thread */
7335 	table_id_t	table_id,	/*!< in: table ID */
7336 	const char*	col_name,	/*!< in: column name */
7337 	dict_col_t*	column,		/*!< in: dict_col_t struct holding
7338 					more column information */
7339 	ulint		nth_v_col,	/*!< in: virtual column, its
7340 					sequence number (nth virtual col) */
7341 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
7342 {
7343 	Field**		fields;
7344 
7345 	DBUG_ENTER("i_s_dict_fill_sys_columns");
7346 
7347 	fields = table_to_fill->field;
7348 
7349 	OK(fields[SYS_COLUMN_TABLE_ID]->store((longlong)table_id, true));
7350 
7351 	OK(field_store_string(fields[SYS_COLUMN_NAME], col_name));
7352 
7353 	if (dict_col_is_virtual(column)) {
7354 		ulint	pos = dict_create_v_col_pos(nth_v_col, column->ind);
7355 		OK(fields[SYS_COLUMN_POSITION]->store(pos, true));
7356 	} else {
7357 		OK(fields[SYS_COLUMN_POSITION]->store(column->ind, true));
7358 	}
7359 
7360 	OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
7361 
7362 	OK(fields[SYS_COLUMN__PRTYPE]->store(column->prtype));
7363 
7364 	OK(fields[SYS_COLUMN_COLUMN_LEN]->store(column->len));
7365 
7366 	OK(schema_table_store_record(thd, table_to_fill));
7367 
7368 	DBUG_RETURN(0);
7369 }
7370 /*******************************************************************//**
7371 Function to fill information_schema.innodb_sys_columns with information
7372 collected by scanning SYS_COLUMNS table.
7373 @return 0 on success */
7374 static
7375 int
i_s_sys_columns_fill_table(THD * thd,TABLE_LIST * tables,Item *)7376 i_s_sys_columns_fill_table(
7377 /*=======================*/
7378 	THD*		thd,	/*!< in: thread */
7379 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7380 	Item*		)	/*!< in: condition (not used) */
7381 {
7382 	btr_pcur_t	pcur;
7383 	const rec_t*	rec;
7384 	const char*	col_name;
7385 	mem_heap_t*	heap;
7386 	mtr_t		mtr;
7387 
7388 	DBUG_ENTER("i_s_sys_columns_fill_table");
7389 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
7390 
7391 	/* deny access to user without PROCESS_ACL privilege */
7392 	if (check_global_access(thd, PROCESS_ACL)) {
7393 		DBUG_RETURN(0);
7394 	}
7395 
7396 	heap = mem_heap_create(1000);
7397 	mutex_enter(&dict_sys->mutex);
7398 	mtr_start(&mtr);
7399 
7400 	rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS);
7401 
7402 	while (rec) {
7403 		const char*	err_msg;
7404 		dict_col_t	column_rec;
7405 		table_id_t	table_id;
7406 		ulint		nth_v_col;
7407 
7408 		/* populate a dict_col_t structure with information from
7409 		a SYS_COLUMNS row */
7410 		err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec,
7411 						       &table_id, &col_name,
7412 						       &nth_v_col);
7413 
7414 		mtr_commit(&mtr);
7415 		mutex_exit(&dict_sys->mutex);
7416 
7417 		if (!err_msg) {
7418 			i_s_dict_fill_sys_columns(thd, table_id, col_name,
7419 						 &column_rec, nth_v_col,
7420 						 tables->table);
7421 		} else {
7422 			push_warning_printf(thd, Sql_condition::SL_WARNING,
7423 					    ER_CANT_FIND_SYSTEM_REC, "%s",
7424 					    err_msg);
7425 		}
7426 
7427 		mem_heap_empty(heap);
7428 
7429 		/* Get the next record */
7430 		mutex_enter(&dict_sys->mutex);
7431 		mtr_start(&mtr);
7432 		rec = dict_getnext_system(&pcur, &mtr);
7433 	}
7434 
7435 	mtr_commit(&mtr);
7436 	mutex_exit(&dict_sys->mutex);
7437 	mem_heap_free(heap);
7438 
7439 	DBUG_RETURN(0);
7440 }
7441 /*******************************************************************//**
7442 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns
7443 @return 0 on success */
7444 static
7445 int
innodb_sys_columns_init(void * p)7446 innodb_sys_columns_init(
7447 /*====================*/
7448 	void*	p)	/*!< in/out: table schema object */
7449 {
7450 	ST_SCHEMA_TABLE*	schema;
7451 
7452 	DBUG_ENTER("innodb_sys_columns_init");
7453 
7454 	schema = (ST_SCHEMA_TABLE*) p;
7455 
7456 	schema->fields_info = innodb_sys_columns_fields_info;
7457 	schema->fill_table = i_s_sys_columns_fill_table;
7458 
7459 	DBUG_RETURN(0);
7460 }
7461 
7462 struct st_mysql_plugin	i_s_innodb_sys_columns =
7463 {
7464 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7465 	/* int */
7466 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
7467 
7468 	/* pointer to type-specific plugin descriptor */
7469 	/* void* */
7470 	STRUCT_FLD(info, &i_s_info),
7471 
7472 	/* plugin name */
7473 	/* const char* */
7474 	STRUCT_FLD(name, "INNODB_SYS_COLUMNS"),
7475 
7476 	/* plugin author (for SHOW PLUGINS) */
7477 	/* const char* */
7478 	STRUCT_FLD(author, plugin_author),
7479 
7480 	/* general descriptive text (for SHOW PLUGINS) */
7481 	/* const char* */
7482 	STRUCT_FLD(descr, "InnoDB SYS_COLUMNS"),
7483 
7484 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7485 	/* int */
7486 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
7487 
7488 	/* the function to invoke when plugin is loaded */
7489 	/* int (*)(void*); */
7490 	STRUCT_FLD(init, innodb_sys_columns_init),
7491 
7492 	/* the function to invoke when plugin is unloaded */
7493 	/* int (*)(void*); */
7494 	STRUCT_FLD(deinit, i_s_common_deinit),
7495 
7496 	/* plugin version (for SHOW PLUGINS) */
7497 	/* unsigned int */
7498 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
7499 
7500 	/* struct st_mysql_show_var* */
7501 	STRUCT_FLD(status_vars, NULL),
7502 
7503 	/* struct st_mysql_sys_var** */
7504 	STRUCT_FLD(system_vars, NULL),
7505 
7506 	/* reserved for dependency checking */
7507 	/* void* */
7508 	STRUCT_FLD(__reserved1, NULL),
7509 
7510 	/* Plugin flags */
7511 	/* unsigned long */
7512 	STRUCT_FLD(flags, 0UL),
7513 };
7514 
7515 /**  SYS_VIRTUAL **************************************************/
7516 /** Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL */
7517 static ST_FIELD_INFO	innodb_sys_virtual_fields_info[] =
7518 {
7519 #define SYS_VIRTUAL_TABLE_ID		0
7520 	{STRUCT_FLD(field_name,		"TABLE_ID"),
7521 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
7522 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
7523 	 STRUCT_FLD(value,		0),
7524 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7525 	 STRUCT_FLD(old_name,		""),
7526 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7527 
7528 #define SYS_VIRTUAL_POS			1
7529 	{STRUCT_FLD(field_name,		"POS"),
7530 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7531 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7532 	 STRUCT_FLD(value,		0),
7533 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7534 	 STRUCT_FLD(old_name,		""),
7535 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7536 
7537 #define SYS_VIRTUAL_BASE_POS		2
7538 	{STRUCT_FLD(field_name,		"BASE_POS"),
7539 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7540 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7541 	 STRUCT_FLD(value,		0),
7542 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7543 	 STRUCT_FLD(old_name,		""),
7544 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7545 
7546 	END_OF_ST_FIELD_INFO
7547 };
7548 
7549 /** Function to populate the information_schema.innodb_sys_virtual with
7550 related information
7551 param[in]	thd		thread
7552 param[in]	table_id	table ID
7553 param[in]	pos		virtual column position
7554 param[in]	base_pos	base column position
7555 param[in,out]	table_to_fill	fill this table
7556 @return 0 on success */
7557 static
7558 int
i_s_dict_fill_sys_virtual(THD * thd,table_id_t table_id,ulint pos,ulint base_pos,TABLE * table_to_fill)7559 i_s_dict_fill_sys_virtual(
7560 	THD*		thd,
7561 	table_id_t	table_id,
7562 	ulint		pos,
7563 	ulint		base_pos,
7564 	TABLE*		table_to_fill)
7565 {
7566 	Field**		fields;
7567 
7568 	DBUG_ENTER("i_s_dict_fill_sys_virtual");
7569 
7570 	fields = table_to_fill->field;
7571 
7572 	OK(fields[SYS_VIRTUAL_TABLE_ID]->store(table_id, true));
7573 
7574 	OK(fields[SYS_VIRTUAL_POS]->store(pos, true));
7575 
7576 	OK(fields[SYS_VIRTUAL_BASE_POS]->store(base_pos, true));
7577 
7578 	OK(schema_table_store_record(thd, table_to_fill));
7579 
7580 	DBUG_RETURN(0);
7581 }
7582 
7583 /** Function to fill information_schema.innodb_sys_virtual with information
7584 collected by scanning SYS_VIRTUAL table.
7585 param[in]	thd		thread
7586 param[in,out]	tables		tables to fill
7587 param[in]	item		condition (not used)
7588 @return 0 on success */
7589 static
7590 int
i_s_sys_virtual_fill_table(THD * thd,TABLE_LIST * tables,Item *)7591 i_s_sys_virtual_fill_table(
7592 	THD*		thd,
7593 	TABLE_LIST*	tables,
7594 	Item*		)
7595 {
7596 	btr_pcur_t	pcur;
7597 	const rec_t*	rec;
7598 	ulint		pos;
7599 	ulint		base_pos;
7600 	mem_heap_t*	heap;
7601 	mtr_t		mtr;
7602 
7603 	DBUG_ENTER("i_s_sys_virtual_fill_table");
7604 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
7605 
7606 	/* deny access to user without PROCESS_ACL privilege */
7607 	if (check_global_access(thd, PROCESS_ACL)) {
7608 		DBUG_RETURN(0);
7609 	}
7610 
7611 	heap = mem_heap_create(1000);
7612 	mutex_enter(&dict_sys->mutex);
7613 	mtr_start(&mtr);
7614 
7615 	rec = dict_startscan_system(&pcur, &mtr, SYS_VIRTUAL);
7616 
7617 	while (rec) {
7618 		const char*	err_msg;
7619 		table_id_t	table_id;
7620 
7621 		/* populate a dict_col_t structure with information from
7622 		a SYS_VIRTUAL row */
7623 		err_msg = dict_process_sys_virtual_rec(heap, rec,
7624 						       &table_id, &pos,
7625 						       &base_pos);
7626 
7627 		mtr_commit(&mtr);
7628 		mutex_exit(&dict_sys->mutex);
7629 
7630 		if (!err_msg) {
7631 			i_s_dict_fill_sys_virtual(thd, table_id, pos, base_pos,
7632 						  tables->table);
7633 		} else {
7634 			push_warning_printf(thd, Sql_condition::SL_WARNING,
7635 					    ER_CANT_FIND_SYSTEM_REC, "%s",
7636 					    err_msg);
7637 		}
7638 
7639 		mem_heap_empty(heap);
7640 
7641 		/* Get the next record */
7642 		mutex_enter(&dict_sys->mutex);
7643 		mtr_start(&mtr);
7644 		rec = dict_getnext_system(&pcur, &mtr);
7645 	}
7646 
7647 	mtr_commit(&mtr);
7648 	mutex_exit(&dict_sys->mutex);
7649 	mem_heap_free(heap);
7650 
7651 	DBUG_RETURN(0);
7652 }
7653 
7654 /** Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_virtual
7655 param[in,out]	p	table schema object
7656 @return 0 on success */
7657 static
7658 int
innodb_sys_virtual_init(void * p)7659 innodb_sys_virtual_init(
7660 	void*	p)
7661 {
7662 	ST_SCHEMA_TABLE*	schema;
7663 
7664 	DBUG_ENTER("innodb_sys_virtual_init");
7665 
7666 	schema = (ST_SCHEMA_TABLE*) p;
7667 
7668 	schema->fields_info = innodb_sys_virtual_fields_info;
7669 	schema->fill_table = i_s_sys_virtual_fill_table;
7670 
7671 	DBUG_RETURN(0);
7672 }
7673 
7674 struct st_mysql_plugin	i_s_innodb_sys_virtual =
7675 {
7676 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7677 	/* int */
7678 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
7679 
7680 	/* pointer to type-specific plugin descriptor */
7681 	/* void* */
7682 	STRUCT_FLD(info, &i_s_info),
7683 
7684 	/* plugin name */
7685 	/* const char* */
7686 	STRUCT_FLD(name, "INNODB_SYS_VIRTUAL"),
7687 
7688 	/* plugin author (for SHOW PLUGINS) */
7689 	/* const char* */
7690 	STRUCT_FLD(author, plugin_author),
7691 
7692 	/* general descriptive text (for SHOW PLUGINS) */
7693 	/* const char* */
7694 	STRUCT_FLD(descr, "InnoDB SYS_VIRTUAL"),
7695 
7696 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7697 	/* int */
7698 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
7699 
7700 	/* the function to invoke when plugin is loaded */
7701 	/* int (*)(void*); */
7702 	STRUCT_FLD(init, innodb_sys_virtual_init),
7703 
7704 	/* the function to invoke when plugin is unloaded */
7705 	/* int (*)(void*); */
7706 	STRUCT_FLD(deinit, i_s_common_deinit),
7707 
7708 	/* plugin version (for SHOW PLUGINS) */
7709 	/* unsigned int */
7710 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
7711 
7712 	/* struct st_mysql_show_var* */
7713 	STRUCT_FLD(status_vars, NULL),
7714 
7715 	/* struct st_mysql_sys_var** */
7716 	STRUCT_FLD(system_vars, NULL),
7717 
7718 	/* reserved for dependency checking */
7719 	/* void* */
7720 	STRUCT_FLD(__reserved1, NULL),
7721 
7722 	/* Plugin flags */
7723 	/* unsigned long */
7724 	STRUCT_FLD(flags, 0UL),
7725 };
7726 /**  SYS_FIELDS  ***************************************************/
7727 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FIELDS */
7728 static ST_FIELD_INFO	innodb_sys_fields_fields_info[] =
7729 {
7730 #define SYS_FIELD_INDEX_ID	0
7731 	{STRUCT_FLD(field_name,		"INDEX_ID"),
7732 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
7733 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
7734 	 STRUCT_FLD(value,		0),
7735 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7736 	 STRUCT_FLD(old_name,		""),
7737 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7738 
7739 #define SYS_FIELD_NAME		1
7740 	{STRUCT_FLD(field_name,		"NAME"),
7741 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
7742 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
7743 	 STRUCT_FLD(value,		0),
7744 	 STRUCT_FLD(field_flags,	0),
7745 	 STRUCT_FLD(old_name,		""),
7746 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7747 
7748 #define SYS_FIELD_POS		2
7749 	{STRUCT_FLD(field_name,		"POS"),
7750 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7751 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7752 	 STRUCT_FLD(value,		0),
7753 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7754 	 STRUCT_FLD(old_name,		""),
7755 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7756 
7757 	END_OF_ST_FIELD_INFO
7758 };
7759 
7760 /**********************************************************************//**
7761 Function to fill information_schema.innodb_sys_fields with information
7762 collected by scanning SYS_FIELDS table.
7763 @return 0 on success */
7764 static
7765 int
i_s_dict_fill_sys_fields(THD * thd,index_id_t index_id,dict_field_t * field,ulint pos,TABLE * table_to_fill)7766 i_s_dict_fill_sys_fields(
7767 /*=====================*/
7768 	THD*		thd,		/*!< in: thread */
7769 	index_id_t	index_id,	/*!< in: index id for the field */
7770 	dict_field_t*	field,		/*!< in: table */
7771 	ulint		pos,		/*!< in: Field position */
7772 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
7773 {
7774 	Field**		fields;
7775 
7776 	DBUG_ENTER("i_s_dict_fill_sys_fields");
7777 
7778 	fields = table_to_fill->field;
7779 
7780 	OK(fields[SYS_FIELD_INDEX_ID]->store(index_id, true));
7781 
7782 	OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
7783 
7784 	OK(fields[SYS_FIELD_POS]->store(pos, true));
7785 
7786 	OK(schema_table_store_record(thd, table_to_fill));
7787 
7788 	DBUG_RETURN(0);
7789 }
7790 /*******************************************************************//**
7791 Function to go through each record in SYS_FIELDS table, and fill the
7792 information_schema.innodb_sys_fields table with related index field
7793 information
7794 @return 0 on success */
7795 static
7796 int
i_s_sys_fields_fill_table(THD * thd,TABLE_LIST * tables,Item *)7797 i_s_sys_fields_fill_table(
7798 /*======================*/
7799 	THD*		thd,	/*!< in: thread */
7800 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7801 	Item*		)	/*!< in: condition (not used) */
7802 {
7803 	btr_pcur_t	pcur;
7804 	const rec_t*	rec;
7805 	mem_heap_t*	heap;
7806 	index_id_t	last_id;
7807 	mtr_t		mtr;
7808 
7809 	DBUG_ENTER("i_s_sys_fields_fill_table");
7810 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
7811 
7812 	/* deny access to user without PROCESS_ACL privilege */
7813 	if (check_global_access(thd, PROCESS_ACL)) {
7814 
7815 		DBUG_RETURN(0);
7816 	}
7817 
7818 	heap = mem_heap_create(1000);
7819 	mutex_enter(&dict_sys->mutex);
7820 	mtr_start(&mtr);
7821 
7822 	/* will save last index id so that we know whether we move to
7823 	the next index. This is used to calculate prefix length */
7824 	last_id = 0;
7825 
7826 	rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS);
7827 
7828 	while (rec) {
7829 		ulint		pos;
7830 		const char*	err_msg;
7831 		index_id_t	index_id;
7832 		dict_field_t	field_rec;
7833 
7834 		/* Populate a dict_field_t structure with information from
7835 		a SYS_FIELDS row */
7836 		err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
7837 						      &pos, &index_id, last_id);
7838 
7839 		mtr_commit(&mtr);
7840 		mutex_exit(&dict_sys->mutex);
7841 
7842 		if (!err_msg) {
7843 			i_s_dict_fill_sys_fields(thd, index_id, &field_rec,
7844 						 pos, tables->table);
7845 			last_id = index_id;
7846 		} else {
7847 			push_warning_printf(thd, Sql_condition::SL_WARNING,
7848 					    ER_CANT_FIND_SYSTEM_REC, "%s",
7849 					    err_msg);
7850 		}
7851 
7852 		mem_heap_empty(heap);
7853 
7854 		/* Get the next record */
7855 		mutex_enter(&dict_sys->mutex);
7856 		mtr_start(&mtr);
7857 		rec = dict_getnext_system(&pcur, &mtr);
7858 	}
7859 
7860 	mtr_commit(&mtr);
7861 	mutex_exit(&dict_sys->mutex);
7862 	mem_heap_free(heap);
7863 
7864 	DBUG_RETURN(0);
7865 }
7866 /*******************************************************************//**
7867 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_fields
7868 @return 0 on success */
7869 static
7870 int
innodb_sys_fields_init(void * p)7871 innodb_sys_fields_init(
7872 /*===================*/
7873 	void*   p)	/*!< in/out: table schema object */
7874 {
7875 	ST_SCHEMA_TABLE*	schema;
7876 
7877 	DBUG_ENTER("innodb_sys_field_init");
7878 
7879 	schema = (ST_SCHEMA_TABLE*) p;
7880 
7881 	schema->fields_info = innodb_sys_fields_fields_info;
7882 	schema->fill_table = i_s_sys_fields_fill_table;
7883 
7884 	DBUG_RETURN(0);
7885 }
7886 
7887 struct st_mysql_plugin	i_s_innodb_sys_fields =
7888 {
7889 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7890 	/* int */
7891 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
7892 
7893 	/* pointer to type-specific plugin descriptor */
7894 	/* void* */
7895 	STRUCT_FLD(info, &i_s_info),
7896 
7897 	/* plugin name */
7898 	/* const char* */
7899 	STRUCT_FLD(name, "INNODB_SYS_FIELDS"),
7900 
7901 	/* plugin author (for SHOW PLUGINS) */
7902 	/* const char* */
7903 	STRUCT_FLD(author, plugin_author),
7904 
7905 	/* general descriptive text (for SHOW PLUGINS) */
7906 	/* const char* */
7907 	STRUCT_FLD(descr, "InnoDB SYS_FIELDS"),
7908 
7909 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7910 	/* int */
7911 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
7912 
7913 	/* the function to invoke when plugin is loaded */
7914 	/* int (*)(void*); */
7915 	STRUCT_FLD(init, innodb_sys_fields_init),
7916 
7917 	/* the function to invoke when plugin is unloaded */
7918 	/* int (*)(void*); */
7919 	STRUCT_FLD(deinit, i_s_common_deinit),
7920 
7921 	/* plugin version (for SHOW PLUGINS) */
7922 	/* unsigned int */
7923 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
7924 
7925 	/* struct st_mysql_show_var* */
7926 	STRUCT_FLD(status_vars, NULL),
7927 
7928 	/* struct st_mysql_sys_var** */
7929 	STRUCT_FLD(system_vars, NULL),
7930 
7931 	/* reserved for dependency checking */
7932 	/* void* */
7933 	STRUCT_FLD(__reserved1, NULL),
7934 
7935 	/* Plugin flags */
7936 	/* unsigned long */
7937 	STRUCT_FLD(flags, 0UL),
7938 };
7939 
7940 /**  SYS_FOREIGN        ********************************************/
7941 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN */
7942 static ST_FIELD_INFO	innodb_sys_foreign_fields_info[] =
7943 {
7944 #define SYS_FOREIGN_ID		0
7945 	{STRUCT_FLD(field_name,		"ID"),
7946 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
7947 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
7948 	 STRUCT_FLD(value,		0),
7949 	 STRUCT_FLD(field_flags,	0),
7950 	 STRUCT_FLD(old_name,		""),
7951 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7952 
7953 #define SYS_FOREIGN_FOR_NAME	1
7954 	{STRUCT_FLD(field_name,		"FOR_NAME"),
7955 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
7956 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
7957 	 STRUCT_FLD(value,		0),
7958 	 STRUCT_FLD(field_flags,	0),
7959 	 STRUCT_FLD(old_name,		""),
7960 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7961 
7962 #define SYS_FOREIGN_REF_NAME	2
7963 	{STRUCT_FLD(field_name,		"REF_NAME"),
7964 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
7965 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
7966 	 STRUCT_FLD(value,		0),
7967 	 STRUCT_FLD(field_flags,	0),
7968 	 STRUCT_FLD(old_name,		""),
7969 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7970 
7971 #define SYS_FOREIGN_NUM_COL	3
7972 	{STRUCT_FLD(field_name,		"N_COLS"),
7973 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7974 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7975 	 STRUCT_FLD(value,		0),
7976 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7977 	 STRUCT_FLD(old_name,		""),
7978 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7979 
7980 #define SYS_FOREIGN_TYPE	4
7981 	{STRUCT_FLD(field_name,		"TYPE"),
7982 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
7983 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
7984 	 STRUCT_FLD(value,		0),
7985 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
7986 	 STRUCT_FLD(old_name,		""),
7987 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
7988 
7989 	END_OF_ST_FIELD_INFO
7990 };
7991 
7992 /**********************************************************************//**
7993 Function to fill information_schema.innodb_sys_foreign with information
7994 collected by scanning SYS_FOREIGN table.
7995 @return 0 on success */
7996 static
7997 int
i_s_dict_fill_sys_foreign(THD * thd,dict_foreign_t * foreign,TABLE * table_to_fill)7998 i_s_dict_fill_sys_foreign(
7999 /*======================*/
8000 	THD*		thd,		/*!< in: thread */
8001 	dict_foreign_t*	foreign,	/*!< in: table */
8002 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
8003 {
8004 	Field**		fields;
8005 
8006 	DBUG_ENTER("i_s_dict_fill_sys_foreign");
8007 
8008 	fields = table_to_fill->field;
8009 
8010 	OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id));
8011 
8012 	OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME],
8013 			      foreign->foreign_table_name));
8014 
8015 	OK(field_store_string(fields[SYS_FOREIGN_REF_NAME],
8016 			      foreign->referenced_table_name));
8017 
8018 	OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields));
8019 
8020 	OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type));
8021 
8022 	OK(schema_table_store_record(thd, table_to_fill));
8023 
8024 	DBUG_RETURN(0);
8025 }
8026 
8027 /*******************************************************************//**
8028 Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop
8029 through each record in SYS_FOREIGN, and extract the foreign key
8030 information.
8031 @return 0 on success */
8032 static
8033 int
i_s_sys_foreign_fill_table(THD * thd,TABLE_LIST * tables,Item *)8034 i_s_sys_foreign_fill_table(
8035 /*=======================*/
8036 	THD*		thd,	/*!< in: thread */
8037 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
8038 	Item*		)	/*!< in: condition (not used) */
8039 {
8040 	btr_pcur_t	pcur;
8041 	const rec_t*	rec;
8042 	mem_heap_t*	heap;
8043 	mtr_t		mtr;
8044 
8045 	DBUG_ENTER("i_s_sys_foreign_fill_table");
8046 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
8047 
8048 	/* deny access to user without PROCESS_ACL privilege */
8049 	if (check_global_access(thd, PROCESS_ACL)) {
8050 
8051 		DBUG_RETURN(0);
8052 	}
8053 
8054 	heap = mem_heap_create(1000);
8055 	mutex_enter(&dict_sys->mutex);
8056 	mtr_start(&mtr);
8057 
8058 	rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN);
8059 
8060 	while (rec) {
8061 		const char*	err_msg;
8062 		dict_foreign_t	foreign_rec;
8063 
8064 		/* Populate a dict_foreign_t structure with information from
8065 		a SYS_FOREIGN row */
8066 		err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
8067 
8068 		mtr_commit(&mtr);
8069 		mutex_exit(&dict_sys->mutex);
8070 
8071 		if (!err_msg) {
8072 			i_s_dict_fill_sys_foreign(thd, &foreign_rec,
8073 						 tables->table);
8074 		} else {
8075 			push_warning_printf(thd, Sql_condition::SL_WARNING,
8076 					    ER_CANT_FIND_SYSTEM_REC, "%s",
8077 					    err_msg);
8078 		}
8079 
8080 		mem_heap_empty(heap);
8081 
8082 		/* Get the next record */
8083 		mtr_start(&mtr);
8084 		mutex_enter(&dict_sys->mutex);
8085 		rec = dict_getnext_system(&pcur, &mtr);
8086 	}
8087 
8088 	mtr_commit(&mtr);
8089 	mutex_exit(&dict_sys->mutex);
8090 	mem_heap_free(heap);
8091 
8092 	DBUG_RETURN(0);
8093 }
8094 
8095 /*******************************************************************//**
8096 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign
8097 @return 0 on success */
8098 static
8099 int
innodb_sys_foreign_init(void * p)8100 innodb_sys_foreign_init(
8101 /*====================*/
8102 	void*   p)	/*!< in/out: table schema object */
8103 {
8104 	ST_SCHEMA_TABLE*	schema;
8105 
8106 	DBUG_ENTER("innodb_sys_foreign_init");
8107 
8108 	schema = (ST_SCHEMA_TABLE*) p;
8109 
8110 	schema->fields_info = innodb_sys_foreign_fields_info;
8111 	schema->fill_table = i_s_sys_foreign_fill_table;
8112 
8113 	DBUG_RETURN(0);
8114 }
8115 
8116 struct st_mysql_plugin	i_s_innodb_sys_foreign =
8117 {
8118 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
8119 	/* int */
8120 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
8121 
8122 	/* pointer to type-specific plugin descriptor */
8123 	/* void* */
8124 	STRUCT_FLD(info, &i_s_info),
8125 
8126 	/* plugin name */
8127 	/* const char* */
8128 	STRUCT_FLD(name, "INNODB_SYS_FOREIGN"),
8129 
8130 	/* plugin author (for SHOW PLUGINS) */
8131 	/* const char* */
8132 	STRUCT_FLD(author, plugin_author),
8133 
8134 	/* general descriptive text (for SHOW PLUGINS) */
8135 	/* const char* */
8136 	STRUCT_FLD(descr, "InnoDB SYS_FOREIGN"),
8137 
8138 	/* the plugin license (PLUGIN_LICENSE_XXX) */
8139 	/* int */
8140 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
8141 
8142 	/* the function to invoke when plugin is loaded */
8143 	/* int (*)(void*); */
8144 	STRUCT_FLD(init, innodb_sys_foreign_init),
8145 
8146 	/* the function to invoke when plugin is unloaded */
8147 	/* int (*)(void*); */
8148 	STRUCT_FLD(deinit, i_s_common_deinit),
8149 
8150 	/* plugin version (for SHOW PLUGINS) */
8151 	/* unsigned int */
8152 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
8153 
8154 	/* struct st_mysql_show_var* */
8155 	STRUCT_FLD(status_vars, NULL),
8156 
8157 	/* struct st_mysql_sys_var** */
8158 	STRUCT_FLD(system_vars, NULL),
8159 
8160 	/* reserved for dependency checking */
8161 	/* void* */
8162 	STRUCT_FLD(__reserved1, NULL),
8163 
8164 	/* Plugin flags */
8165 	/* unsigned long */
8166 	STRUCT_FLD(flags, 0UL),
8167 };
8168 
8169 /**  SYS_FOREIGN_COLS   ********************************************/
8170 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS */
8171 static ST_FIELD_INFO	innodb_sys_foreign_cols_fields_info[] =
8172 {
8173 #define SYS_FOREIGN_COL_ID		0
8174 	{STRUCT_FLD(field_name,		"ID"),
8175 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
8176 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8177 	 STRUCT_FLD(value,		0),
8178 	 STRUCT_FLD(field_flags,	0),
8179 	 STRUCT_FLD(old_name,		""),
8180 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8181 
8182 #define SYS_FOREIGN_COL_FOR_NAME	1
8183 	{STRUCT_FLD(field_name,		"FOR_COL_NAME"),
8184 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
8185 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8186 	 STRUCT_FLD(value,		0),
8187 	 STRUCT_FLD(field_flags,	0),
8188 	 STRUCT_FLD(old_name,		""),
8189 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8190 
8191 #define SYS_FOREIGN_COL_REF_NAME	2
8192 	{STRUCT_FLD(field_name,		"REF_COL_NAME"),
8193 	 STRUCT_FLD(field_length,	NAME_LEN + 1),
8194 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8195 	 STRUCT_FLD(value,		0),
8196 	 STRUCT_FLD(field_flags,	0),
8197 	 STRUCT_FLD(old_name,		""),
8198 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8199 
8200 #define SYS_FOREIGN_COL_POS		3
8201 	{STRUCT_FLD(field_name,		"POS"),
8202 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8203 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8204 	 STRUCT_FLD(value,		0),
8205 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8206 	 STRUCT_FLD(old_name,		""),
8207 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8208 
8209 	END_OF_ST_FIELD_INFO
8210 };
8211 
8212 /**********************************************************************//**
8213 Function to fill information_schema.innodb_sys_foreign_cols with information
8214 collected by scanning SYS_FOREIGN_COLS table.
8215 @return 0 on success */
8216 static
8217 int
i_s_dict_fill_sys_foreign_cols(THD * thd,const char * name,const char * for_col_name,const char * ref_col_name,ulint pos,TABLE * table_to_fill)8218 i_s_dict_fill_sys_foreign_cols(
8219 /*==========================*/
8220 	THD*		thd,		/*!< in: thread */
8221 	const char*	name,		/*!< in: foreign key constraint name */
8222 	const char*	for_col_name,	/*!< in: referencing column name*/
8223 	const char*	ref_col_name,	/*!< in: referenced column
8224 					name */
8225 	ulint		pos,		/*!< in: column position */
8226 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
8227 {
8228 	Field**		fields;
8229 
8230 	DBUG_ENTER("i_s_dict_fill_sys_foreign_cols");
8231 
8232 	fields = table_to_fill->field;
8233 
8234 	OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name));
8235 
8236 	OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name));
8237 
8238 	OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
8239 
8240 	OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true));
8241 
8242 	OK(schema_table_store_record(thd, table_to_fill));
8243 
8244 	DBUG_RETURN(0);
8245 }
8246 /*******************************************************************//**
8247 Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop
8248 through each record in SYS_FOREIGN_COLS, and extract the foreign key column
8249 information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table.
8250 @return 0 on success */
8251 static
8252 int
i_s_sys_foreign_cols_fill_table(THD * thd,TABLE_LIST * tables,Item *)8253 i_s_sys_foreign_cols_fill_table(
8254 /*============================*/
8255 	THD*		thd,	/*!< in: thread */
8256 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
8257 	Item*		)	/*!< in: condition (not used) */
8258 {
8259 	btr_pcur_t	pcur;
8260 	const rec_t*	rec;
8261 	mem_heap_t*	heap;
8262 	mtr_t		mtr;
8263 
8264 	DBUG_ENTER("i_s_sys_foreign_cols_fill_table");
8265 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
8266 
8267 	/* deny access to user without PROCESS_ACL privilege */
8268 	if (check_global_access(thd, PROCESS_ACL)) {
8269 		DBUG_RETURN(0);
8270 	}
8271 
8272 	heap = mem_heap_create(1000);
8273 	mutex_enter(&dict_sys->mutex);
8274 	mtr_start(&mtr);
8275 
8276 	rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS);
8277 
8278 	while (rec) {
8279 		const char*	err_msg;
8280 		const char*	name;
8281 		const char*	for_col_name;
8282 		const char*	ref_col_name;
8283 		ulint		pos;
8284 
8285 		/* Extract necessary information from a SYS_FOREIGN_COLS row */
8286 		err_msg = dict_process_sys_foreign_col_rec(
8287 			heap, rec, &name, &for_col_name, &ref_col_name, &pos);
8288 
8289 		mtr_commit(&mtr);
8290 		mutex_exit(&dict_sys->mutex);
8291 
8292 		if (!err_msg) {
8293 			i_s_dict_fill_sys_foreign_cols(
8294 				thd, name, for_col_name, ref_col_name, pos,
8295 				tables->table);
8296 		} else {
8297 			push_warning_printf(thd, Sql_condition::SL_WARNING,
8298 					    ER_CANT_FIND_SYSTEM_REC, "%s",
8299 					    err_msg);
8300 		}
8301 
8302 		mem_heap_empty(heap);
8303 
8304 		/* Get the next record */
8305 		mutex_enter(&dict_sys->mutex);
8306 		mtr_start(&mtr);
8307 		rec = dict_getnext_system(&pcur, &mtr);
8308 	}
8309 
8310 	mtr_commit(&mtr);
8311 	mutex_exit(&dict_sys->mutex);
8312 	mem_heap_free(heap);
8313 
8314 	DBUG_RETURN(0);
8315 }
8316 /*******************************************************************//**
8317 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols
8318 @return 0 on success */
8319 static
8320 int
innodb_sys_foreign_cols_init(void * p)8321 innodb_sys_foreign_cols_init(
8322 /*========================*/
8323 	void*	p)	/*!< in/out: table schema object */
8324 {
8325 	ST_SCHEMA_TABLE*	schema;
8326 
8327 	DBUG_ENTER("innodb_sys_foreign_cols_init");
8328 
8329 	schema = (ST_SCHEMA_TABLE*) p;
8330 
8331 	schema->fields_info = innodb_sys_foreign_cols_fields_info;
8332 	schema->fill_table = i_s_sys_foreign_cols_fill_table;
8333 
8334 	DBUG_RETURN(0);
8335 }
8336 
8337 struct st_mysql_plugin	i_s_innodb_sys_foreign_cols =
8338 {
8339 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
8340 	/* int */
8341 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
8342 
8343 	/* pointer to type-specific plugin descriptor */
8344 	/* void* */
8345 	STRUCT_FLD(info, &i_s_info),
8346 
8347 	/* plugin name */
8348 	/* const char* */
8349 	STRUCT_FLD(name, "INNODB_SYS_FOREIGN_COLS"),
8350 
8351 	/* plugin author (for SHOW PLUGINS) */
8352 	/* const char* */
8353 	STRUCT_FLD(author, plugin_author),
8354 
8355 	/* general descriptive text (for SHOW PLUGINS) */
8356 	/* const char* */
8357 	STRUCT_FLD(descr, "InnoDB SYS_FOREIGN_COLS"),
8358 
8359 	/* the plugin license (PLUGIN_LICENSE_XXX) */
8360 	/* int */
8361 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
8362 
8363 	/* the function to invoke when plugin is loaded */
8364 	/* int (*)(void*); */
8365 	STRUCT_FLD(init, innodb_sys_foreign_cols_init),
8366 
8367 	/* the function to invoke when plugin is unloaded */
8368 	/* int (*)(void*); */
8369 	STRUCT_FLD(deinit, i_s_common_deinit),
8370 
8371 	/* plugin version (for SHOW PLUGINS) */
8372 	/* unsigned int */
8373 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
8374 
8375 	/* struct st_mysql_show_var* */
8376 	STRUCT_FLD(status_vars, NULL),
8377 
8378 	/* struct st_mysql_sys_var** */
8379 	STRUCT_FLD(system_vars, NULL),
8380 
8381 	/* reserved for dependency checking */
8382 	/* void* */
8383 	STRUCT_FLD(__reserved1, NULL),
8384 
8385 	/* Plugin flags */
8386 	/* unsigned long */
8387 	STRUCT_FLD(flags, 0UL),
8388 };
8389 
8390 /**  SYS_TABLESPACES    ********************************************/
8391 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES */
8392 static ST_FIELD_INFO	innodb_sys_tablespaces_fields_info[] =
8393 {
8394 #define SYS_TABLESPACES_SPACE		0
8395 	{STRUCT_FLD(field_name,		"SPACE"),
8396 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8397 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8398 	 STRUCT_FLD(value,		0),
8399 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8400 	 STRUCT_FLD(old_name,		""),
8401 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8402 
8403 #define SYS_TABLESPACES_NAME		1
8404 	{STRUCT_FLD(field_name,		"NAME"),
8405 	 STRUCT_FLD(field_length,	MAX_FULL_NAME_LEN + 1),
8406 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8407 	 STRUCT_FLD(value,		0),
8408 	 STRUCT_FLD(field_flags,	0),
8409 	 STRUCT_FLD(old_name,		""),
8410 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8411 
8412 #define SYS_TABLESPACES_FLAGS		2
8413 	{STRUCT_FLD(field_name,		"FLAG"),
8414 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8415 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8416 	 STRUCT_FLD(value,		0),
8417 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8418 	 STRUCT_FLD(old_name,		""),
8419 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8420 
8421 #define SYS_TABLESPACES_FILE_FORMAT	3
8422 	{STRUCT_FLD(field_name,		"FILE_FORMAT"),
8423 	 STRUCT_FLD(field_length,	10),
8424 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8425 	 STRUCT_FLD(value,		0),
8426 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
8427 	 STRUCT_FLD(old_name,		""),
8428 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8429 
8430 #define SYS_TABLESPACES_ROW_FORMAT	4
8431 	{STRUCT_FLD(field_name,		"ROW_FORMAT"),
8432 	 STRUCT_FLD(field_length,	22),
8433 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8434 	 STRUCT_FLD(value,		0),
8435 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
8436 	 STRUCT_FLD(old_name,		""),
8437 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8438 
8439 #define SYS_TABLESPACES_PAGE_SIZE	5
8440 	{STRUCT_FLD(field_name,		"PAGE_SIZE"),
8441 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8442 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8443 	 STRUCT_FLD(value,		0),
8444 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8445 	 STRUCT_FLD(old_name,		""),
8446 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8447 
8448 #define SYS_TABLESPACES_ZIP_PAGE_SIZE	6
8449 	{STRUCT_FLD(field_name,		"ZIP_PAGE_SIZE"),
8450 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8451 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8452 	 STRUCT_FLD(value,		0),
8453 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8454 	 STRUCT_FLD(old_name,		""),
8455 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8456 
8457 #define SYS_TABLESPACES_SPACE_TYPE	7
8458 	{STRUCT_FLD(field_name,		"SPACE_TYPE"),
8459 	 STRUCT_FLD(field_length,	10),
8460 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8461 	 STRUCT_FLD(value,		0),
8462 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
8463 	 STRUCT_FLD(old_name,		""),
8464 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8465 
8466 #define SYS_TABLESPACES_FS_BLOCK_SIZE	8
8467 	{STRUCT_FLD(field_name,		"FS_BLOCK_SIZE"),
8468 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8469 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8470 	 STRUCT_FLD(value,		0),
8471 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8472 	 STRUCT_FLD(old_name,		""),
8473 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8474 
8475 #define SYS_TABLESPACES_FILE_SIZE	9
8476 	{STRUCT_FLD(field_name,		"FILE_SIZE"),
8477 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
8478 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
8479 	 STRUCT_FLD(value,		0),
8480 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8481 	 STRUCT_FLD(old_name,		""),
8482 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8483 
8484 #define SYS_TABLESPACES_ALLOC_SIZE	10
8485 	{STRUCT_FLD(field_name,		"ALLOCATED_SIZE"),
8486 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
8487 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
8488 	 STRUCT_FLD(value,		0),
8489 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8490 	 STRUCT_FLD(old_name,           ""),
8491 	 STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
8492 
8493 	END_OF_ST_FIELD_INFO
8494 
8495 };
8496 
8497 /**********************************************************************//**
8498 Function to fill INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES with information
8499 collected by scanning SYS_TABLESPACESS table.
8500 @return 0 on success */
8501 static
8502 int
i_s_dict_fill_sys_tablespaces(THD * thd,ulint space,const char * name,ulint flags,TABLE * table_to_fill)8503 i_s_dict_fill_sys_tablespaces(
8504 /*==========================*/
8505 	THD*		thd,		/*!< in: thread */
8506 	ulint		space,		/*!< in: space ID */
8507 	const char*	name,		/*!< in: tablespace name */
8508 	ulint		flags,		/*!< in: tablespace flags */
8509 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
8510 {
8511 	Field**		fields;
8512 	ulint		atomic_blobs = FSP_FLAGS_HAS_ATOMIC_BLOBS(flags);
8513 	bool		is_compressed = FSP_FLAGS_GET_ZIP_SSIZE(flags);
8514 	const char*	file_format;
8515 	const char*	row_format;
8516 	const page_size_t	page_size(flags);
8517 	const char*	space_type;
8518 
8519 	DBUG_ENTER("i_s_dict_fill_sys_tablespaces");
8520 
8521 	file_format = trx_sys_file_format_id_to_name(atomic_blobs);
8522 	if (is_system_tablespace(space)) {
8523 		row_format = "Compact or Redundant";
8524 	} else if (fsp_is_shared_tablespace(flags) && !is_compressed) {
8525 		file_format = "Any";
8526 		row_format = "Any";
8527 	} else if (is_compressed) {
8528 		row_format = "Compressed";
8529 	} else if (atomic_blobs) {
8530 		row_format = "Dynamic";
8531 	} else {
8532 		row_format = "Compact or Redundant";
8533 	}
8534 
8535 	if (is_system_tablespace(space)) {
8536 		space_type = "System";
8537 	} else if (fsp_is_shared_tablespace(flags)) {
8538 		space_type = "General";
8539 	} else  {
8540 		space_type = "Single";
8541 	}
8542 
8543 	fields = table_to_fill->field;
8544 
8545 	OK(fields[SYS_TABLESPACES_SPACE]->store(space, true));
8546 
8547 	OK(field_store_string(fields[SYS_TABLESPACES_NAME], name));
8548 
8549 	OK(fields[SYS_TABLESPACES_FLAGS]->store(flags, true));
8550 
8551 	OK(field_store_string(fields[SYS_TABLESPACES_FILE_FORMAT],
8552 			      file_format));
8553 
8554 	OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT], row_format));
8555 
8556 	OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(
8557 			univ_page_size.physical(), true));
8558 
8559 	OK(fields[SYS_TABLESPACES_ZIP_PAGE_SIZE]->store(
8560 				page_size.is_compressed()
8561 				? page_size.physical()
8562 				: 0, true));
8563 
8564 	OK(field_store_string(fields[SYS_TABLESPACES_SPACE_TYPE],
8565 			      space_type));
8566 
8567 	char*	filepath = NULL;
8568 	if (FSP_FLAGS_HAS_DATA_DIR(flags)
8569 	    || FSP_FLAGS_GET_SHARED(flags)) {
8570 		mutex_enter(&dict_sys->mutex);
8571 		filepath = dict_get_first_path(space);
8572 		mutex_exit(&dict_sys->mutex);
8573 	}
8574 
8575 	if (filepath == NULL) {
8576 		filepath = fil_make_filepath(NULL, name, IBD, false);
8577 	}
8578 
8579 	os_file_stat_t	stat;
8580 	os_file_size_t	file;
8581 
8582 	memset(&file, 0xff, sizeof(file));
8583 	memset(&stat, 0x0, sizeof(stat));
8584 
8585 	if (filepath != NULL) {
8586 
8587 		file = os_file_get_size(filepath);
8588 
8589 		/* Get the file system (or Volume) block size. */
8590 		dberr_t	err = os_file_get_status(filepath, &stat, false, false);
8591 
8592 		switch(err) {
8593 		case DB_FAIL:
8594 			ib::warn()
8595 				<< "File '" << filepath << "', failed to get "
8596 				<< "stats";
8597 			break;
8598 
8599 		case DB_SUCCESS:
8600 		case DB_NOT_FOUND:
8601 			break;
8602 
8603 		default:
8604 			ib::error()
8605 				<< "File '" << filepath << "' "
8606 				<< ut_strerr(err);
8607 			break;
8608 		}
8609 
8610 		ut_free(filepath);
8611 	}
8612 
8613 	if (file.m_total_size == static_cast<os_offset_t>(~0)) {
8614 		stat.block_size = 0;
8615 		file.m_total_size = 0;
8616 		file.m_alloc_size = 0;
8617 	}
8618 
8619 	OK(fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->store(stat.block_size, true));
8620 
8621 	OK(fields[SYS_TABLESPACES_FILE_SIZE]->store(file.m_total_size, true));
8622 
8623 	OK(fields[SYS_TABLESPACES_ALLOC_SIZE]->store(file.m_alloc_size, true));
8624 
8625 	OK(schema_table_store_record(thd, table_to_fill));
8626 
8627 	DBUG_RETURN(0);
8628 }
8629 
8630 /*******************************************************************//**
8631 Function to populate INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES table.
8632 Loop through each record in SYS_TABLESPACES, and extract the column
8633 information and fill the INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES table.
8634 @return 0 on success */
8635 static
8636 int
i_s_sys_tablespaces_fill_table(THD * thd,TABLE_LIST * tables,Item *)8637 i_s_sys_tablespaces_fill_table(
8638 /*===========================*/
8639 	THD*		thd,	/*!< in: thread */
8640 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
8641 	Item*		)	/*!< in: condition (not used) */
8642 {
8643 	btr_pcur_t	pcur;
8644 	const rec_t*	rec;
8645 	mem_heap_t*	heap;
8646 	mtr_t		mtr;
8647 
8648 	DBUG_ENTER("i_s_sys_tablespaces_fill_table");
8649 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
8650 
8651 	/* deny access to user without PROCESS_ACL privilege */
8652 	if (check_global_access(thd, PROCESS_ACL)) {
8653 		DBUG_RETURN(0);
8654 	}
8655 
8656 	heap = mem_heap_create(1000);
8657 	mutex_enter(&dict_sys->mutex);
8658 	mtr_start(&mtr);
8659 
8660 	for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES);
8661 	     rec != NULL;
8662 	     rec = dict_getnext_system(&pcur, &mtr)) {
8663 
8664 		const char*	err_msg;
8665 		ulint		space;
8666 		const char*	name;
8667 		ulint		flags;
8668 
8669 		/* Extract necessary information from a SYS_TABLESPACES row */
8670 		err_msg = dict_process_sys_tablespaces(
8671 			heap, rec, &space, &name, &flags);
8672 
8673 		mtr_commit(&mtr);
8674 		mutex_exit(&dict_sys->mutex);
8675 
8676 		if (!err_msg) {
8677 			i_s_dict_fill_sys_tablespaces(
8678 				thd, space, name, flags,
8679 				tables->table);
8680 		} else {
8681 			push_warning_printf(thd, Sql_condition::SL_WARNING,
8682 					    ER_CANT_FIND_SYSTEM_REC, "%s",
8683 					    err_msg);
8684 		}
8685 
8686 		mem_heap_empty(heap);
8687 
8688 		/* Get the next record */
8689 		mutex_enter(&dict_sys->mutex);
8690 		mtr_start(&mtr);
8691 	}
8692 
8693 	mtr_commit(&mtr);
8694 	mutex_exit(&dict_sys->mutex);
8695 	mem_heap_free(heap);
8696 
8697 	DBUG_RETURN(0);
8698 }
8699 /*******************************************************************//**
8700 Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
8701 @return 0 on success */
8702 static
8703 int
innodb_sys_tablespaces_init(void * p)8704 innodb_sys_tablespaces_init(
8705 /*========================*/
8706 	void*	p)	/*!< in/out: table schema object */
8707 {
8708 	ST_SCHEMA_TABLE*	schema;
8709 
8710 	DBUG_ENTER("innodb_sys_tablespaces_init");
8711 
8712 	schema = (ST_SCHEMA_TABLE*) p;
8713 
8714 	schema->fields_info = innodb_sys_tablespaces_fields_info;
8715 	schema->fill_table = i_s_sys_tablespaces_fill_table;
8716 
8717 	DBUG_RETURN(0);
8718 }
8719 
8720 struct st_mysql_plugin	i_s_innodb_sys_tablespaces =
8721 {
8722 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
8723 	/* int */
8724 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
8725 
8726 	/* pointer to type-specific plugin descriptor */
8727 	/* void* */
8728 	STRUCT_FLD(info, &i_s_info),
8729 
8730 	/* plugin name */
8731 	/* const char* */
8732 	STRUCT_FLD(name, "INNODB_SYS_TABLESPACES"),
8733 
8734 	/* plugin author (for SHOW PLUGINS) */
8735 	/* const char* */
8736 	STRUCT_FLD(author, plugin_author),
8737 
8738 	/* general descriptive text (for SHOW PLUGINS) */
8739 	/* const char* */
8740 	STRUCT_FLD(descr, "InnoDB SYS_TABLESPACES"),
8741 
8742 	/* the plugin license (PLUGIN_LICENSE_XXX) */
8743 	/* int */
8744 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
8745 
8746 	/* the function to invoke when plugin is loaded */
8747 	/* int (*)(void*); */
8748 	STRUCT_FLD(init, innodb_sys_tablespaces_init),
8749 
8750 	/* the function to invoke when plugin is unloaded */
8751 	/* int (*)(void*); */
8752 	STRUCT_FLD(deinit, i_s_common_deinit),
8753 
8754 	/* plugin version (for SHOW PLUGINS) */
8755 	/* unsigned int */
8756 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
8757 
8758 	/* struct st_mysql_show_var* */
8759 	STRUCT_FLD(status_vars, NULL),
8760 
8761 	/* struct st_mysql_sys_var** */
8762 	STRUCT_FLD(system_vars, NULL),
8763 
8764 	/* reserved for dependency checking */
8765 	/* void* */
8766 	STRUCT_FLD(__reserved1, NULL),
8767 
8768 	/* Plugin flags */
8769 	/* unsigned long */
8770 	STRUCT_FLD(flags, 0UL),
8771 };
8772 
8773 /**  SYS_DATAFILES  ************************************************/
8774 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_DATAFILES */
8775 static ST_FIELD_INFO	innodb_sys_datafiles_fields_info[] =
8776 {
8777 #define SYS_DATAFILES_SPACE		0
8778 	{STRUCT_FLD(field_name,		"SPACE"),
8779 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8780 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8781 	 STRUCT_FLD(value,		0),
8782 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8783 	 STRUCT_FLD(old_name,		""),
8784 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8785 
8786 #define SYS_DATAFILES_PATH		1
8787 	{STRUCT_FLD(field_name,		"PATH"),
8788 	 STRUCT_FLD(field_length,	OS_FILE_MAX_PATH),
8789 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
8790 	 STRUCT_FLD(value,		0),
8791 	 STRUCT_FLD(field_flags,	0),
8792 	 STRUCT_FLD(old_name,		""),
8793 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8794 
8795 	END_OF_ST_FIELD_INFO
8796 };
8797 
8798 /**********************************************************************//**
8799 Function to fill INFORMATION_SCHEMA.INNODB_SYS_DATAFILES with information
8800 collected by scanning SYS_DATAFILESS table.
8801 @return 0 on success */
8802 static
8803 int
i_s_dict_fill_sys_datafiles(THD * thd,ulint space,const char * path,TABLE * table_to_fill)8804 i_s_dict_fill_sys_datafiles(
8805 /*========================*/
8806 	THD*		thd,		/*!< in: thread */
8807 	ulint		space,		/*!< in: space ID */
8808 	const char*	path,		/*!< in: absolute path */
8809 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
8810 {
8811 	Field**		fields;
8812 
8813 	DBUG_ENTER("i_s_dict_fill_sys_datafiles");
8814 
8815 	fields = table_to_fill->field;
8816 
8817 	OK(field_store_ulint(fields[SYS_DATAFILES_SPACE], space));
8818 
8819 	OK(field_store_string(fields[SYS_DATAFILES_PATH], path));
8820 
8821 	OK(schema_table_store_record(thd, table_to_fill));
8822 
8823 	DBUG_RETURN(0);
8824 }
8825 /*******************************************************************//**
8826 Function to populate INFORMATION_SCHEMA.INNODB_SYS_DATAFILES table.
8827 Loop through each record in SYS_DATAFILES, and extract the column
8828 information and fill the INFORMATION_SCHEMA.INNODB_SYS_DATAFILES table.
8829 @return 0 on success */
8830 static
8831 int
i_s_sys_datafiles_fill_table(THD * thd,TABLE_LIST * tables,Item *)8832 i_s_sys_datafiles_fill_table(
8833 /*=========================*/
8834 	THD*		thd,	/*!< in: thread */
8835 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
8836 	Item*		)	/*!< in: condition (not used) */
8837 {
8838 	btr_pcur_t	pcur;
8839 	const rec_t*	rec;
8840 	mem_heap_t*	heap;
8841 	mtr_t		mtr;
8842 
8843 	DBUG_ENTER("i_s_sys_datafiles_fill_table");
8844 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
8845 
8846 	/* deny access to user without PROCESS_ACL privilege */
8847 	if (check_global_access(thd, PROCESS_ACL)) {
8848 		DBUG_RETURN(0);
8849 	}
8850 
8851 	heap = mem_heap_create(1000);
8852 	mutex_enter(&dict_sys->mutex);
8853 	mtr_start(&mtr);
8854 
8855 	rec = dict_startscan_system(&pcur, &mtr, SYS_DATAFILES);
8856 
8857 	while (rec) {
8858 		const char*	err_msg;
8859 		ulint		space;
8860 		const char*	path;
8861 
8862 		/* Extract necessary information from a SYS_DATAFILES row */
8863 		err_msg = dict_process_sys_datafiles(
8864 			heap, rec, &space, &path);
8865 
8866 		mtr_commit(&mtr);
8867 		mutex_exit(&dict_sys->mutex);
8868 
8869 		if (!err_msg) {
8870 			i_s_dict_fill_sys_datafiles(
8871 				thd, space, path, tables->table);
8872 		} else {
8873 			push_warning_printf(thd, Sql_condition::SL_WARNING,
8874 					    ER_CANT_FIND_SYSTEM_REC, "%s",
8875 					    err_msg);
8876 		}
8877 
8878 		mem_heap_empty(heap);
8879 
8880 		/* Get the next record */
8881 		mutex_enter(&dict_sys->mutex);
8882 		mtr_start(&mtr);
8883 		rec = dict_getnext_system(&pcur, &mtr);
8884 	}
8885 
8886 	mtr_commit(&mtr);
8887 	mutex_exit(&dict_sys->mutex);
8888 	mem_heap_free(heap);
8889 
8890 	DBUG_RETURN(0);
8891 }
8892 /*******************************************************************//**
8893 Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_DATAFILES
8894 @return 0 on success */
8895 static
8896 int
innodb_sys_datafiles_init(void * p)8897 innodb_sys_datafiles_init(
8898 /*======================*/
8899 	void*	p)	/*!< in/out: table schema object */
8900 {
8901 	ST_SCHEMA_TABLE*	schema;
8902 
8903 	DBUG_ENTER("innodb_sys_datafiles_init");
8904 
8905 	schema = (ST_SCHEMA_TABLE*) p;
8906 
8907 	schema->fields_info = innodb_sys_datafiles_fields_info;
8908 	schema->fill_table = i_s_sys_datafiles_fill_table;
8909 
8910 	DBUG_RETURN(0);
8911 }
8912 
8913 struct st_mysql_plugin	i_s_innodb_sys_datafiles =
8914 {
8915 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
8916 	/* int */
8917 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
8918 
8919 	/* pointer to type-specific plugin descriptor */
8920 	/* void* */
8921 	STRUCT_FLD(info, &i_s_info),
8922 
8923 	/* plugin name */
8924 	/* const char* */
8925 	STRUCT_FLD(name, "INNODB_SYS_DATAFILES"),
8926 
8927 	/* plugin author (for SHOW PLUGINS) */
8928 	/* const char* */
8929 	STRUCT_FLD(author, plugin_author),
8930 
8931 	/* general descriptive text (for SHOW PLUGINS) */
8932 	/* const char* */
8933 	STRUCT_FLD(descr, "InnoDB SYS_DATAFILES"),
8934 
8935 	/* the plugin license (PLUGIN_LICENSE_XXX) */
8936 	/* int */
8937 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
8938 
8939 	/* the function to invoke when plugin is loaded */
8940 	/* int (*)(void*); */
8941 	STRUCT_FLD(init, innodb_sys_datafiles_init),
8942 
8943 	/* the function to invoke when plugin is unloaded */
8944 	/* int (*)(void*); */
8945 	STRUCT_FLD(deinit, i_s_common_deinit),
8946 
8947 	/* plugin version (for SHOW PLUGINS) */
8948 	/* unsigned int */
8949 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
8950 
8951 	/* struct st_mysql_show_var* */
8952 	STRUCT_FLD(status_vars, NULL),
8953 
8954 	/* struct st_mysql_sys_var** */
8955 	STRUCT_FLD(system_vars, NULL),
8956 
8957 	/* reserved for dependency checking */
8958 	/* void* */
8959 	STRUCT_FLD(__reserved1, NULL),
8960 
8961 	/* Plugin flags */
8962 	/* unsigned long */
8963 	STRUCT_FLD(flags, 0UL),
8964 };
8965 
8966 static ST_FIELD_INFO	i_s_innodb_changed_pages_info[] =
8967 {
8968 	{STRUCT_FLD(field_name,		"space_id"),
8969 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8970 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8971 	 STRUCT_FLD(value,		0),
8972 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8973 	 STRUCT_FLD(old_name,		""),
8974 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8975 
8976 	{STRUCT_FLD(field_name,		"page_id"),
8977 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
8978 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
8979 	 STRUCT_FLD(value,		0),
8980 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8981 	 STRUCT_FLD(old_name,		""),
8982 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8983 
8984 	{STRUCT_FLD(field_name,		"start_lsn"),
8985 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
8986 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
8987 	 STRUCT_FLD(value,		0),
8988 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8989 	 STRUCT_FLD(old_name,		""),
8990 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8991 
8992 	{STRUCT_FLD(field_name,		"end_lsn"),
8993 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
8994 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
8995 	 STRUCT_FLD(value,		0),
8996 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
8997 	 STRUCT_FLD(old_name,		""),
8998 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
8999 
9000 	END_OF_ST_FIELD_INFO
9001 };
9002 
9003 /***********************************************************************
9004   This function implements ICP for I_S.INNODB_CHANGED_PAGES by parsing a
9005   condition and getting lower and upper bounds for start and end LSNs if the
9006   condition corresponds to a certain pattern.
9007 
9008   In the most general form, we understand queries like
9009 
9010   SELECT * FROM INNODB_CHANGED_PAGES
9011       WHERE START_LSN > num1 AND START_LSN < num2
9012             AND END_LSN > num3 AND END_LSN < num4;
9013 
9014   That's why the pattern syntax is:
9015 
9016   pattern:  comp | and_comp;
9017   comp:     lsn <  int_num | lsn <= int_num | int_num > lsn  | int_num >= lsn;
9018   lsn:	    start_lsn | end_lsn;
9019   and_comp: expression AND expression | expression AND and_comp;
9020   expression: comp | any_other_expression;
9021 
9022   The two bounds are handled differently: the lower bound is used to find the
9023   correct starting _file_, the upper bound the last _block_ that needs reading.
9024 
9025   Lower bound conditions are handled in the following way: start_lsn >= X
9026   specifies that the reading must start from the file that has the highest
9027   starting LSN less than or equal to X. start_lsn > X is equivalent to
9028   start_lsn >= X + 1.  For end_lsn, end_lsn >= X is treated as
9029   start_lsn >= X - 1 and end_lsn > X as start_lsn >= X.
9030 
9031   For the upper bound, suppose the condition is start_lsn < 100, this means we
9032   have to read all blocks with start_lsn < 100. Which is equivalent to reading
9033   all the blocks with end_lsn <= 99, or just end_lsn < 100. That's why it's
9034   enough to find maximum lsn value, doesn't matter if this is start or end lsn
9035   and compare it with "start_lsn" field. LSN <= 100 is treated as LSN < 101.
9036 
9037   Example:
9038 
9039   SELECT * FROM INNODB_CHANGED_PAGES
9040     WHERE
9041     start_lsn > 10  AND
9042     end_lsn <= 1111 AND
9043     555 > end_lsn   AND
9044     page_id = 100;
9045 
9046   end_lsn will be set to 555, start_lsn will be set 11.
9047 
9048   Support for other functions (equal, NULL-safe equal, BETWEEN, IN, etc.) will
9049   be added on demand.
9050 
9051 */
9052 static
9053 void
limit_lsn_range_from_condition(TABLE * table,Item * cond,ib_uint64_t * start_lsn,ib_uint64_t * end_lsn)9054 limit_lsn_range_from_condition(
9055 /*===========================*/
9056 	TABLE*		table,		/*!<in: table */
9057 	Item*		cond,		/*!<in: condition */
9058 	ib_uint64_t*	start_lsn,	/*!<in/out: minumum LSN */
9059 	ib_uint64_t*	end_lsn)	/*!<in/out: maximum LSN */
9060 {
9061 	enum Item_func::Functype	func_type;
9062 
9063 	if (cond->type() != Item::COND_ITEM &&
9064 	    cond->type() != Item::FUNC_ITEM)
9065 		return;
9066 
9067 	func_type = ((Item_func*) cond)->functype();
9068 
9069 	switch (func_type)
9070 	{
9071 	case Item_func::COND_AND_FUNC:
9072 	{
9073 		List_iterator<Item>	li(*((Item_cond*) cond)
9074 					   ->argument_list());
9075 		Item			*item;
9076 
9077 		while ((item= li++)) {
9078 			limit_lsn_range_from_condition(table, item, start_lsn,
9079 						       end_lsn);
9080 		}
9081 		break;
9082 	}
9083 	case Item_func::LT_FUNC:
9084 	case Item_func::LE_FUNC:
9085 	case Item_func::GT_FUNC:
9086 	case Item_func::GE_FUNC:
9087 	{
9088 		Item		*left;
9089 		Item		*right;
9090 		Item_field	*item_field;
9091 		ib_uint64_t	tmp_result;
9092 		bool		is_end_lsn;
9093 
9094 		/* a <= b equals to b >= a that's why we just exchange "left"
9095 		and "right" in the case of ">" or ">=" function.  We don't
9096 		touch the operation itself.  */
9097 		if (((Item_func*) cond)->functype() == Item_func::LT_FUNC
9098 		    || ((Item_func*) cond)->functype() == Item_func::LE_FUNC) {
9099 			left = ((Item_func*) cond)->arguments()[0];
9100 			right = ((Item_func*) cond)->arguments()[1];
9101 		} else {
9102 			left = ((Item_func*) cond)->arguments()[1];
9103 			right = ((Item_func*) cond)->arguments()[0];
9104 		}
9105 
9106 		if (left->type() == Item::FIELD_ITEM) {
9107 			item_field = (Item_field *)left;
9108 		} else if (right->type() == Item::FIELD_ITEM) {
9109 			item_field = (Item_field *)right;
9110 		} else {
9111 			return;
9112 		}
9113 
9114 		/* Check if the current field belongs to our table */
9115 		if (table != item_field->field->table) {
9116 			return;
9117 		}
9118 
9119 		/* Check if the field is START_LSN or END_LSN */
9120 		/* END_LSN */
9121 		is_end_lsn = table->field[3]->eq(item_field->field);
9122 
9123 		if (/* START_LSN */ !table->field[2]->eq(item_field->field)
9124 		    && !is_end_lsn) {
9125 			return;
9126 		}
9127 
9128 		if (left->type() == Item::FIELD_ITEM
9129 		    && right->type() == Item::INT_ITEM) {
9130 
9131 			/* The case of start_lsn|end_lsn <|<= const, i.e. the
9132 			upper bound.  */
9133 
9134 			tmp_result = right->val_int();
9135 			if (((func_type == Item_func::LE_FUNC)
9136 			     || (func_type == Item_func::GE_FUNC))
9137 			    && (tmp_result != IB_UINT64_MAX)) {
9138 
9139 				tmp_result++;
9140 			}
9141 			if (tmp_result < *end_lsn) {
9142 				*end_lsn = tmp_result;
9143 			}
9144 
9145 		} else if (left->type() == Item::INT_ITEM
9146 			   && right->type() == Item::FIELD_ITEM) {
9147 
9148 			/* The case of const <|<= start_lsn|end_lsn, i.e. the
9149 			lower bound */
9150 
9151 			tmp_result = left->val_int();
9152 			if (is_end_lsn && tmp_result != 0) {
9153 				tmp_result--;
9154 			}
9155 			if (((func_type == Item_func::LT_FUNC)
9156 			     || (func_type == Item_func::GT_FUNC))
9157 			    && (tmp_result != IB_UINT64_MAX)) {
9158 
9159 				tmp_result++;
9160 			}
9161 			if (tmp_result > *start_lsn) {
9162 				*start_lsn = tmp_result;
9163 			}
9164 		}
9165 
9166 		break;
9167 	}
9168 	default:;
9169 	}
9170 }
9171 
9172 /***********************************************************************
9173 Fill the dynamic table information_schema.innodb_changed_pages.
9174 @return 0 on success, 1 on failure */
9175 static
9176 int
i_s_innodb_changed_pages_fill(THD * thd,TABLE_LIST * tables,Item * cond)9177 i_s_innodb_changed_pages_fill(
9178 /*==========================*/
9179 	THD*		thd,	/*!<in: thread */
9180 	TABLE_LIST*	tables,	/*!<in/out: tables to fill */
9181 	Item*		cond)	/*!<in: condition */
9182 {
9183 	TABLE*			table = (TABLE *) tables->table;
9184 	log_bitmap_iterator_t	i;
9185 	ib_uint64_t		output_rows_num = 0UL;
9186 	lsn_t			max_lsn = LSN_MAX;
9187 	lsn_t			min_lsn = 0ULL;
9188 	int			ret = 0;
9189 
9190 	DBUG_ENTER("i_s_innodb_changed_pages_fill");
9191 
9192 	/* deny access to non-superusers */
9193 	if (check_global_access(thd, PROCESS_ACL)) {
9194 
9195 		DBUG_RETURN(0);
9196 	}
9197 
9198 	if (cond) {
9199 		limit_lsn_range_from_condition(table, cond, &min_lsn,
9200 					       &max_lsn);
9201 	}
9202 
9203 	/* If the log tracker is running and our max_lsn > current tracked LSN,
9204 	cap the max lsn so that we don't try to read any partial runs as the
9205 	tracked LSN advances. */
9206 	if (srv_track_changed_pages) {
9207 		ib_uint64_t		tracked_lsn = log_get_tracked_lsn();
9208 		if (max_lsn > tracked_lsn)
9209 			max_lsn = tracked_lsn;
9210 	}
9211 
9212 	if (!log_online_bitmap_iterator_init(&i, min_lsn, max_lsn)) {
9213 		my_error(ER_CANT_FIND_SYSTEM_REC, MYF(0));
9214 		DBUG_RETURN(1);
9215 	}
9216 
9217 	DEBUG_SYNC(thd, "i_s_innodb_changed_pages_range_ready");
9218 
9219 	while(log_online_bitmap_iterator_next(&i) &&
9220 	      (!srv_max_changed_pages ||
9221 	       output_rows_num < srv_max_changed_pages))
9222 	{
9223 		if (!LOG_BITMAP_ITERATOR_PAGE_CHANGED(i))
9224 			continue;
9225 
9226 		/* SPACE_ID */
9227 		table->field[0]->store(
9228 				       LOG_BITMAP_ITERATOR_SPACE_ID(i));
9229 		/* PAGE_ID */
9230 		table->field[1]->store(
9231 				       LOG_BITMAP_ITERATOR_PAGE_NUM(i));
9232 		/* START_LSN */
9233 		table->field[2]->store(
9234 				       LOG_BITMAP_ITERATOR_START_LSN(i), true);
9235 		/* END_LSN */
9236 		table->field[3]->store(
9237 				       LOG_BITMAP_ITERATOR_END_LSN(i), true);
9238 
9239 		/*
9240 		  I_S tables are in-memory tables. If bitmap file is big enough
9241 		  a lot of memory can be used to store the table. But the size
9242 		  of used memory can be diminished if we store only data which
9243 		  corresponds to some conditions (in WHERE sql clause). Here
9244 		  conditions are checked for the field values stored above.
9245 
9246 		  Conditions are checked twice. The first is here (during table
9247 		  generation) and the second during query execution. Maybe it
9248 		  makes sense to use some flag in THD object to avoid double
9249 		  checking.
9250 		*/
9251 		if (cond && !cond->val_int())
9252 			continue;
9253 
9254 		if (schema_table_store_record(thd, table))
9255 		{
9256 			log_online_bitmap_iterator_release(&i);
9257 			my_error(ER_CANT_FIND_SYSTEM_REC, MYF(0));
9258 			DBUG_RETURN(1);
9259 		}
9260 
9261 		++output_rows_num;
9262 	}
9263 
9264 	if (i.failed) {
9265 		my_error(ER_CANT_FIND_SYSTEM_REC, MYF(0));
9266 		ret = 1;
9267 	}
9268 
9269 	log_online_bitmap_iterator_release(&i);
9270 	DBUG_RETURN(ret);
9271 }
9272 
9273 static
9274 int
i_s_innodb_changed_pages_init(void * p)9275 i_s_innodb_changed_pages_init(
9276 /*==========================*/
9277 	void*	p)
9278 {
9279 	DBUG_ENTER("i_s_innodb_changed_pages_init");
9280 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
9281 
9282 	schema->fields_info = i_s_innodb_changed_pages_info;
9283 	schema->fill_table = i_s_innodb_changed_pages_fill;
9284 
9285 	DBUG_RETURN(0);
9286 }
9287 
9288 struct st_mysql_plugin   i_s_innodb_changed_pages =
9289 {
9290 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
9291 	STRUCT_FLD(info, &i_s_info),
9292 	STRUCT_FLD(name, "INNODB_CHANGED_PAGES"),
9293 	STRUCT_FLD(author, "Percona"),
9294 	STRUCT_FLD(descr, "InnoDB CHANGED_PAGES table"),
9295 	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
9296 	STRUCT_FLD(init, i_s_innodb_changed_pages_init),
9297 	STRUCT_FLD(deinit, i_s_common_deinit),
9298 	STRUCT_FLD(version, 0x0100 /* 1.0 */),
9299 	STRUCT_FLD(status_vars, NULL),
9300 	STRUCT_FLD(system_vars, NULL),
9301 	STRUCT_FLD(__reserved1, NULL),
9302 	STRUCT_FLD(flags, 0UL),
9303 };
9304 
9305 /** Fill handlerton based INFORMATION_SCHEMA.FILES table.
9306 @param[in,out]	thd	thread/connection descriptor
9307 @param[in,out]	tables	information schema tables to fill
9308 @retval 0 for success
9309 @retval HA_ERR_OUT_OF_MEM when running out of memory
9310 @return nonzero for failure */
9311 int
i_s_files_table_fill(THD * thd,TABLE_LIST * tables)9312 i_s_files_table_fill(
9313 	THD*		thd,
9314 	TABLE_LIST*	tables)
9315 {
9316 	TABLE*			table_to_fill	= tables->table;
9317 	Field**			fields		= table_to_fill->field;
9318 	/* Use this class so that if the OK() macro returns,
9319 	fil_space_release() is called. */
9320 	FilSpace		space;
9321 
9322 	DBUG_ENTER("i_s_files_table_fill");
9323 
9324 	/* Gather information reportable to information_schema.files
9325 	for the first or next file in fil_system. */
9326 	for (const fil_node_t* node = fil_node_next(NULL);
9327 	     node != NULL;
9328 	     node = fil_node_next(node)) {
9329 		const char*	type = "TABLESPACE";
9330 		const char*	space_name;
9331 		/** Buffer to build file-per-table tablespace names.
9332 		Even though a space_id is often stored in a ulint, it cannot
9333 		be larger than 1<<32-1, which is 10 numeric characters. */
9334 		char		file_per_table_name[
9335 			sizeof("innodb_file_per_table_1234567890")];
9336 		uintmax_t	avail_space;
9337 		ulint		extent_pages;
9338 		ulint		extend_pages;
9339 
9340 		space = node->space;
9341 		fil_type_t	purpose = space()->purpose;
9342 
9343 		switch (purpose) {
9344 		case FIL_TYPE_LOG:
9345 			/* Do not report REDO LOGs to I_S.FILES */
9346 			space = NULL;
9347 			continue;
9348 		case FIL_TYPE_TABLESPACE:
9349 			if (srv_is_undo_tablespace(space()->id)) {
9350 				type = "UNDO LOG";
9351 				break;
9352 			} /* else fall through for TABLESPACE */
9353 		case FIL_TYPE_IMPORT:
9354 			/* 'IMPORTING'is a status. The type is TABLESPACE. */
9355 			break;
9356 		case FIL_TYPE_TEMPORARY:
9357 			type = "TEMPORARY";
9358 			break;
9359 		};
9360 
9361 		page_size_t	page_size(space()->flags);
9362 
9363 		/* Single-table tablespaces are assigned to a schema. */
9364 		if (!is_predefined_tablespace(space()->id)
9365 		    && !FSP_FLAGS_GET_SHARED(space()->flags)) {
9366 			/* Their names will be like "test/t1" */
9367 			ut_ad(NULL != strchr(space()->name, '/'));
9368 
9369 			/* File-per-table tablespace names are generated
9370 			internally and certain non-file-system-allowed
9371 			characters are expanded which can make the space
9372 			name too long. In order to avoid that problem,
9373 			use a modified tablespace name.
9374 			Since we are not returning dbname and tablename,
9375 			the user must match the space_id to i_s_table.space
9376 			in order find the single table that is in it or the
9377 			schema it belongs to. */
9378 			ut_snprintf(
9379 				file_per_table_name,
9380 				sizeof(file_per_table_name),
9381 				"innodb_file_per_table_" ULINTPF,
9382 				space()->id);
9383 			space_name = file_per_table_name;
9384 		} else {
9385 			/* Only file-per-table space names contain '/'.
9386                         This is not file-per-table . */
9387 			ut_ad(NULL == strchr(space()->name, '/'));
9388 
9389 			space_name = space()->name;
9390 		}
9391 
9392 		init_fill_schema_files_row(table_to_fill);
9393 
9394 		OK(field_store_ulint(fields[IS_FILES_FILE_ID],
9395 				     space()->id));
9396 		OK(field_store_string(fields[IS_FILES_FILE_NAME],
9397 				      node->name));
9398 		OK(field_store_string(fields[IS_FILES_FILE_TYPE],
9399 				      type));
9400 		OK(field_store_string(fields[IS_FILES_TABLESPACE_NAME],
9401 				      space_name));
9402 		OK(field_store_string(fields[IS_FILES_ENGINE],
9403 				      "InnoDB"));
9404 		OK(field_store_ulint(fields[IS_FILES_FREE_EXTENTS],
9405 				     space()->free_len));
9406 
9407 		extent_pages = fsp_get_extent_size_in_pages(page_size);
9408 
9409 		OK(field_store_ulint(fields[IS_FILES_TOTAL_EXTENTS],
9410 				     space()->size_in_header / extent_pages));
9411 		OK(field_store_ulint(fields[IS_FILES_EXTENT_SIZE],
9412 				     extent_pages * page_size.physical()));
9413 		OK(field_store_ulint(fields[IS_FILES_INITIAL_SIZE],
9414 				     node->init_size * page_size.physical()));
9415 
9416 		if (node->max_size >= ULINT_MAX) {
9417 			fields[IS_FILES_MAXIMUM_SIZE]->set_null();
9418 		} else {
9419 			OK(field_store_ulint(fields[IS_FILES_MAXIMUM_SIZE],
9420 				node->max_size * page_size.physical()));
9421 		}
9422 		if (space()->id == srv_sys_space.space_id()) {
9423 			extend_pages = srv_sys_space.get_increment();
9424 		} else if (space()->id == srv_tmp_space.space_id()) {
9425 			extend_pages = srv_tmp_space.get_increment();
9426 		} else {
9427 			extend_pages = fsp_get_pages_to_extend_ibd(
9428 				page_size, node->size);
9429 		}
9430 
9431 		OK(field_store_ulint(fields[IS_FILES_AUTOEXTEND_SIZE],
9432 				     extend_pages * page_size.physical()));
9433 
9434 		avail_space = fsp_get_available_space_in_free_extents(space());
9435 		OK(field_store_ulint(fields[IS_FILES_DATA_FREE],
9436 				     static_cast<ulint>(avail_space * 1024)));
9437 		OK(field_store_string(fields[IS_FILES_STATUS],
9438 				      (purpose == FIL_TYPE_IMPORT)
9439 				      ? "IMPORTING" : "NORMAL"));
9440 
9441 		schema_table_store_record(thd, table_to_fill);
9442 		space = NULL;
9443 	}
9444 
9445 	DBUG_RETURN(0);
9446 }
9447 
9448 /**  TABLESPACES_ENCRYPTION    ********************************************/
9449 /* Fields of the table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION */
9450 static ST_FIELD_INFO	innodb_tablespaces_encryption_fields_info[] =
9451 {
9452 #define TABLESPACES_ENCRYPTION_SPACE	0
9453 	{STRUCT_FLD(field_name,		"SPACE"),
9454 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
9455 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9456 	 STRUCT_FLD(value,		0),
9457 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
9458 	 STRUCT_FLD(old_name,		""),
9459 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9460 
9461 #define TABLESPACES_ENCRYPTION_NAME		1
9462 	{STRUCT_FLD(field_name,		"NAME"),
9463 	 STRUCT_FLD(field_length,	MAX_FULL_NAME_LEN + 1),
9464 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
9465 	 STRUCT_FLD(value,		0),
9466 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
9467 	 STRUCT_FLD(old_name,		""),
9468 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9469 
9470 #define TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME	2
9471 	{STRUCT_FLD(field_name,		"ENCRYPTION_SCHEME"),
9472 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
9473 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9474 	 STRUCT_FLD(value,		0),
9475 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
9476 	 STRUCT_FLD(old_name,		""),
9477 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9478 
9479 #define TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS	3
9480 	{STRUCT_FLD(field_name,		"KEYSERVER_REQUESTS"),
9481 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
9482 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9483 	 STRUCT_FLD(value,		0),
9484 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
9485 	 STRUCT_FLD(old_name,		""),
9486 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9487 
9488 #define TABLESPACES_ENCRYPTION_MIN_KEY_VERSION	4
9489 	{STRUCT_FLD(field_name,		"MIN_KEY_VERSION"),
9490 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
9491 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9492 	 STRUCT_FLD(value,		0),
9493 	 STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
9494 	 STRUCT_FLD(old_name,		""),
9495 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9496 
9497 #define TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION	5
9498 	{STRUCT_FLD(field_name,		"CURRENT_KEY_VERSION"),
9499 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
9500 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9501 	 STRUCT_FLD(value,		0),
9502 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
9503 	 STRUCT_FLD(old_name,		""),
9504 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9505 
9506 #define TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER	6
9507 	{STRUCT_FLD(field_name,		"KEY_ROTATION_PAGE_NUMBER"),
9508 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
9509 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
9510 	 STRUCT_FLD(value,		0),
9511 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
9512 	 STRUCT_FLD(old_name,		""),
9513 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9514 
9515 #define TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER 7
9516 	{STRUCT_FLD(field_name,		"KEY_ROTATION_MAX_PAGE_NUMBER"),
9517 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
9518 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
9519 	 STRUCT_FLD(value,		0),
9520 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
9521 	 STRUCT_FLD(old_name,		""),
9522 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9523 
9524 #define TABLESPACES_ENCRYPTION_CURRENT_KEY_ID	8
9525 	{STRUCT_FLD(field_name,		"CURRENT_KEY_ID"),
9526 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
9527 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9528 	 STRUCT_FLD(value,		0),
9529 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
9530 	 STRUCT_FLD(old_name,		""),
9531 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9532 
9533 #define TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING 9
9534 	{STRUCT_FLD(field_name,		"ROTATING_OR_FLUSHING"),
9535 	 STRUCT_FLD(field_length,	1),
9536 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
9537 	 STRUCT_FLD(value,		0),
9538 	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
9539 	 STRUCT_FLD(old_name,		""),
9540 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
9541 
9542 	END_OF_ST_FIELD_INFO
9543 };
9544 
9545 /**********************************************************************//**
9546 Function to fill INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION
9547 with information collected by scanning SYS_TABLESPACES table.
9548 @param[in]	thd		thread handle
9549 @param[in]	space		Tablespace
9550 @param[in]	table_to_fill	I_S table to fill
9551 @return 0 on success */
9552 static
9553 int
i_s_dict_fill_tablespaces_encryption(THD * thd,fil_space_t * space,TABLE * table_to_fill)9554 i_s_dict_fill_tablespaces_encryption(
9555 	THD*		thd,
9556 	fil_space_t*	space,
9557 	TABLE*		table_to_fill)
9558 {
9559 	Field**	fields;
9560 	struct fil_space_crypt_status_t status;
9561 
9562 	DBUG_ENTER("i_s_dict_fill_tablespaces_encryption");
9563 
9564 	fields = table_to_fill->field;
9565 
9566 	fil_space_crypt_get_status(space, &status);
9567 
9568 	/* If tablespace id does not match, we did not find
9569 	encryption information for this tablespace. */
9570 	if (!space->crypt_data || space->id != status.space) {
9571 		goto skip;
9572 	}
9573 
9574 	OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true));
9575 
9576 	OK(field_store_string(fields[TABLESPACES_ENCRYPTION_NAME],
9577 			      space->name));
9578 
9579 	OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store(
9580 		   status.scheme, true));
9581 	OK(fields[TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS]->store(
9582 		   status.keyserver_requests, true));
9583 	OK(fields[TABLESPACES_ENCRYPTION_MIN_KEY_VERSION]->store(
9584                    status.min_key_version, true));
9585 	OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION]->store(
9586 		   status.current_key_version, true));
9587 	OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_ID]->store(
9588 		   status.key_id, true));
9589 	OK(fields[TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING]->store(
9590 		   status.rotating || status.flushing, true));
9591 
9592 	if (status.rotating) {
9593 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->set_notnull();
9594 		OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->store(
9595 			   status.rotate_next_page_number, true));
9596 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->set_notnull();
9597 		OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->store(
9598 			   status.rotate_max_page_number, true));
9599 	} else {
9600 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]
9601 			->set_null();
9602 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]
9603 			->set_null();
9604 	}
9605 
9606 	OK(schema_table_store_record(thd, table_to_fill));
9607 
9608 skip:
9609 	DBUG_RETURN(0);
9610 }
9611 /*******************************************************************//**
9612 Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
9613 Loop through each record in TABLESPACES_ENCRYPTION, and extract the column
9614 information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
9615 @return 0 on success */
9616 static
9617 int
i_s_tablespaces_encryption_fill_table(THD * thd,TABLE_LIST * tables,Item *)9618 i_s_tablespaces_encryption_fill_table(
9619 /*===========================*/
9620 	THD*		thd,	/*!< in: thread */
9621 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
9622 	Item*		)	/*!< in: condition (not used) */
9623 {
9624 	btr_pcur_t	pcur;
9625 	const rec_t*	rec;
9626 	mem_heap_t*	heap;
9627 	mtr_t		mtr;
9628 	bool		found_space_0 = false;
9629 
9630 	DBUG_ENTER("i_s_tablespaces_encryption_fill_table");
9631 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
9632 
9633 	/* deny access to user without PROCESS_ACL privilege */
9634 	if (check_global_access(thd, SUPER_ACL)) {
9635 		DBUG_RETURN(0);
9636 	}
9637 
9638 	heap = mem_heap_create(1000);
9639 	mutex_enter(&dict_sys->mutex);
9640 	mtr_start(&mtr);
9641 
9642 	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES);
9643 
9644 	while (rec) {
9645 		const char*	err_msg;
9646 		ulint		space_id;
9647 		const char*	name;
9648 		ulint		flags;
9649 
9650 		/* Extract necessary information from a SYS_TABLESPACES row */
9651 		err_msg = dict_process_sys_tablespaces(
9652 			heap, rec, &space_id, &name, &flags);
9653 
9654 		mtr_commit(&mtr);
9655 		mutex_exit(&dict_sys->mutex);
9656 
9657 		if (space_id == 0) {
9658 			found_space_0 = true;
9659 		}
9660 
9661 		fil_space_t* space = fil_space_acquire_silent(space_id);
9662 
9663 		if (!err_msg && space) {
9664 			i_s_dict_fill_tablespaces_encryption(
9665 				thd, space, tables->table);
9666 		} else {
9667 			push_warning_printf(thd, Sql_condition::SL_WARNING,
9668 					    ER_CANT_FIND_SYSTEM_REC, "%s",
9669 					    err_msg);
9670 		}
9671 
9672 		if (space) {
9673 			fil_space_release(space);
9674 		}
9675 
9676 		mem_heap_empty(heap);
9677 
9678 		/* Get the next record */
9679 		mutex_enter(&dict_sys->mutex);
9680 		mtr_start(&mtr);
9681 		rec = dict_getnext_system(&pcur, &mtr);
9682 	}
9683 
9684 	mtr_commit(&mtr);
9685 	mutex_exit(&dict_sys->mutex);
9686 	mem_heap_free(heap);
9687 
9688 	if (found_space_0 == false) {
9689 		/* space 0 does for what ever unknown reason not show up
9690 		* in iteration above, add it manually */
9691 
9692 		fil_space_t* space = fil_space_acquire_silent(0);
9693 
9694 		i_s_dict_fill_tablespaces_encryption(
9695 			thd, space, tables->table);
9696 
9697 		fil_space_release(space);
9698 	}
9699 
9700 	DBUG_RETURN(0);
9701 }
9702 /*******************************************************************//**
9703 Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION
9704 @return 0 on success */
9705 static
9706 int
innodb_tablespaces_encryption_init(void * p)9707 innodb_tablespaces_encryption_init(
9708 /*========================*/
9709 	void*	p)	/*!< in/out: table schema object */
9710 {
9711 	ST_SCHEMA_TABLE*	schema;
9712 
9713 	DBUG_ENTER("innodb_tablespaces_encryption_init");
9714 
9715 	schema = (ST_SCHEMA_TABLE*) p;
9716 
9717 	schema->fields_info = innodb_tablespaces_encryption_fields_info;
9718 	schema->fill_table = i_s_tablespaces_encryption_fill_table;
9719 
9720 	DBUG_RETURN(0);
9721 }
9722 
9723 struct st_mysql_plugin	i_s_innodb_tablespaces_encryption =
9724 {
9725 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
9726 	/* int */
9727 	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
9728 
9729 	/* pointer to type-specific plugin descriptor */
9730 	/* void* */
9731 	STRUCT_FLD(info, &i_s_info),
9732 
9733 	/* plugin name */
9734 	/* const char* */
9735 	STRUCT_FLD(name, "INNODB_TABLESPACES_ENCRYPTION"),
9736 
9737 	/* plugin author (for SHOW PLUGINS) */
9738 	/* const char* */
9739 	STRUCT_FLD(author, "Google Inc"),
9740 
9741 	/* general descriptive text (for SHOW PLUGINS) */
9742 	/* const char* */
9743 	STRUCT_FLD(descr, "InnoDB TABLESPACES_ENCRYPTION"),
9744 
9745 	/* the plugin license (PLUGIN_LICENSE_XXX) */
9746 	/* int */
9747 	STRUCT_FLD(license, PLUGIN_LICENSE_BSD),
9748 
9749 	/* the function to invoke when plugin is loaded */
9750 	/* int (*)(void*); */
9751 	STRUCT_FLD(init, innodb_tablespaces_encryption_init),
9752 
9753 	/* the function to invoke when plugin is unloaded */
9754 	/* int (*)(void*); */
9755 	STRUCT_FLD(deinit, i_s_common_deinit),
9756 
9757 	/* plugin version (for SHOW PLUGINS) */
9758 	/* unsigned int */
9759 	STRUCT_FLD(version, INNODB_VERSION_SHORT),
9760 
9761 	/* struct st_mysql_show_var* */
9762 	STRUCT_FLD(status_vars, NULL),
9763 
9764 	/* struct st_mysql_sys_var** */
9765 	STRUCT_FLD(system_vars, NULL),
9766 
9767 	/* reserved for dependency checking */
9768 	/* void* */
9769 	STRUCT_FLD(__reserved1, NULL),
9770 
9771 	/* Plugin flags */
9772 	/* unsigned long */
9773 	STRUCT_FLD(flags, 0UL)
9774 };
9775 
9776 /**  TABLESPACES_SCRUBBING    ********************************************/
9777 /* Fields of the table INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING */
9778 static ST_FIELD_INFO    innodb_tablespaces_scrubbing_fields_info[] =
9779 {
9780 #define TABLESPACES_SCRUBBING_SPACE     0
9781         {STRUCT_FLD(field_name,         "SPACE"),
9782          STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
9783          STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
9784          STRUCT_FLD(value,              0),
9785          STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
9786          STRUCT_FLD(old_name,           ""),
9787          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9788 
9789 #define TABLESPACES_SCRUBBING_NAME              1
9790         {STRUCT_FLD(field_name,         "NAME"),
9791          STRUCT_FLD(field_length,       MAX_FULL_NAME_LEN + 1),
9792          STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
9793          STRUCT_FLD(value,              0),
9794          STRUCT_FLD(field_flags,        MY_I_S_MAYBE_NULL),
9795          STRUCT_FLD(old_name,           ""),
9796          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9797 
9798 #define TABLESPACES_SCRUBBING_COMPRESSED        2
9799         {STRUCT_FLD(field_name,         "COMPRESSED"),
9800          STRUCT_FLD(field_length,       MY_INT32_NUM_DECIMAL_DIGITS),
9801          STRUCT_FLD(field_type,         MYSQL_TYPE_LONG),
9802          STRUCT_FLD(value,              0),
9803          STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
9804          STRUCT_FLD(old_name,           ""),
9805          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9806 
9807 #define TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED      3
9808         {STRUCT_FLD(field_name,         "LAST_SCRUB_COMPLETED"),
9809          STRUCT_FLD(field_length,       0),
9810          STRUCT_FLD(field_type,         MYSQL_TYPE_DATETIME),
9811          STRUCT_FLD(value,              0),
9812          STRUCT_FLD(field_flags,        MY_I_S_MAYBE_NULL),
9813          STRUCT_FLD(old_name,           ""),
9814          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9815 
9816 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED     4
9817         {STRUCT_FLD(field_name,         "CURRENT_SCRUB_STARTED"),
9818          STRUCT_FLD(field_length,       0),
9819          STRUCT_FLD(field_type,         MYSQL_TYPE_DATETIME),
9820          STRUCT_FLD(value,              0),
9821          STRUCT_FLD(field_flags,        MY_I_S_MAYBE_NULL),
9822          STRUCT_FLD(old_name,           ""),
9823          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9824 
9825 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS      5
9826         {STRUCT_FLD(field_name,         "CURRENT_SCRUB_ACTIVE_THREADS"),
9827          STRUCT_FLD(field_length,       MY_INT32_NUM_DECIMAL_DIGITS),
9828          STRUCT_FLD(field_type,         MYSQL_TYPE_LONG),
9829          STRUCT_FLD(value,              0),
9830          STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
9831          STRUCT_FLD(old_name,           ""),
9832          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9833 
9834 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER 6
9835         {STRUCT_FLD(field_name,         "CURRENT_SCRUB_PAGE_NUMBER"),
9836          STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
9837          STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
9838          STRUCT_FLD(value,              0),
9839          STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
9840          STRUCT_FLD(old_name,           ""),
9841          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9842 
9843 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER     7
9844         {STRUCT_FLD(field_name,         "CURRENT_SCRUB_MAX_PAGE_NUMBER"),
9845          STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
9846          STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
9847          STRUCT_FLD(value,              0),
9848          STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
9849          STRUCT_FLD(old_name,           ""),
9850          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9851 
9852 #define TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING 9
9853         {STRUCT_FLD(field_name,         "ROTATING_OR_FLUSHING"),
9854          STRUCT_FLD(field_length,       MY_INT32_NUM_DECIMAL_DIGITS),
9855          STRUCT_FLD(field_type,         MYSQL_TYPE_LONG),
9856          STRUCT_FLD(value,              0),
9857          STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
9858          STRUCT_FLD(old_name,           ""),
9859          STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
9860 
9861         END_OF_ST_FIELD_INFO
9862 };
9863 
9864 /**********************************************************************//**
9865 Function to fill INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING
9866 with information collected by scanning SYS_TABLESPACES table and
9867 fil_space.
9868 @param[in]      thd             Thread handle
9869 @param[in]      space           Tablespace
9870 @param[in]      table_to_fill   I_S table
9871 @return 0 on success */
9872 static
9873 int
i_s_dict_fill_tablespaces_scrubbing(THD * thd,fil_space_t * space,TABLE * table_to_fill)9874 i_s_dict_fill_tablespaces_scrubbing(
9875         THD*            thd,
9876         fil_space_t*    space,
9877         TABLE*          table_to_fill)
9878 {
9879         Field** fields;
9880         struct fil_space_scrub_status_t status;
9881 
9882         DBUG_ENTER("i_s_dict_fill_tablespaces_scrubbing");
9883 
9884         fields = table_to_fill->field;
9885 
9886         fil_space_get_scrub_status(space, &status);
9887 
9888         OK(fields[TABLESPACES_SCRUBBING_SPACE]->store(space->id, true));
9889 
9890         OK(field_store_string(fields[TABLESPACES_SCRUBBING_NAME],
9891                               space->name));
9892 
9893         OK(fields[TABLESPACES_SCRUBBING_COMPRESSED]->store(
9894                    status.compressed ? 1 : 0, true));
9895 
9896         if (status.last_scrub_completed == 0) {
9897                 fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED]->set_null();
9898         } else {
9899                 fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED]
9900                         ->set_notnull();
9901                 OK(field_store_time_t(
9902                            fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED],
9903                            status.last_scrub_completed));
9904         }
9905 
9906         int field_numbers[] = {
9907                 TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED,
9908                 TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS,
9909                 TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER,
9910                 TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER };
9911 
9912         if (status.scrubbing) {
9913                 for (uint i = 0; i < array_elements(field_numbers); i++) {
9914                         fields[field_numbers[i]]->set_notnull();
9915                 }
9916 
9917                 OK(field_store_time_t(
9918                            fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED],
9919                            status.current_scrub_started));
9920                 OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS]
9921                    ->store(status.current_scrub_active_threads, true));
9922                 OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER]
9923                    ->store(status.current_scrub_page_number, true));
9924                 OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER]
9925                    ->store(status.current_scrub_max_page_number, true));
9926         } else {
9927                 for (uint i = 0; i < array_elements(field_numbers); i++) {
9928                         fields[field_numbers[i]]->set_null();
9929                 }
9930         }
9931 
9932         OK(schema_table_store_record(thd, table_to_fill));
9933 
9934         DBUG_RETURN(0);
9935 }
9936 /*******************************************************************//**
9937 Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING table.
9938 Loop through each record in TABLESPACES_SCRUBBING, and extract the column
9939 information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING table.
9940 @return 0 on success */
9941 static
9942 int
i_s_tablespaces_scrubbing_fill_table(THD * thd,TABLE_LIST * tables,Item *)9943 i_s_tablespaces_scrubbing_fill_table(
9944 /*===========================*/
9945         THD*            thd,    /*!< in: thread */
9946         TABLE_LIST*     tables, /*!< in/out: tables to fill */
9947         Item*           )       /*!< in: condition (not used) */
9948 {
9949         DBUG_ENTER("i_s_tablespaces_scrubbing_fill_table");
9950         RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
9951 
9952         /* deny access to user without SUPER_ACL privilege */
9953         if (check_global_access(thd, SUPER_ACL)) {
9954                 DBUG_RETURN(0);
9955         }
9956 
9957         mutex_enter(&fil_system->mutex);
9958 
9959         for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system->space_list);
9960              space; space = UT_LIST_GET_NEXT(space_list, space)) {
9961                 if (space->purpose == FIL_TYPE_TABLESPACE
9962                     && !space->is_stopping()) {
9963 			//fil_space_acquire_silent(space->id);
9964                         mutex_exit(&fil_system->mutex);
9965                         if (int err = i_s_dict_fill_tablespaces_scrubbing(
9966                                     thd, space, tables->table)) {
9967 				//fil_space_release(space);
9968                                 DBUG_RETURN(err);
9969                         }
9970                         mutex_enter(&fil_system->mutex);
9971                         //space->release();
9972                 }
9973         }
9974 
9975         mutex_exit(&fil_system->mutex);
9976         DBUG_RETURN(0);
9977 }
9978 /*******************************************************************//**
9979 Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING
9980 @return 0 on success */
9981 static
9982 int
innodb_tablespaces_scrubbing_init(void * p)9983 innodb_tablespaces_scrubbing_init(
9984 /*========================*/
9985         void*   p)      /*!< in/out: table schema object */
9986 {
9987         ST_SCHEMA_TABLE*        schema;
9988 
9989         DBUG_ENTER("innodb_tablespaces_scrubbing_init");
9990 
9991         schema = (ST_SCHEMA_TABLE*) p;
9992 
9993         schema->fields_info = innodb_tablespaces_scrubbing_fields_info;
9994         schema->fill_table = i_s_tablespaces_scrubbing_fill_table;
9995 
9996         DBUG_RETURN(0);
9997 }
9998 
9999 struct st_mysql_plugin      i_s_innodb_tablespaces_scrubbing =
10000 {
10001         /* the plugin type (a MYSQL_XXX_PLUGIN value) */
10002         /* int */
10003         STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
10004 
10005         /* pointer to type-specific plugin descriptor */
10006         /* void* */
10007         STRUCT_FLD(info, &i_s_info),
10008 
10009         /* plugin name */
10010         /* const char* */
10011         STRUCT_FLD(name, "INNODB_TABLESPACES_SCRUBBING"),
10012 
10013         /* plugin author (for SHOW PLUGINS) */
10014         /* const char* */
10015         STRUCT_FLD(author, "Google Inc"),
10016 
10017         /* general descriptive text (for SHOW PLUGINS) */
10018         /* const char* */
10019         STRUCT_FLD(descr, "InnoDB TABLESPACES_SCRUBBING"),
10020 
10021         /* the plugin license (PLUGIN_LICENSE_XXX) */
10022         /* int */
10023         STRUCT_FLD(license, PLUGIN_LICENSE_BSD),
10024 
10025         /* the function to invoke when plugin is loaded */
10026         /* int (*)(void*); */
10027         STRUCT_FLD(init, innodb_tablespaces_scrubbing_init),
10028 
10029         /* the function to invoke when plugin is unloaded */
10030         /* int (*)(void*); */
10031         STRUCT_FLD(deinit, i_s_common_deinit),
10032 
10033         /* plugin version (for SHOW PLUGINS) */
10034         /* unsigned int */
10035         STRUCT_FLD(version, INNODB_VERSION_SHORT),
10036 
10037         /* struct st_mysql_show_var* */
10038         STRUCT_FLD(status_vars, NULL),
10039 
10040         /* struct st_mysql_sys_var** */
10041         STRUCT_FLD(system_vars, NULL),
10042 
10043 	/* reserved for dependency checking */
10044 	/* void* */
10045 	STRUCT_FLD(__reserved1, NULL),
10046 
10047 	/* Plugin flags */
10048 	/* unsigned long */
10049 	STRUCT_FLD(flags, 0UL)
10050 };
10051 
10052