简介

在MySQL中, INFORMATION_SCHEMA 信息数据库提供了访问数据库元数据的方式,其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,列的数据类型与访问权限等。在INFORMATION_SCHEMA中,有数个只读表。它们实际上是视图,也不是基本表,因此,你将无法看到与之相关的任何文件。下面将介绍如何新加一个INFORMATION_SCHEMA系统表,以能够通过查询表的方式来查询我们希望得到的元数据信息。

INFORMATION_SCHEMA表是作为MySQL的插件来实现的

INFORMATION_SCHEMA和我们经常讲到的引擎插件(Engine plugin)MYSQL_STORAGE_ENGINE_PLUGIN = 1类似,作为一个MySQL的插件来实现的。INFORMATION_SCHEMA的插件类型是MYSQL_INFORMATION_SCHEMA_PLUGIN = 4 。

  1. #define MYSQL_UDF_PLUGIN 0 /* User-defined function */
  2. #define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */
  3. #define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */
  4. #define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */
  5. #define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */
  6. #define MYSQL_AUDIT_PLUGIN 5 /* The Audit plugin type */
  7. #define MYSQL_REPLICATION_PLUGIN 6 /* The replication plugin type */
  8. #define MYSQL_AUTHENTICATION_PLUGIN 7 /* The authentication plugin type */
  9. #define MYSQL_VALIDATE_PASSWORD_PLUGIN 8 /* validate password plugin type */

INFORMATION_SCHEMA表插件接口

Mysql为要定义的INFORMATION_SCHEMA表提供了如下插件接口。主要通过st_mysql_plugin 结构实现的。

  1. struct st_mysql_plugin
  2. {
  3. int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */
  4. void *info; /* pointer to type-specific plugin descriptor */
  5. const char *name; /* plugin name */
  6. const char *author; /* plugin author (for I_S.PLUGINS) */
  7. const char *descr; /* general descriptive text (for I_S.PLUGINS) */
  8. int license; /* the plugin license (PLUGIN_LICENSE_XXX) */
  9. int (*init)(MYSQL_PLUGIN); /* the function to invoke when plugin is loaded */
  10. int (*deinit)(MYSQL_PLUGIN);/* the function to invoke when plugin is unloaded */
  11. unsigned int version; /* plugin version (for I_S.PLUGINS) */
  12. struct st_mysql_show_var *status_vars;
  13. struct st_mysql_sys_var **system_vars;
  14. void * __reserved1; /* reserved for dependency checking */
  15. unsigned long flags; /* flags for plugin */
  16. };

此接口要提供这个插件的类型。这里我们要添加一个INFORMATION_SCHEMA表,所以type就是MYSQL_INFORMATION_SCHEMA_PLUGIN; name就是你要定义的表名字, 就像INFORMATION_SCHEMA中的表INNODB_SYS_DATAFILES 一样。 这里比如INNODB_MY_TABLE; 另外比较重要的两个字段就是init和deinit,这两个字段分别是在这个插件在装载和卸载时调用的函数。如果没有特殊的需求deinit函数可以直接使用系统提供的i_s_common_deinit 通用函数。 在st_mysql_plugin结构中,init字段用来提供在这个插件装载时调用的函数。其实现主要是通过为ST_SCHEMA_TABLE结构提供INFORMATION_SCHEMA表结构定义和表填充数据函数。

  1. i_s_innodb_my_table_init(
  2. void* p) /*!< in/out: table schema object */
  3. {
  4. ST_SCHEMA_TABLE* schema;
  5. schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
  6. schema->fields_info = innodb_my_table_field;
  7. schema->fill_table = i_s_innodb_my_table_fill_table;
  8. DBUG_RETURN(0);
  9. }

其中innodb_my_table_field就是此新加入INFORMATION_SCHEMA表结构定义;innodb_my_table_fill_table就是当我们查询这张表时,其中显示的数据就是通过这个函数提供的。

