i_s.cc 181 KB
Newer Older
1 2
/*****************************************************************************

Sergei Golubchik's avatar
Sergei Golubchik committed
3
Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
Marko Mäkelä's avatar
Marko Mäkelä committed
4
Copyright (c) 2014, 2021, MariaDB Corporation.
5 6 7 8 9 10 11 12 13 14

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

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.,
Vicențiu Ciorbaru's avatar
Vicențiu Ciorbaru committed
16
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 18 19

*****************************************************************************/

20 21
/**************************************************//**
@file handler/i_s.cc
22 23 24 25 26
InnoDB INFORMATION SCHEMA tables interface to MySQL.

Created July 18, 2007 Vasil Dimov
*******************************************************/

27
#include "univ.i"
28 29
#include <mysql_version.h>
#include <field.h>
30

31
#include <sql_acl.h>
32 33
#include <sql_show.h>
#include <sql_time.h>
34 35

#include "i_s.h"
36
#include "btr0pcur.h"
37
#include "btr0types.h"
38 39 40 41 42
#include "dict0dict.h"
#include "dict0load.h"
#include "buf0buddy.h"
#include "buf0buf.h"
#include "ibuf0ibuf.h"
43 44
#include "dict0mem.h"
#include "dict0types.h"
45
#include "srv0start.h"
46
#include "trx0i_s.h"
47
#include "trx0trx.h"
48 49 50 51 52 53 54 55
#include "srv0mon.h"
#include "fut0fut.h"
#include "pars0pars.h"
#include "fts0types.h"
#include "fts0opt.h"
#include "fts0priv.h"
#include "btr0btr.h"
#include "page0zip.h"
56 57
#include "fil0fil.h"
#include "fil0crypt.h"
58
#include "dict0crea.h"
59
#include "scope.h"
60

61
/** The latest successfully looked up innodb_fts_aux_table */
62
table_id_t innodb_ft_aux_table_id;
63

64 65
/** structure associates a name string with a file page type and/or buffer
page state. */
66
struct buf_page_desc_t{
67 68 69 70 71 72 73 74 75
	const char*	type_str;	/*!< String explain the page
					type/state */
	ulint		type_value;	/*!< Page type or page state */
};

/** We also define I_S_PAGE_TYPE_INDEX as the Index Page's position
in i_s_page_type[] array */
#define I_S_PAGE_TYPE_INDEX		1

76 77 78 79 80 81 82 83 84 85 86 87 88
/** Any unassigned FIL_PAGE_TYPE will be treated as unknown. */
#define	I_S_PAGE_TYPE_UNKNOWN		FIL_PAGE_TYPE_UNKNOWN

/** R-tree index page */
#define	I_S_PAGE_TYPE_RTREE		(FIL_PAGE_TYPE_LAST + 1)

/** Change buffer B-tree page */
#define	I_S_PAGE_TYPE_IBUF		(FIL_PAGE_TYPE_LAST + 2)

#define I_S_PAGE_TYPE_LAST		I_S_PAGE_TYPE_IBUF

#define I_S_PAGE_TYPE_BITS		4

89
/** Name string for File Page Types */
90
static buf_page_desc_t	i_s_page_type[] = {
91 92 93 94 95 96 97 98 99 100 101 102 103
	{"ALLOCATED", FIL_PAGE_TYPE_ALLOCATED},
	{"INDEX", FIL_PAGE_INDEX},
	{"UNDO_LOG", FIL_PAGE_UNDO_LOG},
	{"INODE", FIL_PAGE_INODE},
	{"IBUF_FREE_LIST", FIL_PAGE_IBUF_FREE_LIST},
	{"IBUF_BITMAP", FIL_PAGE_IBUF_BITMAP},
	{"SYSTEM", FIL_PAGE_TYPE_SYS},
	{"TRX_SYSTEM", FIL_PAGE_TYPE_TRX_SYS},
	{"FILE_SPACE_HEADER", FIL_PAGE_TYPE_FSP_HDR},
	{"EXTENT_DESCRIPTOR", FIL_PAGE_TYPE_XDES},
	{"BLOB", FIL_PAGE_TYPE_BLOB},
	{"COMPRESSED_BLOB", FIL_PAGE_TYPE_ZBLOB},
	{"COMPRESSED_BLOB2", FIL_PAGE_TYPE_ZBLOB2},
104 105
	{"UNKNOWN", I_S_PAGE_TYPE_UNKNOWN},
	{"RTREE_INDEX", I_S_PAGE_TYPE_RTREE},
106
	{"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
107
	{"PAGE COMPRESSED", FIL_PAGE_PAGE_COMPRESSED},
108
	{"PAGE COMPRESSED AND ENCRYPTED", FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED},
109 110 111 112 113
};

/** This structure defines information we will fetch from pages
currently cached in the buffer pool. It will be used to populate
table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE */
114
struct buf_page_info_t{
115
	ulint		block_id;	/*!< Buffer Pool block ID */
116 117
	/** page identifier */
	page_id_t	id;
118 119
	unsigned	access_time:32;	/*!< Time of first access */
	unsigned	io_fix:2;	/*!< type of pending I/O operation */
120
	uint32_t	fix_count;	/*!< Count of how manyfold this block
121
					is bufferfixed */
122
#ifdef BTR_CUR_HASH_ADAPT
123 124
	unsigned	hashed:1;	/*!< Whether hash index has been
					built on this page */
125
#endif /* BTR_CUR_HASH_ADAPT */
126
	unsigned	is_old:1;	/*!< TRUE if the block is in the old
127
					blocks in buf_pool.LRU_old */
128
	unsigned	freed_page_clock:31; /*!< the value of
129
					buf_pool.freed_page_clock */
130 131
	unsigned	zip_ssize:PAGE_ZIP_SSIZE_BITS;
					/*!< Compressed page size */
132
	unsigned	page_state:3; /*!< Page state */
133
	unsigned	page_type:I_S_PAGE_TYPE_BITS;	/*!< Page type */
134 135 136 137 138 139 140 141 142 143 144
	unsigned	num_recs:UNIV_PAGE_SIZE_SHIFT_MAX-2;
					/*!< Number of records on Page */
	unsigned	data_size:UNIV_PAGE_SIZE_SHIFT_MAX;
					/*!< Sum of the sizes of the records */
	lsn_t		newest_mod;	/*!< Log sequence number of
					the youngest modification */
	lsn_t		oldest_mod;	/*!< Log sequence number of
					the oldest modification */
	index_id_t	index_id;	/*!< Index ID if a index page */
};

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
/*
Use the following types mapping:

C type	ST_FIELD_INFO::field_type
---------------------------------
long			MYSQL_TYPE_LONGLONG
(field_length=MY_INT64_NUM_DECIMAL_DIGITS)

long unsigned		MYSQL_TYPE_LONGLONG
(field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)

char*			MYSQL_TYPE_STRING
(field_length=n)

float			MYSQL_TYPE_FLOAT
(field_length=0 is ignored)

void*			MYSQL_TYPE_LONGLONG
(field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)

boolean (if else)	MYSQL_TYPE_LONG
(field_length=1)

time_t			MYSQL_TYPE_DATETIME
(field_length=0 ignored)
---------------------------------
*/

173
/*******************************************************************//**
174 175 176
Common function to fill any of the dynamic tables:
INFORMATION_SCHEMA.innodb_trx
INFORMATION_SCHEMA.innodb_locks
177
INFORMATION_SCHEMA.innodb_lock_waits
178
@return 0 on success */
179 180 181 182
static
int
trx_i_s_common_fill_table(
/*======================*/
183 184
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
185
	Item*		);	/*!< in: condition (not used) */
186

187
/*******************************************************************//**
188
Unbind a dynamic INFORMATION_SCHEMA table.
189
@return 0 on success */
190 191
static
int
192 193
i_s_common_deinit(
/*==============*/
194
	void*	p);	/*!< in/out: table schema object */
195
/*******************************************************************//**
196
Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
197
field.
198
@return 0 on success */
199 200 201 202
static
int
field_store_time_t(
/*===============*/
203 204
	Field*	field,	/*!< in/out: target field for storage */
	time_t	time)	/*!< in: value to store */
205 206 207 208
{
	MYSQL_TIME	my_time;
	struct tm	tm_time;

209
	if (time) {
210
#if 0
211 212 213 214
		/* use this if you are sure that `variables' and `time_zone'
		are always initialized */
		thd->variables.time_zone->gmt_sec_to_TIME(
			&my_time, (my_time_t) time);
215
#else
216 217 218
		localtime_r(&time, &tm_time);
		localtime_to_TIME(&my_time, &tm_time);
		my_time.time_type = MYSQL_TIMESTAMP_DATETIME;
219
#endif
220 221 222
	} else {
		memset(&my_time, 0, sizeof(my_time));
	}
223

224 225 226
	/* JAN: TODO: MySQL 5.7
	return(field->store_time(&my_time, MYSQL_TIMESTAMP_DATETIME));
	*/
227
	return(field->store_time(&my_time));
228 229
}

230
/*******************************************************************//**
231
Auxiliary function to store char* value in MYSQL_TYPE_STRING field.
232
@return 0 on success */
233
static
234 235 236
int
field_store_string(
/*===============*/
237 238
	Field*		field,	/*!< in/out: target field for storage */
	const char*	str)	/*!< in: NUL-terminated utf-8 string,
239 240
				or NULL */
{
241
	if (!str) {
242
		field->set_null();
243
		return 0;
244 245 246
	}

	field->set_notnull();
247
	return field->store(str, uint(strlen(str)), system_charset_info);
248 249
}

250 251 252 253 254 255
#ifdef BTR_CUR_HASH_ADAPT
# define I_S_AHI 1 /* Include the IS_HASHED column */
#else
# define I_S_AHI 0 /* Omit the IS_HASHED column */
#endif

256 257 258 259 260 261 262 263 264 265
static const LEX_CSTRING isolation_level_values[] =
{
	{ STRING_WITH_LEN("READ UNCOMMITTED") },
	{ STRING_WITH_LEN("READ COMMITTED") },
	{ STRING_WITH_LEN("REPEATABLE READ") },
	{ STRING_WITH_LEN("SERIALIZABLE") }
};

static TypelibBuffer<4> isolation_level_values_typelib(isolation_level_values);

266 267
namespace Show {

268 269 270 271
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
static ST_FIELD_INFO	innodb_trx_fields_info[] =
{
#define IDX_TRX_ID		0
272
  Column("trx_id", ULonglong(), NOT_NULL),
273

vasil's avatar
vasil committed
274
#define IDX_TRX_STATE		1
Marko Mäkelä's avatar
Marko Mäkelä committed
275
  Column("trx_state", Varchar(13), NOT_NULL),
276

vasil's avatar
vasil committed
277
#define IDX_TRX_STARTED		2
278
  Column("trx_started", Datetime(0), NOT_NULL),
279

vasil's avatar
vasil committed
280
#define IDX_TRX_REQUESTED_LOCK_ID	3
281 282
  Column("trx_requested_lock_id",
         Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NULLABLE),
283

vasil's avatar
vasil committed
284
#define IDX_TRX_WAIT_STARTED	4
285
 Column("trx_wait_started", Datetime(0), NULLABLE),
286

vasil's avatar
vasil committed
287
#define IDX_TRX_WEIGHT		5
288
 Column("trx_weight", ULonglong(), NOT_NULL),
vasil's avatar
vasil committed
289

vasil's avatar
vasil committed
290
#define IDX_TRX_MYSQL_THREAD_ID	6
291
  Column("trx_mysql_thread_id", ULonglong(), NOT_NULL),
292

vasil's avatar
vasil committed
293
#define IDX_TRX_QUERY		7
294
  Column("trx_query", Varchar(TRX_I_S_TRX_QUERY_MAX_LEN), NULLABLE),
vasil's avatar
vasil committed
295

296
#define IDX_TRX_OPERATION_STATE	8
297
  Column("trx_operation_state", Varchar(64), NULLABLE),
298 299

#define IDX_TRX_TABLES_IN_USE	9
300
  Column("trx_tables_in_use", ULonglong(), NOT_NULL),
301 302

#define IDX_TRX_TABLES_LOCKED	10
303
  Column("trx_tables_locked", ULonglong(), NOT_NULL),
304 305

#define IDX_TRX_LOCK_STRUCTS	11
306
  Column("trx_lock_structs", ULonglong(), NOT_NULL),
307 308

#define IDX_TRX_LOCK_MEMORY_BYTES	12
309
  Column("trx_lock_memory_bytes", ULonglong(), NOT_NULL),
310 311

#define IDX_TRX_ROWS_LOCKED	13
312 313 314 315
  Column("trx_rows_locked", ULonglong(), NOT_NULL),

#define IDX_TRX_ROWS_MODIFIED	14
  Column("trx_rows_modified", ULonglong(), NOT_NULL),
316 317

#define IDX_TRX_CONNCURRENCY_TICKETS	15
318
  Column("trx_concurrency_tickets", ULonglong(), NOT_NULL),
319 320

#define IDX_TRX_ISOLATION_LEVEL	16
321
  Column("trx_isolation_level",
322
         Enum(&isolation_level_values_typelib), NOT_NULL, DEFAULT_NONE),
323 324

#define IDX_TRX_UNIQUE_CHECKS	17
325
  Column("trx_unique_checks", SLong(1), NOT_NULL),
326 327

#define IDX_TRX_FOREIGN_KEY_CHECKS	18
328
  Column("trx_foreign_key_checks", SLong(1), NOT_NULL),
329 330

#define IDX_TRX_LAST_FOREIGN_KEY_ERROR	19
331 332
  Column("trx_last_foreign_key_error",
         Varchar(TRX_I_S_TRX_FK_ERROR_MAX_LEN),NULLABLE),
333

334
#define IDX_TRX_READ_ONLY		20
335
  Column("trx_is_read_only", SLong(1), NOT_NULL),
336

337
#define IDX_TRX_AUTOCOMMIT_NON_LOCKING	21
338 339 340
  Column("trx_autocommit_non_locking", SLong(1), NOT_NULL),

  CEnd()
341 342
};

343 344
} // namespace Show

345
/*******************************************************************//**
346
Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx
347
table with it.
348
@return 0 on success */
349 350 351 352
static
int
fill_innodb_trx_from_cache(
/*=======================*/
353 354
	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
	THD*			thd,	/*!< in: used to call
355
					schema_table_store_record() */
356
	TABLE*			table)	/*!< in/out: fill this table */
357 358 359
{
	Field**	fields;
	ulint	rows_num;
vasil's avatar
vasil committed
360
	char	lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
	ulint	i;

	DBUG_ENTER("fill_innodb_trx_from_cache");

	fields = table->field;

	rows_num = trx_i_s_cache_get_rows_used(cache,
					       I_S_INNODB_TRX);

	for (i = 0; i < rows_num; i++) {

		i_s_trx_row_t*	row;

		row = (i_s_trx_row_t*)
			trx_i_s_cache_get_nth_row(
				cache, I_S_INNODB_TRX, i);

		/* trx_id */
379
		OK(fields[IDX_TRX_ID]->store(row->trx_id, true));
380 381 382 383 384 385 386 387 388

		/* trx_state */
		OK(field_store_string(fields[IDX_TRX_STATE],
				      row->trx_state));

		/* trx_started */
		OK(field_store_time_t(fields[IDX_TRX_STARTED],
				      (time_t) row->trx_started));

vasil's avatar
vasil committed
389
		/* trx_requested_lock_id */
390 391 392 393
		/* trx_wait_started */
		if (row->trx_wait_started != 0) {

			OK(field_store_string(
vasil's avatar
vasil committed
394
				   fields[IDX_TRX_REQUESTED_LOCK_ID],
395
				   trx_i_s_create_lock_id(
vasil's avatar
vasil committed
396
					   row->requested_lock_row,
397 398 399 400 401 402 403 404 405
					   lock_id, sizeof(lock_id))));
			/* field_store_string() sets it no notnull */

			OK(field_store_time_t(
				   fields[IDX_TRX_WAIT_STARTED],
				   (time_t) row->trx_wait_started));
			fields[IDX_TRX_WAIT_STARTED]->set_notnull();
		} else {

vasil's avatar
vasil committed
406
			fields[IDX_TRX_REQUESTED_LOCK_ID]->set_null();
407 408 409
			fields[IDX_TRX_WAIT_STARTED]->set_null();
		}

vasil's avatar
vasil committed
410
		/* trx_weight */
411
		OK(fields[IDX_TRX_WEIGHT]->store(row->trx_weight, true));
vasil's avatar
vasil committed
412

413 414
		/* trx_mysql_thread_id */
		OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
415
			   row->trx_mysql_thread_id, true));
416

vasil's avatar
vasil committed
417
		/* trx_query */
418 419 420 421
		if (row->trx_query) {
			/* store will do appropriate character set
			conversion check */
			fields[IDX_TRX_QUERY]->store(
Sergei Golubchik's avatar
Sergei Golubchik committed
422 423
				row->trx_query,
				static_cast<uint>(strlen(row->trx_query)),
424 425 426 427 428
				row->trx_query_cs);
			fields[IDX_TRX_QUERY]->set_notnull();
		} else {
			fields[IDX_TRX_QUERY]->set_null();
		}
vasil's avatar
vasil committed
429

430 431 432 433 434 435
		/* trx_operation_state */
		OK(field_store_string(fields[IDX_TRX_OPERATION_STATE],
				      row->trx_operation_state));

		/* trx_tables_in_use */
		OK(fields[IDX_TRX_TABLES_IN_USE]->store(
436
			   row->trx_tables_in_use, true));
437 438 439

		/* trx_tables_locked */
		OK(fields[IDX_TRX_TABLES_LOCKED]->store(
440
			   row->trx_tables_locked, true));
441 442 443

		/* trx_lock_structs */
		OK(fields[IDX_TRX_LOCK_STRUCTS]->store(
444
			   row->trx_lock_structs, true));
445 446 447

		/* trx_lock_memory_bytes */
		OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store(
448
			   row->trx_lock_memory_bytes, true));
449 450 451

		/* trx_rows_locked */
		OK(fields[IDX_TRX_ROWS_LOCKED]->store(
452
			   row->trx_rows_locked, true));
453 454 455

		/* trx_rows_modified */
		OK(fields[IDX_TRX_ROWS_MODIFIED]->store(
456
			   row->trx_rows_modified, true));
457 458

		/* trx_concurrency_tickets */
459
		OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store(0, true));
460 461

		/* trx_isolation_level */
462 463
		OK(fields[IDX_TRX_ISOLATION_LEVEL]->store(
			   1 + row->trx_isolation_level, true));
464 465 466

		/* trx_unique_checks */
		OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
467
			   row->trx_unique_checks, true));
468 469 470

		/* trx_foreign_key_checks */
		OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
471
			   row->trx_foreign_key_checks, true));
472 473 474 475 476

		/* trx_last_foreign_key_error */
		OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
				      row->trx_foreign_key_error));

477 478
		/* trx_is_read_only*/
		OK(fields[IDX_TRX_READ_ONLY]->store(
479
			   row->trx_is_read_only, true));
480 481 482

		/* trx_is_autocommit_non_locking */
		OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
483
			   row->trx_is_autocommit_non_locking, true));
484

485 486 487 488 489 490
		OK(schema_table_store_record(thd, table));
	}

	DBUG_RETURN(0);
}

491
/*******************************************************************//**
492
Bind the dynamic table INFORMATION_SCHEMA.innodb_trx
493
@return 0 on success */
494 495 496 497
static
int
innodb_trx_init(
/*============*/
498
	void*	p)	/*!< in/out: table schema object */
499 500 501 502 503 504 505
{
	ST_SCHEMA_TABLE*	schema;

	DBUG_ENTER("innodb_trx_init");

	schema = (ST_SCHEMA_TABLE*) p;

506
	schema->fields_info = Show::innodb_trx_fields_info;
507 508 509 510 511
	schema->fill_table = trx_i_s_common_fill_table;

	DBUG_RETURN(0);
}

512
static struct st_mysql_information_schema	i_s_info =
513 514 515 516
{
	MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};

517
struct st_maria_plugin	i_s_innodb_trx =
518 519 520 521 522 523 524
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
525
	STRUCT_FLD(info, &i_s_info),
526 527 528

	/* plugin name */
	/* const char* */
vasil's avatar
vasil committed
529
	STRUCT_FLD(name, "INNODB_TRX"),
530 531 532

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
533
	STRUCT_FLD(author, plugin_author),
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB transactions"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, innodb_trx_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
549
	STRUCT_FLD(deinit, i_s_common_deinit),
550 551 552

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
553
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
554 555 556 557 558 559 560

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

561 562
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
563
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
564 565
};

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
static const LEX_CSTRING lock_mode_values[] =
{
	{ STRING_WITH_LEN("S") },
	{ STRING_WITH_LEN("S,GAP") },
	{ STRING_WITH_LEN("X") },
	{ STRING_WITH_LEN("X,GAP") },
	{ STRING_WITH_LEN("IS") },
	{ STRING_WITH_LEN("IS,GAP") },
	{ STRING_WITH_LEN("IX") },
	{ STRING_WITH_LEN("IX,GAP") },
	{ STRING_WITH_LEN("AUTO_INC") }
};

static TypelibBuffer<9> lock_mode_values_typelib(lock_mode_values);

static const LEX_CSTRING lock_type_values[] =
{
	{ STRING_WITH_LEN("RECORD") },
	{ STRING_WITH_LEN("TABLE") }
};

static TypelibBuffer<2> lock_type_values_typelib(lock_type_values);

589
namespace Show {
590 591 592 593
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_locks */
static ST_FIELD_INFO	innodb_locks_fields_info[] =
{
#define IDX_LOCK_ID		0
594
  Column("lock_id",     Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1),  NOT_NULL),
595 596

#define IDX_LOCK_TRX_ID		1
597
  Column("lock_trx_id", ULonglong(), NOT_NULL),
598 599

#define IDX_LOCK_MODE		2
600
  Column("lock_mode",   Enum(&lock_mode_values_typelib), NOT_NULL, DEFAULT_NONE),
601 602

#define IDX_LOCK_TYPE		3
603
  Column("lock_type",   Enum(&lock_type_values_typelib), NOT_NULL, DEFAULT_NONE),
604 605

#define IDX_LOCK_TABLE		4
606
  Column("lock_table",  Varchar(1024), NOT_NULL),
607 608

#define IDX_LOCK_INDEX		5
609
  Column("lock_index",  Varchar(1024), NULLABLE),
610 611

#define IDX_LOCK_SPACE		6
612
  Column("lock_space",  ULong(),   NULLABLE),
613 614

#define IDX_LOCK_PAGE		7
615
  Column("lock_page",   ULong(),   NULLABLE),
616 617

#define IDX_LOCK_REC		8
618
  Column("lock_rec",    ULong(),   NULLABLE),
619

vasil's avatar
vasil committed
620
#define IDX_LOCK_DATA		9
621 622
  Column("lock_data",   Varchar(TRX_I_S_LOCK_DATA_MAX_LEN), NULLABLE),
  CEnd()
623
};
624
} // namespace Show
625

626
/*******************************************************************//**
627
Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_locks
628
table with it.
629
@return 0 on success */
630 631 632 633
static
int
fill_innodb_locks_from_cache(
/*=========================*/
634 635 636
	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
	THD*			thd,	/*!< in: MySQL client connection */
	TABLE*			table)	/*!< in/out: fill this table */
637 638 639
{
	Field**	fields;
	ulint	rows_num;
vasil's avatar
vasil committed
640
	char	lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
641 642 643 644 645 646 647 648 649 650 651 652
	ulint	i;

	DBUG_ENTER("fill_innodb_locks_from_cache");

	fields = table->field;

	rows_num = trx_i_s_cache_get_rows_used(cache,
					       I_S_INNODB_LOCKS);

	for (i = 0; i < rows_num; i++) {

		i_s_locks_row_t*	row;
653
		char			buf[MAX_FULL_NAME_LEN + 1];
654
		const char*		bufend;
655 656 657 658 659 660

		row = (i_s_locks_row_t*)
			trx_i_s_cache_get_nth_row(
				cache, I_S_INNODB_LOCKS, i);

		/* lock_id */
vasil's avatar
vasil committed
661 662 663
		trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id));
		OK(field_store_string(fields[IDX_LOCK_ID],
				      lock_id));
664 665

		/* lock_trx_id */
666
		OK(fields[IDX_LOCK_TRX_ID]->store(row->lock_trx_id, true));
667 668

		/* lock_mode */
669
		OK(fields[IDX_LOCK_MODE]->store(row->lock_mode, true));
670 671

		/* lock_type */
672 673
		OK(fields[IDX_LOCK_TYPE]->store(
			   row->lock_index ? 1 : 2, true));
674 675

		/* lock_table */
vasil's avatar
vasil committed
676
		bufend = innobase_convert_name(buf, sizeof(buf),
677 678
					       row->lock_table,
					       strlen(row->lock_table),
679
					       thd);
Sergei Golubchik's avatar
Sergei Golubchik committed
680
		OK(fields[IDX_LOCK_TABLE]->store(
681
			buf, uint(bufend - buf), system_charset_info));
682

683 684 685 686 687
		if (row->lock_index) {
			/* record lock */
			OK(field_store_string(fields[IDX_LOCK_INDEX],
					      row->lock_index));
			OK(fields[IDX_LOCK_SPACE]->store(
688
				   row->lock_page.space(), true));
689 690
			fields[IDX_LOCK_SPACE]->set_notnull();
			OK(fields[IDX_LOCK_PAGE]->store(
691
				   row->lock_page.page_no(), true));
692 693 694 695 696 697 698 699 700 701 702 703
			fields[IDX_LOCK_PAGE]->set_notnull();
			OK(fields[IDX_LOCK_REC]->store(
				   row->lock_rec, true));
			fields[IDX_LOCK_REC]->set_notnull();
			OK(field_store_string(fields[IDX_LOCK_DATA],
					      row->lock_data));
		} else {
			fields[IDX_LOCK_INDEX]->set_null();
			fields[IDX_LOCK_SPACE]->set_null();
			fields[IDX_LOCK_REC]->set_null();
			fields[IDX_LOCK_DATA]->set_null();
		}
vasil's avatar
vasil committed
704

705 706 707 708 709 710
		OK(schema_table_store_record(thd, table));
	}

	DBUG_RETURN(0);
}

711
/*******************************************************************//**
712
Bind the dynamic table INFORMATION_SCHEMA.innodb_locks
713
@return 0 on success */
714 715 716 717
static
int
innodb_locks_init(
/*==============*/
718
	void*	p)	/*!< in/out: table schema object */
719 720 721 722 723 724 725
{
	ST_SCHEMA_TABLE*	schema;

	DBUG_ENTER("innodb_locks_init");

	schema = (ST_SCHEMA_TABLE*) p;

726
	schema->fields_info = Show::innodb_locks_fields_info;
727 728 729 730 731
	schema->fill_table = trx_i_s_common_fill_table;

	DBUG_RETURN(0);
}

