28章扩展MySQL

目录

28.1 MySQL内部
28.1.1 MySQL线程
28.1.2 MySQL测试套件
28.2 mysql插件API
28.2.1类型的插件
28.2.2插件API特性
28.2.3零件插件API
28.2.4编写插件
28.3 MySQL服务插件
28.3.1锁定服务
28.3.2到此服务
28.4添加新的功能到MySQL
的用户定义的函数接口28.4.1特征
28.4.2添加一个新的用户定义的函数
28.4.3添加一个新的原生功能
调试和移植MySQL 28.5
28.5.1调试一个MySQL服务器
28.5.2调试MySQL客户端
28.5.3该包的

28.1 MySQL内部

本章介绍了很多的事情,你需要知道的关于MySQL的代码工作时。跟踪或有助于MySQL的开发,遵循指示第2.8.3,“安装MySQL使用开发源码树”。如果你在MySQL内部感兴趣,你也应该加入我们internals通讯名单该表具有相对较低的交通。有关如何订阅,请参阅第1.6.2,MySQL邮件列表”。在甲骨文公司很多MySQL开发者对internals清单,我们帮助其他有工作的人对MySQL的代码。可以使用此列表来问问题的代码和发送补丁,你愿意贡献MySQL项目!

笔记

MySQL的源代码包含内部文件写入使用Doxygen。本文档是有用的了解MySQL从开发者的角度是如何工作的。它的内容是在生成http://dev.mysql.com / DOC / dev / / /最新的MySQL服务器。它也可以从本地一个使用说明,在MySQL源分布生成的内容第2.8.7,“生成MySQL doxygen文档内容”

28.1.1 MySQL线程

MySQL服务器创建以下螺纹:

  • 连接管理器线程处理客户端连接请求的网络接口,服务器监听。在所有平台上,一个管理线程处理TCP/IP连接请求。在Unix上,这个管理线程也处理UNIX套接字文件的连接请求。在Windows中,管理线程处理共享内存连接请求,而另一个命名管道的连接请求的处理。服务器无法创建线程来处理接口,它听不到。例如,一个Windows服务器没有启用命名管道连接不支持创建一个线程来处理他们。

  • 连接管理器线程将每个客户端连接与一个线程专门给它处理身份验证请求处理该连接的。管理线程创建一个新线程需要时可尽量避免这样做咨询的线程缓存首先要看它是否包含一个线程可用于连接。当一个连接端,其线程如果缓存未满返回线程缓存。

    关于调整,控制线程的资源参数信息,看第8.12.4.1,“MySQL如何使用线程,客户端连接”

  • 在一个主复制服务器,从服务器连接的客户端的连接处理:如有一个线程每连接的奴隶。

  • 在从复制服务器,I/O线程开始连接到主服务器和从中读出更新。一个SQL线程开始申请更新从读硕士。这两个线程独立运行,可以独立启动和停止。

  • 一个信号线程处理所有信号。该线程通常处理报警电话process_alarm()给力,闲的时间太长了连接超时。

  • 如果InnoDB使用时,将有额外的读写线程的默认。一些这些受innodb_read_io_threadsinnodb_write_io_threads参数.看到15.13节,“InnoDB启动选项和系统变量”

  • 如果服务器开始的--flush_time=val选择,一个专门的线程被创建的所有表都冲洗val

  • 如果事件调度器是活跃的,有一个线程的调度,和每一个事件正在运行的线程。看到第23.4.1,“事件调度器概述”

mysqladmin processlist只有在连接、复制和传播方面。

28.1.2 MySQL测试套件

这包括在Unix源码和二进制分布测试系统可以让用户和开发者对MySQL的代码执行回归测试。这些测试可以运行在UNIX。

你也可以自己写测试用例。关于MySQL的测试框架的信息,包括系统要求,请参阅手册可在http:/ / / / / dev.mysql.com DOC / mysqltest 2.0

测试用例的电流设定不测试所有的MySQL,但应该在SQL处理代码捕捉最明显的错误,操作系统或库的问题,是相当彻底的测试复制。我们的目标是要测试的代码覆盖率为100。我们欢迎您到我们的测试套件的贡献。你可能特别想有助于检查你的系统功能的关键因为这确保未来所有的MySQL版本的工作以及与您的应用程序。

该测试系统由测试语言解释器(MySqlTest),的Perl脚本的运行所有的测试(mysql-test-run.pl),实际测试的情况写在一个特殊的测试语言,和预期的结果。在一个建立在您的系统上运行测试套件,型做试验从源的根目录,或改变位置的mysql-test目录和类型mysql-test-run.pl。/。如果你已经安装了一个二进制分布位置的变化mysql-test安装根目录下的目录(例如,/usr/local MySQL和MySQL测试),并运行mysql-test-run.pl。/。所有的试验成功。如果不这样做,随时找出原因,并报告问题,如果它表明mysql的bug。看到7节,“如何报告错误或问题”

如果测试失败,你应该运行mysql-test-run.pl--force选项来检查是否其他任何测试失败。

如果你有一个副本mysqld运行在本机的地方你想运行测试套件,你没有去阻止它,只要它不使用的端口9306九千三百零七。如果这些端口,你应该设置MTR_BUILD_THREAD环境变量到一个适当的值,和测试套件将使用一套不同的奴隶主,港口,和NDB)。例如:

shell> export MTR_BUILD_THREAD=31shell> ./mysql-test-run.pl [options] [test_name]

mysql-test目录,您可以运行一个单独的测试用例mysql-test-run.pl。/test_name

如果你有一个关于测试的问题,或有一个测试案例的贡献,发送电子邮件至MySQLinternals通讯名单看到第1.6.2,MySQL邮件列表”

28.2 mysql插件API

MySQL支持插件API,使服务器组件创作。插件可以在服务器启动时加载的加载和卸载,或者在运行时无需重新启动服务器。API是通用的,没有具体说明哪些插件可以做。该组件支持的接口包括,但不限于,存储引擎,全文解析插件和服务器扩展。

例如,全文解析插件可以用来替换或增加内置全文解析。插件可以解析文本使用不同于那些由内置分析器使用规则的话。这可能是有用的如果你需要解析文本,不同于那些期望通过内置分析器的特点。

插件的接口比年长的用户自定义函数(UDF)接口一般。

插件界面使用plugin表中MySQL数据库记录已被永久安装的插件信息INSTALL PLUGIN声明。本表中创建MySQL的安装过程的一部分。插件也可以安装一个单一的服务器调用——插件加载选项插件安装这样不记录在plugin表看到第5.6.1,“安装和卸载插件”

MySQL支持服务器插件除了客户端插件API。这是使用,例如,在服务器端验证插件插件和客户端插件的合作,使客户能够通过多种认证方式连接到服务器。

笔记

MySQL的源代码包含内部文件写入使用Doxygen。本文档是有用的了解MySQL从开发者的角度是如何工作的。它的内容是在生成http://dev.mysql.com / DOC / dev / / /最新的MySQL服务器。它也可以从本地一个使用说明,在MySQL源分布生成的内容第2.8.7,“生成MySQL doxygen文档内容”

额外资源

这本书MySQL 5.1插件开发由Sergei Golubchik和Andrew Hutchings提供了丰富的细节,关于插件的API。尽管这本书的标题指的是MySQL服务器也在它的大多数信息适用于以后的版本以及。

28.2.1类型的插件

插件API可以实现多种功能的插件创建:

以下各节提供了这些插件类型概述。

存储引擎插件

通过MySQL服务器使用插入式存储引擎架构,使存储引擎要写成插件装入和卸载运行的服务器。为了描述这个建筑,看到16.11部分,概述MySQL存储引擎体系结构”

有关如何使用插件的API编写的存储引擎,看MySQL内核:编写一个自定义的存储引擎

全文解析插件

MySQL有一个内置的解析器,它使用的默认全文操作(解析文本进行索引,或解析查询字符串来确定术语被用于搜索)。内置支持全文解析InnoDBMyISAM

MySQL也有一个基于字符的N-gram全文解析器支持中国、日本、韩国(CJK),和基于词的mecab解析器插件,支持日本,使用InnoDBMyISAM

全文处理,解析方法提取的话(或令牌,在语言特征的基于案例的解析器)从文本或查询字符串基于规则定义的字符序列组成一个单词,单词边界。

当解析为索引的目的,解析器每个单词传递到服务器,并把它添加到全文索引。当解析查询字符串解析器每个单词传递到服务器,积累了用于搜索的词。

解析性能内置了全文解析12.9节,“全文搜索功能”。这些属性包括规则确定如何从文本中提取关键字。解析器是通过某些系统变量的原因的话,或长或短的被排除在外的影响,并通过停用词表,确定常用词被忽略。有关更多信息,参见第12.9.4,“全文构建”,和第12.9.6,“微调MySQL全文搜索”

插件API允许您使用全文解析非默认内置的全文解析。例如,如果你正在与日本,你可以选择使用mecab全文解析。插件API也可以提供您自己的全文的解释器,你在一个解析器的基本职责控制。一个解析器插件可以在两个角色的操作:

  • 该插件可以取代内置的解析器。在这个角色中,插件读取被解析的输入,它分割成单词,并将单词到服务器(或者索引或令牌积累)。词频统计和mecab解析器作为替代内置的全文解析。

    你可以选择提供自己的全文解析如果你需要使用不同的规则与内置的解析器,用于确定如何拆分输入文字。例如,内置的解析器认为文本区分大小写由两个字案例敏感,而一个应用程序可能需要处理的文本作为一个字。

  • 该插件可以在内置的解析器一起作为前端它。在这个角色中,插件提取文本的输入,通过解析文本,将文本语言的使用正常的解析规则。这一分析的影响innodb_ft_xxx_ FTxxx系统变量和停用词列表。

    一个理由使用解析器这样是你需要的指标内容,如PDF文件,XML文件,或.doc文件内置的解析器是不打算为这些类型的输入,但是插件可以把文本从这些输入源,通过它内置的剖析。

一个解析器插件在角色操作也是可能的。就是说,它可以提取noncleartext输入文本(前端的作用),并解析文本的话(从而取代内置的解析器)。

全文插件是对每一个指标的基础上全文索引相关。那就是,当你安装一个解析器插件最初,不使它被用于任何全文操作。它只是变得可用。例如,一个全文解析插件就可以在一个名为WITH PARSER当创建个人条款全文指标。在创建表时创建索引,这样做:

CREATE TABLE t
(
  doc CHAR(255),
  FULLTEXT INDEX (doc) WITH PARSER parser_name
) ENGINE=InnoDB;

或者你可以创建表后添加索引:

ALTER TABLE t ADD FULLTEXT INDEX (doc) WITH PARSER parser_name;

关联分析器与指数的变化是唯一的SQLWITH PARSER条款.搜索指定为前,无需任何修改查询。

当你把一个解析器插件和一个FULLTEXT指数,插件使用的指标要求。如果解析器插件是下降的,与它相关的任何指标都不可用。任何试图使用一个表,一个插件是不是一个错误的结果,虽然DROP TABLE仍然有可能

有关全文插件的更多信息,参见第28.2.4.4,“写满文本解析器插件”。MySQL 8的支持全文插件MyISAMInnoDB

后台的插件

一个守护进程插件是一个简单的用于代码的插件,应该由服务器运行但不与它沟通。MySQL分布包括例程序插件,写周期性的心跳消息发送到一个文件。

关于后台插件的更多信息,参见第28.2.4.5,“写作进程插件”

information_schema插件

INFORMATION_SCHEMA插件使包含服务器的元数据,通过暴露给用户创建表information_schema数据库例如,InnoDB使用information_schema插件提供了包含当前事务和锁的信息表。

为更多的信息关于INFORMATION_SCHEMA插件,看第28.2.4.6,“写作information_schema插件”

半同步复制插件

MySQL默认是异步复制。半同步复制,提交在主侧块后回到会议进行交易,直到至少一个奴隶确认已经收到并记录交易活动的表演。半同步复制的实现通过互补主客户端插件。看到第17.3.10,“半同步复制”

关于半同步复制插件的更多信息,参见第28.2.4.7”写作,半同步复制插件”

审计插件

MySQL服务器提供了一个可插拔的审计接口,使有关服务器操作信息被报告给利害关系人。审计通知发生这些操作(虽然界面一般服务器可以修改报告的人):

  • 写一个信息通用查询日志(如果日志启用)

  • 消息写入错误日志

  • 发送一个查询结果给客户端

审计插件可能与审计接口接收有关服务器操作通知登记。当一个审计事件发生在服务器端,服务器确定是否需要通知。每个注册审计插件,服务器检查对这些事件类的插件感兴趣,把事件传递给插件,如果有一个匹配的事件。

这个接口使审计插件接收通知只有在他们认为重要的事件类的操作,忽略其他。该接口提供了分类的业务分为事件类、事件类进一步划分为每个类别中。

当一个审计插件是通知的审核事件,它接收一个指向电流的THD的结构和结构的指针,包含有关事件的信息。该插件可以检查事件和执行任何审计行为是适当的。例如,该插件可以看到语句生成的结果集或被记录,在结果的行数,而当前用户是一个操作,或错误代码失败的操作。

关于审计插件的更多信息,参见第28.2.4.8,“写作审计插件”

身份验证插件

MySQL支持可插拔认证。身份验证插件存在在服务器端和客户端。插件在服务器端执行身份验证方法使用的客户,当他们连接到服务器。在客户端与服务器端插件插件提供的认证信息,它需要沟通。一个客户端插件可以与用户交互,完成任务,如索取密码或其他身份验证凭据发送到服务器。看到第6.3.10,“认证”

可插拔认证也使代理用户的能力,其中一个用户以其他用户的身份。一个服务器端的身份验证插件可以返回到服务器的用户连接的用户应该有其身份的名字。看到第6.3.11”代理用户”

有关身份验证插件的更多信息,参见第28.2.4.9,“写作认证插件”

密码验证插件

MySQL服务器编写插件,测试密码提供了一个接口。这样的一个插件,实现了两个功能:

有关编写这类插件的信息,参见第28.2.4.10,“写作密码验证插件”

协议跟踪插件

MySQL支持协议跟踪插件使用:客户端插件,实现了一个客户端,利用客户端/服务器协议的服务器之间的通信跟踪。

有关协议跟踪插件的更多信息,参见第28.2.4.11,“书面协议跟踪插件”

查询重写插件

MySQL服务器支持查询重写插件,可以查看和修改服务器接收到服务器执行他们之前的声明。查询重写插件以之前或之后,服务器解析他们的陈述。

一个preparse查询重写插件具有这些特点:

  • 插件使SQL语句到服务器在服务器处理重写。

  • 插件接收字符串的声明和可能返回不同的字符串。

一个postparse查询重写插件具有这些特点:

  • 该插件允许声明基于解析树重写。

  • 服务器解析每个语句,通过解析树的插件,它可以遍历树。该插件可以返回原树到服务器进行进一步的处理,或构建一个不同的树,而不是回报。

  • 插件可以使用mysql_parser为了这些目的的插件服务:

    • 激活声明摘要计算得到归一化版本声明独立的性能是否产生消化模式。

    • 遍历语法树

    • 分析报表。如果插件构建解析树的新声明字符串,这是有用的。这个插件可以让服务器解析产生一个新的树的字符串,然后返回那棵树一样的重写声明表示。

关于插件服务的更多信息,参见28.3节,“MySQL服务插件”

preparse和postparse查询重写插件共享这些特性:

  • 如果安装了查询重写插件的--log-raw选项影响语句记录如下:

    • 没有--log-raw,服务器日志中的语句返回的查询重写插件。这可能与声明收到。

    • --log-raw原来,服务器日志语句接收。

  • 如果一个插件重写声明,服务器决定是否将它写入二进制日志(因此任何复制奴隶)基于重写声明,不声明原文。如果一个插件改写了只有SELECT报表SELECT报表,在二进制日志没有影响,因为服务器不写SELECT报表的二进制日志

  • 如果一个插件重写声明,服务器产生一个Note消息,客户端可以使用SHOW WARNINGS。信息格式,在stmt_in是原来的声明stmt_out是改写的声明:

    查询”stmt_in“重写”stmt_out“通过查询重写插件

MySQL分布包括了postparse查询重写插件命名Rewriter。这个插件是基于规则。你可以添加行的规则表原因SELECT语句改写。有关更多信息,参见5.6.4节,“重写查询重写插件”

查询重写插件使用相同的API审核插件。关于审计插件的更多信息,参见第28.2.4.8,“写作审计插件”

钥匙圈的插件

MySQL服务器支持的钥匙圈的插件,使内部服务器组件和插件来安全地存储敏感信息供以后检索。

所有MySQL分布包括一个钥匙圈插件命名keyring_file。MySQL企业版分布包括额外的钥匙环插件。看到第6.5.4,“MySQL的钥匙”

关于钥匙的插件的更多信息,参见第28.2.4.12,“写作钥匙插件”

28.2.2插件API特性

服务器插件API具有这些特点:

  • 所有的插件都有几个共同的东西。

    每个插件都有一个名字,它可以被称为SQL语句,以及其他的元数据,如作者和描述,提供其他信息。这个信息可以检查的INFORMATION_SCHEMA.PLUGINS表或使用SHOW PLUGINS声明

  • 插件框架扩展到容纳不同类型的插件。

    虽然某些方面的插件API对所有类型的插件,API还允许特定类型的界面元素,不同类型的插件可以创建。有一个目的的插件可以有一个接口最合适自己的要求而不是其他的插件式的要求。

    对几种类型的接口插件存在,如存储引擎、全文解析器,和INFORMATION_SCHEMA表。others can be added。

  • 插件可以让用户的信息。

    插件可以实现系统状态变量,可通过SHOW VARIABLESSHOW STATUS声明.

  • 插件API包含版本信息。

    包含在插件版本信息API允许插件库,每个插件,它包含要自我认同方面的API的版本,用于建图书馆。如果随着时间的推移,API的变化,版本号会改变,但服务器可以检查一个给定的插件库的版本信息来确定它是否支持库中的插件。

    有两种类型的版本号。第一个是一般的插件框架本身的版本。每个插件库包括这种版本号。版本二型适用于单独的插件。每个特定类型的插件有一个接口的版本,所以在图书馆每个插件都有一个特定类型的版本号。例如,一个库包含全文解析插件有一个大致的插件API的版本号,和插件版本号具体到全文插件接口。

  • 插件API实现了安全限制。

    一个插件库必须安装在一个专用的目录位置是由服务器和不能控制是在运行时改变。同时,图书馆必须包含特定的符号,把它作为一个插件库。服务器将不加载一些插件,如果不建立一个插件。

  • 插件可以访问服务器服务。

    服务接口提供服务器功能的插件可以使用普通的函数调用。详情见28.3节,“MySQL服务插件”

在某些方面,API类似于年长的用户自定义函数(UDF)服务器插件API,它取代,但插件API在旧的接口的几个优点。例如,UDFs没有版本信息。同时,新的插件接口消除了旧的UDF接口的安全问题。写nonplugin老接口UDF允许图书馆可以从任何目录搜索系统的动态链接装入,并确定了UDF库符号是相对非特异性的。

客户端插件API有类似建筑的特点,但客户端插件没有直接访问服务器的服务器插件做的方式。

28.2.3零件插件API

服务器插件的具体实现包括几个组件。

SQL语句:

  • INSTALL PLUGIN寄存器中的一个插件mysql.plugin表和加载插件代码

  • UNINSTALL PLUGIN注册一个插件从mysql.plugin表和卸载插件代码

  • 这个WITH PARSER全文索引创建条款将全文解析插件与一个给定的全文指数

  • SHOW PLUGINS显示有关服务器的插件信息。

命令行选项和系统变量:

关于插件加载的更多信息,参见第5.6.1,“安装和卸载插件”

插件相关表:

  • 这个INFORMATION_SCHEMA.PLUGINS表包含插件的信息

  • 这个mysql.plugin表中列出的每个插件,安装INSTALL PLUGIN是插件的使用要求。新的MySQL的安装,这是安装过程中创建表。

客户端插件实现简单:

  • 对于mysql_options()C API函数的_ _ auth mysql默认MYSQL_PLUGIN_DIR可供选择的客户端程序来为“负载”认证。

  • 有C API函数,使客户端插件管理。

检查MySQL如何实现插件,参考以下在MySQL源分布的源文件:

  • include/mysql目录,H的插件暴露出公共插件API。这个文件应该由谁想写一个插件库研究。plugin_xxx.h文件提供额外的信息有关的特定类型的插件。_ plugin.h客户端集装箱信息特异性客户端。

  • sql目录,SQL _ plugin.hsql_plugin.cc包括内部插件的实现SQL _ acl.cc在服务器使用的身份验证插件。这些文件不需要的插件开发人员参考。他们可能对那些想知道更多关于服务器如何处理插件感兴趣。

  • sql-common目录,_ plugin.h客户端在客户端功能的应用client.c实现了客户端身份验证支持。这些文件不需要的插件开发人员参考。他们可能对那些想知道更多关于服务器如何处理插件感兴趣。

28.2.4编写插件

创建一个插件库,您必须提供所需的描述符信息显示库文件包含哪些插件,并为每个插件编写接口功能。

每个服务器插件必须有一个大致的描述,以插件的API提供的信息,和一个特定类型的描述符提供关于一个给定类型的插件接口信息。的一般描述的结构是所有插件类型相同。特定类型的描述符的结构不同的插件类型和用什么插件需要做决定的要求。服务器插件接口还允许插件暴露状态变量和系统变量。这些变量是可见的SHOW STATUSSHOW VARIABLES报表及相应的information_schema

客户端插件的体系结构是一个有点不同。每个插件都必须有一个描述符,但没有分裂成独立的通用和特定类型的描述符。相反,描述从一组固定的成员共同所有客户端插件类型,和普通成员之后,需要实现特定的插件式的任何其他成员。

你可以写在C或C插件(或另一种语言,可以使用C调用约定)。插件是动态地加载和卸载,所以你的操作系统必须支持动态加载,你必须编写调用应用程序的动态(静态)。服务器插件,这意味着mysqld必须与动态

一个服务器插件包含代码,成为正在运行的服务器的一部分,所以当你写的插件,你的任何及所有的约束,否则申请写服务器代码绑定。例如,您可能在您尝试使用的功能从有问题libstdc++图书馆这些限制可能在未来版本的服务器,因此服务器升级将需要修改原来的老服务器编写插件。有关这些限制的信息,参见2.8.4”部分,MySQL源配置选项”,和第2,“处理编译MySQL”问题

客户端插件的作家应该避免在调用应用程序有什么符号的依赖因为你无法确定哪些应用程序将使用插件。

28.2.4.1插件写作概述

下面的过程提供了需要创建一个插件库的步骤概述。下一节提供设置插件数据结构写插件的具体类型的更多细节。

  1. 在插件的源文件,包含头文件,插件库的需求。这个plugin.h文件是必需的,而图书馆可能需要其他文件以及。例如:

    #include <stdlib.h>#include <ctype.h>#include <mysql/plugin.h>
  2. 对于插件库文件设置描述符信息。服务器插件,写库描述符,它必须包含在文件中为每个服务器插件一般插件描述符。有关更多信息,参见第28.2.4.2.1”图书馆和服务器插件,插件参数”。此外,在图书馆设置为每个服务器插件的特定类型的描述符。每个插件的通用描述符指向该特定类型的描述符。

    客户端插件,编写客户端描述符。有关更多信息,参见第28.2.4.2.3,“客户端插件描述符”

  3. 每一个插件的插件接口函数的编写。例如,每个插件的插件描述符指向初始化和deinitialization,服务器应该调用时加载和卸载插件功能。插件式的具体描述也可能指向接口功能。

  4. 服务器插件,建立系统的状态变量,如果有任何。

  5. 编译插件库作为共享库并将其安装在插件目录。有关更多信息,参见第28.2.4.3,编译和安装插件库”

  6. 服务器插件,插件与服务器登记。有关更多信息,参见第5.6.1,“安装和卸载插件”

  7. 测试插件来验证它的正确。

28.2.4.2插件数据结构

一个插件库文件包括描述符信息表明它含有什么插件。

