广告
返回顶部
首页 > 资讯 > 数据库 >MySQL中如何编写Information Schema Plugin
  • 807
分享到

MySQL中如何编写Information Schema Plugin

2024-04-02 19:04:59 807人浏览 泡泡鱼
摘要

Mysql中如何编写InfORMation Schema Plugin,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 1. 什么是i_s p

Mysql中如何编写InfORMation Schema Plugin,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

1. 什么是i_s plugin

mysql里面,默认会有一个information schema(以下简写为i_s),用于记录一些与元数据或表的模式相关的信息,与其他数据库不一样,在data目录下,并没有为i_s建立文件夹,这说明,i_s并不是物理存在的,而是在需要的时候,才会临时创建。这就可以解释为什么i_s库中的表的记录总是无法删除或修改。

2.为什么使用i_s plugin

虽然i_s中定义了丰富的表,但通过i_s plugin,我们可以将其功能进行扩展,丰富其中的信息,比如,我们可以把关心信息以表的形式展现出来,可以通过引入Mysql的内核代码,来监控内核的运行状态,例如资源状态、线程状态、table cache状态等信息。客户端可以通过sql来过滤想要的内容,甚至,我们可以在plugin中通过cond来进行过滤,而无需在层处理。

3.如何编写i_s plugin

1)之前已经介绍过的,这里不在赘述,在plugin间通用的包括:

a. plugin的声明;

b.添加系统变量(show /setvariables)

c.添加状态变量(show status)

2)初始化I_S插件

函数原型:name_init(void *p)

函数用于初始化插件,包括指定表的模式、创建表、构造表的函数指针等信息,指针p会指向一个结构体st_schema_table,如下表:

初始化的目的是为了填充结构体st_schema_table,从而确定表的定义,在查询表的时候,调用相应的函数进行记录填充。由于该结构体与内建的i_s表是公用的,因此一些字段我们可以直接忽略掉。在编写plugin的时候,我们需要填充的内容包括:

Ø  Fields_info

Ø  Fill_table

2).初始化表结构fields_info

Fields_info结构体为st_field_info

通常我们会预定义数组,以NULL列结束:

ST_FIELD_INFO  is_field[] = {

         {……},

         ……

{0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0}

}

3)fill_table()

函数原型:int fill_table(THD *thd, TABLE_LIST *tables, COND *cond);

参数描述:

为了将记录保存到i_s表中,这里不的不提到两个函数:field类的成员函数store_系列函数和schema_table_store_record(),前者用来存储数据到表结构体追踪,后者用来将一行存储好的数据放入到临时表中。

store函数是Field类的方法,有5个:

其中my_declimal类型或者MYSQL_TIME等MySQL代码内特有的类型,我们都可以通过引入相应的代码来构建结构体。

注意当列被声明为MY_I_S_MAYBE_NULL时,需要做一些额外的处理,见之前关于st_field_info结构体的介绍。

当store数据到Field结构体后,我们还需要将其存储到表中,api函数如下:

boolschema_table_store_record(THD *thd, TABLE *table);

其中thd为当前线程,table为tables->table

为了包含这两个函数,我们需要引入如下头文件:

#include <mysql_priv.h>

4)使用COND进行优化

从fill_table的函数原型中,我们可以看到结构体COND,这在MySQL层用作对条件进行记录过滤,实际上在plugin里,我们可以直接进行过滤,只返回到MYSQL层需要的数据。如下图所示:

如果你接触过源代码,会发现COND是一个相当复杂的类型,如果由我们自己编写代码来操作显然要耗费大量的精力,我们可以依葫芦画瓢,找到源代码里是如何使用该结构体的,构造相应的参数,就可以直接调用了,这也是Plugin的诱人之处,我们可以根据需求引用已有的代码。

MySQL层代码大多定义在sql文件夹下,我们在编译时指定相应的目录即可。

当我们的操作对系统影响比较大时,需要尽快的得到结果,例如,内建的I_S表COLUMNS,在填充数据时需要打开所有的表,如果在Plugin层做过滤,那么当我们找到一个不符合条件的表时,尽快关闭,而不是等到MYSQL层来过滤后关闭。