732
struct st_maria_plugin	i_s_innodb_locks =
733 734 735 736 737 738 739
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
740
	STRUCT_FLD(info, &i_s_info),
741 742 743

	/* plugin name */
	/* const char* */
vasil's avatar
vasil committed
744
	STRUCT_FLD(name, "INNODB_LOCKS"),
745 746 747

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
748
	STRUCT_FLD(author, plugin_author),
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB conflicting locks"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, innodb_locks_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
764
	STRUCT_FLD(deinit, i_s_common_deinit),
765 766 767

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
768
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
769 770 771 772 773 774 775

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

776 777
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
778
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
779 780
};

781 782

namespace Show {
783 784 785
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */
static ST_FIELD_INFO	innodb_lock_waits_fields_info[] =
{
vasil's avatar
vasil committed
786
#define IDX_REQUESTING_TRX_ID	0
787
  Column("requesting_trx_id", ULonglong(), NOT_NULL),
vasil's avatar
vasil committed
788 789

#define IDX_REQUESTED_LOCK_ID	1
790
  Column("requested_lock_id", Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NOT_NULL),
791

vasil's avatar
vasil committed
792
#define IDX_BLOCKING_TRX_ID	2
793
  Column("blocking_trx_id",   ULonglong(), NOT_NULL),
vasil's avatar
vasil committed
794 795

#define IDX_BLOCKING_LOCK_ID	3
796 797
  Column("blocking_lock_id",  Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NOT_NULL),
  CEnd()
798
};
799
} // namespace Show
800

801
/*******************************************************************//**
802
Read data from cache buffer and fill the
803
INFORMATION_SCHEMA.innodb_lock_waits table with it.
804
@return 0 on success */
805 806 807 808
static
int
fill_innodb_lock_waits_from_cache(
/*==============================*/
809 810
	trx_i_s_cache_t*	cache,	/*!< in: cache to read from */
	THD*			thd,	/*!< in: used to call
811
					schema_table_store_record() */
812
	TABLE*			table)	/*!< in/out: fill this table */
813 814 815
{
	Field**	fields;
	ulint	rows_num;
vasil's avatar
vasil committed
816 817
	char	requested_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
	char	blocking_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
	ulint	i;

	DBUG_ENTER("fill_innodb_lock_waits_from_cache");

	fields = table->field;

	rows_num = trx_i_s_cache_get_rows_used(cache,
					       I_S_INNODB_LOCK_WAITS);

	for (i = 0; i < rows_num; i++) {

		i_s_lock_waits_row_t*	row;

		row = (i_s_lock_waits_row_t*)
			trx_i_s_cache_get_nth_row(
				cache, I_S_INNODB_LOCK_WAITS, i);

vasil's avatar
vasil committed
835
		/* requesting_trx_id */
836 837
		OK(fields[IDX_REQUESTING_TRX_ID]->store(
				      row->requested_lock_row->lock_trx_id, true));
vasil's avatar
vasil committed
838 839

		/* requested_lock_id */
840
		OK(field_store_string(
vasil's avatar
vasil committed
841
			   fields[IDX_REQUESTED_LOCK_ID],
842
			   trx_i_s_create_lock_id(
vasil's avatar
vasil committed
843 844 845 846 847
				   row->requested_lock_row,
				   requested_lock_id,
				   sizeof(requested_lock_id))));

		/* blocking_trx_id */
848 849
		OK(fields[IDX_BLOCKING_TRX_ID]->store(
				      row->blocking_lock_row->lock_trx_id, true));
850

vasil's avatar
vasil committed
851
		/* blocking_lock_id */
852
		OK(field_store_string(
vasil's avatar
vasil committed
853
			   fields[IDX_BLOCKING_LOCK_ID],
854
			   trx_i_s_create_lock_id(
vasil's avatar
vasil committed
855 856 857
				   row->blocking_lock_row,
				   blocking_lock_id,
				   sizeof(blocking_lock_id))));
858 859 860 861 862 863 864

		OK(schema_table_store_record(thd, table));
	}

	DBUG_RETURN(0);
}

865
/*******************************************************************//**
866
Bind the dynamic table INFORMATION_SCHEMA.innodb_lock_waits
867
@return 0 on success */
868 869 870 871
static
int
innodb_lock_waits_init(
/*===================*/
872
	void*	p)	/*!< in/out: table schema object */
873 874 875 876 877 878 879
{
	ST_SCHEMA_TABLE*	schema;

	DBUG_ENTER("innodb_lock_waits_init");

	schema = (ST_SCHEMA_TABLE*) p;

880
	schema->fields_info = Show::innodb_lock_waits_fields_info;
881 882 883 884 885
	schema->fill_table = trx_i_s_common_fill_table;

	DBUG_RETURN(0);
}

886
struct st_maria_plugin	i_s_innodb_lock_waits =
887 888 889 890 891 892 893
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
894
	STRUCT_FLD(info, &i_s_info),
895 896 897

	/* plugin name */
	/* const char* */
vasil's avatar
vasil committed
898
	STRUCT_FLD(name, "INNODB_LOCK_WAITS"),
899 900 901

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
902
	STRUCT_FLD(author, plugin_author),
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB which lock is blocking which"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, innodb_lock_waits_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
918
	STRUCT_FLD(deinit, i_s_common_deinit),
919 920 921

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
922
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
923 924 925 926 927 928 929

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

930 931
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
932
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
933 934
};

935
/*******************************************************************//**
936 937 938
Common function to fill any of the dynamic tables:
INFORMATION_SCHEMA.innodb_trx
INFORMATION_SCHEMA.innodb_locks
939
INFORMATION_SCHEMA.innodb_lock_waits
940
@return 0 on success */
941 942 943 944
static
int
trx_i_s_common_fill_table(
/*======================*/
945 946
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
947
	Item*		)	/*!< in: condition (not used) */
948
{
949
	LEX_CSTRING		table_name;
950 951 952 953 954
	int			ret;
	trx_i_s_cache_t*	cache;

	DBUG_ENTER("trx_i_s_common_fill_table");

vasil's avatar
vasil committed
955
	/* deny access to non-superusers */
vasil's avatar
vasil committed
956
	if (check_global_access(thd, PROCESS_ACL)) {
vasil's avatar
vasil committed
957 958 959 960

		DBUG_RETURN(0);
	}

961 962 963 964
	/* minimize the number of places where global variables are
	referenced */
	cache = trx_i_s_cache;

vasil's avatar
vasil committed
965 966 967 968
	/* which table we have to fill? */
	table_name = tables->schema_table_name;
	/* or table_name = tables->schema_table->table_name; */

969
	RETURN_IF_INNODB_NOT_STARTED(table_name.str);
970

971 972 973 974 975
	/* update the cache */
	trx_i_s_cache_start_write(cache);
	trx_i_s_possibly_fetch_data_into_cache(cache);
	trx_i_s_cache_end_write(cache);

vasil's avatar
vasil committed
976 977
	if (trx_i_s_cache_is_truncated(cache)) {

978
		ib::warn() << "Data in " << table_name.str << " truncated due to"
979
			" memory limit of " << TRX_I_S_MEM_LIMIT << " bytes";
vasil's avatar
vasil committed
980
	}
981 982 983 984 985

	ret = 0;

	trx_i_s_cache_start_read(cache);

986
	if (innobase_strcasecmp(table_name.str, "innodb_trx") == 0) {
987 988 989 990 991 992 993

		if (fill_innodb_trx_from_cache(
			cache, thd, tables->table) != 0) {

			ret = 1;
		}

994
	} else if (innobase_strcasecmp(table_name.str, "innodb_locks") == 0) {
995 996 997 998 999 1000 1001

		if (fill_innodb_locks_from_cache(
			cache, thd, tables->table) != 0) {

			ret = 1;
		}

1002
	} else if (innobase_strcasecmp(table_name.str, "innodb_lock_waits") == 0) {
1003 1004 1005 1006 1007 1008 1009 1010

		if (fill_innodb_lock_waits_from_cache(
			cache, thd, tables->table) != 0) {

			ret = 1;
		}

	} else {
1011
		ib::error() << "trx_i_s_common_fill_table() was"
1012
			" called to fill unknown table: " << table_name.str << "."
1013 1014 1015
			" This function only knows how to fill"
			" innodb_trx, innodb_locks and"
			" innodb_lock_waits tables.";
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028

		ret = 1;
	}

	trx_i_s_cache_end_read(cache);

#if 0
	DBUG_RETURN(ret);
#else
	/* if this function returns something else than 0 then a
	deadlock occurs between the mysqld server and mysql client,
	see http://bugs.mysql.com/29900 ; when that bug is resolved
	we can enable the DBUG_RETURN(ret) above */
1029
	ret++;  // silence a gcc46 warning
1030
	DBUG_RETURN(0);
1031 1032 1033
#endif
}

1034
namespace Show {
1035 1036
/* Fields of the dynamic table information_schema.innodb_cmp. */
static ST_FIELD_INFO	i_s_cmp_fields_info[] =
1037
{
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
  Column("page_size",      SLong(5),NOT_NULL, "Compressed Page Size"),
  Column("compress_ops",   SLong(), NOT_NULL, "Total Number of Compressions"),
  Column("compress_ops_ok",SLong(), NOT_NULL, "Total Number of "
                                              "Successful Compressions"),
  Column("compress_time",  SLong(), NOT_NULL, "Total Duration of "
                                              "Compressions, in Seconds"),
  Column("uncompress_ops", SLong(), NOT_NULL, "Total Number of Decompressions"),
  Column("uncompress_time",SLong(), NOT_NULL, "Total Duration of "
                                              "Decompressions, in Seconds"),
  CEnd(),
1048
};
1049
} // namespace Show
1050 1051


1052
/*******************************************************************//**
1053
Fill the dynamic table information_schema.innodb_cmp or
1054
innodb_cmp_reset.
1055
@return 0 on success, 1 on failure */
1056 1057 1058 1059
static
int
i_s_cmp_fill_low(
/*=============*/
1060 1061
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1062
	Item*		,	/*!< in: condition (ignored) */
1063
	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1064
{
1065
	TABLE*	table	= (TABLE*) tables->table;
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
	int	status	= 0;

	DBUG_ENTER("i_s_cmp_fill_low");

	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {

		DBUG_RETURN(0);
	}

1076
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
1077

1078
	for (uint i = 0; i < PAGE_ZIP_SSIZE_MAX; i++) {
1079 1080
		page_zip_stat_t*	zip_stat = &page_zip_stat[i];

1081
		table->field[0]->store(UNIV_ZIP_SIZE_MIN << i);
1082 1083

		/* The cumulated counts are not protected by any
1084
		mutex.  Thus, some operation in page0zip.cc could
1085 1086 1087
		increment a counter between the time we read it and
		clear it.  We could introduce mutex protection, but it
		could cause a measureable performance hit in
1088
		page0zip.cc. */
1089 1090
		table->field[1]->store(zip_stat->compressed, true);
		table->field[2]->store(zip_stat->compressed_ok, true);
1091 1092
		table->field[3]->store(zip_stat->compressed_usec / 1000000,
				       true);
1093
		table->field[4]->store(zip_stat->decompressed, true);
1094 1095
		table->field[5]->store(zip_stat->decompressed_usec / 1000000,
				       true);
1096 1097

		if (reset) {
1098
			new (zip_stat) page_zip_stat_t();
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
		}

		if (schema_table_store_record(thd, table)) {
			status = 1;
			break;
		}
	}

	DBUG_RETURN(status);
}

1110
/*******************************************************************//**
1111
Fill the dynamic table information_schema.innodb_cmp.
1112
@return 0 on success, 1 on failure */
1113 1114 1115 1116
static
int
i_s_cmp_fill(
/*=========*/
1117 1118
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1119
	Item*		cond)	/*!< in: condition (ignored) */
1120 1121 1122 1123
{
	return(i_s_cmp_fill_low(thd, tables, cond, FALSE));
}

1124
/*******************************************************************//**
1125
Fill the dynamic table information_schema.innodb_cmp_reset.
1126
@return 0 on success, 1 on failure */
1127 1128 1129 1130
static
int
i_s_cmp_reset_fill(
/*===============*/
1131 1132
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1133
	Item*		cond)	/*!< in: condition (ignored) */
1134 1135 1136 1137
{
	return(i_s_cmp_fill_low(thd, tables, cond, TRUE));
}

1138
/*******************************************************************//**
1139
Bind the dynamic table information_schema.innodb_cmp.
1140
@return 0 on success */
1141 1142 1143 1144
static
int
i_s_cmp_init(
/*=========*/
1145
	void*	p)	/*!< in/out: table schema object */
1146 1147 1148 1149
{
	DBUG_ENTER("i_s_cmp_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

1150
	schema->fields_info = Show::i_s_cmp_fields_info;
1151 1152 1153 1154 1155
	schema->fill_table = i_s_cmp_fill;

	DBUG_RETURN(0);
}

1156
/*******************************************************************//**
1157
Bind the dynamic table information_schema.innodb_cmp_reset.
1158
@return 0 on success */
1159 1160 1161 1162
static
int
i_s_cmp_reset_init(
/*===============*/
1163
	void*	p)	/*!< in/out: table schema object */
1164 1165 1166 1167
{
	DBUG_ENTER("i_s_cmp_reset_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

1168
	schema->fields_info = Show::i_s_cmp_fields_info;
1169 1170 1171 1172 1173
	schema->fill_table = i_s_cmp_reset_fill;

	DBUG_RETURN(0);
}

1174
struct st_maria_plugin	i_s_innodb_cmp =
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_CMP"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "Statistics for the InnoDB compression"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, i_s_cmp_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

1218 1219
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
1220
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
1221 1222
};

1223
struct st_maria_plugin	i_s_innodb_cmp_reset =
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_CMP_RESET"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "Statistics for the InnoDB compression;"
		   " reset cumulated counts"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, i_s_cmp_reset_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

1268 1269
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
1270
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
1271 1272
};

1273 1274

namespace Show {
1275 1276 1277 1278
/* Fields of the dynamic tables
information_schema.innodb_cmp_per_index and
information_schema.innodb_cmp_per_index_reset. */
static ST_FIELD_INFO	i_s_cmp_per_index_fields_info[] =
1279
{
1280
#define IDX_DATABASE_NAME	0
1281
  Column("database_name",   Varchar(NAME_CHAR_LEN), NOT_NULL),
1282

1283 1284
#define IDX_TABLE_NAME		1 /* FIXME: this is in my_charset_filename! */
  Column("table_name",      Varchar(NAME_CHAR_LEN), NOT_NULL),
irana's avatar
irana committed
1285

1286
#define IDX_INDEX_NAME		2
1287
  Column("index_name",      Varchar(NAME_CHAR_LEN), NOT_NULL),
1288 1289

#define IDX_COMPRESS_OPS	3
1290
  Column("compress_ops",    SLong(),      NOT_NULL),
1291

1292
#define IDX_COMPRESS_OPS_OK	4
1293
  Column("compress_ops_ok", SLong(),      NOT_NULL),
1294

1295
#define IDX_COMPRESS_TIME	5
1296
  Column("compress_time",   SLong(),      NOT_NULL),
1297

1298
#define IDX_UNCOMPRESS_OPS	6
1299
  Column("uncompress_ops",  SLong(),      NOT_NULL),
1300 1301

#define IDX_UNCOMPRESS_TIME	7
1302 1303 1304
  Column("uncompress_time", SLong(),      NOT_NULL),

  CEnd()
1305 1306
};

1307 1308
} // namespace Show

1309
/*******************************************************************//**
1310 1311 1312
Fill the dynamic table
information_schema.innodb_cmp_per_index or
information_schema.innodb_cmp_per_index_reset.
1313
@return 0 on success, 1 on failure */
1314 1315
static
int
1316 1317
i_s_cmp_per_index_fill_low(
/*=======================*/
1318 1319
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1320
	Item*		,	/*!< in: condition (ignored) */
1321
	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1322
{
1323 1324 1325
	TABLE*	table = tables->table;
	Field**	fields = table->field;
	int	status = 0;
1326

1327
	DBUG_ENTER("i_s_cmp_per_index_fill_low");
1328

1329
	/* deny access to non-superusers */
vasil's avatar
vasil committed
1330
	if (check_global_access(thd, PROCESS_ACL)) {
1331 1332 1333 1334

		DBUG_RETURN(0);
	}

1335
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
1336

1337
	/* Create a snapshot of the stats so we do not bump into lock
1338
	order violations with dict_sys.mutex below. */
1339
	mysql_mutex_lock(&page_zip_stat_per_index_mutex);
1340
	page_zip_stat_per_index_t		snap (page_zip_stat_per_index);
1341
	mysql_mutex_unlock(&page_zip_stat_per_index_mutex);
1342

1343
	dict_sys.mutex_lock();
1344

1345 1346
	page_zip_stat_per_index_t::iterator	iter;
	ulint					i;
irana's avatar
irana committed
1347

1348
	for (iter = snap.begin(), i = 0; iter != snap.end(); iter++, i++) {
irana's avatar
irana committed
1349

1350
		dict_index_t*	index = dict_index_find_on_id_low(iter->first);
irana's avatar
irana committed
1351

1352 1353 1354
		if (index != NULL) {
			char	db_utf8[MAX_DB_UTF8_LEN];
			char	table_utf8[MAX_TABLE_UTF8_LEN];
irana's avatar
irana committed
1355

1356
			dict_fs2utf8(index->table->name.m_name,
1357 1358
				     db_utf8, sizeof(db_utf8),
				     table_utf8, sizeof(table_utf8));
irana's avatar
irana committed
1359

1360 1361 1362 1363 1364 1365
			status = field_store_string(fields[IDX_DATABASE_NAME],
						    db_utf8)
				|| field_store_string(fields[IDX_TABLE_NAME],
						      table_utf8)
				|| field_store_string(fields[IDX_INDEX_NAME],
						      index->name);
1366 1367
		} else {
			/* index not found */
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
			char name[MY_INT64_NUM_DECIMAL_DIGITS
				  + sizeof "index_id: "];
			fields[IDX_DATABASE_NAME]->set_null();
			fields[IDX_TABLE_NAME]->set_null();
			fields[IDX_INDEX_NAME]->set_notnull();
			status = fields[IDX_INDEX_NAME]->store(
				name,
				uint(snprintf(name, sizeof name,
					      "index_id: " IB_ID_FMT,
					      iter->first)),
				system_charset_info);
1379 1380
		}

1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
		if (status
		    || fields[IDX_COMPRESS_OPS]->store(
			    iter->second.compressed, true)
		    || fields[IDX_COMPRESS_OPS_OK]->store(
			    iter->second.compressed_ok, true)
		    || fields[IDX_COMPRESS_TIME]->store(
			    iter->second.compressed_usec / 1000000, true)
		    || fields[IDX_UNCOMPRESS_OPS]->store(
			    iter->second.decompressed, true)
		    || fields[IDX_UNCOMPRESS_TIME]->store(
			    iter->second.decompressed_usec / 1000000, true)
		    || schema_table_store_record(thd, table)) {
1393
			status = 1;
1394 1395
			break;
		}
1396 1397 1398 1399
		/* Release and reacquire the dict mutex to allow other
		threads to proceed. This could eventually result in the
		contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
		inconsistent, but it is an acceptable compromise. */
1400
		if (i == 1000) {
1401
			dict_sys.mutex_unlock();
1402
			i = 0;
1403
			dict_sys.mutex_lock();
1404 1405 1406
		}
	}

1407
	dict_sys.mutex_unlock();
1408 1409 1410

	if (reset) {
		page_zip_reset_stat_per_index();
1411 1412 1413 1414 1415
	}

	DBUG_RETURN(status);
}

1416
/*******************************************************************//**
1417
Fill the dynamic table information_schema.innodb_cmp_per_index.
1418
@return 0 on success, 1 on failure */
1419 1420
static
int
1421 1422
i_s_cmp_per_index_fill(
/*===================*/
1423 1424
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1425
	Item*		cond)	/*!< in: condition (ignored) */
1426
{
1427
	return(i_s_cmp_per_index_fill_low(thd, tables, cond, FALSE));
1428 1429
}

1430
/*******************************************************************//**
1431
Fill the dynamic table information_schema.innodb_cmp_per_index_reset.
1432
@return 0 on success, 1 on failure */
1433 1434
static
int
1435 1436
i_s_cmp_per_index_reset_fill(
/*=========================*/
1437 1438
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1439
	Item*		cond)	/*!< in: condition (ignored) */
1440
{
1441
	return(i_s_cmp_per_index_fill_low(thd, tables, cond, TRUE));
1442 1443
}

1444
/*******************************************************************//**
1445
Bind the dynamic table information_schema.innodb_cmp_per_index.
1446
@return 0 on success */
1447 1448
static
int
1449 1450
i_s_cmp_per_index_init(
/*===================*/
1451
	void*	p)	/*!< in/out: table schema object */
1452
{
1453
	DBUG_ENTER("i_s_cmp_init");
1454 1455
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

1456
	schema->fields_info = Show::i_s_cmp_per_index_fields_info;
1457
	schema->fill_table = i_s_cmp_per_index_fill;
1458 1459 1460 1461

	DBUG_RETURN(0);
}

1462
/*******************************************************************//**
1463
Bind the dynamic table information_schema.innodb_cmp_per_index_reset.
1464
@return 0 on success */
1465 1466
static
int
1467 1468
i_s_cmp_per_index_reset_init(
/*=========================*/
1469
	void*	p)	/*!< in/out: table schema object */
1470
{
1471
	DBUG_ENTER("i_s_cmp_reset_init");
1472 1473
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

1474
	schema->fields_info = Show::i_s_cmp_per_index_fields_info;
1475
	schema->fill_table = i_s_cmp_per_index_reset_fill;
1476 1477 1478 1479

	DBUG_RETURN(0);
}

1480
struct st_maria_plugin	i_s_innodb_cmp_per_index =
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
1492
	STRUCT_FLD(name, "INNODB_CMP_PER_INDEX"),
1493 1494 1495 1496 1497 1498 1499

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
1500
	STRUCT_FLD(descr, "Statistics for the InnoDB compression (per index)"),
1501 1502 1503 1504 1505 1506 1507

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
1508
	STRUCT_FLD(init, i_s_cmp_per_index_init),
1509 1510 1511 1512 1513 1514 1515

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
1516
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1517 1518 1519 1520 1521 1522 1523

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

1524 1525
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
1526
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
1527 1528
};

1529
struct st_maria_plugin	i_s_innodb_cmp_per_index_reset =
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
1541
	STRUCT_FLD(name, "INNODB_CMP_PER_INDEX_RESET"),
1542 1543 1544 1545 1546 1547 1548

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
1549
	STRUCT_FLD(descr, "Statistics for the InnoDB compression (per index);"
1550 1551 1552 1553 1554 1555 1556 1557
		   " reset cumulated counts"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
1558
	STRUCT_FLD(init, i_s_cmp_per_index_reset_init),
1559 1560 1561 1562 1563 1564 1565

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
1566
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
1567 1568 1569 1570 1571 1572 1573

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

1574 1575
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
1576
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
1577 1578
};

1579 1580

namespace Show {
1581 1582
/* Fields of the dynamic table information_schema.innodb_cmpmem. */
static ST_FIELD_INFO	i_s_cmpmem_fields_info[] =
1583
{
1584
  Column("page_size",           SLong(5), NOT_NULL, "Buddy Block Size"),
1585
  Column("buffer_pool_instance", SLong(), NOT_NULL, "Buffer Pool Id"),
1586 1587 1588 1589 1590 1591
  Column("pages_used",           SLong(), NOT_NULL, "Currently in Use"),
  Column("pages_free",           SLong(), NOT_NULL, "Currently Available"),
  Column("relocation_ops",   SLonglong(), NOT_NULL, "Total Number of Relocations"),
  Column("relocation_time",      SLong(), NOT_NULL, "Total Duration of Relocations,"
                                                    " in Seconds"),
  CEnd()
1592
};
1593
} // namespace Show
1594

1595 1596 1597
/*******************************************************************//**
Fill the dynamic table information_schema.innodb_cmpmem or
innodb_cmpmem_reset.
1598
@return 0 on success, 1 on failure */
1599 1600
static
int
1601 1602 1603 1604 1605 1606
i_s_cmpmem_fill_low(
/*================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		,	/*!< in: condition (ignored) */
	ibool		reset)	/*!< in: TRUE=reset cumulated counts */
1607
{
1608
	TABLE*	table	= (TABLE*) tables->table;
1609

1610
	DBUG_ENTER("i_s_cmpmem_fill_low");
1611

1612 1613
	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {
1614

1615 1616
		DBUG_RETURN(0);
	}
1617

1618
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
1619

1620 1621
	ulint			zip_free_len_local[BUF_BUDDY_SIZES_MAX + 1];
	buf_buddy_stat_t	buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1];
1622

1623
	/* Save buddy stats for buffer pool in local variables. */
1624
	mysql_mutex_lock(&buf_pool.mutex);
1625

1626 1627
	for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
		zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ?
1628
			UT_LIST_GET_LEN(buf_pool.zip_free[x]) : 0;
1629

1630
		buddy_stat_local[x] = buf_pool.buddy_stat[x];
1631

1632
		if (reset) {
1633 1634 1635
			/* This is protected by buf_pool.mutex. */
			buf_pool.buddy_stat[x].relocated = 0;
			buf_pool.buddy_stat[x].relocated_usec = 0;
1636
		}
1637
	}
1638

1639
	mysql_mutex_unlock(&buf_pool.mutex);
1640

1641
	for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
1642
		buf_buddy_stat_t* buddy_stat = &buddy_stat_local[x];
1643

1644
		Field **field = table->field;
1645

1646 1647 1648 1649 1650 1651
		(*field++)->store(BUF_BUDDY_LOW << x);
		(*field++)->store(0, true);
		(*field++)->store(buddy_stat->used, true);
		(*field++)->store(zip_free_len_local[x], true);
		(*field++)->store(buddy_stat->relocated, true);
		(*field)->store(buddy_stat->relocated_usec / 1000000, true);
1652

1653 1654
		if (schema_table_store_record(thd, table)) {
			DBUG_RETURN(1);
1655
		}
1656
	}
1657

1658
	DBUG_RETURN(0);
1659
}
1660