如果插件库包含任何服务器插件,它必须包含以下的描述信息:

  • 一个库描述符指示一般服务器插件API版本号所使用的库,包含库中的每个服务器插件一般插件描述符。为这个广义的框架,从两宏调用plugin.h头文件:

    MySQL _宣布(_插件name... one or more server plugin descriptors here ...MySQL _声明_插件_结局;

    宏扩展到自动提供的API版本声明。你必须提供插件描述符。

  • 图书馆内的描述符,每个通用服务器插件的描述st_mysql_plugin结构。这个插件描述符结构包含对服务器插件每型公共信息:值显示插件式;插件名称、作者、描述、和证型;以初始化和deinitialization功能,服务器调用时加载和卸载插件指针和指针的任何状态或系统变量插件实现。

  • 每个通用服务器插件描述符在库描述符还包含一个指针指向特定类型的插件描述符。特定类型的描述符的结构变化从一个到另一个插件式因为每个类型的插件可以有它自己的API。一个特定类型的插件描述符包含一个特定类型的API的版本号和指针所需要的插件式功能的实现。例如,一个全文解析插件的初始化和deinitialization功能,和一个主要的解析函数。服务器调用这些函数时,它使用插件来解析文本。

插件库还包含的一般和特定类型的描述符,每个插件库中引用的函数接口。

如果插件库包含一个客户端插件,它必须包括一个插件描述符。描述从一组固定的成员共同所有的客户端插件,其次是任何成员特定的插件式。提供描述框架,从两宏调用client_plugin.h头文件:

MySQL客户端插件(_宣布_ _plugin_type)…members common to all client plugins……type-specific extra members...mysql _ _ _端客户端插件;

此外,书店还包括由客户描述的任何界面功能。

这个mysql_declare_plugin()MySQL客户端_宣布_ _(插件)宏有所不同在他们如何被调用,为插件库内容的影响。以下指南总结规律:

  • mysql_declare_plugin()MySQL客户端_宣布_ _(插件)可以用在同一个源文件中,这意味着一个插件库可以包含服务器端和客户端插件。然而,每个mysql_declare_plugin()MySQL客户端_宣布_ _(插件)可以用在最一次

  • mysql_declare_plugin()允许多个服务器插件的声明,这样插件库可以包含多个服务器插件。

  • mysql_declare_client_plugin()只允许一个客户端插件声明。创建多个客户端插件,插件必须使用单独的图书馆。

当一个客户端程序查找客户端插件,在插件库没有建成libmysqlclient,看起来一个是作为插件的名称相同的基名称的文件。例如,如果一个程序需要使用客户端身份验证插件命名欧美一个系统,使用.so作为图书馆的后缀,它看起来在命名文件auth_xxx.so。(在OS X上,程序首先会auth_xxx.dylib,然后auth_xxx.so。)因此,如果一个插件库包含一个客户端插件,图书馆必须有相同的基本名称,插件。

同样是不正确的一个库,包含服务器插件。这个--plugin-load选择和INSTALL PLUGIN声明提供的库文件的名称明确,所以需要有图书馆的名字和任何服务器插件,它包含的名称之间没有明确的关系。

28.2.4.2.1服务器插件库和插件描述符

每一个插件库,包含服务器插件必须包括一个图书馆描述符包含文件中的每个服务器插件一般插件描述符。本节讨论如何为服务器插件写的图书和一般描述。

图书馆的描述符必须定义两个符号:

  • _mysql_plugin_interface_version_指定的插件框架的版本号。这是由我的意思是,我的意思是。的象征,它是定义在plugin.h文件

  • _mysql_plugin_declarations_定义了插件的声明一个数组,被设置为0的所有成员声明终止。每个声明的实例st_mysql_plugin结构(定义在plugin.h)。必须有库中每个服务器的一个插件。

如果服务器不在图书馆找到这两个符号,它不接受它作为一个合法的插件库,拒绝一个错误。这可以防止使用一个插件的目的,除非它是专门图书馆作为一个插件库的建立。

定义两个符号的传统方法是通过使用mysql_declare_plugin()MySQL _宣布_ _端插件宏从plugin.h文件:

MySQL _宣布(_插件name... one or more server plugin descriptors here ...MySQL _声明_插件_结局;

每个服务器插件必须有一个大致的描述,提供信息的服务器插件API。一般描述为所有插件类型相同的结构。这个st_mysql_plugin结构中的H的插件文件定义描述符:

struct st_mysql_plugin
{
  int type;             /* the plugin type (a MYSQL_XXX_PLUGIN value)   */
  void *info;           /* pointer to type-specific plugin descriptor   */
  const char *name;     /* plugin name                                  */
  const char *author;   /* plugin author (for I_S.PLUGINS)              */
  const char *descr;    /* general descriptive text (for I_S.PLUGINS)   */
  int license;          /* the plugin license (PLUGIN_LICENSE_XXX)      */
  int (*init)(void *);  /* the function to invoke when plugin is loaded */
  int (*deinit)(void *);/* the function to invoke when plugin is unloaded */
  unsigned int version; /* plugin version (for I_S.PLUGINS)             */
  struct st_mysql_show_var *status_vars;
  struct st_mysql_sys_var **system_vars;
  void * __reserved1;   /* reserved for dependency checking             */
  unsigned long flags;  /* flags for plugin */
};

这个st_mysql_plugin描述符结构构件应用如下。char *成员国应指定为零终止字符串。

  • type插件式。这必须是一个插件式值H的插件

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

    例如,为全文解析插件的typeMySQL _ ftparser _插件

  • info:一个指向特定类型的描述符的插件。该描述符的结构取决于插件的特定类型,不像一般的插件描述符结构。版本控制的目的,每个插件类型的特定类型的描述符的第一个成员预计将该类型的接口版本。这使得服务器检查每一个插件的特定类型版本无论其类型。以下版本号,该描述符包括任何其他成员的需要,如服务器需要调用插件正常回调函数等信息。后面的章节写服务器插件特定类型描述他们的特定类型的描述符的结构。

  • name:一个字符串,给出了插件的名称。这个名称会被列在mysql.plugin表和你所指的是在SQL语句等插件INSTALL PLUGINUNINSTALL PLUGIN,或与--plugin-load选项名称中也可见INFORMATION_SCHEMA.PLUGINS表或输出SHOW PLUGINS

    插件的名称不应该从任何服务器选项的名称。如果是这样,服务器将无法初始化。例如,服务器有--socket选项,那么你不应该使用一个插件的名称,如插座socket_plugin,等等

  • author:一个字符串命名插件作者。这可以是任何你喜欢的。

  • desc:一个字符串,提供插件的一般描述。这可以是任何你喜欢的。

  • license插件:许可证的人。一个多月以前评论_ license _专有插件PLUGIN_LICENSE_GPL,或_插件_ BSD license

  • init:只有一次的初始化函数,或无效的如果没有这样的功能。服务器执行此功能时,它加载的插件,它的发生INSTALL PLUGIN或者,对于上市的插件mysql.plugin表,在服务器启动。该函数接受一个参数指用来识别插件的内部结构。它返回非零的零成功和失败。

  • deinit:只有一次的deinitialization功能,或无效的如果没有这样的功能。服务器执行这个函数当它卸载插件,它会UNINSTALL PLUGIN或者,对于上市的插件mysql.plugin表,在服务器关闭。该函数接受一个参数指用来识别它返回成功和失败的非零的零插件的内部结构。

  • version插件的版本号。当插件安装,此值可从INFORMATION_SCHEMA.PLUGINS表价值包括主要和次要的数。如果你写的值作为一个十六进制常数,格式是0xMMNN,在那里MM神经网络是主要和次要的号码,分别。例如,0x0302代表3.2版

  • status_vars:一个指针的结构状态变量与插件相关的,或无效的如果没有这样的变量。当插件安装,这些变量在输出显示SHOW STATUS声明

    这个status_vars如果不是会员,无效的指向一个数组,st_mysql_show_var描述状态变量结构。看到第28.2.4.2.2,“服务器插件状态变量和系统变量”

  • system_vars:一个指针指向一个结构变量与系统相关的插件,或无效的如果没有这样的变量。这些选项和系统变量可以在插件初始化变量。当插件安装,这些变量在输出显示SHOW VARIABLES声明

    这个system_vars如果不是会员,无效的指向一个数组,st_mysql_sys_var描述系统变量结构。看到第28.2.4.2.2,“服务器插件状态变量和系统变量”

  • __reserved1:一个未来的占位符。它应该被设置为无效的

  • flags国旗:插件。单个的位对应不同的旗帜。该值应设置为或适用的旗帜。这些旗子是可用的:

    #定义plugin_opt_no_install 1ul / * * /不可动态加载的#定义plugin_opt_no_uninstall 2ul / *不* /动态卸载

    PLUGIN_OPT_NO_INSTALL表明该插件不能在运行时的负载INSTALL PLUGIN声明。这是适当的插件,必须在服务器启动时加载--plugin-load选项plugin_opt_no_uninstall表明该插件无法卸载运行时的UNINSTALL PLUGIN声明

服务器调用initdeinit函数在一般插件描述符时,加载和卸载插件。他们没有任何使用的插件,如当一个SQL语句导致插件被调用。

例如,广义信息库包含一个全文解析插件命名simple_parser看起来像这样:

mysql_declare_plugin(ftexample){ mysql_ftparser_plugin,/ *型* / / * * / simple_parser_descriptor,描述“simple_parser”/名字/甲骨文公司/ * * /”,作者简单的文本解析器”,/ *说明* / plugin_license_gpl,/ *插件许可*/ /*初始化函数simple_parser_plugin_init,(当加载)* / / * simple_parser_plugin_deinit,deinit功能(空载时)* / / * * /版本端口,simple_status,/ * * / simple_system_variables状态变量,系统变量/ * * /空,0 } mysql_declare_plugin_end;

为全文解析插件的类型必须MYSQL_FTPARSER_PLUGIN。这是识别插件作为法律中使用的价值与解析当创建一个条款FULLTEXT指数(没有其他的插件式是合法的这一条款。)

plugin.h定义MySQL _宣布_(插件)mysql_declare_plugin_end这样的宏:

#ifndef MYSQL_DYNAMIC_PLUGIN#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \MYSQL_PLUGIN_EXPORT int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION; \MYSQL_PLUGIN_EXPORT int PSIZE= sizeof(struct st_mysql_plugin); \MYSQL_PLUGIN_EXPORT struct st_mysql_plugin DECLS[]= {#else#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]= {#endif#define mysql_declare_plugin(NAME) \__MYSQL_DECLARE_PLUGIN(NAME, \                 builtin_ ## NAME ## _plugin_interface_version, \                 builtin_ ## NAME ## _sizeof_struct_st_plugin, \                 builtin_ ## NAME ## _plugin)#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0,0}}
笔记

这些声明定义_mysql_plugin_interface_version_符号只有mysql_dynamic_plugin符号定义。这意味着,-DMYSQL_DYNAMIC_PLUGIN必须提供的编译命令的一部分建立插件作为一个共享库。

当宏作为上面,他们扩大到下面的代码,它定义了所需的符号(_mysql_plugin_interface_version__ MySQL以_ _ _插件):

int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION;
int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin);
struct st_mysql_plugin _mysql_plugin_declarations_[]= {
{
  MYSQL_FTPARSER_PLUGIN,      /* type                            */
  &simple_parser_descriptor,  /* descriptor                      */
  "simple_parser",            /* name                            */
  "Oracle Corporation",       /* author                          */
  "Simple Full-Text Parser",  /* description                     */
  PLUGIN_LICENSE_GPL,         /* plugin license                  */
  simple_parser_plugin_init,  /* init function (when loaded)     */
  simple_parser_plugin_deinit,/* deinit function (when unloaded) */
  0x0001,                     /* version                         */
  simple_status,              /* status variables                */
  simple_system_variables,    /* system variables                */
  NULL,
  0
}
  ,{0,0,0,0,0,0,0,0,0,0,0,0}}
};

前面的示例声明的一般描述一个插件,但可以声明多个插件。列表的声明一个接一个的mysql_declare_plugin()MySQL _宣布_ _端插件通过commas,分隔。

MySQL服务器插件可以使用C或C(或另一种语言,可以使用C调用约定)。如果你写一个C的插件,一个C的功能,你不应该使用恒定的变量初始化的全局结构。等建筑构件st_mysql_plugin结构应该只有常数变量初始化。这个简单的描述符出现早在C插件允许因为它满足要求:

mysql_declare_plugin(ftexample)
{
  MYSQL_FTPARSER_PLUGIN,      /* type                            */
  &simple_parser_descriptor,  /* descriptor                      */
  "simple_parser",            /* name                            */
  "Oracle Corporation",       /* author                          */
  "Simple Full-Text Parser",  /* description                     */
  PLUGIN_LICENSE_GPL,         /* plugin license                  */
  simple_parser_plugin_init,  /* init function (when loaded)     */
  simple_parser_plugin_deinit,/* deinit function (when unloaded) */
  0x0001,                     /* version                         */
  simple_status,              /* status variables                */
  simple_system_variables,    /* system variables                */
  NULL,
  0
}
mysql_declare_plugin_end;

这里是另一个写的一般描述的有效方法。它采用恒定的变量显示插件名称、作者、和描述:

const char *simple_parser_name = "simple_parser";
const char *simple_parser_author = "Oracle Corporation";
const char *simple_parser_description = "Simple Full-Text Parser";

mysql_declare_plugin(ftexample)
{
  MYSQL_FTPARSER_PLUGIN,      /* type                            */
  &simple_parser_descriptor,  /* descriptor                      */
  simple_parser_name,         /* name                            */
  simple_parser_author,       /* author                          */
  simple_parser_description,  /* description                     */
  PLUGIN_LICENSE_GPL,         /* plugin license                  */
  simple_parser_plugin_init,  /* init function (when loaded)     */
  simple_parser_plugin_deinit,/* deinit function (when unloaded) */
  0x0001,                     /* version                         */
  simple_status,              /* status variables                */
  simple_system_variables,    /* system variables                */
  NULL,
  0
}
mysql_declare_plugin_end;

然而,以下通用描述符无效。它采用结构成员显示插件名称、作者、和描述,但结构不考虑常数初始化:

typedef struct
{
  const char *name;
  const char *author;
  const char *description;
} plugin_info;

plugin_info parser_info = {
  "simple_parser",
  "Oracle Corporation",
  "Simple Full-Text Parser"
};

mysql_declare_plugin(ftexample)
{
  MYSQL_FTPARSER_PLUGIN,      /* type                            */
  &simple_parser_descriptor,  /* descriptor                      */
  parser_info.name,           /* name                            */
  parser_info.author,         /* author                          */
  parser_info.description,    /* description                     */
  PLUGIN_LICENSE_GPL,         /* plugin license                  */
  simple_parser_plugin_init,  /* init function (when loaded)     */
  simple_parser_plugin_deinit,/* deinit function (when unloaded) */
  0x0001,                     /* version                         */
  simple_status,              /* status variables                */
  simple_system_variables,    /* system variables                */
  NULL,
  0
}
mysql_declare_plugin_end;
28.2.4.2.2服务器插件的状态变量和系统变量

服务器插件接口使插件暴露状态变量和系统变量的使用status_vars系统的_普通的钢笔将军

这个status_varsmember of the General插件描述符,if not to an array of 0点圣_ _ _是MySQL的表演结构,其中每一个状态变量的描述,其次是一个设置为所有成员结构。这个st_mysql_show_var结构定义:

struct圣_ MySQL _是教育节目_ { char * name;char *枚举枚举值;_ MySQL _秀_型;};

下表显示了允许的状态变量type值和对应的变量应该是什么。

表28.1服务器插件状态变量类型

变量类型意义
SHOW_BOOL一个布尔变量的指针
SHOW_INT一个整数变量的指针
SHOW_LONG一个长整型变量的指针
SHOW_LONGLONG在龙龙的整型变量的指针
SHOW_CHAR一个字符串
SHOW_CHAR_PTR一个字符串的指针
SHOW_ARRAY到另一个指针st_mysql_show_var阵列
SHOW_FUNC一个函数指针
SHOW_DOUBLE一种双指针

对于SHOW_FUNC类型、函数调用和填补它外面的参数,从而提供了可变信息显示。这个签名功能:

#define SHOW_VAR_FUNC_BUFF_SIZE 1024

typedef int (*mysql_show_var_func) (void *thd,
                                    struct st_mysql_show_var *out,
                                    char *buf);

这个system_vars的成员,如果不是0,指向一个数组圣_ MySQL是_ _缝合的结构,分别描述了系统变量(也可以从命令行或配置文件),其次是设置为0的所有成员结构。这个st_mysql_sys_var结构定义如下:

