1 /*****************************************************************************
2 
3 Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2014, 2021, MariaDB Corporation.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file handler/i_s.cc
22 InnoDB INFORMATION SCHEMA tables interface to MySQL.
23 
24 Created July 18, 2007 Vasil Dimov
25 Modified Dec 29, 2014 Jan Lindström (Added sys_semaphore_waits)
26 *******************************************************/
27 
28 #include "univ.i"
29 #include <mysql_version.h>
30 #include <field.h>
31 
32 #include <sql_acl.h>
33 #include <sql_show.h>
34 #include <sql_time.h>
35 
36 #include "i_s.h"
37 #include "btr0pcur.h"
38 #include "btr0types.h"
39 #include "dict0dict.h"
40 #include "dict0load.h"
41 #include "buf0buddy.h"
42 #include "buf0buf.h"
43 #include "ibuf0ibuf.h"
44 #include "dict0mem.h"
45 #include "dict0types.h"
46 #include "srv0start.h"
47 #include "trx0i_s.h"
48 #include "trx0trx.h"
49 #include "srv0mon.h"
50 #include "fut0fut.h"
51 #include "pars0pars.h"
52 #include "fts0types.h"
53 #include "fts0opt.h"
54 #include "fts0priv.h"
55 #include "btr0btr.h"
56 #include "page0zip.h"
57 #include "sync0arr.h"
58 #include "fil0fil.h"
59 #include "fil0crypt.h"
60 #include "dict0crea.h"
61 #include "fts0vlc.h"
62 
63 /** The latest successfully looked up innodb_fts_aux_table */
64 UNIV_INTERN table_id_t innodb_ft_aux_table_id;
65 
66 /** structure associates a name string with a file page type and/or buffer
67 page state. */
68 struct buf_page_desc_t{
69 	const char*	type_str;	/*!< String explain the page
70 					type/state */
71 	ulint		type_value;	/*!< Page type or page state */
72 };
73 
74 /** We also define I_S_PAGE_TYPE_INDEX as the Index Page's position
75 in i_s_page_type[] array */
76 #define I_S_PAGE_TYPE_INDEX		1
77 
78 /** Any unassigned FIL_PAGE_TYPE will be treated as unknown. */
79 #define	I_S_PAGE_TYPE_UNKNOWN		FIL_PAGE_TYPE_UNKNOWN
80 
81 /** R-tree index page */
82 #define	I_S_PAGE_TYPE_RTREE		(FIL_PAGE_TYPE_LAST + 1)
83 
84 /** Change buffer B-tree page */
85 #define	I_S_PAGE_TYPE_IBUF		(FIL_PAGE_TYPE_LAST + 2)
86 
87 #define I_S_PAGE_TYPE_LAST		I_S_PAGE_TYPE_IBUF
88 
89 #define I_S_PAGE_TYPE_BITS		4
90 
91 /** Name string for File Page Types */
92 static buf_page_desc_t	i_s_page_type[] = {
93 	{"ALLOCATED", FIL_PAGE_TYPE_ALLOCATED},
94 	{"INDEX", FIL_PAGE_INDEX},
95 	{"UNDO_LOG", FIL_PAGE_UNDO_LOG},
96 	{"INODE", FIL_PAGE_INODE},
97 	{"IBUF_FREE_LIST", FIL_PAGE_IBUF_FREE_LIST},
98 	{"IBUF_BITMAP", FIL_PAGE_IBUF_BITMAP},
99 	{"SYSTEM", FIL_PAGE_TYPE_SYS},
100 	{"TRX_SYSTEM", FIL_PAGE_TYPE_TRX_SYS},
101 	{"FILE_SPACE_HEADER", FIL_PAGE_TYPE_FSP_HDR},
102 	{"EXTENT_DESCRIPTOR", FIL_PAGE_TYPE_XDES},
103 	{"BLOB", FIL_PAGE_TYPE_BLOB},
104 	{"COMPRESSED_BLOB", FIL_PAGE_TYPE_ZBLOB},
105 	{"COMPRESSED_BLOB2", FIL_PAGE_TYPE_ZBLOB2},
106 	{"UNKNOWN", I_S_PAGE_TYPE_UNKNOWN},
107 	{"RTREE_INDEX", I_S_PAGE_TYPE_RTREE},
108 	{"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
109 	{"PAGE COMPRESSED", FIL_PAGE_PAGE_COMPRESSED},
110 	{"PAGE COMPRESSED AND ENCRYPTED", FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED},
111 };
112 
113 /** This structure defines information we will fetch from pages
114 currently cached in the buffer pool. It will be used to populate
115 table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE */
116 struct buf_page_info_t{
117 	ulint		block_id;	/*!< Buffer Pool block ID */
118 	unsigned	space_id:32;	/*!< Tablespace ID */
119 	unsigned	page_num:32;	/*!< Page number/offset */
120 	unsigned	access_time:32;	/*!< Time of first access */
121 	unsigned	pool_id:MAX_BUFFER_POOLS_BITS;
122 					/*!< Buffer Pool ID. Must be less than
123 					MAX_BUFFER_POOLS */
124 	unsigned	flush_type:2;	/*!< Flush type */
125 	unsigned	io_fix:2;	/*!< type of pending I/O operation */
126 	unsigned	fix_count:19;	/*!< Count of how manyfold this block
127 					is bufferfixed */
128 #ifdef BTR_CUR_HASH_ADAPT
129 	unsigned	hashed:1;	/*!< Whether hash index has been
130 					built on this page */
131 #endif /* BTR_CUR_HASH_ADAPT */
132 	unsigned	is_old:1;	/*!< TRUE if the block is in the old
133 					blocks in buf_pool->LRU_old */
134 	unsigned	freed_page_clock:31; /*!< the value of
135 					buf_pool->freed_page_clock */
136 	unsigned	zip_ssize:PAGE_ZIP_SSIZE_BITS;
137 					/*!< Compressed page size */
138 	unsigned	page_state:BUF_PAGE_STATE_BITS; /*!< Page state */
139 	unsigned	page_type:I_S_PAGE_TYPE_BITS;	/*!< Page type */
140 	unsigned	num_recs:UNIV_PAGE_SIZE_SHIFT_MAX-2;
141 					/*!< Number of records on Page */
142 	unsigned	data_size:UNIV_PAGE_SIZE_SHIFT_MAX;
143 					/*!< Sum of the sizes of the records */
144 	lsn_t		newest_mod;	/*!< Log sequence number of
145 					the youngest modification */
146 	lsn_t		oldest_mod;	/*!< Log sequence number of
147 					the oldest modification */
148 	index_id_t	index_id;	/*!< Index ID if a index page */
149 };
150 
151 /*
152 Use the following types mapping:
153 
154 C type	ST_FIELD_INFO::field_type
155 ---------------------------------
156 long			MYSQL_TYPE_LONGLONG
157 (field_length=MY_INT64_NUM_DECIMAL_DIGITS)
158 
159 long unsigned		MYSQL_TYPE_LONGLONG
160 (field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
161 
162 char*			MYSQL_TYPE_STRING
163 (field_length=n)
164 
165 float			MYSQL_TYPE_FLOAT
166 (field_length=0 is ignored)
167 
168 void*			MYSQL_TYPE_LONGLONG
169 (field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
170 
171 boolean (if else)	MYSQL_TYPE_LONG
172 (field_length=1)
173 
174 time_t			MYSQL_TYPE_DATETIME
175 (field_length=0 ignored)
176 ---------------------------------
177 */
178 
179 /** Implemented on sync0arr.cc */
180 /*******************************************************************//**
181 Function to populate INFORMATION_SCHEMA.INNODB_SYS_SEMAPHORE_WAITS table.
182 Loop through each item on sync array, and extract the column
183 information and fill the INFORMATION_SCHEMA.INNODB_SYS_SEMAPHORE_WAITS table.
184 @return 0 on success */
185 UNIV_INTERN
186 int
187 sync_arr_fill_sys_semphore_waits_table(
188 /*===================================*/
189 	THD*		thd,	/*!< in: thread */
190 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
191 	Item*		);	/*!< in: condition (not used) */
192 
193 /*******************************************************************//**
194 Common function to fill any of the dynamic tables:
195 INFORMATION_SCHEMA.innodb_trx
196 INFORMATION_SCHEMA.innodb_locks
197 INFORMATION_SCHEMA.innodb_lock_waits
198 @return 0 on success */
199 static
200 int
201 trx_i_s_common_fill_table(
202 /*======================*/
203 	THD*		thd,	/*!< in: thread */
204 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
205 	Item*		);	/*!< in: condition (not used) */
206 
207 /*******************************************************************//**
208 Unbind a dynamic INFORMATION_SCHEMA table.
209 @return 0 on success */
210 static
211 int
212 i_s_common_deinit(
213 /*==============*/
214 	void*	p);	/*!< in/out: table schema object */
215 /*******************************************************************//**
216 Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
217 field.
218 @return 0 on success */
219 static
220 int
field_store_time_t(Field * field,time_t time)221 field_store_time_t(
222 /*===============*/
223 	Field*	field,	/*!< in/out: target field for storage */
224 	time_t	time)	/*!< in: value to store */
225 {
226 	MYSQL_TIME	my_time;
227 	struct tm	tm_time;
228 
229 	if (time) {
230 #if 0
231 		/* use this if you are sure that `variables' and `time_zone'
232 		are always initialized */
233 		thd->variables.time_zone->gmt_sec_to_TIME(
234 			&my_time, (my_time_t) time);
235 #else
236 		localtime_r(&time, &tm_time);
237 		localtime_to_TIME(&my_time, &tm_time);
238 		my_time.time_type = MYSQL_TIMESTAMP_DATETIME;
239 #endif
240 	} else {
241 		memset(&my_time, 0, sizeof(my_time));
242 	}
243 
244 	/* JAN: TODO: MySQL 5.7
245 	return(field->store_time(&my_time, MYSQL_TIMESTAMP_DATETIME));
246 	*/
247 	return(field->store_time(&my_time));
248 }
249 
250 /*******************************************************************//**
251 Auxiliary function to store char* value in MYSQL_TYPE_STRING field.
252 @return 0 on success */
253 int
field_store_string(Field * field,const char * str)254 field_store_string(
255 /*===============*/
256 	Field*		field,	/*!< in/out: target field for storage */
257 	const char*	str)	/*!< in: NUL-terminated utf-8 string,
258 				or NULL */
259 {
260 	if (!str) {
261 		field->set_null();
262 		return 0;
263 	}
264 
265 	field->set_notnull();
266 	return field->store(str, uint(strlen(str)), system_charset_info);
267 }
268 
269 /*******************************************************************//**
270 Auxiliary function to store ulint value in MYSQL_TYPE_LONGLONG field.
271 If the value is ULINT_UNDEFINED then the field is set to NULL.
272 @return 0 on success */
273 int
field_store_ulint(Field * field,ulint n)274 field_store_ulint(
275 /*==============*/
276 	Field*	field,	/*!< in/out: target field for storage */
277 	ulint	n)	/*!< in: value to store */
278 {
279 	int	ret;
280 
281 	if (n != ULINT_UNDEFINED) {
282 
283 		ret = field->store(longlong(n), true);
284 		field->set_notnull();
285 	} else {
286 
287 		ret = 0; /* success */
288 		field->set_null();
289 	}
290 
291 	return(ret);
292 }
293 
294 #ifdef BTR_CUR_HASH_ADAPT
295 # define I_S_AHI 1 /* Include the IS_HASHED column */
296 #else
297 # define I_S_AHI 0 /* Omit the IS_HASHED column */
298 #endif
299 
300 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
301 static ST_FIELD_INFO innodb_trx_fields_info[]=
302 {
303 #define IDX_TRX_ID		0
304   {"trx_id", TRX_ID_MAX_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
305 
306 #define IDX_TRX_STATE		1
307   {"trx_state", TRX_QUE_STATE_STR_MAX_LEN + 1, MYSQL_TYPE_STRING,
308    0, 0, "", SKIP_OPEN_TABLE},
309 
310 #define IDX_TRX_STARTED		2
311   {"trx_started", 0, MYSQL_TYPE_DATETIME, 0, 0, "", SKIP_OPEN_TABLE},
312 
313 #define IDX_TRX_REQUESTED_LOCK_ID	3
314   {"trx_requested_lock_id", TRX_I_S_LOCK_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
315    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
316 
317 #define IDX_TRX_WAIT_STARTED	4
318   {"trx_wait_started", 0, MYSQL_TYPE_DATETIME,
319    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
320 
321 #define IDX_TRX_WEIGHT		5
322   {"trx_weight",MY_INT64_NUM_DECIMAL_DIGITS,MYSQL_TYPE_LONGLONG,
323    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
324 
325 #define IDX_TRX_MYSQL_THREAD_ID	6
326   {"trx_mysql_thread_id",MY_INT64_NUM_DECIMAL_DIGITS,MYSQL_TYPE_LONGLONG,
327    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
328 
329 #define IDX_TRX_QUERY		7
330   {"trx_query", TRX_I_S_TRX_QUERY_MAX_LEN, MYSQL_TYPE_STRING,
331    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
332 
333 #define IDX_TRX_OPERATION_STATE	8
334   {"trx_operation_state", TRX_I_S_TRX_OP_STATE_MAX_LEN, MYSQL_TYPE_STRING,
335    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
336 
337 #define IDX_TRX_TABLES_IN_USE	9
338   {"trx_tables_in_use", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
339    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
340 
341 #define IDX_TRX_TABLES_LOCKED	10
342   {"trx_tables_locked", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
343    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
344 
345 #define IDX_TRX_LOCK_STRUCTS	11
346   {"trx_lock_structs", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
347    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
348 
349 #define IDX_TRX_LOCK_MEMORY_BYTES	12
350   {"trx_lock_memory_bytes", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
351    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
352 
353 #define IDX_TRX_ROWS_LOCKED	13
354   {"trx_rows_locked", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
355    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
356 
357 #define IDX_TRX_ROWS_MODIFIED		14
358   {"trx_rows_modified", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
359    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
360 
361 #define IDX_TRX_CONNCURRENCY_TICKETS	15
362   {"trx_concurrency_tickets", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
363    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
364 
365 #define IDX_TRX_ISOLATION_LEVEL	16
366   {"trx_isolation_level", TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN,
367    MYSQL_TYPE_STRING,
368    0, 0, "", SKIP_OPEN_TABLE},
369 
370 #define IDX_TRX_UNIQUE_CHECKS	17
371   {"trx_unique_checks", 1, MYSQL_TYPE_LONG,
372    1, 0, "", SKIP_OPEN_TABLE},
373 
374 #define IDX_TRX_FOREIGN_KEY_CHECKS	18
375   {"trx_foreign_key_checks", 1, MYSQL_TYPE_LONG,
376    1, 0, "", SKIP_OPEN_TABLE},
377 
378 #define IDX_TRX_LAST_FOREIGN_KEY_ERROR	19
379   {"trx_last_foreign_key_error", TRX_I_S_TRX_FK_ERROR_MAX_LEN,
380    MYSQL_TYPE_STRING,
381    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
382 
383 #define IDX_TRX_READ_ONLY		20
384   {"trx_is_read_only", 1, MYSQL_TYPE_LONG,
385    0, 0, "", SKIP_OPEN_TABLE},
386 
387 #define IDX_TRX_AUTOCOMMIT_NON_LOCKING	21
388   {"trx_autocommit_non_locking", 1, MYSQL_TYPE_LONG,
389    0, 0, "", SKIP_OPEN_TABLE},
390 
391   END_OF_ST_FIELD_INFO
392 };
393 
394 /*******************************************************************//**
395 Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx
396 table with it.
397 @return 0 on success */
398 static
399 int
fill_innodb_trx_from_cache(trx_i_s_cache_t * cache,THD * thd,TABLE * table)400 fill_innodb_trx_from_cache(
401 /*=======================*/
402 	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
403 	THD*			thd,	/*!< in: used to call
404 					schema_table_store_record() */
405 	TABLE*			table)	/*!< in/out: fill this table */
406 {
407 	Field**	fields;
408 	ulint	rows_num;
409 	char	lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
410 	ulint	i;
411 
412 	DBUG_ENTER("fill_innodb_trx_from_cache");
413 
414 	fields = table->field;
415 
416 	rows_num = trx_i_s_cache_get_rows_used(cache,
417 					       I_S_INNODB_TRX);
418 
419 	for (i = 0; i < rows_num; i++) {
420 
421 		i_s_trx_row_t*	row;
422 		char		trx_id[TRX_ID_MAX_LEN + 1];
423 
424 		row = (i_s_trx_row_t*)
425 			trx_i_s_cache_get_nth_row(
426 				cache, I_S_INNODB_TRX, i);
427 
428 		/* trx_id */
429 		snprintf(trx_id, sizeof(trx_id), TRX_ID_FMT, row->trx_id);
430 		OK(field_store_string(fields[IDX_TRX_ID], trx_id));
431 
432 		/* trx_state */
433 		OK(field_store_string(fields[IDX_TRX_STATE],
434 				      row->trx_state));
435 
436 		/* trx_started */
437 		OK(field_store_time_t(fields[IDX_TRX_STARTED],
438 				      (time_t) row->trx_started));
439 
440 		/* trx_requested_lock_id */
441 		/* trx_wait_started */
442 		if (row->trx_wait_started != 0) {
443 
444 			OK(field_store_string(
445 				   fields[IDX_TRX_REQUESTED_LOCK_ID],
446 				   trx_i_s_create_lock_id(
447 					   row->requested_lock_row,
448 					   lock_id, sizeof(lock_id))));
449 			/* field_store_string() sets it no notnull */
450 
451 			OK(field_store_time_t(
452 				   fields[IDX_TRX_WAIT_STARTED],
453 				   (time_t) row->trx_wait_started));
454 			fields[IDX_TRX_WAIT_STARTED]->set_notnull();
455 		} else {
456 
457 			fields[IDX_TRX_REQUESTED_LOCK_ID]->set_null();
458 			fields[IDX_TRX_WAIT_STARTED]->set_null();
459 		}
460 
461 		/* trx_weight */
462 		OK(fields[IDX_TRX_WEIGHT]->store(row->trx_weight, true));
463 
464 		/* trx_mysql_thread_id */
465 		OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
466 			   row->trx_mysql_thread_id, true));
467 
468 		/* trx_query */
469 		if (row->trx_query) {
470 			/* store will do appropriate character set
471 			conversion check */
472 			fields[IDX_TRX_QUERY]->store(
473 				row->trx_query,
474 				static_cast<uint>(strlen(row->trx_query)),
475 				row->trx_query_cs);
476 			fields[IDX_TRX_QUERY]->set_notnull();
477 		} else {
478 			fields[IDX_TRX_QUERY]->set_null();
479 		}
480 
481 		/* trx_operation_state */
482 		OK(field_store_string(fields[IDX_TRX_OPERATION_STATE],
483 				      row->trx_operation_state));
484 
485 		/* trx_tables_in_use */
486 		OK(fields[IDX_TRX_TABLES_IN_USE]->store(
487 			   row->trx_tables_in_use, true));
488 
489 		/* trx_tables_locked */
490 		OK(fields[IDX_TRX_TABLES_LOCKED]->store(
491 			   row->trx_tables_locked, true));
492 
493 		/* trx_lock_structs */
494 		OK(fields[IDX_TRX_LOCK_STRUCTS]->store(
495 			   row->trx_lock_structs, true));
496 
497 		/* trx_lock_memory_bytes */
498 		OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store(
499 			   row->trx_lock_memory_bytes, true));
500 
501 		/* trx_rows_locked */
502 		OK(fields[IDX_TRX_ROWS_LOCKED]->store(
503 			   row->trx_rows_locked, true));
504 
505 		/* trx_rows_modified */
506 		OK(fields[IDX_TRX_ROWS_MODIFIED]->store(
507 			   row->trx_rows_modified, true));
508 
509 		/* trx_concurrency_tickets */
510 		OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store(
511 			   row->trx_concurrency_tickets, true));
512 
513 		/* trx_isolation_level */
514 		OK(field_store_string(fields[IDX_TRX_ISOLATION_LEVEL],
515 				      row->trx_isolation_level));
516 
517 		/* trx_unique_checks */
518 		OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
519 			   row->trx_unique_checks, true));
520 
521 		/* trx_foreign_key_checks */
522 		OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
523 			   row->trx_foreign_key_checks, true));
524 
525 		/* trx_last_foreign_key_error */
526 		OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
527 				      row->trx_foreign_key_error));
528 
529 		/* trx_is_read_only*/
530 		OK(fields[IDX_TRX_READ_ONLY]->store(
531 			   row->trx_is_read_only, true));
532 
533 		/* trx_is_autocommit_non_locking */
534 		OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
535 			   (longlong) row->trx_is_autocommit_non_locking,
536 			   true));
537 
538 		OK(schema_table_store_record(thd, table));
539 	}
540 
541 	DBUG_RETURN(0);
542 }
543 
544 /*******************************************************************//**
545 Bind the dynamic table INFORMATION_SCHEMA.innodb_trx
546 @return 0 on success */
547 static
548 int
innodb_trx_init(void * p)549 innodb_trx_init(
550 /*============*/
551 	void*	p)	/*!< in/out: table schema object */
552 {
553 	ST_SCHEMA_TABLE*	schema;
554 
555 	DBUG_ENTER("innodb_trx_init");
556 
557 	schema = (ST_SCHEMA_TABLE*) p;
558 
559 	schema->fields_info = innodb_trx_fields_info;
560 	schema->fill_table = trx_i_s_common_fill_table;
561 
562 	DBUG_RETURN(0);
563 }
564 
565 static struct st_mysql_information_schema	i_s_info =
566 {
567 	MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
568 };
569 
570 UNIV_INTERN struct st_maria_plugin	i_s_innodb_trx =
571 {
572 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
573 	/* int */
574 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
575 
576 	/* pointer to type-specific plugin descriptor */
577 	/* void* */
578 	&i_s_info,
579 
580 	/* plugin name */
581 	/* const char* */
582 	"INNODB_TRX",
583 
584 	/* plugin author (for SHOW PLUGINS) */
585 	/* const char* */
586 	plugin_author,
587 
588 	/* general descriptive text (for SHOW PLUGINS) */
589 	/* const char* */
590 	"InnoDB transactions",
591 
592 	/* the plugin license (PLUGIN_LICENSE_XXX) */
593 	/* int */
594 	PLUGIN_LICENSE_GPL,
595 
596 	/* the function to invoke when plugin is loaded */
597 	/* int (*)(void*); */
598 	innodb_trx_init,
599 
600 	/* the function to invoke when plugin is unloaded */
601 	/* int (*)(void*); */
602 	i_s_common_deinit,
603 
604 	/* plugin version (for SHOW PLUGINS) */
605 	/* unsigned int */
606 	INNODB_VERSION_SHORT,
607 
608 	/* struct st_mysql_show_var* */
609 	NULL,
610 
611 	/* struct st_mysql_sys_var** */
612 	NULL,
613 
614         /* Maria extension */
615 	INNODB_VERSION_STR,
616         MariaDB_PLUGIN_MATURITY_STABLE,
617 };
618 
619 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_locks */
620 static ST_FIELD_INFO innodb_locks_fields_info[]=
621 {
622 #define IDX_LOCK_ID		0
623   {"lock_id", TRX_I_S_LOCK_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
624    0, 0, "", SKIP_OPEN_TABLE},
625 
626 #define IDX_LOCK_TRX_ID		1
627   {"lock_trx_id", TRX_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
628    0, 0, "", SKIP_OPEN_TABLE},
629 
630 #define IDX_LOCK_MODE		2
631   {"lock_mode",
632    /* S[,GAP] X[,GAP] IS[,GAP] IX[,GAP] AUTO_INC UNKNOWN */
633    32, MYSQL_TYPE_STRING,
634    0, 0, "", SKIP_OPEN_TABLE},
635 
636 #define IDX_LOCK_TYPE		3
637   {"lock_type", 32 /* RECORD|TABLE|UNKNOWN */, MYSQL_TYPE_STRING,
638    0, 0, "", SKIP_OPEN_TABLE},
639 
640 #define IDX_LOCK_TABLE		4
641   {"lock_table", 1024, MYSQL_TYPE_STRING,
642    0, 0, "", SKIP_OPEN_TABLE},
643 
644 #define IDX_LOCK_INDEX		5
645   {"lock_index", 1024, MYSQL_TYPE_STRING,
646    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
647 
648 #define IDX_LOCK_SPACE		6
649   {"lock_space", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
650    0, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
651 
652 #define IDX_LOCK_PAGE		7
653   {"lock_page", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
654    0, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
655 
656 #define IDX_LOCK_REC		8
657   {"lock_rec", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
658    0, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
659 
660 #define IDX_LOCK_DATA		9
661   {"lock_data", TRX_I_S_LOCK_DATA_MAX_LEN, MYSQL_TYPE_STRING,
662    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
663 
664   END_OF_ST_FIELD_INFO
665 };
666 
667 /*******************************************************************//**
668 Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_locks
669 table with it.
670 @return 0 on success */
671 static
672 int
fill_innodb_locks_from_cache(trx_i_s_cache_t * cache,THD * thd,TABLE * table)673 fill_innodb_locks_from_cache(
674 /*=========================*/
675 	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
676 	THD*			thd,	/*!< in: MySQL client connection */
677 	TABLE*			table)	/*!< in/out: fill this table */
678 {
679 	Field**	fields;
680 	ulint	rows_num;
681 	char	lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
682 	ulint	i;
683 
684 	DBUG_ENTER("fill_innodb_locks_from_cache");
685 
686 	fields = table->field;
687 
688 	rows_num = trx_i_s_cache_get_rows_used(cache,
689 					       I_S_INNODB_LOCKS);
690 
691 	for (i = 0; i < rows_num; i++) {
692 
693 		i_s_locks_row_t*	row;
694 		char			buf[MAX_FULL_NAME_LEN + 1];
695 		const char*		bufend;
696 
697 		char			lock_trx_id[TRX_ID_MAX_LEN + 1];
698 
699 		row = (i_s_locks_row_t*)
700 			trx_i_s_cache_get_nth_row(
701 				cache, I_S_INNODB_LOCKS, i);
702 
703 		/* lock_id */
704 		trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id));
705 		OK(field_store_string(fields[IDX_LOCK_ID],
706 				      lock_id));
707 
708 		/* lock_trx_id */
709 		snprintf(lock_trx_id, sizeof(lock_trx_id),
710 			 TRX_ID_FMT, row->lock_trx_id);
711 		OK(field_store_string(fields[IDX_LOCK_TRX_ID], lock_trx_id));
712 
713 		/* lock_mode */
714 		OK(field_store_string(fields[IDX_LOCK_MODE],
715 				      row->lock_mode));
716 
717 		/* lock_type */
718 		OK(field_store_string(fields[IDX_LOCK_TYPE],
719 				      row->lock_type));
720 
721 		/* lock_table */
722 		bufend = innobase_convert_name(buf, sizeof(buf),
723 					       row->lock_table,
724 					       strlen(row->lock_table),
725 					       thd);
726 		OK(fields[IDX_LOCK_TABLE]->store(
727 			buf, uint(bufend - buf), system_charset_info));
728 
729 		/* lock_index */
730 		OK(field_store_string(fields[IDX_LOCK_INDEX],
731 				      row->lock_index));
732 
733 		/* lock_space */
734 		OK(field_store_ulint(fields[IDX_LOCK_SPACE],
735 				     row->lock_space));
736 
737 		/* lock_page */
738 		OK(field_store_ulint(fields[IDX_LOCK_PAGE],
739 				     row->lock_page));
740 
741 		/* lock_rec */
742 		OK(field_store_ulint(fields[IDX_LOCK_REC],
743 				     row->lock_rec));
744 
745 		/* lock_data */
746 		OK(field_store_string(fields[IDX_LOCK_DATA],
747 				      row->lock_data));
748 
749 		OK(schema_table_store_record(thd, table));
750 	}
751 
752 	DBUG_RETURN(0);
753 }
754 
755 /*******************************************************************//**
756 Bind the dynamic table INFORMATION_SCHEMA.innodb_locks
757 @return 0 on success */
758 static
759 int
innodb_locks_init(void * p)760 innodb_locks_init(
761 /*==============*/
762 	void*	p)	/*!< in/out: table schema object */
763 {
764 	ST_SCHEMA_TABLE*	schema;
765 
766 	DBUG_ENTER("innodb_locks_init");
767 
768 	schema = (ST_SCHEMA_TABLE*) p;
769 
770 	schema->fields_info = innodb_locks_fields_info;
771 	schema->fill_table = trx_i_s_common_fill_table;
772 
773 	DBUG_RETURN(0);
774 }
775 
776 UNIV_INTERN struct st_maria_plugin	i_s_innodb_locks =
777 {
778 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
779 	/* int */
780 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
781 
782 	/* pointer to type-specific plugin descriptor */
783 	/* void* */
784 	&i_s_info,
785 
786 	/* plugin name */
787 	/* const char* */
788 	"INNODB_LOCKS",
789 
790 	/* plugin author (for SHOW PLUGINS) */
791 	/* const char* */
792 	plugin_author,
793 
794 	/* general descriptive text (for SHOW PLUGINS) */
795 	/* const char* */
796 	"InnoDB conflicting locks",
797 
798 	/* the plugin license (PLUGIN_LICENSE_XXX) */
799 	/* int */
800 	PLUGIN_LICENSE_GPL,
801 
802 	/* the function to invoke when plugin is loaded */
803 	/* int (*)(void*); */
804 	innodb_locks_init,
805 
806 	/* the function to invoke when plugin is unloaded */
807 	/* int (*)(void*); */
808 	i_s_common_deinit,
809 
810 	/* plugin version (for SHOW PLUGINS) */
811 	/* unsigned int */
812 	INNODB_VERSION_SHORT,
813 
814 	/* struct st_mysql_show_var* */
815 	NULL,
816 
817 	/* struct st_mysql_sys_var** */
818 	NULL,
819 
820         /* Maria extension */
821 	INNODB_VERSION_STR,
822         MariaDB_PLUGIN_MATURITY_STABLE,
823 };
824 
825 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */
826 static ST_FIELD_INFO innodb_lock_waits_fields_info[]=
827 {
828 #define IDX_REQUESTING_TRX_ID	0
829   {"requesting_trx_id", TRX_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
830    0, 0, "", SKIP_OPEN_TABLE},
831 
832 #define IDX_REQUESTED_LOCK_ID	1
833   {"requested_lock_id", TRX_I_S_LOCK_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
834    0, 0, "", SKIP_OPEN_TABLE},
835 
836 #define IDX_BLOCKING_TRX_ID	2
837   {"blocking_trx_id", TRX_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
838    0, 0, "", SKIP_OPEN_TABLE},
839 
840 #define IDX_BLOCKING_LOCK_ID	3
841   {"blocking_lock_id", TRX_I_S_LOCK_ID_MAX_LEN + 1, MYSQL_TYPE_STRING,
842    0, 0, "", SKIP_OPEN_TABLE},
843 
844   END_OF_ST_FIELD_INFO
845 };
846 
847 /*******************************************************************//**
848 Read data from cache buffer and fill the
849 INFORMATION_SCHEMA.innodb_lock_waits table with it.
850 @return 0 on success */
851 static
852 int
fill_innodb_lock_waits_from_cache(trx_i_s_cache_t * cache,THD * thd,TABLE * table)853 fill_innodb_lock_waits_from_cache(
854 /*==============================*/
855 	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
856 	THD*			thd,	/*!< in: used to call
857 					schema_table_store_record() */
858 	TABLE*			table)	/*!< in/out: fill this table */
859 {
860 	Field**	fields;
861 	ulint	rows_num;
862 	char	requested_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
863 	char	blocking_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
864 	ulint	i;
865 
866 	DBUG_ENTER("fill_innodb_lock_waits_from_cache");
867 
868 	fields = table->field;
869 
870 	rows_num = trx_i_s_cache_get_rows_used(cache,
871 					       I_S_INNODB_LOCK_WAITS);
872 
873 	for (i = 0; i < rows_num; i++) {
874 
875 		i_s_lock_waits_row_t*	row;
876 
877 		char	requesting_trx_id[TRX_ID_MAX_LEN + 1];
878 		char	blocking_trx_id[TRX_ID_MAX_LEN + 1];
879 
880 		row = (i_s_lock_waits_row_t*)
881 			trx_i_s_cache_get_nth_row(
882 				cache, I_S_INNODB_LOCK_WAITS, i);
883 
884 		/* requesting_trx_id */
885 		snprintf(requesting_trx_id, sizeof(requesting_trx_id),
886 			 TRX_ID_FMT, row->requested_lock_row->lock_trx_id);
887 		OK(field_store_string(fields[IDX_REQUESTING_TRX_ID],
888 				      requesting_trx_id));
889 
890 		/* requested_lock_id */
891 		OK(field_store_string(
892 			   fields[IDX_REQUESTED_LOCK_ID],
893 			   trx_i_s_create_lock_id(
894 				   row->requested_lock_row,
895 				   requested_lock_id,
896 				   sizeof(requested_lock_id))));
897 
898 		/* blocking_trx_id */
899 		snprintf(blocking_trx_id, sizeof(blocking_trx_id),
900 			 TRX_ID_FMT, row->blocking_lock_row->lock_trx_id);
901 		OK(field_store_string(fields[IDX_BLOCKING_TRX_ID],
902 				      blocking_trx_id));
903 
904 		/* blocking_lock_id */
905 		OK(field_store_string(
906 			   fields[IDX_BLOCKING_LOCK_ID],
907 			   trx_i_s_create_lock_id(
908 				   row->blocking_lock_row,
909 				   blocking_lock_id,
910 				   sizeof(blocking_lock_id))));
911 
912 		OK(schema_table_store_record(thd, table));
913 	}
914 
915 	DBUG_RETURN(0);
916 }
917 
918 /*******************************************************************//**
919 Bind the dynamic table INFORMATION_SCHEMA.innodb_lock_waits
920 @return 0 on success */
921 static
922 int
innodb_lock_waits_init(void * p)923 innodb_lock_waits_init(
924 /*===================*/
925 	void*	p)	/*!< in/out: table schema object */
926 {
927 	ST_SCHEMA_TABLE*	schema;
928 
929 	DBUG_ENTER("innodb_lock_waits_init");
930 
931 	schema = (ST_SCHEMA_TABLE*) p;
932 
933 	schema->fields_info = innodb_lock_waits_fields_info;
934 	schema->fill_table = trx_i_s_common_fill_table;
935 
936 	DBUG_RETURN(0);
937 }
938 
939 UNIV_INTERN struct st_maria_plugin	i_s_innodb_lock_waits =
940 {
941 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
942 	/* int */
943 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
944 
945 	/* pointer to type-specific plugin descriptor */
946 	/* void* */
947 	&i_s_info,
948 
949 	/* plugin name */
950 	/* const char* */
951 	"INNODB_LOCK_WAITS",
952 
953 	/* plugin author (for SHOW PLUGINS) */
954 	/* const char* */
955 	plugin_author,
956 
957 	/* general descriptive text (for SHOW PLUGINS) */
958 	/* const char* */
959 	"InnoDB which lock is blocking which",
960 
961 	/* the plugin license (PLUGIN_LICENSE_XXX) */
962 	/* int */
963 	PLUGIN_LICENSE_GPL,
964 
965 	/* the function to invoke when plugin is loaded */
966 	/* int (*)(void*); */
967 	innodb_lock_waits_init,
968 
969 	/* the function to invoke when plugin is unloaded */
970 	/* int (*)(void*); */
971 	i_s_common_deinit,
972 
973 	/* plugin version (for SHOW PLUGINS) */
974 	/* unsigned int */
975 	INNODB_VERSION_SHORT,
976 
977 	/* struct st_mysql_show_var* */
978 	NULL,
979 
980 	/* struct st_mysql_sys_var** */
981 	NULL,
982 
983         /* Maria extension */
984 	INNODB_VERSION_STR,
985         MariaDB_PLUGIN_MATURITY_STABLE,
986 };
987 
988 /*******************************************************************//**
989 Common function to fill any of the dynamic tables:
990 INFORMATION_SCHEMA.innodb_trx
991 INFORMATION_SCHEMA.innodb_locks
992 INFORMATION_SCHEMA.innodb_lock_waits
993 @return 0 on success */
994 static
995 int
trx_i_s_common_fill_table(THD * thd,TABLE_LIST * tables,Item *)996 trx_i_s_common_fill_table(
997 /*======================*/
998 	THD*		thd,	/*!< in: thread */
999 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1000 	Item*		)	/*!< in: condition (not used) */
1001 {
1002 	LEX_CSTRING		table_name;
1003 	int			ret;
1004 	trx_i_s_cache_t*	cache;
1005 
1006 	DBUG_ENTER("trx_i_s_common_fill_table");
1007 
1008 	/* deny access to non-superusers */
1009 	if (check_global_access(thd, PROCESS_ACL)) {
1010 
1011 		DBUG_RETURN(0);
1012 	}
1013 
1014 	/* minimize the number of places where global variables are
1015 	referenced */
1016 	cache = trx_i_s_cache;
1017 
1018 	/* which table we have to fill? */
1019 	table_name = tables->schema_table_name;
1020 	/* or table_name = tables->schema_table->table_name; */
1021 
1022 	RETURN_IF_INNODB_NOT_STARTED(table_name.str);
1023 
1024 	/* update the cache */
1025 	trx_i_s_cache_start_write(cache);
1026 	trx_i_s_possibly_fetch_data_into_cache(cache);
1027 	trx_i_s_cache_end_write(cache);
1028 
1029 	if (trx_i_s_cache_is_truncated(cache)) {
1030 
1031 		ib::warn() << "Data in " << table_name.str << " truncated due to"
1032 			" memory limit of " << TRX_I_S_MEM_LIMIT << " bytes";
1033 	}
1034 
1035 	ret = 0;
1036 
1037 	trx_i_s_cache_start_read(cache);
1038 
1039 	if (innobase_strcasecmp(table_name.str, "innodb_trx") == 0) {
1040 
1041 		if (fill_innodb_trx_from_cache(
1042 			cache, thd, tables->table) != 0) {
1043 
1044 			ret = 1;
1045 		}
1046 
1047 	} else if (innobase_strcasecmp(table_name.str, "innodb_locks") == 0) {
1048 
1049 		if (fill_innodb_locks_from_cache(
1050 			cache, thd, tables->table) != 0) {
1051 
1052 			ret = 1;
1053 		}
1054 
1055 	} else if (innobase_strcasecmp(table_name.str, "innodb_lock_waits") == 0) {
1056 
1057 		if (fill_innodb_lock_waits_from_cache(
1058 			cache, thd, tables->table) != 0) {
1059 
1060 			ret = 1;
1061 		}
1062 
1063 	} else {
1064 		ib::error() << "trx_i_s_common_fill_table() was"
1065 			" called to fill unknown table: " << table_name.str << "."
1066 			" This function only knows how to fill"
1067 			" innodb_trx, innodb_locks and"
1068 			" innodb_lock_waits tables.";
1069 
1070 		ret = 1;
1071 	}
1072 
1073 	trx_i_s_cache_end_read(cache);
1074 
1075 #if 0
1076 	DBUG_RETURN(ret);
1077 #else
1078 	/* if this function returns something else than 0 then a
1079 	deadlock occurs between the mysqld server and mysql client,
1080 	see http://bugs.mysql.com/29900 ; when that bug is resolved
1081 	we can enable the DBUG_RETURN(ret) above */
1082 	ret++;  // silence a gcc46 warning
1083 	DBUG_RETURN(0);
1084 #endif
1085 }
1086 
1087 /* Fields of the dynamic table information_schema.innodb_cmp. */
1088 static ST_FIELD_INFO i_s_cmp_fields_info[]=
1089 {
1090   {"page_size", 5, MYSQL_TYPE_LONG,
1091    0, 0, "Compressed Page Size", SKIP_OPEN_TABLE},
1092   {"compress_ops", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1093    0, 0, "Total Number of Compressions", SKIP_OPEN_TABLE},
1094   {"compress_ops_ok", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1095    0, 0, "Total Number of Successful Compressions", SKIP_OPEN_TABLE},
1096   {"compress_time", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1097    0, 0, "Total Duration of Compressions, in Seconds", SKIP_OPEN_TABLE},
1098   {"uncompress_ops", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1099    0, 0, "Total Number of Decompressions", SKIP_OPEN_TABLE},
1100   {"uncompress_time", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1101    0, 0, "Total Duration of Decompressions, in Seconds", SKIP_OPEN_TABLE},
1102   END_OF_ST_FIELD_INFO
1103 };
1104 
1105 
1106 /*******************************************************************//**
1107 Fill the dynamic table information_schema.innodb_cmp or
1108 innodb_cmp_reset.
1109 @return 0 on success, 1 on failure */
1110 static
1111 int
i_s_cmp_fill_low(THD * thd,TABLE_LIST * tables,Item *,ibool reset)1112 i_s_cmp_fill_low(
1113 /*=============*/
1114 	THD*		thd,	/*!< in: thread */
1115 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1116 	Item*		,	/*!< in: condition (ignored) */
1117 	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1118 {
1119 	TABLE*	table	= (TABLE*) tables->table;
1120 	int	status	= 0;
1121 
1122 	DBUG_ENTER("i_s_cmp_fill_low");
1123 
1124 	/* deny access to non-superusers */
1125 	if (check_global_access(thd, PROCESS_ACL)) {
1126 
1127 		DBUG_RETURN(0);
1128 	}
1129 
1130 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
1131 
1132 	for (uint i = 0; i < PAGE_ZIP_SSIZE_MAX; i++) {
1133 		page_zip_stat_t*	zip_stat = &page_zip_stat[i];
1134 
1135 		table->field[0]->store(UNIV_ZIP_SIZE_MIN << i);
1136 
1137 		/* The cumulated counts are not protected by any
1138 		mutex.  Thus, some operation in page0zip.cc could
1139 		increment a counter between the time we read it and
1140 		clear it.  We could introduce mutex protection, but it
1141 		could cause a measureable performance hit in
1142 		page0zip.cc. */
1143 		table->field[1]->store(zip_stat->compressed, true);
1144 		table->field[2]->store(zip_stat->compressed_ok, true);
1145 		table->field[3]->store(zip_stat->compressed_usec / 1000000,
1146 				       true);
1147 		table->field[4]->store(zip_stat->decompressed, true);
1148 		table->field[5]->store(zip_stat->decompressed_usec / 1000000,
1149 				       true);
1150 
1151 		if (reset) {
1152 			new (zip_stat) page_zip_stat_t();
1153 		}
1154 
1155 		if (schema_table_store_record(thd, table)) {
1156 			status = 1;
1157 			break;
1158 		}
1159 	}
1160 
1161 	DBUG_RETURN(status);
1162 }
1163 
1164 /*******************************************************************//**
1165 Fill the dynamic table information_schema.innodb_cmp.
1166 @return 0 on success, 1 on failure */
1167 static
1168 int
i_s_cmp_fill(THD * thd,TABLE_LIST * tables,Item * cond)1169 i_s_cmp_fill(
1170 /*=========*/
1171 	THD*		thd,	/*!< in: thread */
1172 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1173 	Item*		cond)	/*!< in: condition (ignored) */
1174 {
1175 	return(i_s_cmp_fill_low(thd, tables, cond, FALSE));
1176 }
1177 
1178 /*******************************************************************//**
1179 Fill the dynamic table information_schema.innodb_cmp_reset.
1180 @return 0 on success, 1 on failure */
1181 static
1182 int
i_s_cmp_reset_fill(THD * thd,TABLE_LIST * tables,Item * cond)1183 i_s_cmp_reset_fill(
1184 /*===============*/
1185 	THD*		thd,	/*!< in: thread */
1186 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1187 	Item*		cond)	/*!< in: condition (ignored) */
1188 {
1189 	return(i_s_cmp_fill_low(thd, tables, cond, TRUE));
1190 }
1191 
1192 /*******************************************************************//**
1193 Bind the dynamic table information_schema.innodb_cmp.
1194 @return 0 on success */
1195 static
1196 int
i_s_cmp_init(void * p)1197 i_s_cmp_init(
1198 /*=========*/
1199 	void*	p)	/*!< in/out: table schema object */
1200 {
1201 	DBUG_ENTER("i_s_cmp_init");
1202 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1203 
1204 	schema->fields_info = i_s_cmp_fields_info;
1205 	schema->fill_table = i_s_cmp_fill;
1206 
1207 	DBUG_RETURN(0);
1208 }
1209 
1210 /*******************************************************************//**
1211 Bind the dynamic table information_schema.innodb_cmp_reset.
1212 @return 0 on success */
1213 static
1214 int
i_s_cmp_reset_init(void * p)1215 i_s_cmp_reset_init(
1216 /*===============*/
1217 	void*	p)	/*!< in/out: table schema object */
1218 {
1219 	DBUG_ENTER("i_s_cmp_reset_init");
1220 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1221 
1222 	schema->fields_info = i_s_cmp_fields_info;
1223 	schema->fill_table = i_s_cmp_reset_fill;
1224 
1225 	DBUG_RETURN(0);
1226 }
1227 
1228 UNIV_INTERN struct st_maria_plugin	i_s_innodb_cmp =
1229 {
1230 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1231 	/* int */
1232 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
1233 
1234 	/* pointer to type-specific plugin descriptor */
1235 	/* void* */
1236 	&i_s_info,
1237 
1238 	/* plugin name */
1239 	/* const char* */
1240 	"INNODB_CMP",
1241 
1242 	/* plugin author (for SHOW PLUGINS) */
1243 	/* const char* */
1244 	plugin_author,
1245 
1246 	/* general descriptive text (for SHOW PLUGINS) */
1247 	/* const char* */
1248 	"Statistics for the InnoDB compression",
1249 
1250 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1251 	/* int */
1252 	PLUGIN_LICENSE_GPL,
1253 
1254 	/* the function to invoke when plugin is loaded */
1255 	/* int (*)(void*); */
1256 	i_s_cmp_init,
1257 
1258 	/* the function to invoke when plugin is unloaded */
1259 	/* int (*)(void*); */
1260 	i_s_common_deinit,
1261 
1262 	/* plugin version (for SHOW PLUGINS) */
1263 	/* unsigned int */
1264 	INNODB_VERSION_SHORT,
1265 
1266 	/* struct st_mysql_show_var* */
1267 	NULL,
1268 
1269 	/* struct st_mysql_sys_var** */
1270 	NULL,
1271 
1272         /* Maria extension */
1273 	INNODB_VERSION_STR,
1274         MariaDB_PLUGIN_MATURITY_STABLE,
1275 };
1276 
1277 UNIV_INTERN struct st_maria_plugin	i_s_innodb_cmp_reset =
1278 {
1279 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1280 	/* int */
1281 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
1282 
1283 	/* pointer to type-specific plugin descriptor */
1284 	/* void* */
1285 	&i_s_info,
1286 
1287 	/* plugin name */
1288 	/* const char* */
1289 	"INNODB_CMP_RESET",
1290 
1291 	/* plugin author (for SHOW PLUGINS) */
1292 	/* const char* */
1293 	plugin_author,
1294 
1295 	/* general descriptive text (for SHOW PLUGINS) */
1296 	/* const char* */
1297 	"Statistics for the InnoDB compression;"
1298 		   " reset cumulated counts",
1299 
1300 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1301 	/* int */
1302 	PLUGIN_LICENSE_GPL,
1303 
1304 	/* the function to invoke when plugin is loaded */
1305 	/* int (*)(void*); */
1306 	i_s_cmp_reset_init,
1307 
1308 	/* the function to invoke when plugin is unloaded */
1309 	/* int (*)(void*); */
1310 	i_s_common_deinit,
1311 
1312 	/* plugin version (for SHOW PLUGINS) */
1313 	/* unsigned int */
1314 	INNODB_VERSION_SHORT,
1315 
1316 	/* struct st_mysql_show_var* */
1317 	NULL,
1318 
1319 	/* struct st_mysql_sys_var** */
1320 	NULL,
1321 
1322         /* Maria extension */
1323 	INNODB_VERSION_STR,
1324         MariaDB_PLUGIN_MATURITY_STABLE,
1325 };
1326 
1327 /* Fields of the dynamic tables
1328 information_schema.innodb_cmp_per_index and
1329 information_schema.innodb_cmp_per_index_reset. */
1330 static ST_FIELD_INFO i_s_cmp_per_index_fields_info[]=
1331 {
1332 #define IDX_DATABASE_NAME	0
1333   {"database_name", 192, MYSQL_TYPE_STRING,
1334    0, 0, "", SKIP_OPEN_TABLE},
1335 
1336 #define IDX_TABLE_NAME		1
1337   {"table_name", 192, MYSQL_TYPE_STRING,
1338    0, 0, "", SKIP_OPEN_TABLE},
1339 
1340 #define IDX_INDEX_NAME		2
1341   {"index_name", 192, MYSQL_TYPE_STRING,
1342    0, 0, "", SKIP_OPEN_TABLE},
1343 
1344 #define IDX_COMPRESS_OPS	3
1345   {"compress_ops", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1346    0, 0, "", SKIP_OPEN_TABLE},
1347 
1348 #define IDX_COMPRESS_OPS_OK	4
1349   {"compress_ops_ok", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1350    0, 0, "", SKIP_OPEN_TABLE},
1351 
1352 #define IDX_COMPRESS_TIME	5
1353   {"compress_time", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1354    0, 0, "", SKIP_OPEN_TABLE},
1355 
1356 #define IDX_UNCOMPRESS_OPS	6
1357   {"uncompress_ops", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1358    0, 0, "", SKIP_OPEN_TABLE},
1359 
1360 #define IDX_UNCOMPRESS_TIME	7
1361   {"uncompress_time", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1362    0, 0, "", SKIP_OPEN_TABLE},
1363 
1364   END_OF_ST_FIELD_INFO
1365 };
1366 
1367 /*******************************************************************//**
1368 Fill the dynamic table
1369 information_schema.innodb_cmp_per_index or
1370 information_schema.innodb_cmp_per_index_reset.
1371 @return 0 on success, 1 on failure */
1372 static
1373 int
i_s_cmp_per_index_fill_low(THD * thd,TABLE_LIST * tables,Item *,ibool reset)1374 i_s_cmp_per_index_fill_low(
1375 /*=======================*/
1376 	THD*		thd,	/*!< in: thread */
1377 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1378 	Item*		,	/*!< in: condition (ignored) */
1379 	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1380 {
1381 	TABLE*	table = tables->table;
1382 	Field**	fields = table->field;
1383 	int	status = 0;
1384 
1385 	DBUG_ENTER("i_s_cmp_per_index_fill_low");
1386 
1387 	/* deny access to non-superusers */
1388 	if (check_global_access(thd, PROCESS_ACL)) {
1389 
1390 		DBUG_RETURN(0);
1391 	}
1392 
1393 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
1394 
1395 	/* Create a snapshot of the stats so we do not bump into lock
1396 	order violations with dict_sys->mutex below. */
1397 	mutex_enter(&page_zip_stat_per_index_mutex);
1398 	page_zip_stat_per_index_t		snap (page_zip_stat_per_index);
1399 	mutex_exit(&page_zip_stat_per_index_mutex);
1400 
1401 	mutex_enter(&dict_sys->mutex);
1402 
1403 	page_zip_stat_per_index_t::iterator	iter;
1404 	ulint					i;
1405 
1406 	for (iter = snap.begin(), i = 0; iter != snap.end(); iter++, i++) {
1407 
1408 		dict_index_t*	index = dict_index_find_on_id_low(iter->first);
1409 
1410 		if (index != NULL) {
1411 			char	db_utf8[MAX_DB_UTF8_LEN];
1412 			char	table_utf8[MAX_TABLE_UTF8_LEN];
1413 
1414 			dict_fs2utf8(index->table->name.m_name,
1415 				     db_utf8, sizeof(db_utf8),
1416 				     table_utf8, sizeof(table_utf8));
1417 
1418 			status = field_store_string(fields[IDX_DATABASE_NAME],
1419 						    db_utf8)
1420 				|| field_store_string(fields[IDX_TABLE_NAME],
1421 						      table_utf8)
1422 				|| field_store_string(fields[IDX_INDEX_NAME],
1423 						      index->name);
1424 		} else {
1425 			/* index not found */
1426 			char name[MY_INT64_NUM_DECIMAL_DIGITS
1427 				  + sizeof "index_id: "];
1428 			fields[IDX_DATABASE_NAME]->set_null();
1429 			fields[IDX_TABLE_NAME]->set_null();
1430 			fields[IDX_INDEX_NAME]->set_notnull();
1431 			status = fields[IDX_INDEX_NAME]->store(
1432 				name,
1433 				uint(snprintf(name, sizeof name,
1434 					      "index_id: " IB_ID_FMT,
1435 					      iter->first)),
1436 				system_charset_info);
1437 		}
1438 
1439 		if (status
1440 		    || fields[IDX_COMPRESS_OPS]->store(
1441 			    iter->second.compressed, true)
1442 		    || fields[IDX_COMPRESS_OPS_OK]->store(
1443 			    iter->second.compressed_ok, true)
1444 		    || fields[IDX_COMPRESS_TIME]->store(
1445 			    iter->second.compressed_usec / 1000000, true)
1446 		    || fields[IDX_UNCOMPRESS_OPS]->store(
1447 			    iter->second.decompressed, true)
1448 		    || fields[IDX_UNCOMPRESS_TIME]->store(
1449 			    iter->second.decompressed_usec / 1000000, true)
1450 		    || schema_table_store_record(thd, table)) {
1451 			status = 1;
1452 			break;
1453 		}
1454 		/* Release and reacquire the dict mutex to allow other
1455 		threads to proceed. This could eventually result in the
1456 		contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
1457 		inconsistent, but it is an acceptable compromise. */
1458 		if (i == 1000) {
1459 			mutex_exit(&dict_sys->mutex);
1460 			i = 0;
1461 			mutex_enter(&dict_sys->mutex);
1462 		}
1463 	}
1464 
1465 	mutex_exit(&dict_sys->mutex);
1466 
1467 	if (reset) {
1468 		page_zip_reset_stat_per_index();
1469 	}
1470 
1471 	DBUG_RETURN(status);
1472 }
1473 
1474 /*******************************************************************//**
1475 Fill the dynamic table information_schema.innodb_cmp_per_index.
1476 @return 0 on success, 1 on failure */
1477 static
1478 int
i_s_cmp_per_index_fill(THD * thd,TABLE_LIST * tables,Item * cond)1479 i_s_cmp_per_index_fill(
1480 /*===================*/
1481 	THD*		thd,	/*!< in: thread */
1482 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1483 	Item*		cond)	/*!< in: condition (ignored) */
1484 {
1485 	return(i_s_cmp_per_index_fill_low(thd, tables, cond, FALSE));
1486 }
1487 
1488 /*******************************************************************//**
1489 Fill the dynamic table information_schema.innodb_cmp_per_index_reset.
1490 @return 0 on success, 1 on failure */
1491 static
1492 int
i_s_cmp_per_index_reset_fill(THD * thd,TABLE_LIST * tables,Item * cond)1493 i_s_cmp_per_index_reset_fill(
1494 /*=========================*/
1495 	THD*		thd,	/*!< in: thread */
1496 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1497 	Item*		cond)	/*!< in: condition (ignored) */
1498 {
1499 	return(i_s_cmp_per_index_fill_low(thd, tables, cond, TRUE));
1500 }
1501 
1502 /*******************************************************************//**
1503 Bind the dynamic table information_schema.innodb_cmp_per_index.
1504 @return 0 on success */
1505 static
1506 int
i_s_cmp_per_index_init(void * p)1507 i_s_cmp_per_index_init(
1508 /*===================*/
1509 	void*	p)	/*!< in/out: table schema object */
1510 {
1511 	DBUG_ENTER("i_s_cmp_init");
1512 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1513 
1514 	schema->fields_info = i_s_cmp_per_index_fields_info;
1515 	schema->fill_table = i_s_cmp_per_index_fill;
1516 
1517 	DBUG_RETURN(0);
1518 }
1519 
1520 /*******************************************************************//**
1521 Bind the dynamic table information_schema.innodb_cmp_per_index_reset.
1522 @return 0 on success */
1523 static
1524 int
i_s_cmp_per_index_reset_init(void * p)1525 i_s_cmp_per_index_reset_init(
1526 /*=========================*/
1527 	void*	p)	/*!< in/out: table schema object */
1528 {
1529 	DBUG_ENTER("i_s_cmp_reset_init");
1530 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1531 
1532 	schema->fields_info = i_s_cmp_per_index_fields_info;
1533 	schema->fill_table = i_s_cmp_per_index_reset_fill;
1534 
1535 	DBUG_RETURN(0);
1536 }
1537 
1538 UNIV_INTERN struct st_maria_plugin	i_s_innodb_cmp_per_index =
1539 {
1540 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1541 	/* int */
1542 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
1543 
1544 	/* pointer to type-specific plugin descriptor */
1545 	/* void* */
1546 	&i_s_info,
1547 
1548 	/* plugin name */
1549 	/* const char* */
1550 	"INNODB_CMP_PER_INDEX",
1551 
1552 	/* plugin author (for SHOW PLUGINS) */
1553 	/* const char* */
1554 	plugin_author,
1555 
1556 	/* general descriptive text (for SHOW PLUGINS) */
1557 	/* const char* */
1558 	"Statistics for the InnoDB compression (per index)",
1559 
1560 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1561 	/* int */
1562 	PLUGIN_LICENSE_GPL,
1563 
1564 	/* the function to invoke when plugin is loaded */
1565 	/* int (*)(void*); */
1566 	i_s_cmp_per_index_init,
1567 
1568 	/* the function to invoke when plugin is unloaded */
1569 	/* int (*)(void*); */
1570 	i_s_common_deinit,
1571 
1572 	/* plugin version (for SHOW PLUGINS) */
1573 	/* unsigned int */
1574 	INNODB_VERSION_SHORT,
1575 
1576 	/* struct st_mysql_show_var* */
1577 	NULL,
1578 
1579 	/* struct st_mysql_sys_var** */
1580 	NULL,
1581 
1582         /* Maria extension */
1583 	INNODB_VERSION_STR,
1584         MariaDB_PLUGIN_MATURITY_STABLE,
1585 };
1586 
1587 UNIV_INTERN struct st_maria_plugin	i_s_innodb_cmp_per_index_reset =
1588 {
1589 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1590 	/* int */
1591 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
1592 
1593 	/* pointer to type-specific plugin descriptor */
1594 	/* void* */
1595 	&i_s_info,
1596 
1597 	/* plugin name */
1598 	/* const char* */
1599 	"INNODB_CMP_PER_INDEX_RESET",
1600 
1601 	/* plugin author (for SHOW PLUGINS) */
1602 	/* const char* */
1603 	plugin_author,
1604 
1605 	/* general descriptive text (for SHOW PLUGINS) */
1606 	/* const char* */
1607 	"Statistics for the InnoDB compression (per index);"
1608 		   " reset cumulated counts",
1609 
1610 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1611 	/* int */
1612 	PLUGIN_LICENSE_GPL,
1613 
1614 	/* the function to invoke when plugin is loaded */
1615 	/* int (*)(void*); */
1616 	i_s_cmp_per_index_reset_init,
1617 
1618 	/* the function to invoke when plugin is unloaded */
1619 	/* int (*)(void*); */
1620 	i_s_common_deinit,
1621 
1622 	/* plugin version (for SHOW PLUGINS) */
1623 	/* unsigned int */
1624 	INNODB_VERSION_SHORT,
1625 
1626 	/* struct st_mysql_show_var* */
1627 	NULL,
1628 
1629 	/* struct st_mysql_sys_var** */
1630 	NULL,
1631 
1632         /* Maria extension */
1633 	INNODB_VERSION_STR,
1634         MariaDB_PLUGIN_MATURITY_STABLE,
1635 };
1636 
1637 /* Fields of the dynamic table information_schema.innodb_cmpmem. */
1638 static ST_FIELD_INFO i_s_cmpmem_fields_info[]=
1639 {
1640   {"page_size", 5, MYSQL_TYPE_LONG,
1641    0, 0, "Buddy Block Size", SKIP_OPEN_TABLE},
1642   {"buffer_pool_instance", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1643    0, 0, "Buffer Pool Id", SKIP_OPEN_TABLE},
1644   {"pages_used", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1645    0, 0, "Currently in Use", SKIP_OPEN_TABLE},
1646   {"pages_free", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1647    0, 0, "Currently Available", SKIP_OPEN_TABLE},
1648   {"relocation_ops", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1649    0, 0, "Total Number of Relocations", SKIP_OPEN_TABLE},
1650   {"relocation_time", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
1651    0, 0, "Total Duration of Relocations, in Seconds", SKIP_OPEN_TABLE},
1652   END_OF_ST_FIELD_INFO
1653 };
1654 
1655 /*******************************************************************//**
1656 Fill the dynamic table information_schema.innodb_cmpmem or
1657 innodb_cmpmem_reset.
1658 @return 0 on success, 1 on failure */
1659 static
1660 int
i_s_cmpmem_fill_low(THD * thd,TABLE_LIST * tables,Item *,ibool reset)1661 i_s_cmpmem_fill_low(
1662 /*================*/
1663 	THD*		thd,	/*!< in: thread */
1664 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1665 	Item*		,	/*!< in: condition (ignored) */
1666 	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1667 {
1668 	int		status = 0;
1669 	TABLE*	table	= (TABLE*) tables->table;
1670 
1671 	DBUG_ENTER("i_s_cmpmem_fill_low");
1672 
1673 	/* deny access to non-superusers */
1674 	if (check_global_access(thd, PROCESS_ACL)) {
1675 
1676 		DBUG_RETURN(0);
1677 	}
1678 
1679 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
1680 
1681 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
1682 		buf_pool_t*		buf_pool;
1683 		ulint			zip_free_len_local[BUF_BUDDY_SIZES_MAX + 1];
1684 		buf_buddy_stat_t	buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1];
1685 
1686 		status	= 0;
1687 
1688 		buf_pool = buf_pool_from_array(i);
1689 
1690 		/* Save buddy stats for buffer pool in local variables. */
1691 		buf_pool_mutex_enter(buf_pool);
1692 		for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
1693 
1694 			zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ?
1695 				UT_LIST_GET_LEN(buf_pool->zip_free[x]) : 0;
1696 
1697 			buddy_stat_local[x] = buf_pool->buddy_stat[x];
1698 
1699 			if (reset) {
1700 				/* This is protected by buf_pool->mutex. */
1701 				buf_pool->buddy_stat[x].relocated = 0;
1702 				buf_pool->buddy_stat[x].relocated_usec = 0;
1703 			}
1704 		}
1705 		buf_pool_mutex_exit(buf_pool);
1706 
1707 		for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
1708 			buf_buddy_stat_t*	buddy_stat;
1709 
1710 			buddy_stat = &buddy_stat_local[x];
1711 
1712 			table->field[0]->store(BUF_BUDDY_LOW << x);
1713 			table->field[1]->store(i, true);
1714 			table->field[2]->store(buddy_stat->used, true);
1715 			table->field[3]->store(zip_free_len_local[x], true);
1716 			table->field[4]->store(buddy_stat->relocated, true);
1717 			table->field[5]->store(
1718 				buddy_stat->relocated_usec / 1000000, true);
1719 
1720 			if (schema_table_store_record(thd, table)) {
1721 				status = 1;
1722 				break;
1723 			}
1724 		}
1725 
1726 		if (status) {
1727 			break;
1728 		}
1729 	}
1730 
1731 	DBUG_RETURN(status);
1732 }
1733 
1734 /*******************************************************************//**
1735 Fill the dynamic table information_schema.innodb_cmpmem.
1736 @return 0 on success, 1 on failure */
1737 static
1738 int
i_s_cmpmem_fill(THD * thd,TABLE_LIST * tables,Item * cond)1739 i_s_cmpmem_fill(
1740 /*============*/
1741 	THD*		thd,	/*!< in: thread */
1742 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1743 	Item*		cond)	/*!< in: condition (ignored) */
1744 {
1745 	return(i_s_cmpmem_fill_low(thd, tables, cond, FALSE));
1746 }
1747 
1748 /*******************************************************************//**
1749 Fill the dynamic table information_schema.innodb_cmpmem_reset.
1750 @return 0 on success, 1 on failure */
1751 static
1752 int
i_s_cmpmem_reset_fill(THD * thd,TABLE_LIST * tables,Item * cond)1753 i_s_cmpmem_reset_fill(
1754 /*==================*/
1755 	THD*		thd,	/*!< in: thread */
1756 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1757 	Item*		cond)	/*!< in: condition (ignored) */
1758 {
1759 	return(i_s_cmpmem_fill_low(thd, tables, cond, TRUE));
1760 }
1761 
1762 /*******************************************************************//**
1763 Bind the dynamic table information_schema.innodb_cmpmem.
1764 @return 0 on success */
1765 static
1766 int
i_s_cmpmem_init(void * p)1767 i_s_cmpmem_init(
1768 /*============*/
1769 	void*	p)	/*!< in/out: table schema object */
1770 {
1771 	DBUG_ENTER("i_s_cmpmem_init");
1772 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1773 
1774 	schema->fields_info = i_s_cmpmem_fields_info;
1775 	schema->fill_table = i_s_cmpmem_fill;
1776 
1777 	DBUG_RETURN(0);
1778 }
1779 
1780 /*******************************************************************//**
1781 Bind the dynamic table information_schema.innodb_cmpmem_reset.
1782 @return 0 on success */
1783 static
1784 int
i_s_cmpmem_reset_init(void * p)1785 i_s_cmpmem_reset_init(
1786 /*==================*/
1787 	void*	p)	/*!< in/out: table schema object */
1788 {
1789 	DBUG_ENTER("i_s_cmpmem_reset_init");
1790 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1791 
1792 	schema->fields_info = i_s_cmpmem_fields_info;
1793 	schema->fill_table = i_s_cmpmem_reset_fill;
1794 
1795 	DBUG_RETURN(0);
1796 }
1797 
1798 UNIV_INTERN struct st_maria_plugin	i_s_innodb_cmpmem =
1799 {
1800 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1801 	/* int */
1802 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
1803 
1804 	/* pointer to type-specific plugin descriptor */
1805 	/* void* */
1806 	&i_s_info,
1807 
1808 	/* plugin name */
1809 	/* const char* */
1810 	"INNODB_CMPMEM",
1811 
1812 	/* plugin author (for SHOW PLUGINS) */
1813 	/* const char* */
1814 	plugin_author,
1815 
1816 	/* general descriptive text (for SHOW PLUGINS) */
1817 	/* const char* */
1818 	"Statistics for the InnoDB compressed buffer pool",
1819 
1820 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1821 	/* int */
1822 	PLUGIN_LICENSE_GPL,
1823 
1824 	/* the function to invoke when plugin is loaded */
1825 	/* int (*)(void*); */
1826 	i_s_cmpmem_init,
1827 
1828 	/* the function to invoke when plugin is unloaded */
1829 	/* int (*)(void*); */
1830 	i_s_common_deinit,
1831 
1832 	/* plugin version (for SHOW PLUGINS) */
1833 	/* unsigned int */
1834 	INNODB_VERSION_SHORT,
1835 
1836 	/* struct st_mysql_show_var* */
1837 	NULL,
1838 
1839 	/* struct st_mysql_sys_var** */
1840 	NULL,
1841 
1842         /* Maria extension */
1843 	INNODB_VERSION_STR,
1844         MariaDB_PLUGIN_MATURITY_STABLE,
1845 };
1846 
1847 UNIV_INTERN struct st_maria_plugin	i_s_innodb_cmpmem_reset =
1848 {
1849 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
1850 	/* int */
1851 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
1852 
1853 	/* pointer to type-specific plugin descriptor */
1854 	/* void* */
1855 	&i_s_info,
1856 
1857 	/* plugin name */
1858 	/* const char* */
1859 	"INNODB_CMPMEM_RESET",
1860 
1861 	/* plugin author (for SHOW PLUGINS) */
1862 	/* const char* */
1863 	plugin_author,
1864 
1865 	/* general descriptive text (for SHOW PLUGINS) */
1866 	/* const char* */
1867 	"Statistics for the InnoDB compressed buffer pool;"
1868 		   " reset cumulated counts",
1869 
1870 	/* the plugin license (PLUGIN_LICENSE_XXX) */
1871 	/* int */
1872 	PLUGIN_LICENSE_GPL,
1873 
1874 	/* the function to invoke when plugin is loaded */
1875 	/* int (*)(void*); */
1876 	i_s_cmpmem_reset_init,
1877 
1878 	/* the function to invoke when plugin is unloaded */
1879 	/* int (*)(void*); */
1880 	i_s_common_deinit,
1881 
1882 	/* plugin version (for SHOW PLUGINS) */
1883 	/* unsigned int */
1884 	INNODB_VERSION_SHORT,
1885 
1886 	/* struct st_mysql_show_var* */
1887 	NULL,
1888 
1889 	/* struct st_mysql_sys_var** */
1890 	NULL,
1891 
1892         /* Maria extension */
1893 	INNODB_VERSION_STR,
1894         MariaDB_PLUGIN_MATURITY_STABLE,
1895 };
1896 
1897 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_metrics */
1898 static ST_FIELD_INFO innodb_metrics_fields_info[]=
1899 {
1900 #define	METRIC_NAME		0
1901   {"NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
1902 #define	METRIC_SUBSYS		1
1903   {"SUBSYSTEM", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
1904 #define	METRIC_VALUE_START	2
1905   {"COUNT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1906    0, 0, "", SKIP_OPEN_TABLE},
1907 #define	METRIC_MAX_VALUE_START	3
1908   {"MAX_COUNT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1909    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1910 #define	METRIC_MIN_VALUE_START	4
1911   {"MIN_COUNT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1912    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1913 #define	METRIC_AVG_VALUE_START	5
1914   {"AVG_COUNT", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
1915    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1916 #define	METRIC_VALUE_RESET	6
1917   {"COUNT_RESET", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1918    0, 0, "", SKIP_OPEN_TABLE},
1919 #define	METRIC_MAX_VALUE_RESET	7
1920   {"MAX_COUNT_RESET", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1921    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1922 #define	METRIC_MIN_VALUE_RESET	8
1923   {"MIN_COUNT_RESET", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1924    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1925 #define	METRIC_AVG_VALUE_RESET	9
1926   {"AVG_COUNT_RESET", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
1927    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1928 #define	METRIC_START_TIME	10
1929   {"TIME_ENABLED", 0, MYSQL_TYPE_DATETIME,
1930    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1931 #define	METRIC_STOP_TIME	11
1932   {"TIME_DISABLED", 0, MYSQL_TYPE_DATETIME,
1933    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1934 #define	METRIC_TIME_ELAPSED	12
1935   {"TIME_ELAPSED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
1936    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1937 #define	METRIC_RESET_TIME	13
1938   {"TIME_RESET", 0, MYSQL_TYPE_DATETIME,
1939    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
1940 #define	METRIC_STATUS		14
1941   {"STATUS", NAME_LEN + 1, MYSQL_TYPE_STRING,
1942    0, 0, "", SKIP_OPEN_TABLE},
1943 #define	METRIC_TYPE		15
1944   {"TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING,
1945    0, 0, "", SKIP_OPEN_TABLE},
1946 #define	METRIC_DESC		16
1947   {"COMMENT", NAME_LEN + 1, MYSQL_TYPE_STRING,
1948    0, 0, "", SKIP_OPEN_TABLE},
1949 
1950   END_OF_ST_FIELD_INFO
1951 };
1952 
1953 /**********************************************************************//**
1954 Fill the information schema metrics table.
1955 @return 0 on success */
1956 static
1957 int
i_s_metrics_fill(THD * thd,TABLE * table_to_fill)1958 i_s_metrics_fill(
1959 /*=============*/
1960 	THD*		thd,		/*!< in: thread */
1961 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
1962 {
1963 	int		count;
1964 	Field**		fields;
1965 	double		time_diff = 0;
1966 	monitor_info_t*	monitor_info;
1967 	mon_type_t	min_val;
1968 	mon_type_t	max_val;
1969 
1970 	DBUG_ENTER("i_s_metrics_fill");
1971 	fields = table_to_fill->field;
1972 
1973 	for (count = 0; count < NUM_MONITOR; count++) {
1974 		monitor_info = srv_mon_get_info((monitor_id_t) count);
1975 
1976 		/* A good place to sanity check the Monitor ID */
1977 		ut_a(count == monitor_info->monitor_id);
1978 
1979 		/* If the item refers to a Module, nothing to fill,
1980 		continue. */
1981 		if ((monitor_info->monitor_type & MONITOR_MODULE)
1982 		    || (monitor_info->monitor_type & MONITOR_HIDDEN)) {
1983 			continue;
1984 		}
1985 
1986 		/* If this is an existing "status variable", and
1987 		its corresponding counter is still on, we need
1988 		to calculate the result from its corresponding
1989 		counter. */
1990 		if (monitor_info->monitor_type & MONITOR_EXISTING
1991 		    && MONITOR_IS_ON(count)) {
1992 			srv_mon_process_existing_counter((monitor_id_t) count,
1993 							 MONITOR_GET_VALUE);
1994 		}
1995 
1996 		/* Fill in counter's basic information */
1997 		OK(field_store_string(fields[METRIC_NAME],
1998 				      monitor_info->monitor_name));
1999 
2000 		OK(field_store_string(fields[METRIC_SUBSYS],
2001 				      monitor_info->monitor_module));
2002 
2003 		OK(field_store_string(fields[METRIC_DESC],
2004 				      monitor_info->monitor_desc));
2005 
2006 		/* Fill in counter values */
2007 		OK(fields[METRIC_VALUE_RESET]->store(
2008 			MONITOR_VALUE(count), FALSE));
2009 
2010 		OK(fields[METRIC_VALUE_START]->store(
2011 			MONITOR_VALUE_SINCE_START(count), FALSE));
2012 
2013 		/* If the max value is MAX_RESERVED, counter max
2014 		value has not been updated. Set the column value
2015 		to NULL. */
2016 		if (MONITOR_MAX_VALUE(count) == MAX_RESERVED
2017 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2018 			fields[METRIC_MAX_VALUE_RESET]->set_null();
2019 		} else {
2020 			OK(fields[METRIC_MAX_VALUE_RESET]->store(
2021 				MONITOR_MAX_VALUE(count), FALSE));
2022 			fields[METRIC_MAX_VALUE_RESET]->set_notnull();
2023 		}
2024 
2025 		/* If the min value is MAX_RESERVED, counter min
2026 		value has not been updated. Set the column value
2027 		to NULL. */
2028 		if (MONITOR_MIN_VALUE(count) == MIN_RESERVED
2029 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2030 			fields[METRIC_MIN_VALUE_RESET]->set_null();
2031 		} else {
2032 			OK(fields[METRIC_MIN_VALUE_RESET]->store(
2033 				MONITOR_MIN_VALUE(count), FALSE));
2034 			fields[METRIC_MIN_VALUE_RESET]->set_notnull();
2035 		}
2036 
2037 		/* Calculate the max value since counter started */
2038 		max_val = srv_mon_calc_max_since_start((monitor_id_t) count);
2039 
2040 		if (max_val == MAX_RESERVED
2041 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2042 			fields[METRIC_MAX_VALUE_START]->set_null();
2043 		} else {
2044 			OK(fields[METRIC_MAX_VALUE_START]->store(
2045 				max_val, FALSE));
2046 			fields[METRIC_MAX_VALUE_START]->set_notnull();
2047 		}
2048 
2049 		/* Calculate the min value since counter started */
2050 		min_val = srv_mon_calc_min_since_start((monitor_id_t) count);
2051 
2052 		if (min_val == MIN_RESERVED
2053 		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
2054 			fields[METRIC_MIN_VALUE_START]->set_null();
2055 		} else {
2056 			OK(fields[METRIC_MIN_VALUE_START]->store(
2057 				min_val, FALSE));
2058 
2059 			fields[METRIC_MIN_VALUE_START]->set_notnull();
2060 		}
2061 
2062 		/* If monitor has been enabled (no matter it is disabled
2063 		or not now), fill METRIC_START_TIME and METRIC_TIME_ELAPSED
2064 		field */
2065 		if (MONITOR_FIELD(count, mon_start_time)) {
2066 			OK(field_store_time_t(fields[METRIC_START_TIME],
2067 				(time_t)MONITOR_FIELD(count, mon_start_time)));
2068 			fields[METRIC_START_TIME]->set_notnull();
2069 
2070 			/* If monitor is enabled, the TIME_ELAPSED is the
2071 			time difference between current and time when monitor
2072 			is enabled. Otherwise, it is the time difference
2073 			between time when monitor is enabled and time
2074 			when it is disabled */
2075 			if (MONITOR_IS_ON(count)) {
2076 				time_diff = difftime(time(NULL),
2077 					MONITOR_FIELD(count, mon_start_time));
2078 			} else {
2079 				time_diff =  difftime(
2080 					MONITOR_FIELD(count, mon_stop_time),
2081 					MONITOR_FIELD(count, mon_start_time));
2082 			}
2083 
2084 			OK(fields[METRIC_TIME_ELAPSED]->store(
2085 				time_diff));
2086 			fields[METRIC_TIME_ELAPSED]->set_notnull();
2087 		} else {
2088 			fields[METRIC_START_TIME]->set_null();
2089 			fields[METRIC_TIME_ELAPSED]->set_null();
2090 			time_diff = 0;
2091 		}
2092 
2093 		/* Unless MONITOR_NO_AVERAGE is set, we must
2094 		to calculate the average value. If this is a monitor set
2095 		owner marked by MONITOR_SET_OWNER, divide
2096 		the value by another counter (number of calls) designated
2097 		by monitor_info->monitor_related_id.
2098 		Otherwise average the counter value by the time between the
2099 		time that the counter is enabled and time it is disabled
2100 		or time it is sampled. */
2101 		if ((monitor_info->monitor_type
2102 		     & (MONITOR_NO_AVERAGE | MONITOR_SET_OWNER))
2103 		    == MONITOR_SET_OWNER
2104 		    && monitor_info->monitor_related_id) {
2105 			mon_type_t	value_start
2106 				 = MONITOR_VALUE_SINCE_START(
2107 					monitor_info->monitor_related_id);
2108 
2109 			if (value_start) {
2110 				OK(fields[METRIC_AVG_VALUE_START]->store(
2111 					MONITOR_VALUE_SINCE_START(count)
2112 					/ value_start, FALSE));
2113 
2114 				fields[METRIC_AVG_VALUE_START]->set_notnull();
2115 			} else {
2116 				fields[METRIC_AVG_VALUE_START]->set_null();
2117 			}
2118 
2119 			if (mon_type_t related_value =
2120 			    MONITOR_VALUE(monitor_info->monitor_related_id)) {
2121 				OK(fields[METRIC_AVG_VALUE_RESET]
2122 				   ->store(MONITOR_VALUE(count)
2123 					   / related_value, false));
2124 				fields[METRIC_AVG_VALUE_RESET]->set_notnull();
2125 			} else {
2126 				fields[METRIC_AVG_VALUE_RESET]->set_null();
2127 			}
2128 		} else if (!(monitor_info->monitor_type
2129 			     & (MONITOR_NO_AVERAGE
2130 				| MONITOR_DISPLAY_CURRENT))) {
2131 			if (time_diff != 0) {
2132 				OK(fields[METRIC_AVG_VALUE_START]->store(
2133 					(double) MONITOR_VALUE_SINCE_START(
2134 						count) / time_diff));
2135 				fields[METRIC_AVG_VALUE_START]->set_notnull();
2136 			} else {
2137 				fields[METRIC_AVG_VALUE_START]->set_null();
2138 			}
2139 
2140 			if (MONITOR_FIELD(count, mon_reset_time)) {
2141 				/* calculate the time difference since last
2142 				reset */
2143 				if (MONITOR_IS_ON(count)) {
2144 					time_diff = difftime(
2145 						time(NULL), MONITOR_FIELD(
2146 							count, mon_reset_time));
2147 				} else {
2148 					time_diff =  difftime(
2149 					MONITOR_FIELD(count, mon_stop_time),
2150 					MONITOR_FIELD(count, mon_reset_time));
2151 				}
2152 			} else {
2153 				time_diff = 0;
2154 			}
2155 
2156 			if (time_diff != 0) {
2157 				OK(fields[METRIC_AVG_VALUE_RESET]->store(
2158 					static_cast<double>(
2159 						MONITOR_VALUE(count) / time_diff)));
2160 				fields[METRIC_AVG_VALUE_RESET]->set_notnull();
2161 			} else {
2162 				fields[METRIC_AVG_VALUE_RESET]->set_null();
2163 			}
2164 		} else {
2165 			fields[METRIC_AVG_VALUE_START]->set_null();
2166 			fields[METRIC_AVG_VALUE_RESET]->set_null();
2167 		}
2168 
2169 
2170 		if (MONITOR_IS_ON(count)) {
2171 			/* If monitor is on, the stop time will set to NULL */
2172 			fields[METRIC_STOP_TIME]->set_null();
2173 
2174 			/* Display latest Monitor Reset Time only if Monitor
2175 			counter is on. */
2176 			if (MONITOR_FIELD(count, mon_reset_time)) {
2177 				OK(field_store_time_t(
2178 					fields[METRIC_RESET_TIME],
2179 					(time_t)MONITOR_FIELD(
2180 						count, mon_reset_time)));
2181 				fields[METRIC_RESET_TIME]->set_notnull();
2182 			} else {
2183 				fields[METRIC_RESET_TIME]->set_null();
2184 			}
2185 
2186 			/* Display the monitor status as "enabled" */
2187 			OK(field_store_string(fields[METRIC_STATUS],
2188 					      "enabled"));
2189 		} else {
2190 			if (MONITOR_FIELD(count, mon_stop_time)) {
2191 				OK(field_store_time_t(fields[METRIC_STOP_TIME],
2192 				(time_t)MONITOR_FIELD(count, mon_stop_time)));
2193 				fields[METRIC_STOP_TIME]->set_notnull();
2194 			} else {
2195 				fields[METRIC_STOP_TIME]->set_null();
2196 			}
2197 
2198 			fields[METRIC_RESET_TIME]->set_null();
2199 
2200 			OK(field_store_string(fields[METRIC_STATUS],
2201 					      "disabled"));
2202 		}
2203 
2204 		if (monitor_info->monitor_type & MONITOR_DISPLAY_CURRENT) {
2205 			OK(field_store_string(fields[METRIC_TYPE],
2206 					      "value"));
2207 		} else if (monitor_info->monitor_type & MONITOR_EXISTING) {
2208 			OK(field_store_string(fields[METRIC_TYPE],
2209 					      "status_counter"));
2210 		} else if (monitor_info->monitor_type & MONITOR_SET_OWNER) {
2211 			OK(field_store_string(fields[METRIC_TYPE],
2212 					      "set_owner"));
2213 		} else if ( monitor_info->monitor_type & MONITOR_SET_MEMBER) {
2214 			OK(field_store_string(fields[METRIC_TYPE],
2215 					      "set_member"));
2216 		} else {
2217 			OK(field_store_string(fields[METRIC_TYPE],
2218 					      "counter"));
2219 		}
2220 
2221 		OK(schema_table_store_record(thd, table_to_fill));
2222 	}
2223 
2224 	DBUG_RETURN(0);
2225 }
2226 
2227 /*******************************************************************//**
2228 Function to fill information schema metrics tables.
2229 @return 0 on success */
2230 static
2231 int
i_s_metrics_fill_table(THD * thd,TABLE_LIST * tables,Item *)2232 i_s_metrics_fill_table(
2233 /*===================*/
2234 	THD*		thd,	/*!< in: thread */
2235 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2236 	Item*		)	/*!< in: condition (not used) */
2237 {
2238 	DBUG_ENTER("i_s_metrics_fill_table");
2239 
2240 	/* deny access to non-superusers */
2241 	if (check_global_access(thd, PROCESS_ACL)) {
2242 		DBUG_RETURN(0);
2243 	}
2244 
2245 	i_s_metrics_fill(thd, tables->table);
2246 
2247 	DBUG_RETURN(0);
2248 }
2249 /*******************************************************************//**
2250 Bind the dynamic table INFORMATION_SCHEMA.innodb_metrics
2251 @return 0 on success */
2252 static
2253 int
innodb_metrics_init(void * p)2254 innodb_metrics_init(
2255 /*================*/
2256 	void*	p)	/*!< in/out: table schema object */
2257 {
2258 	ST_SCHEMA_TABLE*	schema;
2259 
2260 	DBUG_ENTER("innodb_metrics_init");
2261 
2262 	schema = (ST_SCHEMA_TABLE*) p;
2263 
2264 	schema->fields_info = innodb_metrics_fields_info;
2265 	schema->fill_table = i_s_metrics_fill_table;
2266 
2267 	DBUG_RETURN(0);
2268 }
2269 
2270 UNIV_INTERN struct st_maria_plugin	i_s_innodb_metrics =
2271 {
2272 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2273 	/* int */
2274 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
2275 
2276 	/* pointer to type-specific plugin descriptor */
2277 	/* void* */
2278 	&i_s_info,
2279 
2280 	/* plugin name */
2281 	/* const char* */
2282 	"INNODB_METRICS",
2283 
2284 	/* plugin author (for SHOW PLUGINS) */
2285 	/* const char* */
2286 	plugin_author,
2287 
2288 	/* general descriptive text (for SHOW PLUGINS) */
2289 	/* const char* */
2290 	"InnoDB Metrics Info",
2291 
2292 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2293 	/* int */
2294 	PLUGIN_LICENSE_GPL,
2295 
2296 	/* the function to invoke when plugin is loaded */
2297 	/* int (*)(void*); */
2298 	innodb_metrics_init,
2299 
2300 	/* the function to invoke when plugin is unloaded */
2301 	/* int (*)(void*); */
2302 	i_s_common_deinit,
2303 
2304 	/* plugin version (for SHOW PLUGINS) */
2305 	/* unsigned int */
2306 	INNODB_VERSION_SHORT,
2307 
2308 	/* struct st_mysql_show_var* */
2309 	NULL,
2310 
2311 	/* struct st_mysql_sys_var** */
2312 	NULL,
2313 
2314         /* Maria extension */
2315 	INNODB_VERSION_STR,
2316         MariaDB_PLUGIN_MATURITY_STABLE,
2317 };
2318 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_ft_default_stopword */
2319 static ST_FIELD_INFO i_s_stopword_fields_info[]=
2320 {
2321 #define STOPWORD_VALUE	0
2322   {"value", TRX_ID_MAX_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
2323   END_OF_ST_FIELD_INFO
2324 };
2325 
2326 /*******************************************************************//**
2327 Fill the dynamic table information_schema.innodb_ft_default_stopword.
2328 @return 0 on success, 1 on failure */
2329 static
2330 int
i_s_stopword_fill(THD * thd,TABLE_LIST * tables,Item *)2331 i_s_stopword_fill(
2332 /*==============*/
2333 	THD*		thd,	/*!< in: thread */
2334 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2335 	Item*		)	/*!< in: condition (not used) */
2336 {
2337 	Field**	fields;
2338 	ulint	i = 0;
2339 	TABLE*	table = (TABLE*) tables->table;
2340 
2341 	DBUG_ENTER("i_s_stopword_fill");
2342 
2343 	fields = table->field;
2344 
2345 	/* Fill with server default stopword list in array
2346 	fts_default_stopword */
2347 	while (fts_default_stopword[i]) {
2348 		OK(field_store_string(fields[STOPWORD_VALUE],
2349 				      fts_default_stopword[i]));
2350 
2351 		OK(schema_table_store_record(thd, table));
2352 		i++;
2353 	}
2354 
2355 	DBUG_RETURN(0);
2356 }
2357 
2358 /*******************************************************************//**
2359 Bind the dynamic table information_schema.innodb_ft_default_stopword.
2360 @return 0 on success */
2361 static
2362 int
i_s_stopword_init(void * p)2363 i_s_stopword_init(
2364 /*==============*/
2365 	void*	p)	/*!< in/out: table schema object */
2366 {
2367 	DBUG_ENTER("i_s_stopword_init");
2368 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2369 
2370 	schema->fields_info = i_s_stopword_fields_info;
2371 	schema->fill_table = i_s_stopword_fill;
2372 
2373 	DBUG_RETURN(0);
2374 }
2375 
2376 UNIV_INTERN struct st_maria_plugin	i_s_innodb_ft_default_stopword =
2377 {
2378 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2379 	/* int */
2380 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
2381 
2382 	/* pointer to type-specific plugin descriptor */
2383 	/* void* */
2384 	&i_s_info,
2385 
2386 	/* plugin name */
2387 	/* const char* */
2388 	"INNODB_FT_DEFAULT_STOPWORD",
2389 
2390 	/* plugin author (for SHOW PLUGINS) */
2391 	/* const char* */
2392 	plugin_author,
2393 
2394 	/* general descriptive text (for SHOW PLUGINS) */
2395 	/* const char* */
2396 	"Default stopword list for InnoDB Full Text Search",
2397 
2398 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2399 	/* int */
2400 	PLUGIN_LICENSE_GPL,
2401 
2402 	/* the function to invoke when plugin is loaded */
2403 	/* int (*)(void*); */
2404 	i_s_stopword_init,
2405 
2406 	/* the function to invoke when plugin is unloaded */
2407 	/* int (*)(void*); */
2408 	i_s_common_deinit,
2409 
2410 	/* plugin version (for SHOW PLUGINS) */
2411 	/* unsigned int */
2412 	INNODB_VERSION_SHORT,
2413 
2414 	/* struct st_mysql_show_var* */
2415 	NULL,
2416 
2417 	/* struct st_mysql_sys_var** */
2418 	NULL,
2419 
2420         /* Maria extension */
2421 	INNODB_VERSION_STR,
2422         MariaDB_PLUGIN_MATURITY_STABLE,
2423 };
2424 
2425 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2426 INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED */
2427 static ST_FIELD_INFO i_s_fts_doc_fields_info[]=
2428 {
2429 #define	I_S_FTS_DOC_ID			0
2430   {"DOC_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
2431    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
2432   END_OF_ST_FIELD_INFO
2433 };
2434 
2435 /*******************************************************************//**
2436 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED or
2437 INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2438 @return 0 on success, 1 on failure */
2439 static
2440 int
i_s_fts_deleted_generic_fill(THD * thd,TABLE_LIST * tables,ibool being_deleted)2441 i_s_fts_deleted_generic_fill(
2442 /*=========================*/
2443 	THD*		thd,		/*!< in: thread */
2444 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
2445 	ibool		being_deleted)	/*!< in: BEING_DELTED table */
2446 {
2447 	Field**			fields;
2448 	TABLE*			table = (TABLE*) tables->table;
2449 	trx_t*			trx;
2450 	fts_table_t		fts_table;
2451 	fts_doc_ids_t*		deleted;
2452 	dict_table_t*		user_table;
2453 
2454 	DBUG_ENTER("i_s_fts_deleted_generic_fill");
2455 
2456 	/* deny access to non-superusers */
2457 	if (check_global_access(thd, PROCESS_ACL)) {
2458 		DBUG_RETURN(0);
2459 	}
2460 
2461 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
2462 
2463 	/* Prevent DROP of the internal tables for fulltext indexes.
2464 	FIXME: acquire DDL-blocking MDL on the user table name! */
2465 	rw_lock_s_lock(&dict_operation_lock);
2466 
2467 	user_table = dict_table_open_on_id(
2468 		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
2469 
2470 	if (!user_table) {
2471 		rw_lock_s_unlock(&dict_operation_lock);
2472 		DBUG_RETURN(0);
2473 	} else if (!dict_table_has_fts_index(user_table)
2474 		   || !user_table->is_readable()) {
2475 		dict_table_close(user_table, FALSE, FALSE);
2476 		rw_lock_s_unlock(&dict_operation_lock);
2477 		DBUG_RETURN(0);
2478 	}
2479 
2480 	deleted = fts_doc_ids_create();
2481 
2482 	trx = trx_create();
2483 	trx->op_info = "Select for FTS DELETE TABLE";
2484 
2485 	FTS_INIT_FTS_TABLE(&fts_table,
2486 			   (being_deleted) ? "BEING_DELETED" : "DELETED",
2487 			   FTS_COMMON_TABLE, user_table);
2488 
2489 	fts_table_fetch_doc_ids(trx, &fts_table, deleted);
2490 
2491 	dict_table_close(user_table, FALSE, FALSE);
2492 
2493 	rw_lock_s_unlock(&dict_operation_lock);
2494 
2495 	trx->free();
2496 
2497 	fields = table->field;
2498 
2499 	int	ret = 0;
2500 
2501 	for (ulint j = 0; j < ib_vector_size(deleted->doc_ids); ++j) {
2502 		doc_id_t	doc_id;
2503 
2504 		doc_id = *(doc_id_t*) ib_vector_get_const(deleted->doc_ids, j);
2505 
2506 		BREAK_IF(ret = fields[I_S_FTS_DOC_ID]->store(doc_id, true));
2507 
2508 		BREAK_IF(ret = schema_table_store_record(thd, table));
2509 	}
2510 
2511 	fts_doc_ids_free(deleted);
2512 
2513 	DBUG_RETURN(ret);
2514 }
2515 
2516 /*******************************************************************//**
2517 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2518 @return 0 on success, 1 on failure */
2519 static
2520 int
i_s_fts_deleted_fill(THD * thd,TABLE_LIST * tables,Item *)2521 i_s_fts_deleted_fill(
2522 /*=================*/
2523 	THD*		thd,	/*!< in: thread */
2524 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2525 	Item*		)	/*!< in: condition (ignored) */
2526 {
2527 	DBUG_ENTER("i_s_fts_deleted_fill");
2528 
2529 	DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, FALSE));
2530 }
2531 
2532 /*******************************************************************//**
2533 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2534 @return 0 on success */
2535 static
2536 int
i_s_fts_deleted_init(void * p)2537 i_s_fts_deleted_init(
2538 /*=================*/
2539 	void*	p)	/*!< in/out: table schema object */
2540 {
2541 	DBUG_ENTER("i_s_fts_deleted_init");
2542 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2543 
2544 	schema->fields_info = i_s_fts_doc_fields_info;
2545 	schema->fill_table = i_s_fts_deleted_fill;
2546 
2547 	DBUG_RETURN(0);
2548 }
2549 
2550 UNIV_INTERN struct st_maria_plugin	i_s_innodb_ft_deleted =
2551 {
2552 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2553 	/* int */
2554 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
2555 
2556 	/* pointer to type-specific plugin descriptor */
2557 	/* void* */
2558 	&i_s_info,
2559 
2560 	/* plugin name */
2561 	/* const char* */
2562 	"INNODB_FT_DELETED",
2563 
2564 	/* plugin author (for SHOW PLUGINS) */
2565 	/* const char* */
2566 	plugin_author,
2567 
2568 	/* general descriptive text (for SHOW PLUGINS) */
2569 	/* const char* */
2570 	"INNODB AUXILIARY FTS DELETED TABLE",
2571 
2572 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2573 	/* int */
2574 	PLUGIN_LICENSE_GPL,
2575 
2576 	/* the function to invoke when plugin is loaded */
2577 	/* int (*)(void*); */
2578 	i_s_fts_deleted_init,
2579 
2580 	/* the function to invoke when plugin is unloaded */
2581 	/* int (*)(void*); */
2582 	i_s_common_deinit,
2583 
2584 	/* plugin version (for SHOW PLUGINS) */
2585 	/* unsigned int */
2586 	INNODB_VERSION_SHORT,
2587 
2588 	/* struct st_mysql_show_var* */
2589 	NULL,
2590 
2591 	/* struct st_mysql_sys_var** */
2592 	NULL,
2593 
2594         /* Maria extension */
2595 	INNODB_VERSION_STR,
2596         MariaDB_PLUGIN_MATURITY_STABLE,
2597 };
2598 
2599 /*******************************************************************//**
2600 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2601 @return 0 on success, 1 on failure */
2602 static
2603 int
i_s_fts_being_deleted_fill(THD * thd,TABLE_LIST * tables,Item *)2604 i_s_fts_being_deleted_fill(
2605 /*=======================*/
2606 	THD*		thd,	/*!< in: thread */
2607 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2608 	Item*		)	/*!< in: condition (ignored) */
2609 {
2610 	DBUG_ENTER("i_s_fts_being_deleted_fill");
2611 
2612 	DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, TRUE));
2613 }
2614 
2615 /*******************************************************************//**
2616 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2617 @return 0 on success */
2618 static
2619 int
i_s_fts_being_deleted_init(void * p)2620 i_s_fts_being_deleted_init(
2621 /*=======================*/
2622 	void*	p)	/*!< in/out: table schema object */
2623 {
2624 	DBUG_ENTER("i_s_fts_deleted_init");
2625 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2626 
2627 	schema->fields_info = i_s_fts_doc_fields_info;
2628 	schema->fill_table = i_s_fts_being_deleted_fill;
2629 
2630 	DBUG_RETURN(0);
2631 }
2632 
2633 UNIV_INTERN struct st_maria_plugin	i_s_innodb_ft_being_deleted =
2634 {
2635 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2636 	/* int */
2637 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
2638 
2639 	/* pointer to type-specific plugin descriptor */
2640 	/* void* */
2641 	&i_s_info,
2642 
2643 	/* plugin name */
2644 	/* const char* */
2645 	"INNODB_FT_BEING_DELETED",
2646 
2647 	/* plugin author (for SHOW PLUGINS) */
2648 	/* const char* */
2649 	plugin_author,
2650 
2651 	/* general descriptive text (for SHOW PLUGINS) */
2652 	/* const char* */
2653 	"INNODB AUXILIARY FTS BEING DELETED TABLE",
2654 
2655 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2656 	/* int */
2657 	PLUGIN_LICENSE_GPL,
2658 
2659 	/* the function to invoke when plugin is loaded */
2660 	/* int (*)(void*); */
2661 	i_s_fts_being_deleted_init,
2662 
2663 	/* the function to invoke when plugin is unloaded */
2664 	/* int (*)(void*); */
2665 	i_s_common_deinit,
2666 
2667 	/* plugin version (for SHOW PLUGINS) */
2668 	/* unsigned int */
2669 	INNODB_VERSION_SHORT,
2670 
2671 	/* struct st_mysql_show_var* */
2672 	NULL,
2673 
2674 	/* struct st_mysql_sys_var** */
2675 	NULL,
2676 
2677         /* Maria extension */
2678 	INNODB_VERSION_STR,
2679         MariaDB_PLUGIN_MATURITY_STABLE,
2680 };
2681 
2682 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED and
2683 INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE */
2684 static ST_FIELD_INFO i_s_fts_index_fields_info[]=
2685 {
2686 #define	I_S_FTS_WORD			0
2687   {"WORD", FTS_MAX_WORD_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
2688 #define	I_S_FTS_FIRST_DOC_ID		1
2689   {"FIRST_DOC_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
2690    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
2691 #define	I_S_FTS_LAST_DOC_ID		2
2692   {"LAST_DOC_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
2693    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
2694 #define	I_S_FTS_DOC_COUNT		3
2695   {"DOC_COUNT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
2696    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
2697 #define	I_S_FTS_ILIST_DOC_ID		4
2698   {"DOC_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
2699    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
2700 #define	I_S_FTS_ILIST_DOC_POS		5
2701   {"POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
2702    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
2703 
2704   END_OF_ST_FIELD_INFO
2705 };
2706 
2707 /*******************************************************************//**
2708 Go through the Doc Node and its ilist, fill the dynamic table
2709 INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED for one FTS index on the table.
2710 @return 0 on success, 1 on failure */
2711 static
2712 int
i_s_fts_index_cache_fill_one_index(fts_index_cache_t * index_cache,THD * thd,fts_string_t * conv_str,TABLE_LIST * tables)2713 i_s_fts_index_cache_fill_one_index(
2714 /*===============================*/
2715 	fts_index_cache_t*	index_cache,	/*!< in: FTS index cache */
2716 	THD*			thd,		/*!< in: thread */
2717 	fts_string_t*		conv_str,	/*!< in/out: buffer */
2718 	TABLE_LIST*		tables)		/*!< in/out: tables to fill */
2719 {
2720 	TABLE*			table = (TABLE*) tables->table;
2721 	Field**			fields;
2722 	CHARSET_INFO*		index_charset;
2723 	const ib_rbt_node_t*	rbt_node;
2724 	uint			dummy_errors;
2725 	char*			word_str;
2726 
2727 	DBUG_ENTER("i_s_fts_index_cache_fill_one_index");
2728 
2729 	fields = table->field;
2730 
2731 	index_charset = index_cache->charset;
2732 	conv_str->f_n_char = 0;
2733 
2734 	int	ret = 0;
2735 
2736 	/* Go through each word in the index cache */
2737 	for (rbt_node = rbt_first(index_cache->words);
2738 	     rbt_node;
2739 	     rbt_node = rbt_next(index_cache->words, rbt_node)) {
2740 		fts_tokenizer_word_t* word;
2741 
2742 		word = rbt_value(fts_tokenizer_word_t, rbt_node);
2743 
2744 		/* Convert word from index charset to system_charset_info */
2745 		if (index_charset->cset != system_charset_info->cset) {
2746 			conv_str->f_n_char = my_convert(
2747 				reinterpret_cast<char*>(conv_str->f_str),
2748 				static_cast<uint32>(conv_str->f_len),
2749 				system_charset_info,
2750 				reinterpret_cast<char*>(word->text.f_str),
2751 				static_cast<uint32>(word->text.f_len),
2752 				index_charset, &dummy_errors);
2753 			ut_ad(conv_str->f_n_char <= conv_str->f_len);
2754 			conv_str->f_str[conv_str->f_n_char] = 0;
2755 			word_str = reinterpret_cast<char*>(conv_str->f_str);
2756 		} else {
2757 			word_str = reinterpret_cast<char*>(word->text.f_str);
2758 		}
2759 
2760 		/* Decrypt the ilist, and display Dod ID and word position */
2761 		for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
2762 			fts_node_t*	node;
2763 			const byte*	ptr;
2764 			ulint		decoded = 0;
2765 			doc_id_t	doc_id = 0;
2766 
2767 			node = static_cast<fts_node_t*> (ib_vector_get(
2768 				word->nodes, i));
2769 
2770 			ptr = node->ilist;
2771 
2772 			while (decoded < node->ilist_size) {
2773 
2774 				doc_id += fts_decode_vlc(&ptr);
2775 
2776 				/* Get position info */
2777 				while (*ptr) {
2778 
2779 					OK(field_store_string(
2780 						   fields[I_S_FTS_WORD],
2781 						   word_str));
2782 
2783 					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
2784 						   node->first_doc_id,
2785 						   true));
2786 
2787 					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
2788 						   node->last_doc_id,
2789 						   true));
2790 
2791 					OK(fields[I_S_FTS_DOC_COUNT]->store(
2792 						   node->doc_count, true));
2793 
2794 					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
2795 						   doc_id, true));
2796 
2797 					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
2798 						   fts_decode_vlc(&ptr), true));
2799 
2800 					OK(schema_table_store_record(
2801 						   thd, table));
2802 				}
2803 
2804 				++ptr;
2805 
2806 				decoded = ptr - (byte*) node->ilist;
2807 			}
2808 		}
2809 	}
2810 
2811 	DBUG_RETURN(ret);
2812 }
2813 /*******************************************************************//**
2814 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED
2815 @return 0 on success, 1 on failure */
2816 static
2817 int
i_s_fts_index_cache_fill(THD * thd,TABLE_LIST * tables,Item *)2818 i_s_fts_index_cache_fill(
2819 /*=====================*/
2820 	THD*		thd,	/*!< in: thread */
2821 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
2822 	Item*		)	/*!< in: condition (ignored) */
2823 {
2824 	dict_table_t*		user_table;
2825 	fts_cache_t*		cache;
2826 
2827 	DBUG_ENTER("i_s_fts_index_cache_fill");
2828 
2829 	/* deny access to non-superusers */
2830 	if (check_global_access(thd, PROCESS_ACL)) {
2831 		DBUG_RETURN(0);
2832 	}
2833 
2834 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
2835 
2836 	/* Prevent DROP of the internal tables for fulltext indexes.
2837 	FIXME: acquire DDL-blocking MDL on the user table name! */
2838 	rw_lock_s_lock(&dict_operation_lock);
2839 
2840 	user_table = dict_table_open_on_id(
2841 		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
2842 
2843 	if (!user_table) {
2844 no_fts:
2845 		rw_lock_s_unlock(&dict_operation_lock);
2846 		DBUG_RETURN(0);
2847 	}
2848 
2849 	if (!user_table->fts || !user_table->fts->cache) {
2850 		dict_table_close(user_table, FALSE, FALSE);
2851 		goto no_fts;
2852 	}
2853 
2854 	cache = user_table->fts->cache;
2855 
2856 	int			ret = 0;
2857 	fts_string_t		conv_str;
2858 	byte			word[HA_FT_MAXBYTELEN + 1];
2859 	conv_str.f_len = sizeof word;
2860 	conv_str.f_str = word;
2861 
2862 	rw_lock_s_lock(&cache->lock);
2863 
2864 	for (ulint i = 0; i < ib_vector_size(cache->indexes); i++) {
2865 		fts_index_cache_t*      index_cache;
2866 
2867 		index_cache = static_cast<fts_index_cache_t*> (
2868 			ib_vector_get(cache->indexes, i));
2869 
2870 		BREAK_IF(ret = i_s_fts_index_cache_fill_one_index(
2871 				 index_cache, thd, &conv_str, tables));
2872 	}
2873 
2874 	rw_lock_s_unlock(&cache->lock);
2875 	dict_table_close(user_table, FALSE, FALSE);
2876 	rw_lock_s_unlock(&dict_operation_lock);
2877 
2878 	DBUG_RETURN(ret);
2879 }
2880 
2881 /*******************************************************************//**
2882 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE
2883 @return 0 on success */
2884 static
2885 int
i_s_fts_index_cache_init(void * p)2886 i_s_fts_index_cache_init(
2887 /*=====================*/
2888 	void*	p)	/*!< in/out: table schema object */
2889 {
2890 	DBUG_ENTER("i_s_fts_index_cache_init");
2891 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
2892 
2893 	schema->fields_info = i_s_fts_index_fields_info;
2894 	schema->fill_table = i_s_fts_index_cache_fill;
2895 
2896 	DBUG_RETURN(0);
2897 }
2898 
2899 UNIV_INTERN struct st_maria_plugin	i_s_innodb_ft_index_cache =
2900 {
2901 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
2902 	/* int */
2903 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
2904 
2905 	/* pointer to type-specific plugin descriptor */
2906 	/* void* */
2907 	&i_s_info,
2908 
2909 	/* plugin name */
2910 	/* const char* */
2911 	"INNODB_FT_INDEX_CACHE",
2912 
2913 	/* plugin author (for SHOW PLUGINS) */
2914 	/* const char* */
2915 	plugin_author,
2916 
2917 	/* general descriptive text (for SHOW PLUGINS) */
2918 	/* const char* */
2919 	"INNODB AUXILIARY FTS INDEX CACHED",
2920 
2921 	/* the plugin license (PLUGIN_LICENSE_XXX) */
2922 	/* int */
2923 	PLUGIN_LICENSE_GPL,
2924 
2925 	/* the function to invoke when plugin is loaded */
2926 	/* int (*)(void*); */
2927 	i_s_fts_index_cache_init,
2928 
2929 	/* the function to invoke when plugin is unloaded */
2930 	/* int (*)(void*); */
2931 	i_s_common_deinit,
2932 
2933 	/* plugin version (for SHOW PLUGINS) */
2934 	/* unsigned int */
2935 	INNODB_VERSION_SHORT,
2936 
2937 	/* struct st_mysql_show_var* */
2938 	NULL,
2939 
2940 	/* struct st_mysql_sys_var** */
2941 	NULL,
2942 
2943         /* Maria extension */
2944 	INNODB_VERSION_STR,
2945         MariaDB_PLUGIN_MATURITY_STABLE,
2946 };
2947 
2948 /*******************************************************************//**
2949 Go through a FTS index auxiliary table, fetch its rows and fill
2950 FTS word cache structure.
2951 @return DB_SUCCESS on success, otherwise error code */
2952 static
2953 dberr_t
i_s_fts_index_table_fill_selected(dict_index_t * index,ib_vector_t * words,ulint selected,fts_string_t * word)2954 i_s_fts_index_table_fill_selected(
2955 /*==============================*/
2956 	dict_index_t*		index,		/*!< in: FTS index */
2957 	ib_vector_t*		words,		/*!< in/out: vector to hold
2958 						fetched words */
2959 	ulint			selected,	/*!< in: selected FTS index */
2960 	fts_string_t*		word)		/*!< in: word to select */
2961 {
2962 	pars_info_t*		info;
2963 	fts_table_t		fts_table;
2964 	trx_t*			trx;
2965 	que_t*			graph;
2966 	dberr_t			error;
2967 	fts_fetch_t		fetch;
2968 	char			table_name[MAX_FULL_NAME_LEN];
2969 
2970 	info = pars_info_create();
2971 
2972 	fetch.read_arg = words;
2973 	fetch.read_record = fts_optimize_index_fetch_node;
2974 	fetch.total_memory = 0;
2975 
2976 	DBUG_EXECUTE_IF("fts_instrument_result_cache_limit",
2977 	        fts_result_cache_limit = 8192;
2978 	);
2979 
2980 	trx = trx_create();
2981 
2982 	trx->op_info = "fetching FTS index nodes";
2983 
2984 	pars_info_bind_function(info, "my_func", fetch.read_record, &fetch);
2985 	pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len);
2986 
2987 	FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected),
2988 			     FTS_INDEX_TABLE, index);
2989 	fts_get_table_name(&fts_table, table_name);
2990 	pars_info_bind_id(info, "table_name", table_name);
2991 
2992 	graph = fts_parse_sql(
2993 		&fts_table, info,
2994 		"DECLARE FUNCTION my_func;\n"
2995 		"DECLARE CURSOR c IS"
2996 		" SELECT word, doc_count, first_doc_id, last_doc_id,"
2997 		" ilist\n"
2998 		" FROM $table_name WHERE word >= :word;\n"
2999 		"BEGIN\n"
3000 		"\n"
3001 		"OPEN c;\n"
3002 		"WHILE 1 = 1 LOOP\n"
3003 		"  FETCH c INTO my_func();\n"
3004 		"  IF c % NOTFOUND THEN\n"
3005 		"    EXIT;\n"
3006 		"  END IF;\n"
3007 		"END LOOP;\n"
3008 		"CLOSE c;");
3009 
3010 	for (;;) {
3011 		error = fts_eval_sql(trx, graph);
3012 
3013 		if (UNIV_LIKELY(error == DB_SUCCESS)) {
3014 			fts_sql_commit(trx);
3015 
3016 			break;
3017 		} else {
3018 			fts_sql_rollback(trx);
3019 
3020 			if (error == DB_LOCK_WAIT_TIMEOUT) {
3021 				ib::warn() << "Lock wait timeout reading"
3022 					" FTS index. Retrying!";
3023 
3024 				trx->error_state = DB_SUCCESS;
3025 			} else {
3026 				ib::error() << "Error occurred while reading"
3027 					" FTS index: " << error;
3028 				break;
3029 			}
3030 		}
3031 	}
3032 
3033 	mutex_enter(&dict_sys->mutex);
3034 	que_graph_free(graph);
3035 	mutex_exit(&dict_sys->mutex);
3036 
3037 	trx->free();
3038 
3039 	if (fetch.total_memory >= fts_result_cache_limit) {
3040 		error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT;
3041 	}
3042 
3043 	return(error);
3044 }
3045 
3046 /*******************************************************************//**
3047 Free words. */
3048 static
3049 void
i_s_fts_index_table_free_one_fetch(ib_vector_t * words)3050 i_s_fts_index_table_free_one_fetch(
3051 /*===============================*/
3052 	ib_vector_t*		words)		/*!< in: words fetched */
3053 {
3054 	for (ulint i = 0; i < ib_vector_size(words); i++) {
3055 		fts_word_t*	word;
3056 
3057 		word = static_cast<fts_word_t*>(ib_vector_get(words, i));
3058 
3059 		for (ulint j = 0; j < ib_vector_size(word->nodes); j++) {
3060 			fts_node_t*     node;
3061 
3062 			node = static_cast<fts_node_t*> (ib_vector_get(
3063 				word->nodes, j));
3064 			ut_free(node->ilist);
3065 		}
3066 
3067 		fts_word_free(word);
3068 	}
3069 
3070 	ib_vector_reset(words);
3071 }
3072 
3073 /*******************************************************************//**
3074 Go through words, fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
3075 @return	0 on success, 1 on failure */
3076 static
3077 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)3078 i_s_fts_index_table_fill_one_fetch(
3079 /*===============================*/
3080 	CHARSET_INFO*		index_charset,	/*!< in: FTS index charset */
3081 	THD*			thd,		/*!< in: thread */
3082 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
3083 	ib_vector_t*		words,		/*!< in: words fetched */
3084 	fts_string_t*		conv_str,	/*!< in: string for conversion*/
3085 	bool			has_more)	/*!< in: has more to fetch */
3086 {
3087 	TABLE*			table = (TABLE*) tables->table;
3088 	Field**			fields;
3089 	uint			dummy_errors;
3090 	char*			word_str;
3091 	ulint			words_size;
3092 	int			ret = 0;
3093 
3094 	DBUG_ENTER("i_s_fts_index_table_fill_one_fetch");
3095 
3096 	fields = table->field;
3097 
3098 	words_size = ib_vector_size(words);
3099 	if (has_more) {
3100 		/* the last word is not fetched completely. */
3101 		ut_ad(words_size > 1);
3102 		words_size -= 1;
3103 	}
3104 
3105 	/* Go through each word in the index cache */
3106 	for (ulint i = 0; i < words_size; i++) {
3107 		fts_word_t*	word;
3108 
3109 		word = static_cast<fts_word_t*>(ib_vector_get(words, i));
3110 
3111 		word->text.f_str[word->text.f_len] = 0;
3112 
3113 		/* Convert word from index charset to system_charset_info */
3114 		if (index_charset->cset != system_charset_info->cset) {
3115 			conv_str->f_n_char = my_convert(
3116 				reinterpret_cast<char*>(conv_str->f_str),
3117 				static_cast<uint32>(conv_str->f_len),
3118 				system_charset_info,
3119 				reinterpret_cast<char*>(word->text.f_str),
3120 				static_cast<uint32>(word->text.f_len),
3121 				index_charset, &dummy_errors);
3122 			ut_ad(conv_str->f_n_char <= conv_str->f_len);
3123 			conv_str->f_str[conv_str->f_n_char] = 0;
3124 			word_str = reinterpret_cast<char*>(conv_str->f_str);
3125 		} else {
3126 			word_str = reinterpret_cast<char*>(word->text.f_str);
3127 		}
3128 
3129 		/* Decrypt the ilist, and display Dod ID and word position */
3130 		for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
3131 			fts_node_t*	node;
3132 			const byte*	ptr;
3133 			ulint		decoded = 0;
3134 			doc_id_t	doc_id = 0;
3135 
3136 			node = static_cast<fts_node_t*> (ib_vector_get(
3137 				word->nodes, i));
3138 
3139 			ptr = node->ilist;
3140 
3141 			while (decoded < node->ilist_size) {
3142 				doc_id += fts_decode_vlc(&ptr);
3143 
3144 				/* Get position info */
3145 				while (*ptr) {
3146 
3147 					OK(field_store_string(
3148 						   fields[I_S_FTS_WORD],
3149 						   word_str));
3150 
3151 					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
3152 						longlong(node->first_doc_id), true));
3153 
3154 					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
3155 						longlong(node->last_doc_id), true));
3156 
3157 					OK(fields[I_S_FTS_DOC_COUNT]->store(
3158 						   node->doc_count, true));
3159 
3160 					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
3161 						longlong(doc_id), true));
3162 
3163 					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
3164 						   fts_decode_vlc(&ptr), true));
3165 
3166 					OK(schema_table_store_record(
3167 						   thd, table));
3168 				}
3169 
3170 				++ptr;
3171 
3172 				decoded = ptr - (byte*) node->ilist;
3173 			}
3174 		}
3175 	}
3176 
3177 	DBUG_RETURN(ret);
3178 }
3179 
3180 /*******************************************************************//**
3181 Go through a FTS index and its auxiliary tables, fetch rows in each table
3182 and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
3183 @return 0 on success, 1 on failure */
3184 static
3185 int
i_s_fts_index_table_fill_one_index(dict_index_t * index,THD * thd,fts_string_t * conv_str,TABLE_LIST * tables)3186 i_s_fts_index_table_fill_one_index(
3187 /*===============================*/
3188 	dict_index_t*		index,		/*!< in: FTS index */
3189 	THD*			thd,		/*!< in: thread */
3190 	fts_string_t*		conv_str,	/*!< in/out: buffer */
3191 	TABLE_LIST*		tables)		/*!< in/out: tables to fill */
3192 {
3193 	ib_vector_t*		words;
3194 	mem_heap_t*		heap;
3195 	CHARSET_INFO*		index_charset;
3196 	dberr_t			error;
3197 	int			ret = 0;
3198 
3199 	DBUG_ENTER("i_s_fts_index_table_fill_one_index");
3200 	DBUG_ASSERT(!dict_index_is_online_ddl(index));
3201 
3202 	heap = mem_heap_create(1024);
3203 
3204 	words = ib_vector_create(ib_heap_allocator_create(heap),
3205 				 sizeof(fts_word_t), 256);
3206 
3207 	index_charset = fts_index_get_charset(index);
3208 
3209 	/* Iterate through each auxiliary table as described in
3210 	fts_index_selector */
3211 	for (ulint selected = 0; selected < FTS_NUM_AUX_INDEX; selected++) {
3212 		fts_string_t	word;
3213 		bool		has_more = false;
3214 
3215 		word.f_str = NULL;
3216 		word.f_len = 0;
3217 		word.f_n_char = 0;
3218 
3219 		do {
3220 			/* Fetch from index */
3221 			error = i_s_fts_index_table_fill_selected(
3222 				index, words, selected, &word);
3223 
3224 			if (error == DB_SUCCESS) {
3225 				has_more = false;
3226 			} else if (error == DB_FTS_EXCEED_RESULT_CACHE_LIMIT) {
3227 				has_more = true;
3228 			} else {
3229 				i_s_fts_index_table_free_one_fetch(words);
3230 				ret = 1;
3231 				goto func_exit;
3232 			}
3233 
3234 			if (has_more) {
3235 				fts_word_t*	last_word;
3236 
3237 				/* Prepare start point for next fetch */
3238 				last_word = static_cast<fts_word_t*>(ib_vector_last(words));
3239 				ut_ad(last_word != NULL);
3240 				fts_string_dup(&word, &last_word->text, heap);
3241 			}
3242 
3243 			/* Fill into tables */
3244 			ret = i_s_fts_index_table_fill_one_fetch(
3245 				index_charset, thd, tables, words, conv_str,
3246 				has_more);
3247 			i_s_fts_index_table_free_one_fetch(words);
3248 
3249 			if (ret != 0) {
3250 				goto func_exit;
3251 			}
3252 		} while (has_more);
3253 	}
3254 
3255 func_exit:
3256 	mem_heap_free(heap);
3257 
3258 	DBUG_RETURN(ret);
3259 }
3260 /*******************************************************************//**
3261 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
3262 @return 0 on success, 1 on failure */
3263 static
3264 int
i_s_fts_index_table_fill(THD * thd,TABLE_LIST * tables,Item *)3265 i_s_fts_index_table_fill(
3266 /*=====================*/
3267 	THD*		thd,	/*!< in: thread */
3268 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
3269 	Item*		)	/*!< in: condition (ignored) */
3270 {
3271 	dict_table_t*		user_table;
3272 	dict_index_t*		index;
3273 
3274 	DBUG_ENTER("i_s_fts_index_table_fill");
3275 
3276 	/* deny access to non-superusers */
3277 	if (check_global_access(thd, PROCESS_ACL)) {
3278 		DBUG_RETURN(0);
3279 	}
3280 
3281 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
3282 
3283 	/* Prevent DROP of the internal tables for fulltext indexes.
3284 	FIXME: acquire DDL-blocking MDL on the user table name! */
3285 	rw_lock_s_lock(&dict_operation_lock);
3286 
3287 	user_table = dict_table_open_on_id(
3288 		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
3289 
3290 	if (!user_table) {
3291 		rw_lock_s_unlock(&dict_operation_lock);
3292 		DBUG_RETURN(0);
3293 	}
3294 
3295 	int		ret = 0;
3296 	fts_string_t	conv_str;
3297 	conv_str.f_len = system_charset_info->mbmaxlen
3298 		* FTS_MAX_WORD_LEN_IN_CHAR;
3299 	conv_str.f_str = static_cast<byte*>(ut_malloc_nokey(conv_str.f_len));
3300 
3301 	for (index = dict_table_get_first_index(user_table);
3302 	     index; index = dict_table_get_next_index(index)) {
3303 		if (index->type & DICT_FTS) {
3304 			BREAK_IF(ret = i_s_fts_index_table_fill_one_index(
3305 					 index, thd, &conv_str, tables));
3306 		}
3307 	}
3308 
3309 	dict_table_close(user_table, FALSE, FALSE);
3310 
3311 	rw_lock_s_unlock(&dict_operation_lock);
3312 
3313 	ut_free(conv_str.f_str);
3314 
3315 	DBUG_RETURN(ret);
3316 }
3317 
3318 /*******************************************************************//**
3319 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
3320 @return 0 on success */
3321 static
3322 int
i_s_fts_index_table_init(void * p)3323 i_s_fts_index_table_init(
3324 /*=====================*/
3325 	void*	p)	/*!< in/out: table schema object */
3326 {
3327 	DBUG_ENTER("i_s_fts_index_table_init");
3328 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
3329 
3330 	schema->fields_info = i_s_fts_index_fields_info;
3331 	schema->fill_table = i_s_fts_index_table_fill;
3332 
3333 	DBUG_RETURN(0);
3334 }
3335 
3336 UNIV_INTERN struct st_maria_plugin	i_s_innodb_ft_index_table =
3337 {
3338 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3339 	/* int */
3340 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
3341 
3342 	/* pointer to type-specific plugin descriptor */
3343 	/* void* */
3344 	&i_s_info,
3345 
3346 	/* plugin name */
3347 	/* const char* */
3348 	"INNODB_FT_INDEX_TABLE",
3349 
3350 	/* plugin author (for SHOW PLUGINS) */
3351 	/* const char* */
3352 	plugin_author,
3353 
3354 	/* general descriptive text (for SHOW PLUGINS) */
3355 	/* const char* */
3356 	"INNODB AUXILIARY FTS INDEX TABLE",
3357 
3358 	/* the plugin license (PLUGIN_LICENSE_XXX) */
3359 	/* int */
3360 	PLUGIN_LICENSE_GPL,
3361 
3362 	/* the function to invoke when plugin is loaded */
3363 	/* int (*)(void*); */
3364 	i_s_fts_index_table_init,
3365 
3366 	/* the function to invoke when plugin is unloaded */
3367 	/* int (*)(void*); */
3368 	i_s_common_deinit,
3369 
3370 	/* plugin version (for SHOW PLUGINS) */
3371 	/* unsigned int */
3372 	INNODB_VERSION_SHORT,
3373 
3374 	/* struct st_mysql_show_var* */
3375 	NULL,
3376 
3377 	/* struct st_mysql_sys_var** */
3378 	NULL,
3379 
3380         /* Maria extension */
3381 	INNODB_VERSION_STR,
3382         MariaDB_PLUGIN_MATURITY_STABLE,
3383 };
3384 
3385 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG */
3386 static ST_FIELD_INFO i_s_fts_config_fields_info[]=
3387 {
3388 #define	FTS_CONFIG_KEY			0
3389   {"KEY", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
3390 #define	FTS_CONFIG_VALUE		1
3391   {"VALUE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
3392   END_OF_ST_FIELD_INFO
3393 };
3394 
3395 static const char* fts_config_key[] = {
3396 	FTS_OPTIMIZE_LIMIT_IN_SECS,
3397 	FTS_SYNCED_DOC_ID,
3398 	FTS_STOPWORD_TABLE_NAME,
3399 	FTS_USE_STOPWORD,
3400         NULL
3401 };
3402 
3403 /*******************************************************************//**
3404 Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
3405 @return 0 on success, 1 on failure */
3406 static
3407 int
i_s_fts_config_fill(THD * thd,TABLE_LIST * tables,Item *)3408 i_s_fts_config_fill(
3409 /*================*/
3410 	THD*		thd,		/*!< in: thread */
3411 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
3412 	Item*		)	/*!< in: condition (ignored) */
3413 {
3414 	Field**			fields;
3415 	TABLE*			table = (TABLE*) tables->table;
3416 	trx_t*			trx;
3417 	fts_table_t		fts_table;
3418 	dict_table_t*		user_table;
3419 	ulint			i = 0;
3420 	dict_index_t*		index = NULL;
3421 	unsigned char		str[FTS_MAX_CONFIG_VALUE_LEN + 1];
3422 
3423 	DBUG_ENTER("i_s_fts_config_fill");
3424 
3425 	/* deny access to non-superusers */
3426 	if (check_global_access(thd, PROCESS_ACL)) {
3427 		DBUG_RETURN(0);
3428 	}
3429 
3430 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
3431 
3432 	/* Prevent DROP of the internal tables for fulltext indexes.
3433 	FIXME: acquire DDL-blocking MDL on the user table name! */
3434 	rw_lock_s_lock(&dict_operation_lock);
3435 
3436 	user_table = dict_table_open_on_id(
3437 		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
3438 
3439 	if (!user_table) {
3440 no_fts:
3441 		rw_lock_s_unlock(&dict_operation_lock);
3442 		DBUG_RETURN(0);
3443 	}
3444 
3445 	if (!dict_table_has_fts_index(user_table)) {
3446 		dict_table_close(user_table, FALSE, FALSE);
3447 		goto no_fts;
3448 	}
3449 
3450 	fields = table->field;
3451 
3452 	trx = trx_create();
3453 	trx->op_info = "Select for FTS CONFIG TABLE";
3454 
3455 	FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE, user_table);
3456 
3457 	if (!ib_vector_is_empty(user_table->fts->indexes)) {
3458 		index = (dict_index_t*) ib_vector_getp_const(
3459 				user_table->fts->indexes, 0);
3460 		DBUG_ASSERT(!dict_index_is_online_ddl(index));
3461 	}
3462 
3463 	int	ret = 0;
3464 
3465 	while (fts_config_key[i]) {
3466 		fts_string_t	value;
3467 		char*		key_name;
3468 		ulint		allocated = FALSE;
3469 
3470 		value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
3471 
3472 		value.f_str = str;
3473 
3474 		if (index
3475 		    && strcmp(fts_config_key[i], FTS_TOTAL_WORD_COUNT) == 0) {
3476 			key_name = fts_config_create_index_param_name(
3477 				fts_config_key[i], index);
3478 			allocated = TRUE;
3479 		} else {
3480 			key_name = (char*) fts_config_key[i];
3481 		}
3482 
3483 		fts_config_get_value(trx, &fts_table, key_name, &value);
3484 
3485 		if (allocated) {
3486 			ut_free(key_name);
3487 		}
3488 
3489 		BREAK_IF(ret = field_store_string(
3490 				 fields[FTS_CONFIG_KEY], fts_config_key[i]));
3491 
3492 		BREAK_IF(ret = field_store_string(
3493 				 fields[FTS_CONFIG_VALUE],
3494 				 reinterpret_cast<const char*>(value.f_str)));
3495 
3496 		BREAK_IF(ret = schema_table_store_record(thd, table));
3497 
3498 		i++;
3499 	}
3500 
3501 	fts_sql_commit(trx);
3502 
3503 	dict_table_close(user_table, FALSE, FALSE);
3504 
3505 	rw_lock_s_unlock(&dict_operation_lock);
3506 
3507 	trx->free();
3508 
3509 	DBUG_RETURN(ret);
3510 }
3511 
3512 /*******************************************************************//**
3513 Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
3514 @return 0 on success */
3515 static
3516 int
i_s_fts_config_init(void * p)3517 i_s_fts_config_init(
3518 /*=================*/
3519 	void*	p)	/*!< in/out: table schema object */
3520 {
3521 	DBUG_ENTER("i_s_fts_config_init");
3522 	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
3523 
3524 	schema->fields_info = i_s_fts_config_fields_info;
3525 	schema->fill_table = i_s_fts_config_fill;
3526 
3527 	DBUG_RETURN(0);
3528 }
3529 
3530 UNIV_INTERN struct st_maria_plugin	i_s_innodb_ft_config =
3531 {
3532 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3533 	/* int */
3534 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
3535 
3536 	/* pointer to type-specific plugin descriptor */
3537 	/* void* */
3538 	&i_s_info,
3539 
3540 	/* plugin name */
3541 	/* const char* */
3542 	"INNODB_FT_CONFIG",
3543 
3544 	/* plugin author (for SHOW PLUGINS) */
3545 	/* const char* */
3546 	plugin_author,
3547 
3548 	/* general descriptive text (for SHOW PLUGINS) */
3549 	/* const char* */
3550 	"INNODB AUXILIARY FTS CONFIG TABLE",
3551 
3552 	/* the plugin license (PLUGIN_LICENSE_XXX) */
3553 	/* int */
3554 	PLUGIN_LICENSE_GPL,
3555 
3556 	/* the function to invoke when plugin is loaded */
3557 	/* int (*)(void*); */
3558 	i_s_fts_config_init,
3559 
3560 	/* the function to invoke when plugin is unloaded */
3561 	/* int (*)(void*); */
3562 	i_s_common_deinit,
3563 
3564 	/* plugin version (for SHOW PLUGINS) */
3565 	/* unsigned int */
3566 	INNODB_VERSION_SHORT,
3567 
3568 	/* struct st_mysql_show_var* */
3569 	NULL,
3570 
3571 	/* struct st_mysql_sys_var** */
3572 	NULL,
3573 
3574         /* Maria extension */
3575 	INNODB_VERSION_STR,
3576         MariaDB_PLUGIN_MATURITY_STABLE,
3577 };
3578 
3579 /* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */
3580 static ST_FIELD_INFO i_s_innodb_buffer_stats_fields_info[]=
3581 {
3582 #define IDX_BUF_STATS_POOL_ID		0
3583   {"POOL_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3584    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3585 #define IDX_BUF_STATS_POOL_SIZE		1
3586   {"POOL_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3587    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3588 #define IDX_BUF_STATS_FREE_BUFFERS	2
3589   {"FREE_BUFFERS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3590    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3591 #define IDX_BUF_STATS_LRU_LEN		3
3592   {"DATABASE_PAGES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3593    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3594 #define IDX_BUF_STATS_OLD_LRU_LEN	4
3595   {"OLD_DATABASE_PAGES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3596    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3597 #define IDX_BUF_STATS_FLUSH_LIST_LEN	5
3598   {"MODIFIED_DATABASE_PAGES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3599    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3600 #define IDX_BUF_STATS_PENDING_ZIP	6
3601   {"PENDING_DECOMPRESS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3602    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3603 #define IDX_BUF_STATS_PENDING_READ	7
3604   {"PENDING_READS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3605    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3606 #define IDX_BUF_STATS_FLUSH_LRU		8
3607   {"PENDING_FLUSH_LRU", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3608    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3609 #define IDX_BUF_STATS_FLUSH_LIST	9
3610   {"PENDING_FLUSH_LIST", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3611    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3612 #define IDX_BUF_STATS_PAGE_YOUNG	10
3613   {"PAGES_MADE_YOUNG", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3614    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3615 #define IDX_BUF_STATS_PAGE_NOT_YOUNG	11
3616   {"PAGES_NOT_MADE_YOUNG", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3617    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3618 #define	IDX_BUF_STATS_PAGE_YOUNG_RATE	12
3619   {"PAGES_MADE_YOUNG_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3620    0, 0, "", SKIP_OPEN_TABLE},
3621 #define	IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE 13
3622   {"PAGES_MADE_NOT_YOUNG_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3623    0, 0, "", SKIP_OPEN_TABLE},
3624 #define IDX_BUF_STATS_PAGE_READ		14
3625   {"NUMBER_PAGES_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3626    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3627 #define IDX_BUF_STATS_PAGE_CREATED	15
3628   {"NUMBER_PAGES_CREATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3629    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3630 #define IDX_BUF_STATS_PAGE_WRITTEN	16
3631   {"NUMBER_PAGES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3632    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3633 #define	IDX_BUF_STATS_PAGE_READ_RATE	17
3634   {"PAGES_READ_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3635    0, 0, "", SKIP_OPEN_TABLE},
3636 #define	IDX_BUF_STATS_PAGE_CREATE_RATE	18
3637   {"PAGES_CREATE_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3638    0, 0, "", SKIP_OPEN_TABLE},
3639 #define	IDX_BUF_STATS_PAGE_WRITTEN_RATE	19
3640   {"PAGES_WRITTEN_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3641    0, 0, "", SKIP_OPEN_TABLE},
3642 #define IDX_BUF_STATS_GET		20
3643   {"NUMBER_PAGES_GET", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3644    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3645 #define IDX_BUF_STATS_HIT_RATE		21
3646   {"HIT_RATE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3647    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3648 #define IDX_BUF_STATS_MADE_YOUNG_PCT	22
3649   {"YOUNG_MAKE_PER_THOUSAND_GETS", MY_INT64_NUM_DECIMAL_DIGITS,
3650    MYSQL_TYPE_LONGLONG,
3651    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3652 #define IDX_BUF_STATS_NOT_MADE_YOUNG_PCT 23
3653   {"NOT_YOUNG_MAKE_PER_THOUSAND_GETS", MY_INT64_NUM_DECIMAL_DIGITS,
3654    MYSQL_TYPE_LONGLONG,
3655    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3656 #define IDX_BUF_STATS_READ_AHREAD	24
3657   {"NUMBER_PAGES_READ_AHEAD", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3658    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3659 #define IDX_BUF_STATS_READ_AHEAD_EVICTED 25
3660   {"NUMBER_READ_AHEAD_EVICTED", MY_INT64_NUM_DECIMAL_DIGITS,
3661    MYSQL_TYPE_LONGLONG,
3662    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3663 #define	IDX_BUF_STATS_READ_AHEAD_RATE	26
3664   {"READ_AHEAD_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3665    0, 0, "", SKIP_OPEN_TABLE},
3666 #define	IDX_BUF_STATS_READ_AHEAD_EVICT_RATE 27
3667   {"READ_AHEAD_EVICTED_RATE", MAX_FLOAT_STR_LENGTH, MYSQL_TYPE_FLOAT,
3668    0, 0, "", SKIP_OPEN_TABLE},
3669 #define IDX_BUF_STATS_LRU_IO_SUM	28
3670   {"LRU_IO_TOTAL", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3671    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3672 #define IDX_BUF_STATS_LRU_IO_CUR	29
3673   {"LRU_IO_CURRENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3674    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3675 #define IDX_BUF_STATS_UNZIP_SUM		30
3676   {"UNCOMPRESS_TOTAL", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3677    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3678 #define IDX_BUF_STATS_UNZIP_CUR		31
3679   {"UNCOMPRESS_CURRENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3680    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3681   END_OF_ST_FIELD_INFO
3682 };
3683 
3684 /*******************************************************************//**
3685 Fill Information Schema table INNODB_BUFFER_POOL_STATS for a particular
3686 buffer pool
3687 @return 0 on success, 1 on failure */
3688 static
3689 int
i_s_innodb_stats_fill(THD * thd,TABLE_LIST * tables,const buf_pool_info_t * info)3690 i_s_innodb_stats_fill(
3691 /*==================*/
3692 	THD*			thd,		/*!< in: thread */
3693 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
3694 	const buf_pool_info_t*	info)		/*!< in: buffer pool
3695 						information */
3696 {
3697 	TABLE*			table;
3698 	Field**			fields;
3699 
3700 	DBUG_ENTER("i_s_innodb_stats_fill");
3701 
3702 	table = tables->table;
3703 
3704 	fields = table->field;
3705 
3706 	OK(fields[IDX_BUF_STATS_POOL_ID]->store(
3707 		   info->pool_unique_id, true));
3708 
3709 	OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(
3710 		   info->pool_size, true));
3711 
3712 	OK(fields[IDX_BUF_STATS_LRU_LEN]->store(
3713 		   info->lru_len, true));
3714 
3715 	OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(
3716 		   info->old_lru_len, true));
3717 
3718 	OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
3719 		   info->free_list_len, true));
3720 
3721 	OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
3722 		   info->flush_list_len, true));
3723 
3724 	OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(
3725 		   info->n_pend_unzip, true));
3726 
3727 	OK(fields[IDX_BUF_STATS_PENDING_READ]->store(
3728 		   info->n_pend_reads, true));
3729 
3730 	OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
3731 		   info->n_pending_flush_lru, true));
3732 
3733 	OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
3734 		   info->n_pending_flush_list, true));
3735 
3736 	OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
3737 		   info->n_pages_made_young, true));
3738 
3739 	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
3740 		   info->n_pages_not_made_young, true));
3741 
3742 	OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
3743 		   info->page_made_young_rate));
3744 
3745 	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
3746 		   info->page_not_made_young_rate));
3747 
3748 	OK(fields[IDX_BUF_STATS_PAGE_READ]->store(
3749 		   info->n_pages_read, true));
3750 
3751 	OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
3752 		   info->n_pages_created, true));
3753 
3754 	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
3755 		   info->n_pages_written, true));
3756 
3757 	OK(fields[IDX_BUF_STATS_GET]->store(
3758 		   info->n_page_gets, true));
3759 
3760 	OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
3761 		   info->pages_read_rate));
3762 
3763 	OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
3764 		   info->pages_created_rate));
3765 
3766 	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
3767 		   info->pages_written_rate));
3768 
3769 	if (info->n_page_get_delta) {
3770 		if (info->page_read_delta <= info->n_page_get_delta) {
3771 			OK(fields[IDX_BUF_STATS_HIT_RATE]->store(
3772 				static_cast<double>(
3773 					1000 - (1000 * info->page_read_delta
3774 					/ info->n_page_get_delta))));
3775 		} else {
3776 			OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0));
3777 		}
3778 
3779 		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
3780 			   1000 * info->young_making_delta
3781 			   / info->n_page_get_delta, true));
3782 
3783 		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
3784 			   1000 * info->not_young_making_delta
3785 			   / info->n_page_get_delta, true));
3786 	} else {
3787 		OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0, true));
3788 		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0, true));
3789 		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0, true));
3790 	}
3791 
3792 	OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(
3793 		   info->n_ra_pages_read, true));
3794 
3795 	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
3796 		   info->n_ra_pages_evicted, true));
3797 
3798 	OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
3799 		   info->pages_readahead_rate));
3800 
3801 	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
3802 		   info->pages_evicted_rate));
3803 
3804 	OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(
3805 		   info->io_sum, true));
3806 
3807 	OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(
3808 		   info->io_cur, true));
3809 
3810 	OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(
3811 		   info->unzip_sum, true));
3812 
3813 	OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(
3814 		   info->unzip_cur, true));
3815 
3816 	DBUG_RETURN(schema_table_store_record(thd, table));
3817 }
3818 
3819 /*******************************************************************//**
3820 This is the function that loops through each buffer pool and fetch buffer
3821 pool stats to information schema  table: I_S_INNODB_BUFFER_POOL_STATS
3822 @return 0 on success, 1 on failure */
3823 static
3824 int
i_s_innodb_buffer_stats_fill_table(THD * thd,TABLE_LIST * tables,Item *)3825 i_s_innodb_buffer_stats_fill_table(
3826 /*===============================*/
3827 	THD*		thd,		/*!< in: thread */
3828 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
3829 	Item*		)		/*!< in: condition (ignored) */
3830 {
3831 	int			status	= 0;
3832 	buf_pool_info_t*	pool_info;
3833 
3834 	DBUG_ENTER("i_s_innodb_buffer_fill_general");
3835 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
3836 
3837 	/* Only allow the PROCESS privilege holder to access the stats */
3838 	if (check_global_access(thd, PROCESS_ACL)) {
3839 		DBUG_RETURN(0);
3840 	}
3841 
3842 	pool_info = (buf_pool_info_t*) ut_zalloc_nokey(
3843 		srv_buf_pool_instances *  sizeof *pool_info);
3844 
3845 	/* Walk through each buffer pool */
3846 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
3847 		buf_pool_t*		buf_pool;
3848 
3849 		buf_pool = buf_pool_from_array(i);
3850 
3851 		/* Fetch individual buffer pool info */
3852 		buf_stats_get_pool_info(buf_pool, i, pool_info);
3853 
3854 		status = i_s_innodb_stats_fill(thd, tables, &pool_info[i]);
3855 
3856 		/* If something goes wrong, break and return */
3857 		if (status) {
3858 			break;
3859 		}
3860 	}
3861 
3862 	ut_free(pool_info);
3863 
3864 	DBUG_RETURN(status);
3865 }
3866 
3867 /*******************************************************************//**
3868 Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS.
3869 @return 0 on success, 1 on failure */
3870 static
3871 int
i_s_innodb_buffer_pool_stats_init(void * p)3872 i_s_innodb_buffer_pool_stats_init(
3873 /*==============================*/
3874 	void*	p)	/*!< in/out: table schema object */
3875 {
3876 	ST_SCHEMA_TABLE*	schema;
3877 
3878 	DBUG_ENTER("i_s_innodb_buffer_pool_stats_init");
3879 
3880 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
3881 
3882 	schema->fields_info = i_s_innodb_buffer_stats_fields_info;
3883 	schema->fill_table = i_s_innodb_buffer_stats_fill_table;
3884 
3885 	DBUG_RETURN(0);
3886 }
3887 
3888 UNIV_INTERN struct st_maria_plugin	i_s_innodb_buffer_stats =
3889 {
3890 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
3891 	/* int */
3892 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
3893 
3894 	/* pointer to type-specific plugin descriptor */
3895 	/* void* */
3896 	&i_s_info,
3897 
3898 	/* plugin name */
3899 	/* const char* */
3900 	"INNODB_BUFFER_POOL_STATS",
3901 
3902 	/* plugin author (for SHOW PLUGINS) */
3903 	/* const char* */
3904 	plugin_author,
3905 
3906 	/* general descriptive text (for SHOW PLUGINS) */
3907 	/* const char* */
3908 	"InnoDB Buffer Pool Statistics Information ",
3909 
3910 	/* the plugin license (PLUGIN_LICENSE_XXX) */
3911 	/* int */
3912 	PLUGIN_LICENSE_GPL,
3913 
3914 	/* the function to invoke when plugin is loaded */
3915 	/* int (*)(void*); */
3916 	i_s_innodb_buffer_pool_stats_init,
3917 
3918 	/* the function to invoke when plugin is unloaded */
3919 	/* int (*)(void*); */
3920 	i_s_common_deinit,
3921 
3922 	/* plugin version (for SHOW PLUGINS) */
3923 	/* unsigned int */
3924 	INNODB_VERSION_SHORT,
3925 
3926 	/* struct st_mysql_show_var* */
3927 	NULL,
3928 
3929 	/* struct st_mysql_sys_var** */
3930 	NULL,
3931 
3932         /* Maria extension */
3933 	INNODB_VERSION_STR,
3934         MariaDB_PLUGIN_MATURITY_STABLE,
3935 };
3936 
3937 /* Fields of the dynamic table INNODB_BUFFER_POOL_PAGE. */
3938 static ST_FIELD_INFO i_s_innodb_buffer_page_fields_info[]=
3939 {
3940 #define IDX_BUFFER_POOL_ID		0
3941   {"POOL_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3942    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3943 #define IDX_BUFFER_BLOCK_ID		1
3944   {"BLOCK_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3945    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3946 #define IDX_BUFFER_PAGE_SPACE		2
3947   {"SPACE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3948    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3949 #define IDX_BUFFER_PAGE_NUM		3
3950   {"PAGE_NUMBER", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3951    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3952 #define IDX_BUFFER_PAGE_TYPE		4
3953   {"PAGE_TYPE", 64, MYSQL_TYPE_STRING,
3954    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3955 #define IDX_BUFFER_PAGE_FLUSH_TYPE	5
3956   {"FLUSH_TYPE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3957    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3958 #define IDX_BUFFER_PAGE_FIX_COUNT	6
3959   {"FIX_COUNT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3960    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3961 #ifdef BTR_CUR_HASH_ADAPT
3962 # define IDX_BUFFER_PAGE_HASHED		7
3963   {"IS_HASHED", 3, MYSQL_TYPE_STRING,
3964    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3965 #endif /* BTR_CUR_HASH_ADAPT */
3966 #define IDX_BUFFER_PAGE_NEWEST_MOD	7 + I_S_AHI
3967   {"NEWEST_MODIFICATION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3968    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3969 #define IDX_BUFFER_PAGE_OLDEST_MOD	8 + I_S_AHI
3970   {"OLDEST_MODIFICATION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3971    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3972 #define IDX_BUFFER_PAGE_ACCESS_TIME	9 + I_S_AHI
3973   {"ACCESS_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3974    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3975 #define IDX_BUFFER_PAGE_TABLE_NAME	10 + I_S_AHI
3976   {"TABLE_NAME", 1024, MYSQL_TYPE_STRING,
3977    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3978 #define IDX_BUFFER_PAGE_INDEX_NAME	11 + I_S_AHI
3979   {"INDEX_NAME", 1024, MYSQL_TYPE_STRING,
3980    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3981 #define IDX_BUFFER_PAGE_NUM_RECS	12 + I_S_AHI
3982   {"NUMBER_RECORDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3983    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3984 #define IDX_BUFFER_PAGE_DATA_SIZE	13 + I_S_AHI
3985   {"DATA_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3986    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3987 #define IDX_BUFFER_PAGE_ZIP_SIZE	14 + I_S_AHI
3988   {"COMPRESSED_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
3989    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
3990 #define IDX_BUFFER_PAGE_STATE		15 + I_S_AHI
3991   {"PAGE_STATE", 64, MYSQL_TYPE_STRING,
3992    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3993 #define IDX_BUFFER_PAGE_IO_FIX		16 + I_S_AHI
3994   {"IO_FIX", 64, MYSQL_TYPE_STRING,
3995    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3996 #define IDX_BUFFER_PAGE_IS_OLD		17 + I_S_AHI
3997   {"IS_OLD", 3, MYSQL_TYPE_STRING,
3998    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
3999 #define IDX_BUFFER_PAGE_FREE_CLOCK	18 + I_S_AHI
4000   {"FREE_PAGE_CLOCK", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4001    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4002   END_OF_ST_FIELD_INFO
4003 };
4004 
4005 /*******************************************************************//**
4006 Fill Information Schema table INNODB_BUFFER_PAGE with information
4007 cached in the buf_page_info_t array
4008 @return 0 on success, 1 on failure */
4009 static
4010 int
i_s_innodb_buffer_page_fill(THD * thd,TABLE_LIST * tables,const buf_page_info_t * info_array,ulint num_page)4011 i_s_innodb_buffer_page_fill(
4012 /*========================*/
4013 	THD*			thd,		/*!< in: thread */
4014 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
4015 	const buf_page_info_t*	info_array,	/*!< in: array cached page
4016 						info */
4017 	ulint			num_page)	/*!< in: number of page info
4018 						cached */
4019 {
4020 	TABLE*			table;
4021 	Field**			fields;
4022 
4023 	compile_time_assert(I_S_PAGE_TYPE_LAST < 1 << I_S_PAGE_TYPE_BITS);
4024 
4025 	DBUG_ENTER("i_s_innodb_buffer_page_fill");
4026 
4027 	table = tables->table;
4028 
4029 	fields = table->field;
4030 
4031 	/* Iterate through the cached array and fill the I_S table rows */
4032 	for (ulint i = 0; i < num_page; i++) {
4033 		const buf_page_info_t*	page_info;
4034 		char			table_name[MAX_FULL_NAME_LEN + 1];
4035 		const char*		table_name_end = NULL;
4036 		const char*		state_str;
4037 		enum buf_page_state	state;
4038 
4039 		page_info = info_array + i;
4040 
4041 		state_str = NULL;
4042 
4043 		OK(fields[IDX_BUFFER_POOL_ID]->store(
4044 			   page_info->pool_id, true));
4045 
4046 		OK(fields[IDX_BUFFER_BLOCK_ID]->store(
4047 			   page_info->block_id, true));
4048 
4049 		OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
4050 			   page_info->space_id, true));
4051 
4052 		OK(fields[IDX_BUFFER_PAGE_NUM]->store(
4053 			   page_info->page_num, true));
4054 
4055 		OK(field_store_string(
4056 			   fields[IDX_BUFFER_PAGE_TYPE],
4057 			   i_s_page_type[page_info->page_type].type_str));
4058 
4059 		OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store(
4060 			   page_info->flush_type, true));
4061 
4062 		OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
4063 			   page_info->fix_count, true));
4064 
4065 #ifdef BTR_CUR_HASH_ADAPT
4066 		OK(field_store_string(fields[IDX_BUFFER_PAGE_HASHED],
4067 				      page_info->hashed ? "YES" : "NO"));
4068 #endif /* BTR_CUR_HASH_ADAPT */
4069 
4070 		OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
4071 			   page_info->newest_mod, true));
4072 
4073 		OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store(
4074 			   page_info->oldest_mod, true));
4075 
4076 		OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store(
4077 			   page_info->access_time, true));
4078 
4079 		fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_null();
4080 
4081 		fields[IDX_BUFFER_PAGE_INDEX_NAME]->set_null();
4082 
4083 		/* If this is an index page, fetch the index name
4084 		and table name */
4085 		if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
4086 			bool ret = false;
4087 
4088 			mutex_enter(&dict_sys->mutex);
4089 
4090 			const dict_index_t* index =
4091 				dict_index_get_if_in_cache_low(
4092 					page_info->index_id);
4093 
4094 			if (index) {
4095 				table_name_end = innobase_convert_name(
4096 					table_name, sizeof(table_name),
4097 					index->table->name.m_name,
4098 					strlen(index->table->name.m_name),
4099 					thd);
4100 
4101 				ret = fields[IDX_BUFFER_PAGE_TABLE_NAME]
4102 					->store(table_name,
4103 						static_cast<uint>(
4104 							table_name_end
4105 							- table_name),
4106 						system_charset_info)
4107 					|| fields[IDX_BUFFER_PAGE_INDEX_NAME]
4108 					->store(index->name,
4109 						uint(strlen(index->name)),
4110 						system_charset_info);
4111 			}
4112 
4113 			mutex_exit(&dict_sys->mutex);
4114 
4115 			OK(ret);
4116 
4117 			if (index) {
4118 				fields[IDX_BUFFER_PAGE_TABLE_NAME]
4119 					->set_notnull();
4120 				fields[IDX_BUFFER_PAGE_INDEX_NAME]
4121 					->set_notnull();
4122 			}
4123 		}
4124 
4125 		OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store(
4126 			   page_info->num_recs, true));
4127 
4128 		OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store(
4129 			   page_info->data_size, true));
4130 
4131 		OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store(
4132 			   page_info->zip_ssize
4133 			   ? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
4134 			   : 0, true));
4135 		compile_time_assert(BUF_PAGE_STATE_BITS == 3);
4136 		state = static_cast<enum buf_page_state>(page_info->page_state);
4137 
4138 		switch (state) {
4139 		/* First three states are for compression pages and
4140 		are not states we would get as we scan pages through
4141 		buffer blocks */
4142 		case BUF_BLOCK_POOL_WATCH:
4143 		case BUF_BLOCK_ZIP_PAGE:
4144 		case BUF_BLOCK_ZIP_DIRTY:
4145 			state_str = NULL;
4146 			break;
4147 		case BUF_BLOCK_NOT_USED:
4148 			state_str = "NOT_USED";
4149 			break;
4150 		case BUF_BLOCK_READY_FOR_USE:
4151 			state_str = "READY_FOR_USE";
4152 			break;
4153 		case BUF_BLOCK_FILE_PAGE:
4154 			state_str = "FILE_PAGE";
4155 			break;
4156 		case BUF_BLOCK_MEMORY:
4157 			state_str = "MEMORY";
4158 			break;
4159 		case BUF_BLOCK_REMOVE_HASH:
4160 			state_str = "REMOVE_HASH";
4161 			break;
4162 		};
4163 
4164 		OK(field_store_string(fields[IDX_BUFFER_PAGE_STATE],
4165 				      state_str));
4166 
4167 		switch (page_info->io_fix) {
4168 		case BUF_IO_NONE:
4169 			state_str = "IO_NONE";
4170 			break;
4171 		case BUF_IO_READ:
4172 			state_str = "IO_READ";
4173 			break;
4174 		case BUF_IO_WRITE:
4175 			state_str = "IO_WRITE";
4176 			break;
4177 		case BUF_IO_PIN:
4178 			state_str = "IO_PIN";
4179 			break;
4180 		}
4181 
4182 		OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX],
4183 				      state_str));
4184 
4185 		OK(field_store_string(fields[IDX_BUFFER_PAGE_IS_OLD],
4186 				      (page_info->is_old) ? "YES" : "NO"));
4187 
4188 		OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store(
4189 			   page_info->freed_page_clock, true));
4190 
4191 		OK(schema_table_store_record(thd, table));
4192 	}
4193 
4194 	DBUG_RETURN(0);
4195 }
4196 
4197 /*******************************************************************//**
4198 Set appropriate page type to a buf_page_info_t structure */
4199 static
4200 void
i_s_innodb_set_page_type(buf_page_info_t * page_info,ulint page_type,const byte * frame)4201 i_s_innodb_set_page_type(
4202 /*=====================*/
4203 	buf_page_info_t*page_info,	/*!< in/out: structure to fill with
4204 					scanned info */
4205 	ulint		page_type,	/*!< in: page type */
4206 	const byte*	frame)		/*!< in: buffer frame */
4207 {
4208 	if (fil_page_type_is_index(page_type)) {
4209 		const page_t*	page = (const page_t*) frame;
4210 
4211 		page_info->index_id = btr_page_get_index_id(page);
4212 
4213 		/* FIL_PAGE_INDEX and FIL_PAGE_RTREE are a bit special,
4214 		their values are defined as 17855 and 17854, so we cannot
4215 		use them to index into i_s_page_type[] array, its array index
4216 		in the i_s_page_type[] array is I_S_PAGE_TYPE_INDEX
4217 		(1) for index pages or I_S_PAGE_TYPE_IBUF for
4218 		change buffer index pages */
4219 		if (page_type == FIL_PAGE_RTREE) {
4220 			page_info->page_type = I_S_PAGE_TYPE_RTREE;
4221 		} else if (page_info->index_id
4222 			   == static_cast<index_id_t>(DICT_IBUF_ID_MIN
4223 						      + IBUF_SPACE_ID)) {
4224 			page_info->page_type = I_S_PAGE_TYPE_IBUF;
4225 		} else {
4226 			ut_ad(page_type == FIL_PAGE_INDEX
4227 			      || page_type == FIL_PAGE_TYPE_INSTANT);
4228 			page_info->page_type = I_S_PAGE_TYPE_INDEX;
4229 		}
4230 
4231 		page_info->data_size = unsigned(page_header_get_field(
4232 			page, PAGE_HEAP_TOP) - (page_is_comp(page)
4233 						? PAGE_NEW_SUPREMUM_END
4234 						: PAGE_OLD_SUPREMUM_END)
4235 			- page_header_get_field(page, PAGE_GARBAGE));
4236 
4237 		page_info->num_recs = page_get_n_recs(page);
4238 	} else if (page_type > FIL_PAGE_TYPE_LAST) {
4239 		/* Encountered an unknown page type */
4240 		page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
4241 	} else {
4242 		/* Make sure we get the right index into the
4243 		i_s_page_type[] array */
4244 		ut_a(page_type == i_s_page_type[page_type].type_value);
4245 
4246 		page_info->page_type = page_type;
4247 	}
4248 
4249 	if (page_info->page_type == FIL_PAGE_TYPE_ZBLOB
4250 	    || page_info->page_type == FIL_PAGE_TYPE_ZBLOB2) {
4251 		page_info->page_num = mach_read_from_4(
4252 			frame + FIL_PAGE_OFFSET);
4253 		page_info->space_id = mach_read_from_4(
4254 			frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
4255 	}
4256 }
4257 /*******************************************************************//**
4258 Scans pages in the buffer cache, and collect their general information
4259 into the buf_page_info_t array which is zero-filled. So any fields
4260 that are not initialized in the function will default to 0 */
4261 static
4262 void
i_s_innodb_buffer_page_get_info(const buf_page_t * bpage,ulint pool_id,ulint pos,buf_page_info_t * page_info)4263 i_s_innodb_buffer_page_get_info(
4264 /*============================*/
4265 	const buf_page_t*bpage,		/*!< in: buffer pool page to scan */
4266 	ulint		pool_id,	/*!< in: buffer pool id */
4267 	ulint		pos,		/*!< in: buffer block position in
4268 					buffer pool or in the LRU list */
4269 	buf_page_info_t*page_info)	/*!< in: zero filled info structure;
4270 					out: structure filled with scanned
4271 					info */
4272 {
4273 	ut_ad(pool_id < MAX_BUFFER_POOLS);
4274 
4275 	page_info->pool_id = pool_id;
4276 
4277 	page_info->block_id = pos;
4278 
4279 	page_info->page_state = buf_page_get_state(bpage);
4280 
4281 	/* Only fetch information for buffers that map to a tablespace,
4282 	that is, buffer page with state BUF_BLOCK_ZIP_PAGE,
4283 	BUF_BLOCK_ZIP_DIRTY or BUF_BLOCK_FILE_PAGE */
4284 	if (buf_page_in_file(bpage)) {
4285 		const byte*	frame;
4286 		ulint		page_type;
4287 
4288 		page_info->space_id = bpage->id.space();
4289 
4290 		page_info->page_num = bpage->id.page_no();
4291 
4292 		page_info->flush_type = bpage->flush_type;
4293 
4294 		page_info->fix_count = bpage->buf_fix_count;
4295 
4296 		page_info->newest_mod = bpage->newest_modification;
4297 
4298 		page_info->oldest_mod = bpage->oldest_modification;
4299 
4300 		page_info->access_time = bpage->access_time;
4301 
4302 		page_info->zip_ssize = bpage->zip.ssize;
4303 
4304 		page_info->io_fix = bpage->io_fix;
4305 
4306 		page_info->is_old = bpage->old;
4307 
4308 		page_info->freed_page_clock = bpage->freed_page_clock;
4309 
4310 		switch (buf_page_get_io_fix(bpage)) {
4311 		case BUF_IO_NONE:
4312 		case BUF_IO_WRITE:
4313 		case BUF_IO_PIN:
4314 			break;
4315 		case BUF_IO_READ:
4316 			page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
4317 			return;
4318 		}
4319 
4320 		if (page_info->page_state == BUF_BLOCK_FILE_PAGE) {
4321 			const buf_block_t*block;
4322 
4323 			block = reinterpret_cast<const buf_block_t*>(bpage);
4324 			frame = block->frame;
4325 #ifdef BTR_CUR_HASH_ADAPT
4326 			/* Note: this may be a false positive, that
4327 			is, block->index will not always be set to
4328 			NULL when the last adaptive hash index
4329 			reference is dropped. */
4330 			page_info->hashed = (block->index != NULL);
4331 #endif /* BTR_CUR_HASH_ADAPT */
4332 		} else {
4333 			ut_ad(page_info->zip_ssize);
4334 			frame = bpage->zip.data;
4335 		}
4336 
4337 		page_type = fil_page_get_type(frame);
4338 
4339 		i_s_innodb_set_page_type(page_info, page_type, frame);
4340 	} else {
4341 		page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
4342 	}
4343 }
4344 
4345 /*******************************************************************//**
4346 This is the function that goes through each block of the buffer pool
4347 and fetch information to information schema tables: INNODB_BUFFER_PAGE.
4348 @return 0 on success, 1 on failure */
4349 static
4350 int
i_s_innodb_fill_buffer_pool(THD * thd,TABLE_LIST * tables,buf_pool_t * buf_pool,const ulint pool_id)4351 i_s_innodb_fill_buffer_pool(
4352 /*========================*/
4353 	THD*			thd,		/*!< in: thread */
4354 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
4355 	buf_pool_t*		buf_pool,	/*!< in: buffer pool to scan */
4356 	const ulint		pool_id)	/*!< in: buffer pool id */
4357 {
4358 	int			status	= 0;
4359 	mem_heap_t*		heap;
4360 
4361 	DBUG_ENTER("i_s_innodb_fill_buffer_pool");
4362 
4363 	heap = mem_heap_create(10000);
4364 
4365 	/* Go through each chunk of buffer pool. Currently, we only
4366 	have one single chunk for each buffer pool */
4367 	for (ulint n = 0;
4368 	     n < ut_min(buf_pool->n_chunks, buf_pool->n_chunks_new); n++) {
4369 		const buf_block_t*	block;
4370 		ulint			n_blocks;
4371 		buf_page_info_t*	info_buffer;
4372 		ulint			num_page;
4373 		ulint			mem_size;
4374 		ulint			chunk_size;
4375 		ulint			num_to_process = 0;
4376 		ulint			block_id = 0;
4377 
4378 		/* Get buffer block of the nth chunk */
4379 		block = buf_get_nth_chunk_block(buf_pool, n, &chunk_size);
4380 		num_page = 0;
4381 
4382 		while (chunk_size > 0) {
4383 			/* we cache maximum MAX_BUF_INFO_CACHED number of
4384 			buffer page info */
4385 			num_to_process = ut_min(chunk_size,
4386 				(ulint)MAX_BUF_INFO_CACHED);
4387 
4388 			mem_size = num_to_process * sizeof(buf_page_info_t);
4389 
4390 			/* For each chunk, we'll pre-allocate information
4391 			structures to cache the page information read from
4392 			the buffer pool. Doing so before obtain any mutex */
4393 			info_buffer = (buf_page_info_t*) mem_heap_zalloc(
4394 				heap, mem_size);
4395 
4396 			/* Obtain appropriate mutexes. Since this is diagnostic
4397 			buffer pool info printout, we are not required to
4398 			preserve the overall consistency, so we can
4399 			release mutex periodically */
4400 			buf_pool_mutex_enter(buf_pool);
4401 
4402 			/* GO through each block in the chunk */
4403 			for (n_blocks = num_to_process; n_blocks--; block++) {
4404 				i_s_innodb_buffer_page_get_info(
4405 					&block->page, pool_id, block_id,
4406 					info_buffer + num_page);
4407 				block_id++;
4408 				num_page++;
4409 			}
4410 
4411 			buf_pool_mutex_exit(buf_pool);
4412 
4413 			/* Fill in information schema table with information
4414 			just collected from the buffer chunk scan */
4415 			status = i_s_innodb_buffer_page_fill(
4416 				thd, tables, info_buffer,
4417 				num_page);
4418 
4419 			/* If something goes wrong, break and return */
4420 			if (status) {
4421 				break;
4422 			}
4423 
4424 			mem_heap_empty(heap);
4425 			chunk_size -= num_to_process;
4426 			num_page = 0;
4427 		}
4428 	}
4429 
4430 	mem_heap_free(heap);
4431 
4432 	DBUG_RETURN(status);
4433 }
4434 
4435 /*******************************************************************//**
4436 Fill page information for pages in InnoDB buffer pool to the
4437 dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
4438 @return 0 on success, 1 on failure */
4439 static
4440 int
i_s_innodb_buffer_page_fill_table(THD * thd,TABLE_LIST * tables,Item *)4441 i_s_innodb_buffer_page_fill_table(
4442 /*==============================*/
4443 	THD*		thd,		/*!< in: thread */
4444 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
4445 	Item*		)		/*!< in: condition (ignored) */
4446 {
4447 	int	status	= 0;
4448 
4449 	DBUG_ENTER("i_s_innodb_buffer_page_fill_table");
4450 
4451 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
4452 
4453 	/* deny access to user without PROCESS privilege */
4454 	if (check_global_access(thd, PROCESS_ACL)) {
4455 		DBUG_RETURN(0);
4456 	}
4457 
4458 	/* Walk through each buffer pool */
4459 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
4460 		buf_pool_t*	buf_pool;
4461 
4462 		buf_pool = buf_pool_from_array(i);
4463 
4464 		/* Fetch information from pages in this buffer pool,
4465 		and fill the corresponding I_S table */
4466 		status = i_s_innodb_fill_buffer_pool(thd, tables, buf_pool, i);
4467 
4468 		/* If something wrong, break and return */
4469 		if (status) {
4470 			break;
4471 		}
4472 	}
4473 
4474 	DBUG_RETURN(status);
4475 }
4476 
4477 /*******************************************************************//**
4478 Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE.
4479 @return 0 on success, 1 on failure */
4480 static
4481 int
i_s_innodb_buffer_page_init(void * p)4482 i_s_innodb_buffer_page_init(
4483 /*========================*/
4484 	void*	p)	/*!< in/out: table schema object */
4485 {
4486 	ST_SCHEMA_TABLE*	schema;
4487 
4488 	DBUG_ENTER("i_s_innodb_buffer_page_init");
4489 
4490 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
4491 
4492 	schema->fields_info = i_s_innodb_buffer_page_fields_info;
4493 	schema->fill_table = i_s_innodb_buffer_page_fill_table;
4494 
4495 	DBUG_RETURN(0);
4496 }
4497 
4498 UNIV_INTERN struct st_maria_plugin	i_s_innodb_buffer_page =
4499 {
4500 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
4501 	/* int */
4502 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
4503 
4504 	/* pointer to type-specific plugin descriptor */
4505 	/* void* */
4506 	&i_s_info,
4507 
4508 	/* plugin name */
4509 	/* const char* */
4510 	"INNODB_BUFFER_PAGE",
4511 
4512 	/* plugin author (for SHOW PLUGINS) */
4513 	/* const char* */
4514 	plugin_author,
4515 
4516 	/* general descriptive text (for SHOW PLUGINS) */
4517 	/* const char* */
4518 	"InnoDB Buffer Page Information",
4519 
4520 	/* the plugin license (PLUGIN_LICENSE_XXX) */
4521 	/* int */
4522 	PLUGIN_LICENSE_GPL,
4523 
4524 	/* the function to invoke when plugin is loaded */
4525 	/* int (*)(void*); */
4526 	i_s_innodb_buffer_page_init,
4527 
4528 	/* the function to invoke when plugin is unloaded */
4529 	/* int (*)(void*); */
4530 	i_s_common_deinit,
4531 
4532 	/* plugin version (for SHOW PLUGINS) */
4533 	/* unsigned int */
4534 	INNODB_VERSION_SHORT,
4535 
4536 	/* struct st_mysql_show_var* */
4537 	NULL,
4538 
4539 	/* struct st_mysql_sys_var** */
4540 	NULL,
4541 
4542         /* Maria extension */
4543 	INNODB_VERSION_STR,
4544         MariaDB_PLUGIN_MATURITY_STABLE,
4545 };
4546 
4547 static ST_FIELD_INFO i_s_innodb_buf_page_lru_fields_info[]=
4548 {
4549 #define IDX_BUF_LRU_POOL_ID		0
4550   {"POOL_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4551    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4552 #define IDX_BUF_LRU_POS			1
4553   {"LRU_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4554    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4555 #define IDX_BUF_LRU_PAGE_SPACE		2
4556   {"SPACE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4557    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4558 #define IDX_BUF_LRU_PAGE_NUM		3
4559   {"PAGE_NUMBER", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4560    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4561 #define IDX_BUF_LRU_PAGE_TYPE		4
4562   {"PAGE_TYPE", 64, MYSQL_TYPE_STRING,
4563    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4564 #define IDX_BUF_LRU_PAGE_FLUSH_TYPE	5
4565   {"FLUSH_TYPE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4566    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4567 #define IDX_BUF_LRU_PAGE_FIX_COUNT	6
4568   {"FIX_COUNT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4569    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4570 #ifdef BTR_CUR_HASH_ADAPT
4571 # define IDX_BUF_LRU_PAGE_HASHED		7
4572   {"IS_HASHED", 3, MYSQL_TYPE_STRING,
4573    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4574 #endif /* BTR_CUR_HASH_ADAPT */
4575 #define IDX_BUF_LRU_PAGE_NEWEST_MOD	7 + I_S_AHI
4576   {"NEWEST_MODIFICATION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4577    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4578 #define IDX_BUF_LRU_PAGE_OLDEST_MOD	8 + I_S_AHI
4579   {"OLDEST_MODIFICATION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4580    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4581 #define IDX_BUF_LRU_PAGE_ACCESS_TIME	9 + I_S_AHI
4582   {"ACCESS_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4583    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4584 #define IDX_BUF_LRU_PAGE_TABLE_NAME	10 + I_S_AHI
4585   {"TABLE_NAME", 1024, MYSQL_TYPE_STRING,
4586    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4587 #define IDX_BUF_LRU_PAGE_INDEX_NAME	11 + I_S_AHI
4588   {"INDEX_NAME", 1024, MYSQL_TYPE_STRING,
4589    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4590 #define IDX_BUF_LRU_PAGE_NUM_RECS	12 + I_S_AHI
4591   {"NUMBER_RECORDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4592    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4593 #define IDX_BUF_LRU_PAGE_DATA_SIZE	13 + I_S_AHI
4594   {"DATA_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4595    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4596 #define IDX_BUF_LRU_PAGE_ZIP_SIZE	14 + I_S_AHI
4597   {"COMPRESSED_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4598    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4599 #define IDX_BUF_LRU_PAGE_STATE		15 + I_S_AHI
4600   {"COMPRESSED", 3, MYSQL_TYPE_STRING,
4601    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4602 #define IDX_BUF_LRU_PAGE_IO_FIX		16 + I_S_AHI
4603   {"IO_FIX", 64, MYSQL_TYPE_STRING,
4604    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4605 #define IDX_BUF_LRU_PAGE_IS_OLD		17 + I_S_AHI
4606   {"IS_OLD", 3, MYSQL_TYPE_STRING,
4607    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
4608 #define IDX_BUF_LRU_PAGE_FREE_CLOCK	18 + I_S_AHI
4609   {"FREE_PAGE_CLOCK", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4610    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4611   END_OF_ST_FIELD_INFO
4612 };
4613 
4614 /*******************************************************************//**
4615 Fill Information Schema table INNODB_BUFFER_PAGE_LRU with information
4616 cached in the buf_page_info_t array
4617 @return 0 on success, 1 on failure */
4618 static
4619 int
i_s_innodb_buf_page_lru_fill(THD * thd,TABLE_LIST * tables,const buf_page_info_t * info_array,ulint num_page)4620 i_s_innodb_buf_page_lru_fill(
4621 /*=========================*/
4622 	THD*			thd,		/*!< in: thread */
4623 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
4624 	const buf_page_info_t*	info_array,	/*!< in: array cached page
4625 						info */
4626 	ulint			num_page)	/*!< in: number of page info
4627 						 cached */
4628 {
4629 	DBUG_ENTER("i_s_innodb_buf_page_lru_fill");
4630 
4631 	TABLE*	table	= tables->table;
4632 	Field**	fields	= table->field;
4633 
4634 	/* Iterate through the cached array and fill the I_S table rows */
4635 	for (ulint i = 0; i < num_page; i++) {
4636 		const buf_page_info_t*	page_info;
4637 		char			table_name[MAX_FULL_NAME_LEN + 1];
4638 		const char*		table_name_end = NULL;
4639 		const char*		state_str;
4640 		enum buf_page_state	state;
4641 
4642 		state_str = NULL;
4643 
4644 		page_info = info_array + i;
4645 
4646 		OK(fields[IDX_BUF_LRU_POOL_ID]->store(
4647 			   page_info->pool_id, true));
4648 
4649 		OK(fields[IDX_BUF_LRU_POS]->store(
4650 			   page_info->block_id, true));
4651 
4652 		OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
4653 			   page_info->space_id, true));
4654 
4655 		OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
4656 			   page_info->page_num, true));
4657 
4658 		OK(field_store_string(
4659 			   fields[IDX_BUF_LRU_PAGE_TYPE],
4660 			   i_s_page_type[page_info->page_type].type_str));
4661 
4662 		OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(
4663 			   page_info->flush_type, true));
4664 
4665 		OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
4666 			   page_info->fix_count, true));
4667 
4668 #ifdef BTR_CUR_HASH_ADAPT
4669 		OK(field_store_string(fields[IDX_BUF_LRU_PAGE_HASHED],
4670 				      page_info->hashed ? "YES" : "NO"));
4671 #endif /* BTR_CUR_HASH_ADAPT */
4672 
4673 		OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
4674 			   page_info->newest_mod, true));
4675 
4676 		OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store(
4677 			   page_info->oldest_mod, true));
4678 
4679 		OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store(
4680 			   page_info->access_time, true));
4681 
4682 		fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_null();
4683 
4684 		fields[IDX_BUF_LRU_PAGE_INDEX_NAME]->set_null();
4685 
4686 		/* If this is an index page, fetch the index name
4687 		and table name */
4688 		if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
4689 			bool ret = false;
4690 
4691 			mutex_enter(&dict_sys->mutex);
4692 
4693 			const dict_index_t* index =
4694 				dict_index_get_if_in_cache_low(
4695 					page_info->index_id);
4696 
4697 			if (index) {
4698 				table_name_end = innobase_convert_name(
4699 					table_name, sizeof(table_name),
4700 					index->table->name.m_name,
4701 					strlen(index->table->name.m_name),
4702 					thd);
4703 
4704 				ret = fields[IDX_BUF_LRU_PAGE_TABLE_NAME]
4705 					->store(table_name,
4706 						static_cast<uint>(
4707 							table_name_end
4708 							- table_name),
4709 						system_charset_info)
4710 					|| fields[IDX_BUF_LRU_PAGE_INDEX_NAME]
4711 					->store(index->name,
4712 						uint(strlen(index->name)),
4713 						system_charset_info);
4714 			}
4715 
4716 			mutex_exit(&dict_sys->mutex);
4717 
4718 			OK(ret);
4719 
4720 			if (index) {
4721 				fields[IDX_BUF_LRU_PAGE_TABLE_NAME]
4722 					->set_notnull();
4723 				fields[IDX_BUF_LRU_PAGE_INDEX_NAME]
4724 					->set_notnull();
4725 			}
4726 		}
4727 
4728 		OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store(
4729 			   page_info->num_recs, true));
4730 
4731 		OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store(
4732 			   page_info->data_size, true));
4733 
4734 		OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store(
4735 			   page_info->zip_ssize
4736 			   ? 512 << page_info->zip_ssize : 0, true));
4737 
4738 		state = static_cast<enum buf_page_state>(page_info->page_state);
4739 
4740 		switch (state) {
4741 		/* Compressed page */
4742 		case BUF_BLOCK_ZIP_PAGE:
4743 		case BUF_BLOCK_ZIP_DIRTY:
4744 			state_str = "YES";
4745 			break;
4746 		/* Uncompressed page */
4747 		case BUF_BLOCK_FILE_PAGE:
4748 			state_str = "NO";
4749 			break;
4750 		/* We should not see following states */
4751 		case BUF_BLOCK_POOL_WATCH:
4752 		case BUF_BLOCK_READY_FOR_USE:
4753 		case BUF_BLOCK_NOT_USED:
4754 		case BUF_BLOCK_MEMORY:
4755 		case BUF_BLOCK_REMOVE_HASH:
4756 			state_str = NULL;
4757 			break;
4758 		};
4759 
4760 		OK(field_store_string(fields[IDX_BUF_LRU_PAGE_STATE],
4761 				      state_str));
4762 
4763 		switch (page_info->io_fix) {
4764 		case BUF_IO_NONE:
4765 			state_str = "IO_NONE";
4766 			break;
4767 		case BUF_IO_READ:
4768 			state_str = "IO_READ";
4769 			break;
4770 		case BUF_IO_WRITE:
4771 			state_str = "IO_WRITE";
4772 			break;
4773 		case BUF_IO_PIN:
4774 			state_str = "IO_PIN";
4775 			break;
4776 		}
4777 
4778 		OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX],
4779 				      state_str));
4780 
4781 		OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IS_OLD],
4782 				      page_info->is_old ? "YES" : "NO"));
4783 
4784 		OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store(
4785 			   page_info->freed_page_clock, true));
4786 
4787 		OK(schema_table_store_record(thd, table));
4788 	}
4789 
4790 	DBUG_RETURN(0);
4791 }
4792 
4793 /*******************************************************************//**
4794 This is the function that goes through buffer pool's LRU list
4795 and fetch information to INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
4796 @return 0 on success, 1 on failure */
4797 static
4798 int
i_s_innodb_fill_buffer_lru(THD * thd,TABLE_LIST * tables,buf_pool_t * buf_pool,const ulint pool_id)4799 i_s_innodb_fill_buffer_lru(
4800 /*=======================*/
4801 	THD*			thd,		/*!< in: thread */
4802 	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
4803 	buf_pool_t*		buf_pool,	/*!< in: buffer pool to scan */
4804 	const ulint		pool_id)	/*!< in: buffer pool id */
4805 {
4806 	int			status = 0;
4807 	buf_page_info_t*	info_buffer;
4808 	ulint			lru_pos = 0;
4809 	const buf_page_t*	bpage;
4810 	ulint			lru_len;
4811 
4812 	DBUG_ENTER("i_s_innodb_fill_buffer_lru");
4813 
4814 	/* Obtain buf_pool mutex before allocate info_buffer, since
4815 	UT_LIST_GET_LEN(buf_pool->LRU) could change */
4816 	buf_pool_mutex_enter(buf_pool);
4817 
4818 	lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
4819 
4820 	/* Print error message if malloc fail */
4821 	info_buffer = (buf_page_info_t*) my_malloc(
4822 		lru_len * sizeof *info_buffer, MYF(MY_WME));
4823 	/* JAN: TODO: MySQL 5.7 PSI
4824 	info_buffer = (buf_page_info_t*) my_malloc(PSI_INSTRUMENT_ME,
4825 		lru_len * sizeof *info_buffer, MYF(MY_WME));
4826 	*/
4827 
4828 	if (!info_buffer) {
4829 		status = 1;
4830 		goto exit;
4831 	}
4832 
4833 	memset(info_buffer, 0, lru_len * sizeof *info_buffer);
4834 
4835 	/* Walk through Pool's LRU list and print the buffer page
4836 	information */
4837 	bpage = UT_LIST_GET_LAST(buf_pool->LRU);
4838 
4839 	while (bpage != NULL) {
4840 		/* Use the same function that collect buffer info for
4841 		INNODB_BUFFER_PAGE to get buffer page info */
4842 		i_s_innodb_buffer_page_get_info(bpage, pool_id, lru_pos,
4843 						(info_buffer + lru_pos));
4844 
4845 		bpage = UT_LIST_GET_PREV(LRU, bpage);
4846 
4847 		lru_pos++;
4848 	}
4849 
4850 	ut_ad(lru_pos == lru_len);
4851 	ut_ad(lru_pos == UT_LIST_GET_LEN(buf_pool->LRU));
4852 
4853 exit:
4854 	buf_pool_mutex_exit(buf_pool);
4855 
4856 	if (info_buffer) {
4857 		status = i_s_innodb_buf_page_lru_fill(
4858 			thd, tables, info_buffer, lru_len);
4859 
4860 		my_free(info_buffer);
4861 	}
4862 
4863 	DBUG_RETURN(status);
4864 }
4865 
4866 /*******************************************************************//**
4867 Fill page information for pages in InnoDB buffer pool to the
4868 dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU
4869 @return 0 on success, 1 on failure */
4870 static
4871 int
i_s_innodb_buf_page_lru_fill_table(THD * thd,TABLE_LIST * tables,Item *)4872 i_s_innodb_buf_page_lru_fill_table(
4873 /*===============================*/
4874 	THD*		thd,		/*!< in: thread */
4875 	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
4876 	Item*		)		/*!< in: condition (ignored) */
4877 {
4878 	int	status	= 0;
4879 
4880 	DBUG_ENTER("i_s_innodb_buf_page_lru_fill_table");
4881 
4882 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
4883 
4884 	/* deny access to any users that do not hold PROCESS_ACL */
4885 	if (check_global_access(thd, PROCESS_ACL)) {
4886 		DBUG_RETURN(0);
4887 	}
4888 
4889 	/* Walk through each buffer pool */
4890 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
4891 		buf_pool_t*	buf_pool;
4892 
4893 		buf_pool = buf_pool_from_array(i);
4894 
4895 		/* Fetch information from pages in this buffer pool's LRU list,
4896 		and fill the corresponding I_S table */
4897 		status = i_s_innodb_fill_buffer_lru(thd, tables, buf_pool, i);
4898 
4899 		/* If something wrong, break and return */
4900 		if (status) {
4901 			break;
4902 		}
4903 	}
4904 
4905 	DBUG_RETURN(status);
4906 }
4907 
4908 /*******************************************************************//**
4909 Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
4910 @return 0 on success, 1 on failure */
4911 static
4912 int
i_s_innodb_buffer_page_lru_init(void * p)4913 i_s_innodb_buffer_page_lru_init(
4914 /*============================*/
4915 	void*	p)	/*!< in/out: table schema object */
4916 {
4917 	ST_SCHEMA_TABLE*	schema;
4918 
4919 	DBUG_ENTER("i_s_innodb_buffer_page_lru_init");
4920 
4921 	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
4922 
4923 	schema->fields_info = i_s_innodb_buf_page_lru_fields_info;
4924 	schema->fill_table = i_s_innodb_buf_page_lru_fill_table;
4925 
4926 	DBUG_RETURN(0);
4927 }
4928 
4929 UNIV_INTERN struct st_maria_plugin	i_s_innodb_buffer_page_lru =
4930 {
4931 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
4932 	/* int */
4933 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
4934 
4935 	/* pointer to type-specific plugin descriptor */
4936 	/* void* */
4937 	&i_s_info,
4938 
4939 	/* plugin name */
4940 	/* const char* */
4941 	"INNODB_BUFFER_PAGE_LRU",
4942 
4943 	/* plugin author (for SHOW PLUGINS) */
4944 	/* const char* */
4945 	plugin_author,
4946 
4947 	/* general descriptive text (for SHOW PLUGINS) */
4948 	/* const char* */
4949 	"InnoDB Buffer Page in LRU",
4950 
4951 	/* the plugin license (PLUGIN_LICENSE_XXX) */
4952 	/* int */
4953 	PLUGIN_LICENSE_GPL,
4954 
4955 	/* the function to invoke when plugin is loaded */
4956 	/* int (*)(void*); */
4957 	i_s_innodb_buffer_page_lru_init,
4958 
4959 	/* the function to invoke when plugin is unloaded */
4960 	/* int (*)(void*); */
4961 	i_s_common_deinit,
4962 
4963 	/* plugin version (for SHOW PLUGINS) */
4964 	/* unsigned int */
4965 	INNODB_VERSION_SHORT,
4966 
4967 	/* struct st_mysql_show_var* */
4968 	NULL,
4969 
4970 	/* struct st_mysql_sys_var** */
4971 	NULL,
4972 
4973         /* Maria extension */
4974 	INNODB_VERSION_STR,
4975         MariaDB_PLUGIN_MATURITY_STABLE,
4976 };
4977 
4978 /*******************************************************************//**
4979 Unbind a dynamic INFORMATION_SCHEMA table.
4980 @return 0 */
i_s_common_deinit(void *)4981 static int i_s_common_deinit(void*)
4982 {
4983 	DBUG_ENTER("i_s_common_deinit");
4984 
4985 	/* Do nothing */
4986 
4987 	DBUG_RETURN(0);
4988 }
4989 
4990 /**  SYS_TABLES  ***************************************************/
4991 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
4992 static ST_FIELD_INFO innodb_sys_tables_fields_info[]=
4993 {
4994 #define SYS_TABLES_ID			0
4995   {"TABLE_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
4996    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
4997 #define SYS_TABLES_NAME			1
4998   {"NAME", MAX_FULL_NAME_LEN + 1, MYSQL_TYPE_STRING,
4999    0, 0, "", SKIP_OPEN_TABLE},
5000 #define SYS_TABLES_FLAG			2
5001   {"FLAG", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5002    0, 0, "", SKIP_OPEN_TABLE},
5003 #define SYS_TABLES_NUM_COLUMN		3
5004   {"N_COLS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5005    0, 0, "", SKIP_OPEN_TABLE},
5006 #define SYS_TABLES_SPACE		4
5007   {"SPACE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5008    0, 0, "", SKIP_OPEN_TABLE},
5009 #define SYS_TABLES_ROW_FORMAT		5
5010   {"ROW_FORMAT", 12, MYSQL_TYPE_STRING,
5011    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
5012 #define SYS_TABLES_ZIP_PAGE_SIZE	6
5013   {"ZIP_PAGE_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5014    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5015 #define SYS_TABLES_SPACE_TYPE	7
5016   {"SPACE_TYPE", 10, MYSQL_TYPE_STRING,
5017    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
5018   END_OF_ST_FIELD_INFO
5019 };
5020 
5021 /**********************************************************************//**
5022 Populate information_schema.innodb_sys_tables table with information
5023 from SYS_TABLES.
5024 @return 0 on success */
5025 static
5026 int
i_s_dict_fill_sys_tables(THD * thd,dict_table_t * table,TABLE * table_to_fill)5027 i_s_dict_fill_sys_tables(
5028 /*=====================*/
5029 	THD*		thd,		/*!< in: thread */
5030 	dict_table_t*	table,		/*!< in: table */
5031 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
5032 {
5033 	Field**			fields;
5034 	ulint			compact = DICT_TF_GET_COMPACT(table->flags);
5035 	ulint			atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(
5036 								table->flags);
5037 	const page_size_t&	page_size = dict_tf_get_page_size(table->flags);
5038 	const char*		row_format;
5039 
5040 	if (!compact) {
5041 		row_format = "Redundant";
5042 	} else if (!atomic_blobs) {
5043 		row_format = "Compact";
5044 	} else if (DICT_TF_GET_ZIP_SSIZE(table->flags)) {
5045 		row_format = "Compressed";
5046 	} else {
5047 		row_format = "Dynamic";
5048 	}
5049 
5050 	DBUG_ENTER("i_s_dict_fill_sys_tables");
5051 
5052 	fields = table_to_fill->field;
5053 
5054 	OK(fields[SYS_TABLES_ID]->store(longlong(table->id), TRUE));
5055 
5056 	OK(field_store_string(fields[SYS_TABLES_NAME], table->name.m_name));
5057 
5058 	OK(fields[SYS_TABLES_FLAG]->store(table->flags));
5059 
5060 	OK(fields[SYS_TABLES_NUM_COLUMN]->store(table->n_cols));
5061 
5062 	OK(fields[SYS_TABLES_SPACE]->store(table->space_id, true));
5063 
5064 	OK(field_store_string(fields[SYS_TABLES_ROW_FORMAT], row_format));
5065 
5066 	OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(
5067 				page_size.is_compressed()
5068 				? page_size.physical()
5069 				: 0, true));
5070 
5071 	OK(field_store_string(fields[SYS_TABLES_SPACE_TYPE],
5072 			      table->space_id ? "Single" : "System"));
5073 
5074 	OK(schema_table_store_record(thd, table_to_fill));
5075 
5076 	DBUG_RETURN(0);
5077 }
5078 /*******************************************************************//**
5079 Function to go through each record in SYS_TABLES table, and fill the
5080 information_schema.innodb_sys_tables table with related table information
5081 @return 0 on success */
5082 static
5083 int
i_s_sys_tables_fill_table(THD * thd,TABLE_LIST * tables,Item *)5084 i_s_sys_tables_fill_table(
5085 /*======================*/
5086 	THD*		thd,	/*!< in: thread */
5087 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
5088 	Item*		)	/*!< in: condition (not used) */
5089 {
5090 	btr_pcur_t	pcur;
5091 	const rec_t*	rec;
5092 	mem_heap_t*	heap;
5093 	mtr_t		mtr;
5094 
5095 	DBUG_ENTER("i_s_sys_tables_fill_table");
5096 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5097 
5098 	/* deny access to user without PROCESS_ACL privilege */
5099 	if (check_global_access(thd, PROCESS_ACL)) {
5100 		DBUG_RETURN(0);
5101 	}
5102 
5103 	heap = mem_heap_create(1000);
5104 	mutex_enter(&dict_sys->mutex);
5105 	mtr_start(&mtr);
5106 
5107 	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
5108 
5109 	while (rec) {
5110 		const char*	err_msg;
5111 		dict_table_t*	table_rec;
5112 
5113 		/* Create and populate a dict_table_t structure with
5114 		information from SYS_TABLES row */
5115 		err_msg = dict_process_sys_tables_rec_and_mtr_commit(
5116 			heap, rec, &table_rec, false, &mtr);
5117 
5118 		mutex_exit(&dict_sys->mutex);
5119 
5120 		if (!err_msg) {
5121 			i_s_dict_fill_sys_tables(thd, table_rec,
5122 						 tables->table);
5123 		} else {
5124 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5125 					    ER_CANT_FIND_SYSTEM_REC, "%s",
5126 					    err_msg);
5127 		}
5128 
5129 		if (table_rec) {
5130 			dict_mem_table_free(table_rec);
5131 		}
5132 
5133 		mem_heap_empty(heap);
5134 
5135 		/* Get the next record */
5136 		mutex_enter(&dict_sys->mutex);
5137 		mtr_start(&mtr);
5138 		rec = dict_getnext_system(&pcur, &mtr);
5139 	}
5140 
5141 	mtr_commit(&mtr);
5142 	mutex_exit(&dict_sys->mutex);
5143 	mem_heap_free(heap);
5144 
5145 	DBUG_RETURN(0);
5146 }
5147 
5148 /*******************************************************************//**
5149 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tables
5150 @return 0 on success */
5151 static
5152 int
innodb_sys_tables_init(void * p)5153 innodb_sys_tables_init(
5154 /*===================*/
5155 	void*	p)	/*!< in/out: table schema object */
5156 {
5157 	ST_SCHEMA_TABLE*	schema;
5158 
5159 	DBUG_ENTER("innodb_sys_tables_init");
5160 
5161 	schema = (ST_SCHEMA_TABLE*) p;
5162 
5163 	schema->fields_info = innodb_sys_tables_fields_info;
5164 	schema->fill_table = i_s_sys_tables_fill_table;
5165 
5166 	DBUG_RETURN(0);
5167 }
5168 
5169 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_tables =
5170 {
5171 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
5172 	/* int */
5173 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
5174 
5175 	/* pointer to type-specific plugin descriptor */
5176 	/* void* */
5177 	&i_s_info,
5178 
5179 	/* plugin name */
5180 	/* const char* */
5181 	"INNODB_SYS_TABLES",
5182 
5183 	/* plugin author (for SHOW PLUGINS) */
5184 	/* const char* */
5185 	plugin_author,
5186 
5187 	/* general descriptive text (for SHOW PLUGINS) */
5188 	/* const char* */
5189 	"InnoDB SYS_TABLES",
5190 
5191 	/* the plugin license (PLUGIN_LICENSE_XXX) */
5192 	/* int */
5193 	PLUGIN_LICENSE_GPL,
5194 
5195 	/* the function to invoke when plugin is loaded */
5196 	/* int (*)(void*); */
5197 	innodb_sys_tables_init,
5198 
5199 	/* the function to invoke when plugin is unloaded */
5200 	/* int (*)(void*); */
5201 	i_s_common_deinit,
5202 
5203 	/* plugin version (for SHOW PLUGINS) */
5204 	/* unsigned int */
5205 	INNODB_VERSION_SHORT,
5206 
5207 	/* struct st_mysql_show_var* */
5208 	NULL,
5209 
5210 	/* struct st_mysql_sys_var** */
5211 	NULL,
5212 
5213         /* Maria extension */
5214 	INNODB_VERSION_STR,
5215         MariaDB_PLUGIN_MATURITY_STABLE,
5216 };
5217 
5218 /**  SYS_TABLESTATS  ***********************************************/
5219 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
5220 static ST_FIELD_INFO innodb_sys_tablestats_fields_info[]=
5221 {
5222 #define SYS_TABLESTATS_ID		0
5223   {"TABLE_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5224    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5225 #define SYS_TABLESTATS_NAME		1
5226   {"NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
5227    0, 0, "", SKIP_OPEN_TABLE},
5228 #define SYS_TABLESTATS_INIT		2
5229   {"STATS_INITIALIZED", NAME_LEN + 1, MYSQL_TYPE_STRING,
5230    0, 0, "", SKIP_OPEN_TABLE},
5231 #define SYS_TABLESTATS_NROW		3
5232   {"NUM_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5233    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5234 #define SYS_TABLESTATS_CLUST_SIZE	4
5235   {"CLUST_INDEX_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5236    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5237 #define SYS_TABLESTATS_INDEX_SIZE	5
5238   {"OTHER_INDEX_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5239    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5240 #define SYS_TABLESTATS_MODIFIED		6
5241   {"MODIFIED_COUNTER", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5242    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5243 #define SYS_TABLESTATS_AUTONINC		7
5244   {"AUTOINC", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5245    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5246 #define SYS_TABLESTATS_TABLE_REF_COUNT	8
5247   {"REF_COUNT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5248    0, 0, "", SKIP_OPEN_TABLE},
5249 
5250   END_OF_ST_FIELD_INFO
5251 };
5252 
5253 /** Populate information_schema.innodb_sys_tablestats table with information
5254 from SYS_TABLES.
5255 @param[in]	thd		thread ID
5256 @param[in,out]	table		table
5257 @param[in]	ref_count	table reference count
5258 @param[in,out]	table_to_fill	fill this table
5259 @return 0 on success */
5260 static
5261 int
i_s_dict_fill_sys_tablestats(THD * thd,dict_table_t * table,ulint ref_count,TABLE * table_to_fill)5262 i_s_dict_fill_sys_tablestats(
5263 	THD*		thd,
5264 	dict_table_t*	table,
5265 	ulint		ref_count,
5266 	TABLE*		table_to_fill)
5267 {
5268 	Field**		fields;
5269 
5270 	DBUG_ENTER("i_s_dict_fill_sys_tablestats");
5271 
5272 	fields = table_to_fill->field;
5273 
5274 	OK(fields[SYS_TABLESTATS_ID]->store(longlong(table->id), TRUE));
5275 
5276 	OK(field_store_string(fields[SYS_TABLESTATS_NAME],
5277 			      table->name.m_name));
5278 
5279 	{
5280 		struct Locking
5281 		{
5282 			Locking() { mutex_enter(&dict_sys->mutex); }
5283 			~Locking() { mutex_exit(&dict_sys->mutex); }
5284 		} locking;
5285 
5286 		if (table->stat_initialized) {
5287 			OK(field_store_string(fields[SYS_TABLESTATS_INIT],
5288 					      "Initialized"));
5289 
5290 			OK(fields[SYS_TABLESTATS_NROW]->store(
5291 				   table->stat_n_rows, true));
5292 
5293 			OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
5294 				   table->stat_clustered_index_size, true));
5295 
5296 			OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
5297 				   table->stat_sum_of_other_index_sizes,
5298 				   true));
5299 
5300 			OK(fields[SYS_TABLESTATS_MODIFIED]->store(
5301 				   table->stat_modified_counter, true));
5302 		} else {
5303 			OK(field_store_string(fields[SYS_TABLESTATS_INIT],
5304 					      "Uninitialized"));
5305 
5306 			OK(fields[SYS_TABLESTATS_NROW]->store(0, true));
5307 
5308 			OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true));
5309 
5310 			OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true));
5311 
5312 			OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true));
5313 		}
5314 	}
5315 
5316 	OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true));
5317 
5318 	OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(ref_count, true));
5319 
5320 	OK(schema_table_store_record(thd, table_to_fill));
5321 
5322 	DBUG_RETURN(0);
5323 }
5324 
5325 /*******************************************************************//**
5326 Function to go through each record in SYS_TABLES table, and fill the
5327 information_schema.innodb_sys_tablestats table with table statistics
5328 related information
5329 @return 0 on success */
5330 static
5331 int
i_s_sys_tables_fill_table_stats(THD * thd,TABLE_LIST * tables,Item *)5332 i_s_sys_tables_fill_table_stats(
5333 /*============================*/
5334 	THD*		thd,	/*!< in: thread */
5335 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
5336 	Item*		)	/*!< in: condition (not used) */
5337 {
5338 	btr_pcur_t	pcur;
5339 	const rec_t*	rec;
5340 	mem_heap_t*	heap;
5341 	mtr_t		mtr;
5342 
5343 	DBUG_ENTER("i_s_sys_tables_fill_table_stats");
5344 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5345 
5346 	/* deny access to user without PROCESS_ACL privilege */
5347 	if (check_global_access(thd, PROCESS_ACL)) {
5348 		DBUG_RETURN(0);
5349 	}
5350 
5351 	heap = mem_heap_create(1000);
5352 	rw_lock_s_lock(&dict_operation_lock);
5353 	mutex_enter(&dict_sys->mutex);
5354 	mtr_start(&mtr);
5355 
5356 	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
5357 
5358 	while (rec) {
5359 		const char*	err_msg;
5360 		dict_table_t*	table_rec;
5361 
5362 		/* Fetch the dict_table_t structure corresponding to
5363 		this SYS_TABLES record */
5364 		err_msg = dict_process_sys_tables_rec_and_mtr_commit(
5365 			heap, rec, &table_rec, true, &mtr);
5366 
5367 		ulint ref_count = table_rec ? table_rec->get_ref_count() : 0;
5368 		mutex_exit(&dict_sys->mutex);
5369 
5370 		DBUG_EXECUTE_IF("test_sys_tablestats", {
5371 			if (strcmp("test/t1", table_rec->name.m_name) == 0 ) {
5372 				DEBUG_SYNC_C("dict_table_not_protected");
5373 			}});
5374 
5375 		if (table_rec != NULL) {
5376 			ut_ad(err_msg == NULL);
5377 			i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count,
5378 						     tables->table);
5379 		} else {
5380 			ut_ad(err_msg != NULL);
5381 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5382 					    ER_CANT_FIND_SYSTEM_REC, "%s",
5383 					    err_msg);
5384 		}
5385 
5386 		rw_lock_s_unlock(&dict_operation_lock);
5387 		mem_heap_empty(heap);
5388 
5389 		/* Get the next record */
5390 		rw_lock_s_lock(&dict_operation_lock);
5391 		mutex_enter(&dict_sys->mutex);
5392 
5393 		mtr_start(&mtr);
5394 		rec = dict_getnext_system(&pcur, &mtr);
5395 	}
5396 
5397 	mtr_commit(&mtr);
5398 	mutex_exit(&dict_sys->mutex);
5399 	rw_lock_s_unlock(&dict_operation_lock);
5400 	mem_heap_free(heap);
5401 
5402 	DBUG_RETURN(0);
5403 }
5404 
5405 /*******************************************************************//**
5406 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tablestats
5407 @return 0 on success */
5408 static
5409 int
innodb_sys_tablestats_init(void * p)5410 innodb_sys_tablestats_init(
5411 /*=======================*/
5412 	void*	p)	/*!< in/out: table schema object */
5413 {
5414 	ST_SCHEMA_TABLE*	schema;
5415 
5416 	DBUG_ENTER("innodb_sys_tablestats_init");
5417 
5418 	schema = (ST_SCHEMA_TABLE*) p;
5419 
5420 	schema->fields_info = innodb_sys_tablestats_fields_info;
5421 	schema->fill_table = i_s_sys_tables_fill_table_stats;
5422 
5423 	DBUG_RETURN(0);
5424 }
5425 
5426 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_tablestats =
5427 {
5428 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
5429 	/* int */
5430 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
5431 
5432 	/* pointer to type-specific plugin descriptor */
5433 	/* void* */
5434 	&i_s_info,
5435 
5436 	/* plugin name */
5437 	/* const char* */
5438 	"INNODB_SYS_TABLESTATS",
5439 
5440 	/* plugin author (for SHOW PLUGINS) */
5441 	/* const char* */
5442 	plugin_author,
5443 
5444 	/* general descriptive text (for SHOW PLUGINS) */
5445 	/* const char* */
5446 	"InnoDB SYS_TABLESTATS",
5447 
5448 	/* the plugin license (PLUGIN_LICENSE_XXX) */
5449 	/* int */
5450 	PLUGIN_LICENSE_GPL,
5451 
5452 	/* the function to invoke when plugin is loaded */
5453 	/* int (*)(void*); */
5454 	innodb_sys_tablestats_init,
5455 
5456 	/* the function to invoke when plugin is unloaded */
5457 	/* int (*)(void*); */
5458 	i_s_common_deinit,
5459 
5460 	/* plugin version (for SHOW PLUGINS) */
5461 	/* unsigned int */
5462 	INNODB_VERSION_SHORT,
5463 
5464 	/* struct st_mysql_show_var* */
5465 	NULL,
5466 
5467 	/* struct st_mysql_sys_var** */
5468 	NULL,
5469 
5470         /* Maria extension */
5471 	INNODB_VERSION_STR,
5472         MariaDB_PLUGIN_MATURITY_STABLE,
5473 };
5474 
5475 /**  SYS_INDEXES  **************************************************/
5476 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
5477 static ST_FIELD_INFO innodb_sysindex_fields_info[]=
5478 {
5479 #define SYS_INDEX_ID		0
5480   {"INDEX_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5481    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5482 #define SYS_INDEX_NAME		1
5483   {"NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
5484    0, 0, "", SKIP_OPEN_TABLE},
5485 #define SYS_INDEX_TABLE_ID	2
5486   {"TABLE_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5487    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5488 #define SYS_INDEX_TYPE		3
5489   {"TYPE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5490    0, 0, "", SKIP_OPEN_TABLE},
5491 #define SYS_INDEX_NUM_FIELDS	4
5492   {"N_FIELDS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5493    0, 0, "", SKIP_OPEN_TABLE},
5494 #define SYS_INDEX_PAGE_NO	5
5495   {"PAGE_NO", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5496    0, 0, "", SKIP_OPEN_TABLE},
5497 #define SYS_INDEX_SPACE		6
5498   {"SPACE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5499    0, 0, "", SKIP_OPEN_TABLE},
5500 #define SYS_INDEX_MERGE_THRESHOLD 7
5501   {"MERGE_THRESHOLD", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5502    0, 0, "", SKIP_OPEN_TABLE},
5503   END_OF_ST_FIELD_INFO
5504 };
5505 
5506 /**********************************************************************//**
5507 Function to populate the information_schema.innodb_sys_indexes table with
5508 collected index information
5509 @return 0 on success */
5510 static
5511 int
i_s_dict_fill_sys_indexes(THD * thd,table_id_t table_id,ulint space_id,dict_index_t * index,TABLE * table_to_fill)5512 i_s_dict_fill_sys_indexes(
5513 /*======================*/
5514 	THD*		thd,		/*!< in: thread */
5515 	table_id_t	table_id,	/*!< in: table id */
5516 	ulint		space_id,	/*!< in: tablespace id */
5517 	dict_index_t*	index,		/*!< in: populated dict_index_t
5518 					struct with index info */
5519 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
5520 {
5521 	Field**		fields;
5522 
5523 	DBUG_ENTER("i_s_dict_fill_sys_indexes");
5524 
5525 	fields = table_to_fill->field;
5526 
5527 	if (*index->name == *TEMP_INDEX_PREFIX_STR) {
5528 		/* Since TEMP_INDEX_PREFIX_STR is not valid UTF-8, we
5529 		need to convert it to something else. */
5530 		*const_cast<char*>(index->name()) = '?';
5531 	}
5532 
5533 	OK(fields[SYS_INDEX_NAME]->store(index->name,
5534 					 uint(strlen(index->name)),
5535 					 system_charset_info));
5536 
5537 	OK(fields[SYS_INDEX_ID]->store(longlong(index->id), true));
5538 
5539 	OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), true));
5540 
5541 	OK(fields[SYS_INDEX_TYPE]->store(index->type, true));
5542 
5543 	OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields));
5544 
5545 	/* FIL_NULL is ULINT32_UNDEFINED */
5546 	if (index->page == FIL_NULL) {
5547 		fields[SYS_INDEX_PAGE_NO]->set_null();
5548 	} else {
5549 		OK(fields[SYS_INDEX_PAGE_NO]->store(index->page, true));
5550 	}
5551 
5552 	if (space_id == ULINT_UNDEFINED) {
5553 		fields[SYS_INDEX_SPACE]->set_null();
5554 	} else {
5555 		OK(fields[SYS_INDEX_SPACE]->store(space_id, true));
5556 	}
5557 
5558 	OK(fields[SYS_INDEX_MERGE_THRESHOLD]->store(index->merge_threshold,
5559 						    true));
5560 
5561 	OK(schema_table_store_record(thd, table_to_fill));
5562 
5563 	DBUG_RETURN(0);
5564 }
5565 /*******************************************************************//**
5566 Function to go through each record in SYS_INDEXES table, and fill the
5567 information_schema.innodb_sys_indexes table with related index information
5568 @return 0 on success */
5569 static
5570 int
i_s_sys_indexes_fill_table(THD * thd,TABLE_LIST * tables,Item *)5571 i_s_sys_indexes_fill_table(
5572 /*=======================*/
5573 	THD*		thd,	/*!< in: thread */
5574 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
5575 	Item*		)	/*!< in: condition (not used) */
5576 {
5577 	btr_pcur_t		pcur;
5578 	const rec_t*		rec;
5579 	mem_heap_t*		heap;
5580 	mtr_t			mtr;
5581 
5582 	DBUG_ENTER("i_s_sys_indexes_fill_table");
5583 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5584 
5585 	/* deny access to user without PROCESS_ACL privilege */
5586 	if (check_global_access(thd, PROCESS_ACL)) {
5587 		DBUG_RETURN(0);
5588 	}
5589 
5590 	heap = mem_heap_create(1000);
5591 	mutex_enter(&dict_sys->mutex);
5592 	mtr_start(&mtr);
5593 
5594 	/* Start scan the SYS_INDEXES table */
5595 	rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
5596 
5597 	/* Process each record in the table */
5598 	while (rec) {
5599 		const char*	err_msg;
5600 		table_id_t	table_id;
5601 		ulint		space_id;
5602 		dict_index_t	index_rec;
5603 
5604 		/* Populate a dict_index_t structure with information from
5605 		a SYS_INDEXES row */
5606 		err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec,
5607 						       &table_id);
5608 		const byte* field = rec_get_nth_field_old(
5609 			rec, DICT_FLD__SYS_INDEXES__SPACE, &space_id);
5610 		space_id = space_id == 4 ? mach_read_from_4(field)
5611 			: ULINT_UNDEFINED;
5612 		mtr_commit(&mtr);
5613 		mutex_exit(&dict_sys->mutex);
5614 
5615 		if (!err_msg) {
5616 			if (int err = i_s_dict_fill_sys_indexes(
5617 				    thd, table_id, space_id, &index_rec,
5618 				    tables->table)) {
5619 				mem_heap_free(heap);
5620 				DBUG_RETURN(err);
5621 			}
5622 		} else {
5623 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5624 					    ER_CANT_FIND_SYSTEM_REC, "%s",
5625 					    err_msg);
5626 		}
5627 
5628 		mem_heap_empty(heap);
5629 
5630 		/* Get the next record */
5631 		mutex_enter(&dict_sys->mutex);
5632 		mtr_start(&mtr);
5633 		rec = dict_getnext_system(&pcur, &mtr);
5634 	}
5635 
5636 	mtr_commit(&mtr);
5637 	mutex_exit(&dict_sys->mutex);
5638 	mem_heap_free(heap);
5639 
5640 	DBUG_RETURN(0);
5641 }
5642 /*******************************************************************//**
5643 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_indexes
5644 @return 0 on success */
5645 static
5646 int
innodb_sys_indexes_init(void * p)5647 innodb_sys_indexes_init(
5648 /*====================*/
5649 	void*	p)	/*!< in/out: table schema object */
5650 {
5651 	ST_SCHEMA_TABLE*	schema;
5652 
5653 	DBUG_ENTER("innodb_sys_indexes_init");
5654 
5655 	schema = (ST_SCHEMA_TABLE*) p;
5656 
5657 	schema->fields_info = innodb_sysindex_fields_info;
5658 	schema->fill_table = i_s_sys_indexes_fill_table;
5659 
5660 	DBUG_RETURN(0);
5661 }
5662 
5663 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_indexes =
5664 {
5665 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
5666 	/* int */
5667 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
5668 
5669 	/* pointer to type-specific plugin descriptor */
5670 	/* void* */
5671 	&i_s_info,
5672 
5673 	/* plugin name */
5674 	/* const char* */
5675 	"INNODB_SYS_INDEXES",
5676 
5677 	/* plugin author (for SHOW PLUGINS) */
5678 	/* const char* */
5679 	plugin_author,
5680 
5681 	/* general descriptive text (for SHOW PLUGINS) */
5682 	/* const char* */
5683 	"InnoDB SYS_INDEXES",
5684 
5685 	/* the plugin license (PLUGIN_LICENSE_XXX) */
5686 	/* int */
5687 	PLUGIN_LICENSE_GPL,
5688 
5689 	/* the function to invoke when plugin is loaded */
5690 	/* int (*)(void*); */
5691 	innodb_sys_indexes_init,
5692 
5693 	/* the function to invoke when plugin is unloaded */
5694 	/* int (*)(void*); */
5695 	i_s_common_deinit,
5696 
5697 	/* plugin version (for SHOW PLUGINS) */
5698 	/* unsigned int */
5699 	INNODB_VERSION_SHORT,
5700 
5701 	/* struct st_mysql_show_var* */
5702 	NULL,
5703 
5704 	/* struct st_mysql_sys_var** */
5705 	NULL,
5706 
5707         /* Maria extension */
5708 	INNODB_VERSION_STR,
5709         MariaDB_PLUGIN_MATURITY_STABLE,
5710 };
5711 
5712 /**  SYS_COLUMNS  **************************************************/
5713 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_COLUMNS */
5714 static ST_FIELD_INFO innodb_sys_columns_fields_info[]=
5715 {
5716 #define SYS_COLUMN_TABLE_ID		0
5717   {"TABLE_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5718    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5719 #define SYS_COLUMN_NAME		1
5720   {"NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
5721    0, 0, "", SKIP_OPEN_TABLE},
5722 #define SYS_COLUMN_POSITION	2
5723   {"POS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5724    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5725 #define SYS_COLUMN_MTYPE		3
5726   {"MTYPE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5727    0, 0, "", SKIP_OPEN_TABLE},
5728 #define SYS_COLUMN__PRTYPE	4
5729   {"PRTYPE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5730    0, 0, "", SKIP_OPEN_TABLE},
5731 #define SYS_COLUMN_COLUMN_LEN	5
5732   {"LEN", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5733    0, 0, "", SKIP_OPEN_TABLE},
5734   END_OF_ST_FIELD_INFO
5735 };
5736 
5737 /**********************************************************************//**
5738 Function to populate the information_schema.innodb_sys_columns with
5739 related column information
5740 @return 0 on success */
5741 static
5742 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)5743 i_s_dict_fill_sys_columns(
5744 /*======================*/
5745 	THD*		thd,		/*!< in: thread */
5746 	table_id_t	table_id,	/*!< in: table ID */
5747 	const char*	col_name,	/*!< in: column name */
5748 	dict_col_t*	column,		/*!< in: dict_col_t struct holding
5749 					more column information */
5750 	ulint		nth_v_col,	/*!< in: virtual column, its
5751 					sequence number (nth virtual col) */
5752 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
5753 {
5754 	Field**		fields;
5755 
5756 	DBUG_ENTER("i_s_dict_fill_sys_columns");
5757 
5758 	fields = table_to_fill->field;
5759 
5760 	OK(fields[SYS_COLUMN_TABLE_ID]->store((longlong) table_id, TRUE));
5761 
5762 	OK(field_store_string(fields[SYS_COLUMN_NAME], col_name));
5763 
5764 	if (column->is_virtual()) {
5765 		ulint	pos = dict_create_v_col_pos(nth_v_col, column->ind);
5766 		OK(fields[SYS_COLUMN_POSITION]->store(pos, true));
5767 	} else {
5768 		OK(fields[SYS_COLUMN_POSITION]->store(column->ind, true));
5769 	}
5770 
5771 	OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
5772 
5773 	OK(fields[SYS_COLUMN__PRTYPE]->store(column->prtype));
5774 
5775 	OK(fields[SYS_COLUMN_COLUMN_LEN]->store(column->len));
5776 
5777 	OK(schema_table_store_record(thd, table_to_fill));
5778 
5779 	DBUG_RETURN(0);
5780 }
5781 /*******************************************************************//**
5782 Function to fill information_schema.innodb_sys_columns with information
5783 collected by scanning SYS_COLUMNS table.
5784 @return 0 on success */
5785 static
5786 int
i_s_sys_columns_fill_table(THD * thd,TABLE_LIST * tables,Item *)5787 i_s_sys_columns_fill_table(
5788 /*=======================*/
5789 	THD*		thd,	/*!< in: thread */
5790 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
5791 	Item*		)	/*!< in: condition (not used) */
5792 {
5793 	btr_pcur_t	pcur;
5794 	const rec_t*	rec;
5795 	const char*	col_name;
5796 	mem_heap_t*	heap;
5797 	mtr_t		mtr;
5798 
5799 	DBUG_ENTER("i_s_sys_columns_fill_table");
5800 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5801 
5802 	/* deny access to user without PROCESS_ACL privilege */
5803 	if (check_global_access(thd, PROCESS_ACL)) {
5804 		DBUG_RETURN(0);
5805 	}
5806 
5807 	heap = mem_heap_create(1000);
5808 	mutex_enter(&dict_sys->mutex);
5809 	mtr_start(&mtr);
5810 
5811 	rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS);
5812 
5813 	while (rec) {
5814 		const char*	err_msg;
5815 		dict_col_t	column_rec;
5816 		table_id_t	table_id;
5817 		ulint		nth_v_col;
5818 
5819 		/* populate a dict_col_t structure with information from
5820 		a SYS_COLUMNS row */
5821 		err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec,
5822 						       &table_id, &col_name,
5823 						       &nth_v_col);
5824 
5825 		mtr_commit(&mtr);
5826 		mutex_exit(&dict_sys->mutex);
5827 
5828 		if (!err_msg) {
5829 			i_s_dict_fill_sys_columns(thd, table_id, col_name,
5830 						 &column_rec, nth_v_col,
5831 						 tables->table);
5832 		} else {
5833 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5834 					    ER_CANT_FIND_SYSTEM_REC, "%s",
5835 					    err_msg);
5836 		}
5837 
5838 		mem_heap_empty(heap);
5839 
5840 		/* Get the next record */
5841 		mutex_enter(&dict_sys->mutex);
5842 		mtr_start(&mtr);
5843 		rec = dict_getnext_system(&pcur, &mtr);
5844 	}
5845 
5846 	mtr_commit(&mtr);
5847 	mutex_exit(&dict_sys->mutex);
5848 	mem_heap_free(heap);
5849 
5850 	DBUG_RETURN(0);
5851 }
5852 /*******************************************************************//**
5853 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns
5854 @return 0 on success */
5855 static
5856 int
innodb_sys_columns_init(void * p)5857 innodb_sys_columns_init(
5858 /*====================*/
5859 	void*	p)	/*!< in/out: table schema object */
5860 {
5861 	ST_SCHEMA_TABLE*	schema;
5862 
5863 	DBUG_ENTER("innodb_sys_columns_init");
5864 
5865 	schema = (ST_SCHEMA_TABLE*) p;
5866 
5867 	schema->fields_info = innodb_sys_columns_fields_info;
5868 	schema->fill_table = i_s_sys_columns_fill_table;
5869 
5870 	DBUG_RETURN(0);
5871 }
5872 
5873 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_columns =
5874 {
5875 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
5876 	/* int */
5877 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
5878 
5879 	/* pointer to type-specific plugin descriptor */
5880 	/* void* */
5881 	&i_s_info,
5882 
5883 	/* plugin name */
5884 	/* const char* */
5885 	"INNODB_SYS_COLUMNS",
5886 
5887 	/* plugin author (for SHOW PLUGINS) */
5888 	/* const char* */
5889 	plugin_author,
5890 
5891 	/* general descriptive text (for SHOW PLUGINS) */
5892 	/* const char* */
5893 	"InnoDB SYS_COLUMNS",
5894 
5895 	/* the plugin license (PLUGIN_LICENSE_XXX) */
5896 	/* int */
5897 	PLUGIN_LICENSE_GPL,
5898 
5899 	/* the function to invoke when plugin is loaded */
5900 	/* int (*)(void*); */
5901 	innodb_sys_columns_init,
5902 
5903 	/* the function to invoke when plugin is unloaded */
5904 	/* int (*)(void*); */
5905 	i_s_common_deinit,
5906 
5907 	/* plugin version (for SHOW PLUGINS) */
5908 	/* unsigned int */
5909 	INNODB_VERSION_SHORT,
5910 
5911 	/* struct st_mysql_show_var* */
5912 	NULL,
5913 
5914 	/* struct st_mysql_sys_var** */
5915 	NULL,
5916 
5917         /* Maria extension */
5918 	INNODB_VERSION_STR,
5919         MariaDB_PLUGIN_MATURITY_STABLE,
5920 };
5921 
5922 /**  SYS_VIRTUAL **************************************************/
5923 /** Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL */
5924 static ST_FIELD_INFO innodb_sys_virtual_fields_info[]=
5925 {
5926 #define SYS_VIRTUAL_TABLE_ID		0
5927   {"TABLE_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
5928    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5929 #define SYS_VIRTUAL_POS			1
5930   {"POS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5931    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5932 #define SYS_VIRTUAL_BASE_POS		2
5933   {"BASE_POS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
5934    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
5935   END_OF_ST_FIELD_INFO
5936 };
5937 
5938 /** Function to populate the information_schema.innodb_sys_virtual with
5939 related information
5940 param[in]	thd		thread
5941 param[in]	table_id	table ID
5942 param[in]	pos		virtual column position
5943 param[in]	base_pos	base column position
5944 param[in,out]	table_to_fill	fill this table
5945 @return 0 on success */
5946 static
5947 int
i_s_dict_fill_sys_virtual(THD * thd,table_id_t table_id,ulint pos,ulint base_pos,TABLE * table_to_fill)5948 i_s_dict_fill_sys_virtual(
5949 	THD*		thd,
5950 	table_id_t	table_id,
5951 	ulint		pos,
5952 	ulint		base_pos,
5953 	TABLE*		table_to_fill)
5954 {
5955 	Field**		fields;
5956 
5957 	DBUG_ENTER("i_s_dict_fill_sys_virtual");
5958 
5959 	fields = table_to_fill->field;
5960 
5961 	OK(fields[SYS_VIRTUAL_TABLE_ID]->store(table_id, true));
5962 
5963 	OK(fields[SYS_VIRTUAL_POS]->store(pos, true));
5964 
5965 	OK(fields[SYS_VIRTUAL_BASE_POS]->store(base_pos, true));
5966 
5967 	OK(schema_table_store_record(thd, table_to_fill));
5968 
5969 	DBUG_RETURN(0);
5970 }
5971 
5972 /** Function to fill information_schema.innodb_sys_virtual with information
5973 collected by scanning SYS_VIRTUAL table.
5974 param[in]	thd		thread
5975 param[in,out]	tables		tables to fill
5976 param[in]	item		condition (not used)
5977 @return 0 on success */
5978 static
5979 int
i_s_sys_virtual_fill_table(THD * thd,TABLE_LIST * tables,Item *)5980 i_s_sys_virtual_fill_table(
5981 	THD*		thd,
5982 	TABLE_LIST*	tables,
5983 	Item*		)
5984 {
5985 	btr_pcur_t	pcur;
5986 	const rec_t*	rec;
5987 	ulint		pos;
5988 	ulint		base_pos;
5989 	mtr_t		mtr;
5990 
5991 	DBUG_ENTER("i_s_sys_virtual_fill_table");
5992 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5993 
5994 	/* deny access to user without PROCESS_ACL privilege */
5995 	if (check_global_access(thd, PROCESS_ACL)) {
5996 		DBUG_RETURN(0);
5997 	}
5998 
5999 	mutex_enter(&dict_sys->mutex);
6000 	mtr_start(&mtr);
6001 
6002 	rec = dict_startscan_system(&pcur, &mtr, SYS_VIRTUAL);
6003 
6004 	while (rec) {
6005 		const char*	err_msg;
6006 		table_id_t	table_id;
6007 
6008 		/* populate a dict_col_t structure with information from
6009 		a SYS_VIRTUAL row */
6010 		err_msg = dict_process_sys_virtual_rec(rec,
6011 						       &table_id, &pos,
6012 						       &base_pos);
6013 
6014 		mtr_commit(&mtr);
6015 		mutex_exit(&dict_sys->mutex);
6016 
6017 		if (!err_msg) {
6018 			i_s_dict_fill_sys_virtual(thd, table_id, pos, base_pos,
6019 						  tables->table);
6020 		} else {
6021 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6022 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6023 					    err_msg);
6024 		}
6025 
6026 		/* Get the next record */
6027 		mutex_enter(&dict_sys->mutex);
6028 		mtr_start(&mtr);
6029 		rec = dict_getnext_system(&pcur, &mtr);
6030 	}
6031 
6032 	mtr_commit(&mtr);
6033 	mutex_exit(&dict_sys->mutex);
6034 
6035 	DBUG_RETURN(0);
6036 }
6037 
6038 /** Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_virtual
6039 param[in,out]	p	table schema object
6040 @return 0 on success */
6041 static
6042 int
innodb_sys_virtual_init(void * p)6043 innodb_sys_virtual_init(
6044 	void*	p)
6045 {
6046 	ST_SCHEMA_TABLE*	schema;
6047 
6048 	DBUG_ENTER("innodb_sys_virtual_init");
6049 
6050 	schema = (ST_SCHEMA_TABLE*) p;
6051 
6052 	schema->fields_info = innodb_sys_virtual_fields_info;
6053 	schema->fill_table = i_s_sys_virtual_fill_table;
6054 
6055 	DBUG_RETURN(0);
6056 }
6057 
6058 struct st_maria_plugin	i_s_innodb_sys_virtual =
6059 {
6060 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6061 	/* int */
6062 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
6063 
6064 	/* pointer to type-specific plugin descriptor */
6065 	/* void* */
6066 	&i_s_info,
6067 
6068 	/* plugin name */
6069 	/* const char* */
6070 	"INNODB_SYS_VIRTUAL",
6071 
6072 	/* plugin author (for SHOW PLUGINS) */
6073 	/* const char* */
6074 	plugin_author,
6075 
6076 	/* general descriptive text (for SHOW PLUGINS) */
6077 	/* const char* */
6078 	"InnoDB SYS_VIRTUAL",
6079 
6080 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6081 	/* int */
6082 	PLUGIN_LICENSE_GPL,
6083 
6084 	/* the function to invoke when plugin is loaded */
6085 	/* int (*)(void*); */
6086 	innodb_sys_virtual_init,
6087 
6088 	/* the function to invoke when plugin is unloaded */
6089 	/* int (*)(void*); */
6090 	i_s_common_deinit,
6091 
6092 	/* plugin version (for SHOW PLUGINS) */
6093 	/* unsigned int */
6094 	INNODB_VERSION_SHORT,
6095 
6096 	/* struct st_mysql_show_var* */
6097 	NULL,
6098 
6099 	/* struct st_mysql_sys_var** */
6100 	NULL,
6101 
6102 	/* Maria extension */
6103 	INNODB_VERSION_STR,
6104 	MariaDB_PLUGIN_MATURITY_STABLE,
6105 };
6106 /**  SYS_FIELDS  ***************************************************/
6107 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FIELDS */
6108 static ST_FIELD_INFO innodb_sys_fields_fields_info[]=
6109 {
6110 #define SYS_FIELD_INDEX_ID	0
6111   {"INDEX_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6112    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6113 #define SYS_FIELD_NAME		1
6114   {"NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
6115    0, 0, "", SKIP_OPEN_TABLE},
6116 #define SYS_FIELD_POS		2
6117   {"POS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6118    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6119   END_OF_ST_FIELD_INFO
6120 };
6121 
6122 /**********************************************************************//**
6123 Function to fill information_schema.innodb_sys_fields with information
6124 collected by scanning SYS_FIELDS table.
6125 @return 0 on success */
6126 static
6127 int
i_s_dict_fill_sys_fields(THD * thd,index_id_t index_id,dict_field_t * field,ulint pos,TABLE * table_to_fill)6128 i_s_dict_fill_sys_fields(
6129 /*=====================*/
6130 	THD*		thd,		/*!< in: thread */
6131 	index_id_t	index_id,	/*!< in: index id for the field */
6132 	dict_field_t*	field,		/*!< in: table */
6133 	ulint		pos,		/*!< in: Field position */
6134 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
6135 {
6136 	Field**		fields;
6137 
6138 	DBUG_ENTER("i_s_dict_fill_sys_fields");
6139 
6140 	fields = table_to_fill->field;
6141 
6142 	OK(fields[SYS_FIELD_INDEX_ID]->store(index_id, true));
6143 
6144 	OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
6145 
6146 	OK(fields[SYS_FIELD_POS]->store(pos, true));
6147 
6148 	OK(schema_table_store_record(thd, table_to_fill));
6149 
6150 	DBUG_RETURN(0);
6151 }
6152 /*******************************************************************//**
6153 Function to go through each record in SYS_FIELDS table, and fill the
6154 information_schema.innodb_sys_fields table with related index field
6155 information
6156 @return 0 on success */
6157 static
6158 int
i_s_sys_fields_fill_table(THD * thd,TABLE_LIST * tables,Item *)6159 i_s_sys_fields_fill_table(
6160 /*======================*/
6161 	THD*		thd,	/*!< in: thread */
6162 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
6163 	Item*		)	/*!< in: condition (not used) */
6164 {
6165 	btr_pcur_t	pcur;
6166 	const rec_t*	rec;
6167 	mem_heap_t*	heap;
6168 	index_id_t	last_id;
6169 	mtr_t		mtr;
6170 
6171 	DBUG_ENTER("i_s_sys_fields_fill_table");
6172 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
6173 
6174 	/* deny access to user without PROCESS_ACL privilege */
6175 	if (check_global_access(thd, PROCESS_ACL)) {
6176 
6177 		DBUG_RETURN(0);
6178 	}
6179 
6180 	heap = mem_heap_create(1000);
6181 	mutex_enter(&dict_sys->mutex);
6182 	mtr_start(&mtr);
6183 
6184 	/* will save last index id so that we know whether we move to
6185 	the next index. This is used to calculate prefix length */
6186 	last_id = 0;
6187 
6188 	rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS);
6189 
6190 	while (rec) {
6191 		ulint		pos;
6192 		const char*	err_msg;
6193 		index_id_t	index_id;
6194 		dict_field_t	field_rec;
6195 
6196 		/* Populate a dict_field_t structure with information from
6197 		a SYS_FIELDS row */
6198 		err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
6199 						      &pos, &index_id, last_id);
6200 
6201 		mtr_commit(&mtr);
6202 		mutex_exit(&dict_sys->mutex);
6203 
6204 		if (!err_msg) {
6205 			i_s_dict_fill_sys_fields(thd, index_id, &field_rec,
6206 						 pos, tables->table);
6207 			last_id = index_id;
6208 		} else {
6209 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6210 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6211 					    err_msg);
6212 		}
6213 
6214 		mem_heap_empty(heap);
6215 
6216 		/* Get the next record */
6217 		mutex_enter(&dict_sys->mutex);
6218 		mtr_start(&mtr);
6219 		rec = dict_getnext_system(&pcur, &mtr);
6220 	}
6221 
6222 	mtr_commit(&mtr);
6223 	mutex_exit(&dict_sys->mutex);
6224 	mem_heap_free(heap);
6225 
6226 	DBUG_RETURN(0);
6227 }
6228 /*******************************************************************//**
6229 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_fields
6230 @return 0 on success */
6231 static
6232 int
innodb_sys_fields_init(void * p)6233 innodb_sys_fields_init(
6234 /*===================*/
6235 	void*   p)	/*!< in/out: table schema object */
6236 {
6237 	ST_SCHEMA_TABLE*	schema;
6238 
6239 	DBUG_ENTER("innodb_sys_field_init");
6240 
6241 	schema = (ST_SCHEMA_TABLE*) p;
6242 
6243 	schema->fields_info = innodb_sys_fields_fields_info;
6244 	schema->fill_table = i_s_sys_fields_fill_table;
6245 
6246 	DBUG_RETURN(0);
6247 }
6248 
6249 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_fields =
6250 {
6251 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6252 	/* int */
6253 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
6254 
6255 	/* pointer to type-specific plugin descriptor */
6256 	/* void* */
6257 	&i_s_info,
6258 
6259 	/* plugin name */
6260 	/* const char* */
6261 	"INNODB_SYS_FIELDS",
6262 
6263 	/* plugin author (for SHOW PLUGINS) */
6264 	/* const char* */
6265 	plugin_author,
6266 
6267 	/* general descriptive text (for SHOW PLUGINS) */
6268 	/* const char* */
6269 	"InnoDB SYS_FIELDS",
6270 
6271 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6272 	/* int */
6273 	PLUGIN_LICENSE_GPL,
6274 
6275 	/* the function to invoke when plugin is loaded */
6276 	/* int (*)(void*); */
6277 	innodb_sys_fields_init,
6278 
6279 	/* the function to invoke when plugin is unloaded */
6280 	/* int (*)(void*); */
6281 	i_s_common_deinit,
6282 
6283 	/* plugin version (for SHOW PLUGINS) */
6284 	/* unsigned int */
6285 	INNODB_VERSION_SHORT,
6286 
6287 	/* struct st_mysql_show_var* */
6288 	NULL,
6289 
6290 	/* struct st_mysql_sys_var** */
6291 	NULL,
6292 
6293         /* Maria extension */
6294 	INNODB_VERSION_STR,
6295         MariaDB_PLUGIN_MATURITY_STABLE,
6296 };
6297 
6298 /**  SYS_FOREIGN        ********************************************/
6299 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN */
6300 static ST_FIELD_INFO innodb_sys_foreign_fields_info[]=
6301 {
6302 #define SYS_FOREIGN_ID		0
6303   {"ID", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6304 #define SYS_FOREIGN_FOR_NAME	1
6305   {"FOR_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6306 #define SYS_FOREIGN_REF_NAME	2
6307   {"REF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6308 #define SYS_FOREIGN_NUM_COL	3
6309   {"N_COLS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6310    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6311 #define SYS_FOREIGN_TYPE	4
6312   {"TYPE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6313    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6314   END_OF_ST_FIELD_INFO
6315 };
6316 
6317 /**********************************************************************//**
6318 Function to fill information_schema.innodb_sys_foreign with information
6319 collected by scanning SYS_FOREIGN table.
6320 @return 0 on success */
6321 static
6322 int
i_s_dict_fill_sys_foreign(THD * thd,dict_foreign_t * foreign,TABLE * table_to_fill)6323 i_s_dict_fill_sys_foreign(
6324 /*======================*/
6325 	THD*		thd,		/*!< in: thread */
6326 	dict_foreign_t*	foreign,	/*!< in: table */
6327 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
6328 {
6329 	Field**		fields;
6330 
6331 	DBUG_ENTER("i_s_dict_fill_sys_foreign");
6332 
6333 	fields = table_to_fill->field;
6334 
6335 	OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id));
6336 
6337 	OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME],
6338 			      foreign->foreign_table_name));
6339 
6340 	OK(field_store_string(fields[SYS_FOREIGN_REF_NAME],
6341 			      foreign->referenced_table_name));
6342 
6343 	OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields));
6344 
6345 	OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type));
6346 
6347 	OK(schema_table_store_record(thd, table_to_fill));
6348 
6349 	DBUG_RETURN(0);
6350 }
6351 
6352 /*******************************************************************//**
6353 Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop
6354 through each record in SYS_FOREIGN, and extract the foreign key
6355 information.
6356 @return 0 on success */
6357 static
6358 int
i_s_sys_foreign_fill_table(THD * thd,TABLE_LIST * tables,Item *)6359 i_s_sys_foreign_fill_table(
6360 /*=======================*/
6361 	THD*		thd,	/*!< in: thread */
6362 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
6363 	Item*		)	/*!< in: condition (not used) */
6364 {
6365 	btr_pcur_t	pcur;
6366 	const rec_t*	rec;
6367 	mem_heap_t*	heap;
6368 	mtr_t		mtr;
6369 
6370 	DBUG_ENTER("i_s_sys_foreign_fill_table");
6371 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
6372 
6373 	/* deny access to user without PROCESS_ACL privilege */
6374 	if (check_global_access(thd, PROCESS_ACL)) {
6375 
6376 		DBUG_RETURN(0);
6377 	}
6378 
6379 	heap = mem_heap_create(1000);
6380 	mutex_enter(&dict_sys->mutex);
6381 	mtr_start(&mtr);
6382 
6383 	rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN);
6384 
6385 	while (rec) {
6386 		const char*	err_msg;
6387 		dict_foreign_t	foreign_rec;
6388 
6389 		/* Populate a dict_foreign_t structure with information from
6390 		a SYS_FOREIGN row */
6391 		err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
6392 
6393 		mtr_commit(&mtr);
6394 		mutex_exit(&dict_sys->mutex);
6395 
6396 		if (!err_msg) {
6397 			i_s_dict_fill_sys_foreign(thd, &foreign_rec,
6398 						 tables->table);
6399 		} else {
6400 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6401 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6402 					    err_msg);
6403 		}
6404 
6405 		mem_heap_empty(heap);
6406 
6407 		/* Get the next record */
6408 		mtr_start(&mtr);
6409 		mutex_enter(&dict_sys->mutex);
6410 		rec = dict_getnext_system(&pcur, &mtr);
6411 	}
6412 
6413 	mtr_commit(&mtr);
6414 	mutex_exit(&dict_sys->mutex);
6415 	mem_heap_free(heap);
6416 
6417 	DBUG_RETURN(0);
6418 }
6419 
6420 /*******************************************************************//**
6421 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign
6422 @return 0 on success */
6423 static
6424 int
innodb_sys_foreign_init(void * p)6425 innodb_sys_foreign_init(
6426 /*====================*/
6427 	void*   p)	/*!< in/out: table schema object */
6428 {
6429 	ST_SCHEMA_TABLE*	schema;
6430 
6431 	DBUG_ENTER("innodb_sys_foreign_init");
6432 
6433 	schema = (ST_SCHEMA_TABLE*) p;
6434 
6435 	schema->fields_info = innodb_sys_foreign_fields_info;
6436 	schema->fill_table = i_s_sys_foreign_fill_table;
6437 
6438 	DBUG_RETURN(0);
6439 }
6440 
6441 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_foreign =
6442 {
6443 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6444 	/* int */
6445 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
6446 
6447 	/* pointer to type-specific plugin descriptor */
6448 	/* void* */
6449 	&i_s_info,
6450 
6451 	/* plugin name */
6452 	/* const char* */
6453 	"INNODB_SYS_FOREIGN",
6454 
6455 	/* plugin author (for SHOW PLUGINS) */
6456 	/* const char* */
6457 	plugin_author,
6458 
6459 	/* general descriptive text (for SHOW PLUGINS) */
6460 	/* const char* */
6461 	"InnoDB SYS_FOREIGN",
6462 
6463 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6464 	/* int */
6465 	PLUGIN_LICENSE_GPL,
6466 
6467 	/* the function to invoke when plugin is loaded */
6468 	/* int (*)(void*); */
6469 	innodb_sys_foreign_init,
6470 
6471 	/* the function to invoke when plugin is unloaded */
6472 	/* int (*)(void*); */
6473 	i_s_common_deinit,
6474 
6475 	/* plugin version (for SHOW PLUGINS) */
6476 	/* unsigned int */
6477 	INNODB_VERSION_SHORT,
6478 
6479 	/* struct st_mysql_show_var* */
6480 	NULL,
6481 
6482 	/* struct st_mysql_sys_var** */
6483 	NULL,
6484 
6485         /* Maria extension */
6486 	INNODB_VERSION_STR,
6487         MariaDB_PLUGIN_MATURITY_STABLE,
6488 };
6489 
6490 /**  SYS_FOREIGN_COLS   ********************************************/
6491 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS */
6492 static ST_FIELD_INFO innodb_sys_foreign_cols_fields_info[]=
6493 {
6494 #define SYS_FOREIGN_COL_ID		0
6495   {"ID", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6496 #define SYS_FOREIGN_COL_FOR_NAME	1
6497   {"FOR_COL_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6498 #define SYS_FOREIGN_COL_REF_NAME	2
6499   {"REF_COL_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6500 #define SYS_FOREIGN_COL_POS		3
6501   {"POS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6502    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6503   END_OF_ST_FIELD_INFO
6504 };
6505 
6506 /**********************************************************************//**
6507 Function to fill information_schema.innodb_sys_foreign_cols with information
6508 collected by scanning SYS_FOREIGN_COLS table.
6509 @return 0 on success */
6510 static
6511 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)6512 i_s_dict_fill_sys_foreign_cols(
6513 /*==========================*/
6514 	THD*		thd,		/*!< in: thread */
6515 	const char*	name,		/*!< in: foreign key constraint name */
6516 	const char*	for_col_name,	/*!< in: referencing column name*/
6517 	const char*	ref_col_name,	/*!< in: referenced column
6518 					name */
6519 	ulint		pos,		/*!< in: column position */
6520 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
6521 {
6522 	Field**		fields;
6523 
6524 	DBUG_ENTER("i_s_dict_fill_sys_foreign_cols");
6525 
6526 	fields = table_to_fill->field;
6527 
6528 	OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name));
6529 
6530 	OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name));
6531 
6532 	OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
6533 
6534 	OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true));
6535 
6536 	OK(schema_table_store_record(thd, table_to_fill));
6537 
6538 	DBUG_RETURN(0);
6539 }
6540 /*******************************************************************//**
6541 Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop
6542 through each record in SYS_FOREIGN_COLS, and extract the foreign key column
6543 information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table.
6544 @return 0 on success */
6545 static
6546 int
i_s_sys_foreign_cols_fill_table(THD * thd,TABLE_LIST * tables,Item *)6547 i_s_sys_foreign_cols_fill_table(
6548 /*============================*/
6549 	THD*		thd,	/*!< in: thread */
6550 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
6551 	Item*		)	/*!< in: condition (not used) */
6552 {
6553 	btr_pcur_t	pcur;
6554 	const rec_t*	rec;
6555 	mem_heap_t*	heap;
6556 	mtr_t		mtr;
6557 
6558 	DBUG_ENTER("i_s_sys_foreign_cols_fill_table");
6559 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
6560 
6561 	/* deny access to user without PROCESS_ACL privilege */
6562 	if (check_global_access(thd, PROCESS_ACL)) {
6563 		DBUG_RETURN(0);
6564 	}
6565 
6566 	heap = mem_heap_create(1000);
6567 	mutex_enter(&dict_sys->mutex);
6568 	mtr_start(&mtr);
6569 
6570 	rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS);
6571 
6572 	while (rec) {
6573 		const char*	err_msg;
6574 		const char*	name;
6575 		const char*	for_col_name;
6576 		const char*	ref_col_name;
6577 		ulint		pos;
6578 
6579 		/* Extract necessary information from a SYS_FOREIGN_COLS row */
6580 		err_msg = dict_process_sys_foreign_col_rec(
6581 			heap, rec, &name, &for_col_name, &ref_col_name, &pos);
6582 
6583 		mtr_commit(&mtr);
6584 		mutex_exit(&dict_sys->mutex);
6585 
6586 		if (!err_msg) {
6587 			i_s_dict_fill_sys_foreign_cols(
6588 				thd, name, for_col_name, ref_col_name, pos,
6589 				tables->table);
6590 		} else {
6591 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6592 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6593 					    err_msg);
6594 		}
6595 
6596 		mem_heap_empty(heap);
6597 
6598 		/* Get the next record */
6599 		mutex_enter(&dict_sys->mutex);
6600 		mtr_start(&mtr);
6601 		rec = dict_getnext_system(&pcur, &mtr);
6602 	}
6603 
6604 	mtr_commit(&mtr);
6605 	mutex_exit(&dict_sys->mutex);
6606 	mem_heap_free(heap);
6607 
6608 	DBUG_RETURN(0);
6609 }
6610 /*******************************************************************//**
6611 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols
6612 @return 0 on success */
6613 static
6614 int
innodb_sys_foreign_cols_init(void * p)6615 innodb_sys_foreign_cols_init(
6616 /*========================*/
6617 	void*	p)	/*!< in/out: table schema object */
6618 {
6619 	ST_SCHEMA_TABLE*	schema;
6620 
6621 	DBUG_ENTER("innodb_sys_foreign_cols_init");
6622 
6623 	schema = (ST_SCHEMA_TABLE*) p;
6624 
6625 	schema->fields_info = innodb_sys_foreign_cols_fields_info;
6626 	schema->fill_table = i_s_sys_foreign_cols_fill_table;
6627 
6628 	DBUG_RETURN(0);
6629 }
6630 
6631 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_foreign_cols =
6632 {
6633 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6634 	/* int */
6635 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
6636 
6637 	/* pointer to type-specific plugin descriptor */
6638 	/* void* */
6639 	&i_s_info,
6640 
6641 	/* plugin name */
6642 	/* const char* */
6643 	"INNODB_SYS_FOREIGN_COLS",
6644 
6645 	/* plugin author (for SHOW PLUGINS) */
6646 	/* const char* */
6647 	plugin_author,
6648 
6649 	/* general descriptive text (for SHOW PLUGINS) */
6650 	/* const char* */
6651 	"InnoDB SYS_FOREIGN_COLS",
6652 
6653 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6654 	/* int */
6655 	PLUGIN_LICENSE_GPL,
6656 
6657 	/* the function to invoke when plugin is loaded */
6658 	/* int (*)(void*); */
6659 	innodb_sys_foreign_cols_init,
6660 
6661 	/* the function to invoke when plugin is unloaded */
6662 	/* int (*)(void*); */
6663 	i_s_common_deinit,
6664 
6665 	/* plugin version (for SHOW PLUGINS) */
6666 	/* unsigned int */
6667 	INNODB_VERSION_SHORT,
6668 
6669 	/* struct st_mysql_show_var* */
6670 	NULL,
6671 
6672 	/* struct st_mysql_sys_var** */
6673 	NULL,
6674 
6675         /* Maria extension */
6676 	INNODB_VERSION_STR,
6677         MariaDB_PLUGIN_MATURITY_STABLE,
6678 };
6679 
6680 /**  SYS_TABLESPACES    ********************************************/
6681 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES */
6682 static ST_FIELD_INFO innodb_sys_tablespaces_fields_info[]=
6683 {
6684 #define SYS_TABLESPACES_SPACE		0
6685   {"SPACE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6686    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6687 #define SYS_TABLESPACES_NAME		1
6688   {"NAME", MAX_FULL_NAME_LEN + 1, MYSQL_TYPE_STRING,
6689    0, 0, "", SKIP_OPEN_TABLE},
6690 #define SYS_TABLESPACES_FLAGS		2
6691   {"FLAG", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6692    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6693 #define SYS_TABLESPACES_ROW_FORMAT	3
6694   {"ROW_FORMAT", 22, MYSQL_TYPE_STRING,
6695    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
6696 #define SYS_TABLESPACES_PAGE_SIZE	4
6697   {"PAGE_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6698    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6699 #define SYS_TABLESPACES_ZIP_PAGE_SIZE	5
6700   {"ZIP_PAGE_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6701    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6702 #define SYS_TABLESPACES_SPACE_TYPE	6
6703   {"SPACE_TYPE", 10, MYSQL_TYPE_STRING,
6704    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
6705 #define SYS_TABLESPACES_FS_BLOCK_SIZE	7
6706   {"FS_BLOCK_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6707    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6708 #define SYS_TABLESPACES_FILE_SIZE	8
6709   {"FILE_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6710    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6711 #define SYS_TABLESPACES_ALLOC_SIZE	9
6712   {"ALLOCATED_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
6713    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6714   END_OF_ST_FIELD_INFO
6715 };
6716 
6717 /**********************************************************************//**
6718 Function to fill INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES with information
6719 collected by scanning SYS_TABLESPACESS table.
6720 @return 0 on success */
6721 static
6722 int
i_s_dict_fill_sys_tablespaces(THD * thd,ulint space,const char * name,ulint flags,TABLE * table_to_fill)6723 i_s_dict_fill_sys_tablespaces(
6724 /*==========================*/
6725 	THD*		thd,		/*!< in: thread */
6726 	ulint		space,		/*!< in: space ID */
6727 	const char*	name,		/*!< in: tablespace name */
6728 	ulint		flags,		/*!< in: tablespace flags */
6729 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
6730 {
6731 	Field**	fields;
6732 	ulint	atomic_blobs	= FSP_FLAGS_HAS_ATOMIC_BLOBS(flags);
6733 	const char* row_format;
6734 
6735 	DBUG_ENTER("i_s_dict_fill_sys_tablespaces");
6736 
6737 	if (is_system_tablespace(space)) {
6738 		row_format = "Compact, Redundant or Dynamic";
6739 	} else if (FSP_FLAGS_GET_ZIP_SSIZE(flags)) {
6740 		row_format = "Compressed";
6741 	} else if (atomic_blobs) {
6742 		row_format = "Dynamic";
6743 	} else {
6744 		row_format = "Compact or Redundant";
6745 	}
6746 
6747 	fields = table_to_fill->field;
6748 
6749 	OK(fields[SYS_TABLESPACES_SPACE]->store(space, true));
6750 
6751 	OK(field_store_string(fields[SYS_TABLESPACES_NAME], name));
6752 
6753 	OK(fields[SYS_TABLESPACES_FLAGS]->store(flags, true));
6754 
6755 	OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT], row_format));
6756 
6757 	OK(field_store_string(fields[SYS_TABLESPACES_SPACE_TYPE],
6758 			      is_system_tablespace(space)
6759 			      ? "System" : "Single"));
6760 
6761 	ulint cflags = fsp_flags_is_valid(flags, space)
6762 		? flags : fsp_flags_convert_from_101(flags);
6763 	if (cflags == ULINT_UNDEFINED) {
6764 		fields[SYS_TABLESPACES_PAGE_SIZE]->set_null();
6765 		fields[SYS_TABLESPACES_ZIP_PAGE_SIZE]->set_null();
6766 		fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->set_null();
6767 		fields[SYS_TABLESPACES_FILE_SIZE]->set_null();
6768 		fields[SYS_TABLESPACES_ALLOC_SIZE]->set_null();
6769 		OK(schema_table_store_record(thd, table_to_fill));
6770 		DBUG_RETURN(0);
6771 	}
6772 
6773 	const page_size_t page_size(cflags);
6774 
6775 	OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(
6776 		   page_size.logical(), true));
6777 
6778 	OK(fields[SYS_TABLESPACES_ZIP_PAGE_SIZE]->store(
6779 		   page_size.physical(), true));
6780 
6781 	os_file_stat_t	stat;
6782 	os_file_size_t	file;
6783 
6784 	memset(&file, 0xff, sizeof(file));
6785 	memset(&stat, 0x0, sizeof(stat));
6786 
6787 	if (fil_space_t* s = fil_space_acquire_silent(space)) {
6788 		const char *filepath = s->chain.start
6789 			? s->chain.start->name : NULL;
6790 		if (!filepath) {
6791 			goto file_done;
6792 		}
6793 
6794 		file = os_file_get_size(filepath);
6795 
6796 		/* Get the file system (or Volume) block size. */
6797 		switch (dberr_t err = os_file_get_status(filepath, &stat,
6798 							 false, false)) {
6799 		case DB_FAIL:
6800 			ib::warn()
6801 				<< "File '" << filepath << "', failed to get "
6802 				<< "stats";
6803 			break;
6804 
6805 		case DB_SUCCESS:
6806 		case DB_NOT_FOUND:
6807 			break;
6808 
6809 		default:
6810 			ib::error() << "File '" << filepath << "' " << err;
6811 			break;
6812 		}
6813 
6814 file_done:
6815 		s->release();
6816 	}
6817 
6818 	if (file.m_total_size == static_cast<os_offset_t>(~0)) {
6819 		stat.block_size = 0;
6820 		file.m_total_size = 0;
6821 		file.m_alloc_size = 0;
6822 	}
6823 
6824 	OK(fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->store(stat.block_size, true));
6825 
6826 	OK(fields[SYS_TABLESPACES_FILE_SIZE]->store(file.m_total_size, true));
6827 
6828 	OK(fields[SYS_TABLESPACES_ALLOC_SIZE]->store(file.m_alloc_size, true));
6829 
6830 	OK(schema_table_store_record(thd, table_to_fill));
6831 
6832 	DBUG_RETURN(0);
6833 }
6834 
6835 /*******************************************************************//**
6836 Function to populate INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES table.
6837 Loop through each record in SYS_TABLESPACES, and extract the column
6838 information and fill the INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES table.
6839 @return 0 on success */
6840 static
6841 int
i_s_sys_tablespaces_fill_table(THD * thd,TABLE_LIST * tables,Item *)6842 i_s_sys_tablespaces_fill_table(
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_tablespaces_fill_table");
6854 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
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 	for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES);
6866 	     rec != NULL;
6867 	     rec = dict_getnext_system(&pcur, &mtr)) {
6868 
6869 		const char*	err_msg;
6870 		ulint		space;
6871 		const char*	name;
6872 		ulint		flags;
6873 
6874 		/* Extract necessary information from a SYS_TABLESPACES row */
6875 		err_msg = dict_process_sys_tablespaces(
6876 			heap, rec, &space, &name, &flags);
6877 
6878 		mtr_commit(&mtr);
6879 		mutex_exit(&dict_sys->mutex);
6880 
6881 		if (!err_msg) {
6882 			i_s_dict_fill_sys_tablespaces(
6883 				thd, space, name, flags,
6884 				tables->table);
6885 		} else {
6886 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
6887 					    ER_CANT_FIND_SYSTEM_REC, "%s",
6888 					    err_msg);
6889 		}
6890 
6891 		mem_heap_empty(heap);
6892 
6893 		/* Get the next record */
6894 		mutex_enter(&dict_sys->mutex);
6895 		mtr_start(&mtr);
6896 	}
6897 
6898 	mtr_commit(&mtr);
6899 	mutex_exit(&dict_sys->mutex);
6900 	mem_heap_free(heap);
6901 
6902 	DBUG_RETURN(0);
6903 }
6904 /*******************************************************************//**
6905 Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
6906 @return 0 on success */
6907 static
6908 int
innodb_sys_tablespaces_init(void * p)6909 innodb_sys_tablespaces_init(
6910 /*========================*/
6911 	void*	p)	/*!< in/out: table schema object */
6912 {
6913 	ST_SCHEMA_TABLE*	schema;
6914 
6915 	DBUG_ENTER("innodb_sys_tablespaces_init");
6916 
6917 	schema = (ST_SCHEMA_TABLE*) p;
6918 
6919 	schema->fields_info = innodb_sys_tablespaces_fields_info;
6920 	schema->fill_table = i_s_sys_tablespaces_fill_table;
6921 
6922 	DBUG_RETURN(0);
6923 }
6924 
6925 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_tablespaces =
6926 {
6927 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
6928 	/* int */
6929 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
6930 
6931 	/* pointer to type-specific plugin descriptor */
6932 	/* void* */
6933 	&i_s_info,
6934 
6935 	/* plugin name */
6936 	/* const char* */
6937 	"INNODB_SYS_TABLESPACES",
6938 
6939 	/* plugin author (for SHOW PLUGINS) */
6940 	/* const char* */
6941 	plugin_author,
6942 
6943 	/* general descriptive text (for SHOW PLUGINS) */
6944 	/* const char* */
6945 	"InnoDB SYS_TABLESPACES",
6946 
6947 	/* the plugin license (PLUGIN_LICENSE_XXX) */
6948 	/* int */
6949 	PLUGIN_LICENSE_GPL,
6950 
6951 	/* the function to invoke when plugin is loaded */
6952 	/* int (*)(void*); */
6953 	innodb_sys_tablespaces_init,
6954 
6955 	/* the function to invoke when plugin is unloaded */
6956 	/* int (*)(void*); */
6957 	i_s_common_deinit,
6958 
6959 	/* plugin version (for SHOW PLUGINS) */
6960 	/* unsigned int */
6961 	INNODB_VERSION_SHORT,
6962 
6963 	/* struct st_mysql_show_var* */
6964 	NULL,
6965 
6966 	/* struct st_mysql_sys_var** */
6967 	NULL,
6968 
6969         /* Maria extension */
6970 	INNODB_VERSION_STR,
6971         MariaDB_PLUGIN_MATURITY_STABLE,
6972 };
6973 
6974 /**  SYS_DATAFILES  ************************************************/
6975 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_DATAFILES */
6976 static ST_FIELD_INFO innodb_sys_datafiles_fields_info[]=
6977 {
6978 #define SYS_DATAFILES_SPACE		0
6979   {"SPACE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
6980    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
6981 #define SYS_DATAFILES_PATH		1
6982   {"PATH", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
6983   END_OF_ST_FIELD_INFO
6984 };
6985 
6986 /**********************************************************************//**
6987 Function to fill INFORMATION_SCHEMA.INNODB_SYS_DATAFILES with information
6988 collected by scanning SYS_DATAFILESS table.
6989 @return 0 on success */
6990 static
6991 int
i_s_dict_fill_sys_datafiles(THD * thd,ulint space,const char * path,TABLE * table_to_fill)6992 i_s_dict_fill_sys_datafiles(
6993 /*========================*/
6994 	THD*		thd,		/*!< in: thread */
6995 	ulint		space,		/*!< in: space ID */
6996 	const char*	path,		/*!< in: absolute path */
6997 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
6998 {
6999 	Field**		fields;
7000 
7001 	DBUG_ENTER("i_s_dict_fill_sys_datafiles");
7002 
7003 	fields = table_to_fill->field;
7004 
7005 	OK(field_store_ulint(fields[SYS_DATAFILES_SPACE], space));
7006 
7007 	OK(field_store_string(fields[SYS_DATAFILES_PATH], path));
7008 
7009 	OK(schema_table_store_record(thd, table_to_fill));
7010 
7011 	DBUG_RETURN(0);
7012 }
7013 /*******************************************************************//**
7014 Function to populate INFORMATION_SCHEMA.INNODB_SYS_DATAFILES table.
7015 Loop through each record in SYS_DATAFILES, and extract the column
7016 information and fill the INFORMATION_SCHEMA.INNODB_SYS_DATAFILES table.
7017 @return 0 on success */
7018 static
7019 int
i_s_sys_datafiles_fill_table(THD * thd,TABLE_LIST * tables,Item *)7020 i_s_sys_datafiles_fill_table(
7021 /*=========================*/
7022 	THD*		thd,	/*!< in: thread */
7023 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7024 	Item*		)	/*!< in: condition (not used) */
7025 {
7026 	btr_pcur_t	pcur;
7027 	const rec_t*	rec;
7028 	mem_heap_t*	heap;
7029 	mtr_t		mtr;
7030 
7031 	DBUG_ENTER("i_s_sys_datafiles_fill_table");
7032 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
7033 
7034 	/* deny access to user without PROCESS_ACL privilege */
7035 	if (check_global_access(thd, PROCESS_ACL)) {
7036 		DBUG_RETURN(0);
7037 	}
7038 
7039 	heap = mem_heap_create(1000);
7040 	mutex_enter(&dict_sys->mutex);
7041 	mtr_start(&mtr);
7042 
7043 	rec = dict_startscan_system(&pcur, &mtr, SYS_DATAFILES);
7044 
7045 	while (rec) {
7046 		const char*	err_msg;
7047 		ulint		space;
7048 		const char*	path;
7049 
7050 		/* Extract necessary information from a SYS_DATAFILES row */
7051 		err_msg = dict_process_sys_datafiles(
7052 			heap, rec, &space, &path);
7053 
7054 		mtr_commit(&mtr);
7055 		mutex_exit(&dict_sys->mutex);
7056 
7057 		if (!err_msg) {
7058 			i_s_dict_fill_sys_datafiles(
7059 				thd, space, path, tables->table);
7060 		} else {
7061 			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
7062 					    ER_CANT_FIND_SYSTEM_REC, "%s",
7063 					    err_msg);
7064 		}
7065 
7066 		mem_heap_empty(heap);
7067 
7068 		/* Get the next record */
7069 		mutex_enter(&dict_sys->mutex);
7070 		mtr_start(&mtr);
7071 		rec = dict_getnext_system(&pcur, &mtr);
7072 	}
7073 
7074 	mtr_commit(&mtr);
7075 	mutex_exit(&dict_sys->mutex);
7076 	mem_heap_free(heap);
7077 
7078 	DBUG_RETURN(0);
7079 }
7080 /*******************************************************************//**
7081 Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_DATAFILES
7082 @return 0 on success */
7083 static
7084 int
innodb_sys_datafiles_init(void * p)7085 innodb_sys_datafiles_init(
7086 /*======================*/
7087 	void*	p)	/*!< in/out: table schema object */
7088 {
7089 	ST_SCHEMA_TABLE*	schema;
7090 
7091 	DBUG_ENTER("innodb_sys_datafiles_init");
7092 
7093 	schema = (ST_SCHEMA_TABLE*) p;
7094 
7095 	schema->fields_info = innodb_sys_datafiles_fields_info;
7096 	schema->fill_table = i_s_sys_datafiles_fill_table;
7097 
7098 	DBUG_RETURN(0);
7099 }
7100 
7101 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_datafiles =
7102 {
7103 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7104 	/* int */
7105 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
7106 
7107 	/* pointer to type-specific plugin descriptor */
7108 	/* void* */
7109 	&i_s_info,
7110 
7111 	/* plugin name */
7112 	/* const char* */
7113 	"INNODB_SYS_DATAFILES",
7114 
7115 	/* plugin author (for SHOW PLUGINS) */
7116 	/* const char* */
7117 	plugin_author,
7118 
7119 	/* general descriptive text (for SHOW PLUGINS) */
7120 	/* const char* */
7121 	"InnoDB SYS_DATAFILES",
7122 
7123 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7124 	/* int */
7125 	PLUGIN_LICENSE_GPL,
7126 
7127 	/* the function to invoke when plugin is loaded */
7128 	/* int (*)(void*); */
7129 	innodb_sys_datafiles_init,
7130 
7131 	/* the function to invoke when plugin is unloaded */
7132 	/* int (*)(void*); */
7133 	i_s_common_deinit,
7134 
7135 	/* plugin version (for SHOW PLUGINS) */
7136 	/* unsigned int */
7137 	INNODB_VERSION_SHORT,
7138 
7139 	/* struct st_mysql_show_var* */
7140 	NULL,
7141 
7142 	/* struct st_mysql_sys_var** */
7143 	NULL,
7144 
7145         /* Maria extension */
7146 	INNODB_VERSION_STR,
7147         MariaDB_PLUGIN_MATURITY_STABLE,
7148 };
7149 
7150 /**  TABLESPACES_ENCRYPTION    ********************************************/
7151 /* Fields of the table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION */
7152 static ST_FIELD_INFO innodb_tablespaces_encryption_fields_info[]=
7153 {
7154 #define TABLESPACES_ENCRYPTION_SPACE	0
7155   {"SPACE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7156    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7157 #define TABLESPACES_ENCRYPTION_NAME		1
7158   {"NAME", MAX_FULL_NAME_LEN + 1, MYSQL_TYPE_STRING,
7159    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7160 #define TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME	2
7161   {"ENCRYPTION_SCHEME", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7162    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7163 #define TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS	3
7164   {"KEYSERVER_REQUESTS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7165    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7166 #define TABLESPACES_ENCRYPTION_MIN_KEY_VERSION	4
7167   {"MIN_KEY_VERSION", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7168    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7169 #define TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION	5
7170   {"CURRENT_KEY_VERSION", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7171    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7172 #define TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER	6
7173   {"KEY_ROTATION_PAGE_NUMBER", MY_INT64_NUM_DECIMAL_DIGITS,
7174    MYSQL_TYPE_LONGLONG,
7175    0, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7176 #define TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER 7
7177   {"KEY_ROTATION_MAX_PAGE_NUMBER", MY_INT64_NUM_DECIMAL_DIGITS,
7178    MYSQL_TYPE_LONGLONG,
7179    0, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7180 #define TABLESPACES_ENCRYPTION_CURRENT_KEY_ID	8
7181   {"CURRENT_KEY_ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7182    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7183 #define TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING 9
7184   {"ROTATING_OR_FLUSHING", 1, MYSQL_TYPE_LONG,
7185    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7186   END_OF_ST_FIELD_INFO
7187 };
7188 
7189 /**********************************************************************//**
7190 Function to fill INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION
7191 with information collected by scanning SYS_TABLESPACES table.
7192 @param[in]	thd		thread handle
7193 @param[in]	space		Tablespace
7194 @param[in]	table_to_fill	I_S table to fill
7195 @return 0 on success */
7196 static
7197 int
i_s_dict_fill_tablespaces_encryption(THD * thd,fil_space_t * space,TABLE * table_to_fill)7198 i_s_dict_fill_tablespaces_encryption(
7199 	THD*		thd,
7200 	fil_space_t*	space,
7201 	TABLE*		table_to_fill)
7202 {
7203 	Field**	fields;
7204 	struct fil_space_crypt_status_t status;
7205 
7206 	DBUG_ENTER("i_s_dict_fill_tablespaces_encryption");
7207 
7208 	fields = table_to_fill->field;
7209 
7210 	fil_space_crypt_get_status(space, &status);
7211 
7212 	/* If tablespace id does not match, we did not find
7213 	encryption information for this tablespace. */
7214 	if (!space->crypt_data || space->id != status.space) {
7215 		goto skip;
7216 	}
7217 
7218 	OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true));
7219 
7220 	OK(field_store_string(fields[TABLESPACES_ENCRYPTION_NAME],
7221 			      space->name));
7222 
7223 	OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store(
7224 		   status.scheme, true));
7225 	OK(fields[TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS]->store(
7226 		   status.keyserver_requests, true));
7227 	OK(fields[TABLESPACES_ENCRYPTION_MIN_KEY_VERSION]->store(
7228 		   status.min_key_version, true));
7229 	OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION]->store(
7230 		   status.current_key_version, true));
7231 	OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_ID]->store(
7232 		   status.key_id, true));
7233 	OK(fields[TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING]->store(
7234 		   status.rotating || status.flushing, true));
7235 
7236 	if (status.rotating) {
7237 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->set_notnull();
7238 		OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->store(
7239 			   status.rotate_next_page_number, true));
7240 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->set_notnull();
7241 		OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->store(
7242 			   status.rotate_max_page_number, true));
7243 	} else {
7244 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]
7245 			->set_null();
7246 		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]
7247 			->set_null();
7248 	}
7249 
7250 	OK(schema_table_store_record(thd, table_to_fill));
7251 
7252 skip:
7253 	DBUG_RETURN(0);
7254 }
7255 /*******************************************************************//**
7256 Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
7257 Loop through each record in TABLESPACES_ENCRYPTION, and extract the column
7258 information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
7259 @return 0 on success */
7260 static
7261 int
i_s_tablespaces_encryption_fill_table(THD * thd,TABLE_LIST * tables,Item *)7262 i_s_tablespaces_encryption_fill_table(
7263 /*===========================*/
7264 	THD*		thd,	/*!< in: thread */
7265 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7266 	Item*		)	/*!< in: condition (not used) */
7267 {
7268 	DBUG_ENTER("i_s_tablespaces_encryption_fill_table");
7269 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
7270 
7271 	/* deny access to user without PROCESS_ACL privilege */
7272 	if (check_global_access(thd, PROCESS_ACL)) {
7273 		DBUG_RETURN(0);
7274 	}
7275 
7276 	mutex_enter(&fil_system.mutex);
7277 
7278 	for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list);
7279 	     space; space = UT_LIST_GET_NEXT(space_list, space)) {
7280 		if (space->purpose == FIL_TYPE_TABLESPACE
7281 		    && space->acquire()) {
7282 			mutex_exit(&fil_system.mutex);
7283 			if (int err = i_s_dict_fill_tablespaces_encryption(
7284 				    thd, space, tables->table)) {
7285 				space->release();
7286 				DBUG_RETURN(err);
7287 			}
7288 			mutex_enter(&fil_system.mutex);
7289 			space->release();
7290 		}
7291 	}
7292 
7293 	mutex_exit(&fil_system.mutex);
7294 	DBUG_RETURN(0);
7295 }
7296 /*******************************************************************//**
7297 Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION
7298 @return 0 on success */
7299 static
7300 int
innodb_tablespaces_encryption_init(void * p)7301 innodb_tablespaces_encryption_init(
7302 /*========================*/
7303 	void*	p)	/*!< in/out: table schema object */
7304 {
7305 	ST_SCHEMA_TABLE*	schema;
7306 
7307 	DBUG_ENTER("innodb_tablespaces_encryption_init");
7308 
7309 	schema = (ST_SCHEMA_TABLE*) p;
7310 
7311 	schema->fields_info = innodb_tablespaces_encryption_fields_info;
7312 	schema->fill_table = i_s_tablespaces_encryption_fill_table;
7313 
7314 	DBUG_RETURN(0);
7315 }
7316 
7317 UNIV_INTERN struct st_maria_plugin	i_s_innodb_tablespaces_encryption =
7318 {
7319 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7320 	/* int */
7321 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
7322 
7323 	/* pointer to type-specific plugin descriptor */
7324 	/* void* */
7325 	&i_s_info,
7326 
7327 	/* plugin name */
7328 	/* const char* */
7329 	"INNODB_TABLESPACES_ENCRYPTION",
7330 
7331 	/* plugin author (for SHOW PLUGINS) */
7332 	/* const char* */
7333 	"Google Inc",
7334 
7335 	/* general descriptive text (for SHOW PLUGINS) */
7336 	/* const char* */
7337 	"InnoDB TABLESPACES_ENCRYPTION",
7338 
7339 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7340 	/* int */
7341 	PLUGIN_LICENSE_BSD,
7342 
7343 	/* the function to invoke when plugin is loaded */
7344 	/* int (*)(void*); */
7345 	innodb_tablespaces_encryption_init,
7346 
7347 	/* the function to invoke when plugin is unloaded */
7348 	/* int (*)(void*); */
7349 	i_s_common_deinit,
7350 
7351 	/* plugin version (for SHOW PLUGINS) */
7352 	/* unsigned int */
7353 	INNODB_VERSION_SHORT,
7354 
7355 	/* struct st_mysql_show_var* */
7356 	NULL,
7357 
7358 	/* struct st_mysql_sys_var** */
7359 	NULL,
7360 
7361 	/* Maria extension */
7362 	INNODB_VERSION_STR,
7363 	MariaDB_PLUGIN_MATURITY_STABLE
7364 };
7365 
7366 /**  TABLESPACES_SCRUBBING    ********************************************/
7367 /* Fields of the table INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING */
7368 static ST_FIELD_INFO innodb_tablespaces_scrubbing_fields_info[]=
7369 {
7370 #define TABLESPACES_SCRUBBING_SPACE	0
7371   {"SPACE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7372    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7373 #define TABLESPACES_SCRUBBING_NAME		1
7374   {"NAME", MAX_FULL_NAME_LEN + 1, MYSQL_TYPE_STRING,
7375    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7376 #define TABLESPACES_SCRUBBING_COMPRESSED	2
7377   {"COMPRESSED", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7378    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7379 #define TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED	3
7380   {"LAST_SCRUB_COMPLETED", 0, MYSQL_TYPE_DATETIME,
7381    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7382 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED	4
7383   {"CURRENT_SCRUB_STARTED", 0, MYSQL_TYPE_DATETIME,
7384    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7385 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS	5
7386   {"CURRENT_SCRUB_ACTIVE_THREADS", MY_INT32_NUM_DECIMAL_DIGITS,
7387    MYSQL_TYPE_LONG,
7388    0, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7389 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER	6
7390   {"CURRENT_SCRUB_PAGE_NUMBER", MY_INT64_NUM_DECIMAL_DIGITS,
7391    MYSQL_TYPE_LONGLONG,
7392    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7393 #define TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER	7
7394   {"CURRENT_SCRUB_MAX_PAGE_NUMBER", MY_INT64_NUM_DECIMAL_DIGITS,
7395    MYSQL_TYPE_LONGLONG,
7396    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7397   END_OF_ST_FIELD_INFO
7398 };
7399 
7400 /**********************************************************************//**
7401 Function to fill INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING
7402 with information collected by scanning SYS_TABLESPACES table and
7403 fil_space.
7404 @param[in]	thd		Thread handle
7405 @param[in]	space		Tablespace
7406 @param[in]	table_to_fill	I_S table
7407 @return 0 on success */
7408 static
7409 int
i_s_dict_fill_tablespaces_scrubbing(THD * thd,fil_space_t * space,TABLE * table_to_fill)7410 i_s_dict_fill_tablespaces_scrubbing(
7411 	THD*		thd,
7412 	fil_space_t*	space,
7413 	TABLE*		table_to_fill)
7414 {
7415 	Field**	fields;
7416         struct fil_space_scrub_status_t status;
7417 
7418 	DBUG_ENTER("i_s_dict_fill_tablespaces_scrubbing");
7419 
7420 	fields = table_to_fill->field;
7421 
7422 	fil_space_get_scrub_status(space, &status);
7423 
7424 	OK(fields[TABLESPACES_SCRUBBING_SPACE]->store(space->id, true));
7425 
7426 	OK(field_store_string(fields[TABLESPACES_SCRUBBING_NAME],
7427 			      space->name));
7428 
7429 	OK(fields[TABLESPACES_SCRUBBING_COMPRESSED]->store(
7430 		   status.compressed ? 1 : 0, true));
7431 
7432 	if (status.last_scrub_completed == 0) {
7433 		fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED]->set_null();
7434 	} else {
7435 		fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED]
7436 			->set_notnull();
7437 		OK(field_store_time_t(
7438 			   fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED],
7439 			   status.last_scrub_completed));
7440 	}
7441 
7442 	int field_numbers[] = {
7443 		TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED,
7444 		TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS,
7445 		TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER,
7446 		TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER };
7447 
7448 	if (status.scrubbing) {
7449 		for (uint i = 0; i < array_elements(field_numbers); i++) {
7450 			fields[field_numbers[i]]->set_notnull();
7451 		}
7452 
7453 		OK(field_store_time_t(
7454 			   fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED],
7455 			   status.current_scrub_started));
7456 		OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS]
7457 		   ->store(status.current_scrub_active_threads, true));
7458 		OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER]
7459 		   ->store(status.current_scrub_page_number, true));
7460 		OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER]
7461 		   ->store(status.current_scrub_max_page_number, true));
7462 	} else {
7463 		for (uint i = 0; i < array_elements(field_numbers); i++) {
7464 			fields[field_numbers[i]]->set_null();
7465 		}
7466 	}
7467 
7468 	OK(schema_table_store_record(thd, table_to_fill));
7469 
7470 	DBUG_RETURN(0);
7471 }
7472 /*******************************************************************//**
7473 Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING table.
7474 Loop through each record in TABLESPACES_SCRUBBING, and extract the column
7475 information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING table.
7476 @return 0 on success */
7477 static
7478 int
i_s_tablespaces_scrubbing_fill_table(THD * thd,TABLE_LIST * tables,Item *)7479 i_s_tablespaces_scrubbing_fill_table(
7480 /*===========================*/
7481 	THD*		thd,	/*!< in: thread */
7482 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7483 	Item*		)	/*!< in: condition (not used) */
7484 {
7485 	DBUG_ENTER("i_s_tablespaces_scrubbing_fill_table");
7486 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
7487 
7488 	/* deny access to user without SUPER_ACL privilege */
7489 	if (check_global_access(thd, SUPER_ACL)) {
7490 		DBUG_RETURN(0);
7491 	}
7492 
7493 	mutex_enter(&fil_system.mutex);
7494 
7495 	for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list);
7496 	     space; space = UT_LIST_GET_NEXT(space_list, space)) {
7497 		if (space->purpose == FIL_TYPE_TABLESPACE
7498 		    && space->acquire()) {
7499 			mutex_exit(&fil_system.mutex);
7500 			if (int err = i_s_dict_fill_tablespaces_scrubbing(
7501 				    thd, space, tables->table)) {
7502 				space->release();
7503 				DBUG_RETURN(err);
7504 			}
7505 			mutex_enter(&fil_system.mutex);
7506 			space->release();
7507 		}
7508 	}
7509 
7510 	mutex_exit(&fil_system.mutex);
7511 	DBUG_RETURN(0);
7512 }
7513 /*******************************************************************//**
7514 Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING
7515 @return 0 on success */
7516 static
7517 int
innodb_tablespaces_scrubbing_init(void * p)7518 innodb_tablespaces_scrubbing_init(
7519 /*========================*/
7520 	void*	p)	/*!< in/out: table schema object */
7521 {
7522 	ST_SCHEMA_TABLE*	schema;
7523 
7524 	DBUG_ENTER("innodb_tablespaces_scrubbing_init");
7525 
7526 	schema = (ST_SCHEMA_TABLE*) p;
7527 
7528 	schema->fields_info = innodb_tablespaces_scrubbing_fields_info;
7529 	schema->fill_table = i_s_tablespaces_scrubbing_fill_table;
7530 
7531 	DBUG_RETURN(0);
7532 }
7533 
7534 UNIV_INTERN struct st_maria_plugin	i_s_innodb_tablespaces_scrubbing =
7535 {
7536 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7537 	/* int */
7538 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
7539 
7540 	/* pointer to type-specific plugin descriptor */
7541 	/* void* */
7542 	&i_s_info,
7543 
7544 	/* plugin name */
7545 	/* const char* */
7546 	"INNODB_TABLESPACES_SCRUBBING",
7547 
7548 	/* plugin author (for SHOW PLUGINS) */
7549 	/* const char* */
7550 	"Google Inc",
7551 
7552 	/* general descriptive text (for SHOW PLUGINS) */
7553 	/* const char* */
7554 	"InnoDB TABLESPACES_SCRUBBING",
7555 
7556 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7557 	/* int */
7558 	PLUGIN_LICENSE_BSD,
7559 
7560 	/* the function to invoke when plugin is loaded */
7561 	/* int (*)(void*); */
7562 	innodb_tablespaces_scrubbing_init,
7563 
7564 	/* the function to invoke when plugin is unloaded */
7565 	/* int (*)(void*); */
7566 	i_s_common_deinit,
7567 
7568 	/* plugin version (for SHOW PLUGINS) */
7569 	/* unsigned int */
7570 	INNODB_VERSION_SHORT,
7571 
7572 	/* struct st_mysql_show_var* */
7573 	NULL,
7574 
7575 	/* struct st_mysql_sys_var** */
7576 	NULL,
7577 
7578 	/* Maria extension */
7579 	INNODB_VERSION_STR,
7580 	MariaDB_PLUGIN_MATURITY_STABLE
7581 };
7582 
7583 /**  INNODB_MUTEXES  *********************************************/
7584 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_MUTEXES */
7585 static ST_FIELD_INFO innodb_mutexes_fields_info[]=
7586 {
7587 #define MUTEXES_NAME			0
7588   {"NAME", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE},
7589 #define MUTEXES_CREATE_FILE		1
7590   {"CREATE_FILE", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING,
7591    0, 0, "", SKIP_OPEN_TABLE},
7592 #define MUTEXES_CREATE_LINE		2
7593   {"CREATE_LINE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7594    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7595 #define MUTEXES_OS_WAITS		3
7596   {"OS_WAITS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7597    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7598   END_OF_ST_FIELD_INFO
7599 };
7600 
7601 /*******************************************************************//**
7602 Function to populate INFORMATION_SCHEMA.INNODB_MUTEXES table.
7603 Loop through each record in mutex and rw_lock lists, and extract the column
7604 information and fill the INFORMATION_SCHEMA.INNODB_MUTEXES table.
7605 @return 0 on success */
7606 static
7607 int
i_s_innodb_mutexes_fill_table(THD * thd,TABLE_LIST * tables,Item *)7608 i_s_innodb_mutexes_fill_table(
7609 /*==========================*/
7610 	THD*		thd,	/*!< in: thread */
7611 	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
7612 	Item*		)	/*!< in: condition (not used) */
7613 {
7614 	rw_lock_t*	lock;
7615 	ulint		block_lock_oswait_count = 0;
7616 	rw_lock_t*	block_lock = NULL;
7617 	Field**		fields = tables->table->field;
7618 
7619 	DBUG_ENTER("i_s_innodb_mutexes_fill_table");
7620 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
7621 
7622 	/* deny access to user without PROCESS_ACL privilege */
7623 	if (check_global_access(thd, PROCESS_ACL)) {
7624 		DBUG_RETURN(0);
7625 	}
7626 
7627 	// mutex_enter(&mutex_list_mutex);
7628 
7629 #ifdef JAN_TODO_FIXME
7630 	ib_mutex_t*	mutex;
7631 	ulint		block_mutex_oswait_count = 0;
7632 	ib_mutex_t*	block_mutex = NULL;
7633 	for (mutex = UT_LIST_GET_FIRST(os_mutex_list); mutex != NULL;
7634 	     mutex = UT_LIST_GET_NEXT(list, mutex)) {
7635 		if (mutex->count_os_wait == 0) {
7636 			continue;
7637 		}
7638 
7639 		if (buf_pool_is_block_mutex(mutex)) {
7640 			block_mutex = mutex;
7641 			block_mutex_oswait_count += mutex->count_os_wait;
7642 			continue;
7643 		}
7644 
7645 		OK(field_store_string(fields[MUTEXES_NAME], mutex->cmutex_name));
7646 		OK(field_store_string(fields[MUTEXES_CREATE_FILE],
7647 				      innobase_basename(mutex->cfile_name)));
7648 		OK(fields[MUTEXES_CREATE_LINE]->store(lock->cline, true));
7649 		fields[MUTEXES_CREATE_LINE]->set_notnull();
7650 		OK(fields[MUTEXES_OS_WAITS]->store(lock->count_os_wait, true));
7651 		fields[MUTEXES_OS_WAITS]->set_notnull();
7652 		OK(schema_table_store_record(thd, tables->table));
7653 	}
7654 
7655 	if (block_mutex) {
7656 		char buf1[IO_SIZE];
7657 
7658 		snprintf(buf1, sizeof buf1, "combined %s",
7659 			 innobase_basename(block_mutex->cfile_name));
7660 
7661 		OK(field_store_string(fields[MUTEXES_NAME], block_mutex->cmutex_name));
7662 		OK(field_store_string(fields[MUTEXES_CREATE_FILE], buf1));
7663 		OK(fields[MUTEXES_CREATE_LINE]->store(block_mutex->cline, true));
7664 		fields[MUTEXES_CREATE_LINE]->set_notnull();
7665 		OK(field_store_ulint(fields[MUTEXES_OS_WAITS], (longlong)block_mutex_oswait_count));
7666 		OK(schema_table_store_record(thd, tables->table));
7667 	}
7668 
7669 	mutex_exit(&mutex_list_mutex);
7670 #endif /* JAN_TODO_FIXME */
7671 
7672 	{
7673 		struct Locking
7674 		{
7675 			Locking() { mutex_enter(&rw_lock_list_mutex); }
7676 			~Locking() { mutex_exit(&rw_lock_list_mutex); }
7677 		} locking;
7678 
7679 		char lock_name[sizeof "buf0dump.cc:12345"];
7680 
7681 		for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
7682 		     lock = UT_LIST_GET_NEXT(list, lock)) {
7683 			if (lock->count_os_wait == 0) {
7684 				continue;
7685 			}
7686 
7687 			if (buf_pool_is_block_lock(lock)) {
7688 				block_lock = lock;
7689 				block_lock_oswait_count += lock->count_os_wait;
7690 				continue;
7691 			}
7692 
7693 			const char* basename = innobase_basename(
7694 				lock->cfile_name);
7695 
7696 			snprintf(lock_name, sizeof lock_name, "%s:%u",
7697 				 basename, lock->cline);
7698 
7699 			OK(field_store_string(fields[MUTEXES_NAME],
7700 					      lock_name));
7701 			OK(field_store_string(fields[MUTEXES_CREATE_FILE],
7702 					      basename));
7703 			OK(fields[MUTEXES_CREATE_LINE]->store(lock->cline,
7704 							      true));
7705 			fields[MUTEXES_CREATE_LINE]->set_notnull();
7706 			OK(fields[MUTEXES_OS_WAITS]->store(lock->count_os_wait,
7707 							   true));
7708 			fields[MUTEXES_OS_WAITS]->set_notnull();
7709 			OK(schema_table_store_record(thd, tables->table));
7710 		}
7711 
7712 		if (block_lock) {
7713 			char buf1[IO_SIZE];
7714 
7715 			snprintf(buf1, sizeof buf1, "combined %s",
7716 				 innobase_basename(block_lock->cfile_name));
7717 
7718 			OK(field_store_string(fields[MUTEXES_NAME],
7719 					      "buf_block_t::lock"));
7720 			OK(field_store_string(fields[MUTEXES_CREATE_FILE],
7721 					      buf1));
7722 			OK(fields[MUTEXES_CREATE_LINE]->store(block_lock->cline,
7723 							      true));
7724 			fields[MUTEXES_CREATE_LINE]->set_notnull();
7725 			OK(fields[MUTEXES_OS_WAITS]->store(
7726 				   block_lock_oswait_count, true));
7727 			fields[MUTEXES_OS_WAITS]->set_notnull();
7728 			OK(schema_table_store_record(thd, tables->table));
7729 		}
7730 	}
7731 
7732 	DBUG_RETURN(0);
7733 }
7734 
7735 /*******************************************************************//**
7736 Bind the dynamic table INFORMATION_SCHEMA.INNODB_MUTEXES
7737 @return 0 on success */
7738 static
7739 int
innodb_mutexes_init(void * p)7740 innodb_mutexes_init(
7741 /*================*/
7742 	void*	p)	/*!< in/out: table schema object */
7743 {
7744 	ST_SCHEMA_TABLE*	schema;
7745 
7746 	DBUG_ENTER("innodb_mutexes_init");
7747 
7748 	schema = (ST_SCHEMA_TABLE*) p;
7749 
7750 	schema->fields_info = innodb_mutexes_fields_info;
7751 	schema->fill_table = i_s_innodb_mutexes_fill_table;
7752 
7753 	DBUG_RETURN(0);
7754 }
7755 
7756 UNIV_INTERN struct st_maria_plugin	i_s_innodb_mutexes =
7757 {
7758 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7759 	/* int */
7760 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
7761 
7762 	/* pointer to type-specific plugin descriptor */
7763 	/* void* */
7764 	&i_s_info,
7765 
7766 	/* plugin name */
7767 	/* const char* */
7768 	"INNODB_MUTEXES",
7769 
7770 	/* plugin author (for SHOW PLUGINS) */
7771 	/* const char* */
7772 	plugin_author,
7773 
7774 	/* general descriptive text (for SHOW PLUGINS) */
7775 	/* const char* */
7776 	"InnoDB SYS_DATAFILES",
7777 
7778 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7779 	/* int */
7780 	PLUGIN_LICENSE_GPL,
7781 
7782 	/* the function to invoke when plugin is loaded */
7783 	/* int (*)(void*); */
7784 	innodb_mutexes_init,
7785 
7786 	/* the function to invoke when plugin is unloaded */
7787 	/* int (*)(void*); */
7788 	i_s_common_deinit,
7789 
7790 	/* plugin version (for SHOW PLUGINS) */
7791 	/* unsigned int */
7792 	INNODB_VERSION_SHORT,
7793 
7794 	/* struct st_mysql_show_var* */
7795 	NULL,
7796 
7797 	/* struct st_mysql_sys_var** */
7798 	NULL,
7799 
7800         /* Maria extension */
7801 	INNODB_VERSION_STR,
7802         MariaDB_PLUGIN_MATURITY_STABLE,
7803 };
7804 
7805 /**  SYS_SEMAPHORE_WAITS  ************************************************/
7806 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_SEMAPHORE_WAITS */
7807 static ST_FIELD_INFO innodb_sys_semaphore_waits_fields_info[]=
7808 {
7809   {"THREAD_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7810    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7811   {"OBJECT_NAME", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING,
7812    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7813   {"FILE", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING,
7814    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7815   {"LINE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7816    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7817   {"WAIT_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7818    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7819   {"WAIT_OBJECT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7820    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7821   {"WAIT_TYPE", 16, MYSQL_TYPE_STRING,
7822    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7823   {"HOLDER_THREAD_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7824    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7825   {"HOLDER_FILE", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING,
7826    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7827   {"HOLDER_LINE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7828    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7829   {"CREATED_FILE", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING,
7830    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7831   {"CREATED_LINE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7832    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7833   {"WRITER_THREAD", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7834    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7835   {"RESERVATION_MODE", 16, MYSQL_TYPE_STRING,
7836    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7837   {"READERS", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7838    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7839   {"WAITERS_FLAG", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7840    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7841   {"LOCK_WORD", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
7842    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7843   {"LAST_WRITER_FILE", OS_FILE_MAX_PATH, MYSQL_TYPE_STRING,
7844    0, MY_I_S_MAYBE_NULL, "", SKIP_OPEN_TABLE},
7845   {"LAST_WRITER_LINE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7846    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7847   {"OS_WAIT_COUNT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
7848    0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE},
7849   END_OF_ST_FIELD_INFO
7850 };
7851 
7852 
7853 /*******************************************************************//**
7854 Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_SEMAPHORE_WAITS
7855 @return 0 on success */
7856 static
7857 int
innodb_sys_semaphore_waits_init(void * p)7858 innodb_sys_semaphore_waits_init(
7859 /*============================*/
7860 	void*	p)	/*!< in/out: table schema object */
7861 {
7862 	ST_SCHEMA_TABLE*	schema;
7863 
7864 	DBUG_ENTER("innodb_sys_semaphore_waits_init");
7865 
7866 	schema = (ST_SCHEMA_TABLE*) p;
7867 
7868 	schema->fields_info = innodb_sys_semaphore_waits_fields_info;
7869 	schema->fill_table = sync_arr_fill_sys_semphore_waits_table;
7870 
7871 	DBUG_RETURN(0);
7872 }
7873 
7874 UNIV_INTERN struct st_maria_plugin	i_s_innodb_sys_semaphore_waits =
7875 {
7876 	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
7877 	/* int */
7878 	MYSQL_INFORMATION_SCHEMA_PLUGIN,
7879 
7880 	/* pointer to type-specific plugin descriptor */
7881 	/* void* */
7882 	&i_s_info,
7883 
7884 	/* plugin name */
7885 	/* const char* */
7886 	"INNODB_SYS_SEMAPHORE_WAITS",
7887 
7888 	/* plugin author (for SHOW PLUGINS) */
7889 	/* const char* */
7890 	maria_plugin_author,
7891 
7892 	/* general descriptive text (for SHOW PLUGINS) */
7893 	/* const char* */
7894 	"InnoDB SYS_SEMAPHORE_WAITS",
7895 
7896 	/* the plugin license (PLUGIN_LICENSE_XXX) */
7897 	/* int */
7898 	PLUGIN_LICENSE_GPL,
7899 
7900 	/* the function to invoke when plugin is loaded */
7901 	/* int (*)(void*); */
7902 	innodb_sys_semaphore_waits_init,
7903 
7904 	/* the function to invoke when plugin is unloaded */
7905 	/* int (*)(void*); */
7906 	i_s_common_deinit,
7907 
7908 	/* plugin version (for SHOW PLUGINS) */
7909 	/* unsigned int */
7910 	INNODB_VERSION_SHORT,
7911 
7912 	/* struct st_mysql_show_var* */
7913 	NULL,
7914 
7915 	/* struct st_mysql_sys_var** */
7916 	NULL,
7917 
7918         /* Maria extension */
7919 	INNODB_VERSION_STR,
7920         MariaDB_PLUGIN_MATURITY_STABLE,
7921 };
7922