1661 1662
/*******************************************************************//**
Fill the dynamic table information_schema.innodb_cmpmem.
1663
@return 0 on success, 1 on failure */
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
static
int
i_s_cmpmem_fill(
/*============*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		cond)	/*!< in: condition (ignored) */
{
	return(i_s_cmpmem_fill_low(thd, tables, cond, FALSE));
}
1674

1675
/*******************************************************************//**
1676
Fill the dynamic table information_schema.innodb_cmpmem_reset.
1677
@return 0 on success, 1 on failure */
1678 1679
static
int
1680 1681
i_s_cmpmem_reset_fill(
/*==================*/
1682 1683
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
1684
	Item*		cond)	/*!< in: condition (ignored) */
1685
{
1686 1687
	return(i_s_cmpmem_fill_low(thd, tables, cond, TRUE));
}
1688

1689 1690
/*******************************************************************//**
Bind the dynamic table information_schema.innodb_cmpmem.
1691
@return 0 on success */
1692 1693 1694 1695 1696 1697 1698 1699
static
int
i_s_cmpmem_init(
/*============*/
	void*	p)	/*!< in/out: table schema object */
{
	DBUG_ENTER("i_s_cmpmem_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1700

1701
	schema->fields_info = Show::i_s_cmpmem_fields_info;
1702
	schema->fill_table = i_s_cmpmem_fill;
1703 1704 1705

	DBUG_RETURN(0);
}
1706

1707
/*******************************************************************//**
1708
Bind the dynamic table information_schema.innodb_cmpmem_reset.
1709
@return 0 on success */
1710 1711
static
int
1712 1713
i_s_cmpmem_reset_init(
/*==================*/
1714
	void*	p)	/*!< in/out: table schema object */
1715
{
1716 1717
	DBUG_ENTER("i_s_cmpmem_reset_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1718

1719
	schema->fields_info = Show::i_s_cmpmem_fields_info;
1720
	schema->fill_table = i_s_cmpmem_reset_fill;
1721 1722 1723

	DBUG_RETURN(0);
}
1724

1725
struct st_maria_plugin	i_s_innodb_cmpmem =
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
1737
	STRUCT_FLD(name, "INNODB_CMPMEM"),
1738 1739 1740 1741 1742 1743 1744

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
1745
	STRUCT_FLD(descr, "Statistics for the InnoDB compressed buffer pool"),
1746 1747 1748 1749 1750 1751 1752

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
1753
	STRUCT_FLD(init, i_s_cmpmem_init),
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

1769 1770
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
1771
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
1772 1773
};

1774
struct st_maria_plugin	i_s_innodb_cmpmem_reset =
1775
{
1776 1777 1778
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1779

1780 1781 1782
	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),
1783

1784 1785 1786
	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_CMPMEM_RESET"),
1787

1788 1789 1790
	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),
1791

1792 1793 1794 1795
	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "Statistics for the InnoDB compressed buffer pool;"
		   " reset cumulated counts"),
1796

1797 1798 1799
	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1800 1801 1802

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
1803
	STRUCT_FLD(init, i_s_cmpmem_reset_init),
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

1819 1820
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
1821
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
1822 1823
};

1824

1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
static const LEX_CSTRING metric_type_values[] =
{
	{ STRING_WITH_LEN("value") },
	{ STRING_WITH_LEN("status_counter") },
	{ STRING_WITH_LEN("set_owner") },
	{ STRING_WITH_LEN("set_member") },
	{ STRING_WITH_LEN("counter") }
};

static TypelibBuffer<5> metric_type_values_typelib(metric_type_values);

1836
namespace Show {
1837 1838
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_metrics */
static ST_FIELD_INFO	innodb_metrics_fields_info[] =
1839
{
1840
#define	METRIC_NAME		0
1841
  Column("NAME",            Varchar(NAME_LEN + 1),       NOT_NULL),
1842 1843

#define	METRIC_SUBSYS		1
1844
  Column("SUBSYSTEM",       Varchar(NAME_LEN + 1),       NOT_NULL),
1845 1846

#define	METRIC_VALUE_START	2
1847
  Column("COUNT",           SLonglong(),                 NOT_NULL),
1848

1849
#define	METRIC_MAX_VALUE_START	3
1850
  Column("MAX_COUNT",       SLonglong(),                 NULLABLE),
1851

1852
#define	METRIC_MIN_VALUE_START	4
1853
  Column("MIN_COUNT",       SLonglong(),                 NULLABLE),
1854

1855
#define	METRIC_AVG_VALUE_START	5
1856
  Column("AVG_COUNT",       Float(MAX_FLOAT_STR_LENGTH), NULLABLE),
1857

1858
#define	METRIC_VALUE_RESET	6
1859
  Column("COUNT_RESET",     SLonglong(),                 NOT_NULL),
1860

1861
#define	METRIC_MAX_VALUE_RESET	7
1862
  Column("MAX_COUNT_RESET", SLonglong(),                 NULLABLE),
1863

1864
#define	METRIC_MIN_VALUE_RESET	8
1865
  Column("MIN_COUNT_RESET", SLonglong(),                 NULLABLE),
1866

1867
#define	METRIC_AVG_VALUE_RESET	9
1868
  Column("AVG_COUNT_RESET", Float(MAX_FLOAT_STR_LENGTH), NULLABLE),
1869

1870
#define	METRIC_START_TIME	10
1871
  Column("TIME_ENABLED",    Datetime(0),                 NULLABLE),
1872

1873
#define	METRIC_STOP_TIME	11
1874
  Column("TIME_DISABLED",   Datetime(0),                 NULLABLE),
1875

1876
#define	METRIC_TIME_ELAPSED	12
1877
  Column("TIME_ELAPSED",    SLonglong(),                 NULLABLE),
1878

1879
#define	METRIC_RESET_TIME	13
1880
  Column("TIME_RESET",      Datetime(0),                 NULLABLE),
1881

1882
#define	METRIC_STATUS		14
1883
  Column("ENABLED", SLong(1), NOT_NULL),
1884

1885
#define	METRIC_TYPE		15
1886
  Column("TYPE",    Enum(&metric_type_values_typelib), NOT_NULL, DEFAULT_NONE),
1887

1888
#define	METRIC_DESC		16
1889 1890
  Column("COMMENT",         Varchar(NAME_LEN + 1),       NOT_NULL),
  CEnd()
1891
};
1892
} // namespace Show
1893

1894 1895
/**********************************************************************//**
Fill the information schema metrics table.
1896
@return 0 on success */
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
static
int
i_s_metrics_fill(
/*=============*/
	THD*		thd,		/*!< in: thread */
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
	int		count;
	Field**		fields;
	double		time_diff = 0;
	monitor_info_t*	monitor_info;
	mon_type_t	min_val;
	mon_type_t	max_val;
1910

1911 1912
	DBUG_ENTER("i_s_metrics_fill");
	fields = table_to_fill->field;
1913

1914 1915
	for (count = 0; count < NUM_MONITOR; count++) {
		monitor_info = srv_mon_get_info((monitor_id_t) count);
1916

1917 1918
		/* A good place to sanity check the Monitor ID */
		ut_a(count == monitor_info->monitor_id);
1919

1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
		/* If the item refers to a Module, nothing to fill,
		continue. */
		if ((monitor_info->monitor_type & MONITOR_MODULE)
		    || (monitor_info->monitor_type & MONITOR_HIDDEN)) {
			continue;
		}

		/* If this is an existing "status variable", and
		its corresponding counter is still on, we need
		to calculate the result from its corresponding
		counter. */
		if (monitor_info->monitor_type & MONITOR_EXISTING
		    && MONITOR_IS_ON(count)) {
			srv_mon_process_existing_counter((monitor_id_t) count,
							 MONITOR_GET_VALUE);
		}

		/* Fill in counter's basic information */
		OK(field_store_string(fields[METRIC_NAME],
				      monitor_info->monitor_name));

		OK(field_store_string(fields[METRIC_SUBSYS],
				      monitor_info->monitor_module));

		OK(field_store_string(fields[METRIC_DESC],
				      monitor_info->monitor_desc));

		/* Fill in counter values */
		OK(fields[METRIC_VALUE_RESET]->store(
			MONITOR_VALUE(count), FALSE));

		OK(fields[METRIC_VALUE_START]->store(
			MONITOR_VALUE_SINCE_START(count), FALSE));

		/* If the max value is MAX_RESERVED, counter max
		value has not been updated. Set the column value
		to NULL. */
		if (MONITOR_MAX_VALUE(count) == MAX_RESERVED
		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
			fields[METRIC_MAX_VALUE_RESET]->set_null();
		} else {
			OK(fields[METRIC_MAX_VALUE_RESET]->store(
				MONITOR_MAX_VALUE(count), FALSE));
			fields[METRIC_MAX_VALUE_RESET]->set_notnull();
		}

		/* If the min value is MAX_RESERVED, counter min
		value has not been updated. Set the column value
		to NULL. */
		if (MONITOR_MIN_VALUE(count) == MIN_RESERVED
		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
			fields[METRIC_MIN_VALUE_RESET]->set_null();
		} else {
			OK(fields[METRIC_MIN_VALUE_RESET]->store(
				MONITOR_MIN_VALUE(count), FALSE));
			fields[METRIC_MIN_VALUE_RESET]->set_notnull();
		}

		/* Calculate the max value since counter started */
		max_val = srv_mon_calc_max_since_start((monitor_id_t) count);

		if (max_val == MAX_RESERVED
		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
			fields[METRIC_MAX_VALUE_START]->set_null();
		} else {
			OK(fields[METRIC_MAX_VALUE_START]->store(
				max_val, FALSE));
			fields[METRIC_MAX_VALUE_START]->set_notnull();
		}

		/* Calculate the min value since counter started */
		min_val = srv_mon_calc_min_since_start((monitor_id_t) count);

		if (min_val == MIN_RESERVED
		    || MONITOR_MAX_MIN_NOT_INIT(count)) {
			fields[METRIC_MIN_VALUE_START]->set_null();
		} else {
			OK(fields[METRIC_MIN_VALUE_START]->store(
				min_val, FALSE));

			fields[METRIC_MIN_VALUE_START]->set_notnull();
		}

		/* If monitor has been enabled (no matter it is disabled
		or not now), fill METRIC_START_TIME and METRIC_TIME_ELAPSED
		field */
		if (MONITOR_FIELD(count, mon_start_time)) {
			OK(field_store_time_t(fields[METRIC_START_TIME],
				(time_t)MONITOR_FIELD(count, mon_start_time)));
			fields[METRIC_START_TIME]->set_notnull();

			/* If monitor is enabled, the TIME_ELAPSED is the
			time difference between current and time when monitor
			is enabled. Otherwise, it is the time difference
			between time when monitor is enabled and time
			when it is disabled */
			if (MONITOR_IS_ON(count)) {
				time_diff = difftime(time(NULL),
					MONITOR_FIELD(count, mon_start_time));
			} else {
				time_diff =  difftime(
					MONITOR_FIELD(count, mon_stop_time),
					MONITOR_FIELD(count, mon_start_time));
			}

			OK(fields[METRIC_TIME_ELAPSED]->store(
				time_diff));
			fields[METRIC_TIME_ELAPSED]->set_notnull();
		} else {
			fields[METRIC_START_TIME]->set_null();
			fields[METRIC_TIME_ELAPSED]->set_null();
			time_diff = 0;
		}

2034
		/* Unless MONITOR_NO_AVERAGE is set, we must
2035 2036 2037 2038 2039 2040 2041
		to calculate the average value. If this is a monitor set
		owner marked by MONITOR_SET_OWNER, divide
		the value by another counter (number of calls) designated
		by monitor_info->monitor_related_id.
		Otherwise average the counter value by the time between the
		time that the counter is enabled and time it is disabled
		or time it is sampled. */
2042 2043 2044
		if ((monitor_info->monitor_type
		     & (MONITOR_NO_AVERAGE | MONITOR_SET_OWNER))
		    == MONITOR_SET_OWNER
2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059
		    && monitor_info->monitor_related_id) {
			mon_type_t	value_start
				 = MONITOR_VALUE_SINCE_START(
					monitor_info->monitor_related_id);

			if (value_start) {
				OK(fields[METRIC_AVG_VALUE_START]->store(
					MONITOR_VALUE_SINCE_START(count)
					/ value_start, FALSE));

				fields[METRIC_AVG_VALUE_START]->set_notnull();
			} else {
				fields[METRIC_AVG_VALUE_START]->set_null();
			}

2060 2061 2062 2063 2064 2065
			if (mon_type_t related_value =
			    MONITOR_VALUE(monitor_info->monitor_related_id)) {
				OK(fields[METRIC_AVG_VALUE_RESET]
				   ->store(MONITOR_VALUE(count)
					   / related_value, false));
				fields[METRIC_AVG_VALUE_RESET]->set_notnull();
2066 2067 2068
			} else {
				fields[METRIC_AVG_VALUE_RESET]->set_null();
			}
2069 2070 2071
		} else if (!(monitor_info->monitor_type
			     & (MONITOR_NO_AVERAGE
				| MONITOR_DISPLAY_CURRENT))) {
2072
			if (time_diff != 0) {
2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
				OK(fields[METRIC_AVG_VALUE_START]->store(
					(double) MONITOR_VALUE_SINCE_START(
						count) / time_diff));
				fields[METRIC_AVG_VALUE_START]->set_notnull();
			} else {
				fields[METRIC_AVG_VALUE_START]->set_null();
			}

			if (MONITOR_FIELD(count, mon_reset_time)) {
				/* calculate the time difference since last
				reset */
				if (MONITOR_IS_ON(count)) {
					time_diff = difftime(
						time(NULL), MONITOR_FIELD(
							count, mon_reset_time));
				} else {
					time_diff =  difftime(
					MONITOR_FIELD(count, mon_stop_time),
					MONITOR_FIELD(count, mon_reset_time));
				}
			} else {
				time_diff = 0;
			}

2097
			if (time_diff != 0) {
2098
				OK(fields[METRIC_AVG_VALUE_RESET]->store(
Sergei Golubchik's avatar
Sergei Golubchik committed
2099
					static_cast<double>(
2100 2101
						MONITOR_VALUE(count))
					/ time_diff));
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
				fields[METRIC_AVG_VALUE_RESET]->set_notnull();
			} else {
				fields[METRIC_AVG_VALUE_RESET]->set_null();
			}
		} else {
			fields[METRIC_AVG_VALUE_START]->set_null();
			fields[METRIC_AVG_VALUE_RESET]->set_null();
		}

		if (MONITOR_IS_ON(count)) {
			/* If monitor is on, the stop time will set to NULL */
			fields[METRIC_STOP_TIME]->set_null();

			/* Display latest Monitor Reset Time only if Monitor
			counter is on. */
			if (MONITOR_FIELD(count, mon_reset_time)) {
				OK(field_store_time_t(
					fields[METRIC_RESET_TIME],
					(time_t)MONITOR_FIELD(
						count, mon_reset_time)));
				fields[METRIC_RESET_TIME]->set_notnull();
			} else {
				fields[METRIC_RESET_TIME]->set_null();
			}

2127
			OK(fields[METRIC_STATUS]->store(1, true));
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
		} else {
			if (MONITOR_FIELD(count, mon_stop_time)) {
				OK(field_store_time_t(fields[METRIC_STOP_TIME],
				(time_t)MONITOR_FIELD(count, mon_stop_time)));
				fields[METRIC_STOP_TIME]->set_notnull();
			} else {
				fields[METRIC_STOP_TIME]->set_null();
			}

			fields[METRIC_RESET_TIME]->set_null();

2139
			OK(fields[METRIC_STATUS]->store(0, true));
2140 2141
		}

2142 2143
		uint metric_type;

2144
		if (monitor_info->monitor_type & MONITOR_DISPLAY_CURRENT) {
2145
			metric_type = 1; /* "value" */
2146
		} else if (monitor_info->monitor_type & MONITOR_EXISTING) {
2147
			metric_type = 2; /* "status_counter" */
2148
		} else if (monitor_info->monitor_type & MONITOR_SET_OWNER) {
2149 2150 2151
			metric_type = 3; /* "set_owner" */
		} else if (monitor_info->monitor_type & MONITOR_SET_MEMBER) {
			metric_type = 4; /* "set_member" */
2152
		} else {
2153
			metric_type = 5; /* "counter" */
2154 2155
		}

2156 2157
		OK(fields[METRIC_TYPE]->store(metric_type, true));

2158 2159 2160 2161 2162 2163 2164 2165
		OK(schema_table_store_record(thd, table_to_fill));
	}

	DBUG_RETURN(0);
}

/*******************************************************************//**
Function to fill information schema metrics tables.
2166
@return 0 on success */
2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
static
int
i_s_metrics_fill_table(
/*===================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
	DBUG_ENTER("i_s_metrics_fill_table");

	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

	i_s_metrics_fill(thd, tables->table);

	DBUG_RETURN(0);
}
/*******************************************************************//**
Bind the dynamic table INFORMATION_SCHEMA.innodb_metrics
2188
@return 0 on success */
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200
static
int
innodb_metrics_init(
/*================*/
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

	DBUG_ENTER("innodb_metrics_init");

	schema = (ST_SCHEMA_TABLE*) p;

2201
	schema->fields_info = Show::innodb_metrics_fields_info;
2202 2203 2204 2205 2206
	schema->fill_table = i_s_metrics_fill_table;

	DBUG_RETURN(0);
}

2207
struct st_maria_plugin	i_s_innodb_metrics =
2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_METRICS"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB Metrics Info"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, innodb_metrics_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

2251 2252
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
2253
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
2254
};
2255 2256

namespace Show {
2257 2258 2259 2260
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_ft_default_stopword */
static ST_FIELD_INFO	i_s_stopword_fields_info[] =
{
#define STOPWORD_VALUE	0
2261 2262
  Column("value", Varchar(TRX_ID_MAX_LEN + 1), NOT_NULL),
  CEnd()
2263
};
2264
} // namespace Show
2265 2266 2267

/*******************************************************************//**
Fill the dynamic table information_schema.innodb_ft_default_stopword.
2268
@return 0 on success, 1 on failure */
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299
static
int
i_s_stopword_fill(
/*==============*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
	Field**	fields;
	ulint	i = 0;
	TABLE*	table = (TABLE*) tables->table;

	DBUG_ENTER("i_s_stopword_fill");

	fields = table->field;

	/* Fill with server default stopword list in array
	fts_default_stopword */
	while (fts_default_stopword[i]) {
		OK(field_store_string(fields[STOPWORD_VALUE],
				      fts_default_stopword[i]));

		OK(schema_table_store_record(thd, table));
		i++;
	}

	DBUG_RETURN(0);
}

/*******************************************************************//**
Bind the dynamic table information_schema.innodb_ft_default_stopword.
2300
@return 0 on success */
2301 2302 2303 2304 2305 2306 2307 2308 2309
static
int
i_s_stopword_init(
/*==============*/
	void*	p)	/*!< in/out: table schema object */
{
	DBUG_ENTER("i_s_stopword_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

2310
	schema->fields_info = Show::i_s_stopword_fields_info;
2311 2312 2313 2314 2315
	schema->fill_table = i_s_stopword_fill;

	DBUG_RETURN(0);
}

2316
struct st_maria_plugin	i_s_innodb_ft_default_stopword =
2317 2318 2319 2320 2321 2322 2323
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
2324
	STRUCT_FLD(info, &i_s_info),
2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_FT_DEFAULT_STOPWORD"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
2336
	STRUCT_FLD(descr, "Default stopword list for InnoDB Full Text Search"),
2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, i_s_stopword_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

2360 2361
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
2362
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
2363 2364
};

2365
namespace Show {
2366
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2367
INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED */
2368 2369 2370
static ST_FIELD_INFO	i_s_fts_doc_fields_info[] =
{
#define	I_S_FTS_DOC_ID			0
2371 2372
  Column("DOC_ID", ULonglong(), NOT_NULL),
  CEnd()
2373
};
2374
} // namespace Show
2375 2376 2377 2378

/*******************************************************************//**
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED or
INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2379
@return 0 on success, 1 on failure */
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
static
int
i_s_fts_deleted_generic_fill(
/*=========================*/
	THD*		thd,		/*!< in: thread */
	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
	ibool		being_deleted)	/*!< in: BEING_DELTED table */
{
	Field**			fields;
	TABLE*			table = (TABLE*) tables->table;
	trx_t*			trx;
	fts_table_t		fts_table;
	fts_doc_ids_t*		deleted;
	dict_table_t*		user_table;

	DBUG_ENTER("i_s_fts_deleted_generic_fill");

	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

2402
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
2403

2404 2405
	/* Prevent DROP of the internal tables for fulltext indexes.
	FIXME: acquire DDL-blocking MDL on the user table name! */
2406
	dict_sys.freeze();
2407

2408 2409
	user_table = dict_table_open_on_id(
		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
2410 2411

	if (!user_table) {
2412 2413
func_exit:
		dict_sys.unfreeze();
2414
		DBUG_RETURN(0);
2415 2416
	} else if (!dict_table_has_fts_index(user_table)
		   || !user_table->is_readable()) {
2417
		dict_table_close(user_table, FALSE, FALSE);
2418
		goto func_exit;
2419 2420
	}

2421 2422
	deleted = fts_doc_ids_create();

2423
	trx = trx_create();
2424 2425 2426 2427 2428 2429 2430 2431
	trx->op_info = "Select for FTS DELETE TABLE";

	FTS_INIT_FTS_TABLE(&fts_table,
			   (being_deleted) ? "BEING_DELETED" : "DELETED",
			   FTS_COMMON_TABLE, user_table);

	fts_table_fetch_doc_ids(trx, &fts_table, deleted);

2432 2433
	dict_table_close(user_table, FALSE, FALSE);

2434
	dict_sys.unfreeze();
2435

Marko Mäkelä's avatar
Marko Mäkelä committed
2436
	trx->free();
2437

2438 2439
	fields = table->field;

2440 2441
	int	ret = 0;

2442 2443 2444 2445 2446
	for (ulint j = 0; j < ib_vector_size(deleted->doc_ids); ++j) {
		doc_id_t	doc_id;

		doc_id = *(doc_id_t*) ib_vector_get_const(deleted->doc_ids, j);

2447
		BREAK_IF(ret = fields[I_S_FTS_DOC_ID]->store(doc_id, true));
2448

2449
		BREAK_IF(ret = schema_table_store_record(thd, table));
2450 2451 2452 2453
	}

	fts_doc_ids_free(deleted);

2454
	DBUG_RETURN(ret);
2455 2456 2457 2458
}

/*******************************************************************//**
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2459
@return 0 on success, 1 on failure */
2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474
static
int
i_s_fts_deleted_fill(
/*=================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (ignored) */
{
	DBUG_ENTER("i_s_fts_deleted_fill");

	DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, FALSE));
}

/*******************************************************************//**
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
2475
@return 0 on success */
2476 2477 2478 2479 2480 2481 2482 2483 2484
static
int
i_s_fts_deleted_init(
/*=================*/
	void*	p)	/*!< in/out: table schema object */
{
	DBUG_ENTER("i_s_fts_deleted_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

2485
	schema->fields_info = Show::i_s_fts_doc_fields_info;
2486 2487 2488 2489 2490
	schema->fill_table = i_s_fts_deleted_fill;

	DBUG_RETURN(0);
}

2491
struct st_maria_plugin	i_s_innodb_ft_deleted =
2492 2493 2494 2495 2496 2497 2498
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
2499
	STRUCT_FLD(info, &i_s_info),
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_FT_DELETED"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "INNODB AUXILIARY FTS DELETED TABLE"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, i_s_fts_deleted_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

2535 2536
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
2537
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
2538 2539 2540 2541
};

/*******************************************************************//**
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2542
@return 0 on success, 1 on failure */
2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557
static
int
i_s_fts_being_deleted_fill(
/*=======================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (ignored) */
{
	DBUG_ENTER("i_s_fts_being_deleted_fill");

	DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, TRUE));
}

/*******************************************************************//**
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
2558
@return 0 on success */
2559 2560 2561 2562 2563 2564 2565 2566 2567
static
int
i_s_fts_being_deleted_init(
/*=======================*/
	void*	p)	/*!< in/out: table schema object */
{
	DBUG_ENTER("i_s_fts_deleted_init");
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

2568
	schema->fields_info = Show::i_s_fts_doc_fields_info;
2569 2570 2571 2572 2573
	schema->fill_table = i_s_fts_being_deleted_fill;

	DBUG_RETURN(0);
}

2574
struct st_maria_plugin	i_s_innodb_ft_being_deleted =
2575 2576 2577 2578 2579 2580 2581
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
2582
	STRUCT_FLD(info, &i_s_info),
2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_FT_BEING_DELETED"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "INNODB AUXILIARY FTS BEING DELETED TABLE"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, i_s_fts_being_deleted_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

2618 2619
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
2620
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
2621 2622
};

2623 2624

namespace Show {
2625 2626 2627 2628 2629
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED and
INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE */
static ST_FIELD_INFO	i_s_fts_index_fields_info[] =
{
#define	I_S_FTS_WORD			0
2630
  Column("WORD",         Varchar(FTS_MAX_WORD_LEN + 1), NOT_NULL),
2631 2632

#define	I_S_FTS_FIRST_DOC_ID		1
2633
  Column("FIRST_DOC_ID", ULonglong(),                   NOT_NULL),
2634 2635

#define	I_S_FTS_LAST_DOC_ID		2
2636
  Column("LAST_DOC_ID",  ULonglong(),                   NOT_NULL),
2637 2638

#define	I_S_FTS_DOC_COUNT		3
2639
  Column("DOC_COUNT",    ULonglong(),                   NOT_NULL),
2640 2641

#define	I_S_FTS_ILIST_DOC_ID		4
2642
  Column("DOC_ID",       ULonglong(),                   NOT_NULL),
2643 2644

#define	I_S_FTS_ILIST_DOC_POS		5
2645 2646
  Column("POSITION",     ULonglong(),                   NOT_NULL),
  CEnd()
2647
};
2648
} // namespace Show
2649 2650 2651 2652