STRT St MySQL MySQL MySQL Sys Sys Le Var { int Flags;Const Char * Name,* E(* check)(thd *,斯特拉斯(* * check)(thd *,斯特拉斯(* * check)(thd *,斯特拉斯(* * Check)(Var Var Var Var * Var Var * Var Var * Var);void(* update)(thd *,斯特拉斯- MysQL Mysql Sys Var Var(Var),void *,Const Vod *);};}

额外的字段添加的要求取决于标志。

为方便起见,有一些宏定义,使在一个插件更简单的创建新的系统变量。

在宏,下面的字段是可用的:

  • name:系统变量标识符为非上市。

  • varname:对于静态变量标识符。不可用,它是一样的姓名

  • opt:为系统变量附加使用的旗帜。下表显示了允许的旗帜。

    表28.2服务器插件系统的可变标志

    标志值描述
    PLUGIN_VAR_READONLY系统变量是只读的
    PLUGIN_VAR_NOSYSVAR系统变量在运行时用户不可见
    PLUGIN_VAR_NOCMDOPT系统变量是不可配置的命令行
    PLUGIN_VAR_NOCMDARG没有参数是在命令行要求(通常用于布尔变量)
    PLUGIN_VAR_RQCMDARG一种说法是在命令行中所需的(这是默认的)
    PLUGIN_VAR_OPCMDARG一种说法是可选的命令行
    PLUGIN_VAR_MEMALLOC用于字符串变量;表明内存被分配的字符串存储

  • comment:一个描述性的评论是在服务器的帮助信息显示。无效的如果这个变量被隐藏

  • check检查功能,无效的默认

  • update更新功能,无效的默认

  • default变量的默认值

  • minimum最小值:变量

  • maximum在变量的最大值

  • blocksize可变块大小。当该值设置,它被舍入到最近的多

系统变量可以用静态变量直接或通过使用SYSVAR()访问宏。这个sysvar(的)宏提供的完整性。通常只能用在代码不能直接访问底层变量。

例如:

static int my_foo;
static MYSQL_SYSVAR_INT(foo_var, my_foo,
                        PLUGIN_VAR_RQCMDARG, "foo comment",
                        NULL, NULL, 0, 0, INT_MAX, 0);
 ...
   SYSVAR(foo_var)= value;
   value= SYSVAR(foo_var);
   my_foo= value;
   value= my_foo;

会话变量只能通过访问THDVAR()存取宏。例如:

static MYSQL_THDVAR_BOOL(some_flag,                         PLUGIN_VAR_NOCMDARG, "flag comment",                         NULL, NULL, FALSE); ...   if (THDVAR(thd, some_flag))   {     do_something();     THDVAR(thd, some_flag)= FALSE;   }

全球所有的会话系统变量必须公布mysqld使用前。这是通过构造一个做NULL终止的变量数组,链接到它的插件接口。例如:

static struct st_mysql_sys_var *my_plugin_vars[]= {  MYSQL_SYSVAR(foo_var),  MYSQL_SYSVAR(some_flag),  NULL};mysql_declare_plugin(fooplug){  MYSQL_..._PLUGIN,  &plugin_data,  "fooplug",  "foo author",  "This does foo!",  PLUGIN_LICENSE_GPL,  foo_init,  foo_fini,  0x0001,  NULL,  my_plugin_vars,  NULL,  0}mysql_declare_plugin_end;

以下便利宏使你申报不同类型的系统变量:

  • 布尔类型的系统变量bool, which is a 1-byte boolean. (0 =, 1 =true

    mysql_thdvar_bool(名称、选择、点评、检查、更新,默认)mysql_sysvar_bool(名称,varname,选择、评论、检查、更新,默认)
  • 字符串类型的系统变量char*,这是一个指向一个空结束的字符串。

    Mysql Control I Thd瓦尔Consef Str(name,OPT,comment,Check,Update,Default)MSQQL SERIN THE SYSVE INTERNATIONAL PRC(name,Varname,OPT,Comment,Check,update,Default)
  • 整数系统变量,其中有几个品种。

    • 一个int系统变量,这是一个典型的4字节有符号字。

      mysql_thdvar_int(名称、选择、点评、检查、更新,默认情况下,min,max,BLK)mysql_sysvar_int(名称,varname,选择、评论、检查、更新,默认情况下,最小,最大,块大小)
    • 一个unsigned int系统变量,这是一个典型的4字节无符号字。

      mysql_thdvar_uint(名称、选择、点评、检查、更新,默认情况下,min,max,BLK)mysql_sysvar_uint(名称,varname,选择、评论、检查、更新,默认情况下,最小,最大,块大小)
    • long系统变量,这是通常是一个4字节的字或符号。

      mysql_thdvar_long(名称、选择、点评、检查、更新,默认情况下,min,max,BLK)mysql_sysvar_long(名称,varname,选择、评论、检查、更新,默认情况下,最小,最大,块大小)
    • 一个unsigned long系统变量,这是通常是4或8字节无符号字。

      mysql_thdvar_ulong(名称、选择、点评、检查、更新,默认情况下,min,max,BLK)mysql_sysvar_ulong(名称,varname,选择、评论、检查、更新,默认情况下,最小,最大,块大小)
    • long long系统变量,它通常是一个8字节有符号字。

      mysql_thdvar_longlong(名称、选择、点评、检查、更新,默认情况下,最小,最大,块)mysql_sysvar_longlong(名称,varname,选择、评论、检查、更新,默认情况下,最小,最大,块大小)
    • 一个unsigned long long系统变量,它通常是一个8字节无符号字。

      Mysql Control I Thd瓦尔Control I Uongagong(name,OPt,Comment,Check,Update,Default,Minimum,Mimimum,Bocksize)Mysql Service Case Control Inc . Ulongong(name,Varname,opt,comment,Check,update,default,minimum,maximum,bocksize)
    • double系统变量,它通常是一个8字节有符号字。

      mysql_thdvar_double(名称、选择、点评、检查、更新,默认情况下,最小,最大,块)mysql_sysvar_double(名称,varname,选择、评论、检查、更新,默认情况下,最小,最大,块大小)
    • 一个unsigned long系统变量,这是通常是4或8字节无符号字。可能的值的范围是在元素数量序号类型库出发,从0

      MYSQL_THDVAR_ENUM(name, opt, comment, check, update, default, typelib)
      MYSQL_SYSVAR_ENUM(name, varname, opt, comment, check, update,
                      default, typelib)
      
    • 一个unsigned long long系统变量,它通常是一个8字节无符号字。每一位代表在一个元素类型库

      MYSQL_THDVAR_SET(name, opt, comment, check, update, default, typelib)
      MYSQL_SYSVAR_SET(name, varname, opt, comment, check, update,
                     default, typelib)
      

在内部,所有的可变和插件系统变量都存储在一个HASH结构

服务器的命令行帮助文本显示是由编译DYNAMIC_ARRAY所有变量的命令行选项,相关排序,然后遍历每个选项来显示。

当一个命令行选项已被处理,然后离开argv_选项(处理)功能(my_getopt.c);实际上,它是消耗。

服务器进程的命令行选项的插件的安装过程后立即插件已成功加载在插件初始化函数被称为

在运行时加载的插件不从任何配置选项的利益必须有可用的默认设置。一旦安装,它们装在mysqld初始化和配置选项可以设置在命令行或在my.cnf

插件应该考虑thd参数是只读的

28.2.4.2.3客户端插件描述符

每个客户端插件必须有一个描述符提供信息给客户端插件API。描述符结构由一组固定的成员共同所有的客户端插件,其次是任何成员特定的插件式。

这个st_mysql_client_plugin结构中的_ plugin.h客户端文件定义了一个通用描述符包含普通成员:

struct st_mysql_client_plugin
{
  int type;
  unsigned int interface_version;
  const char *name;
  const char *author;
  const char *desc;
  unsigned int version[3];
  const char *license;
  void *mysql_api;
  int (*init)(char *, size_t, int, va_list);
  int (*deinit)();
  int (*options)(const char *option, const void *);
};

常见的st_mysql_client_plugin描述符结构构件应用如下。char *成员国应指定为零终止字符串。

  • type插件式。这必须是一个插件式值_ plugin.h客户端,如MYSQL_CLIENT_AUTHENTICATION_PLUGIN

  • interface_version插件接口的版本。例如,这是MySQL客户端认证_ _ _ _ _接口插件版为验证插件

  • name:一个字符串,给出了插件的名称。这是你所指的是插件当你叫的名字mysql_options()_ _ auth mysql默认选择或指定--default-auth选择一个MySQL客户端程序。

  • author:一个字符串命名插件作者。这可以是任何你喜欢的。

  • desc:一个字符串,提供插件的一般描述。这可以是任何你喜欢的。

  • version:插件版本为3的整数表示主要的,次要的数组,和小小的版本。例如,{1,2,3}Indicated version 1.2.3 .

  • license:一个字符串,指定许可证类型。

  • mysql_api:内部使用。其指定为无效的在画面上

  • init:只有一次的初始化函数,或无效的如果没有这样的功能。客户端库执行这个函数当它加载的插件。该函数返回非零的零成功和失败。

    这个init函数使用的前两个参数,如果出现错误,返回一个错误信息。第一个参数是一个指向函数的指针烧焦缓冲区,第二个参数指示缓冲区长度。通过返回的任何消息init函数必须终止,所以消息的最大长度是缓冲区的长度减一。下一个参数传递给mysql_load_plugin()。第一个表示多少更多的参数有(0如果没有),其次是剩余的参数。

  • deinit:只有一次的deinitialization功能,或无效的如果没有这样的功能。客户端库执行此功能时,卸载插件。该函数不需要参数。它返回非零的零成功和失败。

  • options:用于处理通过插件选项功能,或无效的如果没有这样的功能。该函数有两个参数代表选项的名称和一个指向它的价值。该函数返回非零的零成功和失败。

对于一个给定的客户端插件类型,常见的描述符成员可能跟其他成员必须实施这种类型的插件。例如,在st_mysql_client_plugin_AUTHENTICATION身份验证插件结构函数结束时,客户端库的调用进行身份验证。

声明一个插件,使用mysql_declare_client_plugin()_端插件_ _ MySQL客户端宏:

mysql_declare_client_plugin(plugin_type)
   ... members common to all client plugins ...
   ... type-specific extra members ...
mysql_end_client_plugin;

不指定typeinterface_version成员明确。这个mysql_declare_client_plugin()宏使用的plugin_type参数值自动生成。例如,宣布这样一个认证客户端插件:

mysql_declare_client_plugin(认证)”my_auth_plugin”、“作者姓名”,“我的客户端身份验证插件”,{1,0,0},“GPL”,空,my_auth_init,my_auth_deinit,my_auth_options,my_auth_mainmysql_end_client_plugin;

这一声明使用AUTHENTICATION参数设置类型interface_version成员MySQL客户端认证_ _ _插件MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION

根据插件类型,描述可能有其他成员的普通成员。例如,一个身份验证插件,有一个功能(my_auth_main()在描述符只显示与服务器通信,处理)。看到第28.2.4.9,“写作认证插件”

通常,一个支持身份验证插件的使用会导致一个插件是通过调用客户端程序mysql_options()设置_ _ auth mysql默认MYSQL_PLUGIN_DIR备选办法:

char *plugin_dir = "path_to_plugin_dir";char *default_auth = "plugin_name“;/*…过程命令行选项。* / MySQL(MySQL和MySQL _选项,你_ _插件插件,你_);_ options(MySQL和MySQL,MySQL _ _ AUTH的违约,违约_ auth);

通常情况下,该计划还将接受--plugin-dir-默认的认证这使用户能够覆盖默认值选项。

如果客户程序需要低级别的插件管理,客户端库中包含的函数,以st_mysql_client_plugin争论。看到第27.7.13,“C API客户端插件功能”

28.2.4.3编译和安装的插件库

在你的插件是书面的,必须编译并安装它。编制共享对象的过程因系统而异。如果你建立你的图书馆使用CMake,它应该能够产生你的系统正确的编译命令。如果图书馆被命名为somepluglib,你应该结束了一个共享库文件,有一个名字一样的东西somepluglib.so。(The)。所以后缀名的文件可能在您的系统上的不同。)

使用CMake,你需要设置的配置文件来启用插件进行编译和安装。在使用插件的例子插件一个MySQL源分布为指导目录。

创造CMakeLists.txt,它应该是这个样子:

mysql_add_plugin(somepluglib somepluglib。C module_only module_output_name”somepluglib”)

什么时候CMake生成makefile,它应该照顾通过编译命令-DMYSQL_DYNAMIC_PLUGIN国旗,并传递给链接器- lmysqlservices国旗,这是需要链接在任何功能通过插件服务接口提供的服务。看到28.3节,“MySQL服务插件”

运行CMake,然后运行

shell> cmake .
shell> make

如果您需要指定的配置选项CMake,看到2.8.4”部分,MySQL源配置选项”,一个清单。例如,您可能需要指定CMAKE_INSTALL_PREFIX表明MySQL库目录下,插件必须安装。你能看到什么价值来使用这个选项SHOW VARIABLES

MySQL的&#62;SHOW VARIABLES LIKE 'basedir';变量的名字| --------------- ------------------ | _价值| --------------- ------------------ |基地| /usr/local MySQL | --------------- ------------------

位置的插件目录,你要安装的库是由plugin_dir系统变量。例如:

MySQL的&#62;SHOW VARIABLES LIKE 'plugin_dir';_ --------------- ----------------------------------- |变量名称|价值| --------------- -----------------------------------你|插件_ | /usr/local MySQL /图书馆/ MySQL /插件| --------------- -----------------------------------

安装插件库,使用

shell> make install

验证安装在正确的目录中安装的插件库。后安装,确保图书馆的权限允许它被服务器执行。

28.2.4.4写满文本解析器插件

MySQL支持服务器端全文解析插件MyISAMInnoDB。有关全文解析插件的入门资料,看全文解析插件

全文解析插件可以用来替换或修改内置的全文解析。本节介绍了如何编写一个解析器插件命名全文simple_parser。这个插件的基础上进行简单的规则比MySQL内置全文分析器使用解析:话是空运行的空白字符。

说明使用源代码中的plugin/fulltextMySQL源分布目录,所以改变定位到该目录。下面的过程描述了如何创建插件库:

  1. 写一个全文解析插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

    #include <mysql/plugin.h>
    

    plugin.h定义MySQL _ ftparser _插件服务器插件类型和所需要的数据结构声明插件。

  2. 设置插件库文件的库描述符。

    这个描述符包含服务器插件一般插件描述符。为全文解析插件的类型必须MYSQL_FTPARSER_PLUGIN。这是识别插件作为法律中使用的价值与解析当创建一个条款FULLTEXT指数(没有其他的插件式是合法的这一条款。)

    例如,一个图书馆,图书馆的描述符包含一个全文解析插件命名simple_parser看起来像这样:

    mysql_declare_plugin(ftexample){ mysql_ftparser_plugin,/ *型* / / * * / simple_parser_descriptor,描述“simple_parser”/名字/甲骨文公司/ * * /”,作者简单的文本解析器”,/ *说明* / plugin_license_gpl,/ *插件许可*/ /*初始化函数simple_parser_plugin_init,(当加载)* / / * simple_parser_plugin_deinit,deinit功能(空载时)* / / * * /版本端口,simple_status,/ * * / simple_system_variables状态变量,系统变量/ * * /空,0 } mysql_declare_plugin_end;

    这个name成员(简单的)指示要使用的名称在报表如插件引用INSTALL PLUGINUNINSTALL PLUGIN。这也显示的名字SHOW PLUGINSINFORMATION_SCHEMA.PLUGINS

    有关更多信息,参见第28.2.4.2.1”图书馆和服务器插件,插件参数”

  3. 上下型特异的DESCRIPTOR插件。

    每个通用插件描述符在库描述符指向一个特定类型的描述符。为全文解析插件,特定类型的描述符的实例st_mysql_ftparser结构中的H的插件文件:

    struct st_mysql_ftparser
    {
      int interface_version;
      int (*parse)(MYSQL_FTPARSER_PARAM *param);
      int (*init)(MYSQL_FTPARSER_PARAM *param);
      int (*deinit)(MYSQL_FTPARSER_PARAM *param);
    };
    

    如图所示的结构定义,描述了一个接口的版本号和包含指向三个功能。

    界面的版本号是用符号表示,这是在形式:MYSQL_xxx_INTERFACE_VERSION。全文解析插件,符号_ ftparser _接口_ MySQL的版本。在源代码中,你会发现全文解析插件中定义的实际接口的版本号include/mysql/plugin_ftparser.h。当前接口的版本号0x0101

    这个initdeinit成员应指向一个函数或是如果功能不需要设置为0。这个parse成员必须指向函数进行解析。

    simple_parser声明表示,描述与简单的解析器_ _描述符。描述符指定全文插件接口的版本号(由MYSQL_FTPARSER_INTERFACE_VERSION),和插件的解析,初始化,和deinitialization功能:

    static struct st_mysql_ftparser simple_parser_descriptor={  MYSQL_FTPARSER_INTERFACE_VERSION, /* interface version      */  simple_parser_parse,              /* parsing function       */  simple_parser_init,               /* parser init function   */  simple_parser_deinit              /* parser deinit function */};

    全文解析插件采用的是两种不同的情况下,索引和搜索。在这两种情况下,服务器调用初始化和deinitialization函数的开头和结尾的处理每个SQL语句,使插件被调用。然而,在语句的处理,服务器的上下文特定的方式调用的主要分析功能:

    • 对于索引,服务器要求每个列的值进行索引分析器。

    • 搜索,服务器调用解析器解析搜索字符串。解析器可能会调用语句所处理的行。自然语言中的模式,不需要对服务器的调用语法分析器。布尔型短语搜索或自然语言的检索查询扩展,解析器用来解析列值的信息,不在指数。另外,如果是一个布尔模式搜索是一列没有做FULLTEXT指数,内置解析器将被称为。(插件与特定的相关指标。如果没有索引,没有插件的使用。)

    在一般的插件插件描述符声明initdeinit这一点,deinitialization成员初始化的功能,所以没有特定类型的插件描述符所指向的。然而,这些对功能有不同的目的和不同的原因调用:

    • 在一般的插件插件描述符声明、初始化和deinitialization函数调用插件时,加载和卸载。

    • 对于特定类型的插件描述符初始化函数调用时,deinitialization每个SQL语句的插件的使用。

    每个接口的功能插件描述符指定应返回成功或非零故障零,和他们每个人都收到一个说法,指MYSQL_FTPARSER_PARAM含解析上下文结构。这个定义的结构:

    定义st_mysql_ftparser_param { int(* mysql_parse)(结构st_mysql_ftparser_param *,char *医生,int doc_len);int(* mysql_add_word)(结构st_mysql_ftparser_param *,char*,int word_len,mysql_ftparser_boolean_info * boolean_info);void * ftparser_state;void * mysql_ftparam;结构charset_info_st * CS;char * DOC;int长度;int旗;枚举enum_ftparser_mode模式;} mysql_ftparser_param;

    结构构件应用如下:

    • mysql_parse:一个指针指向一个回调函数,调用服务器的内置分析器。使用这个回调的时候插件作为内置的解析器的前端。那就是,当插件解析函数被调用时,它应该处理输入提取文本,通过文本的mysql_parse回调

      这个回调函数的第一个参数应该是param本身的价值:

      参数&#62; MySQL _ parse(参数,……);

      前端插件可以提取文本和一次全部内置解析器通过它,或它可以提取和传递文本内置解析器在一块。然而,在这种情况下,内置的解析器将文本块好像有隐字打破他们之间。

    • mysql_add_word:一个指向回调函数添加一个字一个全文索引或搜索术语列表。使用这个回调当解析器插件替换内置分析器。那就是,当插件解析函数被调用时,它应该解析输入成字和调用mysql_add_word每个字的回调

      这个回调函数的第一个参数应该是param本身的价值:

      参数&#62; MySQL _添加_字(参数,……);
    • ftparser_state:这是一个通用的指针。该插件可以将它设置为指向的信息被用于内部自己的目的。

    • mysql_ftparam:这是由服务器设置。这是对第一个参数传递mysql_parsemysql_add_word回调

    • cs:指针对设置文本的字符信息,或0如果没有可用的信息。

    • doc:一个指向文本被解析。

    • length:被解析的文本的长度,以字节为单位。

    • flags国旗:分析器。这是零,如果没有特殊的旗帜。唯一的非零标志mysql_ftflags_need_copy,这意味着mysql_add_word()必须保存一份字(即,它不能用一个指针指向这个词是因为这个词是在一个缓冲区,将被覆盖。)

      这个标志可以设置或重置MySQL调用解析器插件之前,由解析器插件本身,或由mysql_parse()功能

    • mode:解析模式。此值将下面的一个常数:

      • MYSQL_FTPARSER_SIMPLE_MODE解析:快速和简单的模式,这是用于检索和自然语言查询。解析器应该通过服务器唯一的那些话,应该被索引。如果解析器使用长度限制或停用词列表来确定哪些词忽略,它不应该通过这样的话服务器。

      • MYSQL_FTPARSER_WITH_STOPWORDS:停用词模式解析。这是使用布尔搜索短语匹配。解析器应该通过所有的话服务器,甚至停用词或词,在任何正常长度的限制。

      • MYSQL_FTPARSER_FULL_BOOLEAN_INFO:布尔模式解析。这是用于解析布尔查询字符串。解析器应该认识到不仅单词而且布尔模式运营商传递给服务器作为标记使用mysql_add_word回调。告诉服务器什么样的标记是通过插件需要填写MYSQL_FTPARSER_BOOLEAN_INFO结构和传递一个指向它的指针。

    笔记

    MyISAM,停用词列表ft_min_word_lenft_max_word_len检查里面的分解器。为InnoDB,的停用词表和等效长度变量设置(innodb_ft_min_token_sizeinnodb_ft_max_token_size)检查tokenizer的外面。因此,InnoDB插件解析器不需要检查停用词列表,innodb_ft_min_token_size,或innodb_ft_max_token_size。相反,建议所有的话返回InnoDB。然而,如果你想检查stopwords插件内的解析器,使用MYSQL_FTPARSER_SIMPLE_MODE,这是全文索引搜索和自然语言搜索。为MySQL是一个_ ftparser _ _ stopwordsMYSQL_FTPARSER_FULL_BOOLEAN_INFO模式,建议所有的话返回InnoDB包括停用词在短语搜索案例。

    如果解析器是布尔型的叫,param->mode值将我想知道我的意思是。这个MYSQL_FTPARSER_BOOLEAN_INFO结构分析器使用令牌传递信息到服务器看起来像这样:

    定义st_mysql_ftparser_boolean_info {枚举enum_ft_token_type型;int YesNo;int weight_adjust;焦wasign;字符trunc;国际地位;/*这些解析器状态必须清除。* /焦沪指;char * quot;} mysql_ftparser_boolean_info;

    解析器应该如下填写结构成员:

    • type“令牌类型。下面的表permissible节目的类型。

      表28.3全文解析令牌类型

      标记值意义
      FT_TOKEN_EOF数据结束
      FT_TOKEN_WORD常规的字
      FT_TOKEN_LEFT_PAREN一个集团或子表达式的开始
      FT_TOKEN_RIGHT_PAREN一组或一个表达式结束
      FT_TOKEN_STOPWORD一个词

    • yesno:这个词是否必须出席比赛发生。0意味着这个词是可选的但增加了匹配关联如果存在。值大于0意味的词必须存在。值小于0意味着这个词一定不会是现在。

    • weight_adjust:一个加权因子的确定多少字匹配数。它可以用来增加或减少相关计算单词的重要性。值为零表示没有权重调整。值大于或小于零均值较高或较低的重量,分别。的例子第12.9.2,”布尔全文搜索”,使用<&#62;操作说明如何加权的作品。

    • wasign:加权系数的符号。负价值的行为像~布尔搜索运算符,使词的贡献是负的相关性。

    • trunc是否匹配:应为如果布尔模式*截断了

    • position:启动文件中的字的位置,在字节。用InnoDB全文搜索。现有的插件,在布尔模式,支持必须添加成员的位置。

    插件不应该使用prevquot的成员MYSQL_FTPARSER_BOOLEAN_INFO结构

    笔记

    插件解析器框架不支持:

    • 这个@distance布尔算子

    • 一个领先的加号(+)或减号()布尔算子的一个空格,然后一个字('+ apple'这是我的苹果)。领导正号或负号必须直接相邻的词,例如:'+apple'这是我的苹果

    关于布尔全文搜索运营商的信息,参见第12.9.2,”布尔全文搜索”

  4. 设置该插件的接口函数。

    一般的插件描述符在库描述符名称初始化和deinitialization,服务器应该调用时加载和卸载插件功能。为simple_parser什么也不做,这些函数返回零表示他们成功了:

    静态变量simple_parser_plugin_init(void *精__attribute__((未使用))){ return(0);} static int simple_parser_plugin_deinit(void *精__attribute__((未使用))){ return(0);}

    因为这些功能实际上不做任何事情,你可以忽略他们,指定0为它们中的每一个插件的声明。

    插件型特异性描述符for thesimple_parser名称初始化,deinitialization,和解析功能,服务器调用插件时使用。为简单的、初始化和deinitialization函数什么也不做:

    static int simple_parser_init(MYSQL_FTPARSER_PARAM *param
                                  __attribute__((unused)))
    {
      return(0);
    }
    
    static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param
                                    __attribute__((unused)))
    {
      return(0);
    }
    

    在这里,因为那些函数什么也不做,你可以忽略他们,指定0为它们中的每一个插件描述符。

    主要分析功能,simple_parser_parse(),作为一个内置的全文解析更换,所以需要拆分文本的话,经过的每一个字的服务器。解析函数的第一个参数是一个指向一个结构包含解析语境。这种结构具有文件成员指向文本被解析,和length成员表明文本是多久。简单的解析插件做考虑空运行的空白字符是文字,所以它确定了这样的话:

    static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param){  char *end, *start, *docend= param->doc + param->length;  for (end= start= param->doc;; end++)  {    if (end == docend)    {      if (end > start)        add_word(param, start, end - start);      break;    }    else if (isspace(*end))    {      if (end > start)        add_word(param, start, end - start);      start= end + 1;    }  }  return(0);}

    当解析器发现每一个单词,它调用一个函数add_word()传话给服务器add_word()是一个辅助函数;它不是插件接口部分。分析器通过分析上下文指针add_word(),以及一个指向字和一个长度值:

    static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len){  MYSQL_FTPARSER_BOOLEAN_INFO bool_info=    { FT_TOKEN_WORD, 0, 0, 0, 0, 0, ' ', 0 };  param->mysql_add_word(param, word, len, &bool_info);}

    布尔模式解析,add_word()填写的成员宝醇信息结构在讨论前面介绍的st_mysql_ftparser_boolean_info结构

  5. 建立状态变量。对于simple_parser插件,下面的状态变量数组建立状态变量的值是静态文本,和另一个值存储在一个长整型变量:

    long number_of_calls= 0;struct st_mysql_show_var simple_status[]={  {"simple_parser_static", (char *)"just a static text", SHOW_CHAR},  {"simple_parser_called", (char *)&number_of_calls,     SHOW_LONG},  {0,0,0}};

    采用状态变量名,插件的名称开始,你可以很容易地显示变量的一个插件SHOW STATUS

    MySQL的&#62;SHOW STATUS LIKE 'simple_parser%';---------------------- -------------------- | variable_name |价值| ---------------------- -------------------- | simple_parser_static |只是一个静态文本| | simple_parser_called | 0 | ---------------------- --------------------
  6. 编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量)。for the简单的这是编译和安装插件,当你建立MySQL从源。它也包含在二进制分布。构建过程产生一个共享对象库的名字mypluglib.so(The。所以后缀可能取决于你的平台不同)。

  7. 使用这个插件,它与服务器登记。例如,在运行时登记的插件,使用此语句(调整.so你的平台是必要的后缀):

    安装插件simple_parser现在的mypluglib。”;

    关于插件加载的更多信息,参见第5.6.1,“安装和卸载插件”

  8. to verify the插件安装,检查INFORMATION_SCHEMA.PLUGINS表或使用SHOW PLUGINS声明。看到第2,“获取服务器插件的信息”

  9. 测试插件来验证它的正确。

    创建一个表,包含一个字符串列副解析器插件和一个FULLTEXT在列的索引:

    MySQL的&#62;CREATE TABLE t (c VARCHAR(255),-&#62;  FULLTEXT (c) WITH PARSER simple_parser-&#62;) ENGINE=MyISAM;查询行,0行受影响(0.01秒)

    插入一些文本到桌子,尝试一些搜索。这些应该验证解析器插件将所有非空格字符的汉字:

    mysql> INSERT INTO t VALUES
        ->   ('utf8mb4_0900_as_cs is a case-sensitive collation'),
        ->   ('I\'d like a case of oranges'),
        ->   ('this is sensitive information'),
        ->   ('another row'),
        ->   ('yet another row');
    Query OK, 5 rows affected (0.02 sec)
    Records: 5  Duplicates: 0  Warnings: 0
    
    mysql> SELECT c FROM t;
    +--------------------------------------------------+
    | c                                                |
    +--------------------------------------------------+
    | utf8mb4_0900_as_cs is a case-sensitive collation |
    | I'd like a case of oranges                       |
    | this is sensitive information                    |
    | another row                                      |
    | yet another row                                  |
    +--------------------------------------------------+
    5 rows in set (0.00 sec)
    
    mysql> SELECT MATCH(c) AGAINST('case') FROM t;
    +--------------------------+
    | MATCH(c) AGAINST('case') |
    +--------------------------+
    |                        0 |
    |          1.2968142032623 |
    |                        0 |
    |                        0 |
    |                        0 |
    +--------------------------+
    5 rows in set (0.00 sec)
    
    mysql> SELECT MATCH(c) AGAINST('sensitive') FROM t;
    +-------------------------------+
    | MATCH(c) AGAINST('sensitive') |
    +-------------------------------+
    |                             0 |
    |                             0 |
    |               1.3253291845322 |
    |                             0 |
    |                             0 |
    +-------------------------------+
    5 rows in set (0.01 sec)
    
    mysql> SELECT MATCH(c) AGAINST('case-sensitive') FROM t;
    +------------------------------------+
    | MATCH(c) AGAINST('case-sensitive') |
    +------------------------------------+
    |                    1.3109166622162 |
    |                                  0 |
    |                                  0 |
    |                                  0 |
    |                                  0 |
    +------------------------------------+
    5 rows in set (0.01 sec)
    
    mysql> SELECT MATCH(c) AGAINST('I\'d') FROM t;
    +--------------------------+
    | MATCH(c) AGAINST('I\'d') |
    +--------------------------+
    |                        0 |
    |          1.2968142032623 |
    |                        0 |
    |                        0 |
    |                        0 |
    +--------------------------+
    5 rows in set (0.01 sec)
    

    既不案例也没有不敏感比赛不区分大小写这样他们会对内置分析器。

28.2.4.5写后台插件

一个守护进程插件是一个简单的用于代码的插件,应该由服务器运行但不与它沟通。本节介绍了如何编写一个守护进程服务器插件,使用中发现的示例插件plugin/daemon_exampleMysQL源分配器的目录这些目录含有daemon_example.cc一个后台插件命名源文件daemon_example写一个心跳线定期对文件命名mysql-heartbeat.log在数据目录

写一个程序插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <mysql/plugin.h>

plugin.h定义_ MySQL Daemon _插件服务器插件类型和所需要的数据结构声明插件。

这个daemon_example.cc文件设置库描述如下。图书馆的描述符包括一个单一的通用服务器插件描述符。

mysql_declare_plugin(daemon_example){ mysql_daemon_plugin,与daemon_example_plugin,“daemon_example”、“Brian Aker”、“守护进程实例,创建一个心跳节拍文件mysql的心跳。日志”,plugin_license_gpl,daemon_example_plugin_init,/ * * / daemon_example_plugin_deinit plugin init,/ * * /插件deinit 0x0100 / * 1 * / / *状态,空,变量* /空/ * * /系统变量为空,/ * * / 0配置选项,/* */ } mysql_declare_plugin_end旗帜;

这个name成员(daemon_example)指示要使用的名称在报表如插件引用INSTALL PLUGINUNINSTALL PLUGIN。这也显示的名字SHOW PLUGINSINFORMATION_SCHEMA.PLUGINS

第二插件描述符成员,daemon_example_plugin,指向特定类型的后台插件描述符。这种结构仅由特定类型的API的版本号:

struct st_mysql_daemon daemon_example_plugin={ MYSQL_DAEMON_INTERFACE_VERSION  };

特定类型的结构没有接口功能。有服务器和插件之间没有沟通,除了服务器调用初始化和deinitialization从一般插件描述符函数来启动和停止插件:

  • daemon_example_plugin_init()打开文件并生成一个心跳线程定期苏醒,写下一个消息文件。

  • daemon_example_plugin_deinit()关闭该文件并执行其他清理。

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量为了daemon_example这是编译和安装插件,当你建立MySQL从源。它也包含在二进制分布。构建过程产生一个共享对象库的名字libdaemon_example.so(The。所以后缀可能取决于你的平台不同)。

使用这个插件,它与服务器登记。例如,在运行时登记的插件,使用此语句(调整.so你的平台是必要的后缀):

_ example插件安装守护程序是libdaemon soname _ example.so;

关于插件加载的更多信息,参见第5.6.1,“安装和卸载插件”

to verify the插件安装,检查INFORMATION_SCHEMA.PLUGINS表或使用SHOW PLUGINS声明。看到第2,“获取服务器插件的信息”

载入插件的时候,它写了一个心跳线定期对文件命名mysql-heartbeat.log在数据目录。这个文件也没有限制,所以在你satistifed自己插件运行正确,卸下它:

_ example插件卸载程序;

28.2.4.6写作information_schema插件

本节介绍了如何编写一个服务器端INFORMATION_SCHEMA表格插件。例如,代码实现这样的插件,看SQL / sql_show.cc一个MySQL源配置文件。你也可以看看在示例插件InnoDB来源看到处理器/ i_s.cchandler/ha_innodb.cc文件内InnoDB源树(在storage/innobase目录)

写一个INFORMATION_SCHEMA表格插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <sql_class.h>#include <table.h>

这些头文件位于sqlMySQL源分布目录。它们包含了C语言的结构,所以对一个源文件information_schema插件必须被编译为C(C)代码。

这里的示例插件开发的源文件的名称simple_i_s_table.cc。它创建了一个简单的information_schema表命名SIMPLE_I_S_TABLE有两列姓名VALUE。为实现表格插件库的一般描述看起来像这样:

mysql_declare_plugin(simple_i_s_library){  MYSQL_INFORMATION_SCHEMA_PLUGIN,  &simple_table_info,                /* type-specific descriptor */  "SIMPLE_I_S_TABLE",                /* table name */  "Author Name",                     /* author */  "Simple INFORMATION_SCHEMA table", /* description */  PLUGIN_LICENSE_GPL,                /* license type */  simple_table_init,                 /* init function */  NULL,  0x0100,                            /* version = 1.0 */  NULL,                              /* no status variables */  NULL,                              /* no system variables */  NULL,                              /* no reserved information */  0                                  /* no flags */}mysql_declare_plugin_end;

这个name成员(simple_i_s_table)指示要使用的名称在报表如插件引用INSTALL PLUGINUNINSTALL PLUGIN。这也显示的名字SHOW PLUGINSINFORMATION_SCHEMA.PLUGINS

这个simple_table_info一般的描述符指向特定类型的描述符的成员,只包括特定类型的API的版本号:

static struct st_mysql_information_schema simple_table_info ={ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };

一般广义点初始化和deinitialization功能:

  • 初始化函数提供了有关表的结构和功能,填入表。

  • 的deinitialization函数执行任何所需的清理。如果没有清理是必要的,这可以描述构件NULL(如图所示)

初始化函数应该返回0成功,1如果出现错误。这个函数接收一个普通的指针,它应该解释为一个指针的表结构:

static int table_init(void *ptr)
{
  ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE*)ptr;

  schema_table->fields_info= simple_table_fields;
  schema_table->fill_table= simple_fill_table;
  return 0;
}

这个函数应该将这两个成员的表结构:

  • fields_info:数组st_field_info包含每个列的信息结构。

  • fill_table:一个函数,填入表

指向数组的fields_info应包含每列的一个元素information_schema加终端元素。the followingsimple_table_fields例如插件数组表示simple_i_s_table有两列NAME是一个长度为10的字符串值,价值是整数的值与20的显示宽度。最后的结构标志数组的末尾。

static ST_FIELD_INFO simple_table_fields[]=
{
  {"NAME", 10, MYSQL_TYPE_STRING, 0, 0 0, 0},
  {"VALUE", 6, MYSQL_TYPE_LONG, 0, MY_I_S_UNSIGNED, 0, 0},
  {0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0}
};

有关栏目信息结构的更多信息,参见定义ST_FIELD_INFO表的头文件。《permissibleMYSQL_TYPE_xxx类型的值是那些使用C API;看第27.7.5,“C API的数据结构”

这个fill_table成员应该设置一个功能,填入表并返回0成功,如果出现错误。例如插件的simple_fill_table()功能看起来像这样:

static int simple_fill_table(THD *thd, TABLE_LIST *tables, Item *cond)
{
  TABLE *table= tables->table;

  table->field[0]->store("Name 1", 6, system_charset_info);
  table->field[1]->store(1);
  if (schema_table_store_record(thd, table))
    return 1;
  table->field[0]->store("Name 2", 6, system_charset_info);
  table->field[1]->store(2);
  if (schema_table_store_record(thd, table))
    return 1;
  return 0;
}

每一行的INFORMATION_SCHEMA表的每一列,该函数初始化,然后调用schema_table_store_record()安装排。这个store()方法的参数取决于要存储的值的类型。列0(姓名对字符串),store()以一个字符串的指针,它的长度,并设置字符串的字符信息:

商店(const char*,单位长度,charset_info CS);

列1(VALUE,一个整数),(商店)以指示是否符号标志的值:

store(longlong nr, bool unsigned_value);

其他的例子说明了如何填充INFORMATION_SCHEMATable,Search for Instances ofschema_table_store_record()进入sql_show.cc

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量

测试插件,安装它:

mysql> INSTALL PLUGIN SIMPLE_I_S_TABLE SONAME 'simple_i_s_table.so';

验证表是存在的:

mysql> SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
    -> WHERE TABLE_NAME = 'SIMPLE_I_S_TABLE';
+------------------+
| TABLE_NAME       |
+------------------+
| SIMPLE_I_S_TABLE |
+------------------+

尽量选择它:

mysql> SELECT * FROM INFORMATION_SCHEMA.SIMPLE_I_S_TABLE;
+--------+-------+
| NAME   | VALUE |
+--------+-------+
| Name 1 |     1 |
| Name 2 |     2 |
+--------+-------+

卸载它:

mysql> UNINSTALL PLUGIN SIMPLE_I_S_TABLE;

28.2.4.7写半同步复制插件

本节介绍了如何编写服务器端的半同步复制的插件,使用中发现的例子插件plugin/semisyncMySQL源分布目录。该目录包含源文件为主人和奴隶的插件命名rpl _种子_ sync _硕士rpl_semi_sync_slave。这里的信息只包括如何设置插件框架。如何实现复制的插件功能的详细信息,参见源。

写一个半同步复制插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <mysql/plugin.h>

plugin.h定义mysql_replication_plugin服务器插件类型和所需要的数据结构声明插件。

在主人身边,semisync_master_plugin.cc包含这一插件命名的一般描述rpl _种子_ sync _硕士

mysql_declare_plugin(semi_sync_master)
{
  MYSQL_REPLICATION_PLUGIN,
  &semi_sync_master_plugin,
  "rpl_semi_sync_master",
  "He Zhenxing",
  "Semi-synchronous replication master",
  PLUGIN_LICENSE_GPL,
  semi_sync_master_plugin_init, /* Plugin Init */
  semi_sync_master_plugin_deinit, /* Plugin Deinit */
  0x0100 /* 1.0 */,
  semi_sync_master_status_vars, /* status variables */
  semi_sync_master_system_vars, /* system variables */
  NULL,                         /* config options */
  0,                            /* flags */
}
mysql_declare_plugin_end;

对奴隶的一面,semisync_slave_plugin.cc包含这一插件命名的一般描述rpl_semi_sync_slave

mysql_declare_plugin(semi_sync_slave)
{
  MYSQL_REPLICATION_PLUGIN,
  &semi_sync_slave_plugin,
  "rpl_semi_sync_slave",
  "He Zhenxing",
  "Semi-synchronous replication slave",
  PLUGIN_LICENSE_GPL,
  semi_sync_slave_plugin_init, /* Plugin Init */
  semi_sync_slave_plugin_deinit, /* Plugin Deinit */
  0x0100 /* 1.0 */,
  semi_sync_slave_status_vars,  /* status variables */
  semi_sync_slave_system_vars,  /* system variables */
  NULL,                         /* config options */
  0,                            /* flags */
}
mysql_declare_plugin_end;

无论是主人和奴隶的插件,一般描述对特定类型的描述符的指针,初始化和deinitialization功能和状态变量和系统变量通过插件实现。有关变量的设置信息,看第28.2.4.2.2,“服务器插件状态变量和系统变量”。以下言论讨论的特定类型的描述符和初始化和deinitialization功能主插件,但同样适用于奴隶的插件。

这个semi_sync_master_plugin大师的通用描述符指向特定类型的描述符的成员,只包括特定类型的API的版本号:

struct Mysql_replication semi_sync_master_plugin= {  MYSQL_REPLICATION_INTERFACE_VERSION};

初始化和deinitialization函数声明看起来像这样:

static int semi_sync_master_plugin_init(void *p);
static int semi_sync_master_plugin_deinit(void *p);

初始化函数使用指针登记交易和二进制日志观察员与服务器。初始化成功后,服务器负责调用观察者在适当的时候。(在观察者,详情请看源文件。)的deinitialization清理注销功能的观察。每个函数返回0成功或1如果出现错误。

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量为了rpl _种子_ sync _硕士rpl_semi_sync_slave他们是编译和安装插件,当你建立MySQL从源。他们也包括在二元分布。建设过程中产生的共享对象库的名字semisync_master.sosemisync_slave.so(The。所以后缀可能取决于你的平台不同)。

28.2.4.8编写审核插件

本节介绍了如何编写一个服务器端审核插件,使用中发现的示例插件plugin/audit_nullMysQL源分配器的目录的_ null.c审计audit_null_variables.h在该目录下执行审计插件命名源文件审计

笔记

插件使用插件API审核查询重写插件的例子(见5.6.4节,“重写查询重写插件”)和版本标记插件(参见第5.6.5、”版本标记”

在服务器中,可实现审计接口的sql_audit.hsql_audit.cc文件在sqlMySQL源分布目录。另外,在服务器的几个地方叫审计接口当审计事件的发生,使注册会计师的插件可以通知有关事件,如果有必要的话。看到这样的电话时,搜索的形式与名称的功能调用服务器的源文件MySQL _审计_xxx()。审计通知发生服务器操作等:

  • 客户端连接和断开的事件

  • 写邮件的通用查询日志(如果日志启用)

  • 写邮件的错误日志

  • 发送一个查询结果给客户端

写一个审计插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <mysql/plugin_audit.h>

plugin_audit.h包括H的插件,所以你不需要包含后者的文件明确。plugin.h定义mysql_audit_plugin服务器插件类型和所需要的数据结构声明插件。plugin_audit.h定义数据结构的特定审计插件。

普特普金将军

审计的插件,像任何MySQL服务器插件,有插件描述符(见第28.2.4.2.1”图书馆和服务器插件,插件参数”插件型特异性)和描述符。在audit_null.c一般的描述审计_空看起来像这样:

mysql_declare_plugin(audit_null)
{
  MYSQL_AUDIT_PLUGIN,         /* type                            */
  &audit_null_descriptor,     /* descriptor                      */
  "NULL_AUDIT",               /* name                            */
  "Oracle Corp",              /* author                          */
  "Simple NULL Audit",        /* description                     */
  PLUGIN_LICENSE_GPL,
  audit_null_plugin_init,     /* init function (when loaded)     */
  audit_null_plugin_deinit,   /* deinit function (when unloaded) */
  0x0003,                     /* version                         */
  simple_status,              /* status variables                */
  system_variables,           /* system variables                */
  NULL,
  0,
}
mysql_declare_plugin_end;

第一个成员,MYSQL_AUDIT_PLUGIN,确定这个插件作为一种审计插件。

audit_null_descriptor指向特定类型的插件描述符,稍后介绍。

这个name成员(审计)指示要使用的名称在报表如插件引用INSTALL PLUGINUNINSTALL PLUGIN。这也显示的名字INFORMATION_SCHEMA.PLUGINSSHOW PLUGINS

这个audit_null_plugin_init初始化函数进行初始化时加载的插件插件。这个审计_空_ _ deinit插件函数执行清理插件时,卸下。

一般的插件描述符也指simple_statussystem_variables,结构和系统变量暴露的几种状态。当插件被激活,这些变量可以检查使用SHOW报表(SHOW STATUSSHOW VARIABLESor the tables)适当的性能模式。

这个simple_status这几个结构形式的状态变量的名字Audit Control Cullónxxx审计增量Audit_null_called每一个通知,它接收状态变量。其他状态变量更具体审计增量他们只为特定事件的通知。

system_variables是系统变量元素的数组,其中每个定义使用mysql _ thdvar _xxx宏.这些系统变量形式的名称【中文解释】:努力xxx。这些变量可以用于在运行时插件交流。

审计插件类型特定的描述符

这个audit_null_descriptor价值在一般插件描述符指向特定类型的插件描述符。审计插件,该描述子具有以下结构(定义在羽毛球):

struct st_mysql_audit
{
  int interface_version;
  void (*release_thd)(MYSQL_THD);
  int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
  unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
};

审计插件的特定类型的描述符有这些成员:

  • interface_version:按照惯例,特定类型的插件描述符开始于给定的插件式的接口版本。服务器检查interface_version当它加载的插件是否是兼容的插件。审计插件的价值interface_version成员是我的意思是,我的意思是。(定义plugin_audit.h

  • release_thd:一个函数,服务器调用通知插件,它被从它的线程的上下文分离。这应该是无效的如果没有这样的功能

  • event_notify:一个函数,服务器调用通知插件已发生的审计事件。这个函数不应该无效的;那没有意义因为没有审计会发生。

  • class_mask:数组mysql_audit_class_mask_size元素每个元素指定一个给定事件类指示类的插件要通知屏蔽。(这是怎样的插件订阅对感兴趣的事件。)的一个元素应该是0忽略相应的事件类的事件。

服务器使用event_notifyrelease_thd功能结合在一起。他们是在一个特定的线程的上下文,和线程可以执行生产几个事件通知活动。第一次服务器调用event_notify一个线程,它会创建一个绑定的插件线。插件无法卸载这个绑定。当没有更多的事件的线程将发生,服务器通知这个插件通过调用release_thd功能,然后破坏结合。例如,当一个客户端发出一个声明,螺纹加工的语句可能会通知审核插件的结果集的语句生成和声明被记录。在这些发生通知,服务器版本的插件之前,将线程休眠直到客户端发布另一个声明。

这种设计使插件的配置对于一个给定的线程在第一次调用所需要的资源event_notify在功能和释放release_thd功能:

event_notify function:
  if memory is needed to service the thread
    allocate memory
  ... rest of notification processing ...

release_thd function:
  if memory was allocated
    release memory
  ... rest of release processing ...

这比分配和释放内存多次通知功能更有效。

对于NULL_AUDIT审计的特定类型的插件,插件描述符看起来像这样:

static struct st_mysql_audit audit_null_descriptor={  MYSQL_AUDIT_INTERFACE_VERSION,                    /* interface version    */  NULL,                                             /* release_thd function */  audit_null_notify,                                /* notify function      */  { (unsigned long) MYSQL_AUDIT_GENERAL_ALL,    (unsigned long) MYSQL_AUDIT_CONNECTION_ALL,    (unsigned long) MYSQL_AUDIT_PARSE_ALL,    (unsigned long) MYSQL_AUDIT_AUTHORIZATION_ALL,    (unsigned long) MYSQL_AUDIT_TABLE_ACCESS_ALL,    (unsigned long) MYSQL_AUDIT_GLOBAL_VARIABLE_ALL,    (unsigned long) MYSQL_AUDIT_SERVER_STARTUP_ALL,    (unsigned long) MYSQL_AUDIT_SERVER_SHUTDOWN_ALL,    (unsigned long) MYSQL_AUDIT_COMMAND_ALL,    (unsigned long) MYSQL_AUDIT_QUERY_ALL,    (unsigned long) MYSQL_AUDIT_STORED_PROGRAM_ALL }};

服务器调用audit_null_notify()通过审计事件信息插件。没有release_thd功能

这个class_mask会员是一个数组,显示该事件类插件订阅。如图所示,该数组的内容订阅的所有子类的所有事件类可。忽略了对于一个给定的事件类的所有通知,指定相应的class_mask元素0

class_mask元素对应的事件类的数量,其中每个列在mysql_event_class_t枚举的定义plugin_audit.h

typedef enum{  MYSQL_AUDIT_GENERAL_CLASS          = 0,  MYSQL_AUDIT_CONNECTION_CLASS       = 1,  MYSQL_AUDIT_PARSE_CLASS            = 2,  MYSQL_AUDIT_AUTHORIZATION_CLASS    = 3,  MYSQL_AUDIT_TABLE_ACCESS_CLASS     = 4,  MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS  = 5,  MYSQL_AUDIT_SERVER_STARTUP_CLASS   = 6,  MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS  = 7,  MYSQL_AUDIT_COMMAND_CLASS          = 8,  MYSQL_AUDIT_QUERY_CLASS            = 9,  MYSQL_AUDIT_STORED_PROGRAM_CLASS   = 10,  /* This item must be last in the list. */  MYSQL_AUDIT_CLASS_MASK_SIZE} mysql_event_class_t;

对于任何给定的事件类,plugin_audit.h定义了个别事件类的位掩码的符号,以及一个xxx_all的象征,是所有子类的掩码的联盟。例如,对于审计报告(类,包括连接和断开的事件),plugin_audit.h这些符号的定义:

typedef enum{  /** occurs after authentication phase is completed. */  MYSQL_AUDIT_CONNECTION_CONNECT          = 1 << 0,  /** occurs after connection is terminated. */  MYSQL_AUDIT_CONNECTION_DISCONNECT       = 1 << 1,  /** occurs after COM_CHANGE_USER RPC is completed. */  MYSQL_AUDIT_CONNECTION_CHANGE_USER      = 1 << 2,  /** occurs before authentication. */  MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE = 1 << 3} mysql_event_connection_subclass_t;#define MYSQL_AUDIT_CONNECTION_ALL (MYSQL_AUDIT_CONNECTION_CONNECT | \                                    MYSQL_AUDIT_CONNECTION_DISCONNECT | \                                    MYSQL_AUDIT_CONNECTION_CHANGE_USER | \                                    MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE)

订阅的所有子类的连接事件类(如NULL_AUDIT插件一样),一个插件指定审计报告在相应的class_mask元件(class_mask [ 1 ]在这种情况下)。订阅一些子类,插件的设置class_mask元的感兴趣的子类的联盟。例如,订阅只有连接和改变用户的子类,插件集class_mask [ 1 ]这一价值:

MYSQL_AUDIT_CONNECTION_CONNECT | MYSQL_AUDIT_CONNECTION_CHANGE_USER
审计功能插件的通知

大部分的工作对审计插件出现在通知功能(的event_notify特定类型的插件描述符成员)。服务器调用该函数的每个审核事件。审计插件通知功能有原型:

int(* _事件通知(THD)_ MySQL,MySQL _事件_舱_ t,const void *);

的第二个和第三个参数event_notify函数原型代表事件类和一个通用的指针指向一个事件结构。(在不同的班级活动具有不同的结构。通知功能可以使用事件类的值来确定哪些事件结构适用。)函数处理该事件,并返回一个状态指示服务器是否应该继续处理事件或终止。

NULL_AUDIT,通知功能审计_ notify()_空。这个函数的增量的全球事件计数器(这插件暴露的价值Audit_null_called状态值),并对事件类来决定如何处理该事件结构:

static int audit_null_notify(MYSQL_THD thd __attribute__((unused)),                             mysql_event_class_t event_class,                             const void *event){  ...  number_of_calls++;  if (event_class == MYSQL_AUDIT_GENERAL_CLASS)  {    const struct mysql_event_general *event_general=                                    (const struct mysql_event_general *)event;    ...  }  else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)  {    const struct mysql_event_connection *event_connection=                                (const struct mysql_event_connection *) event;    ...  }  else if (event_class == MYSQL_AUDIT_PARSE_CLASS)  {    const struct mysql_event_parse *event_parse =                                      (const struct mysql_event_parse *)event;    ...  }  ...}

通知功能解释event根据价值的争论事件。这个event参数是一个通用的指针指向事件的记录,它的结构不同,每个事件类。(The羽毛球文件包含定义每个事件类的内容结构为每个类。),audit_null_notify()把事件相应的类的具体结构和再检查,确定哪个子类计数器增加子类。例如,代码在处理连接事件类的事件看起来像这样:

else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS){  const struct mysql_event_connection *event_connection=                              (const struct mysql_event_connection *) event;  switch (event_connection->event_subclass)  {  case MYSQL_AUDIT_CONNECTION_CONNECT:    number_of_calls_connection_connect++;    break;  case MYSQL_AUDIT_CONNECTION_DISCONNECT:    number_of_calls_connection_disconnect++;    break;  case MYSQL_AUDIT_CONNECTION_CHANGE_USER:    number_of_calls_connection_change_user++;    break;  case MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE:    number_of_calls_connection_pre_authenticate++;      break;  default:    break;  }}
笔记

一般事件类(MYSQL_AUDIT_GENERAL_CLASS)是过时的MySQL 5.7.9和将在未来的MySQL版本中删除。减少插件的开销,最好是只订阅感兴趣的更具体的事件类。

对于一些事件类的NULL_AUDIT插件执行其他处理除了递增计数器。在任何情况下,当处理完事件通知功能,它应该返回一个状态指示服务器是否应该继续处理事件或终止。

审计插件错误处理

审计插件通知功能可以报告一个状态值对当前事件的两种方式:

  • 使用通知函数返回值。在这种情况下,函数返回零,如果服务器应该继续处理事件,或非零如果服务器应终止事件。

  • 调用my_message()功能设置错误状态之前,从通知函数返回。在这种情况下,通知函数返回值被忽略,服务器终止事件处理一个错误。这个我_(消息)参数说明错误报告,和它的消息。例如:

    my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0));
    

    有些事件无法中止。一个非零返回值是不考虑的,my_message()错误的调用必须遵循is_error()检查。例如:

    if (!thd->get_stmt_da()->is_error())
    {
      my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0));
    }
    