例如函数:

bool calc_lookup_values_from_cond(THD *thd,COND *cond, TABLE_LIST *table, LOOKUP_FIELD_VALUES *lookups);

其中LOOPUP_FIEDL_VALUES结构体为:

sql/sql_show.cc:

typedef struct st_lookup_field_values

{

LEX_STRING value1, value2;

bool value1_is_wildcard, value2_is_wildcard;

} LOOKUP_FIELD_VALUES;

这个函数用于处理等值的情况,函数将寻找类似field1 = constant1 和field2 = constant2这样的条件, 如果找到了,将被存储在LOOKUP_FIELD_VALUES结构体的value1和value2中:

lookups.value1.str

lookups.value2.str

当我们找到了在COND中定义的条件后,就可以进行字符串匹配了。

该函数用于支持INFORMATION_SCHEMA.TABLES, INFORMATION_ SCHEMA.COLUMNS,和其他类型的内建I_S表,主要用来存储表名和数据库名,也就是说,value值为string类型,并且只支持两个等值操作,如果想实现更复杂的cond遍历,我们需要自己来实现。

示例如下(参考自《mysql plugin development》):

view plain

#include <mysql_priv.h> 

 

typedef struct st_lookup_field_values 

LEX_STRING value1, value2; 

bool value1_is_wildcard,value2_is_wildcard; 

} LOOKUP_FIELD_VALUES; 

bool calc_lookup_values_from_cond(THD *thd,COND *cond, 

TABLE_LIST *table, LOOKUP_FIELD_VALUES*lookups); 

bool schema_table_store_record(THD *thd,TABLE *table); 

 

ST_FIELD_INFO cond_push_fields[] = 

{"NUMBER",10, MYSQL_TYPE_LONG, 0, 0, 0, 0}, 

{"TEXT",100, MYSQL_TYPE_STRING, 0, 0, 0, 0}, 

{0, 0,MYSQL_TYPE_NULL, 0, 0, 0, 0} 

int fill_cond_push(THD *thd, TABLE_LIST*tables, COND *cond) 

          

CHARSET_INFO *cs= system_charset_info; 

TABLE *table =tables->table; 

 

const char**ptr, *output[] = {"hello", "world", "this", "is","a", "test", 0}; 

int num; 

 

LOOKUP_FIELD_VALUESlookups; 

bzero((char*)&lookups, sizeof(lookups)); 

 

if (calc_lookup_values_from_cond(thd, cond, tables,&lookups)) 

return 0; 

for (num = 0,ptr = output; *ptr; ptr++) 

if (lookups.value1.str && 

my_strnncoll(cs, (const uchar*)*ptr, strlen(*ptr), 

(const uchar*)lookups.value1.str, 

lookups.value1.length)) 

continue; 

                    

table->field[0]->store(++num); 

table->field[1]->store(*ptr, strlen(*ptr), cs); 

if (schema_table_store_record(thd, table)) 

return 1; 

return 0; 

 

int cond_push_init(void *p) 

ST_SCHEMA_TABLE*schema = (ST_SCHEMA_TABLE*) p; 

 

schema->fields_info= cond_push_fields; 

 

schema->fill_table= fill_cond_push; 

schema->idx_field1= 1; 

return 0; 

struct st_mysql_information_scheMacond_push= 

{MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; 

mysql_declare_plugin(cond_push) 

MYSQL_INFORMATION_SCHEMA_PLUGIN, 

&cond_push, 

"COND_PUSH", 

"AndrewHutchings (Andrew.Hutchings@Sun.COM)", 

"A simplecondition pushdown demo table", 

PLUGIN_LICENSE_GPL, 

cond_push_init, 

NULL, 

0x0010, 

NULL, 

NULL, 

NULL 

mysql_declare_plugin_end; 

5)例子:获取当前query cache中的QUERY信息(摘自网络,略改)

Query_cache中的query 存储在query_cache->queries结构体中,这是一个hash表,我们可以遍历其中的记录还获得想要的数据,代码如下:

view plain

#include <stdlib.h> 

#include <ctype.h> 

 

#ifndef MYSQL_SERVER 

#define MYSQL_SERVER 

#endif 

 

#include <sql_cache.cc> 

#include <mysql_priv.h> 

#include <mysql/plugin.h> 

#include <my_global.h> 

#include <mysql_version.h> 

#include <my_dir.h> 

 

ST_FIELD_INFOmysql_is_cached_queries_fields[]= 

 {"STATEMENT_ID", 21, MYSQL_TYPE_LONG, 0, 0, "Id"}, 

 {"SCHEMA_NAME", 64, MYSQL_TYPE_STRING, 0, 0,"Schema"}, 

 {"STATEMENT_TEXT", MAX_STATEMENT_TEXT_LENGTH,MYSQL_TYPE_STRING, 0, 0, "Statment text"}, 

 {"RESULT_BLOCKS_COUNT", 21, MYSQL_TYPE_LONG, 0, 0, "CountResult Blocks"}, 

 {"RESULT_BLOCKS_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, 0,"Size Result Blocks"}, 

 {"RESULT_BLOCKS_SIZE_USED", 21, MYSQL_TYPE_LONGLONG, 0, 0,"Size Used Result Blocks"}, 

  {0,0, MYSQL_TYPE_STRING, 0, 0, 0} 

}; 

 

static intmysql_is_cached_queries_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) 

  intstatus;                                

 CHARSET_INFO *scs= system_charset_info;   

 TABLE *table= (TABLE *)tables->table;     

 Accessible_Query_Cache *qc; 

 HASH *queries; 

 const uchar *query_cache_block_raw; 

 Query_cache_block* query_cache_block; 

 Query_cache_query* query_cache_query; 

 uint result_blocks_count; 

 ulonglong result_blocks_size; 

 ulonglong result_blocks_size_used; 

 Query_cache_block *first_result_block; 

 Query_cache_block *result_block; 

 const char *statement_text; 

 size_t statement_text_length; 

 const char *key; 

 size_t key_length; 

 

  qc= (Accessible_Query_Cache *)&query_cache; 

 

  query_cache.lock(); 

 

 queries = qc->get_queries(); 

   

   query_cache_block_raw = hash_element(queries, i); 

   query_cache_block = (Query_cache_block*)query_cache_block_raw; 

query_cache_query= query_cache_block->query(); 

   table->field[COLUMN_STATEMENT_ID]->store(i+1, 0); 

    

   statement_text = (const char*)query_cache_query->query(); 

   statement_text_length = strlen(statement_text); 

 

   table->field[COLUMN_STATEMENT_TEXT]->store(  (char*)statement_text 

                                ,statement_text_length > MAX_STATEMENT_TEXT_LENGTH? 

MAX_STATEMENT_TEXT_LENGTH 

                                :statement_text_length 

                                , scs 

   ); 

    

   key = (const char*)query_cache_query_get_key(  query_cache_block_raw                          

                                                           ,&key_length  , 0 ); 

key_length =strlen(key+statement_text_length+1)-1; 

          

   table->field[COLUMN_SCHEMA_NAME]->store((char*)key+statement_text_length+1 

                                             , key_length 

                                             ,scs  ); 

    

   first_result_block= query_cache_query->result(); 

   if(first_result_block) 

    { 

      

     result_block= first_result_block; 

     result_blocks_count = 1;     

     result_blocks_size = result_block->length; 

     result_blocks_size_used = result_block->used; 

      

     while((result_block= result_block->next)!=first_result_block) 

     { 

        

             result_blocks_count++;               

        

       result_blocks_size += result_block->length; 

        

       result_blocks_size_used += result_block->used; 

     } 

    } 

   else 

    { 

     result_blocks_count = 0; 

     result_blocks_size = 0; 

     result_blocks_size_used = 0; 

    } 

    

   table->field[COLUMN_RESULT_BLOCKS_COUNT]->store( result_blocks_count ,0); 

    

   table->field[COLUMN_RESULT_BLOCKS_SIZE]->store( result_blocks_size  , 0); 

    

   table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->store(result_blocks_size_used , 0 ); 

    

   status = schema_table_store_record(thd, table); 

   if (status) {                                               

     status= 1;                                    

           Goto cleanup;                    

  } 

 status = 0;                                      