/*******************************************************************//**
Go through the Doc Node and its ilist, fill the dynamic table
INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED for one FTS index on the table.
2653
@return 0 on success, 1 on failure */
2654 2655 2656 2657 2658 2659
static
int
i_s_fts_index_cache_fill_one_index(
/*===============================*/
	fts_index_cache_t*	index_cache,	/*!< in: FTS index cache */
	THD*			thd,		/*!< in: thread */
2660
	fts_string_t*		conv_str,	/*!< in/out: buffer */
2661 2662 2663 2664
	TABLE_LIST*		tables)		/*!< in/out: tables to fill */
{
	TABLE*			table = (TABLE*) tables->table;
	Field**			fields;
Sergei Golubchik's avatar
Sergei Golubchik committed
2665
	CHARSET_INFO*		index_charset;
2666
	const ib_rbt_node_t*	rbt_node;
Sergei Golubchik's avatar
Sergei Golubchik committed
2667 2668
	uint			dummy_errors;
	char*			word_str;
2669 2670 2671 2672 2673

	DBUG_ENTER("i_s_fts_index_cache_fill_one_index");

	fields = table->field;

Sergei Golubchik's avatar
Sergei Golubchik committed
2674
	index_charset = index_cache->charset;
2675 2676 2677
	conv_str->f_n_char = 0;

	int	ret = 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
2678

2679 2680 2681 2682 2683 2684 2685 2686
	/* Go through each word in the index cache */
	for (rbt_node = rbt_first(index_cache->words);
	     rbt_node;
	     rbt_node = rbt_next(index_cache->words, rbt_node)) {
		fts_tokenizer_word_t* word;

		word = rbt_value(fts_tokenizer_word_t, rbt_node);

Sergei Golubchik's avatar
Sergei Golubchik committed
2687 2688
		/* Convert word from index charset to system_charset_info */
		if (index_charset->cset != system_charset_info->cset) {
2689 2690 2691
			conv_str->f_n_char = my_convert(
				reinterpret_cast<char*>(conv_str->f_str),
				static_cast<uint32>(conv_str->f_len),
Sergei Golubchik's avatar
Sergei Golubchik committed
2692
				system_charset_info,
Sergei Golubchik's avatar
Sergei Golubchik committed
2693
				reinterpret_cast<char*>(word->text.f_str),
Sergei Golubchik's avatar
Sergei Golubchik committed
2694 2695
				static_cast<uint32>(word->text.f_len),
				index_charset, &dummy_errors);
2696 2697 2698
			ut_ad(conv_str->f_n_char <= conv_str->f_len);
			conv_str->f_str[conv_str->f_n_char] = 0;
			word_str = reinterpret_cast<char*>(conv_str->f_str);
Sergei Golubchik's avatar
Sergei Golubchik committed
2699 2700 2701 2702
		} else {
			word_str = reinterpret_cast<char*>(word->text.f_str);
		}

2703 2704 2705 2706 2707
		/* Decrypt the ilist, and display Dod ID and word position */
		for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
			fts_node_t*	node;
			byte*		ptr;
			ulint		decoded = 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
2708
			doc_id_t	doc_id = 0;
2709 2710 2711 2712 2713

			node = static_cast<fts_node_t*> (ib_vector_get(
				word->nodes, i));

			ptr = node->ilist;
2714

2715 2716 2717 2718 2719 2720 2721 2722 2723 2724
			while (decoded < node->ilist_size) {
				ulint	pos = fts_decode_vlc(&ptr);

				doc_id += pos;

				/* Get position info */
				while (*ptr) {
					pos = fts_decode_vlc(&ptr);

					OK(field_store_string(
2725 2726
						   fields[I_S_FTS_WORD],
						   word_str));
2727 2728

					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
2729 2730
						   node->first_doc_id,
						   true));
2731 2732

					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
2733 2734
						   node->last_doc_id,
						   true));
2735 2736

					OK(fields[I_S_FTS_DOC_COUNT]->store(
2737
						   node->doc_count, true));
2738 2739

					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
2740
						   doc_id, true));
2741 2742

					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
2743
						   pos, true));
2744 2745

					OK(schema_table_store_record(
2746
						   thd, table));
2747 2748 2749 2750 2751 2752 2753 2754 2755
				}

				++ptr;

				decoded = ptr - (byte*) node->ilist;
			}
		}
	}

2756
	DBUG_RETURN(ret);
2757
}
2758
/*******************************************************************//**
2759
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED
2760
@return 0 on success, 1 on failure */
2761 2762
static
int
2763 2764
i_s_fts_index_cache_fill(
/*=====================*/
2765 2766 2767 2768
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (ignored) */
{
2769 2770
	dict_table_t*		user_table;
	fts_cache_t*		cache;
2771

2772 2773 2774 2775 2776 2777 2778
	DBUG_ENTER("i_s_fts_index_cache_fill");

	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

2779
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
2780

2781 2782
	/* Prevent DROP of the internal tables for fulltext indexes.
	FIXME: acquire DDL-blocking MDL on the user table name! */
2783
	dict_sys.freeze();
2784

2785 2786
	user_table = dict_table_open_on_id(
		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
2787 2788

	if (!user_table) {
2789
no_fts:
2790
		dict_sys.unfreeze();
2791 2792 2793
		DBUG_RETURN(0);
	}

2794
	if (!user_table->fts || !user_table->fts->cache) {
2795
		dict_table_close(user_table, FALSE, FALSE);
2796
		goto no_fts;
2797 2798
	}

2799 2800
	cache = user_table->fts->cache;

2801 2802
	int			ret = 0;
	fts_string_t		conv_str;
2803 2804 2805
	byte			word[HA_FT_MAXBYTELEN + 1];
	conv_str.f_len = sizeof word;
	conv_str.f_str = word;
2806

2807
	mysql_mutex_lock(&cache->lock);
2808

2809 2810 2811 2812 2813 2814
	for (ulint i = 0; i < ib_vector_size(cache->indexes); i++) {
		fts_index_cache_t*      index_cache;

		index_cache = static_cast<fts_index_cache_t*> (
			ib_vector_get(cache->indexes, i));

2815 2816
		BREAK_IF(ret = i_s_fts_index_cache_fill_one_index(
				 index_cache, thd, &conv_str, tables));
2817 2818
	}

2819
	mysql_mutex_unlock(&cache->lock);
2820
	dict_table_close(user_table, FALSE, FALSE);
2821
	dict_sys.unfreeze();
2822

2823
	DBUG_RETURN(ret);
2824 2825 2826
}

/*******************************************************************//**
2827
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE
2828
@return 0 on success */
2829 2830
static
int
2831 2832
i_s_fts_index_cache_init(
/*=====================*/
2833 2834
	void*	p)	/*!< in/out: table schema object */
{
2835
	DBUG_ENTER("i_s_fts_index_cache_init");
2836 2837
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

2838
	schema->fields_info = Show::i_s_fts_index_fields_info;
2839
	schema->fill_table = i_s_fts_index_cache_fill;
2840 2841 2842 2843

	DBUG_RETURN(0);
}

2844
struct st_maria_plugin	i_s_innodb_ft_index_cache =
2845 2846 2847 2848 2849 2850 2851
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
2852
	STRUCT_FLD(info, &i_s_info),
2853 2854 2855

	/* plugin name */
	/* const char* */
2856
	STRUCT_FLD(name, "INNODB_FT_INDEX_CACHE"),
2857 2858 2859 2860 2861 2862 2863

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
2864
	STRUCT_FLD(descr, "INNODB AUXILIARY FTS INDEX CACHED"),
2865 2866 2867 2868 2869 2870 2871

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
2872
	STRUCT_FLD(init, i_s_fts_index_cache_init),
2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

2888 2889
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
2890
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
2891 2892 2893
};

/*******************************************************************//**
2894 2895
Go through a FTS index auxiliary table, fetch its rows and fill
FTS word cache structure.
2896
@return DB_SUCCESS on success, otherwise error code */
2897
static
Sergei Golubchik's avatar
Sergei Golubchik committed
2898
dberr_t
2899 2900 2901 2902 2903
i_s_fts_index_table_fill_selected(
/*==============================*/
	dict_index_t*		index,		/*!< in: FTS index */
	ib_vector_t*		words,		/*!< in/out: vector to hold
						fetched words */
Sergei Golubchik's avatar
Sergei Golubchik committed
2904 2905
	ulint			selected,	/*!< in: selected FTS index */
	fts_string_t*		word)		/*!< in: word to select */
2906
{
2907 2908 2909 2910
	pars_info_t*		info;
	fts_table_t		fts_table;
	trx_t*			trx;
	que_t*			graph;
Sergei Golubchik's avatar
Sergei Golubchik committed
2911
	dberr_t			error;
2912
	fts_fetch_t		fetch;
2913
	char			table_name[MAX_FULL_NAME_LEN];
2914

2915 2916 2917 2918
	info = pars_info_create();

	fetch.read_arg = words;
	fetch.read_record = fts_optimize_index_fetch_node;
Sergei Golubchik's avatar
Sergei Golubchik committed
2919 2920 2921 2922 2923
	fetch.total_memory = 0;

	DBUG_EXECUTE_IF("fts_instrument_result_cache_limit",
	        fts_result_cache_limit = 8192;
	);
2924

2925
	trx = trx_create();
2926 2927 2928 2929

	trx->op_info = "fetching FTS index nodes";

	pars_info_bind_function(info, "my_func", fetch.read_record, &fetch);
Sergei Golubchik's avatar
Sergei Golubchik committed
2930
	pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len);
2931 2932 2933

	FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected),
			     FTS_INDEX_TABLE, index);
2934 2935
	fts_get_table_name(&fts_table, table_name);
	pars_info_bind_id(info, true, "table_name", table_name);
2936 2937 2938 2939 2940

	graph = fts_parse_sql(
		&fts_table, info,
		"DECLARE FUNCTION my_func;\n"
		"DECLARE CURSOR c IS"
2941 2942 2943
		" SELECT word, doc_count, first_doc_id, last_doc_id,"
		" ilist\n"
		" FROM $table_name WHERE word >= :word;\n"
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954
		"BEGIN\n"
		"\n"
		"OPEN c;\n"
		"WHILE 1 = 1 LOOP\n"
		"  FETCH c INTO my_func();\n"
		"  IF c % NOTFOUND THEN\n"
		"    EXIT;\n"
		"  END IF;\n"
		"END LOOP;\n"
		"CLOSE c;");

2955
	for (;;) {
2956 2957
		error = fts_eval_sql(trx, graph);

2958
		if (UNIV_LIKELY(error == DB_SUCCESS)) {
2959 2960 2961 2962 2963 2964 2965
			fts_sql_commit(trx);

			break;
		} else {
			fts_sql_rollback(trx);

			if (error == DB_LOCK_WAIT_TIMEOUT) {
2966 2967
				ib::warn() << "Lock wait timeout reading"
					" FTS index. Retrying!";
2968 2969 2970

				trx->error_state = DB_SUCCESS;
			} else {
2971
				ib::error() << "Error occurred while reading"
2972
					" FTS index: " << error;
2973 2974 2975 2976 2977
				break;
			}
		}
	}

2978
	fts_que_graph_free(graph);
2979

Marko Mäkelä's avatar
Marko Mäkelä committed
2980
	trx->free();
2981

Sergei Golubchik's avatar
Sergei Golubchik committed
2982 2983 2984 2985
	if (fetch.total_memory >= fts_result_cache_limit) {
		error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT;
	}

2986
	return(error);
2987 2988 2989
}

/*******************************************************************//**
Sergei Golubchik's avatar
Sergei Golubchik committed
2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
Free words. */
static
void
i_s_fts_index_table_free_one_fetch(
/*===============================*/
	ib_vector_t*		words)		/*!< in: words fetched */
{
	for (ulint i = 0; i < ib_vector_size(words); i++) {
		fts_word_t*	word;

		word = static_cast<fts_word_t*>(ib_vector_get(words, i));

		for (ulint j = 0; j < ib_vector_size(word->nodes); j++) {
			fts_node_t*     node;

			node = static_cast<fts_node_t*> (ib_vector_get(
				word->nodes, j));
			ut_free(node->ilist);
		}

		fts_word_free(word);
	}

	ib_vector_reset(words);
}

/*******************************************************************//**
Go through words, fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
3018
@return	0 on success, 1 on failure */
3019 3020
static
int
Sergei Golubchik's avatar
Sergei Golubchik committed
3021
i_s_fts_index_table_fill_one_fetch(
3022
/*===============================*/
Sergei Golubchik's avatar
Sergei Golubchik committed
3023
	CHARSET_INFO*		index_charset,	/*!< in: FTS index charset */
3024
	THD*			thd,		/*!< in: thread */
Sergei Golubchik's avatar
Sergei Golubchik committed
3025 3026 3027 3028
	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
	ib_vector_t*		words,		/*!< in: words fetched */
	fts_string_t*		conv_str,	/*!< in: string for conversion*/
	bool			has_more)	/*!< in: has more to fetch */
3029
{
3030 3031
	TABLE*			table = (TABLE*) tables->table;
	Field**			fields;
Sergei Golubchik's avatar
Sergei Golubchik committed
3032 3033 3034 3035
	uint			dummy_errors;
	char*			word_str;
	ulint			words_size;
	int			ret = 0;
3036

Sergei Golubchik's avatar
Sergei Golubchik committed
3037
	DBUG_ENTER("i_s_fts_index_table_fill_one_fetch");
3038 3039 3040

	fields = table->field;

Sergei Golubchik's avatar
Sergei Golubchik committed
3041 3042 3043 3044 3045
	words_size = ib_vector_size(words);
	if (has_more) {
		/* the last word is not fetched completely. */
		ut_ad(words_size > 1);
		words_size -= 1;
3046 3047 3048
	}

	/* Go through each word in the index cache */
Sergei Golubchik's avatar
Sergei Golubchik committed
3049
	for (ulint i = 0; i < words_size; i++) {
3050 3051
		fts_word_t*	word;

Sergei Golubchik's avatar
Sergei Golubchik committed
3052
		word = static_cast<fts_word_t*>(ib_vector_get(words, i));
3053 3054 3055

		word->text.f_str[word->text.f_len] = 0;

Sergei Golubchik's avatar
Sergei Golubchik committed
3056 3057 3058 3059
		/* Convert word from index charset to system_charset_info */
		if (index_charset->cset != system_charset_info->cset) {
			conv_str->f_n_char = my_convert(
				reinterpret_cast<char*>(conv_str->f_str),
Sergei Golubchik's avatar
Sergei Golubchik committed
3060 3061
				static_cast<uint32>(conv_str->f_len),
				system_charset_info,
Sergei Golubchik's avatar
Sergei Golubchik committed
3062
				reinterpret_cast<char*>(word->text.f_str),
Sergei Golubchik's avatar
Sergei Golubchik committed
3063 3064
				static_cast<uint32>(word->text.f_len),
				index_charset, &dummy_errors);
Sergei Golubchik's avatar
Sergei Golubchik committed
3065 3066 3067 3068 3069 3070 3071
			ut_ad(conv_str->f_n_char <= conv_str->f_len);
			conv_str->f_str[conv_str->f_n_char] = 0;
			word_str = reinterpret_cast<char*>(conv_str->f_str);
		} else {
			word_str = reinterpret_cast<char*>(word->text.f_str);
		}

3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082
		/* Decrypt the ilist, and display Dod ID and word position */
		for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
			fts_node_t*	node;
			byte*		ptr;
			ulint		decoded = 0;
			doc_id_t	doc_id = 0;

			node = static_cast<fts_node_t*> (ib_vector_get(
				word->nodes, i));

			ptr = node->ilist;
3083

3084 3085
			while (decoded < node->ilist_size) {
				ulint	pos = fts_decode_vlc(&ptr);
3086

3087
				doc_id += pos;
3088

3089 3090 3091
				/* Get position info */
				while (*ptr) {
					pos = fts_decode_vlc(&ptr);
3092

3093
					OK(field_store_string(
3094 3095
						   fields[I_S_FTS_WORD],
						   word_str));
3096

3097
					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
3098
						longlong(node->first_doc_id), true));
3099

3100
					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
3101
						longlong(node->last_doc_id), true));
3102

3103
					OK(fields[I_S_FTS_DOC_COUNT]->store(
3104
						   node->doc_count, true));
3105

3106
					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
3107
						longlong(doc_id), true));
3108

3109
					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
3110
						   pos, true));
3111

3112
					OK(schema_table_store_record(
3113
						   thd, table));
3114
				}
3115

3116
				++ptr;
3117

3118 3119 3120 3121
				decoded = ptr - (byte*) node->ilist;
			}
		}
	}
3122

Sergei Golubchik's avatar
Sergei Golubchik committed
3123 3124 3125 3126 3127 3128
	DBUG_RETURN(ret);
}

/*******************************************************************//**
Go through a FTS index and its auxiliary tables, fetch rows in each table
and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
3129
@return 0 on success, 1 on failure */
Sergei Golubchik's avatar
Sergei Golubchik committed
3130 3131 3132 3133 3134 3135
static
int
i_s_fts_index_table_fill_one_index(
/*===============================*/
	dict_index_t*		index,		/*!< in: FTS index */
	THD*			thd,		/*!< in: thread */
3136
	fts_string_t*		conv_str,	/*!< in/out: buffer */
Sergei Golubchik's avatar
Sergei Golubchik committed
3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156
	TABLE_LIST*		tables)		/*!< in/out: tables to fill */
{
	ib_vector_t*		words;
	mem_heap_t*		heap;
	CHARSET_INFO*		index_charset;
	dberr_t			error;
	int			ret = 0;

	DBUG_ENTER("i_s_fts_index_table_fill_one_index");
	DBUG_ASSERT(!dict_index_is_online_ddl(index));

	heap = mem_heap_create(1024);

	words = ib_vector_create(ib_heap_allocator_create(heap),
				 sizeof(fts_word_t), 256);

	index_charset = fts_index_get_charset(index);

	/* Iterate through each auxiliary table as described in
	fts_index_selector */
3157 3158 3159 3160 3161 3162 3163
	for (ulint selected = 0; selected < FTS_NUM_AUX_INDEX; selected++) {
		fts_string_t	word;
		bool		has_more = false;

		word.f_str = NULL;
		word.f_len = 0;
		word.f_n_char = 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185

		do {
			/* Fetch from index */
			error = i_s_fts_index_table_fill_selected(
				index, words, selected, &word);

			if (error == DB_SUCCESS) {
				has_more = false;
			} else if (error == DB_FTS_EXCEED_RESULT_CACHE_LIMIT) {
				has_more = true;
			} else {
				i_s_fts_index_table_free_one_fetch(words);
				ret = 1;
				goto func_exit;
			}

			if (has_more) {
				fts_word_t*	last_word;

				/* Prepare start point for next fetch */
				last_word = static_cast<fts_word_t*>(ib_vector_last(words));
				ut_ad(last_word != NULL);
3186
				fts_string_dup(&word, &last_word->text, heap);
Sergei Golubchik's avatar
Sergei Golubchik committed
3187 3188 3189 3190
			}

			/* Fill into tables */
			ret = i_s_fts_index_table_fill_one_fetch(
3191 3192 3193
				index_charset, thd, tables, words, conv_str,
				has_more);
			i_s_fts_index_table_free_one_fetch(words);
Sergei Golubchik's avatar
Sergei Golubchik committed
3194 3195 3196 3197 3198 3199 3200 3201

			if (ret != 0) {
				goto func_exit;
			}
		} while (has_more);
	}

func_exit:
3202
	mem_heap_free(heap);
3203

Sergei Golubchik's avatar
Sergei Golubchik committed
3204
	DBUG_RETURN(ret);
3205
}
3206
/*******************************************************************//**
3207
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
3208
@return 0 on success, 1 on failure */
3209 3210
static
int
3211 3212
i_s_fts_index_table_fill(
/*=====================*/
3213 3214 3215 3216 3217
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (ignored) */
{
	dict_table_t*		user_table;
3218
	dict_index_t*		index;
3219

3220
	DBUG_ENTER("i_s_fts_index_table_fill");
3221 3222 3223 3224 3225 3226

	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

3227
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
3228

3229 3230
	/* Prevent DROP of the internal tables for fulltext indexes.
	FIXME: acquire DDL-blocking MDL on the user table name! */
3231
	dict_sys.freeze();
3232

3233 3234
	user_table = dict_table_open_on_id(
		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
3235 3236

	if (!user_table) {
3237
		dict_sys.unfreeze();
3238 3239 3240
		DBUG_RETURN(0);
	}

3241 3242 3243 3244
	int		ret = 0;
	fts_string_t	conv_str;
	conv_str.f_len = system_charset_info->mbmaxlen
		* FTS_MAX_WORD_LEN_IN_CHAR;
Marko Mäkelä's avatar
Marko Mäkelä committed
3245
	conv_str.f_str = static_cast<byte*>(ut_malloc_nokey(conv_str.f_len));
3246

3247 3248 3249
	for (index = dict_table_get_first_index(user_table);
	     index; index = dict_table_get_next_index(index)) {
		if (index->type & DICT_FTS) {
3250 3251
			BREAK_IF(ret = i_s_fts_index_table_fill_one_index(
					 index, thd, &conv_str, tables));
3252
		}
3253 3254
	}

3255
	dict_table_close(user_table, FALSE, FALSE);
3256

3257
	dict_sys.unfreeze();
3258

3259 3260 3261
	ut_free(conv_str.f_str);

	DBUG_RETURN(ret);
3262 3263 3264
}

/*******************************************************************//**
3265
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
3266
@return 0 on success */
3267 3268
static
int
3269 3270
i_s_fts_index_table_init(
/*=====================*/
3271 3272
	void*	p)	/*!< in/out: table schema object */
{
3273
	DBUG_ENTER("i_s_fts_index_table_init");
3274 3275
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

3276
	schema->fields_info = Show::i_s_fts_index_fields_info;
3277
	schema->fill_table = i_s_fts_index_table_fill;
3278 3279 3280 3281

	DBUG_RETURN(0);
}

3282
struct st_maria_plugin	i_s_innodb_ft_index_table =
3283 3284 3285 3286 3287 3288 3289
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
3290
	STRUCT_FLD(info, &i_s_info),
3291 3292 3293

	/* plugin name */
	/* const char* */
3294
	STRUCT_FLD(name, "INNODB_FT_INDEX_TABLE"),
3295 3296 3297 3298 3299 3300 3301

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
3302
	STRUCT_FLD(descr, "INNODB AUXILIARY FTS INDEX TABLE"),
3303 3304 3305 3306 3307 3308 3309

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
3310
	STRUCT_FLD(init, i_s_fts_index_table_init),
3311 3312 3313 3314 3315

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

3316 3317 3318
	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
3319

3320 3321
	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),
3322

3323 3324
	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),
3325

3326 3327
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
3328
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
3329
};
3330

3331 3332

namespace Show {
3333 3334 3335 3336
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG */
static ST_FIELD_INFO	i_s_fts_config_fields_info[] =
{
#define	FTS_CONFIG_KEY			0
3337
  Column("KEY",   Varchar(NAME_LEN + 1),  NOT_NULL),
3338

3339
#define	FTS_CONFIG_VALUE		1
3340 3341 3342
  Column("VALUE", Varchar(NAME_LEN + 1),  NOT_NULL),

  CEnd()
3343
};
3344
} // namespace Show
3345

3346 3347 3348 3349 3350 3351 3352
static const char* fts_config_key[] = {
	FTS_OPTIMIZE_LIMIT_IN_SECS,
	FTS_SYNCED_DOC_ID,
	FTS_STOPWORD_TABLE_NAME,
	FTS_USE_STOPWORD,
        NULL
};
3353 3354

/*******************************************************************//**
3355
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
3356
@return 0 on success, 1 on failure */
3357 3358
static
int
3359 3360 3361 3362
i_s_fts_config_fill(
/*================*/
	THD*		thd,		/*!< in: thread */
	TABLE_LIST*	tables,		/*!< in/out: tables to fill */
3363 3364
	Item*		)	/*!< in: condition (ignored) */
{
3365 3366 3367 3368
	Field**			fields;
	TABLE*			table = (TABLE*) tables->table;
	trx_t*			trx;
	fts_table_t		fts_table;
3369
	dict_table_t*		user_table;
3370 3371 3372
	ulint			i = 0;
	dict_index_t*		index = NULL;
	unsigned char		str[FTS_MAX_CONFIG_VALUE_LEN + 1];
3373

3374
	DBUG_ENTER("i_s_fts_config_fill");
3375 3376 3377 3378 3379 3380

	/* deny access to non-superusers */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

3381
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
3382

3383 3384
	/* Prevent DROP of the internal tables for fulltext indexes.
	FIXME: acquire DDL-blocking MDL on the user table name! */
3385
	dict_sys.freeze();
3386

3387 3388
	user_table = dict_table_open_on_id(
		innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
3389 3390

	if (!user_table) {
3391
no_fts:
3392
		dict_sys.unfreeze();
Sergei Golubchik's avatar
Sergei Golubchik committed
3393
		DBUG_RETURN(0);
3394
	}
3395

3396 3397 3398
	if (!dict_table_has_fts_index(user_table)) {
		dict_table_close(user_table, FALSE, FALSE);
		goto no_fts;
3399 3400
	}

3401 3402
	fields = table->field;

3403
	trx = trx_create();
Sergei Golubchik's avatar
Sergei Golubchik committed
3404
	trx->op_info = "Select for FTS CONFIG TABLE";
3405

3406
	FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE, user_table);
3407

3408 3409 3410 3411 3412
	if (!ib_vector_is_empty(user_table->fts->indexes)) {
		index = (dict_index_t*) ib_vector_getp_const(
				user_table->fts->indexes, 0);
		DBUG_ASSERT(!dict_index_is_online_ddl(index));
	}
3413

3414 3415
	int	ret = 0;

3416 3417 3418 3419
	while (fts_config_key[i]) {
		fts_string_t	value;
		char*		key_name;
		ulint		allocated = FALSE;
3420

3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439
		value.f_len = FTS_MAX_CONFIG_VALUE_LEN;

		value.f_str = str;

		if (index
		    && strcmp(fts_config_key[i], FTS_TOTAL_WORD_COUNT) == 0) {
			key_name = fts_config_create_index_param_name(
				fts_config_key[i], index);
			allocated = TRUE;
		} else {
			key_name = (char*) fts_config_key[i];
		}

		fts_config_get_value(trx, &fts_table, key_name, &value);

		if (allocated) {
			ut_free(key_name);
		}

3440 3441
		BREAK_IF(ret = field_store_string(
				 fields[FTS_CONFIG_KEY], fts_config_key[i]));
3442

3443 3444 3445
		BREAK_IF(ret = field_store_string(
				 fields[FTS_CONFIG_VALUE],
				 reinterpret_cast<const char*>(value.f_str)));
3446

3447
		BREAK_IF(ret = schema_table_store_record(thd, table));
3448 3449

		i++;
3450 3451
	}

3452 3453 3454
	fts_sql_commit(trx);

	dict_table_close(user_table, FALSE, FALSE);
3455

3456
	dict_sys.unfreeze();
3457

Marko Mäkelä's avatar
Marko Mäkelä committed
3458
	trx->free();
3459

3460
	DBUG_RETURN(ret);
3461 3462 3463
}

/*******************************************************************//**
3464
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
3465
@return 0 on success */
3466 3467
static
int
3468 3469
i_s_fts_config_init(
/*=================*/
3470 3471
	void*	p)	/*!< in/out: table schema object */
{
3472
	DBUG_ENTER("i_s_fts_config_init");
3473 3474
	ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;

3475
	schema->fields_info = Show::i_s_fts_config_fields_info;
3476
	schema->fill_table = i_s_fts_config_fill;
3477 3478 3479 3480

	DBUG_RETURN(0);
}