有些事件无法终止:

  • MYSQL_AUDIT_CONNECTION_DISCONNECT:服务器无法防止客户端断开。

  • MYSQL_AUDIT_COMMAND_END:本活动提供了一个命令,执行完成的状态,所以没有目的的终止它。

如果一个审计插件返回一个nonterminable事件非零状态,服务器忽略状态并继续处理事件。这是真的如果一个审计程序应用my_message()函数终止nonterminable事件。

审计插件的使用

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量为了审计这是编译和安装插件,当你建立MySQL从源。它也包含在二进制分布。构建过程产生一个共享对象库的名字adt_null.so(The。所以后缀可能取决于你的平台不同)。

在运行时登记的插件,使用此语句(调整.so你的平台是必要的后缀):

安装插件null_audit现在的adt_null。”;

关于插件加载的更多信息,参见第5.6.1,“安装和卸载插件”

to verify the插件安装,检查INFORMATION_SCHEMA.PLUGINS表或使用SHOW PLUGINS声明。看到第2,“获取服务器插件的信息”

而安装审计插件,它暴露了状态变量表示事件的插件被称为:

mysql> SHOW STATUS LIKE 'Audit_null%';
+----------------------------------------+--------+
| Variable_name                          | Value  |
+----------------------------------------+--------+
| Audit_null_authorization_column        | 0      |
| Audit_null_authorization_db            | 0      |
| Audit_null_authorization_procedure     | 0      |
| Audit_null_authorization_proxy         | 0      |
| Audit_null_authorization_table         | 0      |
| Audit_null_authorization_user          | 0      |
| Audit_null_called                      | 185547 |
| Audit_null_command_end                 | 20999  |
| Audit_null_command_start               | 21001  |
| Audit_null_connection_change_user      | 0      |
| Audit_null_connection_connect          | 5823   |
| Audit_null_connection_disconnect       | 5818   |
| Audit_null_connection_pre_authenticate | 5823   |
| Audit_null_general_error               | 1      |
| Audit_null_general_log                 | 26559  |
| Audit_null_general_result              | 19922  |
| Audit_null_general_status              | 21000  |
| Audit_null_global_variable_get         | 0      |
| Audit_null_global_variable_set         | 0      |
| Audit_null_parse_postparse             | 14648  |
| Audit_null_parse_preparse              | 14648  |
| Audit_null_query_nested_start          | 6      |
| Audit_null_query_nested_status_end     | 6      |
| Audit_null_query_start                 | 14648  |
| Audit_null_query_status_end            | 14647  |
| Audit_null_server_shutdown             | 0      |
| Audit_null_server_startup              | 1      |
| Audit_null_table_access_delete         | 104    |
| Audit_null_table_access_insert         | 2839   |
| Audit_null_table_access_read           | 97842  |
| Audit_null_table_access_update         | 278    |
+----------------------------------------+--------+

Audit_null_called把所有的事件,和其他变量数的具体事件子类的实例。例如,前SHOW STATUS语句使服务器发送结果给客户,如果日志启用写邮件的通用查询日志。因此,客户问题的语句反复的原因audit_null_calledAudit_null_general_result,和一般_空_ _日志审计要增加每次。发生通知是否启用日志。

状态变量的值汇总在所有会话。有个别课程没有柜台。

NULL_AUDIT暴露出一些系统变量,使运行时插件通信:

MySQL的&#62;SHOW VARIABLES LIKE 'null_audit%';_ name变量| ------------------------------------ ------- |空值| ------------------------------------ ------- | _ _ ABORT消息| _审计审计失败_ _ | |空值| _ | |空1阶_ _审计事件_ _检查| | |空阶_ _审计事件的| _ _ _检查1 | | _空_审计_ _事件开始| 0阶| | _审计记录事件_ _空空| | | _审计事件记录_ _ _ DEF | | ------------------------------------ -------

检查审核订单的API调用,设置null_audit_event_order_check变量预期的事件顺序。例如:

SET null_audit_event_order_check =      'MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE;;;'      'MYSQL_AUDIT_GENERAL_LOG;;;'      'MYSQL_AUDIT_CONNECTION_CONNECT;;';

声明中利用SQL语法,连接相邻的字符串为一个字符串。

该值的格式是:

'event_name;event_data;command' [';event_name;event_data;command'] ...

在事件发生后的秩序是匹配的,null_audit_event_order_check价值与价值取代event-order-ok

指定一个命令值ABORT_RET可以中止审核API调用在指定的事件。下面的示例将中止INSERT语句执行时我的意思是,我的意思是。event occurs:

SET null_audit_event_order_check =
   'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
   'MYSQL_AUDIT_GENERAL_LOG;;;'
   'MYSQL_AUDIT_QUERY_START;;;'
   'MYSQL_AUDIT_QUERY_STATUS_END;;ABORT_RET';

审核后的插件匹配前面的序列,它中止的事件处理和发送错误信息给客户:

ERROR 3164 (HY000): Aborted by Audit API ('MYSQL_AUDIT_QUERY_STATUS_END';1).

从审计API通知例程返回一个非零的值是终止事件执行的标准方法。它也可以指定一个自定义的错误代码的设置null_audit_abort_value变量,通知程序应该返回的值:

SET null_audit_abort_value = 123;

中止一个序列的结果在一个自定义错误信息代码标准。假设你设置系统变量这样的审计日志:

SET null_audit_abort_value = 123;
SET null_audit_event_order_check =
    'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
    'MYSQL_AUDIT_GENERAL_LOG;;;'
    'MYSQL_AUDIT_QUERY_START;;ABORT_RET';

然后执行SELECT 1在这个错误的结果:

错误3164(hy000):中止审核的API(&#39;mysql_audit_query_start”;123)。

一个事件也可以中止与自定义消息,由指定的设置null_audit_abort_message变量:假设你设置系统变量这样的审计日志:

SET null_audit_abort_message = 'Custom error text.';SET null_audit_event_order_check =    'MYSQL_AUDIT_COMMAND_START;command_id="3";;'    'MYSQL_AUDIT_GENERAL_LOG;;;'    'MYSQL_AUDIT_QUERY_START;;ABORT_RET';

将一个序列的结果在下面的错误:

ERROR 3164 (HY000): Custom error text.

用于创建测试的目的,可以通过插件的事件记录。记录从指定开始和结束事件null_audit_event_record_def变量:

SET null_audit_event_record_def =    'MYSQL_AUDIT_COMMAND_START;MYSQL_AUDIT_COMMAND_END';

语句执行的结果存储在事件发生null_audit_event_record变量

禁用插件,经过测试,使用此语句卸货:

UNINSTALL PLUGIN NULL_AUDIT;

28.2.4.9写作认证插件

MySQL支持可插拔认证,其中插件调用验证客户端的连接。身份验证插件启用身份验证方法比其他的密码存储在内置的使用方法mysql.user表例如,插件可以写访问外部认证方法。同时,认证插件可以支持代理用户的能力,这样的连接用户是另一个用户代理和处理,用于访问控制的目的,具有不同的用户权限。有关更多信息,参见第6.3.10,“认证”,和第6.3.11”代理用户”

验证插件可以为服务器端或客户端侧写。服务器端插件使用相同的插件API,用于其他服务器插件类型如全文分析器或审计插件(虽然有不同的类型的具体描述)。客户端插件使用客户端插件API。

几个头文件包含认证插件相关的信息:

  • plugin.h:定义mysql_authentication_plugin服务器插件式

  • client_plugin.hdefines API for the:客户端插件。这包括客户和客户端插件描述符函数原型为在插件API(EEA C第27.7.13,“C API客户端插件功能”

  • plugin_auth.h:定义特定的认证服务器API插件插件部分。这包括特定类型的描述符服务器认证插件和MySQL服务器_ _ auth _ info结构

  • plugin_auth_common.h:包含客户端和服务器的身份验证插件的共同要素。这包括返回值的定义和我_ MySQL _插件结构

写一个认证插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

  • 一个源文件,实现一个服务器身份验证插件,包括这个文件:

    #include <mysql/plugin_auth.h>
    
  • 一个源文件,实现了一个客户端身份验证插件,或者客户端和服务器的插件,包括这些文件:

    #include <mysql/plugin_auth.h>
    #include <mysql/client_plugin.h>
    #include <mysql.h>
    

plugin_auth.h包括H的插件plugin_auth_common.h,所以你不需要包含后者的文件明确。

本节介绍了如何编写一个简单的服务器和客户端身份验证插件一起工作。

警告

这些插件接受任何非空密码和密码以明文形式发送。这是不安全的,所以插件不应在生产环境中使用。

这里开发的插件都命名为服务器端和客户端auth_simple。描述第28.2.4.2,”插件数据结构”,插件库文件必须具有相同的基名称作为客户端插件,所以源文件名auth_simple.c并产生一个图书馆命名简单的(假设你的系统使用.soas the suffix for Library files)。

在MySQL源分布,验证插件源位于plugin/auth目录,可以检查为指导写作其他身份验证插件。另外,看看内置认证插件实现的,看SQL SQL / _ acl.cc插件,是建立在MySQL服务器和sql-common/client.c插件,内置的libmysqlclient客户端库。(用于内置客户端插件,注意auth_plugin_t结构用用通常的客户端插件声明宏结构也存在差异。特别是,第一个成员提供明确的声明,不宏。)

28.2.4.9.1写服务器端验证插件

与一般的描述符格式是用于所有服务器插件类型声明服务器端插件(参见第28.2.4.2.1”图书馆和服务器插件,插件参数”)。for theauth_simple插件描述符看起来像这样:

mysql_declare_plugin(auth_simple){  MYSQL_AUTHENTICATION_PLUGIN,  &auth_simple_handler,                 /* type-specific descriptor */  "auth_simple",                        /* plugin name */  "Author Name",                        /* author */  "Any-password authentication plugin", /* description */  PLUGIN_LICENSE_GPL,                   /* license type */  NULL,                                 /* no init function */  NULL,                                 /* no deinit function */  0x0100,                               /* version = 1.0 */  NULL,                                 /* no status variables */  NULL,                                 /* no system variables */  NULL,                                 /* no reserved information */  0                                     /* no flags */}mysql_declare_plugin_end;

这个name成员(_简单认证)指示要使用的名称在报表如插件引用INSTALL PLUGINUNINSTALL PLUGIN。这也显示的名字SHOW PLUGINSINFORMATION_SCHEMA.PLUGINS

这个auth_simple_handler一般的描述符指向特定类型说明符成员。为验证插件,特定类型的描述符的实例圣_ _ auth mysql结构(定义在plugin_auth.h):

结构st_mysql_auth { int interface_version;const char* client_auth_plugin;int(* authenticate_user)(mysql_plugin_vio * VIO,mysql_server_auth_info *信息);int(* generate_authentication_string)(char * outbuf,unsigned int * outbuflen,const char * inbuf,unsigned int inbuflen);int(* validate_authentication_string)(char * const inbuf,unsigned int缓冲区长度);int(* set_salt)(const char *密码,password_len unsigned int,unsigned char *盐,unsigned char * salt_len);const unsigned long authentication_flags;};

这个st_mysql_auth这些成员的结构:

  • interface_version蜜蜂:the version number型特异性,永远MySQL _认证_ _接口版本

  • client_auth_plugin客户:插件Name

  • authenticate_user:一个指向主要插件的功能与客户沟通

  • generate_authentication_string:一个指向插件功能,从认证字符串生成一个密码文摘

  • validate_authentication_string:一个指向插件功能验证密码文摘

  • set_salt:一个指向插件功能,将杂乱的密码以二进制形式

  • authentication_flags标志词:

这个client_auth_plugin成员如果一个特定的插件是必需的指示客户端插件的名称。一个值无效的方法任何插件在后一种情况下,任何插件客户端使用会。如果服务器插件不关心客户端插件或用户名称或密码发送这是有用的。例如,这可能如果服务器插件认证只有本地客户和使用操作系统的一些特性而不是由客户端插件发送的信息是真实的。

auth_simple特定类型的描述符,看起来像这样:

static struct st_mysql_auth auth_simple_handler ={  MYSQL_AUTHENTICATION_INTERFACE_VERSION,  "auth_simple",             /* required client-side plugin name */  auth_simple_server         /* server-side plugin main function */  generate_auth_string_hash, /* generate digest from password string */  validate_auth_string_hash, /* validate password digest */  set_salt,                  /* generate password salt value */  AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE};

主要功能,auth_simple_server(),有两个参数代表一个I/O结构和MySQL服务器_ _ auth _ info结构。结构定义,发现plugin_auth.h,看起来像这样:

typedef struct st_mysql_server_auth_info
{
  char *user_name;
  unsigned int user_name_length;
  const char *auth_string;
  unsigned long auth_string_length;
  char authenticated_as[MYSQL_USERNAME_LENGTH+1];
  char external_user[512];
  int  password_used;
  const char *host_or_ip;
  unsigned int host_or_ip_length;
} MYSQL_SERVER_AUTH_INFO;

设置字符串的字符的gb3212的成员。如果有一个_length件与字符串相关,提示字符串的字节长度。字符串也可以终止。

当一个身份验证插件是由服务器调用,它应该解释MYSQL_SERVER_AUTH_INFO结构成员如下。其中一些是用来设置在客户端会话的SQL函数或系统变量的值,如。

  • user_name这是一个故事。最喜爱的书籍USER()功能价值

  • user_name_length:长度用户_ name在字节

  • auth_string: The value of the_认证字符串列的mysql.user为匹配帐户名称的表行(即,行相匹配的客户端用户名和主机名和服务器使用来决定如何对客户端进行身份验证)。

    假设你创建一个帐户,使用以下语句:

    CREATE USER 'my_user'@'localhost'
      IDENTIFIED WITH my_plugin AS 'my_auth_string';
    

    什么时候my_user连接从本地主机,服务器调用我_插件并通过'my_auth_string'它作为auth _字符串价值

  • auth_string_length:长度auth _字符串在字节

  • authenticated_as:服务器设置的用户名称(价值用户_ name)。该插件可以改变它指示客户端应该有一个不同的用户权限。例如,如果插件支持代理用户,初始值是连接的名称(代理)的用户,和插件可以改变这个会员代理的用户名。然后服务器将代理用户具有代理的用户的权限(假设是满意的;代理用户支持的其他条件见第28.2.4.9.4,实施代理支持用户认证插件”)。该值表示为一个字符串在最MYSQL_USER_NAME_LENGTH字节长,再加上一个终止null。价值成为CURRENT_USER()函数值

  • external_user:服务器设置为空字符串(终止)。它的价值成为external_user系统变量的值。如果插件要系统变量有不同的值,就应该相应地设置该成员;例如,在连接的用户名。该值表示为最多511字节的字符串,再加上一个终止null。

  • password_used:该成员适用于当验证失败。插件可以设置它或忽略它。该值是用来构建失败的错误消息身份验证失败。密码:%s。价值password_used决定如何%s处理,如下表所示

    password_used%s处理
    将不会有%s
  • host_or_ip:客户端的主机名,如果它可以解决,或IP地址,否则。

  • host_or_ip_length:长度host_or_ip在字节

这个auth_simple主要功能,认证服务器_ _(简单),读取密码(一个null结尾的字符串)从客户和成功如果密码是空的(第一个字节不为空):

static int auth_simple_server (MYSQL_PLUGIN_VIO *vio,
                               MYSQL_SERVER_AUTH_INFO *info)
{
  unsigned char *pkt;
  int pkt_len;

  /* read the password as null-terminated string, fail on error */
  if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
    return CR_ERROR;

  /* fail on empty password */
  if (!pkt_len || *pkt == '\0')
  {
    info->password_used= PASSWORD_USED_NO;
    return CR_ERROR;
  }

  /* accept any nonempty password */
  info->password_used= PASSWORD_USED_YES;

  return CR_OK;
}

主函数应该返回一个如下表所示的错误代码。

错误代码意义
CR_OK成功
CR_OK_HANDSHAKE_COMPLETE不要发送状态数据包返回给客户
CR_ERROR误差
CR_AUTH_USER_CREDENTIALS身份验证失败
CR_AUTH_HANDSHAKE认证握手失败
CR_AUTH_PLUGIN_ERROR内部插件错误

关于握手的工作的一个例子,看plugin/auth/dialog.c源文件

服务器在性能模式插件错误计数host_cache

auth_simple_server()基本是这样的,它不只是设置会员是否收到密码使用认证信息结构。

一个支持代理用户插件必须返回到服务器的代理的用户的名称(MySQL的用户权限的用户应该得到)。为此,插件必须设置info->authenticated_as会员代理的用户的名称。关于代理,看第6.3.11”代理用户”,和第28.2.4.9.4,实施代理支持用户认证插件”

这个generate_authentication_string这个插件描述符成员需要密码和生成的密码哈希(摘要)从它:

  • 前两个参数是以字节为单位的输出缓冲区的最大长度的指针。这个函数应该写密码的哈希值到输出缓冲和复位的长度实际哈希长度。

  • 第二个参数指示字节密码输入缓冲区的长度。

  • 函数返回0成功,1如果出现了一个错误。

对于auth_simple插件的generate_auth_string_hash()功能的实现generate_authentication_string会员它只是让一份密码,除非它太长,适合在输出缓冲区。

int generate_auth_string_hash(char *outbuf, unsigned int *buflen,                              const char *inbuf, unsigned int inbuflen){  /*    fail if buffer specified by server cannot be copied to output buffer  */  if (*buflen < inbuflen)    return 1;   /* error */  strncpy(outbuf, inbuf, inbuflen);  *buflen= strlen(inbuf);  return 0;     /* success */}

这个validate_authentication_stringMember of the lugier叙述performance to Password HAH:

  • 该参数是在字节的密码哈希和长度的指针。

  • 函数返回0成功,1如果无法验证的密码哈希。

对于auth_simple插件的验证性_ _ _字符串的hash()功能的实现validate_authentication_string会员它返回成功的条件:

validate_auth_string_hash(int,char *const inbuf __attribute__((未使用)),unsigned int缓冲区长度__attribute__((未使用))){ return 0;/* */ }成功

这个set_salt这个插件描述符成员只能被使用mysql_native_password(这个插件部分6.5.1.1,“本土认证”)。其他认证的插件,你可以使用这个简单的实现:

int set_salt(const char* password __attribute__((unused)),
             unsigned int password_len __attribute__((unused)),
             unsigned char* salt __attribute__((unused)),
             unsigned char* salt_len)
{
  *salt_len= 0;
  return 0;     /* success */
}

这个authentication_flags这个插件描述符成员包含影响插件运行的旗帜。允许的标志:

  • AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE:变化是一个特权操作证书。如果这个标志被设置,服务器要求用户具有全局CREATE USER特权或UPDATE特权的MySQL数据库

  • AUTH_FLAG_USES_INTERNAL_STORAGE:是否插件使用内部存储(在_认证字符串mysql.user行)。如果未设置此标志,试图设置密码失败,服务器产生一个警告。

28.2.4.9.2写客户端身份验证插件

与申报客户端插件描述符mysql_declare_client_plugin()_端插件_ _ MySQL客户端宏(See第28.2.4.2.3,“客户端插件描述符”)。for theauth_simple插件描述符看起来像这样:

mysql_declare_client_plugin(AUTHENTICATION)  "auth_simple",                        /* plugin name */  "Author Name",                        /* author */  "Any-password authentication plugin", /* description */  {1,0,0},                              /* version = 1.0.0 */  "GPL",                                /* license type */  NULL,                                 /* for internal use */  NULL,                                 /* no init function */  NULL,                                 /* no deinit function */  NULL,                                 /* no option-handling function */  auth_simple_client                    /* main function */mysql_end_client_plugin;

描述符成员从插件的名称通过选项处理功能是所有客户端插件类型常见。(描述,看第28.2.4.2.3,“客户端插件描述符”以下的普通成员。),有一个特定的描述符验证插件新增成员。这是主要功能,与服务器处理通信。该函数有两个参数代表一个I/O结构和连接处理。我们简单的任何密码的插件,主要功能只是写到服务器用户提供的密码:

static int auth_simple_client (MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
{
  int res;

  /* send password as null-terminated string in clear text */
  res= vio->write_packet(vio, (const unsigned char *) mysql->passwd,
                         strlen(mysql->passwd) + 1);

  return res ? CR_ERROR : CR_OK;
}

主函数应该返回一个如下表所示的错误代码。

错误代码意义
CR_OK成功
CR_OK_HANDSHAKE_COMPLETE成功完成,客户
CR_ERROR误差

CR_OK_HANDSHAKE_COMPLETE表明客户已经完成了它的部分成功,读了最后一包。一个客户端插件可能会返回cr_ok_handshake_complete如果在认证协议的往返次数,事先是不知道的,插件必须读另一包来确定是否认证完成。

28.2.4.9.3使用身份验证插件

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量

与服务器登记服务器端插件。例如,在服务器启动时加载的插件,使用--plugin-load=auth_simple.so选项(调整。所以足够的你的平台

创建一个用户来说,服务器将使用auth_simple插件的认证:

MySQL的&#62;CREATE USER 'x'@'localhost'-&#62;IDENTIFIED WITH auth_simple;

使用客户端程序连接到服务器的用户x。服务器端_简单认证插件与客户端程序,它应该使用客户端auth_simple插件,后者发送密码到服务器。服务器插件应该拒绝连接,发送一个空的密码和接受连接,发送一个空的密码。调用客户端程序去验证这:

内核mysql --user=x --skip-password错误45(28000):用户访问被拒绝“X &#39;@&#39;本地主机&#39;(使用密码:无)内核&#62;mysql --user=x --password输入密码:abcMySQL的&#62;

因为服务器插件接受任何非空密码,它应该被认为是不安全的。经过测试的插件来验证它,重新启动服务器没有--plugin-load选择不indavertently离开服务器运行不安全的身份验证插件加载。同时,降低用户DROP USER 'x'@'localhost'

关于加载和使用身份验证插件的更多信息,参见第5.6.1,“安装和卸载插件”,和第6.3.10,“认证”

如果你正在写一个支持身份验证插件使用的客户端程序,通常这样的程序使插件可以通过调用mysql_options()设置_ _ auth mysql默认MYSQL_PLUGIN_DIR备选办法:

char *plugin_dir = "path_to_plugin_dir";char *default_auth = "plugin_name“;/*…过程命令行选项。* / MySQL(MySQL和MySQL _选项,你_ _插件插件,你_);_ options(MySQL和MySQL,MySQL _ _ AUTH的违约,违约_ auth);

通常情况下,该计划还将接受--plugin-dir-默认的认证这使用户能够覆盖默认值选项。

如果客户程序需要低级别的插件管理,客户端库中包含的函数,以st_mysql_client_plugin争论。看到第27.7.13,“C API客户端插件功能”

28.2.4.9.4实现代理支持用户认证插件

一个可插拔认证使得能力是代理用户(见第6.3.11”代理用户”)。一个服务器端的身份验证插件参与代理的用户的支持,这些条件必须满足:

  • 当一个连接的客户端应该被视为一个代理用户,插件必须返回一个不同的名字authenticated_as的成员MySQL服务器_ _ auth _ info结构,表示代理的用户的名称。它还可以随意设定external_user成员,设置的值external_user系统变量

  • 代理用户帐户必须设置被插件认证。使用CREATE USERGRANT语句关联账户的插件

  • 代理用户帐户必须有PROXY该代理帐户的特权。使用GRANT语句授予此权限

换句话说,代理用户支持的插件所需的唯一的方面是,它集authenticated_as对代理的用户名。其余的是可选的(设置external_user)或通过使用SQL语句的DBA。

如何验证插件并确定代理用户返回时,代理用户连接?这取决于插件。通常情况下,插件地图客户端代理用户通过服务器传递给它的字符串验证。这串来自AS部分的确定的条款CREATE USER语句指定认证的插件的使用。

插件开发者决定认证字符串的语法规则,根据这些规则实现了插件。假设一个插件以逗号分隔的对地图的外部使用者的MySQL用户列表。例如:

CREATE USER ''@'%.example.com'
  IDENTIFIED WITH my_plugin AS 'extuser1=mysqlusera, extuser2=mysqluserb'
CREATE USER ''@'%.example.org'
  IDENTIFIED WITH my_plugin AS 'extuser1=mysqluserc, extuser2=mysqluserd'

当服务器调用插件来验证客户端,它通过适当的认证字符串插件。插件负责:

  1. 字符串解析成它的组成成分来确定映射使用

  2. 比较客户端用户名映射

  3. 返回适当的MySQL用户名

例如,如果extuser2连接从一个example.com主机,服务器通过'extuser1=mysqlusera, extuser2=mysqluserb'的插件,而插件应该复制mysqluserb进入之内authenticated_as与终止空字节。如果extuser2连接从一个example.org主机,服务器通过'extuser1=mysqluserc, extuser2=mysqluserd',和插件应该复制mysqluserd相反

如果在映射不匹配,行动取决于插件。如果比赛是必需的,该插件可能会返回一个错误。或插件可能只是简单地返回客户的名字;在这种情况下,它不会改变authenticated_as,和服务器将不会把客户作为代理。

下面的示例演示如何处理代理用户使用一个插件命名auth_simple_proxy。像_简单认证插件之前描述的,auth_simple_proxy接受任何非空密码是有效的(因此不应在生产环境中使用的)。此外,它检查auth _字符串验证字符串的成员和使用这些非常简单的规则来解释它:

  • 如果字符串是空的,插件返回用户的姓名和无代理发生。那是,插件叶的价值authenticated_as不变

  • 如果字符串是空的,该插件将其作为代理的用户和复制它的名字authenticated_as所以,代理发生

用于测试,建立一个帐户,不代理根据前面的规则,一个是。这意味着,一个帐户没有AS条款,和一个包括:作为条款名称代理用户:

CREATE USER 'plugin_user1'@'localhost'
  IDENTIFIED WITH auth_simple_proxy;
CREATE USER 'plugin_user2'@'localhost'
  IDENTIFIED WITH auth_simple_proxy AS 'proxied_user';

此外,创建代理用户帐户授予plugin_user2这个PROXY特权的信息:

创建用户的proxied_user &#39;@&#39;本地主机&#39;确定&#39; proxied_user_pass”;授予代理的proxied_user &#39;@&#39;本地主机&#39; &#39; plugin_user2 &#39;@&#39;本地主机&#39;;

在服务器调用验证插件,它集authenticated_as到客户端的用户名。如果用户是一个代理,插件的设置authenticated_as对代理的用户名。为auth_simple_proxy,这意味着它必须检查auth _字符串值,如果值为空,将它复制到authenticated_as成员还作为代理的用户的名称。此外,当代理时,插件的设置external_user会员客户的用户名;这就值了external_user系统变量

static int auth_simple_proxy_server (MYSQL_PLUGIN_VIO *vio,                                     MYSQL_SERVER_AUTH_INFO *info){  unsigned char *pkt;  int pkt_len;  /* read the password as null-terminated string, fail on error */  if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)    return CR_ERROR;  /* fail on empty password */  if (!pkt_len || *pkt == '\0')  {    info->password_used= PASSWORD_USED_NO;    return CR_ERROR;  }  /* accept any nonempty password */  info->password_used= PASSWORD_USED_YES;  /* if authentication string is nonempty, use as proxied user name */  /* and use client name as external_user value */  if (info->auth_string_length > 0)  {    strcpy (info->authenticated_as, info->auth_string);    strcpy (info->external_user, info->user_name);  }  return CR_OK;}

连接成功后,该USER()函数应该显示连接用户和主机名,和CURRENT_USER()应说明其权限申请会议期间账户。后者的价值要连接的用户帐户如果没有代理或代理的代理帐户时如果发生。

编译和安装插件,然后测试它。首先,连接plugin_user1

内核mysql --user=plugin_user1 --password输入密码:x

在这种情况下,不应该有任何代理:

mysql> SELECT USER(), CURRENT_USER(), @@proxy_user, @@external_user\G
*************************** 1. row ***************************
         USER(): plugin_user1@localhost
 CURRENT_USER(): plugin_user1@localhost
   @@proxy_user: NULL
@@external_user: NULL

然后连接plugin_user2

内核mysql --user=plugin_user2 --password输入密码:x

在这种情况下,plugin_user2应向代理proxied_user

mysql> SELECT USER(), CURRENT_USER(), @@proxy_user, @@external_user\G
*************************** 1. row ***************************
         USER(): plugin_user2@localhost
 CURRENT_USER(): proxied_user@localhost
   @@proxy_user: 'plugin_user2'@'localhost'
@@external_user: 'plugin_user2'@'localhost'

28.2.4.10写作密码验证插件

本节介绍如何编写一个服务器端的密码验证插件。指示是基于源代码中的plugin/password_validationMysQL源分配器的目录的验证在实现插件的源文件目录命名validate_password

笔记

在MySQL 8.0.4,validate_password插件是不是多余的验证局分量。插件的形式validate_password仍然可用,但现在是过时的、将在未来版本的MySQL移除。MySQL装置使用的插件应该使用组件来代替过渡。看到第6.5.3.3,”过渡到密码验证组件”

写一个密码验证插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <mysql/plugin_validate_password.h>

plugin_validate_password.h包括H的插件,所以你不需要包含后者的文件明确。plugin.h定义mysql_validate_password_plugin服务器插件类型和所需要的数据结构声明插件。plugin_validate_password.h定义数据结构的特定密码验证插件。

密码验证插件,像任何MySQL服务器插件,有插件描述符(见第28.2.4.2.1”图书馆和服务器插件,插件参数”)。在validate_password.cc一般广义,for the验证局看起来像这样:

mysql_declare_plugin(validate_password)
{
  MYSQL_VALIDATE_PASSWORD_PLUGIN,     /*   type                            */
  &validate_password_descriptor,      /*   descriptor                      */
  "validate_password",                /*   name                            */
  "Oracle Corporation",               /*   author                          */
  "check password strength",          /*   description                     */
  PLUGIN_LICENSE_GPL,
  validate_password_init,             /*   init function (when loaded)     */
  validate_password_deinit,           /*   deinit function (when unloaded) */
  0x0100,                             /*   version                         */
  NULL,
  validate_password_system_variables, /*   system variables                */
  NULL,
  0,
}
mysql_declare_plugin_end;

这个name成员(验证局)指示要使用的名称在报表如插件引用INSTALL PLUGINUNINSTALL PLUGIN。这也显示的名字INFORMATION_SCHEMA.PLUGINSSHOW PLUGINS

一般描述的一般描述validate_password_system_variables,一个结构暴露的几个系统变量的SHOW VARIABLES声明:

static struct st_mysql_sys_var* validate_password_system_variables[]= {  MYSQL_SYSVAR(length),  MYSQL_SYSVAR(number_count),  MYSQL_SYSVAR(mixed_case_count),  MYSQL_SYSVAR(special_char_count),  MYSQL_SYSVAR(policy),  MYSQL_SYSVAR(dictionary_file),  NULL};

这个validate_password_init初始化函数读取字典文件如果是指定的,和validate_password_deinit功能释放与文件相关的数据结构。

这个validate_password_descriptor在一般的描述符指向特定类型的描述符。密码验证插件,该描述子具有以下结构:

结构st_mysql_validate_password { int interface_version;/*这个函数返回满足密码策略密码(通过插件变量选择)和虚假的所有其他密码* / int(* validate_password)(mysql_string_handle密码);/*这个函数返回密码强度(0-100)取决于政策* / int(* get_password_strength)(mysql_string_handle密码);};

特定类型的描述符有这些成员:

  • interface_version:按照惯例,特定类型的插件描述符开始于给定的插件式的接口版本。服务器检查interface_version当它加载的插件是否是兼容的插件。密码验证插件的价值interface_version成员是我的意思是,我的意思是。(定义plugin_validate_password.h

  • validate_password:一个函数,服务器调用测试密码是否满足当前密码策略。它返回1,如果密码是好的,否则为0。争论是密码,传递一个mysql_string_handle价值。此数据类型的实现是由mysql_string服务器服务。详情见_ service.h字符串string_service.cc在源文件SQL目录

  • get_password_strength:一个函数,服务器要求密码强度评估。它返回一个值从0(弱)100(强)。争论是密码,传递一个mysql_string_handle价值

对于validate_password插件,特定类型的描述符看起来像这样:

static struct st_mysql_validate_password validate_password_descriptor={  MYSQL_VALIDATE_PASSWORD_INTERFACE_VERSION,  validate_password,                         /* validate function          */  get_password_strength                      /* validate strength function */};

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量为了验证局这是编译和安装插件,当你建立MySQL从源。它也包含在二进制分布。构建过程产生一个共享对象库的名字validate_password.so(The。所以后缀可能取决于你的平台不同)。

在运行时登记的插件,使用此语句(调整.so你的平台是必要的后缀):

1 . Plujy Plujs Valestate Industry Password Sonamine &#39; s Validate Artiz Pasword.so;

关于插件加载的更多信息,参见第5.6.1,“安装和卸载插件”

to verify the插件安装,检查INFORMATION_SCHEMA.PLUGINS表或使用SHOW PLUGINS声明。看到第2,“获取服务器插件的信息”

validate_password插件安装,它暴露了系统变量,表示密码校验参数:

MySQL的&#62;SHOW VARIABLES LIKE 'validate_password%';-------------------------------------- _ name变量值| -------- | | -------------------------------------- |密码验证_ -------- _字典文件| _ |验证密码长度| _ _ | 8 | |验证密码_ _混合_结婚_ count | 1 | |密码验证_ _ number _计数1 | | _密码验证| _政策中| | |特殊字符的密码验证_ _ _ _ count | -------- | 1 --------------------------------------

这些变量的描述,参见第6.5.3.2,“密码验证选项和变量”

禁用插件,经过测试,使用此语句卸货:

UNINSTALL PLUGIN validate_password;

28.2.4.11书面协议跟踪插件

MySQL支持协议跟踪插件使用:客户端插件,实现了一个客户端,利用客户端/服务器协议的服务器之间的通信跟踪。

28.2.4.11.1使用测试协议跟踪插件

MySQL包括测试协议跟踪插件,足以说明可以从插件的信息,作为一个写作指导其他协议跟踪插件。看看测试插件,使用MySQL源分布;二元分布的测试插件禁用了。

使测试协议跟踪插件的配置MySQLWITH_TEST_TRACE_PLUGINCMake启用选项。这使得测试跟踪插件来建立和MySQL客户端程序来加载它,但没有影响默认插件。使用这些环境变量插件控制:

  • MYSQL_TEST_TRACE_DEBUG:这个变量设置为非0使测试插件产生诊断的输出值标准错误

  • MYSQL_TEST_TRACE_CRASH:这个变量设置为非0使测试插件,如果它检测到一个无效的跟踪事件中止客户端程序的价值。

注意安全

从测试协议跟踪插件诊断输出可以透露密码和其他敏感信息。

给定一个MySQL的安装与测试插件源建成启用,你可以看到一丝之间的通信MySQL客户端和MySQL服务器如下:

shell> export MYSQL_TEST_TRACE_DEBUG=1
shqll> mysql
test_trace: Test trace plugin initialized
test_trace: Starting tracing in stage CONNECTING
test_trace: stage: CONNECTING, event: CONNECTING
test_trace: stage: CONNECTING, event: CONNECTED
test_trace: stage: WAIT_FOR_INIT_PACKET, event: READ_PACKET
test_trace: stage: WAIT_FOR_INIT_PACKET, event: PACKET_RECEIVED
test_trace: packet received: 87 bytes
  0A 35 2E 37 2E 33 2D 6D  31 33 2D 64 65 62 75 67   .5.7.3-m13-debug
  2D 6C 6F 67 00 04 00 00  00 2B 7C 4F 55 3F 79 67   -log.....+|OU?yg
test_trace: 004: stage: WAIT_FOR_INIT_PACKET, event: INIT_PACKET_RECEIVED
test_trace: 004: stage: AUTHENTICATE, event: AUTH_PLUGIN
test_trace: 004: Using authentication plugin: mysql_native_password
test_trace: 004: stage: AUTHENTICATE, event: SEND_AUTH_RESPONSE
test_trace: 004: sending packet: 188 bytes
  85 A6 7F 00 00 00 00 01  21 00 00 00 00 00 00 00   .?......!.......
  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
...
mysql> quit
test_trace: 008: stage: READY_FOR_COMMAND, event: SEND_COMMAND
test_trace: 008: QUIT
test_trace: 008: stage: READY_FOR_COMMAND, event: PACKET_SENT
test_trace: 008: packet sent: 0 bytes
test_trace: 008: stage: READY_FOR_COMMAND, event: DISCONNECTED
test_trace: 008: Connection  closed
test_trace: 008: Tracing connection has ended
Bye
test_trace: Test trace plugin de-initialized

禁用跟踪输出,这样做:

shell> MYSQL_TEST_TRACE_DEBUG=
28.2.4.11.2使用自己的协议跟踪插件
笔记

用你自己的协议跟踪插件,您必须在配置MySQLWITH_TEST_TRACE_PLUGINCMake选项禁用因为只有一个协议跟踪插件,可以一次加载发生错误尝试加载一个。如果你已经建立的MySQL的测试协议跟踪插件能够看到它是如何工作的,你必须重建MySQL没有它之前,你可以使用你自己的插件。

本节讨论如何编写一个基本协议跟踪插件命名simple_trace。这个插件提供了一个框架,显示如何设置客户端插件描述符和创建跟踪相关的回调函数。进入simple_trace这些功能是基本的,做点其他说明的参数要求。看到了一丝插件可以使用跟踪事件的信息,检查测试协议跟踪插件的源文件(test_trace_plugin.cclibmysql一个MySQL源分布目录)。但是,请注意,st_mysql_client_plugin_TRACE结构使用不同于用通常的客户端插件声明宏结构。特别是,第一个成员是明确定义的,不隐式声明的宏。

几个头文件包含协议跟踪插件相关的信息:

  • client_plugin.h:定义了客户端插件API。这包括客户端插件描述符和功能的客户端插件C API调用的原型(见第27.7.13,“C API客户端插件功能”

  • plugin_trace.h声明:含for客户端插件型mysql_client_trace_plugin。它也包含了允许协议阶段之间的过渡阶段,描述,并允许在每个阶段的事件的类型。

写一个协议跟踪插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <mysql/plugin_trace.h>
#include <mysql.h>

plugin_trace.h包括_ plugin.h客户端,所以你不需要包含后者的文件明确。

与申报客户端插件描述符mysql_declare_client_plugin()_端插件_ _ MySQL客户端宏(See第28.2.4.2.3,“客户端插件描述符”)。for thesimple_trace插件描述符看起来像这样:

mysql_declare_client_plugin(TRACE)  "simple_trace",                 /* plugin name */  "Author Name",                  /* author */  "Simple protocol trace plugin", /* description */  {1,0,0},                        /* version = 1.0.0 */  "GPL",                          /* license type */  NULL,                           /* for internal use */  plugin_init,                    /* initialization function */  plugin_deinit,                  /* deinitialization function */  plugin_options,                 /* option-handling function */  trace_start,                    /* start-trace function */  trace_stop,                     /* stop-trace function */  trace_event                     /* event-handling function */mysql_end_client_plugin;

描述符成员从插件的名称通过选项处理功能是所有客户端插件类型常见。以下的普通成员实施跟踪事件处理的成员。

函数成员的插件不需要处理可以声明为NULL在描述,在这种情况下,你不需要写任何相应的功能。为了显示参数语法,下面的讨论中实施描述符列出所有功能,即使有些人没有,

初始化,deinitialization选项功能,和所有客户端插件共同声明如下。一个描述参数和返回值,看第28.2.4.2.3,“客户端插件描述符”

static int
plugin_init(char *errbuf, size_t errbuf_len, int argc, va_list args)
{
  return 0;
}

static int
plugin_deinit()
{
  return 0;
}

static int
plugin_options(const char *option, const void *value)
{
  return 0;
}

该客户端插件描述符的跟踪特定的成员函数。下面的描述提供更详细的关于他们是如何使用的。每一个的第一个参数是一个指向插件实例的情况下你需要访问的实现。

trace_start():这个功能是在每个跟踪连接开始叫(每个连接,启动后载入插件)。它是通过连接处理和协议阶段,跟踪开始。trace_start()分配需要的内存trace_event()功能,如果有,并返回一个指向它的指针。如果没有记忆是必要的,这个函数返回无效的

static void*
trace_start(struct st_mysql_client_plugin_TRACE *self,
            MYSQL *conn,
            enum protocol_stage stage)
{
  struct st_trace_data *plugin_data= malloc(sizeof(struct st_trace_data));

  fprintf(stderr, "Initializing trace: stage %d\n", stage);
  if (plugin_data)
  {
    memset(plugin_data, 0, sizeof(struct st_trace_data));
    fprintf(stderr, "Trace initialized\n");
    return plugin_data;
  }
  fprintf(stderr, "Could not initialize trace\n");
  exit(1);
}

trace_stop():这个函数被调用时跟踪连接。这通常发生在连接关闭,但可以发生。例如,trace_event()可以在任何时候返回非零值,使连接跟踪终止。trace_stop()然后被即使连接还没有结束。

trace_stop()通过连接句柄和指针分配的内存trace_start()NULL如果没有)。如果你不知道无效的trace_stop()要释放内存。这个函数没有返回值。

静态voidtrace_stop(struct st_mysql_client_plugin_trace *自我,mysql * Conn,void * plugin_data){ fprintf(stderr,“终止微量\n”);如果(plugin_data)自由(plugin_data);}

trace_event():这个功能是为每一个事件的发生。它是通过指针分配的内存trace_start()NULL如果没有),连接句柄,当前协议阶段和事件代码,数据和事件数据。这个函数返回0,继续跟踪,如果跟踪非零应停止。

static inttrace_event(struct st_mysql_client_plugin_TRACE *self,            void *plugin_data,            MYSQL *conn,            enum protocol_stage stage,            enum trace_event event,            struct st_trace_event_args args){  fprintf(stderr, "Trace event received: stage %d, event %d\n", stage, event);  if (event == TRACE_EVENT_DISCONNECTED)    fprintf(stderr, "Connection closed\n");  return 0;}

跟踪框架关闭连接跟踪连接结束时,所以trace_event()应该返回非零如果你想终止跟踪连接的早期。假设你想跟踪某只连接MySQL账户。认证通过后,你可以检查用户连接名称和停止跟踪如果不是用户在其中你有兴趣。

每次调用trace_event(),的st_trace_event_args结构包含事件数据。它有这个定义:

struct st_trace_event_args
{
  const char           *plugin_name;
  int                   cmd;
  const unsigned char  *hdr;
  size_t                hdr_len;
  const unsigned char  *pkt;
  size_t                pkt_len;
};

对于不同的事件类型的st_trace_event_args结构包含以下信息描述。所有的长度,以字节为单位。未使用的成员设置为/NULL

AUTH_PLUGIN事件:

plugin_name插件的名称

SEND_COMMAND事件:

CMD命令codehdr指向指针的headerpkt命令包headerhdr_len长度参数的命令argumentspkt_len长度

其他SEND_xxxxxx_received事件

PKT指针或传送数据的数据长度的receivedpkt_len

PACKET_SENT事件:

pkt_len发送的字节数

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量

在插件库文件编译和安装在插件目录中,你可以很容易的通过设置测试LIBMYSQL_PLUGINS环境变量插件的名称,从而影响任何使用该变量的客户端程序。MySQL就是这样的一个程序:

shell> export LIBMYSQL_PLUGINS=simple_trace
shqll> mysql
Initializing trace: stage 0
Trace initialized
Trace event received: stage 0, event 1
Trace event received: stage 0, event 2
...
Welcome to the MySQL monitor.  Commands end with ; or \g.
Trace event received
Trace event received
...
mysql> SELECT 1;
Trace event received: stage 4, event 12
Trace event received: stage 4, event 16
...
Trace event received: stage 8, event 14
Trace event received: stage 8, event 15
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

mysql> quit
Trace event received: stage 4, event 12
Trace event received: stage 4, event 16
Trace event received: stage 4, event 3
Connection closed
Terminating trace
Bye

停止跟踪插件被加载,这样做:

shell> LIBMYSQL_PLUGINS=

也可以编写客户端程序,直接加载插件。你可以告诉客户,通过调用插件目录位于mysql_options()设置MySQL _ _插件目录选项:

char *plugin_dir = "path_to_plugin_dir";

/* ... process command-line options ... */

mysql_options(&mysql, MYSQL_PLUGIN_DIR, plugin_dir);

通常,程序也将接受--plugin-dir选项,用户可以重写默认值。

如果客户程序需要低级别的插件管理,客户端库中包含的函数,以st_mysql_client_plugin争论。看到第27.7.13,“C API客户端插件功能”

28.2.4.12写作钥匙插件

MySQL服务器支持一个钥匙圈服务,使内部服务器组件和插件来安全地存储敏感信息供以后检索。本节介绍了如何编写一个服务器端的插件,可以通过钥匙服务功能进行密钥管理操作。对于一般的密钥信息,看第6.5.4,“MySQL的钥匙”

这里的说明是基于源代码中的plugin/keyringMySQL源分布目录。在该目录中实现一个插件的源文件命名keyring_file使用一个文件服务器的本地主机的数据存储。

写一个钥匙圈的插件,包括头文件的插件的源文件。其他MySQL或一般的头文件,也可能是需要的,这取决于插件的功能和要求。

#include <mysql/plugin_keyring.h>

plugin_keyring.h包括H的插件,所以你不需要包含后者的文件明确。plugin.h定义mysql_keyring_plugin服务器插件类型和所需要的数据结构声明插件。plugin_keyring.h定义数据结构的特定钥匙圈插件。

一个钥匙圈的插件,像任何MySQL服务器插件,有插件描述符(见第28.2.4.2.1”图书馆和服务器插件,插件参数”)。在keyring.cc一般广义,for thekeyring_file看起来像这样:

mysql_declare_plugin(keyring_file)
{
  MYSQL_KEYRING_PLUGIN,     /* type                                     */
  &keyring_descriptor,      /* descriptor                               */
  "keyring_file",           /* name                                     */
  "Oracle Corporation",     /* author                                   */
  "store/fetch authentication data to/from a flat file", /* description */
  PLUGIN_LICENSE_GPL,
  keyring_init,             /* init function (when loaded)              */
  keyring_deinit,           /* deinit function (when unloaded)          */
  0x0100,                   /* version                                  */
  NULL,                     /* status variables                         */
  keyring_system_variables, /* system variables                         */
  NULL,
  0,
}
mysql_declare_plugin_end;

这个name成员(keyring_file)显示插件的名称。这是显示的名字INFORMATION_SCHEMA.PLUGINSSHOW PLUGINS

一般描述的一般描述keyring_system_variables一个结构,使系统变量的SHOW VARIABLES声明:

static struct st_mysql_sys_var *keyring_system_variables[]= {  MYSQL_SYSVAR(data),  NULL};

这个keyring_init初始化函数创建的数据文件,如果不存在,则读取并初始化密钥库。这个keyring_deinit功能释放与文件相关的数据结构。

这个keyring_descriptor在一般的描述符指向特定类型的描述符。对于钥匙的插件,该描述子具有以下结构:

struct { int」_ MySQL _ ST接口_ bool(MySQL版本;* _密钥_店)(const char * const char * _ ID密钥,密钥_ type,const char * const void *用户_ ID密钥,密钥大小_ T _ bool(Len);* _密钥_ mysql fetch)(const char * _ ID密钥,密钥_ char * const char *类型,用户ID _,void * T *的密钥,密钥大小_ _ bool(Len);* MySQL _密钥_删除)(const char * const char * _密钥ID,用户ID _ bool();MySQL _密钥生成_)*(const char * const char * _ ID密钥,密钥_ type,const char *用户_ ID密钥大小,_ _ len t);};

特定类型的描述符有这些成员:

  • interface_version:按照惯例,特定类型的插件描述符开始于给定的插件式的接口版本。服务器检查interface_version当它加载的插件是否是兼容的插件。对于钥匙的插件,值了interface_version成员是mysql_keyring_interface_version(定义plugin_keyring.h

  • mysql_key_store:一个函数混淆并存储在密钥环的关键。

  • mysql_key_fetch:一个函数,deobfuscates和检索从钥匙圈钥匙。

  • mysql_key_remove:一个函数,删除从钥匙圈钥匙。

  • mysql_key_generate:一个在钥匙圈产生一个新的随机密钥并将其存储功能。

对于keyring_file插件,特定类型的描述符看起来像这样:

static struct st_mysql_keyring keyring_descriptor={  MYSQL_KEYRING_INTERFACE_VERSION,  mysql_key_store,  mysql_key_fetch,  mysql_key_remove,  mysql_key_generate};

这个mysql_key_xxx通过一个钥匙圈插件实现的功能是类似的我的_重点_xxx暴露的钥匙圈服务API函数。例如,在MySQL _ key _商店插件的功能类似于my_key_store钥匙圈的服务功能。关于钥匙圈服务功能的参数信息和它们是如何使用的,看第28.3.2,“钥匙”服务

编译和安装一个插件库文件,使用说明第28.2.4.3,编译和安装插件库”。使库文件可供使用,它安装在插件目录(目录命名的plugin_dir系统变量为了keyring_file这是编译和安装插件,当你建立MySQL从源。它也包含在二进制分布。构建过程产生一个共享对象库的名字keyring_file.so(The。所以后缀可能取决于你的平台不同)。

钥匙圈插件通常加载早期服务器启动过程中使他们可用的内置插件和存储引擎,可能取决于他们。为keyring_file在服务器上使用这些线,my.cnf文件(调整.so你的平台是必要的后缀):

[mysqld]early-plugin-load=keyring_file.so

关于插件加载的更多信息,参见第5.6.1,“安装和卸载插件”

to verify the插件安装,检查INFORMATION_SCHEMA.PLUGINS表或使用SHOW PLUGINS声明(见第2,“获取服务器插件的信息”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE 'keyring%';
+--------------+---------------+
| PLUGIN_NAME  | PLUGIN_STATUS |
+--------------+---------------+
| keyring_file | ACTIVE        |
+--------------+---------------+

keyring_file插件安装,它暴露了一个系统变量,表示位置的数据文件用于信息安全存储:

MySQL的&#62;SHOW VARIABLES LIKE 'keyring_file%';------------------- ---------------------------------- | variable_name |价值| ------------------- ---------------------------------- | keyring_file_data | /usr/local/ MySQL /钥匙扣/钥匙圈| ------------------- ----------------------------------

for a description of thekeyring_file_data变,看第5.1.7,服务器“系统变量”

禁用插件测试后,重新启动服务器没有--early-plugin-load选项名称的插件

28.3 MySQL服务插件

MySQL服务器插件访问服务器插件服务插件服务接口公开服务器功能的插件可以调用。它补充了插件的API和具有这些特征的:

  • 服务启用插件访问代码内的服务器使用普通的函数调用。服务也可用户自定义函数(UDF)。

  • 服务是多平台移植工作。

  • 该接口包括版本控制机制,服务版本的服务器支持的可加载时对插件的版本检查。版本之间的不兼容版本的保护服务,服务器提供服务版本的插件所需的预期。

  • 有关测试插件服务插件,看测试插件服务插件

插件服务接口与插件API如下:

  • 插件API允许插件服务器将使用的。调用主动在于服务器调用插件。这使插件来扩展服务器的功能或登记接收服务器处理的通知。

  • 插件服务接口使插件调用代码内的服务器。调用主动在于插件调用服务函数。这使已经实现在服务器被许多使用插件的功能;他们不需要单独实现它自己。

确定哪些服务存在什么功能,他们提供的,看在include/mysql一个MySQL源分布目录。相关文件:

  • plugin.h包括服务的,这是头,包括所有可用的服务特定的头文件。

  • 服务特定的头文件的表单名service_xxx.h

每个服务的特定标题应该包含注释为一个给定的服务全部使用文档,包括哪些服务功能是可用的,它们的调用顺序和返回值。

开发者希望修改服务器添加一个新的服务,看MySQL内核:MySQL服务插件

提供的服务包括以下内容:

  • get_sysvar_source:一个服务可以使插件检索系统变量设置源。

  • locking_service:服务实现锁锁锁3种属性的命名空间,名字,和锁定模式。这种锁定界面可在两个层次:1)与C语言的接口,可从服务器插件或用户定义的函数插件服务;2)在SQL级,为一组用户定义的函数映射到调用的服务程序。有关更多信息,参见第28.3.1,“锁定服务”

  • my_plugin_log_service:一个服务可以使插件来报告错误和指定的错误消息。服务器的错误日志写入消息。

  • status_variable_registration。一个状态变量注册服务。

  • my_thd_scheduler:一个插件来选择一个线程调度服务。

  • mysql_keyring一个密匙存储服务。有关更多信息,参见第28.3.2,“钥匙”服务

  • mysql_password_policy:服务密码验证和强度校核。

  • plugin_registry_serviceMySQL服务器包括:提高服务器可扩展的基于组件的基础设施;看5.5节,“MySQL服务器组件”。然而,MySQL的插件使用一个接口在组件接口。这个plugin_registry_service使插件访问组件的注册和服务。

  • security_context:一个服务可以使插件检查或操作线程的安全上下文。这个服务提供setter和getter例程访问服务器属性_ security context类,包括属性,如登录用户和主机,经过身份验证的用户和主机和客户端的IP地址。

  • thd_alloc服务:内存分配

  • thd_wait:服务插件报告当他们睡觉或失速。

本节描述了一个插件使用,可用的服务器作为服务的功能。又见为源守护进程示例插件,它使用my_snprintf服务在MySQL源分布、插件位于插件/ daemon_example目录

使用服务或服务在一个插件,插件的源文件必须包括plugin.h头文件访问服务的相关信息:

#include <mysql/plugin.h>

这不代表任何额外的安装成本。一个插件必须包括文件无论如何因为它包含定义和结构,每一个插件的需要。

访问服务,插件调用服务功能与任何其他函数一样。

报告错误,服务器将写入错误日志,首先选择一个错误的水平。mysql/service_my_plugin_log.h定义了这些水平:

枚举plugin_log_level { my_error_level,my_warning_level,my_information_level };

然后调用my_plugin_log_message()

我的_国际_ _插件日志消息(mysql * _插件插件,插件_枚举_日志级别的教育水平,字符串格式……);

例如:

my_plugin_log_message(plugin_ptr, MY_ERROR_LEVEL, "Cannot initialize plugin");

一些服务插件提供了可能插件和因此只有如果服务提供的插件加载。任何使用该服务MySQL组件应检查是否有可用的服务。

当你建立你的插件,使用-lmysqlservices国旗在链接时链接的libmysqlservices图书馆例如,对于CMake把这个放在顶层,CMakeLists.txt文件:

find_library(mysqlservices_lib mysqlservices路径“{ } mysql_srcdir美元/ libservices”no_default_path)

把这个放在CMakeLists.txt在包含插件的源文件的目录:

#插件需要误差loggingtarget_link_libraries MySQL服务库(your_plugin_library_namemysqlservices_lib $ { })

28.3.1锁定服务

的分布提供了一个锁定的界面,在两个层次上是可用的:

  • 作为一个C语言接口,可作为一个插件服务从服务器插件或用户定义的函数

  • 在SQL级,为一组用户定义的函数映射到调用的服务程序

关于插件服务的一般信息,看28.3节,“MySQL服务插件”。有关用户定义函数的一般信息,看第28.4.2,“添加一个新的用户定义的函数

锁定界面具有这些特点:

  • 锁有三个属性:锁锁名称和命名空间,锁定模式:

    • 锁识别相结合的命名空间和锁的名字。命名空间使不同的应用程序使用同一个锁的名字无碰撞通过创建单独的命名空间锁。例如,如果应用程序A和B的使用命名空间ns1NS2,分别为每个应用程序可以使用锁的名字lock1lock2不干扰其他应用

    • 锁定模式可以是读或写。读锁是共享的:如果一个会话有读锁在一个给定的锁定标识符,其他会话可以获得读锁在相同的标识符。写锁是唯一的:如果会话有一个写锁在一个给定的锁定标识符,其他会话不能获得读或写在同一标识锁。

  • 命名空间和锁的名称必须是非—NULL,非空的,有一个64个字符的最大长度。一个命名空间或锁名称指定为无效的,空字符串,或一个字符串的长度超过64个字符的结果是ER_LOCKING_SERVICE_WRONG_NAME误差

  • 锁定界面将命名空间和锁名称的二进制字符串,所以比较是区分大小写的。

  • 锁定界面提供的功能来获取锁和释放锁。没有任何特权的需要调用这些函数。权限检查是调用应用程序的责任。

  • 锁可以等待如果不是立即可用。锁的获取要求取整数超时值表明等待获取锁之前放弃多少秒。如果超时没有达到成功获取锁,一ER_LOCKING_SERVICE_TIMEOUT错误发生。如果超时是0,没有等待,呼叫产生一个错误,如果不能立即获得锁。

  • 锁定界面之间的僵局检测获取锁在不同的会议电话。在这种情况下,锁定服务选择呼叫和一个锁请求终止收购ER_LOCKING_SERVICE_DEADLOCK误差。这个错误不会导致事务回滚。选择以僵局的会话,会话锁定服务更喜欢持有读锁在会议举行写锁。

  • 一个会话可以用一个单一的锁的获取调用获取多个锁。对于一个给定的电话,锁的获取是原子的:电话succeeeds如果获得了所有的锁。如果任何锁未采集,电话没有获得锁和失败,通常与ER_LOCKING_SERVICE_TIMEOUTER_LOCKING_SERVICE_DEADLOCK误差

  • 一个会话可以获得相同的锁锁(锁标识符的多个命名空间和名称的组合)。这些锁的情况下可以读锁、写锁,或两者的混合。

  • 获得在一个会话锁是通过调用一个函数显式释放锁的释放,或隐含在会话终止时(无论是正常或异常)。锁不释放当事务提交或回滚。

  • 在一个会话中的所有锁,对于一个给定的命名空间时公布的是一起发布。

通过锁定服务提供的接口是不同的GET_LOCK()和相关的SQL函数(见12.22节,“多功能”)。例如,GET_LOCK()不实现命名空间提供独家的锁,没有明显的读写锁。

28.3.1.1锁定服务接口

本节介绍了如何使用锁定服务C语言接口。使用UDF接口相反,看第28.3.1.2,“锁定服务UDF接口”为锁定服务接口的一般特点,看第28.3.1,“锁定服务”。关于插件服务的一般信息,看28.3节,“MySQL服务插件”

使用锁定服务源文件应该包含这个头文件:

#include <mysql/service_locking.h>

获得一个或一个以上的锁,调用这个函数:

int mysql_acquire_locking_service_locks(MYSQL_THD opaque_thd,
                                        const char* lock_namespace,
                                        const char**lock_names,
                                        size_t lock_num,
                                        enum enum_locking_service_lock_type lock_type,
                                        unsigned long lock_timeout);

这些意义的争论:

  • opaque_thd:一个线程句柄。如果指定为无效的,为当前线程使用的处理。

  • lock_namespace:一个空结束的字符串,表示锁命名空间。

  • lock_names:零终止字符串获取了锁名称的数组。

  • lock_num:名字在数lock_names阵列

  • lock_type:*的锁模式,无论是locking_service_readLOCKING_SERVICE_WRITE获取读锁或写锁,分别。

  • lock_timeout:一个整数秒数等在放弃之前获得锁。

释放锁获得对于一个给定的命名空间,调用这个函数:

int mysql_release_locking_service_locks(MYSQL_THD opaque_thd,
                                        const char* lock_namespace);

这些意义的争论:

  • opaque_thd:一个线程句柄。如果指定为无效的,为当前线程使用的处理。

  • lock_namespace:一个空结束的字符串,表示锁命名空间。

获得的锁或等待的锁服务可以监视在SQL级使用性能模式。详情见第28.3.1.2.3,“锁定服务监控”

28.3.1.2锁定服务UDF接口

本节介绍了如何使用锁定服务的用户定义函数(UDF)接口。使用C语言接口,相反,看到第28.3.1.1,“锁定服务接口”为锁定服务接口的一般特点,看第28.3.1,“锁定服务”。有关用户定义函数的一般信息,看第28.4.2,“添加一个新的用户定义的函数

28.3.1.2.1安装或卸载UDF锁定界面

锁定服务程序的描述第28.3.1.1,“锁定服务接口”不需要是因为他们是建立在服务器安装。相同的是不是真正的用户自定义函数(UDF),映射到调用服务例程:UDFs前必须安装使用。本节介绍了如何做。关于自定义安装的一般信息,看第28.4.2.5,“UDF编译和安装”

锁定服务UDF在插件库文件位于目录下的实现plugin_dir系统变量。文件的基名称是locking_service。文件名后缀不同的平台(例如每,.soUNIX和类UNIX系统,dllWindows)

安装锁服务UDF,使用CREATE FUNCTION声明(调整。所以你的平台是必要的后缀):

CREATE FUNCTION service_get_read_locks RETURNS INT SONAME 'locking_service.so';
CREATE FUNCTION service_get_write_locks RETURNS INT SONAME 'locking_service.so';
CREATE FUNCTION service_release_locks RETURNS INT SONAME 'locking_service.so';

如果UDF使用主复制服务器,安装在所有从服务器以及避免复制问题。

一旦安装,安装之前卸载的UDF保持。删除它们,使用DROP FUNCTION声明:

拖放功能service_get_read_locks;降功能service_get_write_locks;降功能service_release_locks;
28.3.1.2.2使用UDF锁定界面

在使用UDF锁定服务,安装根据提供的指令第28.3.1.2.1,“安装或卸载UDF锁定界面”

获取一个或多个读锁,调用这个函数:

mysql> SELECT service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10);
+---------------------------------------------------------------+
| service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10) |
+---------------------------------------------------------------+
|                                                             1 |
+---------------------------------------------------------------+

第一个参数是锁命名空间。最后一个参数是一个整数超时指示等在放弃之前获得锁多少秒。参数之间是锁的名字。

例如只显示功能获取锁锁标识符(mynamespace, rlock1)(mynamespace,rlock2)

获得写锁而不是读锁,调用这个函数:

mysql> SELECT service_get_write_locks('mynamespace', 'wlock1', 'wlock2', 10);
+----------------------------------------------------------------+
| service_get_write_locks('mynamespace', 'wlock1', 'wlock2', 10) |
+----------------------------------------------------------------+
|                                                              1 |
+----------------------------------------------------------------+

在这种情况下,锁定标识符(mynamespace, wlock1)(MynaesPecia,WLLL2)

释放所有的锁一个命名空间,使用此功能:

mysql> SELECT service_release_locks('mynamespace');
+--------------------------------------+
| service_release_locks('mynamespace') |
+--------------------------------------+
|                                    1 |
+--------------------------------------+

每个锁函数返回非零成功。如果函数失败,出现错误。例如,以下错误的发生是因为锁名称不能为空:

mysql> SELECT service_get_read_locks('mynamespace', '', 10);
ERROR 3131 (42000): Incorrect locking service lock name ''.

一个会话可以获得相同的锁标识多个锁。只要一个不同的会话没有写锁的会话标识符,可以获得任意数量的读写锁。每个锁请求标识符获取一个新的锁。下面的语句获得3写锁具有相同的标识符,然后3读锁相同的标识符:

SELECT service_get_write_locks('ns', 'lock1', 'lock1', 'lock1', 0);
SELECT service_get_read_locks('ns', 'lock1', 'lock1', 'lock1', 0);

如果你检查性能架构metadata_locks在这一点上,你会发现六个不同的会话持有锁的(NNS,Lock1)标识符。(详情见第28.3.1.2.3,“锁定服务监控”。)

因为会话持有至少一个写锁上(ns, lock1),没有其他会话可以获得锁,无论是读或写。如果会话仅持有读锁的标识符,其他会话可以获得读锁,但不能写锁。

一个叫锁锁采集获得原子,而原子不在电话。因此,对于这样一个语句如下,其中service_get_write_locks()被称为每行的结果集一次,原子是每一个人的电话,而不是作为一个整体的声明:

选择service_get_write_locks(&#39;ns &#39;,&#39; lock1 &#39;、&#39; lock2,0)从T1的地方…;
注意安全

由于锁定服务返回一个单独的锁,每个成功的要求对于一个给定的锁定标识符,一个单一的语句来获得大量的锁是可能的。例如:

INSERT INTO ... SELECT service_get_write_locks('ns', t1.col_name, 0) FROM t1;

这些陈述可能有一定的不利影响。例如,如果语句失败并回滚的方式通过,获得的锁到故障点仍然存在。如果是有一个行之间插入对应的锁和收购,意图将不会满意。另外,如果锁在一个特定的顺序当然是重要的,要知道结果集的顺序可能有所不同取决于执行计划的优化选择。由于这些原因,它可能是最好的限制应用到一个单一的锁的获取调用每个语句。

28.3.1.2.3锁定服务监控

锁定服务使用的是MySQL服务器元数据锁框架实现的,所以你监控锁定服务获得的锁或等待的绩效考核模式metadata_locks

首先,使元数据锁紧装置:

mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
    -> WHERE NAME = 'wait/lock/metadata/sql/mdl';

然后获得一些锁和检查的内容metadata_locks

MySQL的&#62;SELECT service_get_write_locks('mynamespace', 'lock1', 0);---------------------------------------------------- | service_get_write_locks(&#39;mynamespace &#39;,&#39; lock1 &#39;,0)| ---------------------------------------------------- | 1 | ---------------------------------------------------- MySQL &#62;SELECT service_get_read_locks('mynamespace', 'lock2', 0);我的意思是,这是一个好的服务。SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS-&#62;FROM performance_schema.metadata_locks-&#62;WHERE OBJECT_TYPE = 'LOCKING SERVICE'\G*************************** 1。行*************************** object_type:锁定serviceobject_schema:mynamespace object_name:lock1 lock_type:独家lock_status:授予*************************** 2。行*************************** object_type:锁定serviceobject_schema:mynamespace object_name:lock2 lock_type:共享lock_status:授予

锁有锁服务OBJECT_TYPE价值锁服务。这是不同的,例如,获取的锁GET_LOCK()功能,它有一个object_type属于USER LEVEL LOCK

锁命名空间、名称、和模式出现在OBJECT_SCHEMAobject_name,和LOCK_TYPE专栏读写锁_型锁SHARED独家,分别

这个LOCK_STATUS授予为获取锁,PENDING一个锁,正在等待。你会看到悬而未决的如果一个会话持有一个写锁和另一个会议,试图获得一个具有相同标识符的锁。

28.3.1.2.4锁定服务UDF接口参考

SQL接口锁定服务实现本节中描述的用户定义函数。使用的例子,看第28.3.1.2.2,使用UDF锁定界面”

分享这些特色功能:

  • 返回值为非零成功。否则,发生了一个错误。

  • 命名空间和锁的名称必须是非—NULL,非空,有64最大字符长度。

  • 超时值必须为整数,指示等前放弃一个错误获取锁多少秒。如果超时是0,没有等待和函数产生一个错误,如果不能立即获得锁。

这些锁服务udf是可用的:

  • service_get_read_locks(namespace, lock_name[, lock_name] ..., timeout)

    获得一个或更多的读锁(共享)给定命名空间使用了锁的名字,定时与错误如果锁是不能获得在给定的超时值。

  • service_get_write_locks(namespace, lock_name[, lock_name] ..., timeout)

    获取一个或多个写(独家)锁在给定的命名空间使用了锁的名字,定时与错误如果锁是不能获得在给定的超时值。

  • service_release_locks(namespace)

    对于给定的命名空间,释放所有的锁被收购在当前会话中使用service_get_read_locks()service_get_write_locks()

    有没有锁的命名空间是不是一个错误。

28.3.2到此服务

MySQL服务器支持一个钥匙圈服务,使内部服务器组件和插件来安全地存储敏感信息供以后检索。本节介绍了如何使用钥匙圈服务功能,存储,检索,和删除MySQL钥匙密钥库的钥匙。一个SQL接口的钥匙圈的服务功能,也可作为一个组的用户自定义函数(UDF);看第6.5.4.8,“通用钥匙的密钥管理功能”。对于一般的密钥信息,看第6.5.4,“MySQL的钥匙”

到此服务使用底层的钥匙圈插件启用,如果任何。如果没有钥匙的插件启用,钥匙圈服务调用失败。

唱片在密钥库包括数据(关键)和一个唯一的标识符,其关键是通过访问。标识符有两部分:

  • key_id:关键的ID或名称_ ID的密钥值开始mysql_通过MySQL服务器保留。

  • user_id:会话有效用户ID,如果没有用户的情况下,此值可无效的。价值实际上并不需要是一个用户;的意义取决于应用

    功能实现密钥环UDF接口通过价值CURRENT_USER()作为user_id钥匙圈服务功能价值

到此服务功能有共同的特点:

  • 每个函数返回0成功,1失败。

  • 这个key_iduser_id争论形成了一个独特的组合显示,钥匙在钥匙圈使用。

  • 这个key_type论点提供了关键的附加信息,如加密方法或使用目的。

  • 钥匙圈服务功能治疗关键ID,用户名称,类型和值的二进制字符串,所以比较是区分大小写的。例如,入侵检测MyKey的myKey引用不同的钥匙

这些钥匙圈服务功能齐备:

  • my_key_fetch()

    deobfuscates和检索从钥匙圈钥匙,随着它的类型。功能分配的内存缓冲区用于存储返回键和键。来电者应该为零或模糊的记忆时,不再需要它,然后释放它。

    语法:

    bool my_key_fetch(const char *key_id, const char **key_type,
                      const char* user_id, void **key, size_t *key_len)
    

    争论:

    • key_iduser_id:null结尾的字符串,作为一对形成独特的指示,关键取标识符。

    • key_type:一个缓冲区的指针地址。功能将它指向一个空结束的字符串,提供关键的附加信息(存储在密钥添加)。

    • key:一个缓冲区的指针地址。函数指针存储到它包含了关键的数据缓冲区。

    • key_len:一个变量的地址,函数存储在字节的大小*键缓冲区

    返回值:

    返回0成功,1失败

  • my_key_generate()

    生成一个新的给定的类型和长度,并将其存储在密钥环随机密钥。钥匙长度key_len是由相关的标识符_ ID的密钥user_id。的类型和长度的值必须是由下面的钥匙圈插件支持的价值观一致。看到第6.5.4.7,“支持Keyring Key Types”

    语法:

    bool my_key_generate(const char *key_id, const char *key_type,
                         const char *user_id, size_t key_len)
    

    争论:

    • key_iduser_id:null结尾的字符串,一对一形式要生成的密钥的唯一标识符。

    • key_type:一个空结束的字符串,提供关键的附加信息。

    • key_len:在关键的字节大小是产生。

    返回值:

    返回0成功,1失败

  • my_key_remove()

    删除从钥匙圈钥匙

    语法:

    bool my_key_remove(const char *key_id, const char* user_id)
    

    争论:

    • key_iduser_id:null结尾的字符串,一对一形式要删除关键的唯一标识符。

    返回值:

    返回0成功,1失败

  • my_key_store()

    混淆和存储在密钥环的关键。

    语法:

    bool my_key_store(const char *key_id, const char *key_type,
                      const char* user_id, void *key, size_t key_len)
    

    争论:

    • key_iduser_id:null结尾的字符串,一对一形式被存储密钥的唯一标识符。

    • key_type:一个空结束的字符串,提供关键的附加信息。

    • key:将含有关键数据的缓冲区。

    • key_len字节:in the size of the钥匙缓冲区

    返回值:

    返回0成功,1失败

28.4添加新的功能到MySQL

有MySQL添加新功能方面:

创建编译功能,每种方法都有优点和缺点:

  • 如果你写的自定义函数,你必须除了服务器本身安装目标文件。如果你编译你的功能分为服务器,你不需要这么做。

  • 本机函数需要修改源分布。udf不。您可以添加UDF二进制MySQL分布。没有访问MySQL源是必要的。

  • 如果你升级你的MySQL分发,您可以继续使用以前安装的UDF,除非你升级到新版本的UDF接口的变化。原生功能,你必须重复你的修改,你每次升级。

不管你用什么方法来增加新的功能,他们可以调用SQL语句就像本地等功能ABS()SOUNDEX()

看到9.2.4节,“函数名称解析和解决”,用于描述服务器如何解释不同类型的函数的引用规则。

以下各节描述UDF接口的特点,为写作提供UDFs的指示,讨论安全措施,以防止MySQL UDF的误用,并描述如何添加本地MySQL功能。

例如,源代码说明了如何写UDFs,看看sql/udf_example.cc文件在MySQL源分布。

笔记

MySQL的源代码包含内部文件写入使用Doxygen。本文档是有用的了解MySQL从开发者的角度是如何工作的。它的内容是在生成http://dev.mysql.com / DOC / dev / / /最新的MySQL服务器。它也可以从本地一个使用说明,在MySQL源分布生成的内容第2.8.7,“生成MySQL doxygen文档内容”

的用户定义的函数接口28.4.1特征

用户自定义函数mysql接口提供以下功能和能力:

  • 函数可以返回字符串,整数,或真正的价值和可接受相同类型的参数。

  • 你可以定义简单的功能操作,单排一次,或聚合函数操作的行组。

  • 信息提供功能,使他们能够检查的数量,类型,和参数传递给他们的名字。

  • 你可以告诉MySQL来要挟个参数传递给一个函数在给定的类型。

  • 你可以表明一个函数返回NULL或者说出现了一个错误。

28.4.2添加一个新的用户定义的函数

对于UDF的工作机制、功能必须使用C或C和你的操作系统必须支持动态加载。MySQL源分布包括一个文件sql/udf_example.cc五UDF函数定义。参照这个文件看看UDF调用约定的工作。这个包括_ com.h / MySQL头文件定义UDF相关符号和数据结构,虽然你不需要包含该头文件,它包括直接;mysql.h

UDF包含代码,成为正在运行的服务器的一部分,所以当你写一个UDF,你受任何约束,适用于写服务器代码绑定。例如,您可能在您尝试使用的功能从有问题libstdc++图书馆这些限制可能在未来版本的服务器,因此服务器升级将需要修改UDF原本老服务器写。有关这些限制的信息,参见2.8.4”部分,MySQL源配置选项”,和第2,“处理编译MySQL”问题

能够使用UDF,你必须链接mysqld动态。如果你想使用UDF需要访问符号mysqld(例如,在metaphone功能SQL / udf_example.cc使用default_charset_info),你必须链接程序-电路动态(见man dlopen

每个函数要使用SQL语句,你应该定义相应的C(或C)功能。在下面的讨论中,这个名字XXX用于实例的函数名称。区分SQL和C / C使用之间,XXX()(大写)表示一个SQL函数调用,并(XXX)(小写)表示C / C函数调用。

笔记

当使用C你可以把你的C函数内:

extern "C" { ... }

这将确保你的C函数的名字仍然可在完成UDF。

下面的列表描述了C / C函数,你写来实现接口功能命名XXX()。主要功能,(XXX),是必需的。此外,UDF需要在这里描述的其他功能的至少一个原因探讨第28.4.2.6,“UDF的安全防范措施”

  • xxx()

    主要功能。这就是函数计算结果。SQL函数的数据类型和C / C函数的返回类型是在这里显示的对应关系。

    SQL类型C / C型
    STRINGchar *
    INTEGERlong long
    REALdouble

    也可以声明一个DECIMAL功能,但目前的值作为字符串返回,所以你应该写的UDF是字符串功能ROW功能未实现

  • xxx_init()

    初始化函数xxx()。如果存在,它可以用于以下用途:

    • 检查参数的数量XXX()

    • 验证参数是所需的类型,或者,告诉MySQL强制参数所需的类型时,主要功能是为。

    • 分配的主要功能所需的任何记忆。

    • 指定结果的最大长度

    • 指定(为REAL功能)结果中小数点的最大数目。

    • 指定是否可以将结果NULL

  • xxx_deinit()

    的deinitialization功能xxx()。如果存在,它应该释放任何内存的初始化函数分配。

当一个SQL语句调用XXX()调用初始化函数,MySQLxxx_init()让它执行所需的任何设置,如参数检查或内存分配。如果xxx_init()返回一个错误,MySQL中止错误消息,不叫主或deinitialization功能的SQL语句。否则,MySQL的电话的主要功能(XXX)每一次行。在处理完所有行之后,MySQL deinitialization函数调用xxx_deinit()因此,它可以执行任何必要的清理。

为聚合函数,就像SUM(),你还必须提供以下功能:

  • xxx_clear()

    重置当前总价值但不插入参数作为一组新的初始总价值。

  • xxx_add()

    添加参数到当前的总价值。

MySQL办理集合UDF如下:

  1. 呼叫xxx_init()让聚合函数分配任何内存需要存储结果。

  2. 根据该表排序GROUP BY表达

  3. 呼叫xxx_clear()第一行中的每一个新的组。

  4. 呼叫xxx_add()对于每一行,属于同一组。

  5. 呼叫xxx()为聚合得到的结果时,组或后最后一排被处理。

  6. 重复步骤3到5,直到所有的行已被处理

  7. 呼叫xxx_deinit()让自由的任何内存分配的UDF。

所有的功能必须是线程安全的。这不仅包括的主要功能,但deinitialization初始化和功能,并通过聚合函数所需的附加功能。这一要求的后果是,不允许分配任何全局变量或静态变量的变化!如果你需要记忆,你应该把它xxx_init()自由的它_ deinit(XXX)

28.4.2.1 UDF调用序列的简单功能

本节描述了您需要定义当你创建一个简单的UDF功能不同。第28.4.2,“添加一个新的用户定义的函数描述的顺序,MySQL,调用这些函数。

xxx()函数必须声明为本部分中所示。注意,返回类型和参数的不同,取决于你是否宣布SQL函数(XXX)返回STRINGINTEGER,或REALCREATE FUNCTION声明:

STRING功能:

char *(UDF _ XXX Init initid *,* _ UDF参数字符串中,结果,unsigned大×长字符串的冰_空字符串误差);

INTEGER功能:

大长(UDF _ xxx Init initid *,* _ UDF参数中,冰_空字符串,字符串误差);

REAL功能:

双(UDF _ xxx Init initid *,* _ UDF参数中,冰_空字符串,字符串误差);

DECIMAL函数返回字符串值和应声明一样字符串功能.ROW功能未实现

初始化和deinitialization功能这样声明:

bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

void xxx_deinit(UDF_INIT *initid);

这个initid参数传递到所有三个功能。它指向一个udf_init结构是用来传达信息的功能之间。这个UDF_INIT结构成员跟着。初始化函数应填写任何成员希望改变。(使用默认的一员,离开它不变。)

  • bool maybe_null

    xxx_init()应设置也许_零1如果(XXX)可以返回NULL。默认值是如果任一参数的声明maybe_null

  • unsigned int decimals

    小数点右边的小数位数。默认值是在传递给主函数的参数的最大数量的小数位数。例如,如果函数是通过1.34一点三四五,和1.3,默认是3,因为一点三四五有3位小数

    对于那些没有固定小数的论点,decimals值设置为31,这是1以上的允许的最大数量的小数DECIMALFLOAT,和DOUBLE数据类型。这是available as the恒定值not_fixed_decmysql_com.h头文件

    decimals值31是用于如例论证FLOATDOUBLE声明没有明确列小数的数量(例如,FLOAT而不是浮(10,3))和浮点常数如1345E-3。它也可以用于字符串和其他nonnumber参数可以在函数转换成数字形式。

    的价值,decimals成员初始化只有默认。它可以改变在函数来反映实际计算。默认值是这样确定的,是用参数的小数最多。如果小数点的数not_fixed_dec即使其中一个论点,即使用价值decimals

  • unsigned int max_length

    最大长度的结果。“违约max_length价值取决于函数的结果类型不同。字符串函数,默认的是最长的长度的争论。整数的函数,默认为21位。真正的功能,默认是13加的小数位数显示initid -&#62;小数。(数字功能,长度包括任何符号或小数点的字符。)

    如果你想返回一个BLOB值,您可以设置max_length对65kb或16MB。这种记忆不分配,但价值决定使用哪个数据类型的使用,如果有需要临时存储的数据。

  • char *ptr

    一个指针,该函数可以用于自己的目的。例如,函数可以使用initid->ptr内存分配他们之间的沟通。xxx_init()要分配内存并将它分配给这个指针:

    initid->ptr = allocated_memory;
    

    进入xxx()_ deinit(XXX),是指initid->ptr使用或释放内存

  • bool const_item

    xxx_init()应设置const_item1如果(XXX)始终返回相同的值,0否则

28.4.2.2 UDF调用序列的聚合函数

本节描述了您需要定义当你创建一个聚合的UDF功能不同。第28.4.2,“添加一个新的用户定义的函数描述的顺序,MySQL,调用这些函数。

  • xxx_reset()

    这个函数被调用时,MySQL发现第一排在一个新的组。要重置任何内部总结变量,然后利用给定的UDF_ARGS参数为集团在内部总结价值的第一价值。声明xxx_reset()如下:

    void xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
                   char *is_null, char *error);
    

    xxx_reset()不需要用MySQL 5.0,其中UDF接口使用xxx_clear()相反。然而,你可以定义xxx_reset()xxx_clear()如果你想使用旧版本的服务器有你的UDF的工作。(如果你有功能的xxx_reset()在许多情况下,可以通过调用内部函数实现xxx_clear()将所有的变量,然后调用xxx_add()添加UDF _ args参数组中的第一个值。)

  • xxx_clear()

    这个函数被调用时,MySQL需要复位的汇总结果。它是在每一个新的集团开始叫但也可以称为重置查询有没有匹配的行的值。声明xxx_clear()如下:

    暴力_(UDF)xxx Init _ initid char * *,冰_空字符串误差);

    is_null设置点字符(0)在调用xxx_clear()

    如果事情出错了,你可以将值存储在变量中error论据错误指向一个单字节变量,而不是一个字符串缓冲区。

    xxx_clear()是以MySQL为要求。

  • xxx_add()

    这个功能被称为所有属于同一组的行。你应该使用它的附加价值UDF_ARGS摘要从你的内部变量

    暴力_ add(xxx Init initid UDF _ *,* _ UDF参数中,冰_空字符串,字符串误差);

这个xxx()一个总的UDF函数的声明应该以同样的方式作为一个非聚合的UDF。看到第28.4.2.1,“UDF调用序列的简单功能”

一个总的UDF,MySQL的电话xxx()在该组中的所有行被处理的功能。你通常不应该访问UDF _ args论点在这里而是返回一个值,基于你的内部总结变量。

返回值的处理xxx()应该以同样的方式做为一个非聚合的UDF。看到第28.4.2.4,“UDF返回值和错误处理”

这个xxx_reset()xxx_add()功能处理UDF_ARGS论点同非聚合的UDF功能。看到第28.4.2.3,“UDF参数处理”

指针参数is_null错误是相同的所有电话xxx_reset()xxx_clear()xxx_add()(XXX)。你可以用这个来记住你有错误或是xxx()函数应该返回无效的。你不应该存储字符串*error错误指向一个单字节变量,而不是一个字符串缓冲区。

*is_null为每个组复位(前称xxx_clear()*error不复位

如果*is_null*错误时设置xxx()返回,MySQL返回无效的作为结果的集团功能

28.4.2.3 UDF参数处理

这个args参数指向的UDF _ args结构,这里列出的成员:

  • unsigned int arg_count

    参数个数。检查这个值在初始化函数,如果你需要你的函数被称为与一个特定的参数数目。例如:

    if (args->arg_count != 2)
    {
        strcpy(message,"XXX() requires two arguments");
        return 1;
    }
    

    其他UDF_ARGS这是数组成员的值,数组是从零开始的。即指阵列成员使用索引值为0→Arg _ count参数?1

  • enum Item_result *arg_type

    一个指针指向一个数组包含每个实参的类型。可能的类型值STRING_RESULTint_resultREAL_RESULT,和decimal _ result

    确保参数的给定的类型和返回一个错误,如果不是,检查arg_type在初始化函数数组。例如:

    if (args->arg_type[0] != STRING_RESULT ||    args->arg_type[1] != INT_RESULT){    strcpy(message,"XXX() requires a string and an integer");    return 1;}

    参数类型DECIMAL_RESULT是以字符串的形式传递的,所以你应该把他们一样_ result string价值观

    作为一种替代需要你的函数的参数是特定的类型,你可以使用初始化函数来设置arg_type元素到你想要的类型。这会导致MySQL强制参数的类型的每个电话(XXX)。例如,指定第一个参数应该强制为字符串和整数,分别在做这个xxx_init()

    args->arg_type[0] = STRING_RESULT;args->arg_type[1] = INT_RESULT;

    精确值小数参数如1.3DECIMAL列值传递一个类型decimal _ result。然而,该值都是字符串。如果你想得到一个号码,使用初始化函数来指定应该被强制转换为一个REAL_RESULT价值:

    args->arg_type[2] = REAL_RESULT;
  • char **args

    args->args将信息传达给有关传递给函数的参数的初始化函数的一般性质。一个常数Iargs->args[i]点的参数值。(见稍后说明如何访问值正常。)对于一个非恒定的说法,args -&#62;参数[我]0。一个恒定的参数是一个表达式,只使用常数,如4*7-2SIN(3.14)。一个非常数的参数是一个指向的值可以改变从一排排的表达,如列名称或函数,称为不定参数。

    每次调用主函数,args->args包含传递给该行目前正在处理的实际参数。

    如果参数i代表无效的args->args[i]是一个空指针(0)。如果参数不是无效的,功能可以参考如下:

    • 类型STRING_RESULT给出一个字符串指针加一个长度,使任意长度的二进制数据或数据处理。字符串的内容,可作为args -&#62;参数[我]和字符串的长度args->lengths[i]。不要认为NULL结尾的字符串。

    • 一个参数的类型INT_RESULT,你必须投args -&#62;参数[我]一个long long价值:

      long long int_val;int_val = *((long long*) args->args[i]);
    • 一个参数的类型REAL_RESULT,你必须投args -&#62;参数[我]一个double价值:

      double    real_val;real_val = *((double*) args->args[i]);
    • 一个参数的类型DECIMAL_RESULT,的值作为一个字符串和要处理像_ result string价值

    • ROW_RESULT争论是没有实现

  • unsigned long *lengths

    为初始化函数,这lengths数组表示每个参数的字符串最大长度。你不能改变这些。每次调用主函数,长度包含,通过行目前正在处理的任何字符串参数的实际长度。参数类型INT_RESULT_实际结果lengths还含有参数的最大长度(如初始化函数)。

  • char *maybe_null

    为初始化函数,这maybe_nullRay Indicated for each argument whether the argument value might be nll(0 if no,1 if I ES).

  • char **attributes

    args->attributescommunicates信息(名称《题元的UDF。争论的I,属性名可以作为一个字符串args->attributes[i]和属性长度args -&#62; attribute_lengths [我]。不要认为NULL结尾的字符串。

    默认情况下,一个UDF参数的名称是用于指定参数的文本表达。对于UDFs,争论也可能有一个可选的[AS] alias_name条款,在这种情况下,参数的名称alias_name。这个属性值为每个参数从而取决于别名了。

    假设一个UDFmy_udf()调用如下:

    我的_ UDF(expr1的选择,你alias1 expr2,expr3 alias2);

    在这种情况下,的attributes属性_长将这些值的数组:

    args->attributes[0] = "expr1"
    args->attribute_lengths[0] = 5
    
    args->attributes[1] = "alias1"
    args->attribute_lengths[1] = 6
    
    args->attributes[2] = "alias2"
    args->attribute_lengths[2] = 6
    
  • unsigned long *attribute_lengths

    这个attribute_lengths数组表示每个参数名称的长度。

28.4.2.4 UDF返回值和错误处理

初始化函数应该返回0如果没有错误发生另有。【中文解释】:误差xxx_init()要存储一个空终止错误信息的消息参数.消息返回给客户端。消息缓冲区MYSQL_ERRMSG_SIZE字符,但你要尽量保持信息不超过80个字符,它符合标准的终端屏幕的宽度。

main函数的返回值xxx()is the function value,for很长很长double功能.字符串函数应该返回一个指针的结果集*长度的长度(以字节为单位)的返回值。例如:

memcpy(result, "result string", 13);
*length = 13;

MySQL通过缓冲区的xxx()函数的使用结果参数.这个缓冲区是足够长的有255字,可多字节字符。这个xxx()函数可以将结果存储在该缓冲区是否合适,在这种情况下,返回值应该是一个指向缓冲区。如果函数在不同的缓冲存储的结果,它应该返回一个指针,缓冲区。

如果你的字符串函数不使用提供的缓冲区(例如,如果需要返回一个字符串的长度超过255个字符),你必须把你自己的缓冲空间malloc()在你的xxx_init()功能或你xxx()在你的功能和自由吧_ deinit(XXX)功能。你可以存储在内存的分配ptr槽中udf_init利用未来的结构xxx()电话.看到第28.4.2.1,“UDF调用序列的简单功能”

表示一个返回值NULL在主函数中,设置* is_null1

*is_null = 1;

表明在主函数返回错误,设置*error

*error = 1;

如果xxx()套装*错误1任何连续函数值无效的当前行和任何后续行的语句处理XXX()被援引。((XXX)甚至没有为后面的行。)

28.4.2.5 UDF编译和安装

文件实现UDF必须编译和安装在服务器运行的主机。这一过程描述如下的UDF文件sql/udf_example.cc这是包含在MySQL源分布。

如果UDF将在陈述将被复制到从服务器,您必须确保每一个奴隶也有功能。否则,复制将失败的奴隶,当他们试图调用函数。

紧随其后的是UNIX指令。说明了在本节后面的窗户。

这个udf_example.cc文件包含以下功能:

  • metaphon()返回一个字符串参数metaphon字符串。这有点像一个模糊的字符串,但它更多的是关注英语。

  • myfunc_double()返回其参数的字符的ASCII值的总和,除以其参数的长度的总和。

  • myfunc_int()返回其参数的长度的总和。

  • sequence([const int])返回一个序列从给定的数字或1如果没有号了。

  • lookup()返回一个主机名的IP地址。

  • reverse_lookup()一个IP地址返回主机名。该函数可以被任何一个单一形式的字符串参数“XXX,XXX,XXX,XXX”或用四号

  • avgcost()返回一个平均成本。这是一个聚合函数。

一个动态加载的文件应该被编译为一个可共享的库文件,使用命令这样的事情:

shell> gcc -shared -o udf_example.so udf_example.cc

如果你使用的是GCCCMake(这是MySQL如何配置),你应该能够创造udf_example.so一个简单的命令:

内核make udf_example

当你编译一个共享对象包含UDFs,你必须安装它并告诉MySQL呢。编译一个共享对象udf_example.cc使用GCC直接生成一个文件名为udf_example.so。复制共享对象服务器的插件目录和名称udf_example.so。这个目录是由给定的值plugin_dir系统变量

在一些系统上的要想程序配置动态链接器不能识别共享对象,除非它的名字开始lib。在这种情况下你应该重命名文件等udf_example.solibudf_example.so

在Windows中,您可以编写自定义函数通过使用下面的过程:

  1. 从神秘来源分发。见2.1.2节,“如何让MySQL”

  2. 获得CMake如果必要,从构建工具,http://www.cmake.org。(要求版本2.6或更高)。

  3. 在源代码树,看在sql目录有文件命名udf_example.defudf_example.cc那里。复制文件从这个目录到你的工作目录。

  4. 创建一个CMakemakefileCMakeLists.txt这些内容):

    PROJECT(udf_example)
    
    # Path for MySQL include directory
    INCLUDE_DIRECTORIES("c:/mysql/include")
    
    ADD_DEFINITIONS("-DHAVE_DLOPEN")
    ADD_LIBRARY(udf_example MODULE udf_example.cc udf_example.def)
    TARGET_LINK_LIBRARIES(udf_example wsock32)
    
  5. 建立风险投资项目和解决方案文件:

    cmake -G "<Generator>"
    

    调用的帮助列出有效的发电机

  6. 创造udf_example.dll

    中udf_example.sln /版本发布

在共享库文件已经安装的通知mysqld关于新功能与下面的语句。如果有一个不同的库文件后缀.so在你的系统上,替代正确的后缀(例如在,dll在线的Windows)。

mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME 'udf_example.so';
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME 'udf_example.so';
mysql> CREATE FUNCTION sequence RETURNS INTEGER SONAME 'udf_example.so';
mysql> CREATE FUNCTION lookup RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE FUNCTION reverse_lookup
    ->        RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE AGGREGATE FUNCTION avgcost
    ->        RETURNS REAL SONAME 'udf_example.so';

一旦安装,功能仍然是卸载安装。

删除功能,使用DROP FUNCTION

MySQL的&#62;DROP FUNCTION metaphon;MySQL的&#62;DROP FUNCTION myfunc_double;MySQL的&#62;DROP FUNCTION myfunc_int;MySQL的&#62;DROP FUNCTION sequence;MySQL的&#62;DROP FUNCTION lookup;MySQL的&#62;DROP FUNCTION reverse_lookup;MySQL的&#62;DROP FUNCTION avgcost;

这个CREATE FUNCTIONDROP FUNCTION报表更新功能在系统表mysql数据库函数的名称、类型和共享库的名字保存在表。你必须有INSERTDELETE特权的MySQL数据库创建或删除功能,分别。

你不应该使用CREATE FUNCTION添加一个函数之前已创建。如果你需要重新安装一个功能,你应该删除它DROP FUNCTION然后重新安装它CREATE FUNCTION。你需要这样做,例如,如果你编译你的功能的新版本,所以mysqld我们的新版本。否则,这两个服务器继续使用旧版本。

一个积极的作用是加载了CREATE FUNCTION而不是删除DROP FUNCTION。所有活动的功能是加载每次服务器启动,除非你开始mysqld--skip-grant-tables选项在这种情况下,自定义初始化跳过和UDFs都不可用。

28.4.2.6 UDF的安全预防措施

MySQL采取几个措施防止用户定义函数的误用。

UDF库文件不能放在任意目录。他们必须位于服务器的插件目录。这个目录是由给定的值plugin_dir系统变量

使用CREATE FUNCTIONDROP FUNCTION,你必须有INSERTDELETE特权,分别为MySQL数据库这是必要的因为这些报表添加和删除行mysql.func

UDFs至少要有一个符号除了定义xxx符号对应于主(XXX)功能。这些辅助符号对应的xxx_init()_ deinit(XXX)xxx_reset()xxx_clear(),和xxx_add()功能.mysqld还支持--allow-suspicious-udfs选项控制是否只有一个UDFXXX符号可以被加载。默认情况下,这个选项是关闭的,以防止在加载功能的共享库文件以外的其他合法的UDF尝试含。如果你有旧的UDF只包含xxx符号和不能重新编译包括辅助符号,它可能需要指定--allow-suspicious-udfs选项否则,你应该避免使用这种能力。

28.4.3添加一个新的原生功能

添加一个新的本地MySQL的函数,使用这里介绍的方法,这就需要你使用源分布。您不能添加本地功能的二进制分布,因为它是必要的修改MySQL的源代码和修改后的源代码编译MySQL。如果你迁移到另一个版本的MySQL(例如,当一个新的版本发布),必须用新版本重复的程序。

如果新的原生功能将在陈述将被复制到从服务器,您必须确保每个从属服务器还具有功能可用。否则,复制将失败的奴隶,当他们试图调用函数。

添加一个新的原生功能,遵循这些步骤来修改源文件sql目录

  1. 创建一个类的子类中的函数item_create.cc

    • 如果函数需要一个固定数量的参数,创建一个类Create_func_arg0create_func_arg1Create_func_arg2,或create_func_arg3,分别取决于函数零,一,二,三参数。例如,看Create_func_uuidcreate_func_absCreate_func_pow,和create_func_lpad分类

    • 如果函数的参数个数可变的,创建一个类Create_native_func。例如,看create_func_concat

  2. 提供的功能可以被称为SQL语句中的名称,登记的名称item_create.cc通过增加一个线阵列:

    静态native_func_registry func_array [ ]

    你可以登记为同一函数的几个名字。例如,看线"LCASE"“低”,这是别名Create_func_lcase

  3. 进入item_func.h,声明一个类继承_ item num _函数Item_str_func,这取决于你的函数返回一个数或一个字符串。

  4. 进入item_func.cc,添加下面的一个声明,这取决于你定义的数值或字符串函数:

    双_ Item函数的名称:_ VAL()函数的_ _隆龙item的名称:_:val(int *)_ item字符串的名称:_函数str():string str)

    如果你继承了你的对象从任何标准的项目(如Item_num_func),你可能只需要定义一个这些功能让父对象照顾其他功能。例如,在item_str_func类定义了一个val()执行的函数(织)在返回的值::str()

  5. 如果函数是不确定的,包括以下语句在item构造函数表明功能的结果不应该被缓存:

    current_thd->lex->safe_to_cache_query=0;
    

    一个函数是不确定的如果,给出其参数固定的值,它可以返回不同的调用不同的结果。

  6. 你可能也应该定义以下目标函数:

    void Item_func_newname::fix_length_and_dec()
    

    这个函数应该至少计算max_length基于给定的参数max_length是函数的最大字符数可能会返回。此功能还应设置maybe_null = 0如果主函数不能返回无效的价值。该功能可以检查是否有任何参数的函数可以返回NULL通过检查参数也许_零变量。看看Item_func_mod::fix_length_and_dec对于一个典型的例子,该怎么做。

所有的功能必须是线程安全的。换句话说,不要在函数中使用任何全局变量或静态变量,而不使用互斥保护他们。

如果你想返回NULLVal()::val_int(),或页::(),你应该设置null_value1和0的回报

::str()对象的功能,有需要注意的其他注意事项:

  • 这个String *str参数提供一个字符串缓冲区,可以用来保存结果。(有关更多信息字符串式,看一看sql_string.h文件。)

  • 这个::str()函数返回包含结果的字符串,或(char *)0如果结果是NULL

  • 目前所有的字符串函数尽量避免分配任何内存除非绝对必要!

调试和移植MySQL 28.5

这部分有助于你端口MySQL其它操作系统。先做检查,目前支持的操作系统列表。看到http://www.mysql.com/support/supportedplatforms/database.html。如果你已经创建了一个新的港口,mysql,请让我们知道,我们可以把它列在这里和我们的网站(www.mysql.com http:/ / /),推荐给其他用户

笔记

如果你创建一个新的端口MySQL,您可以自由复制和分发GPL许可下,但这并不会让你的MySQL版权持有人。

一个使用POSIX线程库是服务器需要。

从源代码构建MySQL,你的系统必须满足上市要求的工具2.8节,从“源”安装MySQL

如果你遇到一个新的端口的问题,你可能需要做一些调试MySQL!看到第28.5.1,调试一个MySQL服务器”

笔记

在你开始调试mysqld,先测试程序mysys/thr_lock工作。这将确保你的螺纹安装甚至远程工作的机会!

笔记

MySQL的源代码包含内部文件写入使用Doxygen。本文档是有用的了解MySQL从开发者的角度是如何工作的。它的内容是在生成http://dev.mysql.com / DOC / dev / / /最新的MySQL服务器。它也可以从本地一个使用说明,在MySQL源分布生成的内容第2.8.7,“生成MySQL doxygen文档内容”

28.5.1调试一个MySQL服务器

如果你正在使用的一些功能,MySQL很新,你可以尝试运行mysqld--skip-new(禁用所有新的,潜在的不安全的功能)。看到第b.5.3.3,“做什么如果MySQL总是死机”

如果mysqld不想开始,确认你没有my.cnf干扰你的安装文件!你可以检查你的my.cnf争论mysqld --打印默认值避免使用它们开始mysqld没有违约…

如果mysqld开始吃CPU或内存或如果它挂,你可以使用mysqladmin processlist状态发现如果有人执行一个查询,需要很长的时间。它可能运行的是一个好主意mysqladmin - I processlist状态在一些窗口,如果您遇到性能问题或问题时,新的客户端无法连接。

命令mysqladmin调试把一些关于锁的使用,用于存储和查询使用MySQL的日志文件。这可能有助于解决一些问题。该命令还提供了一些有用的信息,即使你没有编译MySQL的调试!

如果问题在于有些表越来越慢你应该尝试优化表OPTIMIZE TABLEmyisamchk。看到5章,MySQL服务器管理。你也应该检查慢查询EXPLAIN

你也应该阅读本手册中的操作系统特定的部分,可能是你的环境的独特问题。看到2.1节,“一般安装指导”

28.5.1.1编译MySQL的调试

如果你有一些非常具体的问题,你总是可以尝试调试MySQL。你必须与配置MySQL-DWITH_DEBUG=1选项您可以检查是否MySQL调试通过编译:mysqld的帮助。如果--debug国旗是上市的选项,那么你就启用调试。mysqladmin世界还列出了mysqld版本MySQL——调试在这种情况下

如果mysqld停止崩溃当你配置的-DWITH_DEBUG=1C选项,你可能发现一个编译错误或定时错误在mysql。在这种情况下,你可以尝试添加G使用CMAKE_C_FLAGSCMAKE_CXX_FLAGSC选项不使用-DWITH_DEBUG=1。如果mysqld死了,你至少可以附加到它GDB或使用GDB在发现真相的核心文件。

当你配置MySQL调试你自动地使很多额外的安全检查功能,监测健康mysqld。如果他们找到的东西意外,写的是一个入门stderr,这_ mysqld safe针对错误日志!这也意味着,如果你有一些意想不到的问题,使用的是MySQL的源分布,你应该做的第一件事就是配置MySQL调试!(二是发送邮件到MySQL邮件列表和请求帮助。看到第1.6.2,MySQL邮件列表”。如果你认为你已经发现了一个bug,请使用说明7节,“如何报告错误或问题”

在Windows MySQL分布,mysqld.exe默认为跟踪文件编译支持。

28.5.1.2创建跟踪文件

如果mysqld服务器无法启动或死机,你可以尝试创建一个跟踪文件发现问题。

要做到这一点,你必须有一个mysqld已经编译调试支持。你可以通过执行mysqld -V。如果版本号结束调试,它与跟踪文件编译支持。(在Windows,调试服务器命名mysqld调试而不是mysqld。)

启动mysqld一个跟踪日志服务器/tmp/mysqld.trace在Unix或“mysqld.trace在Windows:

shell> mysqld --debug

在Windows中,应该使用--standalone无法启动标志mysqld作为一个服务。在控制台窗口中,使用此命令:

C:\> mysqld-debug --debug --standalone

在这之后,你可以使用mysql.exe命令行工具在二控制台窗口重现问题。你可以停止mysqld服务器关闭

跟踪文件可以成为非常大的!产生一个较小的跟踪文件,您可以使用调试选项,这样的事情:

mysqld --debug=d,info,error,query,general,where:O,/tmp/mysqld.trace

这只打印信息与最有趣的标签来跟踪文件。

如果你做一个关于这个bug报告,请只把线从跟踪文件到相应的邮件列表里的东西似乎走错了!如果您无法找到错误的地方,你可以打开一个bug报告和上传跟踪文件的报告,所以MySQL开发者可以看看吧。有关说明,见7节,“如何报告错误或问题”

跟踪文件是用包被Fred Fish。看到第28.5.3,“该计划”

28.5.1.3使用WER与PDB创建一个Windows故障转储

程序数据库文件(后缀pdb)都包括在zip文件调试二进制文件和测试套件分布的MySQL。这些文件,在出现问题时调试你的MySQL安装提供信息。这是一个单独的下载标准MSI或zip文件。

笔记

PDB文件都可以在一个单独的文件标记为“ZIP文件调试的二进制文件和测试套件”。

PDB文件包含有关更详细的信息mysqld和其他工具,使更详细的跟踪和转储文件被创建。你可以用这些WinDbg或Visual Studio调试mysqld

在PDB文件的更多信息,参见微软知识库文章121366。在调试选项的更多信息,参见调试工具

使用windbg,要么安装完整的Windows驱动程序工具包(WDK)或安装单机版。

重要

这个.exePBD文件必须完全匹配(版本号和MySQL服务器版)或WinDBG会抱怨当试图加载符号。

  1. 生成一个转储mysqld.dmp,使core-file选择【mysqld】节下my.ini。进行这些更改之后,重新启动MySQL服务器。

  2. 创建一个目录来保存生成的文件,如c:\symbols

  3. 确定你的路径windbg.exe可使用查找GUI或命令行,例如:dir /s /b windbg.exe这是一种常见的默认C:\程序文件\ Windows调试工具(x64)\ windbg.exe

  4. 发射windbg.exe给它的路径mysqld.exemysqld.pdbmysqld.dmp,和源代码。另外,通过在每个路径从windbg的GUI。例如:

    
    windbg.exe -i "C:\mysql-8.0.14-winx64\bin\"^
     -z "C:\mysql-8.0.14-winx64\data\mysqld.dmp"^
     -srcpath "E:\ade\mysql_archives\8.0\8.0.14\mysql-8.0.14"^
     -y "C:\mysql-8.0.14-winx64\bin;SRV*c:\symbols*http://msdl.microsoft.com/download/symbols"^
     -v -n -c "!analyze -vvvvv"
    
    
    笔记

    这个^字符和换行符被Windows命令行处理器移除,所以一定的空间保持完整。

28.5.1.4 mysqld在GDB调试

在大多数系统中还可以启动mysqldGDB为了得到更多的信息,如果mysqld崩溃

一些年长的GDB你必须使用Linux版本run --one-thread如果你想能够调试mysqld螺纹。在这种情况下,你只能有一个线程在一个时间活动。这是最好的升级GDB5.1因为线程调试工作更好的版本!

NPTL线程(Linux新线程运行时库)可能引起的问题mysqld在下面GDB。一些症状:

  • mysqld挂在启动过程中(在写之前ready for connections

  • mysqld坠毁在一pthread_mutex_lock()pthread_mutex_unlock()呼叫

在这种情况下,你应该设置以下在SHELL环境变量开始之前GDB

LD_ASSUME_KERNEL=2.4.1
export LD_ASSUME_KERNEL

当运行mysqld在下面GDB,你应该禁用堆栈跟踪--skip-stack-trace能够抓住这种错误在GDB

使用--gdb选项mysqld安装一个中断处理程序SIGINT(需要停止mysqld^C设置断点)和禁用堆栈跟踪和核心文件处理。

这是很难调试MySQL下GDB如果你做了大量的时间为新的连接GDB不自由的记忆旧螺纹。你可以通过避免这个问题mysqldthread_cache_size设置为等于max_connections1.。只使用在大多数情况下--thread_cache_size=5'有很大的帮助!

如果你想在Linux核心转储如果mysqld一个SIGSEGV信号消失,你就可以开始mysqld--core-file选项这个核心文件可以用来做一个回溯,可以帮助你找出为什么mysqld死亡:

shell> gdb mysqld core
gdb>   backtrace full
gdb>   quit

看到第b.5.3.3,“做什么如果MySQL总是死机”

如果你使用的是GDB4.17。X或以上Linux,你应该安装一个.gdb文件,下面的信息,在你的当前目录:

设置打印sevenbit offhandle SIGUSR1不停不停不停的noprinthandle SIGUSR2 noprinthandle sigwaiting noprinthandle siglwp不停的noprinthandle sigpipe nostophandle SIGALRM信号nostophandle SIGHUP nostophandle SIGTERM路思拓NOPRINT

如果你有问题的调试线程GDB,你应该下载GDB 5. x,试着。新的GDB版本已经非常改进线程处理!

这里有一个例子如何调试mysqld

shell> gdb /usr/local/libexec/mysqld
gdb> run
...
backtrace full # Do this when mysqld crashes

包括前面的输出在一个bug报告,你可以使用说明文件7节,“如何报告错误或问题”

如果mysqld挂,你可以尝试使用一些系统工具strace/ usr / proc /斌/ pstack检查mysqld挂了

strace /tmp/log libexec/mysqld

如果您使用的是PerlDBI接口,你可以打开调试信息的利用追踪方法或通过设置DBI_TRACE环境变量

28.5.1.5使用堆栈跟踪

在一些操作系统错误日志包含堆栈跟踪如果mysqld意外死亡。你可以用这个找到了(也许吧)mysqld死亡.看到5.4.2部分,“错误日志”。获取堆栈跟踪,你必须不能编译mysqld-fomit-frame-pointer选择GCC。看到第28.5.1.1,编译调试MySQL

在错误日志中的堆栈跟踪看起来像这样:

mysqld got signal 11;
Attempting backtrace. You can use the following information
to find out where mysqld died. If you see no messages after
this, something went terribly wrong...

stack_bottom = 0x41fd0110 thread_stack 0x40000
mysqld(my_print_stacktrace+0x32)[0x9da402]
mysqld(handle_segfault+0x28a)[0x6648e9]
/lib/libpthread.so.0[0x7f1a5af000f0]
/lib/libc.so.6(strcmp+0x2)[0x7f1a5a10f0f2]
mysqld(_Z21check_change_passwordP3THDPKcS2_Pcj+0x7c)[0x7412cb]
mysqld(_ZN16set_var_password5checkEP3THD+0xd0)[0x688354]
mysqld(_Z17sql_set_variablesP3THDP4ListI12set_var_baseE+0x68)[0x688494]
mysqld(_Z21mysql_execute_commandP3THD+0x41a0)[0x67a170]
mysqld(_Z11mysql_parseP3THDPKcjPS2_+0x282)[0x67f0ad]
mysqld(_Z16dispatch_command19enum_server_commandP3THDPcj+0xbb7[0x67fdf8]
mysqld(_Z10do_commandP3THD+0x24d)[0x6811b6]
mysqld(handle_one_connection+0x11c)[0x66e05e]

如果为跟踪功能名称解析失败,微量含有较少的信息:

mysqld got signal 11;
Attempting backtrace. You can use the following information
to find out where mysqld died. If you see no messages after
this, something went terribly wrong...

stack_bottom = 0x41fd0110 thread_stack 0x40000
[0x9da402]
[0x6648e9]
[0x7f1a5af000f0]
[0x7f1a5a10f0f2]
[0x7412cb]
[0x688354]
[0x688494]
[0x67a170]
[0x67f0ad]
[0x67fdf8]
[0x6811b6]
[0x66e05e]

在后一种情况下,你可以使用resolve_stack_dump实用工具来确定mysqld使用以下过程死了:

  1. 拷贝数从堆栈跟踪到一个文件中,例如mysqld.stack。数字不包括周围的括号:

    0x9da4020x6648e90x7f1a5af000f00x7f1a5a10f0f20x7412cb0x6883540x6884940x67a1700x67f0ad0x67fdf80x6811b60x66e05e
  2. 为使符号文件mysqld服务器:

    shell> nm -n libexec/mysqld > /tmp/mysqld.sym
    

    如果mysqld不是静态的链接,使用下面的命令来:

    shell> nm -D -n libexec/mysqld > /tmp/mysqld.sym
    

    如果你想解码C符号,使用--demangle如果可以的话,去,nm。如果你的版本nm没有此选项,您将需要使用C滤波在堆栈转储产生了对C的名字demangle选项命令。

  3. 执行以下命令:

    shell> resolve_stack_dump -s /tmp/mysqld.sym -n mysqld.stack
    

    如果你不能够有demangled C的名字在你的符号文件,过程resolve_stack_dump输出使用C滤波

    shell> resolve_stack_dump -s /tmp/mysqld.sym -n mysqld.stack | c++filt
    

    这件事在哪里mysqld死亡.如果不帮助你找出为什么mysqld死了,你应该创建一个bug报告,包括从上述命令的bug报告的输出。

    然而,在大多数情况下,它不会帮助我们刚刚堆栈跟踪寻找问题的原因。能够找到错误或提供解决方案,在大多数情况下,我们需要知道的声明,杀mysqld最好是一个测试案例,我们可以重复的问题!看到7节,“如何报告错误或问题”

新版本的glibc堆栈跟踪功能还可以打印地址相对于对象。打开(放)glibc系统(Linux),在一个插件崩溃的迹像:

plugin/auth/auth_test_plugin.so(+0x9a6)[0x7ff4d11c29a6]

翻译的相对地址(+0x9a6)为文件名和行号,使用此命令:

内核addr2line -fie auth_test_plugin.so 0x9a6auth_test_pluginmysql-trunk /插件/认证/ test_plugin。C:65

这个阿德勒线实用性binutils包在Linux

在Solaris中,过程类似。Solarisprintstack()已打印的相对地址:

插件/认证/ auth_test_plugin。所以:0x1510

翻译,使用此命令:

shell> gaddr2line -fie auth_test_plugin.so 0x1510
mysql-trunk/plugin/auth/test_plugin.c:88

Windows已经打印地址,函数名和线:

000007FEF07E10A4 auth_test_plugin.dll!auth_test_plugin()[test_plugin.c:72]

28.5.1.6使用服务器日志中找到错误的原因在mysqld

注意,在开始mysqld与一般查询日志功能,你应该检查你的表myisamchk。看到5章,MySQL服务器管理

如果mysqld死亡或挂起,你应该开始mysqld与一般查询日志功能。看到5.4.3节,“通用查询日志”。什么时候mysqld死了,你可以查看日志文件的查询,最终死亡mysqld

如果您使用默认的通用查询日志文件,日志存储在数据库目录host_name.log在大多数情况下它是在日志文件中,杀死了最后一个查询mysqld,但如果可能的话你应该验证通过重新启动mysqld从执行发现查询MySQL命令行工具。如果这个工作,你也应该测试所有复杂的查询,没有完成。

你也可以尝试命令EXPLAIN在所有SELECT报表,需要很长的时间来确保mysqld正确使用索引。看到第13.8.2,”解释语法”

你可以发现,需要很长的时间来执行启动查询mysqld与慢查询日志功能。看到第5.4.5、“慢查询日志”

如果你找到的文本mysqld restarted在错误日志文件(通常称为host_name错误)你可能发现一个查询,原因mysqld失败。如果发生这种情况,你应该检查你的表myisamchk(见5章,MySQL服务器管理),和测试在MySQL日志文件的查询是否失败。如果你找到了这样的一个查询,第一次尝试升级到最新版本的MySQL。如果这没有帮助,你不能在找什么mysql邮件归档,你应该报告bug到MySQL的邮件列表。邮件列表描述了lists.mysql.com http:/ / /,其中也有在线列表档案链接。

如果你已经开始mysqld--myisam-recover-optionsMySQL的自动检查,并试图修复MyISAM表如果他们被标记为&#39;不正常关闭”或“坠毁”。如果发生这种情况,MySQL写在一个条目hostname.err文件“警告:检查表……”这是其次Warning: Repairing table如果桌子需要修理。如果你得到了很多这些错误,没有mysqld在意外死亡之前,那么什么是错的,需要进一步调查。看到第5.1.6、“服务器选项”

当服务器检测MyISAM表损坏,它写的额外信息的错误日志,如源文件的名称和行号和线程访问的表的列表。例子:Got an error from thread_id=1, mi_dynrec.c:368。这是包含在错误报告中的有用信息。

这是不是一个好兆头,如果mysqld没有意外死亡,但在这种情况下,你不应该了解Checking table...的信息,而是找出原因mysqld死亡.

28.5.1.7做试验,如果你经验表损坏

下列程序适用于MyISAM表对要采取的步骤,当遇到信息InnoDB表损坏,看7节,“如何报告错误或问题”

如果你遇到损坏MyISAM表或如果mysqld总是失败后的一些更新语句,您可以测试问题是否是通过做以下重现:

  1. 停止MySQL守护进程关闭

  2. 做一个备份表的防范非常不可能的情况下,修不好的事情。

  3. 检查所有的表myisamchk S / * .myi数据库。修复损坏的表myisamchk R /数据库table。我

  4. 让一个表的第二备份

  5. 删除(或离开)任何旧的日志文件从MySQL数据目录,如果你需要更多的空间。

  6. 开始mysqld与二进制日志功能。如果你想找到一个崩溃mysqld,你应该与一般查询日志启动服务器以及启用。看到5.4.3节,“通用查询日志”,和5.4.4节,“二进制日志”

  7. 当你有了一个撞桌子,停止mysqld服务器

  8. 恢复备份

  9. 重新启动mysqld服务器没有二进制日志功能

  10. 重新执行语句mysqlbinlog二进制日志文件| MySQL。二进制日志保存在MySQL数据库目录的名称hostname-bin.NNNNNN

  11. 如果表损坏,又或者你可以得到mysqld死与上面的命令,你找到了一个可重复的bug。FTP表和二进制日志我们的bug数据库采用了指令7节,“如何报告错误或问题”。如果你是客户,你可以使用MySQL客户支持中心(http:/ / / / www.mysql.com支持)提醒关于问题的MySQL团队并尽快修复。

28.5.2调试MySQL客户端

可以调试一个MySQL客户端的集成调试软件包,你应该配置MySQL-DWITH_DEBUG=1。看到2.8.4”部分,MySQL源配置选项”

运行一个客户之前,你应该设定MYSQL_DEBUG环境变量:

内核MYSQL_DEBUG=d:t:O,/tmp/client.trace内核export MYSQL_DEBUG

这使客户产生一个跟踪文件/tmp/client.trace

如果你有你自己的客户代码的问题,你应该尝试连接服务器和客户端,使用已知的工作运行您的查询。通过运行MySQL在调试模式(假设你已经编译MySQL调试):

shell> mysql --debug=d:t:O,/tmp/client.trace

这提供了有用的信息,如果你的邮件错误报告。看到7节,“如何报告错误或问题”

如果你的客户端崩溃在一些“合法”看代码,你应该检查你的mysql.h包括文件匹配你的MySQL库文件。一个很常见的错误是使用旧的MySQL的从一个新的MySQL库旧的MySQL安装文件。

28.5.3该包的

MySQL服务器和MySQL客户与Fred Fish最初创建该包编译。当你调试配置MySQL,这个包可以获得一个跟踪文件的程序正在做什么。看到第28.5.1.2,“创建跟踪文件”

本节总结了参数值,您可以指定在调试MySQL的程序,已经调试支持基于命令行选项。关于与该软件的编程的更多信息,在看到该手册dbugMySQL源分布目录。最好使用最近的分布得到最新的该手册。

在该包可以通过调用程序的使用--debug[=debug_options]- # [debug_options]选项如果您指定的——调试-#没有一个选项debug_options价值,大多数MySQL程序使用默认值。服务器默认是D:T:我:啊,/甲氧苄啶/ mysqld.trace在UNIX和d:t:i:O,\mysqld.trace我们是WindowsThe effect of this default is:

  • d:使输出所有调试宏

  • t:跟踪函数调用和退出

  • i:添加PID输出线

  • o,/tmp/mysqld.trace哦,对mysqld.trace文件集:调试输出

大部分的客户端程序,使用默认的debug_options价值D:T:啊,/甲氧苄啶/program_name。微量,无论平台

这里有一些例子调试控制字符串作为他们可能在一个shell命令行中指定:

--debug=d:t
--debug=d:f,main,subr1:F:L:t,20
--debug=d,input,output,files:n
--debug=d:t:i:O,\\mysqld.trace

mysqld,也可以在运行时更改该设置,通过设置debug系统变量。这个变量具有全局和会话的值:

MySQL的&#62;SET GLOBAL debug = 'debug_options';MySQL的&#62;SET SESSION debug = 'debug_options';

在运行时需要的变化SYSTEM_VARIABLES_ADMINSUPER特权,甚至在会议上的价值。

这个debug_options价值是一个序列的冒号分隔的字段:

field_1:field_2:…:field_N

在价值的各个领域包括强制性的旗帜人物,前面可以使用+性格和后跟一个逗号分隔的列表中的改性剂:

[+|-]flag[,modifier,modifier,...,modifier]

下表描述了允许的旗帜人物。无法识别的标志字符被忽略。

标志

描述

d

使输出dbug_XXX针对当前国家宏。可能是一个关键字列表,使对该宏的关键字输出。关键词空列表使输出的所有宏。

在MySQL中,常见的调试宏关键词使是enter出口error警告info,和

D

每个调试器输出线后延迟。参数是延迟,在十秒,受设备能力。例如,D,20指定一个延迟两秒

f

极限的调试、跟踪和分析,对命名的函数列表。一个空的列表,使所有功能。适当的dT旗帜仍必须考虑;这个标志只限制他们的行动是否启用。

F

确定每一行的源文件名调试或跟踪输出。

i

确定过程的PID或线程ID为每行调试或跟踪输出。

L

识别源文件行数,每行的调试和跟踪输出。

n

打印当前函数的嵌套深度为每行调试或跟踪输出。

N

每行的调试输出

o

调试器输出流重定向到指定的文件。默认的输出是stderr

O

喜欢o,但文件是真的把彼此之间写的。当需要时,文件被关闭然后重新打开各写。

p

限制指定调试器行动过程。一个过程必须是确定的DBUG_PROCESS在调试器的行为发生的宏观匹配列表。

P

打印当前进程名称为每个线的调试或跟踪输出。

r

把一个新的国家时,没有继承以前的状态函数的嵌套层次。有用时,输出的是从左边开始。

S

做功能_sanity(_file_,_line_)在每个调试功能直到_sanity()返回的东西,不同于0。

t

使函数调用/出口线迹。可能是一个列表(只含有一个修饰)给一个数值最大跟踪级别,超越没有输出发生是调试或跟踪宏。默认编译选项。

领先+性格和尾随列表修饰符是用于标志人物如dF这可以使调试操作所有适用的修饰或只是其中的一部分:

  • 没有领导+,该标志值设置为完全修改列表给出。

  • 与一家领先的+列表中的改性剂,添加或修改列表中的电流。

下面的示例演示如何工作的d标志一个空的D输出列表启用所有调试宏。一个非空的列表,使输出列表中的宏关键词。

这些语句集d要修改列表值了:

MySQL的&#62;SET debug = 'd';MySQL的&#62;SELECT @@debug;--------- | @ @调试| --------- | D>| --------- MySQLSET debug = 'd,error,warning';MySQL的&#62;SELECT @@debug;----------------- | @ @调试| ----------------- | D、错误、警告| -----------------

一个领导+添加或减去从当前d价值:

MySQL的&#62;SET debug = '+d,loop';MySQL的&#62;SELECT @@debug;---------------------- | @ @调试| ---------------------- | D、错误、警告、环| ---------------------- MySQL &#62;SET debug = '-d,error,loop';MySQL的&#62;SELECT @@debug;----------- | @ @调试| ----------- | D,警告| -----------

增加启用所有宏在没有变化的结果:

mysql> SET debug = 'd';
mysql> SELECT @@debug;
+---------+
| @@debug |
+---------+
| d       |
+---------+
mysql> SET debug = '+d,loop';
mysql> SELECT @@debug;
+---------+
| @@debug |
+---------+
| d       |
+---------+

禁用所有宏禁用启用d国旗完全:

MySQL的&#62;SET debug = 'd,error,loop';MySQL的&#62;SELECT @@debug;-------------- | @ @调试| -------------- | D、错误、环| -------------- MySQL &#62;SET debug = '-d,error,loop';MySQL的&#62;SELECT @@debug;--------- | @ @调试| --------- | | ---------