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