3481
struct st_maria_plugin	i_s_innodb_ft_config =
3482 3483 3484 3485 3486 3487 3488
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
3489
	STRUCT_FLD(info, &i_s_info),
3490 3491 3492

	/* plugin name */
	/* const char* */
3493
	STRUCT_FLD(name, "INNODB_FT_CONFIG"),
3494 3495 3496 3497 3498 3499 3500

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
3501
	STRUCT_FLD(descr, "INNODB AUXILIARY FTS CONFIG TABLE"),
3502 3503 3504 3505 3506 3507 3508

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
3509
	STRUCT_FLD(init, i_s_fts_config_init),
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

3525 3526
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
3527
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
3528 3529
};

3530
namespace Show {
3531 3532
/* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */
static ST_FIELD_INFO	i_s_innodb_buffer_stats_fields_info[] =
3533
{
3534 3535 3536 3537
#define IDX_BUF_STATS_POOL_ID		0
  Column("POOL_ID", ULong(), NOT_NULL),

#define IDX_BUF_STATS_POOL_SIZE		1
3538
  Column("POOL_SIZE", ULonglong(), NOT_NULL),
3539

3540
#define IDX_BUF_STATS_FREE_BUFFERS	2
3541
  Column("FREE_BUFFERS", ULonglong(), NOT_NULL),
3542

3543
#define IDX_BUF_STATS_LRU_LEN		3
3544
  Column("DATABASE_PAGES", ULonglong(), NOT_NULL),
3545

3546
#define IDX_BUF_STATS_OLD_LRU_LEN	4
3547
  Column("OLD_DATABASE_PAGES", ULonglong(), NOT_NULL),
3548

3549
#define IDX_BUF_STATS_FLUSH_LIST_LEN	5
3550
  Column("MODIFIED_DATABASE_PAGES", ULonglong(), NOT_NULL),
3551

3552
#define IDX_BUF_STATS_PENDING_ZIP	6
3553
  Column("PENDING_DECOMPRESS", ULonglong(), NOT_NULL),
3554

3555
#define IDX_BUF_STATS_PENDING_READ	7
3556
  Column("PENDING_READS",ULonglong(), NOT_NULL),
3557

3558
#define IDX_BUF_STATS_FLUSH_LRU		8
3559
  Column("PENDING_FLUSH_LRU",ULonglong(), NOT_NULL),
3560

3561
#define IDX_BUF_STATS_FLUSH_LIST	9
3562
  Column("PENDING_FLUSH_LIST", ULonglong(), NOT_NULL),
3563

3564
#define IDX_BUF_STATS_PAGE_YOUNG	10
3565
  Column("PAGES_MADE_YOUNG",ULonglong(), NOT_NULL),
3566

3567
#define IDX_BUF_STATS_PAGE_NOT_YOUNG	11
3568
  Column("PAGES_NOT_MADE_YOUNG",ULonglong(), NOT_NULL),
3569

3570
#define	IDX_BUF_STATS_PAGE_YOUNG_RATE	12
3571
  Column("PAGES_MADE_YOUNG_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3572

3573
#define	IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE 13
3574
  Column("PAGES_MADE_NOT_YOUNG_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3575

3576
#define IDX_BUF_STATS_PAGE_READ		14
3577
  Column("NUMBER_PAGES_READ",ULonglong(), NOT_NULL),
3578

3579
#define IDX_BUF_STATS_PAGE_CREATED	15
3580
  Column("NUMBER_PAGES_CREATED",ULonglong(), NOT_NULL),
3581

3582
#define IDX_BUF_STATS_PAGE_WRITTEN	16
3583
  Column("NUMBER_PAGES_WRITTEN",ULonglong(), NOT_NULL),
3584

3585
#define	IDX_BUF_STATS_PAGE_READ_RATE	17
3586
  Column("PAGES_READ_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3587

3588
#define	IDX_BUF_STATS_PAGE_CREATE_RATE	18
3589
  Column("PAGES_CREATE_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3590

3591
#define	IDX_BUF_STATS_PAGE_WRITTEN_RATE	19
3592
  Column("PAGES_WRITTEN_RATE",Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3593

3594
#define IDX_BUF_STATS_GET		20
3595
  Column("NUMBER_PAGES_GET", ULonglong(), NOT_NULL),
3596

3597
#define IDX_BUF_STATS_HIT_RATE		21
3598
  Column("HIT_RATE", ULonglong(), NOT_NULL),
3599

3600
#define IDX_BUF_STATS_MADE_YOUNG_PCT	22
3601
  Column("YOUNG_MAKE_PER_THOUSAND_GETS", ULonglong(), NOT_NULL),
3602

3603
#define IDX_BUF_STATS_NOT_MADE_YOUNG_PCT 23
3604
  Column("NOT_YOUNG_MAKE_PER_THOUSAND_GETS", ULonglong(), NOT_NULL),
3605

3606
#define IDX_BUF_STATS_READ_AHEAD	24
3607
  Column("NUMBER_PAGES_READ_AHEAD", ULonglong(), NOT_NULL),
3608

3609
#define IDX_BUF_STATS_READ_AHEAD_EVICTED 25
3610
  Column("NUMBER_READ_AHEAD_EVICTED", ULonglong(), NOT_NULL),
3611

3612
#define	IDX_BUF_STATS_READ_AHEAD_RATE	26
3613
  Column("READ_AHEAD_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3614

3615
#define	IDX_BUF_STATS_READ_AHEAD_EVICT_RATE 27
3616
  Column("READ_AHEAD_EVICTED_RATE",Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
3617

3618
#define IDX_BUF_STATS_LRU_IO_SUM	28
3619
  Column("LRU_IO_TOTAL", ULonglong(), NOT_NULL),
3620

3621
#define IDX_BUF_STATS_LRU_IO_CUR	29
3622
  Column("LRU_IO_CURRENT", ULonglong(), NOT_NULL),
3623

3624
#define IDX_BUF_STATS_UNZIP_SUM		30
3625
  Column("UNCOMPRESS_TOTAL",ULonglong(), NOT_NULL),
3626

3627
#define IDX_BUF_STATS_UNZIP_CUR		31
3628 3629 3630
  Column("UNCOMPRESS_CURRENT", ULonglong(), NOT_NULL),

  CEnd()
3631
};
3632
} // namespace Show
3633

3634 3635 3636
/** Fill INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS
@param[in,out]	thd	connection
@param[in,out]	tables	tables to fill
3637
@return 0 on success, 1 on failure */
3638
static int i_s_innodb_stats_fill(THD *thd, TABLE_LIST * tables, Item *)
3639
{
3640 3641 3642
	TABLE*		table;
	Field**		fields;
	buf_pool_info_t	info;
3643

3644
	DBUG_ENTER("i_s_innodb_stats_fill");
3645

3646 3647 3648 3649 3650 3651 3652 3653 3654
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);

	/* Only allow the PROCESS privilege holder to access the stats */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

	buf_stats_get_pool_info(&info);

3655
	table = tables->table;
3656

3657
	fields = table->field;
3658

3659 3660
	OK(fields[IDX_BUF_STATS_POOL_ID]->store(0, true));

3661
	OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(info.pool_size, true));
3662

3663
	OK(fields[IDX_BUF_STATS_LRU_LEN]->store(info.lru_len, true));
3664

3665
	OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(info.old_lru_len, true));
3666

Sergei Golubchik's avatar
Sergei Golubchik committed
3667
	OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
3668
		   info.free_list_len, true));
3669

3670
	OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
3671
		   info.flush_list_len, true));
3672

3673
	OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(info.n_pend_unzip, true));
3674

3675
	OK(fields[IDX_BUF_STATS_PENDING_READ]->store(info.n_pend_reads, true));
3676

Sergei Golubchik's avatar
Sergei Golubchik committed
3677
	OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
3678
		   info.n_pending_flush_lru, true));
3679

Sergei Golubchik's avatar
Sergei Golubchik committed
3680
	OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
3681
		   info.n_pending_flush_list, true));
3682

Sergei Golubchik's avatar
Sergei Golubchik committed
3683
	OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
3684
		   info.n_pages_made_young, true));
3685

3686
	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
3687
		   info.n_pages_not_made_young, true));
3688

3689
	OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
3690
		   info.page_made_young_rate));
3691

3692
	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
3693
		   info.page_not_made_young_rate));
3694

3695
	OK(fields[IDX_BUF_STATS_PAGE_READ]->store(info.n_pages_read, true));
3696

Sergei Golubchik's avatar
Sergei Golubchik committed
3697
	OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
3698
		   info.n_pages_created, true));
3699

Sergei Golubchik's avatar
Sergei Golubchik committed
3700
	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
3701
		   info.n_pages_written, true));
3702

3703
	OK(fields[IDX_BUF_STATS_GET]->store(info.n_page_gets, true));
3704

Sergei Golubchik's avatar
Sergei Golubchik committed
3705
	OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
3706
		   info.pages_read_rate));
3707

Sergei Golubchik's avatar
Sergei Golubchik committed
3708
	OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
3709
		   info.pages_created_rate));
3710

Sergei Golubchik's avatar
Sergei Golubchik committed
3711
	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
3712
		   info.pages_written_rate));
3713

3714 3715
	if (info.n_page_get_delta) {
		if (info.page_read_delta <= info.n_page_get_delta) {
Monty's avatar
Monty committed
3716 3717
			OK(fields[IDX_BUF_STATS_HIT_RATE]->store(
				static_cast<double>(
3718 3719
					1000 - (1000 * info.page_read_delta
					/ info.n_page_get_delta))));
Monty's avatar
Monty committed
3720 3721 3722
		} else {
			OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0));
		}
3723

3724
		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
3725 3726
			   1000 * info.young_making_delta
			   / info.n_page_get_delta, true));
3727

3728
		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
3729 3730
			   1000 * info.not_young_making_delta
			   / info.n_page_get_delta, true));
3731
	} else {
3732 3733 3734
		OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0, true));
		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0, true));
		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0, true));
3735
	}
3736

3737
	OK(fields[IDX_BUF_STATS_READ_AHEAD]->store(
3738
		   info.n_ra_pages_read, true));
3739

3740
	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
3741
		   info.n_ra_pages_evicted, true));
3742

3743
	OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
3744
		   info.pages_readahead_rate));
3745

3746
	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
3747
		   info.pages_evicted_rate));
3748

3749
	OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(info.io_sum, true));
3750

3751
	OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(info.io_cur, true));
3752

3753
	OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(info.unzip_sum, true));
3754

3755
	OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(info.unzip_cur, true));
3756

3757 3758
	DBUG_RETURN(schema_table_store_record(thd, table));
}
3759 3760

/*******************************************************************//**
3761
Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS.
3762
@return 0 on success, 1 on failure */
3763 3764
static
int
3765 3766
i_s_innodb_buffer_pool_stats_init(
/*==============================*/
3767 3768
	void*	p)	/*!< in/out: table schema object */
{
3769
	ST_SCHEMA_TABLE*	schema;
3770

3771 3772 3773 3774
	DBUG_ENTER("i_s_innodb_buffer_pool_stats_init");

	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);

3775
	schema->fields_info = Show::i_s_innodb_buffer_stats_fields_info;
3776
	schema->fill_table = i_s_innodb_stats_fill;
3777 3778 3779 3780

	DBUG_RETURN(0);
}

3781
struct st_maria_plugin	i_s_innodb_buffer_stats =
3782 3783 3784 3785 3786 3787 3788
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
3789
	STRUCT_FLD(info, &i_s_info),
3790 3791 3792

	/* plugin name */
	/* const char* */
3793
	STRUCT_FLD(name, "INNODB_BUFFER_POOL_STATS"),
3794 3795 3796 3797 3798 3799 3800

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
3801
	STRUCT_FLD(descr, "InnoDB Buffer Pool Statistics Information "),
3802 3803 3804 3805 3806 3807 3808

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
3809
	STRUCT_FLD(init, i_s_innodb_buffer_pool_stats_init),
3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

3825 3826
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
3827
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
3828 3829
};

3830
/** These must correspond to the first values of buf_page_state */
3831 3832
static const LEX_CSTRING page_state_values[] =
{
3833 3834 3835 3836
  { STRING_WITH_LEN("NOT_USED") },
  { STRING_WITH_LEN("MEMORY") },
  { STRING_WITH_LEN("REMOVE_HASH") },
  { STRING_WITH_LEN("FILE_PAGE") },
3837 3838
};

3839
static const TypelibBuffer<4> page_state_values_typelib(page_state_values);
3840

3841
static const LEX_CSTRING io_values[] =
3842
{
3843 3844 3845 3846
	{ STRING_WITH_LEN("IO_NONE") },
	{ STRING_WITH_LEN("IO_READ") },
	{ STRING_WITH_LEN("IO_WRITE") },
	{ STRING_WITH_LEN("IO_PIN") }
3847 3848 3849 3850 3851
};


static TypelibBuffer<4> io_values_typelib(io_values);

3852
namespace Show {
3853 3854
/* Fields of the dynamic table INNODB_BUFFER_POOL_PAGE. */
static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
3855
{
3856 3857 3858 3859
#define IDX_BUFFER_POOL_ID		0
  Column("POOL_ID", ULong(), NOT_NULL),

#define IDX_BUFFER_BLOCK_ID		1
3860
  Column("BLOCK_ID", ULonglong(), NOT_NULL),
3861

3862
#define IDX_BUFFER_PAGE_SPACE		2
3863
  Column("SPACE", ULong(), NOT_NULL),
3864

3865
#define IDX_BUFFER_PAGE_NUM		3
3866
  Column("PAGE_NUMBER", ULong(), NOT_NULL),
3867

3868
#define IDX_BUFFER_PAGE_TYPE		4
3869
  Column("PAGE_TYPE", Varchar(64), NULLABLE),
3870

3871
#define IDX_BUFFER_PAGE_FLUSH_TYPE	5
3872
  Column("FLUSH_TYPE", ULong(), NOT_NULL),
3873

3874
#define IDX_BUFFER_PAGE_FIX_COUNT	6
3875
  Column("FIX_COUNT", ULong(), NOT_NULL),
3876

3877
#ifdef BTR_CUR_HASH_ADAPT
3878
#define IDX_BUFFER_PAGE_HASHED		7
3879
  Column("IS_HASHED", SLong(1), NOT_NULL),
3880
#endif /* BTR_CUR_HASH_ADAPT */
3881

3882
#define IDX_BUFFER_PAGE_NEWEST_MOD	7 + I_S_AHI
3883
  Column("NEWEST_MODIFICATION", ULonglong(), NOT_NULL),
3884

3885
#define IDX_BUFFER_PAGE_OLDEST_MOD	8 + I_S_AHI
3886
  Column("OLDEST_MODIFICATION", ULonglong(), NOT_NULL),
3887

3888
#define IDX_BUFFER_PAGE_ACCESS_TIME	9 + I_S_AHI
3889
  Column("ACCESS_TIME", ULonglong(), NOT_NULL),
3890

3891
#define IDX_BUFFER_PAGE_TABLE_NAME	10 + I_S_AHI
3892
  Column("TABLE_NAME", Varchar(1024), NULLABLE),
3893

3894
#define IDX_BUFFER_PAGE_INDEX_NAME	11 + I_S_AHI
3895
  Column("INDEX_NAME", Varchar(NAME_CHAR_LEN), NULLABLE),
3896

3897
#define IDX_BUFFER_PAGE_NUM_RECS	12 + I_S_AHI
3898
  Column("NUMBER_RECORDS", ULonglong(), NOT_NULL),
3899

3900
#define IDX_BUFFER_PAGE_DATA_SIZE	13 + I_S_AHI
3901
  Column("DATA_SIZE", ULonglong(), NOT_NULL),
3902

3903
#define IDX_BUFFER_PAGE_ZIP_SIZE	14 + I_S_AHI
3904
  Column("COMPRESSED_SIZE", ULonglong(), NOT_NULL),
3905

3906
#define IDX_BUFFER_PAGE_STATE		15 + I_S_AHI
3907
  Column("PAGE_STATE", Enum(&page_state_values_typelib), NOT_NULL, DEFAULT_NONE),
3908

3909
#define IDX_BUFFER_PAGE_IO_FIX		16 + I_S_AHI
3910
  Column("IO_FIX", Enum(&io_values_typelib), NOT_NULL, DEFAULT_NONE),
3911

3912
#define IDX_BUFFER_PAGE_IS_OLD		17 + I_S_AHI
3913
  Column("IS_OLD", SLong(1), NOT_NULL),
3914

3915
#define IDX_BUFFER_PAGE_FREE_CLOCK	18 + I_S_AHI
3916 3917 3918
  Column("FREE_PAGE_CLOCK", ULonglong(), NOT_NULL),

  CEnd()
3919
};
3920
} // namespace Show
3921

3922 3923 3924
/*******************************************************************//**
Fill Information Schema table INNODB_BUFFER_PAGE with information
cached in the buf_page_info_t array
3925
@return 0 on success, 1 on failure */
3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939
static
int
i_s_innodb_buffer_page_fill(
/*========================*/
	THD*			thd,		/*!< in: thread */
	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
	const buf_page_info_t*	info_array,	/*!< in: array cached page
						info */
	ulint			num_page)	/*!< in: number of page info
						cached */
{
	TABLE*			table;
	Field**			fields;

3940 3941
	compile_time_assert(I_S_PAGE_TYPE_LAST < 1 << I_S_PAGE_TYPE_BITS);

3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955
	DBUG_ENTER("i_s_innodb_buffer_page_fill");

	table = tables->table;

	fields = table->field;

	/* Iterate through the cached array and fill the I_S table rows */
	for (ulint i = 0; i < num_page; i++) {
		const buf_page_info_t*	page_info;
		char			table_name[MAX_FULL_NAME_LEN + 1];
		const char*		table_name_end = NULL;

		page_info = info_array + i;

3956 3957
		OK(fields[IDX_BUFFER_POOL_ID]->store(0, true));

Sergei Golubchik's avatar
Sergei Golubchik committed
3958
		OK(fields[IDX_BUFFER_BLOCK_ID]->store(
3959
			   page_info->block_id, true));
3960

Sergei Golubchik's avatar
Sergei Golubchik committed
3961
		OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
3962
			   page_info->id.space(), true));
3963

Sergei Golubchik's avatar
Sergei Golubchik committed
3964
		OK(fields[IDX_BUFFER_PAGE_NUM]->store(
3965
			   page_info->id.page_no(), true));
3966 3967

		OK(field_store_string(
3968 3969
			   fields[IDX_BUFFER_PAGE_TYPE],
			   i_s_page_type[page_info->page_type].type_str));
3970

3971
		OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store(0, true));
3972 3973

		OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
3974
			   page_info->fix_count, true));
3975

3976
#ifdef BTR_CUR_HASH_ADAPT
3977 3978
		OK(fields[IDX_BUFFER_PAGE_HASHED]->store(
			   page_info->hashed, true));
3979
#endif /* BTR_CUR_HASH_ADAPT */
3980 3981

		OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
3982
			   page_info->newest_mod, true));
3983 3984

		OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store(
3985
			   page_info->oldest_mod, true));
3986 3987

		OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store(
3988
			   page_info->access_time, true));
3989 3990 3991 3992 3993 3994 3995 3996

		fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_null();

		fields[IDX_BUFFER_PAGE_INDEX_NAME]->set_null();

		/* If this is an index page, fetch the index name
		and table name */
		if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
3997
			bool ret = false;
3998

3999
			dict_sys.mutex_lock();
4000

4001 4002 4003 4004 4005
			const dict_index_t* index =
				dict_index_get_if_in_cache_low(
					page_info->index_id);

			if (index) {
4006 4007
				table_name_end = innobase_convert_name(
					table_name, sizeof(table_name),
4008 4009
					index->table->name.m_name,
					strlen(index->table->name.m_name),
4010
					thd);
4011

4012 4013 4014 4015 4016 4017
				ret = fields[IDX_BUFFER_PAGE_TABLE_NAME]
					->store(table_name,
						static_cast<uint>(
							table_name_end
							- table_name),
						system_charset_info)
4018 4019 4020 4021
					|| fields[IDX_BUFFER_PAGE_INDEX_NAME]
					->store(index->name,
						uint(strlen(index->name)),
						system_charset_info);
4022 4023
			}

4024
			dict_sys.mutex_unlock();
4025 4026 4027

			OK(ret);

4028 4029 4030 4031 4032 4033
			if (index) {
				fields[IDX_BUFFER_PAGE_TABLE_NAME]
					->set_notnull();
				fields[IDX_BUFFER_PAGE_INDEX_NAME]
					->set_notnull();
			}
4034 4035 4036
		}

		OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store(
4037
			   page_info->num_recs, true));
4038 4039

		OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store(
4040
			   page_info->data_size, true));
4041 4042

		OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store(
4043 4044 4045
			   page_info->zip_ssize
			   ? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
			   : 0, true));
4046

4047
		OK(fields[IDX_BUFFER_PAGE_STATE]->store(
4048 4049
			   1 + std::min<unsigned>(page_info->page_state,
						  BUF_BLOCK_FILE_PAGE), true));
4050

4051 4052
		OK(fields[IDX_BUFFER_PAGE_IO_FIX]->store(
			   1 + page_info->io_fix, true));
4053

4054 4055
		OK(fields[IDX_BUFFER_PAGE_IS_OLD]->store(
			   page_info->is_old, true));
4056 4057

		OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store(
4058
			   page_info->freed_page_clock, true));
4059

4060
		OK(schema_table_store_record(thd, table));
4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075
	}

	DBUG_RETURN(0);
}

/*******************************************************************//**
Set appropriate page type to a buf_page_info_t structure */
static
void
i_s_innodb_set_page_type(
/*=====================*/
	buf_page_info_t*page_info,	/*!< in/out: structure to fill with
					scanned info */
	const byte*	frame)		/*!< in: buffer frame */
{
4076 4077
	uint16_t page_type = fil_page_get_type(frame);

4078
	if (fil_page_type_is_index(page_type)) {
4079 4080
		const page_t*	page = (const page_t*) frame;

4081 4082
		page_info->index_id = btr_page_get_index_id(page);

4083 4084 4085
		/* FIL_PAGE_INDEX and FIL_PAGE_RTREE are a bit special,
		their values are defined as 17855 and 17854, so we cannot
		use them to index into i_s_page_type[] array, its array index
4086
		in the i_s_page_type[] array is I_S_PAGE_TYPE_INDEX
4087 4088
		(1) for index pages or I_S_PAGE_TYPE_IBUF for
		change buffer index pages */
4089
		if (page_type == FIL_PAGE_RTREE) {
4090
			page_info->page_type = I_S_PAGE_TYPE_RTREE;
4091 4092 4093 4094
		} else if (page_info->index_id
			   == static_cast<index_id_t>(DICT_IBUF_ID_MIN
						      + IBUF_SPACE_ID)) {
			page_info->page_type = I_S_PAGE_TYPE_IBUF;
4095
		} else {
4096 4097
			ut_ad(page_type == FIL_PAGE_INDEX
			      || page_type == FIL_PAGE_TYPE_INSTANT);
4098 4099
			page_info->page_type = I_S_PAGE_TYPE_INDEX;
		}
4100

4101
		page_info->data_size = uint16_t(page_header_get_field(
4102 4103 4104 4105 4106
			page, PAGE_HEAP_TOP) - (page_is_comp(page)
						? PAGE_NEW_SUPREMUM_END
						: PAGE_OLD_SUPREMUM_END)
			- page_header_get_field(page, PAGE_GARBAGE));

4107
		page_info->num_recs = page_get_n_recs(page) & ((1U << 14) - 1);
4108
	} else if (page_type > FIL_PAGE_TYPE_LAST) {
4109 4110 4111 4112 4113 4114
		/* Encountered an unknown page type */
		page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
	} else {
		/* Make sure we get the right index into the
		i_s_page_type[] array */
		ut_a(page_type == i_s_page_type[page_type].type_value);
4115

4116
		page_info->page_type = page_type & 0xf;
4117 4118
	}
}
4119
/*******************************************************************//**
4120 4121 4122
Scans pages in the buffer cache, and collect their general information
into the buf_page_info_t array which is zero-filled. So any fields
that are not initialized in the function will default to 0 */
4123
static
4124 4125 4126 4127 4128 4129 4130 4131 4132
void
i_s_innodb_buffer_page_get_info(
/*============================*/
	const buf_page_t*bpage,		/*!< in: buffer pool page to scan */
	ulint		pos,		/*!< in: buffer block position in
					buffer pool or in the LRU list */
	buf_page_info_t*page_info)	/*!< in: zero filled info structure;
					out: structure filled with scanned
					info */
4133
{
4134
	page_info->block_id = pos;
4135

4136 4137 4138 4139 4140
	compile_time_assert(BUF_BLOCK_NOT_USED == 0);
	compile_time_assert(BUF_BLOCK_MEMORY == 1);
	compile_time_assert(BUF_BLOCK_REMOVE_HASH == 2);
	compile_time_assert(BUF_BLOCK_FILE_PAGE == 3);
	compile_time_assert(BUF_BLOCK_ZIP_PAGE == 4);
4141

4142 4143
	auto state = bpage->state();
	page_info->page_state= int{state} & 7;
4144

4145 4146 4147 4148 4149 4150 4151
	switch (state) {
	default:
		page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
		break;
	case BUF_BLOCK_FILE_PAGE:
	case BUF_BLOCK_ZIP_PAGE:
		const byte*	frame;
4152

4153
		page_info->id = bpage->id();
4154

4155
		page_info->fix_count = bpage->buf_fix_count();
4156

4157
		page_info->oldest_mod = bpage->oldest_modification();
4158

4159
		page_info->access_time = bpage->access_time;
4160

4161
		page_info->zip_ssize = bpage->zip.ssize;
4162

4163
		page_info->io_fix = bpage->io_fix() & 3;
4164

4165
		page_info->is_old = bpage->old;
4166

4167
		page_info->freed_page_clock = bpage->freed_page_clock;
4168

4169
		switch (bpage->io_fix()) {
4170 4171 4172 4173 4174 4175
		case BUF_IO_NONE:
		case BUF_IO_WRITE:
		case BUF_IO_PIN:
			break;
		case BUF_IO_READ:
			page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
4176
			page_info->newest_mod = 0;
4177 4178 4179
			return;
		}

4180
		if (state == BUF_BLOCK_FILE_PAGE) {
4181
			const buf_block_t*block;
4182

4183 4184
			block = reinterpret_cast<const buf_block_t*>(bpage);
			frame = block->frame;
4185
#ifdef BTR_CUR_HASH_ADAPT
4186 4187 4188 4189
			/* Note: this may be a false positive, that
			is, block->index will not always be set to
			NULL when the last adaptive hash index
			reference is dropped. */
4190
			page_info->hashed = (block->index != NULL);
4191
#endif /* BTR_CUR_HASH_ADAPT */
4192 4193 4194 4195
		} else {
			ut_ad(page_info->zip_ssize);
			frame = bpage->zip.data;
		}
4196

4197
		page_info->newest_mod = mach_read_from_8(FIL_PAGE_LSN + frame);
4198
		i_s_innodb_set_page_type(page_info, frame);
4199 4200
	}
}
4201