例如我们定义的新表插件接口如下:

  1. UNIV_INTERN struct st_mysql_plugin i_s_innodb_my_table =
  2. {
  3. /* the plugin type (a MYSQL_XXX_PLUGIN value) */
  4. /* int */
  5. STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
  6. /* pointer to type-specific plugin descriptor */
  7. /* void* */
  8. STRUCT_FLD(info, &i_s_info),
  9. /* plugin name */
  10. /* const char* */
  11. STRUCT_FLD(name, "INNODB_MY_TABLE”),
  12. /* plugin author (for SHOW PLUGINS) */
  13. /* const char* */
  14. STRUCT_FLD(author, "Alibaba"),
  15. /* general descriptive text (for SHOW PLUGINS) */
  16. /* const char* */
  17. STRUCT_FLD(descr, "InnoDB My table info.”),
  18. /* the plugin license (PLUGIN_LICENSE_XXX) */
  19. /* int */
  20. STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
  21. /* the function to invoke when plugin is loaded */
  22. /* int (*)(void*); */
  23. STRUCT_FLD(init, i_s_innodb_my_table_init),
  24. /* the function to invoke when plugin is unloaded */
  25. /* int (*)(void*); */
  26. STRUCT_FLD(deinit, i_s_common_deinit),
  27. /* plugin version (for SHOW PLUGINS) */
  28. /* unsigned int */
  29. STRUCT_FLD(version, INNODB_VERSION_SHORT),
  30. /* struct st_mysql_show_var* */
  31. STRUCT_FLD(status_vars, NULL),
  32. /* struct st_mysql_sys_var** */
  33. STRUCT_FLD(system_vars, NULL),
  34. /* reserved for dependency checking */
  35. /* void* */
  36. STRUCT_FLD(__reserved1, NULL),
  37. /* Plugin flags */
  38. /* unsigned long */
  39. STRUCT_FLD(flags, 0UL),
  40. };

INFORMATION_SCHEMA表的结构定义

表结构定义在一个ST_FIELD_INFO结构中,这个结构定义了要添加到INFORMATION_SCHEMA表的各个字段,包括字段名、字段类型和字段长度等信息。这里就涉及到如何将这里定义的各个字段与在st_mysql_plugin 结构中定的表信息关联起来。这里就要用到在st_mysql_plugin 结构里定义的初始化函数有关了。实现init函数的参数,是一个void类型的输入参数,这个参数在information schema的插件中,就是一个ST_SCHEMA_TABLE结构指针,就在这个结构中要提供这个表的字段信息,以及查询表时调用填充数据的函数。

  1. static ST_FIELD_INFO innodb_my_table_field[] =
  2. {
  3. #define IDX_MY_TABLE_FIELD_0 0
  4. {STRUCT_FLD(field_name, field0”),
  5. STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
  6. STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
  7. STRUCT_FLD(value, 0),
  8. STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
  9. STRUCT_FLD(old_name, ""),
  10. STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
  11. #define IDX_MY_TABLE_FIELD_1 1
  12. {STRUCT_FLD(field_name, field1”),
  13. STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
  14. STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
  15. STRUCT_FLD(value, 0),
  16. STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
  17. STRUCT_FLD(old_name, ""),
  18. STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
  19. ….
  20. }

填充函数就是用来实现往INFORMATION_SCHEMA里填充数据的函数,可以根据具体的需求和要填充的数据,根据实际情况读取引擎内部的状态信息,写入到这个表中。比如上面在初始化装载函数中赋值给field_table字段的函数i_s_innodb_my_table_fill_table()。

加表到INFORMATION_SCHEMA元数据库

通过上述几步就把这个表定义出来了。 如何把这个表真正的加入到INFORMATION_SCHEMA里,客户端可以通过查询语句查询这张表呢?为了实现这个目标就要把这张表加入到ha_innodb.cc文件里,从mysql_declare_plugin(innobase) 到mysql_declare_plugin_end 之间的结构里。在这里我们可以看到已经定义了一系列的INFORMATION_SCHEMA表,包含常见到的i_s_innodb_trx、i_s_innodb_locks和i_s_innodb_sys_tables等表,只要把我们新实现的插件接口i_s_innodb_my_table加入到这个结构中,就成功把这张表加入了INFORMATION_SCHEMA元数据库中了。