简介
在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;
6. schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
7. schema->fields_info = innodb_my_table_field;
8. schema->fill_table = i_s_innodb_my_table_fill_table;
10. DBUG_RETURN(0);
11. }
其中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),
7. /* pointer to type-specific plugin descriptor */
8. /* void* */
9. STRUCT_FLD(info, &i_s_info),
11. /* plugin name */
12. /* const char* */
13. STRUCT_FLD(name, "INNODB_MY_TABLE”),
15. /* plugin author (for SHOW PLUGINS) */
16. /* const char* */
17. STRUCT_FLD(author, "Alibaba"),
19. /* general descriptive text (for SHOW PLUGINS) */
20. /* const char* */
21. STRUCT_FLD(descr, "InnoDB My table info.”),
23. /* the plugin license (PLUGIN_LICENSE_XXX) */
24. /* int */
25. STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
27. /* the function to invoke when plugin is loaded */
28. /* int (*)(void*); */
29. STRUCT_FLD(init, i_s_innodb_my_table_init),
31. /* the function to invoke when plugin is unloaded */
32. /* int (*)(void*); */
33. STRUCT_FLD(deinit, i_s_common_deinit),
34. /* plugin version (for SHOW PLUGINS) */
35. /* unsigned int */
36. STRUCT_FLD(version, INNODB_VERSION_SHORT),
38. /* struct st_mysql_show_var* */
39. STRUCT_FLD(status_vars, NULL),
41. /* struct st_mysql_sys_var** */
42. STRUCT_FLD(system_vars, NULL),
44. /* reserved for dependency checking */
45. /* void* */
46. STRUCT_FLD(__reserved1, NULL),
48. /* Plugin flags */
49. /* unsigned long */
50. STRUCT_FLD(flags, 0UL),
51. };
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)},
13. #define IDX_MY_TABLE_FIELD_1 1
14. {STRUCT_FLD(field_name, “field1”),
15. STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
16. STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
17. STRUCT_FLD(value, 0),
18. STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
19. STRUCT_FLD(old_name, ""),
20. STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
21. ….
22. }
填充函数就是用来实现往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元数据库中了。