4202 4203 4204
/*******************************************************************//**
This is the function that goes through each block of the buffer pool
and fetch information to information schema tables: INNODB_BUFFER_PAGE.
4205 4206
@param[in,out]	thd	connection
@param[in,out]	tables	tables to fill
4207
@return 0 on success, 1 on failure */
4208
static int i_s_innodb_buffer_page_fill(THD *thd, TABLE_LIST *tables, Item *)
4209 4210 4211
{
	int			status	= 0;
	mem_heap_t*		heap;
4212

4213 4214 4215 4216 4217 4218 4219 4220
	DBUG_ENTER("i_s_innodb_buffer_page_fill");

	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);

	/* deny access to user without PROCESS privilege */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}
4221

4222
	heap = mem_heap_create(10000);
4223

4224
	for (ulint n = 0;
4225
	     n < ut_min(buf_pool.n_chunks, buf_pool.n_chunks_new); n++) {
4226 4227 4228 4229 4230 4231 4232 4233
		const buf_block_t*	block;
		ulint			n_blocks;
		buf_page_info_t*	info_buffer;
		ulint			num_page;
		ulint			mem_size;
		ulint			chunk_size;
		ulint			num_to_process = 0;
		ulint			block_id = 0;
4234

4235
		/* Get buffer block of the nth chunk */
4236 4237
		block = buf_pool.chunks[n].blocks;
		chunk_size = buf_pool.chunks[n].size;
4238
		num_page = 0;
4239

4240 4241 4242 4243
		while (chunk_size > 0) {
			/* we cache maximum MAX_BUF_INFO_CACHED number of
			buffer page info */
			num_to_process = ut_min(chunk_size,
4244
				(ulint)MAX_BUF_INFO_CACHED);
4245

4246
			mem_size = num_to_process * sizeof(buf_page_info_t);
4247

4248 4249 4250 4251 4252
			/* For each chunk, we'll pre-allocate information
			structures to cache the page information read from
			the buffer pool. Doing so before obtain any mutex */
			info_buffer = (buf_page_info_t*) mem_heap_zalloc(
				heap, mem_size);
4253

4254 4255 4256 4257
			/* Obtain appropriate mutexes. Since this is diagnostic
			buffer pool info printout, we are not required to
			preserve the overall consistency, so we can
			release mutex periodically */
4258
			mysql_mutex_lock(&buf_pool.mutex);
4259

4260 4261 4262
			/* GO through each block in the chunk */
			for (n_blocks = num_to_process; n_blocks--; block++) {
				i_s_innodb_buffer_page_get_info(
4263
					&block->page, block_id,
4264 4265 4266 4267
					info_buffer + num_page);
				block_id++;
				num_page++;
			}
4268

4269
			mysql_mutex_unlock(&buf_pool.mutex);
4270

4271 4272 4273 4274 4275
			/* Fill in information schema table with information
			just collected from the buffer chunk scan */
			status = i_s_innodb_buffer_page_fill(
				thd, tables, info_buffer,
				num_page);
4276

4277 4278 4279 4280
			/* If something goes wrong, break and return */
			if (status) {
				break;
			}
4281

4282 4283 4284 4285 4286
			mem_heap_empty(heap);
			chunk_size -= num_to_process;
			num_page = 0;
		}
	}
4287

4288
	mem_heap_free(heap);
4289

4290
	DBUG_RETURN(status);
4291 4292 4293
}

/*******************************************************************//**
4294
Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE.
4295
@return 0 on success, 1 on failure */
4296 4297
static
int
4298 4299
i_s_innodb_buffer_page_init(
/*========================*/
4300 4301 4302 4303
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

4304
	DBUG_ENTER("i_s_innodb_buffer_page_init");
4305 4306 4307

	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);

4308
	schema->fields_info = Show::i_s_innodb_buffer_page_fields_info;
4309
	schema->fill_table = i_s_innodb_buffer_page_fill;
4310 4311 4312 4313

	DBUG_RETURN(0);
}

4314
struct st_maria_plugin	i_s_innodb_buffer_page =
4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
4326
	STRUCT_FLD(name, "INNODB_BUFFER_PAGE"),
4327 4328 4329 4330 4331 4332 4333

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
4334
	STRUCT_FLD(descr, "InnoDB Buffer Page Information"),
4335 4336 4337 4338 4339 4340 4341

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
4342
	STRUCT_FLD(init, i_s_innodb_buffer_page_init),
4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

4358 4359
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
4360
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
4361 4362
};

4363
namespace Show {
4364
static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
4365
{
4366 4367 4368 4369
#define IDX_BUF_LRU_POOL_ID		0
  Column("POOL_ID", ULong(), NOT_NULL),

#define IDX_BUF_LRU_POS			1
4370
  Column("LRU_POSITION", ULonglong(), NOT_NULL),
4371

4372
#define IDX_BUF_LRU_PAGE_SPACE		2
4373
  Column("SPACE", ULong(), NOT_NULL),
4374

4375
#define IDX_BUF_LRU_PAGE_NUM		3
4376
  Column("PAGE_NUMBER", ULong(), NOT_NULL),
4377

4378
#define IDX_BUF_LRU_PAGE_TYPE		4
4379
  Column("PAGE_TYPE", Varchar(64), NULLABLE),
4380

4381
#define IDX_BUF_LRU_PAGE_FLUSH_TYPE	5
4382
  Column("FLUSH_TYPE", ULong(), NOT_NULL),
4383

4384
#define IDX_BUF_LRU_PAGE_FIX_COUNT	6
4385
  Column("FIX_COUNT", ULong(), NOT_NULL),
4386

4387
#ifdef BTR_CUR_HASH_ADAPT
4388
#define IDX_BUF_LRU_PAGE_HASHED		7
4389
  Column("IS_HASHED", SLong(1), NOT_NULL),
4390
#endif /* BTR_CUR_HASH_ADAPT */
4391

4392
#define IDX_BUF_LRU_PAGE_NEWEST_MOD	7 + I_S_AHI
4393
  Column("NEWEST_MODIFICATION",ULonglong(), NOT_NULL),
4394

4395
#define IDX_BUF_LRU_PAGE_OLDEST_MOD	8 + I_S_AHI
4396
  Column("OLDEST_MODIFICATION",ULonglong(), NOT_NULL),
4397

4398
#define IDX_BUF_LRU_PAGE_ACCESS_TIME	9 + I_S_AHI
4399
  Column("ACCESS_TIME",ULonglong(), NOT_NULL),
4400

4401
#define IDX_BUF_LRU_PAGE_TABLE_NAME	10 + I_S_AHI
4402
  Column("TABLE_NAME", Varchar(1024), NULLABLE),
4403

4404
#define IDX_BUF_LRU_PAGE_INDEX_NAME	11 + I_S_AHI
4405
  Column("INDEX_NAME", Varchar(NAME_CHAR_LEN), NULLABLE),
4406

4407
#define IDX_BUF_LRU_PAGE_NUM_RECS	12 + I_S_AHI
4408
  Column("NUMBER_RECORDS", ULonglong(), NOT_NULL),
4409

4410
#define IDX_BUF_LRU_PAGE_DATA_SIZE	13 + I_S_AHI
4411
  Column("DATA_SIZE", ULonglong(), NOT_NULL),
4412

4413
#define IDX_BUF_LRU_PAGE_ZIP_SIZE	14 + I_S_AHI
4414
  Column("COMPRESSED_SIZE",ULonglong(), NOT_NULL),
4415

4416
#define IDX_BUF_LRU_PAGE_STATE		15 + I_S_AHI
4417
  Column("COMPRESSED", SLong(1), NOT_NULL),
4418

4419
#define IDX_BUF_LRU_PAGE_IO_FIX		16 + I_S_AHI
4420
  Column("IO_FIX", Enum(&io_values_typelib), NOT_NULL, DEFAULT_NONE),
4421

4422
#define IDX_BUF_LRU_PAGE_IS_OLD		17 + I_S_AHI
4423
  Column("IS_OLD", SLong(1), NULLABLE),
4424

4425
#define IDX_BUF_LRU_PAGE_FREE_CLOCK	18 + I_S_AHI
4426 4427 4428
  Column("FREE_PAGE_CLOCK", ULonglong(), NOT_NULL),

  CEnd()
4429
};
4430
} // namespace Show
4431 4432

/*******************************************************************//**
4433
Fill Information Schema table INNODB_BUFFER_PAGE_LRU with information
4434
cached in the buf_page_info_t array
4435
@return 0 on success, 1 on failure */
4436 4437
static
int
4438 4439
i_s_innodb_buf_page_lru_fill(
/*=========================*/
4440 4441 4442 4443
	THD*			thd,		/*!< in: thread */
	TABLE_LIST*		tables,		/*!< in/out: tables to fill */
	const buf_page_info_t*	info_array,	/*!< in: array cached page
						info */
4444
	ulint			num_page)	/*!< in: number of page info
4445 4446
						 cached */
{
4447
	DBUG_ENTER("i_s_innodb_buf_page_lru_fill");
4448

4449 4450
	TABLE*	table	= tables->table;
	Field**	fields	= table->field;
4451

4452 4453 4454
	/* Iterate through the cached array and fill the I_S table rows */
	for (ulint i = 0; i < num_page; i++) {
		const buf_page_info_t*	page_info;
4455 4456
		char			table_name[MAX_FULL_NAME_LEN + 1];
		const char*		table_name_end = NULL;
4457

4458
		page_info = info_array + i;
4459

4460 4461
		OK(fields[IDX_BUF_LRU_POOL_ID]->store(0, true));

Sergei Golubchik's avatar
Sergei Golubchik committed
4462
		OK(fields[IDX_BUF_LRU_POS]->store(
4463
			   page_info->block_id, true));
4464

Sergei Golubchik's avatar
Sergei Golubchik committed
4465
		OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
4466
			   page_info->id.space(), true));
4467

Sergei Golubchik's avatar
Sergei Golubchik committed
4468
		OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
4469
			   page_info->id.page_no(), true));
4470 4471

		OK(field_store_string(
4472 4473
			   fields[IDX_BUF_LRU_PAGE_TYPE],
			   i_s_page_type[page_info->page_type].type_str));
4474

4475
		OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(0, true));
4476

4477
		OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
4478
			   page_info->fix_count, true));
4479

4480
#ifdef BTR_CUR_HASH_ADAPT
4481 4482
		OK(fields[IDX_BUF_LRU_PAGE_HASHED]->store(
			   page_info->hashed, true));
4483
#endif /* BTR_CUR_HASH_ADAPT */
4484

4485
		OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
4486
			   page_info->newest_mod, true));
4487

4488
		OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store(
4489
			   page_info->oldest_mod, true));
4490

4491
		OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store(
4492
			   page_info->access_time, true));
4493

4494 4495 4496 4497
		fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_null();

		fields[IDX_BUF_LRU_PAGE_INDEX_NAME]->set_null();

4498 4499 4500
		/* If this is an index page, fetch the index name
		and table name */
		if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
4501
			bool ret = false;
4502

4503
			dict_sys.mutex_lock();
4504

4505 4506 4507 4508 4509
			const dict_index_t* index =
				dict_index_get_if_in_cache_low(
					page_info->index_id);

			if (index) {
4510 4511
				table_name_end = innobase_convert_name(
					table_name, sizeof(table_name),
4512 4513
					index->table->name.m_name,
					strlen(index->table->name.m_name),
4514
					thd);
4515

4516 4517 4518 4519 4520 4521
				ret = fields[IDX_BUF_LRU_PAGE_TABLE_NAME]
					->store(table_name,
						static_cast<uint>(
							table_name_end
							- table_name),
						system_charset_info)
4522 4523 4524 4525
					|| fields[IDX_BUF_LRU_PAGE_INDEX_NAME]
					->store(index->name,
						uint(strlen(index->name)),
						system_charset_info);
4526 4527
			}

4528
			dict_sys.mutex_unlock();
4529 4530 4531

			OK(ret);

4532 4533 4534 4535 4536 4537
			if (index) {
				fields[IDX_BUF_LRU_PAGE_TABLE_NAME]
					->set_notnull();
				fields[IDX_BUF_LRU_PAGE_INDEX_NAME]
					->set_notnull();
			}
4538 4539
		}

4540
		OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store(
4541
			   page_info->num_recs, true));
4542

4543
		OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store(
4544
			   page_info->data_size, true));
4545

4546
		OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store(
4547 4548
			   page_info->zip_ssize
			   ? 512 << page_info->zip_ssize : 0, true));
4549

4550
		OK(fields[IDX_BUF_LRU_PAGE_STATE]->store(
4551
			   page_info->page_state == BUF_BLOCK_ZIP_PAGE,
4552
			   true));
4553

4554 4555
		OK(fields[IDX_BUF_LRU_PAGE_IO_FIX]->store(
			   1 + page_info->io_fix, true));
4556

4557 4558
		OK(fields[IDX_BUF_LRU_PAGE_IS_OLD]->store(
			   page_info->is_old, true));
4559 4560

		OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store(
4561
			   page_info->freed_page_clock, true));
4562

4563
		OK(schema_table_store_record(thd, table));
4564 4565 4566 4567 4568
	}

	DBUG_RETURN(0);
}

4569 4570 4571
/** Fill the table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
@param[in]	thd		thread
@param[in,out]	tables		tables to fill
4572
@return 0 on success, 1 on failure */
4573
static int i_s_innodb_fill_buffer_lru(THD *thd, TABLE_LIST *tables, Item *)
4574 4575 4576 4577 4578 4579 4580 4581 4582
{
	int			status = 0;
	buf_page_info_t*	info_buffer;
	ulint			lru_pos = 0;
	const buf_page_t*	bpage;
	ulint			lru_len;

	DBUG_ENTER("i_s_innodb_fill_buffer_lru");

4583 4584 4585 4586 4587 4588 4589 4590
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);

	/* deny access to any users that do not hold PROCESS_ACL */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

	/* Aquire the mutex before allocating info_buffer, since
4591
	UT_LIST_GET_LEN(buf_pool.LRU) could change */
4592
	mysql_mutex_lock(&buf_pool.mutex);
4593

4594
	lru_len = UT_LIST_GET_LEN(buf_pool.LRU);
4595 4596

	/* Print error message if malloc fail */
4597
	info_buffer = (buf_page_info_t*) my_malloc(PSI_INSTRUMENT_ME,
4598
		lru_len * sizeof *info_buffer, MYF(MY_WME | MY_ZEROFILL));
4599 4600 4601 4602 4603 4604 4605 4606

	if (!info_buffer) {
		status = 1;
		goto exit;
	}

	/* Walk through Pool's LRU list and print the buffer page
	information */
4607
	bpage = UT_LIST_GET_LAST(buf_pool.LRU);
4608 4609 4610 4611

	while (bpage != NULL) {
		/* Use the same function that collect buffer info for
		INNODB_BUFFER_PAGE to get buffer page info */
4612
		i_s_innodb_buffer_page_get_info(bpage, lru_pos,
4613 4614 4615 4616 4617 4618 4619 4620
						(info_buffer + lru_pos));

		bpage = UT_LIST_GET_PREV(LRU, bpage);

		lru_pos++;
	}

	ut_ad(lru_pos == lru_len);
4621
	ut_ad(lru_pos == UT_LIST_GET_LEN(buf_pool.LRU));
4622 4623

exit:
4624
	mysql_mutex_unlock(&buf_pool.mutex);
4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635

	if (info_buffer) {
		status = i_s_innodb_buf_page_lru_fill(
			thd, tables, info_buffer, lru_len);

		my_free(info_buffer);
	}

	DBUG_RETURN(status);
}

4636
/*******************************************************************//**
4637
Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
4638
@return 0 on success, 1 on failure */
4639
static
4640 4641 4642 4643
int
i_s_innodb_buffer_page_lru_init(
/*============================*/
	void*	p)	/*!< in/out: table schema object */
4644
{
4645
	ST_SCHEMA_TABLE*	schema;
4646

4647
	DBUG_ENTER("i_s_innodb_buffer_page_lru_init");
4648

4649
	schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
4650

4651
	schema->fields_info = Show::i_s_innodb_buf_page_lru_fields_info;
4652
	schema->fill_table = i_s_innodb_fill_buffer_lru;
4653

4654
	DBUG_RETURN(0);
4655
}
4656

4657
struct st_maria_plugin	i_s_innodb_buffer_page_lru =
4658
{
4659 4660 4661
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
4662

4663 4664 4665
	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),
4666

4667 4668 4669
	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_BUFFER_PAGE_LRU"),
4670

4671 4672 4673
	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),
4674

4675 4676 4677
	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB Buffer Page in LRU"),
4678

4679 4680 4681
	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
4682

4683 4684 4685
	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, i_s_innodb_buffer_page_lru_init),
4686

4687 4688 4689
	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),
4690

4691 4692 4693
	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),
4694

4695 4696
	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),
4697

4698 4699
	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),
4700

4701 4702
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
4703
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
4704
};
4705

4706 4707
/*******************************************************************//**
Unbind a dynamic INFORMATION_SCHEMA table.
4708 4709
@return 0 */
static int i_s_common_deinit(void*)
4710 4711
{
	DBUG_ENTER("i_s_common_deinit");
4712

4713
	/* Do nothing */
4714

4715 4716
	DBUG_RETURN(0);
}
4717

4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735
static const LEX_CSTRING row_format_values[] =
{
  { STRING_WITH_LEN("Redundant") },
  { STRING_WITH_LEN("Compact") },
  { STRING_WITH_LEN("Compressed") },
  { STRING_WITH_LEN("Dynamic") }
};

static TypelibBuffer<4> row_format_values_typelib(row_format_values);

static const LEX_CSTRING space_type_values[] =
{
	{ STRING_WITH_LEN("Single") },
	{ STRING_WITH_LEN("System") }
};

static TypelibBuffer<2> space_type_values_typelib(space_type_values);

4736
namespace Show {
4737 4738 4739 4740 4741
/**  SYS_TABLES  ***************************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
static ST_FIELD_INFO	innodb_sys_tables_fields_info[] =
{
#define SYS_TABLES_ID			0
4742
  Column("TABLE_ID", ULonglong(), NOT_NULL),
4743

4744
#define SYS_TABLES_NAME			1
4745
  Column("NAME", Varchar(MAX_FULL_NAME_LEN + 1), NOT_NULL),
4746

4747
#define SYS_TABLES_FLAG			2
4748
  Column("FLAG", SLong(), NOT_NULL),
4749

4750
#define SYS_TABLES_NUM_COLUMN		3
4751
  Column("N_COLS", ULong(), NOT_NULL),
4752

4753
#define SYS_TABLES_SPACE		4
4754
  Column("SPACE", ULong(), NOT_NULL),
4755

4756
#define SYS_TABLES_ROW_FORMAT		5
4757
  Column("ROW_FORMAT", Enum(&row_format_values_typelib), NULLABLE),
4758

4759
#define SYS_TABLES_ZIP_PAGE_SIZE	6
4760
  Column("ZIP_PAGE_SIZE", ULong(), NOT_NULL),
4761

4762
#define SYS_TABLES_SPACE_TYPE		7
4763
  Column("SPACE_TYPE", Enum(&space_type_values_typelib), NULLABLE),
4764 4765

  CEnd()
4766
};
4767
} // namespace Show
4768 4769 4770 4771

/**********************************************************************//**
Populate information_schema.innodb_sys_tables table with information
from SYS_TABLES.
4772
@return 0 on success */
4773 4774 4775 4776 4777 4778 4779 4780
static
int
i_s_dict_fill_sys_tables(
/*=====================*/
	THD*		thd,		/*!< in: thread */
	dict_table_t*	table,		/*!< in: table */
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
4781 4782 4783 4784
	Field**			fields;
	ulint			compact = DICT_TF_GET_COMPACT(table->flags);
	ulint			atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(
								table->flags);
4785
	const ulint zip_size = dict_tf_get_zip_size(table->flags);
4786
	const char*		row_format;
4787 4788 4789 4790 4791

	if (!compact) {
		row_format = "Redundant";
	} else if (!atomic_blobs) {
		row_format = "Compact";
4792
	} else if (DICT_TF_GET_ZIP_SSIZE(table->flags)) {
4793 4794 4795 4796
		row_format = "Compressed";
	} else {
		row_format = "Dynamic";
	}
4797

4798
	DBUG_ENTER("i_s_dict_fill_sys_tables");
4799

4800
	fields = table_to_fill->field;
4801

4802
	OK(fields[SYS_TABLES_ID]->store(longlong(table->id), TRUE));
4803

4804
	OK(field_store_string(fields[SYS_TABLES_NAME], table->name.m_name));
4805

4806
	OK(fields[SYS_TABLES_FLAG]->store(table->flags));
4807

4808
	OK(fields[SYS_TABLES_NUM_COLUMN]->store(table->n_cols));
4809

4810
	OK(fields[SYS_TABLES_SPACE]->store(table->space_id, true));
4811

4812
	OK(field_store_string(fields[SYS_TABLES_ROW_FORMAT], row_format));
4813

4814
	OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(zip_size, true));
4815

4816 4817
	OK(field_store_string(fields[SYS_TABLES_SPACE_TYPE],
			      table->space_id ? "Single" : "System"));
4818

4819
	OK(schema_table_store_record(thd, table_to_fill));
4820

4821
	DBUG_RETURN(0);
4822
}
4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857

/** Convert one SYS_TABLES record to dict_table_t.
@param pcur      persistent cursor position on SYS_TABLES record
@param rec       record to read from (nullptr=use the dict_sys cache)
@param table     the converted dict_table_t
@return error message
@retval nullptr on success */
static const char *i_s_sys_tables_rec(const btr_pcur_t &pcur, const rec_t *rec,
                                      dict_table_t **table)
{
  static_assert(DICT_FLD__SYS_TABLES__NAME == 0, "compatibility");
  size_t len;
  if (rec_get_1byte_offs_flag(pcur.old_rec))
  {
    len= rec_1_get_field_end_info(pcur.old_rec, 0);
    if (len & REC_1BYTE_SQL_NULL_MASK)
      return "corrupted SYS_TABLES.NAME";
  }
  else
  {
    len= rec_2_get_field_end_info(pcur.old_rec, 0);
    static_assert(REC_2BYTE_EXTERN_MASK == 16384, "compatibility");
    if (len >= REC_2BYTE_EXTERN_MASK)
      return "corrupted SYS_TABLES.NAME";
  }

  const span<const char>name{reinterpret_cast<const char*>(pcur.old_rec), len};

  if (rec)
    return dict_load_table_low(name, rec, table);

  *table= dict_sys.load_table(name);
  return *table ? nullptr : "Table not found in cache";
}

4858
/*******************************************************************//**
4859 4860 4861
Function to go through each record in SYS_TABLES table, and fill the
information_schema.innodb_sys_tables table with related table information
@return 0 on success */
4862 4863
static
int
4864 4865 4866 4867 4868
i_s_sys_tables_fill_table(
/*======================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
4869
{
4870 4871
	btr_pcur_t	pcur;
	mtr_t		mtr;
4872

4873
	DBUG_ENTER("i_s_sys_tables_fill_table");
4874
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
4875

4876
	/* deny access to user without PROCESS_ACL privilege */
4877 4878 4879 4880
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

4881
	dict_sys.mutex_lock();
4882
	mtr_start(&mtr);
4883

4884 4885 4886 4887 4888 4889
	for (const rec_t *rec = dict_startscan_system(&pcur, &mtr,
						      dict_sys.sys_tables);
	     rec; rec = dict_getnext_system(&pcur, &mtr)) {
		if (rec_get_deleted_flag(rec, 0)) {
			continue;
		}
4890

4891 4892
		const char*	err_msg;
		dict_table_t*	table_rec;
4893

4894 4895
		/* Create and populate a dict_table_t structure with
		information from SYS_TABLES row */
4896 4897
		err_msg = i_s_sys_tables_rec(pcur, rec, &table_rec);
		mtr.commit();
4898
		dict_sys.mutex_unlock();
4899 4900

		if (!err_msg) {
4901 4902
			i_s_dict_fill_sys_tables(thd, table_rec,
						 tables->table);
4903 4904 4905 4906 4907 4908 4909 4910
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		if (table_rec) {
			dict_mem_table_free(table_rec);
4911
		}
4912 4913

		/* Get the next record */
4914
		dict_sys.mutex_lock();
4915
		mtr.start();
4916 4917
	}

4918
	mtr.commit();
4919
	dict_sys.mutex_unlock();
4920 4921

	DBUG_RETURN(0);
4922 4923 4924
}

/*******************************************************************//**
4925 4926
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tables
@return 0 on success */
4927 4928
static
int
4929 4930
innodb_sys_tables_init(
/*===================*/
4931 4932 4933 4934
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

4935
	DBUG_ENTER("innodb_sys_tables_init");
4936

4937
	schema = (ST_SCHEMA_TABLE*) p;
4938

4939
	schema->fields_info = Show::innodb_sys_tables_fields_info;
4940
	schema->fill_table = i_s_sys_tables_fill_table;
4941 4942 4943 4944

	DBUG_RETURN(0);
}

4945
struct st_maria_plugin	i_s_innodb_sys_tables =
4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
4957
	STRUCT_FLD(name, "INNODB_SYS_TABLES"),
4958 4959 4960 4961 4962 4963 4964

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
4965
	STRUCT_FLD(descr, "InnoDB SYS_TABLES"),
4966 4967 4968 4969 4970 4971 4972

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
4973
	STRUCT_FLD(init, innodb_sys_tables_init),
4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

4989 4990
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
4991
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
4992 4993
};