cleanup:                                          

  query_cache.unlock(); 

 return status; 

static intmysql_is_cached_queries_plugin_init(void *p) 

 ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p; 

 schema->fields_info= mysql_is_cached_queries_fields; 

 schema->fill_table= mysql_is_cached_queries_fill_table; 

 return 0; 

static int mysql_is_cached_queries_plugin_deinit(void*p) 

         return0; 

struct st_mysql_information_schemamysql_is_cached_queries_plugin= 

{MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; 

 

mysql_declare_plugin(mysql_is_cached_queries) 

 MYSQL_INFORMATION_SCHEMA_PLUGIN, 

 &mysql_is_cached_queries_plugin, 

 "MYSQL_CACHED_QUERIES", 

 "Roland Bouman", 

 "Lists all queries in the query cache.", 

 PLUGIN_LICENSE_GPL, 

 mysql_is_cached_queries_plugin_init,  

 mysql_is_cached_queries_plugin_deinit,  

 0x0010 , 

 NULL,                        

 NULL,                        

 NULL                         

mysql_declare_plugin_end; 

view plain

</pre><pre name="code" class="cpp"> 

view plain

看完上述内容,你们掌握MySQL中如何编写Information Schema Plugin的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网数据库频道,感谢各位的阅读!

您可能感兴趣的文档:

--结束END--

本文标题: MySQL中如何编写Information Schema Plugin

本文链接: https://www.lsjlt.com/news/61669.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MySQL中如何编写Information Schema Plugin
    MySQL中如何编写Information Schema Plugin,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 1. 什么是i_s p...
    99+
    2022-10-18
  • MySQL中如何编写daemon plugin
    这篇文章给大家介绍MySQL中如何编写daemon plugin,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 1.什么是DaemonPlugin 顾名思义,daemon plug...
    99+
    2022-10-18
  • 如何编写mysql函数
    下文主要给大家带来如何编写mysql函数,希望这些内容能够带给大家实际用处,这也是我编辑如何编写mysql函数这篇文章的主要目的。好了,废话不多说,大家直接看下文吧。mysql中函数的编写如下:create...
    99+
    2022-10-18
  • 如何在MySQL中使用JavaScript编写触发器
    在MySQL中使用JavaScript编写触发器并不支持,MySQL的触发器是使用SQL语言编写的。以下是创建触发器的基本语法:``...
    99+
    2023-10-10
    MySQL
  • 如何在MySQL中使用PHP编写触发器
    如何在MySQL中使用PHP编写触发器MySQL是一种常用的关系型数据库管理系统,而PHP是一种流行的服务器端脚本语言。在MySQL中使用PHP编写触发器可以帮助我们实现自动化的数据库操作。本文将介绍如何使用PHP来编写MySQL触发器,并...
    99+
    2023-10-22
    MySQL PHP 触发器
  • 如何在MySQL中使用C#编写存储过程
    如何在MySQL中使用C#编写存储过程在MySQL数据库中,存储过程是一组预定义的SQL语句,可以以一定的逻辑顺序组合成一个单元的程序。它可以用于简化和优化数据库操作,并提高应用程序的性能和安全性。C#是一种广泛使用的编程语言,具有强大的数...
    99+
    2023-10-22
    MySQL C# 存储过程
  • 如何在MySQL中使用Python编写存储过程
    标题:MySQL中使用Python编写存储过程的示例及实践指南在MySQL中使用存储过程可以有效地将复杂的数据库操作封装起来,提高数据库的执行效率和安全性。本文将介绍如何使用Python编写MySQL的存储过程,并提供具体的代码示例供参考。...
    99+
    2023-10-22
    Python MySQL 存储过程
  • 如何编写可重用的MySQL查询
    本篇内容主要讲解“如何编写可重用的MySQL查询”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何编写可重用的MySQL查询”吧! 当人们提及可重用的...
    99+
    2022-10-18
  • java中runtime.exec()如何编写
    这篇文章主要介绍java中runtime.exec()如何编写,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!那就首先说点Runtime类吧,他是一个与JVM运行时环境有关的类,这个类是Singleton的。我说几个自...
    99+
    2023-06-03
  • 如何在MySQL中使用C#编写自定义函数
    在MySQL中使用C#编写自定义函数需要以下步骤:1. 创建一个C#类库项目,并添加对MySQL.Data.dll的引用。2. 在C...
    99+
    2023-10-20
    MySQL
  • 如何在MySQL中使用Python编写自定义函数
    在MySQL中使用Python编写自定义函数可以通过以下步骤实现:1. 首先,需要安装MySQL的Python驱动程序。可以使用以下...
    99+
    2023-10-10
    MySQL
  • 如何在MySQL中使用JavaScript编写自定义函数
    如何在MySQL中使用JavaScript编写自定义函数MySQL是一个流行的关系型数据库管理系统,而JavaScript是一种广泛用于网页开发的脚本语言。尽管MySQL自带了许多内建函数,但有时我们可能需要编写自定义函数来满足特定的需求。...
    99+
    2023-10-22
    MySQL JavaScript 自定义函数
  • 如何编写Python CGI程序与MySQL交互?
    假设您想使用Python CGi脚本登录您的帐户,以下是详细信息 login.html <html> <body> <form action="login.py" method="get"&...
    99+
    2023-10-22
  • 技术分享 | 如何编写 MySQL Shell 插件
    作者:洪斌 爱可生南区负责人兼技术服务总监,MySQL  ACE,擅长数据库架构规划、故障诊断、性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融、运营商、互联网等行业客户提供 MySQL 整体解决方案。 本文来...
    99+
    2016-08-09
    技术分享 | 如何编写 MySQL Shell 插件
  • mysql中如何处理Plugin 'InnoDB' registration as a STORAGE ENGINE failed错误
    这篇文章主要为大家展示了“mysql中如何处理Plugin 'InnoDB' registration as a STORAGE ENGINE failed错误”,内容简而易懂,条理清晰,希...
    99+
    2022-10-18
  • 如何在MySQL中使用Python编写自定义触发器
    如何在MySQL中使用Python编写自定义触发器触发器是MySQL中的一种强大的功能,它可以在数据库中的表上定义一些自动执行的操作。而Python则是一种简洁而强大的编程语言,能够方便地与MySQL进行交互。本文将介绍如何使用Python...
    99+
    2023-10-22
    Python MySQL 触发器
  • vuex 中插件如何编写
    这篇文章将为大家详细讲解有关vuex 中插件如何编写,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、官方文档1、第一步const myPlugin ...
    99+
    2022-10-19
  • 如何在MySQL中使用JavaScript编写自定义存储引擎
    如何在MySQL中使用JavaScript编写自定义存储引擎介绍随着数据量和业务需求的增加,传统的关系型数据库已经无法满足全部的需求。此时,我们可以通过自定义存储引擎,根据特定的需求优化数据库的性能和功能。而MySQL提供了自定义存储引擎的...
    99+
    2023-10-22
    MySQL JavaScript 自定义存储引擎
  • 如何在MySQL中使用C#编写自定义存储引擎
    如何在MySQL中使用C#编写自定义存储引擎摘要:MySQL是一个流行的关系型数据库管理系统,提供了许多内置的存储引擎,诸如InnoDB、MyISAM等。然而,有时候我们需要自定义存储引擎来满足特定的需求。本文将介绍如何使用C#编写自定义存...
    99+
    2023-10-22
    MySQL C# 存储引擎
  • linux中如何编写shell脚本
    在Linux中,可以使用任何文本编辑器编写Shell脚本。以下是编写Shell脚本的一般步骤: 打开终端并创建一个新的文本文件,...
    99+
    2023-10-23
    linux shell
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作