4994
namespace Show {
4995 4996 4997 4998 4999
/**  SYS_TABLESTATS  ***********************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
static ST_FIELD_INFO	innodb_sys_tablestats_fields_info[] =
{
#define SYS_TABLESTATS_ID		0
5000
  Column("TABLE_ID", ULonglong(), NOT_NULL),
5001

5002
#define SYS_TABLESTATS_NAME		1
5003
  Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
5004

5005
#define SYS_TABLESTATS_INIT		2
5006
  Column("STATS_INITIALIZED", SLong(1), NOT_NULL),
5007

5008
#define SYS_TABLESTATS_NROW		3
5009
  Column("NUM_ROWS", ULonglong(), NOT_NULL),
5010

5011
#define SYS_TABLESTATS_CLUST_SIZE	4
5012
  Column("CLUST_INDEX_SIZE", ULonglong(), NOT_NULL),
5013

5014
#define SYS_TABLESTATS_INDEX_SIZE	5
5015
  Column("OTHER_INDEX_SIZE", ULonglong(), NOT_NULL),
5016

5017
#define SYS_TABLESTATS_MODIFIED		6
5018
  Column("MODIFIED_COUNTER", ULonglong(), NOT_NULL),
5019

5020
#define SYS_TABLESTATS_AUTONINC		7
5021
  Column("AUTOINC", ULonglong(), NOT_NULL),
5022

5023
#define SYS_TABLESTATS_TABLE_REF_COUNT	8
5024 5025 5026
  Column("REF_COUNT", SLong(), NOT_NULL),

  CEnd()
5027
};
5028
} // namespace Show
5029

5030
/** Populate information_schema.innodb_sys_tablestats table with information
5031
from SYS_TABLES.
5032 5033 5034 5035 5036
@param[in]	thd		thread ID
@param[in,out]	table		table
@param[in]	ref_count	table reference count
@param[in,out]	table_to_fill	fill this table
@return 0 on success */
5037
static
5038 5039
int
i_s_dict_fill_sys_tablestats(
5040 5041 5042 5043
	THD*		thd,
	dict_table_t*	table,
	ulint		ref_count,
	TABLE*		table_to_fill)
5044
{
5045
	Field**		fields;
5046

5047
	DBUG_ENTER("i_s_dict_fill_sys_tablestats");
5048

5049
	fields = table_to_fill->field;
5050

5051
	OK(fields[SYS_TABLESTATS_ID]->store(longlong(table->id), TRUE));
5052

5053 5054
	OK(field_store_string(fields[SYS_TABLESTATS_NAME],
			      table->name.m_name));
5055

5056
	{
5057 5058 5059
		table->stats_mutex_lock();
		auto _ = make_scope_exit([table]() {
			table->stats_mutex_unlock(); });
5060

Marko Mäkelä's avatar
Marko Mäkelä committed
5061
		OK(fields[SYS_TABLESTATS_INIT]->store(table->stat_initialized,
5062
						      true));
5063

Marko Mäkelä's avatar
Marko Mäkelä committed
5064
		if (table->stat_initialized) {
5065 5066
			OK(fields[SYS_TABLESTATS_NROW]->store(
				   table->stat_n_rows, true));
5067

5068 5069
			OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
				   table->stat_clustered_index_size, true));
5070

5071 5072 5073
			OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
				   table->stat_sum_of_other_index_sizes,
				   true));
5074

5075 5076 5077 5078
			OK(fields[SYS_TABLESTATS_MODIFIED]->store(
				   table->stat_modified_counter, true));
		} else {
			OK(fields[SYS_TABLESTATS_NROW]->store(0, true));
5079

5080
			OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true));
5081

5082
			OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true));
5083

5084 5085
			OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true));
		}
5086
	}
5087

5088
	OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true));
5089

5090
	OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(ref_count, true));
5091 5092 5093 5094

	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
5095 5096 5097
}

/*******************************************************************//**
5098 5099 5100 5101
Function to go through each record in SYS_TABLES table, and fill the
information_schema.innodb_sys_tablestats table with table statistics
related information
@return 0 on success */
5102 5103
static
int
5104 5105 5106 5107 5108
i_s_sys_tables_fill_table_stats(
/*============================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
5109
{
5110 5111 5112
	btr_pcur_t	pcur;
	const rec_t*	rec;
	mtr_t		mtr;
5113

5114
	DBUG_ENTER("i_s_sys_tables_fill_table_stats");
5115
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5116

5117
	/* deny access to user without PROCESS_ACL privilege */
5118 5119 5120 5121
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

5122
	dict_sys.freeze();
5123
	dict_sys.mutex_lock();
5124
	mtr_start(&mtr);
5125

5126
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_tables);
5127

5128 5129
	while (rec) {
		const char*	err_msg;
Monty's avatar
Monty committed
5130
		dict_table_t*	table_rec= 0;
5131

5132
		mtr.commit();
5133 5134
		/* Fetch the dict_table_t structure corresponding to
		this SYS_TABLES record */
5135
		err_msg = i_s_sys_tables_rec(pcur, nullptr, &table_rec);
5136

5137
		ulint ref_count = table_rec ? table_rec->get_ref_count() : 0;
5138
		dict_sys.mutex_unlock();
5139

5140
		if (table_rec != NULL) {
5141
			ut_ad(err_msg == NULL);
5142
			i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count,
5143 5144
						     tables->table);
		} else {
5145
			ut_ad(err_msg != NULL);
5146 5147 5148
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
5149
		}
5150

5151
		dict_sys.unfreeze();
5152 5153

		/* Get the next record */
5154
		dict_sys.freeze();
5155
		dict_sys.mutex_lock();
5156

5157 5158
		mtr_start(&mtr);
		rec = dict_getnext_system(&pcur, &mtr);
5159 5160
	}

5161
	mtr_commit(&mtr);
5162
	dict_sys.mutex_unlock();
5163
	dict_sys.unfreeze();
5164 5165

	DBUG_RETURN(0);
5166 5167 5168
}

/*******************************************************************//**
5169 5170
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tablestats
@return 0 on success */
5171 5172
static
int
5173 5174
innodb_sys_tablestats_init(
/*=======================*/
5175 5176 5177 5178
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

5179
	DBUG_ENTER("innodb_sys_tablestats_init");
5180

5181
	schema = (ST_SCHEMA_TABLE*) p;
5182

5183
	schema->fields_info = Show::innodb_sys_tablestats_fields_info;
5184
	schema->fill_table = i_s_sys_tables_fill_table_stats;
5185 5186 5187 5188

	DBUG_RETURN(0);
}

5189
struct st_maria_plugin	i_s_innodb_sys_tablestats =
5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
5201
	STRUCT_FLD(name, "INNODB_SYS_TABLESTATS"),
5202 5203 5204 5205 5206 5207 5208

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
5209
	STRUCT_FLD(descr, "InnoDB SYS_TABLESTATS"),
5210 5211 5212 5213 5214 5215 5216

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
5217
	STRUCT_FLD(init, innodb_sys_tablestats_init),
5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

5233 5234
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
5235
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
5236 5237
};

5238
namespace Show {
5239 5240 5241
/**  SYS_INDEXES  **************************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
static ST_FIELD_INFO	innodb_sysindex_fields_info[] =
5242
{
5243
#define SYS_INDEX_ID		0
5244
  Column("INDEX_ID", ULonglong(), NOT_NULL),
5245

5246
#define SYS_INDEX_NAME		1
5247
  Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
5248

5249
#define SYS_INDEX_TABLE_ID	2
5250
  Column("TABLE_ID", ULonglong(), NOT_NULL),
5251

5252
#define SYS_INDEX_TYPE		3
5253
  Column("TYPE", SLong(), NOT_NULL),
5254

5255
#define SYS_INDEX_NUM_FIELDS	4
5256
  Column("N_FIELDS", SLong(), NOT_NULL),
5257

5258
#define SYS_INDEX_PAGE_NO	5
5259
  Column("PAGE_NO", SLong(), NOT_NULL),
5260

5261
#define SYS_INDEX_SPACE		6
5262
  Column("SPACE", SLong(), NOT_NULL),
5263

5264
#define SYS_INDEX_MERGE_THRESHOLD 7
5265 5266 5267
  Column("MERGE_THRESHOLD", SLong(), NOT_NULL),

  CEnd()
5268
};
5269
} // namespace Show
5270 5271

/**********************************************************************//**
5272 5273 5274
Function to populate the information_schema.innodb_sys_indexes table with
collected index information
@return 0 on success */
5275 5276
static
int
5277 5278
i_s_dict_fill_sys_indexes(
/*======================*/
5279
	THD*		thd,		/*!< in: thread */
5280
	table_id_t	table_id,	/*!< in: table id */
5281
	ulint		space_id,	/*!< in: tablespace id */
5282 5283
	dict_index_t*	index,		/*!< in: populated dict_index_t
					struct with index info */
5284 5285 5286 5287
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
	Field**		fields;

5288
	DBUG_ENTER("i_s_dict_fill_sys_indexes");
5289 5290 5291

	fields = table_to_fill->field;

5292 5293 5294 5295 5296 5297 5298 5299 5300
	if (*index->name == *TEMP_INDEX_PREFIX_STR) {
		/* Since TEMP_INDEX_PREFIX_STR is not valid UTF-8, we
		need to convert it to something else. */
		*const_cast<char*>(index->name()) = '?';
	}

	OK(fields[SYS_INDEX_NAME]->store(index->name,
					 uint(strlen(index->name)),
					 system_charset_info));
5301

5302
	OK(fields[SYS_INDEX_ID]->store(longlong(index->id), true));
5303

5304
	OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), true));
5305

5306
	OK(fields[SYS_INDEX_TYPE]->store(index->type, true));
5307

5308
	OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields));
5309

5310 5311
	/* FIL_NULL is ULINT32_UNDEFINED */
	if (index->page == FIL_NULL) {
5312
		fields[SYS_INDEX_PAGE_NO]->set_null();
5313
	} else {
5314
		OK(fields[SYS_INDEX_PAGE_NO]->store(index->page, true));
5315
	}
5316

5317 5318 5319 5320 5321
	if (space_id == ULINT_UNDEFINED) {
		fields[SYS_INDEX_SPACE]->set_null();
	} else {
		OK(fields[SYS_INDEX_SPACE]->store(space_id, true));
	}
5322

5323 5324
	OK(fields[SYS_INDEX_MERGE_THRESHOLD]->store(index->merge_threshold,
						    true));
5325

5326 5327 5328 5329 5330
	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
}
/*******************************************************************//**
5331 5332
Function to go through each record in SYS_INDEXES table, and fill the
information_schema.innodb_sys_indexes table with related index information
5333 5334 5335
@return 0 on success */
static
int
5336 5337
i_s_sys_indexes_fill_table(
/*=======================*/
5338 5339 5340 5341
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
5342 5343 5344 5345
	btr_pcur_t		pcur;
	const rec_t*		rec;
	mem_heap_t*		heap;
	mtr_t			mtr;
5346

5347
	DBUG_ENTER("i_s_sys_indexes_fill_table");
5348
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5349 5350 5351 5352 5353 5354 5355

	/* deny access to user without PROCESS_ACL privilege */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

	heap = mem_heap_create(1000);
5356
	dict_sys.mutex_lock();
5357 5358
	mtr_start(&mtr);

5359
	/* Start scan the SYS_INDEXES table */
5360
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_indexes);
5361

5362
	/* Process each record in the table */
5363 5364
	while (rec) {
		const char*	err_msg;
5365
		table_id_t	table_id;
5366
		ulint		space_id;
5367
		dict_index_t	index_rec;
5368

5369 5370 5371 5372
		/* Populate a dict_index_t structure with information from
		a SYS_INDEXES row */
		err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec,
						       &table_id);
5373 5374 5375 5376
		const byte* field = rec_get_nth_field_old(
			rec, DICT_FLD__SYS_INDEXES__SPACE, &space_id);
		space_id = space_id == 4 ? mach_read_from_4(field)
			: ULINT_UNDEFINED;
5377
		mtr_commit(&mtr);
5378
		dict_sys.mutex_unlock();
5379 5380

		if (!err_msg) {
5381 5382 5383 5384 5385 5386
			if (int err = i_s_dict_fill_sys_indexes(
				    thd, table_id, space_id, &index_rec,
				    tables->table)) {
				mem_heap_free(heap);
				DBUG_RETURN(err);
			}
5387 5388 5389 5390 5391 5392 5393 5394 5395
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		mem_heap_empty(heap);

		/* Get the next record */
5396
		dict_sys.mutex_lock();
5397 5398 5399 5400 5401
		mtr_start(&mtr);
		rec = dict_getnext_system(&pcur, &mtr);
	}

	mtr_commit(&mtr);
5402
	dict_sys.mutex_unlock();
5403 5404 5405 5406 5407
	mem_heap_free(heap);

	DBUG_RETURN(0);
}
/*******************************************************************//**
5408
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_indexes
5409 5410 5411
@return 0 on success */
static
int
5412 5413
innodb_sys_indexes_init(
/*====================*/
5414 5415 5416 5417
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

5418
	DBUG_ENTER("innodb_sys_indexes_init");
5419 5420 5421

	schema = (ST_SCHEMA_TABLE*) p;

5422
	schema->fields_info = Show::innodb_sysindex_fields_info;
5423
	schema->fill_table = i_s_sys_indexes_fill_table;
5424 5425 5426 5427

	DBUG_RETURN(0);
}

5428
struct st_maria_plugin	i_s_innodb_sys_indexes =
5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
5440
	STRUCT_FLD(name, "INNODB_SYS_INDEXES"),
5441 5442 5443 5444 5445 5446 5447

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
5448
	STRUCT_FLD(descr, "InnoDB SYS_INDEXES"),
5449 5450 5451 5452 5453 5454 5455

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
5456
	STRUCT_FLD(init, innodb_sys_indexes_init),
5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

5472 5473
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
5474
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
5475 5476
};

5477
namespace Show {
5478 5479 5480
/**  SYS_COLUMNS  **************************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_COLUMNS */
static ST_FIELD_INFO	innodb_sys_columns_fields_info[] =
5481
{
5482
#define SYS_COLUMN_TABLE_ID		0
5483
  Column("TABLE_ID", ULonglong(), NOT_NULL),
5484

5485
#define SYS_COLUMN_NAME		1
5486
  Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
5487

5488
#define SYS_COLUMN_POSITION	2
5489
  Column("POS", ULonglong(), NOT_NULL),
5490

5491
#define SYS_COLUMN_MTYPE		3
5492
  Column("MTYPE", SLong(), NOT_NULL),
5493

5494
#define SYS_COLUMN__PRTYPE	4
5495
  Column("PRTYPE", SLong(), NOT_NULL),
5496

5497
#define SYS_COLUMN_COLUMN_LEN	5
5498 5499 5500
  Column("LEN", SLong(), NOT_NULL),

  CEnd()
5501
};
5502
} // namespace Show
5503 5504

/**********************************************************************//**
5505 5506 5507
Function to populate the information_schema.innodb_sys_columns with
related column information
@return 0 on success */
5508 5509
static
int
5510 5511
i_s_dict_fill_sys_columns(
/*======================*/
5512
	THD*		thd,		/*!< in: thread */
5513 5514 5515 5516
	table_id_t	table_id,	/*!< in: table ID */
	const char*	col_name,	/*!< in: column name */
	dict_col_t*	column,		/*!< in: dict_col_t struct holding
					more column information */
5517 5518
	ulint		nth_v_col,	/*!< in: virtual column, its
					sequence number (nth virtual col) */
5519 5520 5521 5522
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
	Field**		fields;

5523
	DBUG_ENTER("i_s_dict_fill_sys_columns");
5524 5525 5526

	fields = table_to_fill->field;

5527
	OK(fields[SYS_COLUMN_TABLE_ID]->store((longlong) table_id, TRUE));
5528

5529
	OK(field_store_string(fields[SYS_COLUMN_NAME], col_name));
5530

5531
	if (column->is_virtual()) {
5532
		ulint	pos = dict_create_v_col_pos(nth_v_col, column->ind);
5533
		OK(fields[SYS_COLUMN_POSITION]->store(pos, true));
5534
	} else {
5535
		OK(fields[SYS_COLUMN_POSITION]->store(column->ind, true));
5536
	}
5537

5538
	OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
5539

5540
	OK(fields[SYS_COLUMN__PRTYPE]->store(column->prtype));
5541

5542
	OK(fields[SYS_COLUMN_COLUMN_LEN]->store(column->len));
5543 5544 5545 5546 5547 5548

	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
}
/*******************************************************************//**
5549 5550
Function to fill information_schema.innodb_sys_columns with information
collected by scanning SYS_COLUMNS table.
5551 5552 5553
@return 0 on success */
static
int
5554 5555
i_s_sys_columns_fill_table(
/*=======================*/
5556 5557 5558 5559 5560 5561
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
	btr_pcur_t	pcur;
	const rec_t*	rec;
5562
	const char*	col_name;
5563 5564 5565
	mem_heap_t*	heap;
	mtr_t		mtr;

5566
	DBUG_ENTER("i_s_sys_columns_fill_table");
5567
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5568 5569 5570 5571 5572 5573 5574

	/* deny access to user without PROCESS_ACL privilege */
	if (check_global_access(thd, PROCESS_ACL)) {
		DBUG_RETURN(0);
	}

	heap = mem_heap_create(1000);
5575
	dict_sys.mutex_lock();
5576 5577
	mtr_start(&mtr);

5578
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_columns);
5579 5580 5581

	while (rec) {
		const char*	err_msg;
5582 5583
		dict_col_t	column_rec;
		table_id_t	table_id;
5584
		ulint		nth_v_col;
5585

5586 5587 5588
		/* populate a dict_col_t structure with information from
		a SYS_COLUMNS row */
		err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec,
5589 5590
						       &table_id, &col_name,
						       &nth_v_col);
5591

5592
		mtr_commit(&mtr);
5593
		dict_sys.mutex_unlock();
5594 5595

		if (!err_msg) {
5596
			i_s_dict_fill_sys_columns(thd, table_id, col_name,
5597
						 &column_rec, nth_v_col,
5598
						 tables->table);
5599 5600 5601 5602 5603 5604 5605 5606 5607
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		mem_heap_empty(heap);

		/* Get the next record */
5608
		dict_sys.mutex_lock();
5609 5610 5611 5612 5613
		mtr_start(&mtr);
		rec = dict_getnext_system(&pcur, &mtr);
	}

	mtr_commit(&mtr);
5614
	dict_sys.mutex_unlock();
5615 5616 5617 5618 5619
	mem_heap_free(heap);

	DBUG_RETURN(0);
}
/*******************************************************************//**
5620
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns
5621 5622 5623
@return 0 on success */
static
int
5624 5625
innodb_sys_columns_init(
/*====================*/
5626 5627 5628 5629
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

5630
	DBUG_ENTER("innodb_sys_columns_init");
5631 5632 5633

	schema = (ST_SCHEMA_TABLE*) p;

5634
	schema->fields_info = Show::innodb_sys_columns_fields_info;
5635
	schema->fill_table = i_s_sys_columns_fill_table;
5636 5637 5638 5639

	DBUG_RETURN(0);
}

5640
struct st_maria_plugin	i_s_innodb_sys_columns =
5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
5652
	STRUCT_FLD(name, "INNODB_SYS_COLUMNS"),
5653 5654 5655 5656 5657 5658 5659

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
5660
	STRUCT_FLD(descr, "InnoDB SYS_COLUMNS"),
5661 5662 5663 5664 5665 5666 5667

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
5668
	STRUCT_FLD(init, innodb_sys_columns_init),
5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

5684 5685
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
5686
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
5687 5688
};

5689
namespace Show {
5690 5691 5692 5693 5694
/**  SYS_VIRTUAL **************************************************/
/** Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL */
static ST_FIELD_INFO	innodb_sys_virtual_fields_info[] =
{
#define SYS_VIRTUAL_TABLE_ID		0
5695
  Column("TABLE_ID", ULonglong(), NOT_NULL),
5696 5697

#define SYS_VIRTUAL_POS			1
5698
  Column("POS", ULong(), NOT_NULL),
5699 5700

#define SYS_VIRTUAL_BASE_POS		2
5701 5702 5703
  Column("BASE_POS", ULong(), NOT_NULL),

  CEnd()
5704
};
5705
} // namespace Show
5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729

/** Function to populate the information_schema.innodb_sys_virtual with
related information
param[in]	thd		thread
param[in]	table_id	table ID
param[in]	pos		virtual column position
param[in]	base_pos	base column position
param[in,out]	table_to_fill	fill this table
@return 0 on success */
static
int
i_s_dict_fill_sys_virtual(
	THD*		thd,
	table_id_t	table_id,
	ulint		pos,
	ulint		base_pos,
	TABLE*		table_to_fill)
{
	Field**		fields;

	DBUG_ENTER("i_s_dict_fill_sys_virtual");

	fields = table_to_fill->field;

5730
	OK(fields[SYS_VIRTUAL_TABLE_ID]->store(table_id, true));
5731

5732
	OK(fields[SYS_VIRTUAL_POS]->store(pos, true));
5733

5734
	OK(fields[SYS_VIRTUAL_BASE_POS]->store(base_pos, true));
5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760

	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
}

/** Function to fill information_schema.innodb_sys_virtual with information
collected by scanning SYS_VIRTUAL table.
param[in]	thd		thread
param[in,out]	tables		tables to fill
param[in]	item		condition (not used)
@return 0 on success */
static
int
i_s_sys_virtual_fill_table(
	THD*		thd,
	TABLE_LIST*	tables,
	Item*		)
{
	btr_pcur_t	pcur;
	const rec_t*	rec;
	ulint		pos;
	ulint		base_pos;
	mtr_t		mtr;

	DBUG_ENTER("i_s_sys_virtual_fill_table");
5761
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5762 5763

	/* deny access to user without PROCESS_ACL privilege */
5764
	if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_virtual) {
5765 5766 5767
		DBUG_RETURN(0);
	}

5768
	dict_sys.mutex_lock();
5769 5770
	mtr_start(&mtr);

5771
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_virtual);
5772 5773 5774 5775 5776 5777 5778

	while (rec) {
		const char*	err_msg;
		table_id_t	table_id;

		/* populate a dict_col_t structure with information from
		a SYS_VIRTUAL row */
5779
		err_msg = dict_process_sys_virtual_rec(rec,
5780 5781 5782 5783
						       &table_id, &pos,
						       &base_pos);

		mtr_commit(&mtr);
5784
		dict_sys.mutex_unlock();
5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795

		if (!err_msg) {
			i_s_dict_fill_sys_virtual(thd, table_id, pos, base_pos,
						  tables->table);
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		/* Get the next record */
5796
		dict_sys.mutex_lock();
5797 5798 5799 5800 5801
		mtr_start(&mtr);
		rec = dict_getnext_system(&pcur, &mtr);
	}

	mtr_commit(&mtr);
5802
	dict_sys.mutex_unlock();
5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820

	DBUG_RETURN(0);
}

/** Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_virtual
param[in,out]	p	table schema object
@return 0 on success */
static
int
innodb_sys_virtual_init(
	void*	p)
{
	ST_SCHEMA_TABLE*	schema;

	DBUG_ENTER("innodb_sys_virtual_init");

	schema = (ST_SCHEMA_TABLE*) p;

5821
	schema->fields_info = Show::innodb_sys_virtual_fields_info;
5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870
	schema->fill_table = i_s_sys_virtual_fill_table;

	DBUG_RETURN(0);
}

struct st_maria_plugin	i_s_innodb_sys_virtual =
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_SYS_VIRTUAL"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB SYS_VIRTUAL"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, innodb_sys_virtual_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

5871
	/* Maria extension */
5872
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
5873
	STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
5874
};
5875 5876 5877


namespace Show {
5878 5879 5880
/**  SYS_FIELDS  ***************************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FIELDS */
static ST_FIELD_INFO	innodb_sys_fields_fields_info[] =
5881
{
5882
#define SYS_FIELD_INDEX_ID	0
5883
  Column("INDEX_ID", ULonglong(), NOT_NULL),
5884

5885
#define SYS_FIELD_NAME		1
5886
  Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
5887

5888
#define SYS_FIELD_POS		2
5889 5890 5891
  Column("POS", ULong(), NOT_NULL),

  CEnd()
5892
};
5893
} // namespace Show
5894

5895 5896 5897
/**********************************************************************//**
Function to fill information_schema.innodb_sys_fields with information
collected by scanning SYS_FIELDS table.
5898 5899 5900
@return 0 on success */
static
int
5901 5902
i_s_dict_fill_sys_fields(
/*=====================*/
5903
	THD*		thd,		/*!< in: thread */
5904 5905 5906
	index_id_t	index_id,	/*!< in: index id for the field */
	dict_field_t*	field,		/*!< in: table */
	ulint		pos,		/*!< in: Field position */
5907 5908 5909 5910
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
	Field**		fields;

5911
	DBUG_ENTER("i_s_dict_fill_sys_fields");
5912 5913 5914

	fields = table_to_fill->field;

5915
	OK(fields[SYS_FIELD_INDEX_ID]->store(index_id, true));
5916

5917
	OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
5918

5919
	OK(fields[SYS_FIELD_POS]->store(pos, true));
5920 5921 5922 5923 5924 5925

	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
}
/*******************************************************************//**
5926 5927 5928
Function to go through each record in SYS_FIELDS table, and fill the
information_schema.innodb_sys_fields table with related index field
information
5929 5930 5931
@return 0 on success */
static
int
5932 5933
i_s_sys_fields_fill_table(
/*======================*/
5934 5935 5936 5937
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
5938 5939 5940 5941 5942
	btr_pcur_t	pcur;
	const rec_t*	rec;
	mem_heap_t*	heap;
	index_id_t	last_id;
	mtr_t		mtr;
5943

5944
	DBUG_ENTER("i_s_sys_fields_fill_table");
5945
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
5946 5947 5948

	/* deny access to user without PROCESS_ACL privilege */
	if (check_global_access(thd, PROCESS_ACL)) {
5949

5950 5951 5952 5953
		DBUG_RETURN(0);
	}

	heap = mem_heap_create(1000);
5954
	dict_sys.mutex_lock();
5955 5956
	mtr_start(&mtr);

5957 5958 5959 5960
	/* will save last index id so that we know whether we move to
	the next index. This is used to calculate prefix length */
	last_id = 0;

5961
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_fields);
5962 5963

	while (rec) {
5964
		ulint		pos;
5965
		const char*	err_msg;
5966 5967
		index_id_t	index_id;
		dict_field_t	field_rec;
5968

5969 5970 5971 5972
		/* Populate a dict_field_t structure with information from
		a SYS_FIELDS row */
		err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
						      &pos, &index_id, last_id);
5973 5974

		mtr_commit(&mtr);
5975
		dict_sys.mutex_unlock();
5976 5977

		if (!err_msg) {
5978 5979 5980
			i_s_dict_fill_sys_fields(thd, index_id, &field_rec,
						 pos, tables->table);
			last_id = index_id;
5981 5982 5983 5984 5985 5986 5987 5988 5989
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		mem_heap_empty(heap);

		/* Get the next record */
5990
		dict_sys.mutex_lock();
5991 5992 5993 5994 5995
		mtr_start(&mtr);
		rec = dict_getnext_system(&pcur, &mtr);
	}

	mtr_commit(&mtr);
5996
	dict_sys.mutex_unlock();
5997 5998 5999 6000 6001
	mem_heap_free(heap);

	DBUG_RETURN(0);
}
/*******************************************************************//**
6002
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_fields
6003 6004 6005
@return 0 on success */
static
int
6006 6007 6008
innodb_sys_fields_init(
/*===================*/
	void*   p)	/*!< in/out: table schema object */
6009 6010 6011
{
	ST_SCHEMA_TABLE*	schema;

6012
	DBUG_ENTER("innodb_sys_field_init");
6013 6014 6015

	schema = (ST_SCHEMA_TABLE*) p;

6016
	schema->fields_info = Show::innodb_sys_fields_fields_info;
6017
	schema->fill_table = i_s_sys_fields_fill_table;
6018 6019 6020 6021

	DBUG_RETURN(0);
}

6022
struct st_maria_plugin	i_s_innodb_sys_fields =
6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
6034
	STRUCT_FLD(name, "INNODB_SYS_FIELDS"),
6035 6036 6037 6038 6039 6040 6041

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
6042
	STRUCT_FLD(descr, "InnoDB SYS_FIELDS"),
6043 6044 6045 6046 6047 6048 6049

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
6050
	STRUCT_FLD(init, innodb_sys_fields_init),
6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

6066 6067
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
6068
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
6069 6070
};

6071
namespace Show {
6072 6073 6074
/**  SYS_FOREIGN        ********************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN */
static ST_FIELD_INFO	innodb_sys_foreign_fields_info[] =
6075
{
6076
#define SYS_FOREIGN_ID		0
6077
  Column("ID", Varchar(NAME_LEN + 1), NOT_NULL),
6078

6079
#define SYS_FOREIGN_FOR_NAME	1
6080
  Column("FOR_NAME", Varchar(NAME_LEN + 1), NOT_NULL),
6081

6082
#define SYS_FOREIGN_REF_NAME	2
6083
  Column("REF_NAME", Varchar(NAME_LEN + 1), NOT_NULL),
6084

6085
#define SYS_FOREIGN_NUM_COL	3
6086
  Column("N_COLS", ULong(), NOT_NULL),
6087

6088
#define SYS_FOREIGN_TYPE	4
6089 6090 6091
  Column("TYPE", ULong(), NOT_NULL),

  CEnd()
6092
};
6093
} // namespace Show
6094 6095

/**********************************************************************//**
6096 6097
Function to fill information_schema.innodb_sys_foreign with information
collected by scanning SYS_FOREIGN table.
6098 6099 6100
@return 0 on success */
static
int
6101
i_s_dict_fill_sys_foreign(
6102 6103
/*======================*/
	THD*		thd,		/*!< in: thread */
6104
	dict_foreign_t*	foreign,	/*!< in: table */
6105 6106 6107 6108
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
	Field**		fields;

6109
	DBUG_ENTER("i_s_dict_fill_sys_foreign");
6110 6111 6112

	fields = table_to_fill->field;

6113
	OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id));
6114

6115 6116
	OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME],
			      foreign->foreign_table_name));
6117

6118 6119
	OK(field_store_string(fields[SYS_FOREIGN_REF_NAME],
			      foreign->referenced_table_name));
6120

6121
	OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields));
6122

6123
	OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type));
6124 6125 6126 6127 6128

	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
}
6129

6130
/*******************************************************************//**
6131 6132 6133
Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop
through each record in SYS_FOREIGN, and extract the foreign key
information.
6134 6135 6136
@return 0 on success */
static
int
6137
i_s_sys_foreign_fill_table(
6138 6139 6140 6141 6142 6143 6144 6145 6146 6147
/*=======================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
	btr_pcur_t	pcur;
	const rec_t*	rec;
	mem_heap_t*	heap;
	mtr_t		mtr;

6148
	DBUG_ENTER("i_s_sys_foreign_fill_table");
6149
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
6150 6151

	/* deny access to user without PROCESS_ACL privilege */
6152
	if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_foreign) {
6153 6154 6155 6156
		DBUG_RETURN(0);
	}

	heap = mem_heap_create(1000);
6157
	dict_sys.mutex_lock();
6158 6159
	mtr_start(&mtr);

6160
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign);
6161 6162 6163

	while (rec) {
		const char*	err_msg;
6164
		dict_foreign_t	foreign_rec;
6165

6166 6167 6168
		/* Populate a dict_foreign_t structure with information from
		a SYS_FOREIGN row */
		err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
6169 6170

		mtr_commit(&mtr);
6171
		dict_sys.mutex_unlock();
6172 6173

		if (!err_msg) {
6174
			i_s_dict_fill_sys_foreign(thd, &foreign_rec,
6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185
						 tables->table);
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		mem_heap_empty(heap);

		/* Get the next record */
		mtr_start(&mtr);
6186
		dict_sys.mutex_lock();
6187 6188 6189 6190
		rec = dict_getnext_system(&pcur, &mtr);
	}

	mtr_commit(&mtr);
6191
	dict_sys.mutex_unlock();
6192 6193 6194 6195
	mem_heap_free(heap);

	DBUG_RETURN(0);
}
6196

6197
/*******************************************************************//**
6198
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign
6199 6200 6201
@return 0 on success */
static
int
6202
innodb_sys_foreign_init(
6203
/*====================*/
6204
	void*   p)	/*!< in/out: table schema object */
6205 6206 6207
{
	ST_SCHEMA_TABLE*	schema;

6208
	DBUG_ENTER("innodb_sys_foreign_init");
6209 6210 6211

	schema = (ST_SCHEMA_TABLE*) p;

6212
	schema->fields_info = Show::innodb_sys_foreign_fields_info;
6213
	schema->fill_table = i_s_sys_foreign_fill_table;
6214 6215 6216 6217

	DBUG_RETURN(0);
}

6218
struct st_maria_plugin	i_s_innodb_sys_foreign =
6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
6230
	STRUCT_FLD(name, "INNODB_SYS_FOREIGN"),
6231 6232 6233 6234 6235 6236 6237

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
6238
	STRUCT_FLD(descr, "InnoDB SYS_FOREIGN"),
6239 6240 6241 6242 6243 6244 6245

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
6246
	STRUCT_FLD(init, innodb_sys_foreign_init),
6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

6262 6263
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
6264
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
6265
};
6266

6267
namespace Show {
6268 6269 6270
/**  SYS_FOREIGN_COLS   ********************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS */
static ST_FIELD_INFO	innodb_sys_foreign_cols_fields_info[] =
6271
{
6272
#define SYS_FOREIGN_COL_ID		0
6273
  Column("ID", Varchar(NAME_LEN + 1), NOT_NULL),
6274

6275
#define SYS_FOREIGN_COL_FOR_NAME	1
6276
  Column("FOR_COL_NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
6277

6278
#define SYS_FOREIGN_COL_REF_NAME	2
6279
  Column("REF_COL_NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
6280 6281

#define SYS_FOREIGN_COL_POS		3
6282 6283 6284
  Column("POS", ULong(), NOT_NULL),

  CEnd()
6285
};
6286
} // namespace Show
6287 6288

/**********************************************************************//**
6289 6290
Function to fill information_schema.innodb_sys_foreign_cols with information
collected by scanning SYS_FOREIGN_COLS table.
6291 6292 6293
@return 0 on success */
static
int
6294 6295
i_s_dict_fill_sys_foreign_cols(
/*==========================*/
6296
	THD*		thd,		/*!< in: thread */
6297 6298 6299 6300 6301
	const char*	name,		/*!< in: foreign key constraint name */
	const char*	for_col_name,	/*!< in: referencing column name*/
	const char*	ref_col_name,	/*!< in: referenced column
					name */
	ulint		pos,		/*!< in: column position */
6302 6303 6304 6305
	TABLE*		table_to_fill)	/*!< in/out: fill this table */
{
	Field**		fields;

6306
	DBUG_ENTER("i_s_dict_fill_sys_foreign_cols");
6307 6308 6309

	fields = table_to_fill->field;

6310
	OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name));
6311

6312
	OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name));
6313

6314 6315
	OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));

6316
	OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true));
6317 6318 6319 6320 6321 6322

	OK(schema_table_store_record(thd, table_to_fill));

	DBUG_RETURN(0);
}
/*******************************************************************//**
6323 6324 6325
Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop
through each record in SYS_FOREIGN_COLS, and extract the foreign key column
information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table.
6326 6327 6328
@return 0 on success */
static
int
6329 6330
i_s_sys_foreign_cols_fill_table(
/*============================*/
6331 6332 6333 6334 6335 6336 6337 6338 6339
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
	btr_pcur_t	pcur;
	const rec_t*	rec;
	mem_heap_t*	heap;
	mtr_t		mtr;

6340
	DBUG_ENTER("i_s_sys_foreign_cols_fill_table");
6341
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
6342 6343

	/* deny access to user without PROCESS_ACL privilege */
6344 6345
	if (check_global_access(thd, PROCESS_ACL)
	    || !dict_sys.sys_foreign_cols) {
6346 6347 6348 6349
		DBUG_RETURN(0);
	}

	heap = mem_heap_create(1000);
6350
	dict_sys.mutex_lock();
6351 6352
	mtr_start(&mtr);

6353
	rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign_cols);
6354 6355 6356

	while (rec) {
		const char*	err_msg;
6357 6358 6359 6360
		const char*	name;
		const char*	for_col_name;
		const char*	ref_col_name;
		ulint		pos;
6361

6362 6363 6364
		/* Extract necessary information from a SYS_FOREIGN_COLS row */
		err_msg = dict_process_sys_foreign_col_rec(
			heap, rec, &name, &for_col_name, &ref_col_name, &pos);
6365 6366

		mtr_commit(&mtr);
6367
		dict_sys.mutex_unlock();
6368 6369

		if (!err_msg) {
6370 6371 6372
			i_s_dict_fill_sys_foreign_cols(
				thd, name, for_col_name, ref_col_name, pos,
				tables->table);
6373 6374 6375 6376 6377 6378 6379 6380 6381
		} else {
			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
					    ER_CANT_FIND_SYSTEM_REC, "%s",
					    err_msg);
		}

		mem_heap_empty(heap);

		/* Get the next record */
6382
		dict_sys.mutex_lock();
6383 6384 6385 6386 6387
		mtr_start(&mtr);
		rec = dict_getnext_system(&pcur, &mtr);
	}

	mtr_commit(&mtr);
6388
	dict_sys.mutex_unlock();
6389 6390 6391 6392 6393
	mem_heap_free(heap);

	DBUG_RETURN(0);
}
/*******************************************************************//**
6394
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols
6395 6396 6397
@return 0 on success */
static
int
6398 6399 6400
innodb_sys_foreign_cols_init(
/*========================*/
	void*	p)	/*!< in/out: table schema object */
6401 6402 6403
{
	ST_SCHEMA_TABLE*	schema;

6404
	DBUG_ENTER("innodb_sys_foreign_cols_init");
6405 6406 6407

	schema = (ST_SCHEMA_TABLE*) p;

6408
	schema->fields_info = Show::innodb_sys_foreign_cols_fields_info;
6409
	schema->fill_table = i_s_sys_foreign_cols_fill_table;
6410 6411 6412 6413

	DBUG_RETURN(0);
}

6414
struct st_maria_plugin	i_s_innodb_sys_foreign_cols =
6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
6426
	STRUCT_FLD(name, "INNODB_SYS_FOREIGN_COLS"),
6427 6428 6429 6430 6431 6432 6433

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
6434
	STRUCT_FLD(descr, "InnoDB SYS_FOREIGN_COLS"),
6435 6436 6437 6438 6439 6440 6441

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
6442
	STRUCT_FLD(init, innodb_sys_foreign_cols_init),
6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

6458 6459
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
6460
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
6461 6462
};

6463
namespace Show {
6464 6465 6466
/**  SYS_TABLESPACES    ********************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES */
static ST_FIELD_INFO	innodb_sys_tablespaces_fields_info[] =
6467
{
6468
#define SYS_TABLESPACES_SPACE		0
6469
  Column("SPACE", ULong(), NOT_NULL),
6470 6471

#define SYS_TABLESPACES_NAME		1
6472
  Column("NAME", Varchar(MAX_FULL_NAME_LEN + 1), NOT_NULL),
6473

6474
#define SYS_TABLESPACES_FLAGS		2
6475
  Column("FLAG", ULong(), NOT_NULL),
6476

6477
#define SYS_TABLESPACES_ROW_FORMAT	3
6478
  Column("ROW_FORMAT", Varchar(22), NULLABLE),
6479

6480
#define SYS_TABLESPACES_PAGE_SIZE	4
6481
  Column("PAGE_SIZE", ULong(), NOT_NULL),
6482

6483 6484
#define SYS_TABLESPACES_FILENAME	5
  Column("FILENAME", Varchar(FN_REFLEN), NOT_NULL),
6485

6486
#define SYS_TABLESPACES_FS_BLOCK_SIZE	6
6487
  Column("FS_BLOCK_SIZE", ULong(),NOT_NULL),
6488

6489
#define SYS_TABLESPACES_FILE_SIZE	7
6490
  Column("FILE_SIZE", ULonglong(), NOT_NULL),
6491

6492
#define SYS_TABLESPACES_ALLOC_SIZE	8
6493
  Column("ALLOCATED_SIZE", ULonglong(), NOT_NULL),
6494

6495
  CEnd()
6496
};
6497
} // namespace Show
6498

6499 6500 6501 6502
/** Produce one row of INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES.
@param thd  connection
@param s    tablespace
@param t    output table
6503
@return 0 on success */
6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520
static int i_s_sys_tablespaces_fill(THD *thd, const fil_space_t &s, TABLE *t)
{
  DBUG_ENTER("i_s_sys_tablespaces_fill");
  const char *row_format;

  if (s.full_crc32() || is_system_tablespace(s.id))
    row_format= nullptr;
  else if (FSP_FLAGS_GET_ZIP_SSIZE(s.flags))
    row_format= "Compressed";
  else if (FSP_FLAGS_HAS_ATOMIC_BLOBS(s.flags))
    row_format= "Dynamic";
  else
    row_format= "Compact or Redundant";

  Field **fields= t->field;

  OK(fields[SYS_TABLESPACES_SPACE]->store(s.id, true));
6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533
  {
    Field *f= fields[SYS_TABLESPACES_NAME];
    const auto name= s.name();
    if (name.data())
    {
      OK(f->store(name.data(), name.size(), system_charset_info));
      f->set_notnull();
    }
    else
      f->set_notnull();
  }

  fields[SYS_TABLESPACES_NAME]->set_null();
6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570
  OK(fields[SYS_TABLESPACES_FLAGS]->store(s.flags, true));
  OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT], row_format));
  const char *filepath= s.chain.start->name;
  OK(field_store_string(fields[SYS_TABLESPACES_FILENAME], filepath));

  OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(s.physical_size(), true));
  os_file_stat_t stat;
  stat.block_size= 0;
  os_file_size_t file= os_file_get_size(filepath);
  if (file.m_total_size == os_offset_t(~0))
  {
    file.m_total_size= 0;
    file.m_alloc_size= 0;
  }
  else
  {
    /* Get the file system (or Volume) block size. */
    switch (dberr_t err= os_file_get_status(filepath, &stat, false, false)) {
    case DB_FAIL:
      ib::warn() << "File '" << filepath << "', failed to get stats";
      break;
    case DB_SUCCESS:
    case DB_NOT_FOUND:
      break;
    default:
      ib::error() << "File '" << filepath << "' " << err;
      break;
    }
  }

  OK(fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->store(stat.block_size, true));
  OK(fields[SYS_TABLESPACES_FILE_SIZE]->store(file.m_total_size, true));
  OK(fields[SYS_TABLESPACES_ALLOC_SIZE]->store(file.m_alloc_size, true));

  OK(schema_table_store_record(thd, t));

  DBUG_RETURN(0);
6571
}
6572

6573 6574 6575
/** Populate INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES.
@param thd    connection
@param tables table to fill
6576
@return 0 on success */
6577 6578 6579 6580 6581 6582 6583 6584 6585 6586
static int i_s_sys_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, Item*)
{
  DBUG_ENTER("i_s_sys_tablespaces_fill_table");
  RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);

  if (check_global_access(thd, PROCESS_ACL))
    DBUG_RETURN(0);

  int err= 0;

6587
  mysql_mutex_lock(&fil_system.mutex);
6588 6589
  fil_system.freeze_space_list++;

6590
  for (fil_space_t &space : fil_system.space_list)
6591
  {
6592 6593
    if (space.purpose == FIL_TYPE_TABLESPACE && !space.is_stopping() &&
        space.chain.start)
6594
    {
6595
      space.reacquire();
6596
      mysql_mutex_unlock(&fil_system.mutex);
6597
      err= i_s_sys_tablespaces_fill(thd, space, tables->table);
6598
      mysql_mutex_lock(&fil_system.mutex);
6599
      space.release();
6600 6601 6602 6603 6604 6605
      if (err)
        break;
    }
  }

  fil_system.freeze_space_list--;
6606
  mysql_mutex_unlock(&fil_system.mutex);
6607
  DBUG_RETURN(err);
6608
}
6609

6610
/*******************************************************************//**
6611
Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
6612 6613 6614
@return 0 on success */
static
int
6615 6616 6617
innodb_sys_tablespaces_init(
/*========================*/
	void*	p)	/*!< in/out: table schema object */
6618 6619 6620
{
	ST_SCHEMA_TABLE*	schema;

6621
	DBUG_ENTER("innodb_sys_tablespaces_init");
6622 6623 6624

	schema = (ST_SCHEMA_TABLE*) p;

6625
	schema->fields_info = Show::innodb_sys_tablespaces_fields_info;
6626
	schema->fill_table = i_s_sys_tablespaces_fill_table;
6627 6628 6629 6630

	DBUG_RETURN(0);
}

6631
struct st_maria_plugin	i_s_innodb_sys_tablespaces =
6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
6643
	STRUCT_FLD(name, "INNODB_SYS_TABLESPACES"),
6644 6645 6646 6647 6648 6649 6650

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, plugin_author),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
6651
	STRUCT_FLD(descr, "InnoDB tablespaces"),
6652 6653 6654 6655 6656 6657 6658

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
6659
	STRUCT_FLD(init, innodb_sys_tablespaces_init),
6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

6675 6676
        /* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
6677
        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
6678 6679
};

6680
namespace Show {
Monty's avatar
Monty committed
6681 6682 6683 6684 6685
/**  TABLESPACES_ENCRYPTION    ********************************************/
/* Fields of the table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION */
static ST_FIELD_INFO	innodb_tablespaces_encryption_fields_info[] =
{
#define TABLESPACES_ENCRYPTION_SPACE	0
6686
  Column("SPACE", ULong(), NOT_NULL),
Monty's avatar
Monty committed
6687 6688

#define TABLESPACES_ENCRYPTION_NAME		1
6689
  Column("NAME", Varchar(MAX_FULL_NAME_LEN + 1), NULLABLE),
Monty's avatar
Monty committed
6690 6691

#define TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME	2
6692
  Column("ENCRYPTION_SCHEME", ULong(), NOT_NULL),
Monty's avatar
Monty committed
6693 6694

#define TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS	3
6695
  Column("KEYSERVER_REQUESTS", ULong(), NOT_NULL),
Monty's avatar
Monty committed
6696 6697

#define TABLESPACES_ENCRYPTION_MIN_KEY_VERSION	4
6698
  Column("MIN_KEY_VERSION", ULong(), NOT_NULL),
Monty's avatar
Monty committed
6699 6700

#define TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION	5
6701
  Column("CURRENT_KEY_VERSION", ULong(), NOT_NULL),
Monty's avatar
Monty committed
6702 6703

#define TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER	6
6704
  Column("KEY_ROTATION_PAGE_NUMBER", ULonglong(), NULLABLE),
Monty's avatar
Monty committed
6705 6706

#define TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER 7
6707
  Column("KEY_ROTATION_MAX_PAGE_NUMBER", ULonglong(), NULLABLE),
Monty's avatar
Monty committed
6708

6709
#define TABLESPACES_ENCRYPTION_CURRENT_KEY_ID	8
6710
  Column("CURRENT_KEY_ID", ULong(), NOT_NULL),
6711

6712
#define TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING 9
6713
  Column("ROTATING_OR_FLUSHING", SLong(1), NOT_NULL),
6714 6715

  CEnd()
Monty's avatar
Monty committed
6716
};
6717
} // namespace Show
Monty's avatar
Monty committed
6718 6719

/**********************************************************************//**
6720
Function to fill INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION.
6721 6722 6723
@param[in]	thd		thread handle
@param[in]	space		Tablespace
@param[in]	table_to_fill	I_S table to fill
Monty's avatar
Monty committed
6724 6725 6726 6727
@return 0 on success */
static
int
i_s_dict_fill_tablespaces_encryption(
6728 6729 6730
	THD*		thd,
	fil_space_t*	space,
	TABLE*		table_to_fill)
Monty's avatar
Monty committed
6731 6732 6733 6734 6735 6736 6737 6738 6739
{
	Field**	fields;
	struct fil_space_crypt_status_t status;

	DBUG_ENTER("i_s_dict_fill_tablespaces_encryption");

	fields = table_to_fill->field;

	fil_space_crypt_get_status(space, &status);
6740

6741 6742 6743 6744 6745 6746
	/* If tablespace id does not match, we did not find
	encryption information for this tablespace. */
	if (!space->crypt_data || space->id != status.space) {
		goto skip;
	}

6747
	OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true));
Monty's avatar
Monty committed
6748

6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759
	{
		const auto name = space->name();
		if (name.data()) {
			OK(fields[TABLESPACES_ENCRYPTION_NAME]->store(
				   name.data(), name.size(),
				   system_charset_info));
			fields[TABLESPACES_ENCRYPTION_NAME]->set_notnull();
		} else {
			fields[TABLESPACES_ENCRYPTION_NAME]->set_null();
		}
	}
Monty's avatar
Monty committed
6760 6761

	OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store(
6762
		   status.scheme, true));
Monty's avatar
Monty committed
6763
	OK(fields[TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS]->store(
6764
		   status.keyserver_requests, true));
Monty's avatar
Monty committed
6765
	OK(fields[TABLESPACES_ENCRYPTION_MIN_KEY_VERSION]->store(
6766
		   status.min_key_version, true));
Monty's avatar
Monty committed
6767
	OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION]->store(
6768
		   status.current_key_version, true));
6769
	OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_ID]->store(
6770
		   status.key_id, true));
6771
	OK(fields[TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING]->store(
6772
			   status.rotating || status.flushing, true));
6773

Monty's avatar
Monty committed
6774 6775 6776
	if (status.rotating) {
		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->set_notnull();
		OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->store(
6777
			   status.rotate_next_page_number, true));
Monty's avatar
Monty committed
6778 6779
		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->set_notnull();
		OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->store(
6780
			   status.rotate_max_page_number, true));
Monty's avatar
Monty committed
6781 6782 6783 6784 6785 6786
	} else {
		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]
			->set_null();
		fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]
			->set_null();
	}
6787

Monty's avatar
Monty committed
6788 6789
	OK(schema_table_store_record(thd, table_to_fill));

6790
skip:
Monty's avatar
Monty committed
6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806
	DBUG_RETURN(0);
}
/*******************************************************************//**
Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
Loop through each record in TABLESPACES_ENCRYPTION, and extract the column
information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
@return 0 on success */
static
int
i_s_tablespaces_encryption_fill_table(
/*===========================*/
	THD*		thd,	/*!< in: thread */
	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
	Item*		)	/*!< in: condition (not used) */
{
	DBUG_ENTER("i_s_tablespaces_encryption_fill_table");
6807
	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
Monty's avatar
Monty committed
6808 6809

	/* deny access to user without PROCESS_ACL privilege */
6810
	if (check_global_access(thd, PROCESS_ACL)) {
Monty's avatar
Monty committed
6811 6812 6813
		DBUG_RETURN(0);
	}

6814
	int err = 0;
6815
	mysql_mutex_lock(&fil_system.mutex);
6816
	fil_system.freeze_space_list++;
6817

6818 6819 6820 6821
	for (fil_space_t& space : fil_system.space_list) {
		if (space.purpose == FIL_TYPE_TABLESPACE
		    && !space.is_stopping()) {
			space.reacquire();
6822
			mysql_mutex_unlock(&fil_system.mutex);
6823
			err = i_s_dict_fill_tablespaces_encryption(
6824
				thd, &space, tables->table);
6825
			mysql_mutex_lock(&fil_system.mutex);
6826
			space.release();
6827 6828 6829
			if (err) {
				break;
			}
6830
		}
Monty's avatar
Monty committed
6831 6832
	}

6833
	fil_system.freeze_space_list--;
6834
	mysql_mutex_unlock(&fil_system.mutex);
6835
	DBUG_RETURN(err);
Monty's avatar
Monty committed
6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851
}
/*******************************************************************//**
Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION
@return 0 on success */
static
int
innodb_tablespaces_encryption_init(
/*========================*/
	void*	p)	/*!< in/out: table schema object */
{
	ST_SCHEMA_TABLE*	schema;

	DBUG_ENTER("innodb_tablespaces_encryption_init");

	schema = (ST_SCHEMA_TABLE*) p;

6852
	schema->fields_info = Show::innodb_tablespaces_encryption_fields_info;
Monty's avatar
Monty committed
6853 6854 6855 6856 6857
	schema->fill_table = i_s_tablespaces_encryption_fill_table;

	DBUG_RETURN(0);
}

6858
struct st_maria_plugin	i_s_innodb_tablespaces_encryption =
Monty's avatar
Monty committed
6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903
{
	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
	/* int */
	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),

	/* pointer to type-specific plugin descriptor */
	/* void* */
	STRUCT_FLD(info, &i_s_info),

	/* plugin name */
	/* const char* */
	STRUCT_FLD(name, "INNODB_TABLESPACES_ENCRYPTION"),

	/* plugin author (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(author, "Google Inc"),

	/* general descriptive text (for SHOW PLUGINS) */
	/* const char* */
	STRUCT_FLD(descr, "InnoDB TABLESPACES_ENCRYPTION"),

	/* the plugin license (PLUGIN_LICENSE_XXX) */
	/* int */
	STRUCT_FLD(license, PLUGIN_LICENSE_BSD),

	/* the function to invoke when plugin is loaded */
	/* int (*)(void*); */
	STRUCT_FLD(init, innodb_tablespaces_encryption_init),

	/* the function to invoke when plugin is unloaded */
	/* int (*)(void*); */
	STRUCT_FLD(deinit, i_s_common_deinit),

	/* plugin version (for SHOW PLUGINS) */
	/* unsigned int */
	STRUCT_FLD(version, INNODB_VERSION_SHORT),

	/* struct st_mysql_show_var* */
	STRUCT_FLD(status_vars, NULL),

	/* struct st_mysql_sys_var** */
	STRUCT_FLD(system_vars, NULL),

	/* Maria extension */
	STRUCT_FLD(version_info, INNODB_VERSION_STR),
6904
	STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE)
Monty's avatar
Monty committed
6905
};