目录
本章介绍了处理MySQL代码时需要了解的许多内容。
要跟踪或促成MySQL开发,请按照
第2.9.3节“使用开发源树安装MySQL”中的说明进行操作
。
如果您对MySQL内部感兴趣,您还应该订阅我们的
internals
邮件列表。
此列表的流量相对较低。
有关如何订阅的详细信息,请参见
第1.6.2节“MySQL邮件列表”
。
Oracle公司的许多MySQL开发人员都在
internals
列表,我们帮助其他正在研究MySQL代码的人。
您可以随意使用此列表来询问有关代码的问题,并发送您想要为MySQL项目贡献的补丁!
MySQL源代码包含使用Doxygen编写的内部文档。 本文档对于从开发人员的角度理解MySQL的工作原理非常有用。 生成的Doxygen内容可从 https://dev.mysql.com/doc/index-other.html获得 。 也可以使用 第2.9.7节“生成MySQL Doxygen文档内容”中 的说明从MySQL源代码分发本地生成此内容 。
MySQL服务器创建以下线程:
连接管理器线程处理服务器侦听的网络接口上的客户端连接请求。 在所有平台上,一个管理器线程处理TCP / IP连接请求。 在Unix上,此管理器线程还处理Unix套接字文件连接请求。 在Windows上,管理器线程处理共享内存连接请求,另一个处理命名管道连接请求。 服务器不会创建线程来处理它不听的接口。 例如,不支持启用命名管道连接的Windows服务器不会创建处理它们的线程。
连接管理器线程将每个客户端连接与专用于它的线程相关联,该线程处理该连接的身份验证和请求处理。 管理器线程在必要时创建一个新线程,但首先通过查询线程缓存来查看它是否包含可用于连接的线程,从而避免这样做。 当连接结束时,如果缓存未满,则将其线程返回到线程缓存。
有关调整控制线程资源的参数的信息,请参见 第8.12.4.1节“MySQL如何处理客户端连接” 。
在主复制服务器上,来自从属服务器的连接像客户端连接一样处理:每个连接的从属服务器都有一个线程。
在从属复制服务器上,启动I / O线程以连接到主服务器并从中读取更新。 启动SQL线程以应用从主服务器读取的更新。 这两个线程独立运行,可以独立启动和停止。
信号线程处理所有信号。
此线程通常还处理警报和调用
process_alarm()
以强制在空闲时间过长的连接上超时。
如果
InnoDB
使用,默认情况下会有其他读写线程。
这些数量由
innodb_read_io_threads
和
innodb_write_io_threads
参数
控制
。
请参见
第15.13节“InnoDB启动选项和系统变量”
。
如果使用该
选项
启动服务器
,则会创建专用线程以每秒刷新所有表
。
--flush_time=
val
val
如果事件调度程序处于活动状态,则调度程序有一个线程,当前正在运行的每个事件都有一个线程。 请参见 第24.4.1节“事件调度程序概述” 。
mysqladmin processlist 仅显示连接,复制和事件线程。
Unix源代码和二进制分发版中包含的测试系统使用户和开发人员可以对MySQL代码执行回归测试。 这些测试可以在Unix上运行。
您也可以编写自己的测试用例。 有关信息(包括系统要求),请参阅MySQL服务器Doxygen文档中的MySQL测试框架,可从 https://dev.mysql.com/doc/index-other.html获取 。
当前的一组测试用例并未测试MySQL中的所有内容,但它应该捕获SQL处理代码,操作系统或库问题中最明显的错误,并且在测试复制方面非常彻底。 我们的目标是让测试覆盖100%的代码。 我们欢迎对我们的测试套件的贡献。 您可能特别希望提供检查系统关键功能的测试,因为这可确保所有未来的MySQL版本都能很好地与您的应用程序配合使用。
测试系统包括一个测试语言解释器(
mysqltest
),一个运行所有测试的Perl脚本(
mysql-test-run.pl
),用特殊测试语言编写的实际测试用例,以及它们的预期结果。
要在构建后在系统上运行测试套件,请
从源根目录
键入
make test
,或将位置更改为
mysql-test
目录并键入
./mysql-test-run.pl
。
如果已安装二进制分发版,请将位置更改
mysql-test
为安装根目录下的目录(例如,
/usr/local/mysql/mysql-test
),然后运行
./mysql-test-run.pl
。
所有测试都应该成功。
如果没有,请随时尝试找出原因并报告问题,如果它表明MySQL存在错误。
请参见
第1.7节“如何报告错误或问题”
。
如果一个测试失败,您应该运行
mysql-test-run.pl
并
--force
选择检查是否有其他测试失败。
如果你
在要运行测试套件的机器上运行
了
mysqld
的副本,
则只要它不使用端口
9306
或
,就不必停止它
9307
。
如果采用这些端口中的任何一个,则应将
MTR_BUILD_THREAD
环境变量设置为适当的值,并且测试套件将为master,slave和NDB使用不同的端口集。
例如:
shell> export MTR_BUILD_THREAD = 31 shell> ./mysql-test-run.pl [options
] [test_name
]
在
mysql-test
目录中,您可以使用
./mysql-test-run.pl
test_name
运行单个测试用例
。
如果您对测试套件有疑问,或者要提供测试用例,请向MySQL
internals
邮件列表
发送电子邮件
。
请参见
第1.6.2节“MySQL邮件列表”
。
MySQL支持一个插件API,可以创建服务器组件。 插件可以在服务器启动时加载,也可以在运行时加载和卸载,而无需重新启动服务器。 API是通用的,不指定插件可以执行的操作。 此接口支持的组件包括但不限于存储引擎,全文解析器插件和服务器扩展。
例如,全文解析器插件可用于替换或扩充内置的全文解析器。 插件可以使用与内置解析器使用的规则不同的规则将文本解析为单词。 如果您需要解析具有与内置解析器所期望的特征不同的特性的文本,这将非常有用。
插件接口比旧的用户定义函数(UDF)接口更通用。
插件接口使用
数据库中
的
plugin
表
mysql
来记录有关使用该
INSTALL
PLUGIN
语句
永久安装的插件的信息
。
此表是作为MySQL安装过程的一部分创建的。
也可以使用该
--plugin-load
选项
为单个服务器调用安装插件
。
以这种方式安装的插件不会记录在
plugin
表中。
请参见
第5.6.1节“安装和卸载插件”
。
除了服务器插件之外,MySQL还支持客户端插件的API。 例如,这由身份验证插件使用,其中服务器端插件和客户端插件协作以使客户端能够通过各种身份验证方法连接到服务器。
MySQL源代码包含使用Doxygen编写的内部文档。 本文档对于从开发人员的角度理解MySQL的工作原理非常有用。 生成的Doxygen内容可从 https://dev.mysql.com/doc/index-other.html获得 。 也可以使用 第2.9.7节“生成MySQL Doxygen文档内容”中 的说明从MySQL源代码分发本地生成此内容 。
Sergei Golubchik和Andrew Hutchings 撰写的 MySQL 5.1插件开发 书 提供了有关插件API的大量详细信息。 尽管本书的标题涉及MySQL Server 5.1,但其中的大部分信息也适用于更高版本。
插件API支持创建实现多种功能的插件:
以下部分概述了这些插件类型。
MySQL服务器使用的可插拔存储引擎架构使存储引擎可以作为插件编写,并从正在运行的服务器加载和卸载。 有关此体系结构的说明,请参见 第16.11节“MySQL存储引擎体系结构概述” 。
有关如何使用插件API编写存储引擎的信息,请参阅 MySQL内部:编写自定义存储引擎 。
MySQL有一个内置的解析器,默认情况下它用于全文操作(解析要编入索引的文本,或解析查询字符串以确定用于搜索的术语)。
内置的全文解析器由
表
InnoDB
和
MyISAM
表
支持
。
MySQL还有一个基于字符的ngram全文解析器,支持中文,日文和韩文(CJK),以及一个支持日语的基于单词的MeCab解析器插件,用于
InnoDB
和
MyISAM
表。
对于全文处理, “ 解析 ” 意味着 从文本或查询字符串中 提取单词(或 “ 令牌 ” ,在基于n-gram字符的解析器的情况下),基于定义哪些字符序列构成单词的规则和字边界所在。
解析索引时,解析器会将每个单词传递给服务器,然后将其添加到全文索引中。 解析查询字符串时,解析器会将每个单词传递给服务器,服务器会累积用于搜索的单词。
第12.9节“全文搜索功能” 中介绍了内置全文本解析器的解析属性 。 这些属性包括用于确定如何从文本中提取单词的规则。 解析器受某些系统变量的影响,这些系统变量导致短的或更长的单词被排除,并且通过用于标识要忽略的常用单词的禁用词列表。 有关更多信息,请参见 第12.9.4节“全文停用词” 和 第12.9.6节“微调MySQL全文搜索” 。
插件API使您可以使用除默认内置全文解析器之外的全文解析器。 例如,如果您使用日语,则可以选择使用MeCab全文解析器。 插件API还允许您提供自己的全文解析器,以便您可以控制解析器的基本职责。 解析器插件可以以两种角色运行:
该插件可以取代内置的解析器。 在此角色中,插件读取要解析的输入,将其拆分为单词,并将单词传递给服务器(用于索引或用于标记累积)。 ngram和MeCab解析器用作内置全文解析器的替代品。
如果您需要使用与内置解析器不同的规则来确定如何将输入拆分为单词,则可以选择提供自己的全文解析器。 例如,内置解析器认为文本 “ 区分大小写 ” 由两个单词 “ case ” 和 “ sensitive ”组成, 而应用程序可能需要将文本视为单个单词。
该插件可以作为前端解析器与内置解析器一起使用。
在此角色中,插件从输入中提取文本并将文本传递给解析器,解析器使用其正常的解析规则将文本拆分为单词。
此解析受
或
系统变量和禁用词列表的影响。
innodb_ft_
xxx
ft_
xxx
以这种方式使用解析器的一个原因是您需要索引PDF文档,XML文档或
.doc
文件等内容。
内置解析器不适用于那些类型的输入,但插件可以从这些输入源中提取文本并将其传递给内置解析器。
解析器插件也可以在两个角色中运行。 也就是说,它可以从noncleartext输入(前端角色)中提取文本,并将文本解析为单词(从而替换内置解析器)。
全文插件与每个索引的全文索引相关联。
也就是说,当您最初安装解析器插件时,这不会导致它用于任何全文操作。
它变得可用。
例如,
WITH PARSER
在创建单个
FULLTEXT
索引
时
,可以在
子句中
命名全文解析器插件
。
要在创建表时创建此类索引,请执行以下操作:
创建表t ( doc CHAR(255), 带有PARSER parser_name的FULLTEXT INDEX(doc) )ENGINE = InnoDB;
或者您可以在创建表后添加索引:
ALTER TABLE t使用PARSER parser_name添加FULLTEXT INDEX(doc);
将解析器与索引相关联的唯一SQL更改是
WITH PARSER
子句。
搜索与以前一样指定,查询不需要进行任何更改。
将解析器插件与
FULLTEXT
索引
关联时
,插件是使用索引所必需的。
如果删除了解析器插件,则与其关联的任何索引都将变得不可用。
任何尝试使用插件不可用的表都会导致错误,尽管
DROP
TABLE
仍然可能。
有关全文插件的更多信息,请参见
第29.2.4.4节“编写全文分析器插件”
。
MySQL的8.0支持全文插件与
MyISAM
和
InnoDB
。
守护程序插件是一种简单类型的插件,用于应由服务器运行但不与之通信的代码。 MySQL发行版包含一个示例守护程序插件,可将周期性心跳消息写入文件。
有关守护程序插件的更多信息,请参见 第29.2.4.5节“编写守护程序插件” 。
INFORMATION_SCHEMA
plugins支持创建包含通过
INFORMATION_SCHEMA
数据库
向用户公开的服务器元数据的表
。
例如,
InnoDB
使用
INFORMATION_SCHEMA
插件提供包含有关当前事务和锁的信息的表。
有关
INFORMATION_SCHEMA
插件的
更多信息
,请参见
第29.2.4.6节“编写INFORMATION_SCHEMA插件”
。
默认情况下,MySQL复制是异步的。 使用半同步复制,在返回执行事务的会话之前,在主端块上执行提交,直到至少一个从端确认已接收并记录事务的事件。 半同步复制是通过互补的主插件和客户端插件实现的。 请参见 第17.3.11节“半同步复制” 。
有关半同步复制插件的更多信息,请参见 第29.2.4.7节“编写 半同步复制插件 ” 。
MySQL服务器提供可插拔的审计接口,可以将有关服务器操作的信息报告给感兴趣的各方。 这些操作会发生审核通知(尽管接口是通用的,服务器可以修改为报告其他操作):
将消息写入常规查询日志(如果启用了日志)
将消息写入错误日志
将查询结果发送给客户端
审计插件可以向审计接口注册,以接收有关服务器操作的通知。 当服务器内发生可审计事件时,服务器确定是否需要通知。 对于每个已注册的审计插件,服务器会根据插件感兴趣的事件类检查事件,如果匹配则将事件传递给插件。
此接口使审计插件仅接收有关其认为重要的事件类中的操作的通知,并忽略其他操作。 该接口提供将操作分类为事件类,并进一步划分为每个类中的事件子类。
当审计插件被通知可审计事件时,它会收到指向当前THD结构的指针和指向包含有关事件信息的结构的指针。 插件可以检查事件并执行适当的审计操作。 例如,插件可以查看生成结果集或记录的语句,结果中的行数,当前用户的操作对象,或失败操作的错误代码。
有关审计插件的更多信息,请参见 第29.2.4.8节“编写审计插件” 。
MySQL支持可插拔身份验证。 服务器端和客户端都存在身份验证插件。 服务器端的插件实现了身份验证方法,供客户端连接到服务器时使用。 客户端上的插件与服务器端插件通信,以提供它所需的身份验证信息。 客户端插件可以与用户交互,执行诸如请求密码或其他认证凭证的任务以发送到服务器。 请参见 第6.2.17节“可插入验证” 。
可插入身份验证还启用代理用户功能,其中一个用户获取另一个用户的身份。 服务器端身份验证插件可以向连接用户应具有其身份的用户的名称返回服务器。 请参见 第6.2.18节“代理用户” 。
有关身份验证插件的更多信息,请参见 第29.2.4.9节“编写身份验证插件” 。
MySQL服务器提供了一个用于编写测试密码的插件的接口。 这样的插件实现了两个功能:
在分配密码(例如
CREATE
USER
和
ALTER
USER
语句)的
语句中拒绝太弱的密码
。
评估
VALIDATE_PASSWORD_STRENGTH()
SQL函数
的潜在密码的强度
。
有关编写此类插件的信息,请参见 第29.2.4.10节“编写密码验证插件” 。
MySQL Server支持查询重写插件,可以在服务器执行之前检查并可能修改服务器接收的语句。 查询重写插件在服务器解析之前或之后获取语句。
预分析查询重写插件具有以下特征:
该插件允许在服务器处理之前重写到达服务器的SQL语句。
该插件接收一个语句字符串,并可能返回一个不同的字符串。
postparse查询重写插件具有以下特征:
该插件支持基于解析树的语句重写。
服务器解析每个语句并将其解析树传递给插件,插件可以遍历树。 插件可以将原始树返回到服务器以进行进一步处理,或者构造不同的树并返回该树。
该插件可以将
mysql_parser
插件服务用于以下目的:
激活语句摘要计算并获取语句的规范化版本,与性能模式是否生成摘要无关。
遍历解析树。
解析语句。 如果插件从解析树构造新的语句字符串,这将非常有用。 插件可以让服务器解析字符串以生成新树,然后将该树作为重写语句的表示返回。
有关插件服务的更多信息,请参见 第29.3节“插件的MySQL服务” 。
预填充和postparse查询重写插件共享这些特征:
如果安装了查询重写插件,该
--log-raw
选项会影响语句日志记录,如下所示:
如果插件重写语句,服务器将根据重写的语句而不是原始语句决定是将其写入二进制日志(以及因此写入任何复制从属)。
如果插件仅
SELECT
将
SELECT
语句
重写
为
语句,则对二进制日志记录没有影响,因为服务器不会将
SELECT
语句
写入
二进制日志。
如果插件重写语句,则服务器会生成
Note
客户端可以使用
的
消息
SHOW
WARNINGS
。
消息具有以下格式,其中
stmt_in
是原始语句,并且
stmt_out
是重写的语句:
通过查询重写插件查询'stmt_in
'重写为'stmt_out
'
MySQL发行版包括一个名为的postparse查询重写插件
Rewriter
。
这个插件是基于规则的。
您可以向其规则表中添加行以导致
SELECT
语句重写。
有关更多信息,请参见
第5.6.4节“重写器查询重写插件”
。
查询重写插件使用与审计插件相同的API。 有关审计插件的更多信息,请参见 第29.2.4.8节“编写审计插件” 。
MySQL服务器支持密钥环插件,使内部服务器组件和插件能够安全地存储敏感信息,以便以后检索。
所有MySQL发行版都包含一个名为的密钥环插件
keyring_file
。
MySQL企业版发行版包括其他密钥环插件。
请参见
第6.4.4节“MySQL密钥环”
。
有关密钥环插件的更多信息,请参见 第29.2.4.12节“编写密钥环插件” 。
服务器插件API具有以下特征:
所有插件都有几个共同点。
每个插件都有一个可以在SQL语句中引用的名称,以及其他元数据,如作者和提供其他信息的描述。
可以在
INFORMATION_SCHEMA.PLUGINS
表格中或使用
SHOW
PLUGINS
语句
检查此信息
。
插件框架可扩展以适应不同类型的插件。
虽然插件API的某些方面对于所有类型的插件都是通用的,但API还允许特定于类型的界面元素,以便可以创建不同类型的插件。 具有一个目的的插件可以具有最适合其自身要求的接口,而不是某些其他插件类型的要求。
存在多种类型插件的接口,例如存储引擎,全文解析器和
INFORMATION_SCHEMA
表。
其他人可以添加。
插件可以向用户公开信息。
插件可以实现通过
SHOW
VARIABLES
和
SHOW
STATUS
语句
可用的系统和状态变量
。
插件API包括版本控制信息。
插件API中包含的版本信息使插件库及其包含的每个插件能够相对于用于构建库的API版本进行自我识别。 如果API随时间变化,版本号将发生变化,但服务器可以检查给定插件库的版本信息,以确定它是否支持库中的插件。
版本号有两种类型。 第一个是通用插件框架本身的版本。 每个插件库都包含这种版本号。 第二种类型的版本适用于各个插件。 每种特定类型的插件都有一个版本用于其界面,因此库中的每个插件都有一个特定于类型的版本号。 例如,包含全文解析器插件的库具有通用插件API版本号,插件具有特定于全文插件接口的版本号。
插件API实现了安全限制。
插件库必须安装在特定的专用目录中,该目录的位置由服务器控制,并且不能在运行时更改。 此外,库必须包含将其标识为插件库的特定符号。 如果没有将插件构建为插件,服务器将不会将其作为插件加载。
插件可以访问服务器服务。
服务接口公开了插件可以使用普通函数调用访问的服务器功能。 有关详细信息,请参见 第29.3节“用于插件的MySQL服务” 。
在某些方面,服务器插件API类似于它取代的旧用户定义函数(UDF)API,但插件API比旧接口具有几个优点。 例如,UDF没有版本控制信息。 此外,较新的插件接口消除了旧UDF接口的安全问题。 用于编写非插件UDF的旧接口允许从系统的动态链接器搜索的任何目录加载库,并且标识UDF库的符号是相对非特定的。
客户端插件API具有类似的体系结构特征,但客户端插件无法像服务器插件那样直接访问服务器。
服务器插件实现包括几个组件。
SQL语句:
INSTALL
PLUGIN
在
mysql.plugin
表中
注册一个插件
并加载插件代码。
UNINSTALL
PLUGIN
从
mysql.plugin
表中
取消注册插件
并卸载插件代码。
WITH PARSER
全文索引创建
的
子句将全文解析器插件与给定
FULLTEXT
索引
相关联
。
SHOW
PLUGINS
显示有关服务器插件的信息。
命令行选项和系统变量:
该
--plugin-load
选项允许在服务器启动时加载插件。
该
plugin_dir
系统变量指示必须在其中安装的所有插件的目录位置。
可以在服务器启动时使用
选项
指定此变量的值
。
mysql_config --plugindir
显示默认的插件目录路径名。
--plugin_dir=
dir_name
有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件” 。
与插件相关的表:
该
INFORMATION_SCHEMA.PLUGINS
表包含插件信息。
该
mysql.plugin
表列出了安装时使用
INSTALL
PLUGIN
的插件以及插件使用所需的插件。
对于新的MySQL安装,此表是在安装过程中创建的。
客户端插件实现更简单:
对于
mysql_options()
C API函数,
MYSQL_DEFAULT_AUTH
和
MYSQL_PLUGIN_DIR
选项使客户端程序能够加载身份验证插件。
有一些C API函数可以管理客户端插件。
要检查MySQL如何实现插件,请参考MySQL源代码分发中的以下源文件:
在
include/mysql
目录中,
plugin.h
公开公共插件API。
任何想要编写插件库的人都应该检查此文件。
文件提供了与特定类型的插件有关的其他信息。
包含特定于客户端插件的信息。
plugin_
xxx
.hclient_plugin.h
在
sql
目录中,
sql_plugin.h
并
sql_plugin.cc
包含内部插件实现。
sql_acl.cc
是服务器使用身份验证插件的地方。
插件开发人员无需咨询这些文件。
对于那些想要了解服务器如何处理插件的人来说,它们可能是有趣的。
在该
sql-common
目录中,
client_plugin.h
实现C API客户端插件函数,并
client.c
实现客户端身份验证支持。
插件开发人员无需咨询这些文件。
对于那些想要了解服务器如何处理插件的人来说,它们可能是有趣的。
要创建插件库,您必须提供指示库文件包含的插件所需的描述符信息,并为每个插件编写接口函数。
每个服务器插件必须具有为插件API提供信息的通用描述符,以及特定于类型的描述符,该描述符提供有关给定类型插件的插件接口的信息。
一般描述符的结构对于所有插件类型都是相同的。
特定于类型的描述符的结构因插件类型而异,并且由插件需要执行的操作的要求决定。
服务器插件接口还使插件能够公开状态和系统变量。
这些变量通过
SHOW
STATUS
和
SHOW
VARIABLES
语句以及相应的
INFORMATION_SCHEMA
表
变得可见
。
对于客户端插件,架构有点不同。 每个插件必须有一个描述符,但没有划分为单独的通用描述符和特定于类型的描述符。 相反,描述符以所有客户端插件类型共有的固定成员集开头,并且公共成员后面是实现特定插件类型所需的任何其他成员。
服务器插件包含成为正在运行的服务器的一部分的代码,因此当您编写插件时,您将受到编写服务器代码的任何和所有约束的约束。
例如,如果尝试使用
libstdc++
库中的
函数,则可能会出现问题
。
这些约束可能会在服务器的未来版本中发生变化,因此服务器升级可能需要修改最初为旧服务器编写的插件。
有关这些约束的信息,请参见
第2.9.4节“MySQL源配置选项”
和
第2.9.5节“处理编译MySQL的问题”
。
客户端插件编写者应该避免依赖于调用应用程序具有哪些符号,因为您无法确定哪些应用程序将使用该插件。
这些条件适用于插件编写:
插件使用的MySQL头文件包含C ++代码,因此插件必须编译为C ++代码。
您必须编译包含整个服务器源代码的插件,而不仅仅是库和头文件。
编译的插件在服务器版本之间不兼容。
对于针对MySQL 8.0编译的插件。
X
,不能保证它可以与MySQL 8.0一起使用。
Y
没有重新编译MySQL 8.0的服务器。
Y
。
插件是动态加载和卸载的,因此您的操作系统必须支持动态加载,并且您必须动态编译调用应用程序(而不是静态编译)。 对于服务器插件,这意味着 必须动态链接 mysqld 。
以下过程概述了创建插件库所需的步骤。 接下来的部分提供了有关设置插件数据结构和编写特定类型插件的其他详细信息。
在插件源文件中,包含插件库所需的头文件。
该
plugin.h
文件是必需的,库也可能需要其他文件。
例如:
#include <stdlib.h> #include <ctype.h> #include <mysql / plugin.h>
设置插件库文件的描述符信息。 对于服务器插件,请编写库描述符,该描述符必须包含文件中每个服务器插件的常规插件描述符。 有关更多信息,请参见 第29.2.4.2.1节“服务器插件库和插件描述符” 。 此外,为库中的每个服务器插件设置特定于类型的描述符。 每个插件的通用描述符指向其特定于类型的描述符。
对于客户端插件,请编写客户端描述符。 有关更多信息,请参见 第29.2.4.2.3节“客户端插件描述符” 。
为每个插件编写插件接口函数。 例如,每个插件的常规插件描述符指向服务器在加载和卸载插件时应调用的初始化和取消初始化函数。 插件的类型特定描述也可以指向接口功能。
对于服务器插件,请设置状态和系统变量(如果有)。
将插件库编译为共享库并将其安装在插件目录中。 有关更多信息,请参见 第29.2.4.3节“编译和安装插件库” 。
对于服务器插件,请将插件注册到服务器。 有关更多信息,请参见 第5.6.1节“安装和卸载插件” 。
测试插件以验证它是否正常工作。
插件库文件包括描述符信息以指示它包含哪些插件。
如果插件库包含任何服务器插件,则它必须包含以下描述符信息:
库描述符指示库使用的通用服务器插件API版本号,并包含库中每个服务器插件的通用插件描述符。
要为此描述符提供框架,请从头
plugin.h
文件中
调用两个宏
:
mysql_declare_plugin(name
)... one or more server plugin descriptors here ...
mysql_declare_plugin_end;
宏扩展为自动提供API版本的声明。 您必须提供插件描述符。
在库描述符中,每个通用服务器插件由
st_mysql_plugin
结构
描述
。
此插件描述符结构包含每种类型的服务器插件通用的信息:表示插件类型的值;
插件名称,作者,描述和许可证类型;
指向服务器在加载和卸载插件时调用的初始化和取消初始化函数的指针,以及指向插件实现的任何状态或系统变量的指针。
库描述符中的每个通用服务器插件描述符还包含指向特定于类型的插件描述符的指针。 类型特定描述符的结构因插件类型而异,因为每种类型的插件都可以拥有自己的API。 特定于类型的插件描述符包含特定于类型的API版本号以及指向实现该插件类型所需的函数的指针。 例如,全文解析器插件具有初始化和取消初始化函数以及主解析函数。 服务器在使用插件解析文本时调用这些函数。
插件库还包含接口函数,这些函数由库中每个插件的常规描述符和特定于类型的描述符引用。
如果插件库包含客户端插件,则必须包含插件的描述符。
描述符以所有客户端插件通用的固定成员集开头,后跟任何特定于插件类型的成员。
要提供描述符框架,请从头
client_plugin.h
文件中
调用两个宏
:
mysql_declare_client_plugin(plugin_type
) ...members common to all client plugins
... ...type-specific extra members
... mysql_end_client_plugin;
插件库还包含客户端描述符引用的任何接口函数。
在
mysql_declare_plugin()
和
mysql_declare_client_plugin()
宏在它们如何被调用,这对插件库的内容含义有所不同。
以下指南总结了规则:
mysql_declare_plugin()
并且
mysql_declare_client_plugin()
可以在同一个源文件中使用,这意味着插件库可以包含服务器和客户端插件。
然而,每一个
mysql_declare_plugin()
和
mysql_declare_client_plugin()
最多可使用一次。
mysql_declare_plugin()
允许多个服务器插件声明,因此插件库可以包含多个服务器插件。
mysql_declare_client_plugin()
仅允许单个客户端插件声明。
要创建多个客户端插件,必须使用单独的插件库。
当客户端程序查找插件库中没有内置的客户端插件时
libmysqlclient
,它会查找一个基本名称与插件名称相同的文件。
例如,如果程序需要使用
auth_xxx
在
.so
用作库后缀
的系统上
命名的客户端身份验证插件
,则它会查找名为的文件
auth_xxx.so
。
(在OS X上,程序首先查找
auth_xxx.dylib
,然后查找
auth_xxx.so
。)因此,如果插件库包含客户端插件,则库必须具有与该插件相同的基本名称。
对于包含服务器插件的库,情况也是如此。
该
--plugin-load
选项和
INSTALL
PLUGIN
声明明确提供的库文件名,所以有需要的库名,它包含的任何服务器插件的名称之间没有明确的关系。
每个包含服务器插件的插件库都必须包含一个库描述符,其中包含文件中每个服务器插件的常规插件描述符。 本节讨论如何编写服务器插件的库和一般描述符。
库描述符必须定义两个符号:
_mysql_plugin_interface_version_
指定通用插件框架的版本号。
这由
MYSQL_PLUGIN_INTERFACE_VERSION
符号
给出,该
符号在
plugin.h
文件中
定义
。
_mysql_plugin_declarations_
定义一个插件声明数组,由一个声明终止,所有成员都设置为0.每个声明都是
st_mysql_plugin
结构的
一个实例
(也在其中定义
plugin.h
)。
对于库中的每个服务器插件,必须有其中一个。
如果服务器在库中找不到这两个符号,则它不会将其作为合法插件库接受并拒绝它并显示错误。 这可以防止将库用于插件目的,除非它是专门构建为插件库的。
定义两个必需符号的传统方法是使用
文件中
的
mysql_declare_plugin()
和
mysql_declare_plugin_end
宏
plugin.h
:
mysql_declare_plugin(name
)... one or more server plugin descriptors here ...
mysql_declare_plugin_end;
每个服务器插件必须具有一个通用描述符,用于向服务器插件API提供信息。
通用描述符对于所有插件类型具有相同的结构。
文件中
的
st_mysql_plugin
结构
plugin.h
定义了这个描述符:
struct st_mysql_plugin { int类型; / *插件类型(MYSQL_XXX_PLUGIN值)* / void * info; / *指向特定于类型的插件描述符的指针* / const char * name; / *插件名称* / const char * author; / *插件作者(适用于I_S.PLUGINS)* / const char * descr; / *一般描述性文字(适用于I_S.PLUGINS)* / int license; / *插件许可证(PLUGIN_LICENSE_XXX)* / int(* init)(void *); / *加载插件时调用的函数* / int(* deinit)(void *); / *卸载插件时调用的函数* / unsigned int版本; / *插件版本(适用于I_S.PLUGINS)* / struct st_mysql_show_var * status_vars; struct st_mysql_sys_var ** system_vars; void * __reserved1; / *保留用于依赖性检查* / 无符号长旗; 插件的/ *标志* / };
该
st_mysql_plugin
描述符结构构件被使用如下。
char *
成员应指定为以null结尾的字符串。
type
:插件类型。
这必须是以下插件类型值之一
plugin.h
:
/ * 允许的插件类型 * / #define MYSQL_UDF_PLUGIN 0 / *用户自定义函数* / #define MYSQL_STORAGE_ENGINE_PLUGIN 1 / *存储引擎* / #define MYSQL_FTPARSER_PLUGIN 2 / *全文解析器插件* / #define MYSQL_DAEMON_PLUGIN 3 / *守护进程/原始插件类型* / #define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 / * I_S插件类型* / #define MYSQL_AUDIT_PLUGIN 5 / *审核插件类型* / #define MYSQL_REPLICATION_PLUGIN 6 / *复制插件类型* / #define MYSQL_AUTHENTICATION_PLUGIN 7 / *身份验证插件类型* / ...
例如,对于全文解析器插件,
type
值为
MYSQL_FTPARSER_PLUGIN
。
info
:指向插件的特定于类型的描述符的指针。
与一般插件描述符结构不同,此描述符的结构取决于特定类型的插件。
出于版本控制的目的,每个插件类型的特定于类型的描述符的第一个成员应该是该类型的接口版本。
这使服务器可以检查每个插件的类型特定版本,无论其类型如何。
在版本号之后,描述符包括所需的任何其他成员,例如回调函数和服务器正确调用插件所需的其他信息。
name
:一个提供插件名称的字符串。
这是将在
mysql.plugin
表中
列出的名称,您可以通过该名称
引用SQL语句中的插件,例如
INSTALL
PLUGIN
和
UNINSTALL PLUGIN
,或使用该
--plugin-load
选项。
该名称在
INFORMATION_SCHEMA.PLUGINS
表格或输出中
也可见
SHOW
PLUGINS
。
插件名称不应以任何服务器选项的名称开头。
如果是,则服务器将无法初始化它。
例如,服务器有一个
--socket
选项,因此您不应使用插件名称,例如
socket
,
socket_plugin
等等。
author
:一个命名插件作者的字符串。
这可以是你喜欢的任何东西。
desc
:一个字符串,提供插件的一般描述。
这可以是你喜欢的任何东西。
license
:插件许可证类型。
该值可以是一个
PLUGIN_LICENSE_PROPRIETARY
,
PLUGIN_LICENSE_GPL
或
PLUGIN_LICENSE_BSD
。
init
:一次性初始化函数,或者
NULL
如果没有这样的函数。
服务器在加载插件时执行此功能
INSTALL
PLUGIN
,对于
mysql.plugin
表中
列出
的插件,
或者
在服务器启动时发生。
该函数接受一个参数,该参数指向用于标识插件的内部结构。
它为成功返回零,为失败返回非零。
deinit
:一次性取消初始化函数,或者
NULL
如果没有这样的函数。
服务器在卸载插件时执行此功能
UNINSTALL PLUGIN
,对于
mysql.plugin
服务器关闭时
,对于
表中
列出
的插件,
或者为插件
执行该操作
。
该函数接受一个参数,该参数指向用于标识插件的内部结构。它为成功返回零,为失败返回非零。
version
:插件版本号。
安装插件后,可以从
INFORMATION_SCHEMA.PLUGINS
表中
检索此值
。
该值包括主要和次要数字。
如果将值写为十六进制常量,则格式为
,其中
和
分别为主要和次要数字。
例如,
代表版本3.2。
0x
MMNN
MM
NN
0x0302
status_vars
:指向与插件关联的状态变量的结构的指针,或者
NULL
如果没有这样的变量。
安装插件后,这些变量将显示在
SHOW
STATUS
语句
的输出中
。
status_vars
如果不是
NULL
,
该
成员
指向
st_mysql_show_var
描述状态变量
的
结构
数组
。
请参见
第29.2.4.2.2节“服务器插件状态和系统变量”
。
system_vars
:指向与插件关联的系统变量的结构的指针,或者
NULL
如果没有这样的变量。
这些选项和系统变量可用于帮助初始化插件中的变量。
安装插件后,这些变量将显示在
SHOW
VARIABLES
语句
的输出中
。
system_vars
如果不是
NULL
,
该
成员
指向
st_mysql_sys_var
描述系统变量
的
结构
数组
。
请参见
第29.2.4.2.2节“服务器插件状态和系统变量”
。
__reserved1
:未来的占位符。
它应该设置为
NULL
。
flags
:插件标志。
各个位对应于不同的标志。
该值应设置为适用标志的OR。
这些标志可用:
#define PLUGIN_OPT_NO_INSTALL 1UL / *不能动态加载* / #define PLUGIN_OPT_NO_UNINSTALL 2UL / *不能动态卸载* / #define PLUGIN_OPT_ALLOW_EARLY 4UL / *允许--early-plugin-load * /
启用时,标志具有以下含义:
PLUGIN_OPT_NO_INSTALL
:无法在运行时使用该
INSTALL
PLUGIN
语句
加载插件
。
这是适当的,必须在与服务器启动时加载的插件
--plugin-load
,
--plugin-load-add
或
--early-plugin-load
选择。
PLUGIN_OPT_NO_UNINSTALL
:使用该
UNINSTALL PLUGIN
语句
无法在运行时卸载插件
。
PLUGIN_OPT_ALLOW_EARLY
:可以使用该
--early-plugin-load
选项
在服务器启动序列的早期加载插件
。
此标志对于是否可以在服务器启动时使用
--plugin-load
or
--plugin-load-add
选项
加载插件
,或者在运行时使用
INSTALL
PLUGIN
语句
加载此标志
。
此标志已添加到MySQL 8.0.17中。
使用8.0.17之前的MySQL发行版编译的所有插件都没有设置此标志。
将这些加载到8.0.17之前的服务器时这没关系,但尝试使用
--early-plugin-load
8.0.17之前的MySQL发行版加载的插件二进制文件加载到8.0.17或更高版本的服务器中将会失败。
必须根据MySQL 8.0.17或更高版本重新编译插件。
只有在加载和卸载插件时
,服务器
才会
调用
常规插件描述符中
的
init
和
deinit
函数。
它们与插件的使用无关,例如当SQL语句导致调用插件时发生。
例如,包含单个全文解析器插件的库的描述符信息
simple_parser
如下所示:
mysql_declare_plugin(ftexample) { MYSQL_FTPARSER_PLUGIN,/ * type * / &simple_parser_descriptor,/ *描述符* / “simple_parser”,/ * name * / “Oracle Corporation”,/ * author * / “简单的全文解析器”,/ *描述* / PLUGIN_LICENSE_GPL,/ *插件许可证* / simple_parser_plugin_init,/ * init函数(加载时)* / simple_parser_plugin_deinit,/ * deinit函数(卸载时)* / 0x0001,/ *版本* / simple_status,/ *状态变量* / simple_system_variables,/ *系统变量* / 空值, 0 } mysql_declare_plugin_end;
对于全文解析器插件,类型必须是
MYSQL_FTPARSER_PLUGIN
。
这是
WITH PARSER
在创建
FULLTEXT
索引
时
将插件标识为合法用于
子句的
值。
(此子句没有其他插件类型合法。)
plugin.h
像这样
定义
mysql_declare_plugin()
和
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 [] = { #其他 #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 _ [] = { #万一 #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_plugin_declarations_
):
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,/ *描述符* / “simple_parser”,/ * name * / “Oracle Corporation”,/ * author * / “简单的全文解析器”,/ *描述* / PLUGIN_LICENSE_GPL,/ *插件许可证* / simple_parser_plugin_init,/ * init函数(加载时)* / simple_parser_plugin_deinit,/ * deinit函数(卸载时)* / 0x0001,/ *版本* / simple_status,/ *状态变量* / simple_system_variables,/ *系统变量* / 空值, 0 } {0,0,0,0,0,0,0,0,0,0,0,0}} };
前面的示例在通用描述符中声明了一个插件,但是可以声明多个插件。
列出声明一个与前一后
mysql_declare_plugin()
和
mysql_declare_plugin_end
,以逗号分隔。
MySQL服务器插件必须编译为C ++代码。
您不应使用的一个C ++特性是初始化全局结构的非常量变量。
结构的成员(例如
st_mysql_plugin
结构)应仅使用常量变量进行初始化。
simple_parser
前面显示
的
描述符在C ++插件中是允许的,因为它满足了这个要求:
mysql_declare_plugin(ftexample) { MYSQL_FTPARSER_PLUGIN,/ * type * / &simple_parser_descriptor,/ *描述符* / “simple_parser”,/ * name * / “Oracle Corporation”,/ * author * / “简单的全文解析器”,/ *描述* / PLUGIN_LICENSE_GPL,/ *插件许可证* / simple_parser_plugin_init,/ * init函数(加载时)* / simple_parser_plugin_deinit,/ * deinit函数(卸载时)* / 0x0001,/ *版本* / simple_status,/ *状态变量* / simple_system_variables,/ *系统变量* / 空值, 0 } mysql_declare_plugin_end;
这是编写通用描述符的另一种有效方法。 它使用常量变量来指示插件名称,作者和描述:
const char * simple_parser_name =“simple_parser”; const char * simple_parser_author =“Oracle Corporation”; const char * simple_parser_description =“简单的全文解析器”; mysql_declare_plugin(ftexample) { MYSQL_FTPARSER_PLUGIN,/ * type * / &simple_parser_descriptor,/ *描述符* / simple_parser_name,/ * name * / simple_parser_author,/ * author * / simple_parser_description,/ * description * / PLUGIN_LICENSE_GPL,/ *插件许可证* / simple_parser_plugin_init,/ * init函数(加载时)* / simple_parser_plugin_deinit,/ * deinit函数(卸载时)* / 0x0001,/ *版本* / simple_status,/ *状态变量* / simple_system_variables,/ *系统变量* / 空值, 0 } mysql_declare_plugin_end;
但是,以下一般描述符无效。 它使用结构成员来指示插件名称,作者和描述,但结构在C ++中不被视为常量初始化器:
typedef结构 { const char * name; const char * author; const char * description; } plugin_info; plugin_info parser_info = { “simple_parser” “甲骨文公司”, “简单的全文解析器” }; mysql_declare_plugin(ftexample) { MYSQL_FTPARSER_PLUGIN,/ * type * / &simple_parser_descriptor,/ *描述符* / parser_info.name,/ * name * / parser_info.author,/ * author * / parser_info.description,/ * description * / PLUGIN_LICENSE_GPL,/ *插件许可证* / simple_parser_plugin_init,/ * init函数(加载时)* / simple_parser_plugin_deinit,/ * deinit函数(卸载时)* / 0x0001,/ *版本* / simple_status,/ *状态变量* / simple_system_variables,/ *系统变量* / 空值, 0 } mysql_declare_plugin_end;
服务器插件界面使插件暴露使用状态和系统变量
status_vars
和
system_vars
一般的插件描述符的成员。
status_vars
通用插件描述符
的
成员(如果不是0)指向
st_mysql_show_var
结构
数组
,每个结构描述一个状态变量,后跟一个所有成员都设置为0的
st_mysql_show_var
结构
。
结构具有以下定义:
struct st_mysql_show_var { const char * name; char *值; 枚举enum_mysql_show_type类型; };
下表显示了允许的状态变量
type
值以及相应的变量应该是什么。
表29.1服务器插件状态变量类型
变量类型 | 含义 |
---|---|
SHOW_BOOL |
指向布尔变量的指针 |
SHOW_INT |
指向整数变量的指针 |
SHOW_LONG |
指向长整数变量的指针 |
SHOW_LONGLONG |
指向longlong整型变量的指针 |
SHOW_CHAR |
一个字符串 |
SHOW_CHAR_PTR |
指向字符串的指针 |
SHOW_ARRAY |
指向另一个
st_mysql_show_var
数组的
指针
|
SHOW_FUNC |
指向函数的指针 |
SHOW_DOUBLE |
指向双倍的指针 |
对于
SHOW_FUNC
类型,调用该函数并填充其
out
参数,然后
该
参数提供有关要显示的变量的信息。
该功能有这个签名:
#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)指向一个
st_mysql_sys_var
结构
数组
,每个结构描述一个系统变量(也可以从命令行或配置文件中设置),后跟一个所有成员都设置为0的
st_mysql_sys_var
结构。定义如下:
struct st_mysql_sys_var { int标志; const char * name,* comment; int(* check)(THD *,struct st_mysql_sys_var *,void *,st_mysql_value *); void(* update)(THD *,struct st_mysql_sys_var *,void *,const void *); };
根据标志,附加字段根据需要附加。
为方便起见,定义了许多宏,这使得在插件中创建新的系统变量变得更加简单。
在整个宏中,可以使用以下字段:
name
:系统变量的不带引号的标识符。
varname
:静态变量的标识符。
如果没有,则与该
name
字段
相同
。
opt
:系统变量的附加使用标志。
下表显示了允许的标志。
表29.2服务器插件系统变量标志
旗帜价值 | 描述 |
---|---|
PLUGIN_VAR_READONLY |
系统变量是只读的 |
PLUGIN_VAR_NOSYSVAR |
系统变量在运行时不是用户可见的 |
PLUGIN_VAR_NOCMDOPT |
系统变量不能从命令行配置 |
PLUGIN_VAR_NOCMDARG |
命令行不需要参数(通常用于布尔变量) |
PLUGIN_VAR_RQCMDARG |
命令行需要一个参数(这是默认值) |
PLUGIN_VAR_OPCMDARG |
参数在命令行中是可选的 |
PLUGIN_VAR_MEMALLOC |
用于字符串变量; 表示要分配内存以存储字符串 |
comment
:要在服务器帮助消息中显示的描述性注释。
NULL
如果要隐藏此变量。
check
:检查功能,
NULL
默认情况下。
update
:更新功能,
NULL
默认情况下。
default
:变量默认值。
minimum
:变量最小值。
maximum
:变量最大值。
blocksize
:可变块大小。
设置该值时,它将四舍五入为最接近的倍数
blocksize
。
可以通过直接使用静态变量或使用
SYSVAR()
访问器宏
来访问系统变量
。
该
SYSVAR()
宏提供了完整。
通常只有当代码不能直接访问底层变量时才应该使用它。
例如:
static int my_foo; static MYSQL_SYSVAR_INT(foo_var,my_foo, PLUGIN_VAR_RQCMDARG,“foo评论”, NULL,NULL,0,0,INT_MAX,0); ... SYSVAR(foo_var)=值; value = SYSVAR(foo_var); my_foo = value; value = my_foo;
只能通过
THDVAR()
访问者宏
访问会话变量
。
例如:
static MYSQL_THDVAR_BOOL(some_flag, PLUGIN_VAR_NOCMDARG,“旗帜评论”, NULL,NULL,FALSE); ... if(THDVAR(thd,some_flag)) { 做一点事(); THDVAR(thd,some_flag)= FALSE; }
所有全局和会话系统变量必须
在使用前
发布到
mysqld
。
这是通过构造
NULL
变量
的
终止数组并在插件公共接口中链接到变量来完成的。
例如:
static struct st_mysql_sys_var * my_plugin_vars [] = { MYSQL_SYSVAR(foo_var) MYSQL_SYSVAR(some_flag) 空值 }; mysql_declare_plugin(fooplug) { MYSQL _..._插件, &plugin_data, “fooplug” “foo作者”, “这确实很棒!”, PLUGIN_LICENSE_GPL, foo_init, foo_fini, 0×0001, 空值, my_plugin_vars, 空值, 0 } mysql_declare_plugin_end;
以下便捷宏使您可以声明不同类型的系统变量:
类型的布尔系统变量
bool
,它是一个1字节的布尔值。
(0 =
false
,1 =
true
)
MYSQL_THDVAR_BOOL(名称,选择,评论,检查,更新,默认) MYSQL_SYSVAR_BOOL(名称,varname,opt,comment,check,update,default)
字符串系统变量类型
char*
,它是指向以null结尾的字符串的指针。
MYSQL_THDVAR_STR(名称,选择,评论,检查,更新,默认) MYSQL_SYSVAR_STR(name,varname,opt,comment,check,update,default)
整数系统变量,其中有几个变种。
一个
int
系统变量,其通常是4字节的符号字。
MYSQL_THDVAR_INT(name,opt,comment,check,update,default,min,max,blk) MYSQL_SYSVAR_INT(name,varname,opt,comment,check,update,default, 最小,最大,块大小)
一个
unsigned int
系统变量,其通常是4字节的无符号字。
MYSQL_THDVAR_UINT(name,opt,comment,check,update,default,min,max,blk) MYSQL_SYSVAR_UINT(name,varname,opt,comment,check,update,default, 最小,最大,块大小)
甲
long
系统变量,它典型地是4或8字节符号字。
MYSQL_THDVAR_LONG(名称,选择,评论,检查,更新,默认,最小,最大,blk) MYSQL_SYSVAR_LONG(name,varname,opt,comment,check,update,default, 最小,最大,块大小)
一个
unsigned long
系统变量,这典型地是4或8个字节的无符号字。
MYSQL_THDVAR_ULONG(name,opt,comment,check,update,default,min,max,blk) MYSQL_SYSVAR_ULONG(name,varname,opt,comment,check,update,default, 最小,最大,块大小)
甲
long long
系统变量,其通常为8字节符号字。
MYSQL_THDVAR_LONGLONG(姓名,选择,评论,检查,更新, default,minimum,maximum,blocksize) MYSQL_SYSVAR_LONGLONG(名称,varname,opt,comment,check,update, default,minimum,maximum,blocksize)
一个
unsigned long long
系统变量,其通常为8字节无符号字。
MYSQL_THDVAR_ULONGLONG(姓名,选择,评论,检查,更新, default,minimum,maximum,blocksize) MYSQL_SYSVAR_ULONGLONG(名称,varname,opt,comment,check,update, default,minimum,maximum,blocksize)
甲
double
系统变量,其通常为8字节符号字。
MYSQL_THDVAR_DOUBLE(姓名,选择,评论,检查,更新, default,minimum,maximum,blocksize) MYSQL_SYSVAR_DOUBLE(name,varname,opt,comment,check,update, default,minimum,maximum,blocksize)
一个
unsigned long
系统变量,这典型地是4或8个字节的无符号字。
可能值的范围是
typelib
从0开始
的元素数量的序数
。
MYSQL_THDVAR_ENUM(名称,选择,评论,检查,更新,默认,类型库) MYSQL_SYSVAR_ENUM(名称,varname,opt,comment,check,update, 默认,typelib)
一个
unsigned long long
系统变量,其通常为8字节无符号字。
每个位代表一个元素
typelib
。
MYSQL_THDVAR_SET(名称,选择,评论,检查,更新,默认,类型库) MYSQL_SYSVAR_SET(名称,varname,opt,comment,check,update, 默认,typelib)
在内部,所有可变和插件系统变量都存储在
HASH
结构中。
通过编译
DYNAMIC_ARRAY
与命令行选项相关的所有变量,对它们进行排序,然后迭代它们以显示每个选项
来处理服务器命令行帮助文本的
显示。
当一个命令行选项已被处理,则接着从除去
argv
由
handle_option()
函数(
my_getopt.c
);
实际上,它被消耗了。
服务器在插件安装过程中,在插件成功加载之后但在调用插件初始化函数之前立即处理命令行选项
在运行时加载的插件不会受益于任何配置选项,并且必须具有可用的默认值。
安装完成后,它们将在
mysqld
初始化时
加载,
并且可以在命令行或内部设置配置选项
my.cnf
。
插件应该将
thd
参数视为只读。
每个客户端插件必须具有一个描述符,该描述符向客户端插件API提供信息。 描述符结构以所有客户端插件共有的固定成员集开头,后跟任何特定于插件类型的成员。
文件中
的
st_mysql_client_plugin
结构
client_plugin.h
定义了
包含公共成员
的
“
通用
”
描述符:
struct st_mysql_client_plugin { int类型; 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 *
成员应指定为以null结尾的字符串。
type
:插件类型。
这必须是插件类型值之一
client_plugin.h
,例如
MYSQL_CLIENT_AUTHENTICATION_PLUGIN
。
interface_version
:插件界面版本。
例如,这是
MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
一个身份验证插件。
name
:一个提供插件名称的字符串。
当您
mysql_options()
使用该
MYSQL_DEFAULT_AUTH
选项
调用
或指定
--default-auth
MySQL客户端程序
的
选项
时,这是您引用该插件的名称
。
author
:一个命名插件作者的字符串。
这可以是你喜欢的任何东西。
desc
:一个字符串,提供插件的一般描述。
这可以是你喜欢的任何东西。
version
:插件版本为三个整数的数组,表示主要版本,次要版本和次要版本。
例如,
{1,2,3}
表示版本1.2.3。
license
:一个指定许可证类型的字符串。
mysql_api
:供内部使用。
NULL
在插件描述符中
指定它
。
init
:一次性初始化函数,或者
NULL
如果没有这样的函数。
客户端库在加载插件时执行此功能。
该函数返回零表示成功,非零表示失败。
init
如果发生错误,
该
函数使用其前两个参数返回错误消息。
第一个参数是指向
char
缓冲区
的指针
,第二个参数表示缓冲区长度。
init
函数
返回的任何消息都
必须以空值终止,因此最大消息长度是缓冲区长度减去1。
下一个参数传递给
mysql_load_plugin()
。
第一个表示有多少个参数(如果没有,则为0),后跟任何剩余的参数。
deinit
:一次性取消初始化函数,或者
NULL
如果没有这样的函数。
客户端库在卸载插件时执行此功能。
该函数不带参数。
它为成功返回零,为失败返回非零。
options
:用于处理传递给插件的选项的函数,或者
NULL
如果没有这样的函数。
该函数接受两个表示选项名称的参数和一个指向其值的指针。
该函数返回零表示成功,非零表示失败。
对于给定的客户端插件类型,公共描述符成员可以跟随实现该类型的插件所必需的附加成员。
例如,
st_mysql_client_plugin_AUTHENTICATION
身份验证插件
的
结构在客户端库调用以执行身份验证的最后具有一个功能。
要声明插件,请使用
mysql_declare_client_plugin()
和
mysql_end_client_plugin
宏:
mysql_declare_client_plugin(plugin_type
) ...members common to all client plugins
... ...type-specific extra members
... mysql_end_client_plugin;
不要
明确
指定
type
或
interface_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_main mysql_end_client_plugin;
此声明使用
AUTHENTICATION
参数将
type
和
interface_version
成员
设置
为
MYSQL_CLIENT_AUTHENTICATION_PLUGIN
和
MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
。
根据插件类型,描述符可能具有跟随公共成员的其他成员。
例如,对于身份验证插件,有一个函数(
my_auth_main()
在刚才显示的描述符中)处理与服务器的通信。
请参见
第29.2.4.9节“编写身份验证插件”
。
通常,支持使用身份验证插件的客户端程序会通过调用
mysql_options()
来设置
MYSQL_DEFAULT_AUTH
和
MYSQL_PLUGIN_DIR
选项
来加载插件
:
char * plugin_dir =“path_to_plugin_dir
”; char * default_auth =“plugin_name
”; / * ...进程命令行选项... * / mysql_options(&mysql,MYSQL_PLUGIN_DIR,plugin_dir); mysql_options(&mysql,MYSQL_DEFAULT_AUTH,default_auth);
通常,程序还会接受
--plugin-dir
和
--default-auth
允许用户覆盖默认值的选项。
如果客户端程序需要较低级别的插件管理,则客户端库包含带
st_mysql_client_plugin
参数的函数。
请参见
第28.7.17节“C API客户端插件函数”
。
编写插件后,必须编译并安装它。
编译共享对象的过程因系统而异。
如果使用构建库
CMake
,它应该能够为您的系统生成正确的编译命令。
如果库已命名
somepluglib
,则应该使用名称类似的共享库文件
somepluglib.so
。
(
.so
文件名后缀可能与您的系统不同。)
要使用
CMake
,您需要设置配置文件以启用插件的编译和安装。
使用
plugin
MySQL源代码分发目录
下的插件示例
作为指导。
创建
CMakeLists.txt
,应该看起来像这样:
MYSQL_ADD_PLUGIN(somepluglib somepluglib.c MODULE_ONLY MODULE_OUTPUT_NAME“somepluglib”)
当
CMake
生成时
Makefile
,它应该注意将
-DMYSQL_DYNAMIC_PLUGIN
标志
传递给编译命令
,并向链接器传递
-lmysqlservices
标志,该标志是通过插件服务接口提供的服务链接任何函数所需的。
请参见
第29.3节“用于插件的MySQL服务”
。
运行 CMake ,然后运行 make :
shell>cmake .
shell>make
如果需要为
CMake
指定配置选项
,请参见
第2.9.4节“MySQL源配置选项”
以获取列表。
例如,您可能希望指定
CMAKE_INSTALL_PREFIX
指示应安装插件的MySQL基本目录。
您可以通过以下方式查看此选项使用的值
SHOW
VARIABLES
:
MySQL的> SHOW VARIABLES LIKE 'basedir';
+ --------------- + ------------------ +
| Variable_name | 价值|
+ --------------- + ------------------ +
| 基地| / usr / local / mysql |
+ --------------- + ------------------ +
您应该安装库的插件目录的位置由
plugin_dir
系统变量
给出
。
例如:
MySQL的> SHOW VARIABLES LIKE 'plugin_dir';
+ --------------- + --------------------------------- - +
| Variable_name | 价值|
+ --------------- + --------------------------------- - +
| plugin_dir | / usr / local / mysql / lib / mysql / plugin |
+ --------------- + --------------------------------- - +
要安装插件库,请使用 make :
外壳> make install
验证 make install 是否 在正确的目录中安装了插件库。 安装后,请确保库权限允许服务器执行它。
MySQL支持服务器端全文解析器插件
MyISAM
和
InnoDB
。
有关全文解析器插件的介绍性信息,请参阅
全文解析器插件
。
全文解析器插件可用于替换或修改内置的全文解析器。
本节介绍如何编写名为的全文解析器插件
simple_parser
。
此插件基于比MySQL内置全文解析器使用的规则更简单的规则执行解析:单词是空白字符的非空运行。
说明使用
plugin/fulltext
MySQL源代码分发目录中
的源代码
,因此将位置更改为该目录。
以下过程描述了如何创建插件库:
要编写全文解析器插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin.h>
plugin.h
定义
MYSQL_FTPARSER_PLUGIN
服务器插件类型和声明插件所需的数据结构。
设置插件库文件的库描述符。
此描述符包含服务器插件的常规插件描述符。
对于全文解析器插件,类型必须是
MYSQL_FTPARSER_PLUGIN
。
这是
WITH PARSER
在创建
FULLTEXT
索引
时
将插件标识为合法用于
子句的
值。
(此子句没有其他插件类型合法。)
例如,包含单个全文解析器插件的库的库描述符
simple_parser
如下所示:
mysql_declare_plugin(ftexample) { MYSQL_FTPARSER_PLUGIN,/ * type * / &simple_parser_descriptor,/ *描述符* / “simple_parser”,/ * name * / “Oracle Corporation”,/ * author * / “简单的全文解析器”,/ *描述* / PLUGIN_LICENSE_GPL,/ *插件许可证* / simple_parser_plugin_init,/ * init函数(加载时)* / simple_parser_plugin_deinit,/ * deinit函数(卸载时)* / 0x0001,/ *版本* / simple_status,/ *状态变量* / simple_system_variables,/ *系统变量* / 空值, 0 } mysql_declare_plugin_end;
所述
name
构件(
simple_parser
)指示要用于如在语句中的插件的引用名称
INSTALL
PLUGIN
或
UNINSTALL PLUGIN
。
这也是由
SHOW
PLUGINS
或
显示的名称
INFORMATION_SCHEMA.PLUGINS
。
有关更多信息,请参见 第29.2.4.2.1节“服务器插件库和插件描述符” 。
设置特定于类型的插件描述符。
库描述符中的每个通用插件描述符都指向特定于类型的描述符。
对于全文解析器插件,特定于类型的描述符是
文件中
st_mysql_ftparser
结构
的实例
plugin.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_VERSIONMYSQL_FTPARSER_INTERFACE_VERSION
include/mysql/plugin_ftparser.h
0x0101
的
init
和
deinit
成员应指向的函数,或者如果不需要该函数被设置为0。
该
parse
构件必须指向执行解析的功能。
在
simple_parser
声明中,该描述符由表示
&simple_parser_descriptor
。
描述符指定全文插件接口的版本号(由给定
MYSQL_FTPARSER_INTERFACE_VERSION
),以及插件的解析,初始化和取消初始化函数:
static struct st_mysql_ftparser simple_parser_descriptor = { MYSQL_FTPARSER_INTERFACE_VERSION,/ *接口版本* / simple_parser_parse,/ *解析函数* / simple_parser_init,/ *解析器初始化函数* / simple_parser_deinit / *解析器deinit函数* / };
全文解析器插件用于两种不同的上下文,索引和搜索。 在这两种情况下,服务器在处理导致调用插件的每个SQL语句的开头和结尾调用初始化和取消初始化函数。 但是,在语句处理期间,服务器以特定于上下文的方式调用主解析函数:
对于索引,服务器为要索引的每个列值调用解析器。
对于搜索,服务器调用解析器来解析搜索字符串。
也可以为语句处理的行调用解析器。
在自然语言模式下,服务器无需调用解析器。
对于布尔模式短语搜索或带有查询扩展的自然语言搜索,解析器用于解析不在索引中的信息的列值。
此外,如果对没有
FULLTEXT
索引
的列进行布尔模式搜索
,则将调用内置解析器。
(插件与特定索引相关联。如果没有索引,则不使用插件。)
在普通的插件描述符中的插件声明有
init
和
deinit
指向初始化和还原功能的部件,因此不会对特定类型的插件描述它所指向。
但是,这些函数对具有不同的用途,并且由于不同的原因而被调用:
对于通用插件描述符中的插件声明,在加载和卸载插件时调用初始化和取消初始化函数。
对于特定于类型的插件描述符,将根据使用该插件的SQL语句调用初始化和取消初始化函数。
插件描述符中指定的每个接口函数应该为成功返回零,或者为非失败返回非零,并且每个接口函数都接收一个指向
MYSQL_FTPARSER_PARAM
包含解析上下文
的
结构
的参数
。
结构有这个定义:
typedef struct st_mysql_ftparser_param { int(* mysql_parse)(struct st_mysql_ftparser_param *, char * doc,int doc_len); int(* mysql_add_word)(struct st_mysql_ftparser_param *, char * word,int word_len, MYSQL_FTPARSER_BOOLEAN_INFO * boolean_info); void * ftparser_state; void * mysql_ftparam; struct charset_info_st * cs; char * doc; int length; int标志; enum enum_ftparser_mode模式; MYSQL_FTPARSER_PARAM;
结构成员使用如下:
mysql_parse
:指向调用服务器内置解析器的回调函数的指针。
当插件充当内置解析器的前端时,请使用此回调。
也就是说,当调用插件解析函数时,它应该处理输入以提取文本并将文本传递给
mysql_parse
回调。
此回调函数的第一个参数应该是
param
值本身:
param-> mysql_parse(param,...);
前端插件可以提取文本并将其全部传递给内置解析器,或者它可以一次提取并将文本传递给内置解析器。 但是,在这种情况下,内置解析器会对文本片段进行处理,就像它们之间存在隐式字断开一样。
mysql_add_word
:指向回调函数的指针,该函数将单词添加到全文索引或搜索项列表中。
解析器插件替换内置解析器时使用此回调。
也就是说,当调用插件解析函数时,它应该将输入解析为单词并调用
mysql_add_word
每个单词
的
回调。
此回调函数的第一个参数应该是
param
值本身:
param-> mysql_add_word(param,...);
ftparser_state
:这是一个通用指针。
插件可以将其设置为指向内部用于其自身目的的信息。
mysql_ftparam
:这是由服务器设置的。
它作为第一个参数传递给
mysql_parse
或
mysql_add_word
回调。
cs
:指向文本字符集信息的指针,如果没有可用信息,则为0。
doc
:指向要解析的文本的指针。
length
:要解析的文本的长度,以字节为单位。
flags
:解析器标志。
如果没有特殊标志,则为零。
唯一的非零标志是
MYSQL_FTFLAGS_NEED_COPY
,这意味着
mysql_add_word()
必须保存该单词的副本(也就是说,它不能使用指向该单词的指针,因为该单词位于将被覆盖的缓冲区中。)
在调用解析器插件,解析器插件本身或
mysql_parse()
函数
之前,MySQL可以设置或重置此标志
。
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_len
和
ft_max_word_len
在tokenizer内部进行检查。
因为
InnoDB
,
在标记生成器之外检查
停用词列表和等效字长变量设置(
innodb_ft_min_token_size
和
innodb_ft_max_token_size
)。
因此,
InnoDB
插件解析器不需要检查停用词列表
innodb_ft_min_token_size
,或
innodb_ft_max_token_size
。
相反,建议返回所有单词
InnoDB
。
但是,如果要在插件解析器中检查停用词,请使用
MYSQL_FTPARSER_SIMPLE_MODE
,用于全文搜索索引和自然语言搜索。
对于
MYSQL_FTPARSER_WITH_STOPWORDS
和
MYSQL_FTPARSER_FULL_BOOLEAN_INFO
模式,建议
InnoDB
在短语搜索的情况下
将所有单词返回到
包括停用词。
如果在布尔模式下调用解析器,则
param->mode
值为
MYSQL_FTPARSER_FULL_BOOLEAN_INFO
。
该
MYSQL_FTPARSER_BOOLEAN_INFO
解析器用来传送令牌信息到服务器结构如下:
typedef struct st_mysql_ftparser_boolean_info { enum enum_ft_token_type类型; int yesno; int weight_adjust; char wasign; char trunc; int position; / *这些是解析器状态,必须删除。* / char prev; char * quot; MYSQL_FTPARSER_BOOLEAN_INFO;
解析器应该按如下方式填充结构成员:
type
:令牌类型。
下表显示了允许的类型。
表29.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,“布尔全文搜索”
,即使用
<
和
>
运营商说明如何加权作品。
wasign
:加权因子的符号。
负值的作用类似于
~
布尔搜索运算符,这会导致单词对相关性的贡献为负。
trunc
:是否应该进行匹配,就好像
*
已经给出
了布尔模式
截断运算符一样。
position
:文档中单词的起始位置,以字节为单位。
通过使用
InnoDB
全文搜索。
对于以布尔模式调用的现有插件,必须为位置成员添加支持。
插件不应该使用
prev
,并
quot
在成员
MYSQL_FTPARSER_BOOLEAN_INFO
结构。
插件解析器框架不支持:
该
@distance
布尔运算符。
前导加号(
+
)或减号(
-
)布尔运算符后跟空格,然后是单词(
'+
apple'
或
'- apple'
)。
前导加号或减号必须与单词直接相邻,例如:
'+apple'
或
'-apple'
。
有关布尔全文搜索运算符的信息,请参见 第12.9.2节“布尔全文搜索” 。
设置插件接口函数。
库描述符中的通用插件描述符命名服务器在加载和卸载插件时应调用的初始化和取消初始化函数。
因为
simple_parser
,这些函数什么都不做,只返回零表示它们成功:
static int simple_parser_plugin_init(void * arg __attribute __((unused))) { 返回(0); } static int simple_parser_plugin_deinit(void * arg __attribute __((unused))) { 返回(0); }
因为这些函数实际上没有做任何事情,所以可以省略它们并在插件声明中为每个函数指定0。
特定于类型的插件描述符,用于
simple_parser
命名服务器在使用插件时调用的初始化,取消初始化和解析函数。
因为
simple_parser
,初始化和取消初始化函数什么都不做:
static int simple_parser_init(MYSQL_FTPARSER_PARAM * param __attribute __((未使用的))) { 返回(0); } static int simple_parser_deinit(MYSQL_FTPARSER_PARAM * param __attribute __((未使用的))) { 返回(0); }
在这里,因为这些函数什么也不做,你可以省略它们并在插件描述符中为每个函数指定0。
主解析函数
simple_parser_parse()
可以替代内置的全文解析器,因此需要将文本拆分为单词并将每个单词传递给服务器。
解析函数的第一个参数是指向包含解析上下文的结构的指针。
此结构具有
doc
指向要解析的文本的
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(结束== docend) { if(结束>开始) add_word(param,start,end - start); 打破; } 否则if(isspace(* end)) { if(结束>开始) add_word(param,start,end - start); start = end + 1; } } 返回(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()
填充
bool_info
结构
的成员,如
结构讨论中所述
st_mysql_ftparser_boolean_info
。
设置状态变量。
对于
simple_parser
插件,以下状态变量数组设置一个状态变量,其值为静态文本,另一个状态变量具有存储在长整数变量中的值:
long number_of_calls = 0; struct st_mysql_show_var simple_status [] = { {“simple_parser_static”,(char *)“只是一个静态文本”,SHOW_CHAR}, {“simple_parser_called”,(char *)&number_of_calls,SHOW_LONG}, {0,0,0} };
通过使用以插件名称开头的状态变量名称,您可以轻松地显示插件的变量
SHOW
STATUS
:
MySQL的> SHOW STATUS LIKE 'simple_parser%';
+ ---------------------- + -------------------- +
| Variable_name | 价值|
+ ---------------------- + -------------------- +
| simple_parser_static | 只是一个静态文本|
| simple_parser_called | 0 |
+ ---------------------- + -------------------- +
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
对于
simple_parser
插件,它是从源代码构建MySQL时编译和安装的。
它也包含在二进制分发中。
构建过程生成一个名称为的共享对象库
mypluglib.so
(
.so
后缀可能因您的平台而异)。
要使用该插件,请将其注册到服务器。
例如,要在运行时注册插件,请使用此语句(
.so
根据需要
调整
平台
的
后缀):
安装PLUGIN simple_parser SONAME'mypluglib.so';
有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件” 。
要验证插件安装,请检查
INFORMATION_SCHEMA.PLUGINS
表或使用该
SHOW
PLUGINS
语句。
请参见
第5.6.2节“获取服务器插件信息”
。
测试插件以验证它是否正常工作。
创建一个包含字符串列的表,并将解析器插件与
FULLTEXT
列上的索引
相关联
:
mysql>CREATE TABLE t (c VARCHAR(255),
- >FULLTEXT (c) WITH PARSER simple_parser
- >) ENGINE=MyISAM;
查询OK,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');
查询OK,5行受影响(0.02秒) 记录:5个重复:0个警告:0 MySQL的>SELECT c FROM t;
+ ------------------------------------------------- - + | c | + ------------------------------------------------- - + | utf8mb4_0900_as_cs是区分大小写的排序规则| | 我想要一箱橘子| | 这是敏感信息| | 另一行| | 又一行| + ------------------------------------------------- - + 5行(0.00秒) MySQL的>SELECT MATCH(c) AGAINST('case') FROM t;
+ -------------------------- + | 比赛(c)反对('案例')| + -------------------------- + | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | + -------------------------- + 5行(0.00秒) MySQL的>SELECT MATCH(c) AGAINST('sensitive') FROM t;
+ ------------------------------- + | 比赛(c)反对('敏感')| + ------------------------------- + | 0 | | 0 | | 1.3253291845322 | | 0 | | 0 | + ------------------------------- + 5行(0.01秒) MySQL的>SELECT MATCH(c) AGAINST('case-sensitive') FROM t;
+ ------------------------------------ + | 匹配(c)反对('区分大小写')| + ------------------------------------ + | 1.3109166622162 | | 0 | | 0 | | 0 | | 0 | + ------------------------------------ + 5行(0.01秒) MySQL的>SELECT MATCH(c) AGAINST('I\'d') FROM t;
+ -------------------------- + | 比赛(c)反对('我'')| + -------------------------- + | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | + -------------------------- + 5行(0.01秒)
“ case ” 和 “ insensitive ” 都不 匹配 “ 不区分大小写 ” 它们对内置解析器的方式。
守护程序插件是一种简单类型的插件,用于应由服务器运行但不与之通信的代码。
本节介绍如何使用
plugin/daemon_example
MySQL源代码分发目录中
的示例插件编写守护程序服务器插件
。
该目录包含
daemon_example.cc
名为守护进程插件
的
源文件,该守护进程插件以固定
daemon_example
间隔将心跳字符串写入
mysql-heartbeat.log
数据目录中
指定的文件
。
要编写守护程序插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin.h>
plugin.h
定义
MYSQL_DAEMON_PLUGIN
服务器插件类型和声明插件所需的数据结构。
该
daemon_example.cc
文件设置库描述符如下。
库描述符包括单个通用服务器插件描述符。
mysql_declare_plugin(daemon_example) { MYSQL_DAEMON_PLUGIN, &daemon_example_plugin, “daemon_example” “Brian Aker”, “守护进程示例,在mysql-heartbeat.log中创建一个心跳节拍文件”, PLUGIN_LICENSE_GPL, daemon_example_plugin_init,/ *插件初始化* / daemon_example_plugin_deinit,/ *插件Deinit * / 0x0100 / * 1.0 * /, NULL,/ *状态变量* / NULL,/ *系统变量* / NULL,/ * config选项* / 0,/ *标志* / } mysql_declare_plugin_end;
所述
name
构件(
daemon_example
)指示要用于如在语句中的插件的引用名称
INSTALL
PLUGIN
或
UNINSTALL
PLUGIN
。
这也是由
SHOW
PLUGINS
或
显示的名称
INFORMATION_SCHEMA.PLUGINS
。
插件描述符的第二个成员
daemon_example_plugin
指向特定于类型的守护程序插件描述符。
此结构仅包含特定于类型的API版本号:
struct st_mysql_daemon daemon_example_plugin = {MYSQL_DAEMON_INTERFACE_VERSION};
特定于类型的结构没有接口功能。 服务器和插件之间没有通信,除了服务器从通用插件描述符调用初始化和取消初始化函数来启动和停止插件:
daemon_example_plugin_init()
打开心跳文件并生成一个定期唤醒的线程,并将下一条消息写入该文件。
daemon_example_plugin_deinit()
关闭文件并执行其他清理。
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
对于
daemon_example
插件,它是从源代码构建MySQL时编译和安装的。
它也包含在二进制分发中。
构建过程生成一个名称为的共享对象库
libdaemon_example.so
(
.so
后缀可能因您的平台而异)。
要使用该插件,请将其注册到服务器。
例如,要在运行时注册插件,请使用此语句(
.so
根据需要
调整
平台
的
后缀):
INSTALL PLUGIN daemon_example SONAME'ibdaemon_example.so';
有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件” 。
要验证插件安装,请检查
INFORMATION_SCHEMA.PLUGINS
表或使用该
SHOW
PLUGINS
语句。
请参见
第5.6.2节“获取服务器插件信息”
。
在加载插件时,它会定期将心跳字符串写入
mysql-heartbeat.log
数据目录中
指定的文件
。
此文件无限制地增长,因此在您满意自己插件正常运行后,请将其卸载:
UNINSTALL PLUGIN daemon_example;
本节介绍如何编写服务器端
INFORMATION_SCHEMA
表插件。
例如,实现此类插件的代码,请参阅
sql/sql_show.cc
MySQL源代码分发
的
文件。
您还可以查看
InnoDB
源代码
中的示例插件
。
请参阅
源树中
的
handler/i_s.cc
和
handler/ha_innodb.cc
文件
InnoDB
(在
storage/innobase
目录中)。
要编写
INFORMATION_SCHEMA
表插件,请在插件源文件中包含以下头文件。
根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <sql_class.h> #include <table.h>
这些头文件位于
sql
MySQL源代码分发目录中。
它们包含C ++结构,因此
INFORMATION_SCHEMA
插件
的源文件
必须编译为C ++代码。
这里开发的示例插件的源文件名为
simple_i_s_table.cc
。
它创建一个
INFORMATION_SCHEMA
名为
的简单
表
SIMPLE_I_S_TABLE
,其中有两列名为
NAME
和
VALUE
。
实现该表的插件库的一般描述符如下所示:
mysql_declare_plugin(simple_i_s_library) { MYSQL_INFORMATION_SCHEMA_PLUGIN, &simple_table_info,/ *特定于类型的描述符* / “SIMPLE_I_S_TABLE”,/ *表名* / “作者姓名”,/ *作者* / “简单INFORMATION_SCHEMA表”,/ *说明* / PLUGIN_LICENSE_GPL,/ *许可证类型* / simple_table_init,/ * init函数* / 空值, 0x0100,/ *版本= 1.0 * / NULL,/ *没有状态变量* / NULL,/ *没有系统变量* / NULL,/ *没有保留信息* / 0 / *没有标志* / } mysql_declare_plugin_end;
所述
name
构件(
SIMPLE_I_S_TABLE
)指示要用于如在语句中的插件的引用名称
INSTALL
PLUGIN
或
UNINSTALL
PLUGIN
。
这也是由
SHOW
PLUGINS
或
显示的名称
INFORMATION_SCHEMA.PLUGINS
。
simple_table_info
通用描述符
的
成员指向特定于类型的描述符,该描述符仅包含特定于类型的API版本号:
static struct st_mysql_information_schema simple_table_info = {MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION};
通用描述符指向初始化和取消初始化函数:
初始化函数提供有关表结构和填充表的函数的信息。
取消初始化函数执行任何所需的清理。
如果不需要清理,则此描述符成员可以
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; 返回0; }
该函数应该设置表结构的这两个成员:
fields_info
:
ST_FIELD_INFO
包含有关每列的信息
的
结构
数组
。
fill_table
:填充表的函数。
指向的数组
fields_info
应该包含每个列的一个元素
INFORMATION_SCHEMA
加上一个终止元素。
simple_table_fields
示例插件
的以下
数组表示它
SIMPLE_I_S_TABLE
有两列。
NAME
是字符串值,长度为10,
VALUE
是整数值,显示宽度为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
在
table.h
头文件中。
允许的
类型值是C API中使用的值;
请参见
第28.7.5节“C API数据结构”
。
MYSQL_TYPE_
xxx
该
fill_table
成员应设置为填充表的函数,并返回0表示成功,如果发生错误则返回1。
对于示例插件,该
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); 表 - >字段[1] - >存储(1); if(schema_table_store_record(thd,table)) 返回1; table-> field [0] - > store(“Name 2”,6,system_charset_info); 表 - >字段[1] - >存储器(2); if(schema_table_store_record(thd,table)) 返回1; 返回0; }
对于
INFORMATION_SCHEMA
表的
每一行
,此函数初始化每列,然后调用
schema_table_store_record()
以安装该行。
该
store()
参数取决于的值的类型的方法来被存储。
对于第0列(
NAME
,字符串),
store()
获取指向字符串的指针,其长度以及有关字符串字符集的信息:
store(const char * to,uint length,CHARSET_INFO * cs);
对于第1列(
VALUE
,整数),
store()
取值和一个标志,指示它是否为无符号:
store(longlong nr,bool unsigned_value);
有关如何填充
INFORMATION_SCHEMA
表的
其他示例
,请搜索
schema_table_store_record()
in的
实例
sql_show.cc
。
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
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 | 价值|
+ -------- + ------- +
| 名称1 | 1 |
| 名称2 | 2 |
+ -------- + ------- +
卸载它:
MySQL的> UNINSTALL PLUGIN SIMPLE_I_S_TABLE;
本节介绍如何使用
plugin/semisync
MySQL源代码分发目录中
的示例插件编写服务器端半同步复制插件
。
该目录包含名为
rpl_semi_sync_master
和的
主插件和从属插件的源文件
rpl_semi_sync_slave
。
这里的信息仅包括如何设置插件框架。
有关插件如何实现复制功能的详细信息,请参阅源代码。
要编写半同步复制插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin.h>
plugin.h
定义
MYSQL_REPLICATION_PLUGIN
服务器插件类型和声明插件所需的数据结构。
对于主端,
semisync_master_plugin.cc
包含一个名为的插件的通用描述符
rpl_semi_sync_master
:
mysql_declare_plugin(semi_sync_master) { MYSQL_REPLICATION_PLUGIN, &semi_sync_master_plugin, “rpl_semi_sync_master” “何振兴”, “半同步复制主机”, PLUGIN_LICENSE_GPL, semi_sync_master_plugin_init,/ * Plugin Init * / semi_sync_master_plugin_deinit,/ *插件Deinit * / 0x0100 / * 1.0 * /, semi_sync_master_status_vars,/ *状态变量* / semi_sync_master_system_vars,/ *系统变量* / NULL,/ * config选项* / 0,/ *标志* / } mysql_declare_plugin_end;
对于slave端,
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” “何振兴”, “半同步复制从属”, PLUGIN_LICENSE_GPL, semi_sync_slave_plugin_init,/ * Plugin Init * / semi_sync_slave_plugin_deinit,/ *插件Deinit * / 0x0100 / * 1.0 * /, semi_sync_slave_status_vars,/ *状态变量* / semi_sync_slave_system_vars,/ *系统变量* / NULL,/ * config选项* / 0,/ *标志* / } mysql_declare_plugin_end;
对于主插件和从插件,通用描述符具有指向特定于类型的描述符,初始化和取消初始化函数以及插件实现的状态和系统变量的指针。 有关变量设置的信息,请参见 第29.2.4.2.2节“服务器插件状态和系统变量” 。 以下注释讨论了类型特定的描述符以及主插件的初始化和取消初始化函数,但类似地应用于从插件。
semi_sync_master_plugin
主通用描述符
的
成员指向特定于类型的描述符,该描述符仅包含特定于类型的API版本号:
struct Mysql_replication semi_sync_master_plugin = { MYSQL_REPLICATION_INTERFACE_VERSION };
初始化和取消初始化函数声明如下所示:
static int semi_sync_master_plugin_init(void * p); static int semi_sync_master_plugin_deinit(void * p);
初始化函数使用指针向服务器注册事务和二进制日志 “ 观察者 ” 。 成功初始化后,服务器负责在适当的时间调用观察者。 (有关观察者的详细信息,请参阅源文件。)通过取消注册观察者来清除取消初始化函数。 每个函数返回0表示成功,如果发生错误则返回1。
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
对于
rpl_semi_sync_master
和
rpl_semi_sync_slave
插件,从源代码构建MySQL时会编译和安装它们。
它们也包含在二进制分发中。
构建过程生成名称为
semisync_master.so
和的
共享对象库
semisync_slave.so
(
.so
后缀可能因您的平台而异)。
本节介绍如何使用
plugin/audit_null
MySQL源代码分发目录中
的示例插件编写服务器端审计插件
。
该
目录中的源文件
audit_null.c
和
audit_null_variables.h
文件实现了一个名为的审计插件
NULL_AUDIT
。
使用审计插件API的插件的其他示例是查询重写插件(请参见 第5.6.4节“重写器查询重写插件” )和版本标记插件(请参见 第5.6.6节“版本标记” )。
在服务器内,可插拔审计接口在
MySQL源代码分发目录
中的
sql_audit.h
和
sql_audit.cc
文件中
实现
sql
。
此外,当发生可审计事件时,服务器中的多个位置会调用审计接口,以便在必要时通知已注册的审计插件。
要查看此类调用发生的位置,请在服务器源文件中搜索具有表单名称的函数调用
。
服务器操作发生审核通知,例如:
mysql_audit_
xxx
()
客户端连接和断开事件
将消息写入常规查询日志(如果启用了日志)
将消息写入错误日志
将查询结果发送给客户端
要编写审计插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin_audit.h>
plugin_audit.h
包含
plugin.h
,因此您无需明确包含后一个文件。
plugin.h
定义
MYSQL_AUDIT_PLUGIN
服务器插件类型和声明插件所需的数据结构。
plugin_audit.h
定义特定于审计插件的数据结构。
与任何MySQL服务器插件一样,审计插件具有通用插件描述符(请参见
第29.2.4.2.1节“服务器插件库和插件描述符”
)和类型特定的插件描述符。
在
audit_null.c
,一般描述符
audit_null
看起来像这样:
mysql_declare_plugin(audit_null) { MYSQL_AUDIT_PLUGIN,/ * type * / &audit_null_descriptor,/ *描述符* / “NULL_AUDIT”,/ * name * / “甲骨文公司”,/ *作者* / “Simple NULL Audit”,/ * description * / PLUGIN_LICENSE_GPL, audit_null_plugin_init,/ * init函数(加载时)* / audit_null_plugin_deinit,/ * deinit函数(卸载时)* / 0x0003,/ *版本* / simple_status,/ *状态变量* / system_variables,/ *系统变量* / 空值, 0, } mysql_declare_plugin_end;
第一个成员
MYSQL_AUDIT_PLUGIN
将此插件标识为审计插件。
audit_null_descriptor
指向特定于类型的插件描述符,稍后描述。
所述
name
构件(
NULL_AUDIT
)指示要用于如在语句中的插件的引用名称
INSTALL
PLUGIN
或
UNINSTALL
PLUGIN
。
这也是由
INFORMATION_SCHEMA.PLUGINS
或
显示的名称
SHOW
PLUGINS
。
该
audit_null_plugin_init
被加载插件时初始化函数执行插件初始化。
该
audit_null_plugin_deinit
函数在卸载插件时执行清理。
一般的插件描述符还指
simple_status
和
system_variables
,暴露多个状态和系统变量的结构。
启用插件后,可以使用
SHOW
语句(
SHOW
STATUS
,
SHOW
VARIABLES
)或相应的性能架构表
检查这些变量
。
该
simple_status
结构使用表单名称声明了几个状态变量
。
为其收到的每个通知
递增
状态变量。
其他状态变量更具体,
仅为特定事件的通知增加它们。
Audit_null_
xxx
NULL_AUDIT
Audit_null_called
NULL_AUDIT
system_variables
是一个系统变量元素的数组,每个元素都是使用
宏
定义的
。
这些系统变量具有表单的名称
。
这些变量可用于在运行时与插件进行通信。
MYSQL_THDVAR_
xxx
null_audit_
xxx
audit_null_descriptor
通用插件描述符中
的
值指向特定于类型的插件描述符。
对于审计插件,此描述符具有以下结构(在中定义
plugin_audit.h
):
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
成员
的值
是
MYSQL_AUDIT_INTERFACE_VERSION
(在中定义
plugin_audit.h
)。
release_thd
:服务器调用的函数,通知插件它正在与其线程上下文分离。
这应该
NULL
是没有这样的功能。
event_notify
:服务器调用以通知插件已发生可审计事件的函数。
这个功能不应该是
NULL
;
这没有意义,因为不会发生审计。
class_mask
:一系列
MYSQL_AUDIT_CLASS_MASK_SIZE
元素。
每个元素指定给定事件类的位掩码,以指示插件想要通知的子类。
(这是插件
“
订阅
”
感兴趣的事件的方式。)元素应为0以忽略相应事件类的事件。
服务器
一起
使用
event_notify
和
release_thd
功能。
它们在特定线程的上下文中调用,并且线程可以执行产生多个事件通知的活动。
服务器第一次调用
event_notify
线程时,它会创建插件与线程的绑定。
存在此绑定时,无法卸载该插件。
当没有更多的线程事件发生时,服务器通过调用来通知插件
release_thd
功能,然后破坏绑定。
例如,当客户端发出语句时,处理该语句的线程可能会通知审计插件有关该语句生成的结果集以及正在记录的语句。
发生这些通知后,服务器会在将线程置于休眠状态之前释放插件,直到客户端发出另一个语句。
这种设计使插件能够在第一次调用
event_notify
函数时
分配给定线程所需的资源,并在
函数中释放它们
release_thd
:
event_notify函数: 如果需要内存来服务线程 分配内存 ...其余的通知处理...... release_thd函数: 如果分配了内存 释放记忆 ...其余的发布处理......
这比在通知功能中重复分配和释放内存更有效。
对于
NULL_AUDIT
审计插件,特定于类型的插件描述符如下所示:
static struct st_mysql_audit audit_null_descriptor = { MYSQL_AUDIT_INTERFACE_VERSION,/ *接口版本* / NULL,/ * release_thd函数* / 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, / *此项必须在列表的最后。* / MYSQL_AUDIT_CLASS_MASK_SIZE } mysql_event_class_t;
对于任何给定的事件类,
plugin_audit.h
定义各个事件子类的位掩码符号,以及作为
所有子类
位掩码的并集的
符号。
例如,对于
xxx
_ALLMYSQL_AUDIT_CONNECTION_CLASS
(涵盖连接和断开事件的类),
plugin_audit.h
定义以下符号:
typedef enum { 认证阶段完成后发生/ **。* / MYSQL_AUDIT_CONNECTION_CONNECT = 1 << 0, 连接终止后发生/ **。* / MYSQL_AUDIT_CONNECTION_DISCONNECT = 1 << 1, / **在COM_CHANGE_USER RPC完成后发生。* / MYSQL_AUDIT_CONNECTION_CHANGE_USER = 1 << 2, / **在认证之前发生。* / 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
插件所做的那样),插件
MYSQL_AUDIT_CONNECTION_ALL
在相应的
class_mask
元素中
指定
(
class_mask[1]
在本例中)。
为了只订阅一些子类,插件将
class_mask
元素
设置
为感兴趣的子类的并集。
例如,要仅订阅connect和change-user子类,插件将设置
class_mask[1]
为此值:
MYSQL_AUDIT_CONNECTION_CONNECT | MYSQL_AUDIT_CONNECTION_CHANGE_USER
审计插件的大部分工作都发生在通知函数(
event_notify
特定于类型的插件描述符
的
成员)中。
服务器为每个可审计事件调用此函数。
审计插件通知函数有这个原型:
int(* event_notify)(MYSQL_THD,mysql_event_class_t,const void *);
event_notify
函数原型
的第二个和第三个参数
表示事件类和事件结构的通用指针。
(不同类中的事件具有不同的结构。通知函数可以使用事件类值来确定应用哪个事件结构。)该函数处理事件并返回指示服务器是否应继续处理事件或终止事件的状态。
对于
NULL_AUDIT
,通知功能是
audit_null_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 *)事件; ... } else if(event_class == MYSQL_AUDIT_CONNECTION_CLASS) { const struct mysql_event_connection * event_connection = (const struct mysql_event_connection *)事件; ... } else if(event_class == MYSQL_AUDIT_PARSE_CLASS) { const struct mysql_event_parse * event_parse = (const struct mysql_event_parse *)事件; ... } ... }
通知函数
event
根据值
解释
参数
event_class
。
所述
event
参数是一个通用的指针事件记录,其结构的每个事件类不同。
(该
plugin_audit.h
文件包含定义每个事件类内容的结构。)对于每个类,
audit_null_notify()
将事件转换为适当的特定于类的结构,然后检查其子类以确定要递增的子类计数器。
例如,处理连接事件类中的事件的代码如下所示:
else if(event_class == MYSQL_AUDIT_CONNECTION_CLASS) { const struct mysql_event_connection * event_connection = (const struct mysql_event_connection *)事件; switch(event_connection-> event_subclass) { case MYSQL_AUDIT_CONNECTION_CONNECT: number_of_calls_connection_connect ++; 打破; case MYSQL_AUDIT_CONNECTION_DISCONNECT: number_of_calls_connection_disconnect ++; 打破; case MYSQL_AUDIT_CONNECTION_CHANGE_USER: number_of_calls_connection_change_user ++; 打破; case MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE: number_of_calls_connection_pre_authenticate ++; 打破; 默认: 打破; } }
MYSQL_AUDIT_GENERAL_CLASS
自MySQL 5.7.9起,
一般事件class(
)已被弃用,将在未来的MySQL版本中删除。
为了减少插件开销,最好只订阅更感兴趣的特定事件类。
对于某些事件类,
NULL_AUDIT
除了递增计数器之外
,
插件还执行其他处理。
在任何情况下,当通知功能完成处理事件时,它应返回一个状态,指示服务器是应该继续处理事件还是终止事件。
审核插件通知功能可以通过两种方式报告当前事件的状态值:
使用通知函数返回值。 在这种情况下,如果服务器应继续处理事件,则函数返回零;如果服务器应终止事件,则函数返回非零值。
my_message()
在从通知功能返回之前
调用该
函数来设置错误状态。
在这种情况下,忽略通知函数返回值,服务器终止事件处理并显示错误。
该
my_message()
参数指示哪些错误报告,它的消息。
例如:
my_message(ER_AUDIT_API_ABORT,“这是我的错误信息。”,MYF(0));
有些事件无法中止。
不考虑非零返回值,
my_message()
错误调用必须遵循
is_error()
检查。
例如:
if(!thd-> get_stmt_da() - > is_error()) { my_message(ER_AUDIT_API_ABORT,“这是我的错误信息。”,MYF(0)); }
某些事件无法终止:
MYSQL_AUDIT_CONNECTION_DISCONNECT
:服务器无法阻止客户端断开连接。
MYSQL_AUDIT_COMMAND_END
:此事件提供已完成执行的命令的状态,因此无法终止它。
如果审计插件返回非终止事件的非零状态,则服务器将忽略该状态并继续处理该事件。
如果审计插件使用该
my_message()
函数终止
不可
终结事件,
则也是如此
。
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
对于
NULL_AUDIT
插件,它是从源代码构建MySQL时编译和安装的。
它也包含在二进制分发中。
构建过程生成一个名称为的共享对象库
adt_null.so
(
.so
后缀可能因您的平台而异)。
要在运行时注册插件,请使用此语句(
.so
根据需要
调整
平台
的
后缀):
INSTALL PLUGIN NULL_AUDIT SONAME'adt_null.so';
有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件” 。
要验证插件安装,请检查
INFORMATION_SCHEMA.PLUGINS
表或使用该
SHOW
PLUGINS
语句。
请参见
第5.6.2节“获取服务器插件信息”
。
安装审计插件时,它会公开状态变量,指示已调用插件的事件:
MySQL的> SHOW STATUS LIKE 'Audit_null%';
+ ---------------------------------------- + -------- +
| Variable_name | 价值|
+ ---------------------------------------- + -------- +
| 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_called
,
Audit_null_general_result
以及
Audit_null_general_log
将每次递增。
无论是否启用该日志,都会发生通知。
状态变量值在所有会话中聚合。 单个会话没有计数器。
NULL_AUDIT
公开了几个系统变量,可以在运行时与插件进行通信:
MySQL的> SHOW VARIABLES LIKE 'null_audit%';
+ ------------------------------------ + ------- +
| Variable_name | 价值|
+ ------------------------------------ + ------- +
| null_audit_abort_message | |
| null_audit_abort_value | 1 |
| null_audit_event_order_check | |
| null_audit_event_order_check_exact | 1 |
| null_audit_event_order_started | 0 |
| null_audit_event_record | |
| null_audit_event_record_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
在
MYSQL_AUDIT_QUERY_STATUS_END
事件发生
时
中止
语句执行
:
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):由审计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
在此错误中
执行
结果:
ERROR 3164(HY000):由审计API('MYSQL_AUDIT_QUERY_START'; 123)中止。
事件也可以通过设置
null_audit_abort_message
变量
指定的自定义消息中止
:假设您设置审计日志系统变量,如下所示:
SET null_audit_abort_message ='自定义错误文本。'; 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):自定义错误文本。
出于测试创建的目的,可以记录通过插件的事件。
通过在
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;
MySQL支持可插入身份验证,其中调用插件来验证客户端连接。
身份验证插件允许使用除
mysql.user
系统表中
存储的密码的内置方法之外的身份验证方法
。
例如,可以编写插件来访问外部认证方法。
此外,认证插件可以支持代理用户能力,使得连接用户是另一个用户的代理,并且出于访问控制的目的,将其视为具有不同用户的特权。
有关更多信息,请参见
第6.2.17节“可插入身份验证”
和
第6.2.18节“代理用户”
。
可以为服务器端或客户端编写认证插件。 服务器端插件使用与其他服务器插件类型相同的插件API,例如全文解析器或审计插件(尽管具有不同的特定于类型的描述符)。 客户端插件使用客户端插件API。
几个头文件包含与身份验证插件相关的信息:
plugin.h
:定义
MYSQL_AUTHENTICATION_PLUGIN
服务器插件类型。
client_plugin.h
:定义客户端插件的API。
这包括客户端插件描述符和客户端插件C API调用的函数原型(请参见
第28.7.17节“C API客户端插件函数”
)。
plugin_auth.h
:定义特定于身份验证插件的服务器插件API的一部分。
这包括服务器端身份验证插件的类型特定描述符和
MYSQL_SERVER_AUTH_INFO
结构。
plugin_auth_common.h
:包含客户端和服务器身份验证插件的常见元素。
这包括返回值定义和
MYSQL_PLUGIN_VIO
结构。
要编写身份验证插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
对于实现服务器身份验证插件的源文件,请包含以下文件:
#include <mysql / plugin_auth.h>
对于实现客户端身份验证插件或客户端和服务器插件的源文件,请包含以下文件:
#include <mysql / plugin_auth.h> #include <mysql / client_plugin.h> #include <mysql.h>
plugin_auth.h
包括
plugin.h
和
plugin_auth_common.h
,因此您不需要明确包含后面的文件。
本节介绍如何编写一对协同工作的简单服务器和客户端身份验证插件。
这些插件接受任何非空密码,密码以明文形式发送。 这是不安全的,因此插件 不应该在生产环境中使用。
这里开发的服务器端和客户端插件都被命名
auth_simple
。
如
第29.2.4.2节“插件数据结构”
中所述,插件库文件必须与客户端插件具有相同的基本名称,因此源文件名是
auth_simple.c
并生成一个名为的库
auth_simple.so
(假设您的系统使用
.so
后缀作为后缀)库文件)。
在MySQL源代码发行版中,身份验证插件源位于
plugin/auth
目录中,可以作为编写其他身份验证插件的指南进行检查。
另外,要了解如何实现内置身份验证插件,请参阅
sql/sql_acl.cc
内置于MySQL服务器
sql-common/client.c
的插件以及内置于
libmysqlclient
客户端库的
插件
。
(对于内置客户端插件,请注意其中
auth_plugin_t
使用的结构与通常的客户端插件声明宏使用的结构不同。特别是,前两个成员是显式提供的,而不是声明宏。)
使用通常的通用描述符格式声明服务器端插件,该格式用于所有服务器插件类型(请参见
第29.2.4.2.1节“服务器插件库和插件描述符”
)。
对于
auth_simple
插件,描述符如下所示:
mysql_declare_plugin(auth_simple) { MYSQL_AUTHENTICATION_PLUGIN, &auth_simple_handler,/ *特定于类型的描述符* / “auth_simple”,/ *插件名称* / “作者姓名”,/ *作者* / “Any-password authentication plugin”,/ * description * / PLUGIN_LICENSE_GPL,/ *许可证类型* / NULL,/ *没有init函数* / NULL,/ *没有deinit函数* / 0x0100,/ *版本= 1.0 * / NULL,/ *没有状态变量* / NULL,/ *没有系统变量* / NULL,/ *没有保留信息* / 0 / *没有标志* / } mysql_declare_plugin_end;
所述
name
构件(
auth_simple
)指示要用于如在语句中的插件的引用名称
INSTALL
PLUGIN
或
UNINSTALL
PLUGIN
。
这也是由
SHOW
PLUGINS
或
显示的名称
INFORMATION_SCHEMA.PLUGINS
。
auth_simple_handler
通用描述符
的
成员指向特定于类型的描述符。
对于身份验证插件,特定于类型的描述符是
st_mysql_auth
结构
的实例
(在中定义
plugin_auth.h
):
struct st_mysql_auth { int interface_version; const char * client_auth_plugin; int(* authenticate_user)(MYSQL_PLUGIN_VIO * vio,MYSQL_SERVER_AUTH_INFO * 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 buflen); int(* set_salt)(const char * password,unsigned int password_len, unsigned char * salt,unsigned char * salt_len); const unsigned long authentication_flags; };
该
st_mysql_auth
结构具有以下成员:
interface_version
:始终是特定于类型的API版本号
MYSQL_AUTHENTICATION_INTERFACE_VERSION
client_auth_plugin
:客户端插件名称
authenticate_user
:指向与客户端通信的主插件函数的指针
generate_authentication_string
:指向插件函数的指针,该函数从身份验证字符串生成密码摘要
validate_authentication_string
:指向验证密码摘要的插件函数的指针
set_salt
:指向将加扰密码转换为二进制形式的插件函数的指针
authentication_flags
:一个标志词
client_auth_plugin
如果需要特定的插件,
该
成员应指明客户端插件的名称。
的值
NULL
的装置
“
的任何插件。
“
在后一种情况下,客户端使用的任何插件都可以。
如果服务器插件不关心客户端插件或它发送的用户名或密码,这很有用。
例如,如果服务器插件仅对本地客户端进行身份验证并使用操作系统的某些属性而不是客户端插件发送的信息,则可能会出现这种情况。
对于
auth_simple
,特定于类型的描述符如下所示:
static struct st_mysql_auth auth_simple_handler = { MYSQL_AUTHENTICATION_INTERFACE_VERSION, “auth_simple”,/ *需要客户端插件名称* / auth_simple_server / *服务器端插件主要功能* / generate_auth_string_hash,/ *从密码字符串生成摘要* / validate_auth_string_hash,/ *验证密码摘要* / set_salt,/ *生成密码盐值* / AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE };
main函数
auth_simple_server()
采用两个表示I / O结构和
MYSQL_SERVER_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;
字符串成员的字符集是UTF-8。
如果存在
_length
与字符串关联
的
成员,则表示字符串长度(以字节为单位)。
字符串也以空值终止。
当服务器调用身份验证插件时,它应该
MYSQL_SERVER_AUTH_INFO
如下
解释
结构成员。
其中一些用于在客户端会话中设置SQL函数或系统变量的值,如图所示。
user_name
:客户端发送的用户名。
该值成为
USER()
函数值。
user_name_length
:
user_name
以字节
为
单位
的长度
。
auth_string
:
系统表
authentication_string
中行
的
列
的值,
mysql.user
用于匹配的帐户名称(即,与客户端用户名和主机名匹配的行,以及服务器用于确定如何对客户端进行身份验证的行)。
假设您使用以下语句创建帐户:
创建用户'my_user'@'localhost' 用my_plugin AS'my_auth_string'识别;
当
my_user
从本地主机连接时,服务器调用
my_plugin
,并传递
'my_auth_string'
到它作为
auth_string
值。
auth_string_length
:
auth_string
以字节
为
单位
的长度
。
authenticated_as
:服务器将此设置为用户名(值
user_name
)。
插件可以更改它以指示客户端应具有不同用户的权限。
例如,如果插件支持代理用户,则初始值是连接(代理)用户的名称,插件可以将此成员更改为代理用户名。
然后,服务器将代理用户视为具有代理用户的权限(假设满足代理用户支持的其他条件;请参见
第29.2.4.9.4节“在身份验证插件中实现代理用户支持”
)。
该值表示为大多数
MYSQL_USER_NAME_LENGTH
字节长
的字符串
加上终止空值。
该值成为
CURRENT_USER()
函数值。
external_user
:服务器将此设置为空字符串(以null结尾)。
其值成为
external_user
系统变量值。
如果插件希望该系统变量具有不同的值,则应相应地设置此成员(例如,设置连接用户名)。
该值表示为最多511个字节长的字符串,加上终止空值。
password_used
:此成员在身份验证失败时应用。
该插件可以设置或忽略它。
该值用于构造失败错误消息
Authentication fails. Password
used: %s
。
值
password_used
确定如何
%s
处理,如下表所示。
host_or_ip
:客户端主机的名称(如果可以解析),或者IP地址。
host_or_ip_length
:
host_or_ip
以字节
为
单位
的长度
。
的
auth_simple
主要功能,
auth_simple_server()
,读取来自客户端的密码(一个空终止字符串)和成功,如果密码不为空(第一个字节不是null):
static int auth_simple_server(MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info) { unsigned char * pkt; int pkt_len; / *将密码读取为以null结尾的字符串,在出错时失败* / if((pkt_len = vio-> read_packet(vio,&pkt))<0) 返回CR_ERROR; / *空密码失败* / if(!pkt_len || * pkt =='\ 0') { info-> password_used = PASSWORD_USED_NO; 返回CR_ERROR; } / *接受任何非空密码* / info-> password_used = PASSWORD_USED_YES; 返回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
源文件。
服务器计算Performance Schema
host_cache
表
中的插件错误
。
auth_simple_server()
是非常基本的,它不使用身份验证信息结构,除了设置指示是否收到密码的成员。
支持代理用户的插件必须向代理服务器返回代理用户的名称(客户端用户应获得其权限的MySQL用户)。
为此,插件必须将
info->authenticated_as
成员设置为代理用户名。
有关代理的信息,请参见
第6.2.18节“代理用户”
和
第29.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) { / * 如果服务器指定的缓冲区无法复制到输出缓冲区,则失败 * / if(* buflen <inbuflen) 返回1; / *错误* / strncpy(outbuf,inbuf,inbuflen); * buflen = strlen(inbuf); 返回0; / *成功* / }
validate_authentication_string
插件描述符
的
成员验证密码哈希:
参数是指向密码哈希的指针及其长度(以字节为单位)。
该函数返回0表示成功,如果无法验证密码哈希,则返回1。
对于
auth_simple
插件,该
validate_auth_string_hash()
函数实现了该
validate_authentication_string
成员。
它无条件地返回成功:
int validate_auth_string_hash(char * const inbuf __attribute __((unused)), unsigned int buflen __attribute __((unused))) { 返回0; / *成功* / }
set_salt
插件描述符
的
成员仅由
mysql_native_password
插件使用(请参见
第6.4.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; 返回0; / *成功* / }
authentication_flags
插件描述符
的
成员包含影响插件操作的标志。
允许的标志是:
AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE
:凭据更改是特权操作。
如果设置了此标志,则服务器要求用户具有
数据库
的全局
CREATE USER
特权或
UPDATE
特权
mysql
。
AUTH_FLAG_USES_INTERNAL_STORAGE
:无论插件使用内部存储(在
authentication_string
列
mysql.user
行)。
如果未设置此标志,则尝试设置密码失败,服务器将发出警告。
使用
mysql_declare_client_plugin()
和
mysql_end_client_plugin
宏
声明客户端插件描述符
(请参见
第29.2.4.2.3节“客户端插件描述符”
)。
对于
auth_simple
插件,描述符如下所示:
mysql_declare_client_plugin(认证) “auth_simple”,/ *插件名称* / “作者姓名”,/ *作者* / “Any-password authentication plugin”,/ * description * / {1,0,0},/ *版本= 1.0.0 * / “GPL”,/ *许可证类型* / NULL,/ *供内部使用* / NULL,/ *没有init函数* / NULL,/ *没有deinit函数* / NULL,/ *没有选项处理函数* / auth_simple_client / *主要功能* / mysql_end_client_plugin;
插件名称到选项处理函数的描述符成员对于所有客户端插件类型都是通用的。 (有关说明,请参见 第29.2.4.2.3节“客户端插件描述符” 。)在公共成员之后,描述符还有一个特定于身份验证插件的附加成员。 这是 “ 主要 ” 功能,它处理与服务器的通信。 该函数接受两个表示I / O结构和连接处理程序的参数。 对于我们简单的any-password插件,main函数除了向服务器写入用户提供的密码外什么都不做:
static int auth_simple_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql) { int res; / *将密码作为以空字符结尾的字符串发送为明文* / res = vio-> write_packet(vio,(const unsigned char *)mysql-> passwd, strlen(mysql-> passwd)+ 1); 返回资源?CR_ERROR:CR_OK; }
主函数应返回下表中显示的错误代码之一。
CR_OK_HANDSHAKE_COMPLETE
表示客户端已成功完成其部分并已读取最后一个数据包。
CR_OK_HANDSHAKE_COMPLETE
如果预先不知道认证协议中的往返次数,则
客户端插件可以返回
,并且插件必须读取另一个包以确定认证是否结束。
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
向服务器注册服务器端插件。
例如,要在服务器启动时加载插件,请使用
--plugin-load=auth_simple.so
选项(
.so
根据需要
调整
平台
的
后缀)。
创建服务器将使用该
auth_simple
插件进行身份验证的用户:
mysql>CREATE USER 'x'@'localhost'
- >IDENTIFIED WITH auth_simple;
使用客户端程序以用户身份连接到服务器
x
。
服务器端
auth_simple
插件与客户端程序通信它应该使用客户端
auth_simple
插件,后者将密码发送到服务器。
服务器插件应拒绝发送空密码的连接并接受发送非空密码的连接。
每种方式调用客户端程序来验证这一点:
外壳>mysql --user=x --skip-password
ERROR 1045(28000):用户'x'@'localhost'拒绝访问(使用密码:否) shell>mysql --user=x --password
输入密码:abc
MySQL的>
因为服务器插件接受任何非空密码,所以应该认为它不安全。
在测试插件以验证它是否正常工作后,重新启动服务器而不使用该
--plugin-load
选项,以免不加思索地使服务器运行时加载了不安全的身份验证插件。
此外,删除用户
DROP
USER
'x'@'localhost'
。
有关加载和使用身份验证插件的其他信息,请参见 第5.6.1节“安装和卸载插件” 和 第6.2.17节“可插入身份验证” 。
如果您正在编写支持使用身份验证插件的客户端程序,通常这样的程序会通过调用
mysql_options()
来设置
MYSQL_DEFAULT_AUTH
和
MYSQL_PLUGIN_DIR
选项
来加载插件
:
char * plugin_dir =“path_to_plugin_dir
”; char * default_auth =“plugin_name
”; / * ...进程命令行选项... * / mysql_options(&mysql,MYSQL_PLUGIN_DIR,plugin_dir); mysql_options(&mysql,MYSQL_DEFAULT_AUTH,default_auth);
通常,程序还会接受
--plugin-dir
和
--default-auth
允许用户覆盖默认值的选项。
如果客户端程序需要较低级别的插件管理,则客户端库包含带
st_mysql_client_plugin
参数的函数。
请参见
第28.7.17节“C API客户端插件函数”
。
可插拔身份验证使其成为可能的功能之一是代理用户(请参见 第6.2.18节“代理用户” )。 要使服务器端身份验证插件参与代理用户支持,必须满足以下条件:
当连接客户端应被视为代理用户时,插件必须
authenticated_as
在
MYSQL_SERVER_AUTH_INFO
结构
成员中
返回不同的名称
,以指示代理用户名。
它还可以选择设置
external_user
成员,以设置
external_user
系统变量
的值
。
必须将代理用户帐户设置为由插件进行身份验证。
使用
CREATE
USER
or
GRANT
语句将帐户与插件相关联。
换句话说,插件所需的代理用户支持的唯一方面是它设置
authenticated_as
为代理用户名。
其余的是可选的(设置
external_user
)或由DBA使用SQL语句完成。
身份验证插件如何确定代理用户连接时要返回的代理用户?
这取决于插件。
通常,插件根据服务器传递给它的身份验证字符串将客户端映射到代理用户。
此字符串来自
语句
AS
的
IDENTIFIED WITH
子句
部分,该
子句
CREATE
USER
指定使用插件进行身份验证。
插件开发人员确定身份验证字符串的语法规则,并根据这些规则实现插件。 假设插件采用以逗号分隔的对列表,将外部用户映射到MySQL用户。 例如:
创建用户''''%。example.com' 使用my_plugin AS'识别'extuser1 = mysqlusera,extuser2 = mysqluserb' 创建用户''''%。example.org' 使用my_plugin确认AS'extuser1 = mysqluserc,extuser2 = mysqluserd'
当服务器调用插件来验证客户端时,它会将相应的验证字符串传递给插件。 该插件负责:
将字符串解析为其组件以确定要使用的映射
将客户端用户名与映射进行比较
返回正确的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
前面描述
的
插件一样,
auth_simple_proxy
接受任何非空密码作为有效密码(因此不应在生产环境中使用)。
此外,它还检查了
auth_string
身份验证字符串成员,并使用这些非常简单的规则来解释它:
如果字符串为空,则插件返回给定的用户名,不会发生代理。
也就是说,插件
authenticated_as
保持不变
的值
。
如果字符串是非空的,则插件将其视为代理用户的名称并将其复制到
authenticated_as
以便进行代理。
对于测试,根据前面的规则设置一个未代理的帐户,并设置一个帐户。
这意味着一个帐户没有
AS
子句,一个包含一个
AS
命名代理用户
的
子句:
创建用户'plugin_user1'@'localhost' 使用auth_simple_proxy标识; 创建用户'plugin_user2'@'localhost' 使用auth_simple_proxy识别AS'proxyied_user';
此外,由代理用户创建一个帐户,并授予
plugin_user2
的
PROXY
特权吧:
创建用户'proxied_user'@'localhost' 由'proxied_user_pass'识别; 授予代理权 在'proxied_user'@'localhost' TO'plugin_user2'@'localhost';
在服务器调用身份验证插件之前,它会设置
authenticated_as
为客户端用户名。
要指示用户是代理,插件应设置
authenticated_as
为代理用户名。
对于
auth_simple_proxy
,这意味着它必须检查该
auth_string
值,如果该值为非空,则将其复制到该
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; / *将密码读取为以null结尾的字符串,在出错时失败* / if((pkt_len = vio-> read_packet(vio,&pkt))<0) 返回CR_ERROR; / *空密码失败* / if(!pkt_len || * pkt =='\ 0') { info-> password_used = PASSWORD_USED_NO; 返回CR_ERROR; } / *接受任何非空密码* / info-> password_used = PASSWORD_USED_YES; / *如果认证字符串是非空的,则用作代理用户名* / / *并使用客户端名称作为external_user值* / if(info-> auth_string_length> 0) { strcpy(info-> authenticated_as,info-> auth_string); strcpy(info-> external_user,info-> user_name); } 返回CR_OK; }
成功连接后,该
USER()
函数应指示连接的客户端用户和主机名,并
CURRENT_USER()
应指明在会话期间应用其权限的帐户。
如果没有代理发生,则后一个值应该是连接用户帐户;如果代理确实发生,则后者应该是代理帐户。
编译并安装插件,然后测试它。
首先,连接为
plugin_user1
:
shell>mysql --user=plugin_user1 --password
输入密码:x
在这种情况下,应该没有代理:
MySQL的> SELECT USER(), CURRENT_USER(), @@proxy_user, @@external_user\G
*************************** 1。排******************** *******
USER():plugin_user1 @ localhost
CURRENT_USER():plugin_user1 @ localhost
@@ proxy_user:NULL
@@ external_user:NULL
然后连接为
plugin_user2
:
shell>mysql --user=plugin_user2 --password
输入密码:x
在这种情况下,
plugin_user2
应该代理到
proxied_user
:
MySQL的> SELECT USER(), CURRENT_USER(), @@proxy_user, @@external_user\G
*************************** 1。排******************** *******
USER():plugin_user2 @ localhost
CURRENT_USER():proxied_user @ localhost
@@ proxy_user:'plugin_user2'@'localhost'
@@ external_user:'plugin_user2'@'localhost'
本节介绍如何编写服务器端密码验证插件。
这些说明基于
plugin/password_validation
MySQL源代码分发目录中
的源代码
。
该
validate_password.cc
目录中
的
源文件实现了名为的插件
validate_password
。
在MySQL 8.0.4中,
validate_password
插件重新实现为
validate_password
组件。
插件形式
validate_password
仍然可用但现已弃用,将在未来的MySQL版本中删除。
使用该插件的MySQL安装应该转换为使用该组件。
请参见
第6.4.3.3节“转换到密码验证组件”
。
要编写密码验证插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin_validate_password.h>
plugin_validate_password.h
包含
plugin.h
,因此您无需明确包含后一个文件。
plugin.h
定义
MYSQL_VALIDATE_PASSWORD_PLUGIN
服务器插件类型和声明插件所需的数据结构。
plugin_validate_password.h
定义特定于密码验证插件的数据结构。
与任何MySQL服务器插件一样,密码验证插件具有通用插件描述符(请参见
第29.2.4.2.1节“服务器插件库和插件描述符”
)。
在
validate_password.cc
,一般描述符
validate_password
看起来像这样:
mysql_declare_plugin(validate_password) { MYSQL_VALIDATE_PASSWORD_PLUGIN,/ * type * / &validate_password_descriptor,/ *描述符* / “validate_password”,/ * name * / “Oracle Corporation”,/ * author * / “检查密码强度”,/ *说明* / PLUGIN_LICENSE_GPL, validate_password_init,/ * init函数(加载时)* / validate_password_deinit,/ * deinit函数(卸载时)* / 0x0100,/ *版本* / 空值, validate_password_system_variables,/ *系统变量* / 空值, 0, } mysql_declare_plugin_end;
所述
name
构件(
validate_password
)指示要用于如在语句中的插件的引用名称
INSTALL
PLUGIN
或
UNINSTALL
PLUGIN
。
这也是由
INFORMATION_SCHEMA.PLUGINS
或
显示的名称
SHOW
PLUGINS
。
通用描述符还指的是
validate_password_system_variables
一个向
SHOW
VARIABLES
语句
公开几个系统变量的结构
:
static struct st_mysql_sys_var * validate_password_system_variables [] = { MYSQL_SYSVAR(长度), MYSQL_SYSVAR(NUMBER_SHOWN列) MYSQL_SYSVAR(mixed_case_count) MYSQL_SYSVAR(special_char_count) MYSQL_SYSVAR(政策), MYSQL_SYSVAR(dictionary_file) 空值 };
的
validate_password_init
初始化函数读取字典文件如果指定一个,并且
validate_password_deinit
函数释放与文件关联的数据结构。
validate_password_descriptor
通用描述符中
的
值指向特定于类型的描述符。
对于密码验证插件,此描述符具有以下结构:
struct st_mysql_validate_password { int interface_version; / * 对于满足密码的密码,此函数返回TRUE 策略(由插件变量选择)和其他所有的FALSE 密码 * / int(* validate_password)(mysql_string_handle密码); / * 此函数返回密码强度(0-100) 根据政策 * / int(* get_password_strength)(mysql_string_handle密码); };
特定于类型的描述符具有以下成员:
interface_version
:按照惯例,特定于类型的插件描述符以给定插件类型的接口版本开头。
服务器检查
interface_version
何时加载插件以查看插件是否与其兼容。
对于密码验证插件,
interface_version
成员
的值
是
MYSQL_VALIDATE_PASSWORD_INTERFACE_VERSION
(在中定义
plugin_validate_password.h
)。
validate_password
:服务器调用的函数,用于测试密码是否满足当前密码策略。
如果密码正常则返回1,否则返回0。
参数是密码,作为
mysql_string_handle
值
传递
。
此数据类型由
mysql_string
服务器服务实现。
有关详细信息,请参阅
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,/ *验证函数* / get_password_strength / *验证强度函数* / };
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
对于
validate_password
插件,它是从源代码构建MySQL时编译和安装的。
它也包含在二进制分发中。
构建过程生成一个名称为的共享对象库
validate_password.so
(
.so
后缀可能因您的平台而异)。
要在运行时注册插件,请使用此语句(
.so
根据需要
调整
平台
的
后缀):
INSTALL PLUGIN validate_password SONAME'validate_password.so';
有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件” 。
要验证插件安装,请检查
INFORMATION_SCHEMA.PLUGINS
表或使用该
SHOW
PLUGINS
语句。
请参见
第5.6.2节“获取服务器插件信息”
。
虽然
validate_password
已安装的插件,它暴露系统变量指示密码校验参数:
MySQL的> SHOW VARIABLES LIKE 'validate_password%';
+ -------------------------------------- + -------- +
| Variable_name | 价值|
+ -------------------------------------- + -------- +
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+ -------------------------------------- + -------- +
有关这些变量的说明,请参见 第6.4.3.2节“密码验证选项和变量” 。
要在测试后禁用插件,请使用此语句卸载它:
UNINSTALL PLUGIN validate_password;
MySQL支持使用协议跟踪插件:客户端插件,用于实现客户端与使用客户端/服务器协议发生的服务器之间的通信跟踪。
MySQL包含一个测试协议跟踪插件,用于说明此类插件可用的信息,以及编写其他协议跟踪插件的指南。 要了解测试插件的工作原理,请使用MySQL源代码分发; 二进制发行版是在禁用测试插件的情况下构建的。
通过在
启用
CMake
选项的情况
下配置MySQL来启用测试协议跟踪插件
。
这会导致构建测试跟踪插件并加载MySQL客户端程序,但默认情况下该插件无效。
使用以下环境变量控制插件:
WITH_TEST_TRACE_PLUGIN
MYSQL_TEST_TRACE_DEBUG
:将此变量设置为0以外的值,以使测试插件生成诊断输出
stderr
。
MYSQL_TEST_TRACE_CRASH
:将此变量设置为0以外的值,以使测试插件在检测到无效跟踪事件时中止客户端程序。
来自测试协议跟踪插件的诊断输出可以公开密码和其他敏感信息。
鉴于从启用了测试插件的源代码构建的MySQL安装,您可以看到 mysql 客户端和MySQL服务器 之间的通信跟踪, 如下所示:
shell>export MYSQL_TEST_TRACE_DEBUG=1
shqll>mysql
test_trace:初始化测试跟踪插件 test_trace:在阶段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:收到的数据包:87个字节 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:使用身份验证插件:mysql_native_password test_trace:004:stage:AUTHENTICATE,event:SEND_AUTH_RESPONSE test_trace:004:发送数据包:188字节 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:退出 test_trace:008:stage:READY_FOR_COMMAND,event:PACKET_SENT test_trace:008:发送的数据包:0个字节 test_trace:008:stage:READY_FOR_COMMAND,event:DISCONNECTED test_trace:008:连接已关闭 test_trace:008:跟踪连接已结束 再见 test_trace:测试跟踪插件已取消初始化
要禁用跟踪输出,请执行以下操作:
外壳> MYSQL_TEST_TRACE_DEBUG=
要使用自己的协议跟踪插件,必须在
禁用
CMake
选项的情况下
配置MySQL,
因为一次只能加载一个协议跟踪插件,并且尝试加载第二个插件时会发生错误。
如果您已经在启用了测试协议跟踪插件的情况下构建了MySQL以查看它是如何工作的,那么必须在没有它的情况下重建MySQL,然后才能使用自己的插件。
WITH_TEST_TRACE_PLUGIN
本节讨论如何编写名为的基本协议跟踪插件
simple_trace
。
此插件提供了一个框架,显示如何设置客户端插件描述符并创建跟踪相关的回调函数。
在
simple_trace
这些函数中,这些函数是基本的,除了说明所需的参数之外别无他法。
要详细了解跟踪插件如何使用跟踪事件信息,请检查测试协议跟踪插件的源文件(
test_trace_plugin.cc
在
libmysql
MySQL源代码分发
的
目录中)。
不过,请注意
st_mysql_client_plugin_TRACE
这里使用的结构与通常的客户端插件声明宏使用的结构不同。
特别是,前两个成员是明确定义的,而不是由声明宏隐式定义的。
几个头文件包含与协议跟踪插件相关的信息:
client_plugin.h
:定义客户端插件的API。
这包括客户端插件描述符和客户端插件C API调用的函数原型(请参见
第28.7.17节“C API客户端插件函数”
)。
plugin_trace.h
:包含类型的客户端插件的声明
MYSQL_CLIENT_TRACE_PLUGIN
。
它还包含允许的协议阶段,阶段之间的转换以及每个阶段允许的事件类型的描述。
要编写协议跟踪插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin_trace.h> #include <mysql.h>
plugin_trace.h
包含
client_plugin.h
,因此您无需明确包含后一个文件。
使用
mysql_declare_client_plugin()
和
mysql_end_client_plugin
宏
声明客户端插件描述符
(请参见
第29.2.4.2.3节“客户端插件描述符”
)。
对于
simple_trace
插件,描述符如下所示:
mysql_declare_client_plugin(TRACE) “simple_trace”,/ *插件名称* / “作者姓名”,/ *作者* / “简单协议跟踪插件”,/ * description * / {1,0,0},/ *版本= 1.0.0 * / “GPL”,/ *许可证类型* / NULL,/ *供内部使用* / plugin_init,/ *初始化函数* / plugin_deinit,/ *取消初始化函数* / plugin_options,/ *选项处理函数* / trace_start,/ * start-trace function * / trace_stop,/ *停止跟踪功能* / trace_event / *事件处理函数* / mysql_end_client_plugin;
插件名称到选项处理函数的描述符成员对于所有客户端插件类型都是通用的。 公共成员之后的成员实现跟踪事件处理。
插件不需要处理的函数成员可以
NULL
在描述符中
声明
,在这种情况下,您不需要编写任何相应的函数。
为了便于说明和显示参数语法,以下讨论实现了描述符中列出的所有函数,即使其中一些函数不执行任何操作,
所有客户端插件通用的初始化,取消初始化和选项功能声明如下。 有关参数和返回值的说明,请参见 第29.2.4.2.3节“客户端插件描述符” 。
static int plugin_init(char * errbuf,size_t errbuf_len,int argc,va_list args) { 返回0; } static int plugin_deinit() { 返回0; } static int plugin_options(const char *选项,const void * value) { 返回0; }
客户端插件描述符的特定于跟踪的成员是回调函数。 以下描述提供了有关如何使用它们的更多详细信息。 每个都有一个第一个参数,它是一个指向插件实例的指针,以防你的实现需要访问它。
trace_start()
:在每个跟踪连接的开始处调用此函数(每个连接在加载插件后启动)。
它通过连接处理程序和跟踪开始的协议阶段。
trace_start()
分配
trace_event()
函数
所需的内存
(如果有),并返回指向它的指针。
如果不需要内存,则返回此函数
NULL
。
静态无效* trace_start(struct st_mysql_client_plugin_TRACE * self, MYSQL * conn, enum protocol_stage阶段) { struct st_trace_data * plugin_data = malloc(sizeof(struct st_trace_data)); fprintf(stderr,“初始化跟踪:阶段%d \ n”,阶段); if(plugin_data) { memset(plugin_data,0,sizeof(struct st_trace_data)); fprintf(stderr,“Trace initialized \ n”); return plugin_data; } fprintf(stderr,“无法初始化跟踪\ n”); 出口(1); }
trace_stop()
:跟踪连接结束时调用此函数。
这通常发生在连接关闭时,但可能更早发生。
例如,
trace_event()
可以随时返回非零值,并导致跟踪连接终止。
trace_stop()
然后,即使连接尚未结束,也会调用它。
trace_stop()
传递连接处理程序和指向由
trace_start()
(
NULL
如果没有)
分配的内存的指针
。
如果指针为非
NULL
,
trace_stop()
则应释放内存。
此函数不返回任何值。
静态无效 trace_stop(struct st_mysql_client_plugin_TRACE * self, MYSQL * conn, void * plugin_data) { fprintf(stderr,“终止跟踪\ n”); if(plugin_data) 自由(plugin_data); }
trace_event()
:为每个事件发生调用此函数。
它传递一个指向由
trace_start()
(
NULL
如果没有)
分配的内存的指针
,连接处理程序,当前协议阶段和事件代码以及事件数据。
此函数返回0以继续跟踪,如果跟踪应停止则返回非零值。
static int trace_event(struct st_mysql_client_plugin_TRACE * self, void * plugin_data, MYSQL * conn, enum protocol_stage阶段, 枚举trace_event事件, struct st_trace_event_args args) { fprintf(stderr,“跟踪事件收到:阶段%d,事件%d \ n”,阶段,事件); if(event == TRACE_EVENT_DISCONNECTED) fprintf(stderr,“Connection closed \ n”); 返回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
结构包含以下描述的信息。
所有长度都以字节为单位。
未使用的成员设置为
0
/
NULL
。
AUTH_PLUGIN
事件:
plugin_name插件的名称
SEND_COMMAND
事件:
cmd命令代码 hdr指向命令包头的指针 hdr_len标题的长度 pkt指向命令参数的指针 pkt_len参数的长度
其他
和
活动:
SEND_
xxx
xxx
_RECEIVED
pkt指向发送或接收的数据的指针 pkt_len数据的长度
PACKET_SENT
事件:
pkt_len发送的字节数
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
在插件库文件编译并安装在插件目录中之后,您可以通过将
LIBMYSQL_PLUGINS
环境变量设置为插件名称来
轻松测试它
,这会影响使用该变量的任何客户端程序。
mysql
就是这样一个程序:
shell>export LIBMYSQL_PLUGINS=simple_trace
shqll>mysql
初始化跟踪:阶段0 跟踪已初始化 收到跟踪事件:第0阶段,事件1 收到追踪事件:第0阶段,事件2 ... 欢迎使用MySQL监视器。命令以;结尾; 或\ g。 收到跟踪事件 收到跟踪事件 ... MySQL的>SELECT 1;
收到跟踪事件:第4阶段,事件12 收到跟踪事件:第4阶段,事件16 ... 收到跟踪事件:第8阶段,事件14 收到跟踪事件:第8阶段,事件15 + --- + | 1 | + --- + | 1 | + --- + 1排(0.00秒) MySQL的>quit
收到跟踪事件:第4阶段,事件12 收到跟踪事件:第4阶段,事件16 收到跟踪事件:第4阶段,事件3 连接已关闭 终止痕迹 再见
要停止加载跟踪插件,请执行以下操作:
外壳> LIBMYSQL_PLUGINS=
也可以编写直接加载插件的客户端程序。
您可以通过调用
mysql_options()
设置
MYSQL_PLUGIN_DIR
选项
告诉客户端插件目录所在的位置
:
char * plugin_dir =“ path_to_plugin_dir
”;
/ * ...进程命令行选项... * /
mysql_options(&mysql,MYSQL_PLUGIN_DIR,plugin_dir);
通常,程序还会接受一个
--plugin-dir
允许用户覆盖默认值
的
选项。
如果客户端程序需要较低级别的插件管理,则客户端库包含带
st_mysql_client_plugin
参数的函数。
请参见
第28.7.17节“C API客户端插件函数”
。
MySQL服务器支持密钥环服务,该服务使内部服务器组件和插件能够安全地存储敏感信息,以便以后检索。 本节介绍如何编写可由服务功能用于执行密钥管理操作的服务器端密钥环插件。 有关一般密钥环信息,请参见 第6.4.4节“MySQL密钥环” 。
这里的说明基于
plugin/keyring
MySQL源代码分发目录中
的源代码
。
该目录中的源文件实现了一个名为插件的插件
keyring_file
,
该插件
使用服务器主机本地的文件进行数据存储。
要编写密钥环插件,请在插件源文件中包含以下头文件。 根据插件的功能和要求,可能还需要其他MySQL或通用头文件。
#include <mysql / plugin_keyring.h>
plugin_keyring.h
包含
plugin.h
,因此您无需明确包含后一个文件。
plugin.h
定义
MYSQL_KEYRING_PLUGIN
服务器插件类型和声明插件所需的数据结构。
plugin_keyring.h
定义特定于密钥环插件的数据结构。
与任何MySQL服务器插件一样,密钥环插件具有通用插件描述符(请参见
第29.2.4.2.1节“服务器插件库和插件描述符”
)。
在
keyring.cc
,一般描述符
keyring_file
看起来像这样:
mysql_declare_plugin(keyring_file) { MYSQL_KEYRING_PLUGIN,/ *类型* / &keyring_descriptor,/ *描述符* / “keyring_file”,/ * name * / “Oracle Corporation”,/ * author * / “向/从平面文件存储/获取身份验证数据”,/ * description * / PLUGIN_LICENSE_GPL, keyring_init,/ * init函数(加载时)* / keyring_deinit,/ * deinit函数(卸载时)* / 0x0100,/ *版本* / NULL,/ *状态变量* / keyring_system_variables,/ *系统变量* / 空值, 0, } mysql_declare_plugin_end;
所述
name
构件(
keyring_file
)表示插件名称。
这是由
INFORMATION_SCHEMA.PLUGINS
或
显示的名称
SHOW
PLUGINS
。
通用描述符还指的是
keyring_system_variables
一个将系统变量暴露给
SHOW
VARIABLES
语句的结构:
static struct st_mysql_sys_var * keyring_system_variables [] = { MYSQL_SYSVAR(数据), 空值 };
在
keyring_init
初始化函数创建数据文件,如果它不存在,然后读取它并初始化密钥库。
该
keyring_deinit
函数释放与文件关联的数据结构。
keyring_descriptor
通用描述符中
的
值指向特定于类型的描述符。
对于密钥环插件,此描述符具有以下结构:
struct st_mysql_keyring { int interface_version; bool(* mysql_key_store)(const char * key_id,const char * key_type, const char * user_id,const void * key,size_t key_len); bool(* mysql_key_fetch)(const char * key_id,char ** key_type, const char * user_id,void ** key,size_t * key_len); bool(* mysql_key_remove)(const char * key_id,const char * user_id); bool(* mysql_key_generate)(const char * key_id,const char * key_type, const char * user_id,size_t key_len); };
特定于类型的描述符具有以下成员:
interface_version
:按照惯例,特定于类型的插件描述符以给定插件类型的接口版本开头。
服务器检查
interface_version
何时加载插件以查看插件是否与其兼容。
对于密钥环插件,
interface_version
成员
的值
是
MYSQL_KEYRING_INTERFACE_VERSION
(在中定义
plugin_keyring.h
)。
mysql_key_store
:在密钥环中对密钥进行模糊处理和存储的函数。
mysql_key_fetch
:一个从密钥环反混淆和检索密钥的函数。
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 };
密钥环插件实现
的
功能类似于
密钥环服务API公开
的
功能。
例如,
插件功能类似于
密钥环服务功能。
有关密钥环服务功能的参数及其使用方法的信息,请参见
第29.3.2节“密钥环服务”
。
mysql_key_
xxx
my_key_
xxx
mysql_key_store
my_key_store
要编译和安装插件库文件,请使用
第29.2.4.3节“编译和安装插件库”中的说明
。
要使库文件可供使用,请将其安装在plugin目录(
plugin_dir
系统变量
指定的目录
)中。
对于
keyring_file
插件,它是从源代码构建MySQL时编译和安装的。
它也包含在二进制分发中。
构建过程生成一个名称为的共享对象库
keyring_file.so
(
.so
后缀可能因您的平台而异)。
密钥环插件通常在服务器启动过程中尽早加载,以便它们可用于可能依赖于它们的内置插件和存储引擎。
对于
keyring_file
,在服务器
my.cnf
文件中
使用这些行
(
.so
根据需要
调整
平台
的
后缀):
的[mysqld] 早期插件负荷= keyring_file.so
有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件” 。
要验证插件安装,请检查
INFORMATION_SCHEMA.PLUGINS
表或使用该
SHOW
PLUGINS
语句(请参见
第5.6.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的> SHOW VARIABLES LIKE 'keyring_file%';
+ ------------------- + ----------------------------- ----- +
| Variable_name | 价值|
+ ------------------- + ----------------------------- ----- +
| keyring_file_data | / usr / local / mysql / keyring / keyring |
+ ------------------- + ----------------------------- ----- +
有关
keyring_file_data
变量
的说明
,请参见
第5.1.8节“服务器系统变量”
。
要在测试后禁用插件,请重新启动服务器,而不要使用
--early-plugin-load
命名该插件
的
选项。
MySQL服务器插件可以访问服务器 “ 插件服务。 “ 插件服务接口公开了插件可以调用的服务器功能。 它补充了插件API并具有以下特征:
服务使插件能够使用普通函数调用访问服务器内的代码。 服务也可用于用户定义的函数(UDF)。
服务是可移植的,可在多个平台上运行。
该接口包括版本控制机制,以便可以在加载时针对插件版本检查服务器支持的服务版本。 版本控制可防止服务器提供的服务版本与插件预期或要求的服务版本之间的不兼容性。
有关用于测试插件服务的插件的信息,请参阅MySQL服务器Doxygen文档的插件测试插件服务部分,可从 https://dev.mysql.com/doc/index-other.html获取 。
插件服务接口与插件API的不同之处如下:
插件API允许服务器使用插件。 调用主动权在于服务器调用插件。 这使插件能够扩展服务器功能或注册以接收有关服务器处理的通知。
插件服务接口使插件能够调用服务器内的代码。 调用的主动权在于调用服务函数的插件。 这使得许多插件可以使用已在服务器中实现的功能; 他们不需要自己单独实施。
要确定存在哪些服务以及它们提供的功能,请查看
include/mysql
MySQL源代码分发
的
目录。
相关文件是:
plugin.h
包括
services.h
,这是
“
伞
”
标题,包括所有可用的服务特定标头文件。
特定于服务的标头具有表单的名称
。
service_
xxx
.h
每个特定于服务的标头应包含提供给定服务的完整使用文档的注释,包括可用的服务功能,调用顺序和返回值。
对于希望修改服务器以添加新服务的开发人员,请参阅 MySQL Internals:MySQL Services for Plugins 。
可用服务包括以下内容:
get_sysvar_source
:一种服务,使插件能够检索系统变量设置的来源。
locking_service
:实现具有三个属性的锁的服务:锁定命名空间,锁定名称和锁定模式。
此锁定接口有两个级别:1)作为C语言接口,可从服务器插件或用户定义的函数调用为插件服务;
2)在SQL级别,作为一组用户定义的函数映射到服务例程的调用。
有关更多信息,请参见
第29.3.1节“锁定服务”
。
my_plugin_log_service
:一种服务,使插件能够报告错误并指定错误消息。
服务器将消息写入其错误日志。
status_variable_registration
。
用于注册状态变量的服务。
my_thd_scheduler
:用于插件的服务,用于选择线程调度程序。
mysql_keyring
:密钥环存储服务。
有关更多信息,请参见
第29.3.2节“密钥环服务”
。
mysql_password_policy
:用于密码验证和强度检查的服务。
plugin_registry_service
:MySQL Server包括一个基于组件的基础架构,用于提高服务器的可扩展性;
请参见
第5.5节“MySQL服务器组件”
。
但是,MySQL插件使用的是一个早于组件接口的接口。
在
plugin_registry_service
使插件来访问组件注册和服务。
security_context
:一种服务,使插件能够检查或操作线程安全上下文。
此服务提供setter和getter例程来访问服务器
Security_context
类的属性,其中包括操作系统用户和主机,经过身份验证的用户和主机以及客户端IP地址等属性。
thd_alloc
:内存分配服务。
thd_wait
:插件服务,用于报告何时进入睡眠或停止状态。
本节的其余部分描述了插件如何使用可用作服务的服务器功能。
另请参阅
使用该
服务
的
“
守护程序
”
示例插件
的源代码
my_snprintf
。
在MySQL源代码发行版中,该插件位于
plugin/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()
:
int my_plugin_log_message(MYSQL_PLUGIN *插件,枚举plugin_log_level级别, const char * format,...);
例如:
my_plugin_log_message(plugin_ptr,MY_ERROR_LEVEL,“无法初始化插件”);
有些服务 的 插件,可以提供 通过 插件,因此只有当提供服务的插件加载可用。 任何使用此类服务的MySQL组件都应检查该服务是否可用。
构建插件时,请使用
-lmysqlservices
链接时
的
标志链接
libmysqlservices
库中。
例如,对于
CMake
,将其放在顶级
CMakeLists.txt
文件中:
FIND_LIBRARY(MYSQLSERVICES_LIB mysqlservices 路径“$ {MYSQL_SRCDIR} / libservices”NO_DEFAULT_PATH)
把它放在
CMakeLists.txt
包含插件源的目录
中的
文件中:
#plugin需要mysql服务库来进行错误记录
TARGET_LINK_LIBRARIES(your_plugin_library_name
$ {MYSQLSERVICES_LIB})
MySQL发行版提供了一个锁定接口,可在两个级别上使用:
作为C语言接口,可以从服务器插件或用户定义的函数调用为插件服务
在SQL级别,作为一组用户定义的函数映射到服务例程的调用
有关插件服务的一般信息,请参见 第29.3节“插件的MySQL服务” 。 有关用户定义函数的一般信息,请参见 第29.4.2节“添加新的用户定义函数” 。
锁定界面具有以下特征:
锁具有三个属性:锁定命名空间,锁定名称和锁定模式:
锁由名称空间和锁名称的组合标识。
命名空间允许不同的应用程序使用相同的锁名称,而不会在单独的命名空间中创建锁定而发生冲突。
例如,如果应用程序A和B使用的名称空间
ns1
和
ns2
,分别,每个应用可以使用锁的名称
lock1
和
lock2
不与其它应用干扰。
锁定模式是读取或写入。 读锁是共享的:如果会话对给定的锁标识符具有读锁定,则其他会话可以获取对同一标识符的读锁定。 写锁是独占的:如果会话对给定的锁标识符具有写锁定,则其他会话无法获取对同一标识符的读或写锁。
名称空间和锁定名称必须为非
NULL
空,
非
空,并且最大长度为64个字符。
指定为
NULL
空字符串
的命名空间或锁定名称
或长度超过64个字符的字符串会导致
ER_LOCKING_SERVICE_WRONG_NAME
错误。
锁定接口将命名空间和锁定名称视为二进制字符串,因此比较区分大小写。
锁定接口提供获取锁定和释放锁定的功能。 调用这些函数不需要特殊权限。 权限检查是调用应用程序的责任。
如果没有立即可用,可以等待锁。
锁定获取调用采用整数超时值,该值指示在放弃之前等待获取锁的秒数。
如果在未成功锁定获取的情况下达到超时,
ER_LOCKING_SERVICE_TIMEOUT
则会发生错误。
如果超时为0,则没有等待,如果无法立即获取锁,则调用会产生错误。
锁定接口检测不同会话中的锁定获取调用之间的死锁。
在这种情况下,锁定服务选择一个调用者并终止其锁定获取请求并显示
ER_LOCKING_SERVICE_DEADLOCK
错误。
此错误不会导致事务回滚。
要在遇到死锁的情况下选择会话,锁定服务会优先选择在持有写锁定的会话上保持读锁定的会话。
会话可以通过单个锁定获取调用获取多个锁。
对于给定的调用,锁获取是原子的:如果获取了所有锁,则调用成功。
如果获取任何锁失败,则调用不会获取锁定并失败,通常会
出现错误
ER_LOCKING_SERVICE_TIMEOUT
或
ER_LOCKING_SERVICE_DEADLOCK
错误。
会话可以为相同的锁标识符(名称空间和锁名称组合)获取多个锁。 这些锁实例可以是读锁,写锁或两者的混合。
通过调用释放锁定函数显式释放会话中获取的锁定,或者在会话终止(正常或异常)时隐式释放。 事务提交或回滚时不会释放锁。
在会话中,释放时给定命名空间的所有锁定一起释放。
锁定服务提供的接口
GET_LOCK()
与SQL函数
提供的接口不同
(参见
第12.14节“锁定函数”
)。
例如,
GET_LOCK()
不实现名称空间并仅提供排它锁,而不提供不同的读写锁。
本节介绍如何使用锁定服务C语言接口。 要使用UDF接口,请参见 第29.3.1.2节“锁定服务UDF接口” 有关锁定服务接口的一般特性,请参见 第29.3.1节“锁定服务” 。 有关插件服务的一般信息,请参见 第29.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
:一个线程句柄。
如果指定为
NULL
,则使用当前线程的句柄。
lock_namespace
:以空字符结尾的字符串,表示锁定命名空间。
lock_names
:一组以null结尾的字符串,提供要获取的锁的名称。
lock_num
:
lock_names
数组中
的名称数
。
lock_type
:锁定模式,可以是
LOCKING_SERVICE_READ
或
LOCKING_SERVICE_WRITE
获取读锁定或写分别锁,。
lock_timeout
:在放弃之前等待获取锁的整数秒数。
要释放为给定命名空间获取的锁,请调用此函数:
int mysql_release_locking_service_locks(MYSQL_THD opaque_thd, const char * lock_namespace);
这些论点具有以下含义:
opaque_thd
:一个线程句柄。
如果指定为
NULL
,则使用当前线程的句柄。
lock_namespace
:以空字符结尾的字符串,表示锁定命名空间。
可以使用性能模式在SQL级别监视锁定服务获取或等待的锁定。 有关详细信息,请参见 第29.3.1.2.3节“锁定服务监视” 。
本节介绍如何使用锁定服务用户定义函数(UDF)接口。 要使用C语言接口,请参见 第29.3.1.1节“锁定服务C接口” 有关锁定服务接口的一般特性,请参见 第29.3.1节“锁定服务” 。 有关用户定义函数的一般信息,请参见 第29.4.2节“添加新的用户定义函数” 。
无需安装 第29.3.1.1节“锁定服务C接口”中 描述的锁定服务例程 , 因为它们内置于服务器中。 映射到服务例程调用的用户定义函数(UDF)也是如此:必须在使用前安装UDF。 本节介绍如何执行此操作。 有关UDF安装的一般信息,请参见 第5.7.1节“安装和卸载用户定义的函数” 。
锁定服务UDF在位于由
plugin_dir
系统变量
命名的目录中的插件库文件中实现
。
文件基名是
locking_service
。
文件名后缀因平台
.so
而异
(例如,
对于Unix和类Unix系统,
.dll
对于Windows)。
要安装锁定服务UDF,请使用该
CREATE
FUNCTION
语句(
.so
根据需要
调整
平台
的
后缀):
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
语句:
DROP FUNCTION service_get_read_locks; DROP FUNCTION service_get_write_locks; DROP FUNCTION service_release_locks;
在使用锁定服务UDF之前,请按照 第29.3.1.2.1节“安装或卸载UDF锁定接口”中 提供的说明进行 安装 。
要获取一个或多个读锁定,请调用此函数:
MySQL的> SELECT service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10);
+ ------------------------------------------------- -------------- +
| service_get_read_locks('mynamespace','rlock1','rlock2',10)|
+ ------------------------------------------------- -------------- +
| 1 |
+ ------------------------------------------------- -------------- +
第一个参数是lock名称空间。 最后一个参数是一个整数超时,指示在放弃之前等待获取锁的秒数。 中间的参数是锁名称。
对于刚刚所示的示例中,函数获取与锁标识符锁
(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)
和
(mynamespace, wlock2)
。
要释放命名空间的所有锁,请使用以下函数:
MySQL的> SELECT service_release_locks('mynamespace');
+ -------------------------------------- +
| service_release_locks('mynamespace')|
+ -------------------------------------- +
| 1 |
+ -------------------------------------- +
每个锁定函数返回非零表示成功。 如果函数失败,则会发生错误。 例如,出现以下错误,因为锁名称不能为空:
MySQL的> SELECT service_get_read_locks('mynamespace', '', 10);
错误3131(42000):锁定服务锁定名称''不正确。
会话可以获取相同锁定标识符的多个锁。 只要不同的会话没有标识符的写锁定,该会话就可以获取任意数量的读或写锁。 对标识符的每个锁定请求获取新锁。 以下语句获取具有相同标识符的三个写锁,然后获取相同标识符的三个读锁:
SELECT service_get_write_locks('ns','lock1','lock1','lock1',0); SELECT service_get_read_locks('ns','lock1','lock1','lock1',0);
如果此时检查Performance Schema
metadata_locks
表,您会发现该会话包含六个具有相同
(ns, lock1)
标识符的
不同锁
。
(有关详细信息,请参见
第29.3.1.2.3节“锁定服务监视”
。)
因为会话至少保持一个写锁定
(ns, lock1)
,所以没有其他会话可以获取锁定,无论是读取还是写入。
如果会话仅保留标识符的读锁定,则其他会话可以为其获取读锁定,但不能获取写锁定。
单个锁定获取调用的锁定是以原子方式获取的,但原子性不适用于调用。
因此,对于如下的陈述,其中
service_get_write_locks()
每行调用一次结果集,每个单独的调用都保持原子性,但不是整个语句的原子性:
SELECT service_get_write_locks('ns','lock1','lock2',0)FROM t1 WHERE ...;
因为锁定服务为给定锁定标识符的每个成功请求返回单独的锁,所以单个语句可能获取大量锁。 例如:
INSERT INTO ... SELECT service_get_write_locks('ns',t1.col_name,0)FROM t1;
这些类型的陈述可能会产生某些不利影响。 例如,如果语句部分失败并回滚,则仍然存在获取到失败点的锁。 如果意图是在插入的行和获取的锁之间存在对应关系,则不会满足该意图。 此外,如果按特定顺序授予锁定很重要,请注意结果集顺序可能会有所不同,具体取决于优化程序选择的执行计划。 由于这些原因,最好将应用程序限制为每个语句的单个锁定获取调用。
锁定服务是使用MySQL Server元数据锁框架实现的,因此您可以通过检查Performance Schema
metadata_locks
表
来监视获取或等待的锁定服务锁
。
首先,启用元数据锁定工具:
mysql>UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
- >WHERE NAME = 'wait/lock/metadata/sql/mdl';
然后获取一些锁并检查
metadata_locks
表
的内容
:
MySQL的>SELECT service_get_write_locks('mynamespace', 'lock1', 0);
+ ------------------------------------------------- --- + | service_get_write_locks('mynamespace','lock1',0)| + ------------------------------------------------- --- + | 1 | + ------------------------------------------------- --- + MySQL的>SELECT service_get_read_locks('mynamespace', 'lock2', 0);
+ ------------------------------------------------- - + | service_get_read_locks('mynamespace','lock2',0)| + ------------------------------------------------- - + | 1 | + ------------------------------------------------- - + mysql>SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS
- >FROM performance_schema.metadata_locks
- >WHERE OBJECT_TYPE = 'LOCKING SERVICE'\G
*************************** 1。排******************** ******* OBJECT_TYPE:锁定服务 OBJECT_SCHEMA:mynamespace OBJECT_NAME:lock1 LOCK_TYPE:EXCLUSIVE LOCK_STATUS:已授权 *************************** 2.排******************** ******* OBJECT_TYPE:锁定服务 OBJECT_SCHEMA:mynamespace OBJECT_NAME:lock2 LOCK_TYPE:共享 LOCK_STATUS:已授权
锁定服务锁的
OBJECT_TYPE
值为
LOCKING SERVICE
。
这是不同于,例如,与所获取的锁
GET_LOCK()
功能,其具有
OBJECT_TYPE
的
USER
LEVEL LOCK
。
锁命名空间,名称和模式出现在
OBJECT_SCHEMA
,
OBJECT_NAME
和
LOCK_TYPE
列。
读写锁的
LOCK_TYPE
值为
SHARED
和
EXCLUSIVE
分别
。
对于
正在等待的
锁,
该
LOCK_STATUS
值
GRANTED
用于获取的锁
PENDING
。
您将看到
PENDING
一个会话是否持有写锁定,另一个会话是否正在尝试获取具有相同标识符的锁定。
锁定服务的SQL接口实现本节中描述的用户定义的函数。 有关用法示例,请参见 第29.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()
。
命名空间中没有锁定不是错误。
MySQL服务器支持密钥环服务,该服务使内部服务器组件和插件能够安全地存储敏感信息,以便以后检索。 本节介绍如何使用密钥环服务功能来存储,检索和删除MySQL密钥环密钥库中的密钥。 密钥环服务功能的SQL接口也可用作一组用户定义的函数(UDF); 请参见 第6.4.4.8节“通用密钥环密钥管理功能” 。 有关一般密钥环信息,请参见 第6.4.4节“MySQL密钥环” 。
密钥环服务使用启用的任何底层密钥环插件(如果有)。 如果未启用密钥环插件,则密钥环服务调用将失败。
阿 “ 记录 ” 在密钥库中包含的数据(密钥本身)和一个唯一的标识符,通过该键被访问。 标识符有两部分:
key_id
:密钥ID或名称。
MySQL Server保留以
key_id
值开头的值
mysql_
。
user_id
:会话有效用户ID。
如果没有用户上下文,则此值可以是
NULL
。
该值实际上不必是
“
用户
”
;
意义取决于应用程序。
实现密钥环UDF接口的函数将值
CURRENT_USER()
作为
user_id
值传递给密钥环服务函数。
密钥环服务功能具有以下共同特征:
每个函数返回0表示成功,1表示失败。
在
key_id
和
user_id
参数形成指示要使用哪个键在钥匙圈一个独特的组合。
该
key_type
参数提供有关密钥的其他信息,例如其加密方法或预期用途。
密钥环服务功能将密钥ID,用户名,类型和值视为二进制字符串,因此比较区分大小写。
例如,ID
MyKey
和
mykey
引用不同的键。
这些密钥环服务功能可用:
my_key_fetch()
从密钥环中反混淆和检索密钥及其类型。 该函数为用于存储返回的键和键类型的缓冲区分配内存。 当不再需要内存时,调用者应该对内存进行归零或混淆,然后释放它。
句法:
bool my_key_fetch(const char * key_id,const char ** key_type, const char * user_id,void ** key,size_t * key_len)
参数:
key_id
,
user_id
:以空值终止的字符串,作为一对形成唯一标识符,指示要获取的键。
key_type
:缓冲区指针的地址。
该函数在其中存储一个指向以null结尾的字符串的指针,该字符串提供有关密钥的附加信息(在添加密钥时存储)。
key
:缓冲区指针的地址。
该函数在其中存储指向包含所获取的密钥数据的缓冲区的指针。
key_len
:函数的地址,函数将
*key
缓冲区
的大小(以字节为单位)存储到该变量中
。
返回值:
成功返回0,失败返回1。
my_key_generate()
生成给定类型和长度的新随机密钥,并将其存储在密钥环中。
密钥具有长度
key_len
并且与由
key_id
和
形成的标识符相关联
user_id
。
类型和长度值必须与底层密钥环插件支持的值一致。
请参见
第6.4.4.7节“支持的密钥环密钥类型”
。
句法:
bool my_key_generate(const char * key_id,const char * key_type, const char * user_id,size_t key_len)
参数:
key_id
,
user_id
:以空值终止的字符串,它们成对形成要生成的密钥的唯一标识符。
key_type
:以null结尾的字符串,提供有关密钥的其他信息。
key_len
:要生成的密钥的大小(以字节为单位)。
返回值:
成功返回0,失败返回1。
my_key_remove()
从钥匙圈中取出钥匙。
句法:
bool my_key_remove(const char * key_id,const char * user_id)
参数:
key_id
,
user_id
:以空值终止的字符串,作为一对形成要删除的键的唯一标识符。
返回值:
成功返回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_id
,
user_id
:以空值终止的字符串,作为一对形成要存储的密钥的唯一标识符。
key_type
:以null结尾的字符串,提供有关密钥的其他信息。
key
:包含要存储的密钥数据的缓冲区。
key_len
:
key
缓冲区
的大小(以字节为单位)
。
返回值:
成功返回0,失败返回1。
有三种方法可以向MySQL添加新功能:
您可以通过用户定义的函数(UDF)接口添加函数。
用户定义的函数被编译为库文件,然后使用
CREATE
FUNCTION
和
DROP
FUNCTION
语句
动态地添加到服务器或从服务器中删除
。
请参见
第13.7.4.1节“用户定义函数的CREATE FUNCTION语法”
。
您可以将函数添加为本机(内置)MySQL函数。 本机函数被编译到 mysqld 服务器中并永久可用。
添加函数的另一种方法是创建存储函数。 这些是使用SQL语句而不是编译目标代码编写的。 此处不涉及编写存储函数的语法。 请参见 第24.2节“使用存储的例程” 。
创建编译函数的每种方法都有优点和缺点:
如果编写用户定义的函数,则必须安装除服务器本身之外的目标文件。 如果将函数编译到服务器中,则无需执行此操作。
本机功能要求您修改源分发。 UDF没有。 您可以将UDF添加到二进制MySQL发行版中。 无需访问MySQL源代码。
如果升级MySQL发行版,则可以继续使用以前安装的UDF,除非升级到UDF接口更改的较新版本。 对于本机功能,每次升级时都必须重复修改。
无论您使用哪种方法添加新函数,都可以在SQL语句中调用它们,就像本机函数(如
ABS()
或)一样
SOUNDEX()
。
有关 描述服务器如何解释对不同类型函数的引用的规则 , 请参见 第9.2.4节“函数名称解析和解析” 。
以下部分描述了UDF接口的功能,提供了编写UDF的说明,讨论了MySQL为防止UDF滥用而采取的安全预防措施,并描述了如何添加本机MySQL函数。
例如,说明如何编写UDF的源代码,请查看
sql/udf_example.cc
MySQL源代码分发中提供
的
文件。
MySQL源代码包含使用Doxygen编写的内部文档。 本文档对于从开发人员的角度理解MySQL的工作原理非常有用。 生成的Doxygen内容可从 https://dev.mysql.com/doc/index-other.html获得 。 也可以使用 第2.9.7节“生成MySQL Doxygen文档内容”中 的说明从MySQL源代码分发本地生成此内容 。
用户定义函数的MySQL接口提供以下特性和功能:
函数可以返回字符串,整数或实数值,并且可以接受相同类型的参数。
您可以定义一次对单个行进行操作的简单函数,或者对按行组进行操作的聚合函数。
向函数提供信息,使其能够检查传递给它们的参数的数量,类型和名称。
在将它们传递给函数之前,您可以告诉MySQL强制给定类型的参数。
您可以指示函数返回
NULL
或发生错误。
要使UDF机制起作用,必须使用C或C ++编写函数,并且操作系统必须支持动态加载。
MySQL源代码分发包含一个
sql/udf_example.cc
定义五个UDF函数
的文件
。
请参阅此文件以了解UDF调用约定的工作原理。
该
include/mysql_com.h
头文件定义UDF相关的符号和数据结构,虽然你不必直接包含这个头文件;
它包括在内
mysql.h
。
UDF包含成为正在运行的服务器的一部分的代码,因此在编写UDF时,您将受到适用于编写服务器代码的任何和所有约束的约束。
例如,如果尝试使用
libstdc++
库中的
函数,则可能会出现问题
。
这些约束可能会在服务器的未来版本中发生变化,因此服务器升级可能需要对最初为旧服务器编写的UDF进行修订。
有关这些约束的信息,请参见
第2.9.4节“MySQL源配置选项”
和
第2.9.5节“处理编译MySQL的问题”
。
为了能够使用UDF,您必须
动态
链接
mysqld
。
如果你想使用一个需要从访问符号的UDF
的mysqld
(例如,
metaphone
在功能
sql/udf_example.cc
用途
default_charset_info
),必须链接与程序
-rdynamic
(见
man
dlopen
)。
对于要在SQL语句中使用的每个函数,应定义相应的C(或C ++)函数。
在以下讨论中,名称
“
xxx
”
用于示例函数名称。
要区分SQL和C / C ++用法,
XXX()
(大写)表示SQL函数调用,
xxx()
(小写)表示C / C ++函数调用。
使用C ++时,您可以将C函数封装在:
extern“C”{...}
这可确保您的C ++函数名称在已完成的UDF中保持可读性。
以下列表描述了为实现名为的函数实现接口而编写的C / C ++函数
XXX()
。
主要功能
xxx()
是必需的。
此外,由于
第29.4.2.6节“UDF安全预防措施”中
讨论的原因,UDF至少需要此处描述的其他功能之一
。
xxx()
主要功能。 这是计算函数结果的地方。 此处显示SQL函数数据类型与C / C ++函数的返回类型之间的对应关系。
也可以声明一个
DECIMAL
函数,但是当前该值是作为字符串返回的,因此您应该将UDF编写为
STRING
函数。
ROW
功能未实现。
xxx_init()
初始化函数
xxx()
。
如果存在,它可用于以下目的:
检查参数的数量
XXX()
。
验证参数是否为必需类型,或者在调用main函数时告诉MySQL强制所需类型的参数。
分配主函数所需的任何内存。
指定结果的最大长度。
指定(对于
REAL
函数)结果中的最大小数位数。
指定结果是否可以
NULL
。
xxx_deinit()
取消初始化函数
xxx()
。
如果存在,它应该释放由初始化函数分配的任何内存。
当一个SQL语句调用时
XXX()
,MySQL调用初始化函数
xxx_init()
让它执行任何所需的设置,例如参数检查或内存分配。
如果
xxx_init()
返回错误,MySQL将使用错误消息中止SQL语句,并且不调用main或deinitialization函数。
否则,MySQL调用main函数
xxx()
为每一行
一次
。
在处理完所有行之后,MySQL调用deinitialization函数,
xxx_deinit()
以便它可以执行任何所需的清理。
对于类似的聚合函数
SUM()
,还必须提供以下函数:
xxx_clear()
重置当前聚合值但不要将参数作为新组的初始聚合值插入。
xxx_add()
将参数添加到当前聚合值。
MySQL处理聚合UDF,如下所示:
调用
xxx_init()
让聚合函数分配存储结果所需的任何内存。
根据
GROUP BY
表达式
对表进行排序
。
调用
xxx_clear()
每个新组中的第一行。
调用
xxx_add()
属于同一组的每一行。
调用
xxx()
以在组更改时或在处理完最后一行之后获取聚合的结果。
重复步骤3到5,直到处理完所有行
调用
xxx_deinit()
让UDF释放它已分配的任何内存。
所有功能必须是线程安全的。
这不仅包括main函数,还包括初始化和取消初始化函数,以及聚合函数所需的附加函数。
此要求的结果是您不允许分配任何更改的全局变量或静态变量!
如果你需要内存,你应该分配它
xxx_init()
并释放它
xxx_deinit()
。
本节介绍创建简单UDF时需要定义的不同功能。 第29.4.2节“添加新的用户定义函数” 描述了MySQL调用这些函数的顺序。
主要
xxx()
功能应该如本节所示声明。
请注意,返回类型和参数不同,这取决于你是否声明SQL函数
XXX()
返回
STRING
,
INTEGER
或
REAL
在
CREATE
FUNCTION
语句:
对于
STRING
功能:
char * xxx(UDF_INIT * initid,UDF_ARGS * args, char * result,unsigned long * length, char * is_null,char * error);
对于
INTEGER
功能:
long long xxx(UDF_INIT * initid,UDF_ARGS * args, char * is_null,char * error);
对于
REAL
功能:
double xxx(UDF_INIT * initid,UDF_ARGS * args, char * is_null,char * error);
DECIMAL
函数返回字符串值,应该以与
STRING
函数
相同的方式声明
。
ROW
功能未实现。
初始化和取消初始化函数声明如下:
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()
应该设置
maybe_null
为
1
if是否
xxx()
可以返回
NULL
。
1
如果声明了任何参数,则
默认值为
maybe_null
。
unsigned int decimals
小数点右侧的小数位数。
默认值是传递给main函数的参数中的最大小数位数。
例如,如果函数传递
1.34
,
1.345
和
1.3
,默认是3,因为
1.345
有3个十进制数字。
对于具有小数的没有固定数量的参数,所述
decimals
值被设置为31,这比允许的小数的最大数量更多的
DECIMAL
,
FLOAT
和
DOUBLE
数据类型。
该值可作为恒定
NOT_FIXED_DEC
在
mysql_com.h
头文件。
甲
decimals
的31值用于在箱子参数诸如
FLOAT
或
DOUBLE
柱无小数的明确声明数(例如,
FLOAT
而不是
FLOAT(10,3)
)和浮点常数如
1345E-3
。
它还用于字符串和其他非编号参数,这些参数可能在函数内转换为数字形式。
到的值
decimals
构件被初始化仅仅是一个缺省值。
可以在函数内更改它以反映执行的实际计算。
确定默认值,以便使用参数的最大小数位数。
如果小数位数
NOT_FIXED_DEC
甚至是其中一个参数,那就是用于的值
decimals
。
unsigned int max_length
结果的最大长度。
默认
max_length
值因功能的结果类型而异。
对于字符串函数,缺省值是最长参数的长度。
对于整数函数,默认值为21位。
对于实函数,默认值为13加上指示的小数位数
initid->decimals
。
(对于数字函数,长度包括任何符号或小数点字符。)
如果要返回blob值,可以设置
max_length
为65KB或16MB。
此内存未分配,但该值用于决定在需要临时存储数据时使用哪种数据类型。
char *ptr
函数可以用于其自身目的的指针。
例如,函数可用于
initid->ptr
在它们之间传递分配的内存。
xxx_init()
应分配内存并将其分配给此指针:
initid-> ptr = allocated_memory;
在
xxx()
和中
xxx_deinit()
,请参阅
initid->ptr
使用或取消分配内存。
bool const_item
xxx_init()
应该设置
const_item
为
1
if
xxx()
始终返回相同的值,
0
否则。
本节介绍在创建聚合UDF时需要定义的不同功能。 第29.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 8.0中不需要或使用,而UDF接口则使用它
xxx_clear()
。
但是,您可以定义两者
xxx_reset()
以及
xxx_clear()
是否要让UDF与旧版本的服务器一起使用。
(如果确实包含这两个函数,则
xxx_reset()
在许多情况下
,
函数可以通过调用
xxx_clear()
重置所有变量
在内部实现
,然后调用
xxx_add()
以将
UDF_ARGS
参数
添加
为组中的第一个值。)
xxx_clear()
当MySQL需要重置摘要结果时,将调用此函数。
它在每个新组的开头调用,但也可以调用以重置没有匹配行的查询的值。
声明
xxx_clear()
如下:
void xxx_clear(UDF_INIT * initid,char * is_null,char * error);
is_null
设置为
CHAR(0)
在调用之前
指向
xxx_clear()
。
如果出现问题,您可以在
error
参数指向
的变量中存储值
。
error
指向单字节变量,而不是字符串缓冲区。
xxx_clear()
是MySQL 8.0所必需的。
xxx_add()
为属于同一组的所有行调用此函数。
您应该使用它将
UDF_ARGS
参数中
的值添加
到内部摘要变量中。
void xxx_add(UDF_INIT * initid,UDF_ARGS * args, char * is_null,char * error);
xxx()
应该以与非聚合UDF相同的方式声明聚合UDF
的
函数。
请参见
第29.4.2.1节“简单函数的UDF调用序列”
。
对于聚合UDF,MySQL
xxx()
在处理完组中的所有行之后
调用该
函数。
您通常不应该
UDF_ARGS
在此处
访问其
参数,而是根据您的内部汇总变量返回一个值。
返回值处理
xxx()
应该与非聚合UDF的
处理
方式相同。
请参见
第29.4.2.4节“UDF返回值和错误处理”
。
在
xxx_reset()
和
xxx_add()
函数处理他们的
UDF_ARGS
论据的方式与非聚集UDF的功能相同。
请参见
第29.4.2.3节“UDF参数处理”
。
指针参数
is_null
和
error
是相同的所有来电
xxx_reset()
,
xxx_clear()
,
xxx_add()
和
xxx()
。
您可以使用它来记住您遇到错误或
xxx()
函数
是否
应该返回
NULL
。
你不应该存储一个字符串
*error
!
error
指向单字节变量,而不是字符串缓冲区。
*is_null
为每个组重置(在呼叫之前
xxx_clear()
)。
*error
永远不会重置。
如果
在
返回
时设置
*is_null
或
*error
设置
xxx()
,则MySQL返回
NULL
组功能的结果。
该
args
参数指向
UDF_ARGS
具有此处列出的成员
的
结构:
unsigned int arg_count
参数的数量。 如果需要使用特定数量的参数调用函数,请在初始化函数中检查此值。 例如:
if(args-> arg_count!= 2) { strcpy(消息,“XXX()需要两个参数”); 返回1; }
对于
UDF_ARGS
作为数组的
其他
成员值,数组引用从零开始。
也就是说,使用从0到
args->arg_count
-1的
索引值来引用数组成员
。
enum Item_result *arg_type
指向包含每个参数类型的数组的指针。
可能的类型的值是
STRING_RESULT
,
INT_RESULT
,
REAL_RESULT
,和
DECIMAL_RESULT
。
要确保参数属于给定类型并返回错误(如果不是),请检查
arg_type
初始化函数中
的
数组。
例如:
if(args-> arg_type [0]!= STRING_RESULT || args-> arg_type [1]!= INT_RESULT) { strcpy(消息,“XXX()需要一个字符串和一个整数”); 返回1; }
类型的参数
DECIMAL_RESULT
作为字符串传递,因此您应该以与
STRING_RESULT
值
相同的方式处理它们
。
作为要求函数的参数具有特定类型的替代方法,您可以使用初始化函数将
arg_type
元素
设置
为所需的类型。
这会导致MySQL为每次调用强制转换这些类型的参数
xxx()
。
例如,要指定前两个参数应分别强制转换为字符串和整数,请执行以下操作
xxx_init()
:
args-> arg_type [0] = STRING_RESULT; args-> arg_type [1] = INT_RESULT;
精确值十进制参数(如
1.3
或
DECIMAL
列值)的类型为
DECIMAL_RESULT
。
但是,值将作为字符串传递。
如果要接收数字,请使用初始化函数指定应将参数强制转换为
REAL_RESULT
值:
args-> arg_type [2] = REAL_RESULT;
char **args
args->args
将信息传递给初始化函数,以了解传递给函数的参数的一般性质。
对于常量参数
i
,
args->args[i]
指向参数值。
(有关如何正确访问该值的说明,请参阅后面的内容。)对于非常量参数,
args->args[i]
是
0
。
常量参数是仅使用常量的表达式,例如
3
or
4*7-2
或
SIN(3.14)
。
非常量参数是一个表达式,它引用可能在行之间更改的值,例如使用非常量参数调用的列名或函数。
对于main函数的每次调用,
args->args
包含为当前正在处理的行传递的实际参数。
如果参数
i
表示
NULL
,
args->args[i]
则为空指针(0)。
如果参数不是
NULL
,函数可以引用如下:
类型的参数
STRING_RESULT
作为字符串指针加上长度给出,以便能够处理二进制数据或任意长度的数据。
字符串内容可用,
args->args[i]
字符串长度为
args->lengths[i]
。
不要假设该字符串以空值终止。
对于类型的参数
INT_RESULT
,必须强制
args->args[i]
转换为
long long
值:
long long int_val; int_val = *((long long *)args-> args [i]);
对于类型的参数
REAL_RESULT
,必须强制
args->args[i]
转换为
double
值:
double real_val; real_val = *((double *)args-> args [i]);
对于类型的参数
DECIMAL_RESULT
,该值作为字符串传递,应该像
STRING_RESULT
值
一样处理
。
ROW_RESULT
参数没有实现。
unsigned long *lengths
对于初始化函数,
lengths
数组指示每个参数的最大字符串长度。
你不应该改变这些。
对于main函数的每次调用,
lengths
包含为当前正在处理的行传递的任何字符串参数的实际长度。
对于类型的参数
INT_RESULT
或
REAL_RESULT
,
lengths
仍包含该参数的最大长度(作为用于初始化功能)。
char *maybe_null
对于初始化函数,
maybe_null
数组为每个参数指示参数值是否为空(如果不是0,如果是,则为1)。
char **attributes
args->attributes
传递有关UDF参数名称的信息。
对于参数
i
,属性名称可用作字符串,
args->attributes[i]
属性长度为
args->attribute_lengths[i]
。
不要假设该字符串以空值终止。
默认情况下,UDF参数的名称是用于指定参数的表达式的文本。
对于UDF,参数也可以有一个可选
子句,在这种情况下参数名称是
。
因此
,每个参数
的
值取决于是否给出了别名。
[AS]
alias_name
alias_name
attributes
假设
my_udf()
调用
UDF
如下:
SELECT my_udf(expr1,expr2 AS alias1,expr3 alias2);
在这种情况下,
attributes
和
attribute_lengths
数组将具有以下值:
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
阵列表示每个参数的名称的长度。
0
如果没有发生错误,
则应返回初始化函数
,
1
否则
返回
。
如果发生错误,
xxx_init()
应在
message
参数中
存储以null结尾的错误消息
。
消息将返回给客户端。
消息缓冲区是
MYSQL_ERRMSG_SIZE
字符长,但您应该尝试将消息保持少于80个字符,以使其适合标准终端屏幕的宽度。
main函数的返回值
xxx()
是函数值,for
long long
和
double
函数。
字符串函数应返回指向结果的指针,并设置
*length
为返回值的长度(以字节为单位)。
例如:
memcpy(结果,“结果字符串”,13); *长度= 13;
MySQL
xxx()
使用
result
参数
将缓冲区传递给
函数
。
此缓冲区足够长,可容纳255个字符,可以是多字节字符。
如果
xxx()
函数适合,
该
函数可以将结果存储在此缓冲区中,在这种情况下,返回值应该是指向缓冲区的指针。
如果函数将结果存储在不同的缓冲区中,它应该返回指向该缓冲区的指针。
如果您的字符串函数不使用提供的缓冲区(例如,如果它需要返回长度超过255个字符的字符串),则必须
malloc()
在
xxx_init()
函数或
xxx()
函数中
为自己的缓冲区分配空间,并
在
函数中释放它
xxx_deinit()
。
您可以将分配的内存存储在
结构
的
ptr
插槽中,以
UDF_INIT
供将来的
xxx()
调用
重用
。
请参见
第29.4.2.1节“简单函数的UDF调用序列”
。
要指示
NULL
main函数
的返回值
,请设置
*is_null
为
1
:
* is_null = 1;
要在main函数中指示错误返回,请设置
*error
为
1
:
*错误= 1;
如果
xxx()
套
*error
到
1
任何行,函数值是
NULL
当前行,并通过在该语句处理任何后续行
XXX()
被调用。
(
xxx()
甚至没有为后续行调用。)
必须在运行服务器的主机上编译和安装实现UDF的文件。
此处描述
sql/udf_example.cc
了MySQL源代码分发中包含
的示例UDF文件的过程
。
有关UDF安装的其他信息,请参见
第5.7.1节“安装和卸载用户定义的函数”
。
如果将在将要复制到从属服务器的语句中引用UDF,则必须确保每个从属服务器都具有可用的功能。 否则,当从属服务器尝试调用该函数时,复制将失败。
紧接着的说明适用于Unix。 Windows的说明将在本节后面给出。
该
udf_example.cc
文件包含以下功能:
metaphon()
返回字符串参数的metaphon字符串。
这类似于soundex字符串,但它更适合英语。
myfunc_double()
返回其参数中字符的ASCII值之和除以其参数长度的总和。
myfunc_int()
返回其参数长度的总和。
sequence([const int])
如果没有给出数字,则返回从给定数字开始的序列或1。
lookup()
返回主机名的IP地址。
reverse_lookup()
返回IP地址的主机名。
可以使用表单的单个字符串参数
'xxx.xxx.xxx.xxx'
或使用四个数字
来调用该函数
。
avgcost()
返回平均成本。
这是一个聚合函数。
应该将可动态加载的文件编译为可共享的库文件,使用如下命令:
gcc -shared -o udf_example.so udf_example.cc
如果你正在使用
CMK
与
CMake
(这是MySQL本身的配置),你应该能够
udf_example.so
用一个更简单的命令
创建
:
make udf_example
编译包含UDF的共享对象后,必须安装它并告诉MySQL它。
udf_example.cc
使用
gcc
直接
编译共享对象
会生成一个名为的文件
udf_example.so
。
将共享对象复制到服务器的插件目录并命名
udf_example.so
。
该目录由
plugin_dir
系统变量
的值给出
。
在某些系统上,
配置动态链接器
的
ldconfig
程序无法识别共享对象,除非其名称以
lib
。
在这种情况下,您应该重命名文件,如
udf_example.so
to
libudf_example.so
。
在Windows上,使用以下过程编译用户定义的函数:
获取MySQL源代码分发。 请参见 第2.1.2节“如何获取MySQL” 。
如有必要,从 http://www.cmake.org 获取 CMake 构建实用程序 。 (需要2.6或更高版本)。
在源代码树中,在
sql
目录中查找名为
udf_example.def
和的
文件
udf_example.cc
。
将这个目录中的两个文件复制到您的工作目录。
使用以下内容
创建一个
CMake
makefile
(
CMakeLists.txt
):
PROJECT(udf_example) #SQL包含目录的路径 INCLUDE_DIRECTORIES( “C:/ MySQL的/包括”) ADD_DEFINITIONS( “ - DHAVE_DLOPEN”) ADD_LIBRARY(udf_example MODULE udf_example.cc udf_example.def) TARGET_LINK_LIBRARIES(udf_example wsock32)
创建VC项目和解决方案文件,替换适当的
generator
值:
cmake -G“ generator
”
调用 cmake --help会 显示有效生成器的列表。
创建
udf_example.dll
:
devenv udf_example.sln / build发布
在所有平台上,将共享库文件复制到
plugin_dir
目录后,
使用以下语句
通知
mysqld
有关新函数的信息。
如果库文件的后缀与
.so
系统上
的后缀不同,请
在整个过程中替换正确的后缀(例如,
.dll
在Windows上)。
创建功能metaphon返回STRING SONAME'udf_example.so'; 创建功能myfunc_double RETURNS REAL SONAME'udf_example.so'; 创建函数myfunc_int RETURNS INTEGER SONAME'udf_example.so'; CREATE FUNCTION序列RETURNS INTEGER SONAME'udf_example.so'; CREATE FUNCTION查找RETURNS STRING SONAME'udf_example.so'; 创建功能reverse_lookup返回STRING SONAME'udf_example.so'; 创造集合功能avgcost RETURNS REAL SONAME'udf_example.so';
安装后,功能将一直保持安装状态,直到卸载为止。
要删除功能,请使用
DROP
FUNCTION
:
DROP FUNCTION metaphon; DROP FUNCTION myfunc_double; DROP FUNCTION myfunc_int; DROP FUNCTION序列; DROP FUNCTION查找; DROP FUNCTION reverse_lookup; DROP FUNCTION avgcost;
该
CREATE
FUNCTION
和
DROP
FUNCTION
语句更新
func
表中
mysql
充当UDF登记系统数据库。
函数的名称,类型和共享库名称保存在
mysql.func
表中。
要创建函数,您必须具有
数据库
的
INSERT
特权
mysql
。
要删除函数,您必须具有
数据库
的
DELETE
权限
mysql
。
您无法用于
CREATE
FUNCTION
重新安装以前安装的功能。
要重新安装某个功能,请先将其删除
DROP
FUNCTION
,然后再安装
CREATE
FUNCTION
。
您需要执行此操作,例如,如果升级到提供该函数的更新实现的新版本的MySQL,或者您重新编译已编写的函数的新版本。
否则,服务器继续使用旧版本。
活动功能是已加载但
CREATE
FUNCTION
未被删除的功能
DROP
FUNCTION
。
每次服务器启动时都会重新加载所有活动函数,除非您
使用该
选项
启动
mysqld
--skip-grant-tables
。
在这种情况下,服务器在启动期间不加载UDF并且UDF不可用。
MySQL采取了一些措施来防止滥用用户定义的函数。
UDF库文件不能放在任意目录中。
它们必须位于服务器的插件目录中。
该目录由值给出
plugin_dir
系统变量
。
要使用
CREATE
FUNCTION
或
DROP
FUNCTION
,您必须
分别拥有
数据库的
权限
INSERT
或
DELETE
权限
mysql
。
这是必要的,因为这些语句会添加和删除
mysql.func
表中的
行
。
除了
xxx
与main
xxx()
函数
对应
的
符号
之外,UDF还应至少定义一个符号
。
这些辅助符号对应
xxx_init()
,
xxx_deinit()
,
xxx_reset()
,
xxx_clear()
,和
xxx_add()
功能。
mysqld
还支持一个
--allow-suspicious-udfs
选项,用于控制是否
xxx
可以加载
仅包含
符号的
UDF
。
默认情况下,该选项处于关闭状态,以防止尝试从包含合法UDF的共享库文件加载函数。
如果您有较旧的UDF只包含
xxx
符号且无法重新编译的
包含辅助符号,可能需要指定该
--allow-suspicious-udfs
选项。
否则,您应该避免启用此功能。
要添加新的本机MySQL函数,请使用此处描述的过程,该过程要求您使用源分发。 您无法将本机函数添加到二进制分发版中,因为必须修改MySQL源代码并从修改后的源代码编译MySQL。 如果迁移到另一个版本的MySQL(例如,发布新版本时),则必须使用新版本重复此过程。
如果将在将复制到从属服务器的语句中引用新的本机函数,则必须确保每个从属服务器也具有可用的函数。 否则,当从属设备尝试调用该函数时,复制将失败。
要添加新的本机函数,请按照以下步骤修改目录中的源文件
sql
:
在以下位置为函数创建子类
item_create.cc
:
如果函数采用的参数的固定数,创建的一个子类
Create_func_arg0
,
Create_func_arg1
,
Create_func_arg2
,或
Create_func_arg3
,分别取决于功能是否需要零个,一个,两个或三个参数。
举例来说,看到的
Create_func_uuid
,
Create_func_abs
,
Create_func_pow
,和
Create_func_lpad
类。
如果函数采用可变数量的参数,则创建一个子类
Create_native_func
。
有关示例,请参阅
Create_func_concat
。
要提供可在SQL语句中引用该函数的名称,请
item_create.cc
通过向此数组添加一行来
注册该名称
:
static Native_func_registry func_array []
您可以为同一功能注册多个名称。
例如,请参阅for
"LCASE"
和
的行
"LOWER"
,它们是别名
Create_func_lcase
。
在
item_func.h
,声明一个继承自
Item_num_func
或
的类
Item_str_func
,取决于函数是返回数字还是字符串。
在
item_func.cc
,添加以下声明之一,具体取决于您是否定义数字或字符串函数:
double Item_func_newname :: val() longlong Item_func_newname :: val_int() String * Item_func_newname :: Str(String * str)
如果从任何标准项(例如
Item_num_func
)
继承对象
,则可能只需定义其中一个函数,并让父对象处理其他函数。
例如,
Item_str_func
该类定义了一个
对返回的值
val()
执行
的
函数
。
atof()
::str()
如果函数是非确定性的,请在项构造函数中包含以下语句,以指示不应缓存函数结果:
current_thd-> lex-> safe_to_cache_query = 0;
如果给定参数的固定值,它可以为不同的调用返回不同的结果,那么函数是不确定的。
您还应该定义以下对象函数:
void Item_func_newname :: fix_length_and_dec()
此函数至少应
max_length
根据给定的参数进行
计算
。
max_length
是函数可能返回的最大字符数。
maybe_null = 0
如果主函数不能返回
NULL
值,
则
此函数也应该设置
。
该函数可以
NULL
通过检查参数的
maybe_null
变量
来检查是否有任何函数参数可以返回
。
请查看
Item_func_mod::fix_length_and_dec
如何执行此操作的典型示例。
所有功能必须是线程安全的。 换句话说,不要在函数中使用任何全局变量或静态变量而不用互斥体保护它们。
如果
NULL
要从
::val()
,,
::val_int()
或者
返回
,
::str()
则应设置
null_value
为1并返回0。
对于
::str()
对象函数,还需要注意以下注意事项:
该
String *str
参数提供了一个字符串缓冲区,可用于保存结果。
(有关
String
类型的
更多信息
,请查看该
sql_string.h
文件。)
该
::str()
函数应该返回保存结果的字符串,或者
(char*)
0
结果是
NULL
。
除非绝对必要,否则所有当前字符串函数都会尝试避免分配任何内存
本节帮助您将MySQL移植到其他操作系统。 首先检查当前支持的操作系统列表。 请参阅 https://www.mysql.com/support/supportedplatforms/database.html 。 如果您已经创建了一个新的MySQL端口,请告诉我们,以便我们在此处和我们的网站( http://www.mysql.com/ ) 上列出 ,推荐给其他用户。
如果您创建一个新的MySQL端口,您可以根据GPL许可证自由复制和分发它,但它不会使您成为MySQL的版权所有者。
服务器需要一个正在运行的POSIX线程库。
要从源代码构建MySQL,您的系统必须满足 第2.9节“从源代码安装MySQL”中 列出的工具要求 。
如果您遇到新端口问题,您可能需要对MySQL进行一些调试! 请参见 第29.5.1节“调试MySQL服务器” 。
在开始调试
mysqld
之前
,首先让测试程序运行
mysys/thr_lock
。
这可以确保您的线程安装甚至可以远程工作!
MySQL源代码包含使用Doxygen编写的内部文档。 本文档对于从开发人员的角度理解MySQL的工作原理非常有用。 生成的Doxygen内容可从 https://dev.mysql.com/doc/index-other.html获得 。 也可以使用 第2.9.7节“生成MySQL Doxygen文档内容”中 的说明从MySQL源代码分发本地生成此内容 。
如果您使用的一些功能是在MySQL很新,你可以尝试运行
mysqld的
与
--skip-new
(即禁用所有新的,潜在的不安全功能)。
请参见
第B.4.3.3节“如果MySQL不断崩溃该怎么办”
。
如果
mysqld
不想启动,请确认您没有
my.cnf
干扰您的设置的文件!
您可以
my.cnf
使用
mysqld --print-defaults
检查您的
参数,
并避免使用
mysqld --no-defaults ...
开头
。
如果 mysqld 开始占用CPU或内存或者它 “ 挂起 ”, 你可以使用 mysqladmin processlist status 来查明某人是否正在执行需要很长时间的查询。 如果遇到性能问题或新客户端无法连接时出现问题,在某些窗口中 运行 mysqladmin -i10 processlist状态 可能是个好主意 。
命令 mysqladmin debug 将有关正在使用的锁,已用内存和查询用法的一些信息转储到MySQL日志文件中。 这可能有助于解决一些问题。 即使您没有编译MySQL进行调试,此命令也提供了一些有用的信息!
如果问题是某些表越来越慢,你应该尝试使用
OPTIMIZE
TABLE
或
myisamchk
优化表
。
请参见
第5章,
MySQL服务器管理
。
您还应该检查慢查询
EXPLAIN
。
您还应该阅读本手册中特定于操作系统的部分,以了解您的环境可能存在的问题。 请参见 第2.1节“一般安装指南” 。
如果您有一些非常具体的问题,可以随时尝试调试MySQL。
为此,您必须使用该
-DWITH_DEBUG=1
选项
配置MySQL
。
您可以通过执行以下操作来检查MySQL是否通过调试进行编译:
mysqld --help
。
如果
--debug
列出了带有选项
的
标志,那么您已启用调试。
mysqladmin ver
还将
mysqld
版本列为
mysql ... -
在这种情况下
为
--debug
。
如果
mysqld
在使用
-DWITH_DEBUG=1
CMake选项
配置时停止崩溃
,您可能在MySQL中发现了编译器错误或计时错误。
在这种情况下,您可以尝试
-g
使用
CMAKE_C_FLAGS
和
CMAKE_CXX_FLAGS
CMake选项
添加
,
而不是使用
-DWITH_DEBUG=1
。
如果
mysqld
死了,你至少可以用
gdb
附加它
或者
在核心文件上
使用
gdb
来找出发生了什么。
当您配置MySQL进行调试时,您会自动启用许多额外的安全检查功能来监控
mysqld
的运行状况
。
如果他们发现
“
意外
”
的内容,则会写入一个条目
stderr
,
mysqld_safe会
指向错误日志!
这也意味着如果您遇到MySQL的一些意外问题并且正在使用源代码分发,那么您应该做的第一件事就是配置MySQL进行调试!
(第二件事是将邮件发送到MySQL邮件列表并寻求帮助。请参见
第1.6.2节“MySQL邮件列表”
。
如果您认为自己发现了错误,请使用
第1.7节“如何报告错误或问题”中的说明
。
在Windows MySQL发行版中,
mysqld.exe
默认情况下编译时支持跟踪文件。
如果 mysqld 服务器无法启动或轻松崩溃,您可以尝试创建跟踪文件以查找问题。
为此,您必须
具有已使用调试支持编译
的
mysqld
。
您可以通过执行来检查
mysqld -V
。
如果版本号以...结尾
-debug
,则编译时支持跟踪文件。
(在Windows上,调试服务器名为
mysqld-debug
而不是
mysqld
。)
在Unix或
Windows
上
使用跟踪登录
启动
mysqld
服务器
:
/tmp/mysqld.trace
\mysqld.trace
外壳> mysqld --debug
在Windows上,您还应该使用该
--standalone
标志不启动
mysqld
作为服务。
在控制台窗口中,使用以下命令:
C:\> mysqld-debug --debug --standalone
在此之后,您可以
mysql.exe
在第二个控制台窗口中
使用
命令行工具来重现该问题。
您可以
使用
mysqladmin shutdown
停止
mysqld
服务器
。
跟踪文件可能变得 非常大 ! 要生成较小的跟踪文件,可以使用以下调试选项:
mysqld --debug = d,info,error,query,general,where:O,/ tmp / mysqld.trace
这仅将带有最有趣标签的信息打印到跟踪文件中。
如果您对此进行错误报告,请仅将跟踪文件中的行发送到相应的邮件列表,其中似乎出现了问题! 如果找不到错误的位置,可以打开错误报告并将跟踪文件上载到报告中,以便MySQL开发人员可以查看它。 有关说明,请参见 第1.7节“如何报告错误或问题” 。
跟踪文件 由Fred Fish 的 DBUG 包 制作 。 请参见 第29.5.4节“DBUG包” 。
程序数据库文件(带后缀
pdb
)包含在
MySQL
的
ZIP Archive Debug Binaries&Test Suite
发行版中。
这些文件提供了在出现问题时调试MySQL安装的信息。
这是从标准MSI或Zip文件单独下载。
PDB文件位于标有“ZIP存档调试二进制文件和测试套件”的单独文件中。
PDB文件包含有关
mysqld
其他工具的
更多详细信息
,可以创建更详细的跟踪和转储文件。
您可以使用
WinDbg
或Visual Studio来调试
mysqld
。
有关PDB文件的详细信息,请参阅 Microsoft知识库文章121366 。 有关可用调试选项的详细信息,请参阅 Windows调试工具 。
要使用WinDbg,请安装完整的Windows驱动程序工具包(WDK)或安装独立版本。
在
.exe
和
.pdb
文件必须完全匹配(包括版本号和MySQL服务器版),或尝试加载符号的WinDBG会抱怨。
要生成minidump
mysqld.dmp
,请启用
core-file
[mysqld]部分下的选项
my.ini
。
进行这些更改后重新启动MySQL服务器。
创建一个目录来存储生成的文件,例如
c:\symbols
使用Find GUI或命令行
确定
windbg.exe
可执行文件
的路径
,例如:
dir /s /b windbg.exe
- 常见的默认设置是
C:\ Program Files \ Windows调试工具(x64)\ windbg.exe
启动
windbg.exe
给它的路径
mysqld.exe
,
mysqld.pdb
,
mysqld.dmp
,和源代码。
或者,从WinDbg GUI传递每个路径。
例如:
windbg.exe -i“C:\ mysql-8.0.18-winx64 \ bin \”^ -z“C:\ mysql-8.0.18-winx64 \ data \ mysqld.dmp”^ -srcpath“E:\ ade \ mysql_archives \ 8.0 \ 8.0.18 \ mysql-8.0.18”^ -y“C:\ mysql-8.0.18-winx64 \ bin; SRV * c:\ symbols * http://msdl.microsoft.com/download/symbols”^ -v -n -c“!analyze -vvvvv”
该
^
字符和换行符由Windows命令行处理器断电,所以一定的空间保持不变。
在大多数系统上, 如果 mysqld 崩溃, 你也可以 从 gdb 启动 mysqld 以获取更多信息 。
对于
Linux上的
一些较旧的
gdb
版本,
run --one-thread
如果您希望能够调试
mysqld
线程,
则
必须使用
它
。
在这种情况下,您一次只能激活一个线程。
最好升级到
gdb
5.1,因为这个版本的线程调试工作得更好!
NPTL线程(Linux上的新线程库) 在 gdb 下 运行 mysqld时 可能会导致问题 。 一些症状是:
在这种情况下,您应该在启动 gdb 之前在shell中设置以下环境变量 :
LD_ASSUME_KERNEL = 2.4.1 export LD_ASSUME_KERNEL
在
gdb
下
运行
mysqld时
,应该禁用堆栈跟踪,
以便能够捕获
gdb中的段错误
。
--skip-stack-trace
使用
--gdb
选项
mysqld的
安装了中断处理程序
SIGINT
(停止所需
的mysqld
与
^C
设置断点),并且禁止堆栈跟踪和核心文件处理。
如果你一直做很多新的连接,因为
gdb
没有为旧线程释放内存,所以
很难在
gdb
下调试MySQL
。
您可以通过启动避免这个问题
的mysqld
与
设定为等于值
+ 1。在只使用大多数情况下
有很大帮助!
thread_cache_size
max_connections
--thread_cache_size=5'
如果你想在Linux上获得核心转储,如果
mysqld
死于SIGSEGV信号,你可以
使用该
选项
启动
mysqld
--core-file
。
这个核心文件可以用来做一个回溯,可以帮助你找出
mysqld
死亡的
原因
:
外壳> gdb mysqld core
gdb> backtrace已满
gdb>退出
请参见 第B.4.3.3节“如果MySQL不断崩溃该怎么办” 。
如果您
在Linux
上使用
gdb
4.17.x或更高版本,则应
.gdb
在当前目录中
安装
包含以下信息的文件:
设置打印七位关闭 处理SIGUSR1 nostop noprint 处理SIGUSR2 nostop noprint 处理SIGWAITING nostop noprint 处理SIGLWP nostop noprint 处理SIGPIPE nostop 处理SIGALRM nostop 处理SIGHUP nostop 处理SIGTERM nostop noprint
如果你在使用 gdb 调试线程时遇到问题 ,你应该下载gdb 5.x并试试这个。 新的 gdb 版本具有非常改进的线程处理!
这是一个如何调试 mysqld 的示例 :
外壳> gdb /usr/local/libexec/mysqld
gdb>运行
...
backtrace full#在mysqld崩溃时执行此操作
在错误报告中包含前面的输出,您可以使用 第1.7节“如何报告错误或问题”中 的说明进行归档 。
如果
mysqld的
挂起,你可以尝试使用一些系统工具,如
strace
或
/usr/proc/bin/pstack
检查其中
的mysqld
已挂起。
strace / tmp / log libexec / mysqld
如果您使用的是Perl
DBI
接口,则可以使用该
trace
方法或设置
DBI_TRACE
环境变量
来打开调试信息
。
在某些操作系统上,如果
mysqld
意外死亡
,则错误日志包含堆栈跟踪
。
您可以使用它来找出
mysqld
死亡的
地方(也许也就是为什么)
。
请参见
第5.4.2节“错误日志”
。
要获得堆栈跟踪,您不能
使用
gcc选项
编译
mysqld
-fomit-frame-pointer
。
请参见
第29.5.1.1节“编译MySQL以进行调试”
。
错误日志中的堆栈跟踪如下所示:
mysqld得到信号11; 试图回溯。您可以使用以下信息 找出mysqld去世的地方。如果之后没有看到任何消息 这个,出了什么问题...... 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得到信号11; 试图回溯。您可以使用以下信息 找出mysqld去世的地方。如果之后没有看到任何消息 这个,出了什么问题...... stack_bottom = 0x41fd0110 thread_stack 0x40000 [0x9da402] [0x6648e9] [0x7f1a5af000f0] [0x7f1a5a10f0f2] [0x7412cb] [0x688354] [0x688494] [0x67a170] [0x67f0ad] [0x67fdf8] [0x6811b6] [0x66e05e]
较新版本的
glibc
堆栈跟踪功能还会打印相对于对象的地址。
glibc
基于
On-
based的系统(Linux),插件中崩溃的跟踪看起来像:
插件/ AUTH / auth_test_plugin.so(+ 0x9a6)[0x7ff4d11c29a6]
要将相对地址(
+0x9a6
)转换为文件名和行号,请使用以下命令:
外壳> addr2line -fie auth_test_plugin.so 0x9a6
auth_test_plugin
MySQL的干线/插件/ AUTH / test_plugin.c:65
该
addr2line
实用程序是部分
binutils
包在Linux上。
在Solaris上,过程类似。
Solaris
printstack()
已经打印了相对地址:
插件/认证/ auth_test_plugin.so:0x1510
要翻译,请使用以下命令:
外壳> gaddr2line -fie auth_test_plugin.so 0x1510
MySQL的干线/插件/ AUTH / test_plugin.c:88
Windows已经打印了地址,函数名称和行:
000007FEF07E10A4 auth_test_plugin.dll!auth_test_plugin()[test_plugin.c:72]
请注意,在 启用通用查询日志 启动 mysqld 之前 ,您应该使用 myisamchk 检查所有表 。 请参见 第5章, MySQL服务器管理 。
如果 mysqld 死亡或挂起,则应启用 mysqld 并启用常规查询日志。 请参见 第5.4.3节“常规查询日志” 。 当 mysqld 再次死亡时,您可以检查杀死 mysqld 的查询的日志文件的结尾 。
如果使用默认的通用查询日志文件,则日志存储在数据库目录中,因为
在大多数情况下,它是日志文件中杀死
mysqld
的最后一个查询
,但如果可能,您应该通过重新启动
mysqld
并执行找到的查询来
验证这一点。
来自
mysql
命令行工具。
如果这样做,您还应该测试所有未完成的复杂查询。
host_name
.log
您还可以
EXPLAIN
在
SELECT
需要很长时间的
所有
语句
上
尝试该命令
,
以确保
mysqld
正确使用索引。
请参见
第13.8.2节“EXPLAIN语法”
。
通过 启用慢查询日志 启动 mysqld , 您可以找到需要很长时间才能执行的 查询。 请参见 第5.4.5节“慢查询日志” 。
如果您
mysqld restarted
在错误日志中
找到文本
(通常是一个名为的文件
),您可能找到了导致
mysqld
失败
的查询
。
如果发生这种情况,您应该使用
myisamchk
检查所有表
(请参阅
第5章,
MySQL服务器管理
),并在MySQL日志文件中测试查询以查看是否出现故障。
如果您发现此类查询,请先尝试升级到最新的MySQL版本。
如果这没有帮助,并且您在
host_name
.errmysql
邮件存档中
找不到任何内容
,则应将错误报告给MySQL邮件列表。
邮件列表在
http://lists.mysql.com/
上描述
,也有链接到在线列表档案。
如果你已经开始
的mysqld
使用
--myisam-recover-options
中,MySQL自动检查并尝试修复
MyISAM
表,如果他们被标记为“未正常关闭”或“崩溃”。
如果发生这种情况,MySQL会在
hostname.err
文件中
写入一个条目,
如果需要修复该表
'Warning: Checking table ...'
,则后跟
该
文件
Warning: Repairing table
。
如果你得到很多这些错误,如果没有
mysqld
在之前意外死亡,那么就会出现问题并需要进一步调查。
请参见
第5.1.7节“服务器命令选项”
。
当服务器检测到
MyISAM
表损坏时,它会将其他信息写入错误日志,例如源文件的名称和行号以及访问该表的线程列表。
示例:
Got an
error from thread_id=1, mi_dynrec.c:368
。
这是包含在错误报告中的有用信息。
如果
mysqld
意外死亡,
这不是一个好兆头
,但在这种情况下,你不应该调查这些
Checking table...
消息,而是试着找出为什么
mysqld
死了。
以下过程适用于
MyISAM
表。
有关遇到
InnoDB
表损坏
时要采取的步骤的信息
,请参见
第1.7节“如何报告错误或问题”
。
如果您遇到损坏的
MyISAM
表或者
mysqld
在某些更新语句后总是失败,您可以通过执行以下操作来测试问题是否可重现:
使用 mysqladmin shutdown 停止MySQL守护进程 。
对表进行备份以防止修复做坏事的非常不可能的情况。
使用
myisamchk -s database / *
检查所有表
.MYI
。
使用
myisamchk -r database /
table
.MYI
修复任何损坏的表
。
对表进行第二次备份。
如果需要更多空间,请从MySQL数据目录中删除(或移走)任何旧日志文件。
启用 mysqld 并启用二进制日志。 如果要查找崩溃 mysqld 的语句, 则应启动服务器并启用常规查询日志。 请参见 第5.4.3节“一般查询日志” 和 第5.4.4节“二进制日志” 。
当你有一个崩溃的表,停止 mysqld 服务器。
恢复备份。
重启 mysqld 服务器, 不 启用二进制日志。
使用
mysqlbinlog binary-log-file |
重新执行语句
mysql
。
二进制日志以名称保存在MySQL数据库目录中
。
hostname-bin.
NNNNNN
如果表再次损坏或者你可以 使用上面的命令 让 mysqld 死掉,你就发现了一个可重现的错误。 使用 第1.7节“如何报告错误或问题”中 给出的说明将表和二进制日志FTP到我们的错误数据库 。 如果您是支持客户,可以使用MySQL客户支持中心( https://www.mysql.com/support/ )向MySQL团队发出有关问题的警报,并尽快修复。
为了能够使用集成的调试包调试MySQL客户端,您应该使用
-DWITH_DEBUG=1
。
请参见
第2.9.4节“MySQL源配置选项”
。
在运行客户端之前,您应该设置
MYSQL_DEBUG
环境变量:
shell>MYSQL_DEBUG=d:t:O,/tmp/client.trace
shell>export MYSQL_DEBUG
这会导致客户端生成跟踪文件
/tmp/client.trace
。
如果您自己的客户端代码有问题,您应该尝试连接到服务器并使用已知可以工作的客户端运行查询。 通过 在调试模式下 运行 mysql 来 做到这一点 (假设您已经编译了MySQL并进行了调试):
外壳> mysql --debug=d:t:O,/tmp/client.trace
如果您邮寄错误报告,这将提供有用的信息。 请参见 第1.7节“如何报告错误或问题” 。
如果您的客户端崩溃了一些“合法”的代码,您应该检查您的
mysql.h
包含文件是否与您的MySQL库文件匹配。
一个非常常见的错误是使用
mysql.h
旧MySQL安装中
的旧
文件和新的MySQL库。
MySQL服务器是一个多线程应用程序,它使用许多内部锁定和与锁相关的原语,例如互斥锁,rwlock(包括prlocks和sxlocks),条件和文件。 在服务器中,与锁相关的对象集随着新功能的实现和代码重构而改变,以提高性能。 与使用锁定原语的任何多线程应用程序一样,在执行多个锁定时,执行期间始终存在遇到死锁的风险。 对于MySQL,死锁的影响是灾难性的,导致完全丧失服务。
从MySQL 8.0.17开始,为了能够检测锁定获取死锁并强制执行运行时执行,MySQL支持LOCK_ORDER工具。 这使得锁定顺序依赖图可以定义为服务器设计的一部分,并且服务器运行时检查可以确保锁获取是非循环的,并且执行路径符合图形。
本节提供有关使用LOCK_ORDER工具的信息,但仅限于基本级别。 有关完整的详细信息,请参阅MySQL服务器Doxygen文档的Lock Order部分,可从 https://dev.mysql.com/doc/index-other.html获取 。
LOCK_ORDER工具用于调试服务器,而不是用于生产。
要使用LOCK_ORDER工具,请按照以下步骤操作:
从源代码构建MySQL,使用
CMake
选项
对其进行配置,
以便构建包含LOCK_ORDER工具。
-DWITH_LOCK_ORDER=ON
WITH_LOCK_ORDER
启用
该
选项后,MySQL构建需要
flex
程序。
要在启用LOCK_ORDER工具的情况下运行服务器,请
lock_order
在服务器启动时
启用
系统变量。
还可以使用LOCK_ORDER配置的其他几个系统变量。
对于MySQL测试套件操作,
mysql-test-run.pl
有一个
--lock-order
选项,用于控制在测试用例执行期间是否启用LOCK_ORDER工具。
系统变量描述了LOCK_ORDER工具的配置操作,假设MySQL已经构建为包含LOCK_ORDER工具。
主变量是
lock_order
,表示是否在运行时启用LOCK_ORDER工具:
如果
lock_order
禁用(默认值),则没有其他LOCK_ORDER系统变量有任何影响。
如果
lock_order
启用,则其他系统变量配置要启用的LOCK_ORDER功能。
通常,通过
使用
选项
执行
mysql-test-run.pl
来配置LOCK_ORDER工具
--lock-order
,并使用
mysql-test-run.pl
将LOCK_ORDER系统变量设置为适当的值。
必须在服务器启动时设置所有LOCK_ORDER系统变量。 在运行时,它们的值是可见的,但不能更改。
一些系统变量成对存在,例如
lock_order_debug_loop
和
lock_order_trace_loop
。
对于这样的对,当条件与它们相关联时,变量如下区分:
如果
_debug_
启用
该
变量,则会引发调试断言。
如果
_trace_
启用
该
变量,则会在日志中输出错误。
表29.4 LOCK_ORDER系统变量摘要
变量名 | 变量类型 | 可变范围 |
---|---|---|
的lock_order | 布尔 | 全球 |
lock_order_debug_loop | 布尔 | 全球 |
lock_order_debug_missing_arc | 布尔 | 全球 |
lock_order_debug_missing_key | 布尔 | 全球 |
lock_order_debug_missing_unlock | 布尔 | 全球 |
lock_order_dependencies | 文件名 | 全球 |
lock_order_extra_dependencies | 文件名 | 全球 |
lock_order_output_directory | 目录名称 | 全球 |
lock_order_print_txt | 布尔 | 全球 |
lock_order_trace_loop | 布尔 | 全球 |
lock_order_trace_missing_arc | 布尔 | 全球 |
lock_order_trace_missing_key | 布尔 | 全球 |
lock_order_trace_missing_unlock | 布尔 | 全球 |
属性 | 值 |
---|---|
命令行格式 | --lock-order[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
是否在运行时启用LOCK_ORDER工具。
如果
lock_order
禁用(默认值),则没有其他LOCK_ORDER系统变量有任何影响。
如果
lock_order
启用,则其他系统变量配置要启用的LOCK_ORDER功能。
如果
lock_order
启用,则如果服务器遇到未在锁定顺序图中声明的锁定获取序列,则会引发错误。
属性 | 值 |
---|---|
命令行格式 | --lock-order-debug-loop[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_debug_loop |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
当LOCK_ORDER工具遇到在锁定顺序图中标记为循环的依赖项时,它是否会导致调试断言失败。
属性 | 值 |
---|---|
命令行格式 | --lock-order-debug-missing-arc[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_debug_missing_arc |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
当LOCK_ORDER工具遇到未在锁定顺序图中声明的依赖项时,是否会导致调试断言失败。
属性 | 值 |
---|---|
命令行格式 | --lock-order-debug-missing-key[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_debug_missing_key |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
当LOCK_ORDER工具遇到未正确使用性能模式检测的对象时,它是否会导致调试断言失败。
lock_order_debug_missing_unlock
属性 | 值 |
---|---|
命令行格式 | --lock-order-debug-missing-unlock[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_debug_missing_unlock |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
LOCK_ORDER工具是否在遇到仍然保持时销毁的锁时导致调试断言失败。
属性 | 值 |
---|---|
命令行格式 | --lock-order-dependencies=file_name |
介绍 | 8.0.17 |
系统变量 | lock_order_dependencies |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 文件名 |
默认值 | empty string |
lock_order_dependencies.txt
定义服务器锁定顺序依赖关系图
的
文件
的路径
。
允许指定无依赖关系。 在这种情况下使用空依赖图。
属性 | 值 |
---|---|
命令行格式 | --lock-order-extra-dependencies=file_name |
介绍 | 8.0.17 |
系统变量 | lock_order_extra_dependencies |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 文件名 |
默认值 | empty string |
包含锁定顺序依赖关系图的其他依赖关系的文件的路径。
这对于修改
lock_order_dependencies.txt
文件中
定义的主服务器依赖关系图以及
描述第三方代码行为的其他依赖关系
非常有用
。
(另一种方法是修改
lock_order_dependencies.txt
自己,不鼓励。)
如果未设置此变量,则不使用辅助文件。
属性 | 值 |
---|---|
命令行格式 | --lock-order-output-directory=dir_name |
介绍 | 8.0.17 |
系统变量 | lock_order_output_directory |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 目录名称 |
默认值 | empty string |
LOCK_ORDER工具写入其日志的目录。 如果未设置此变量,则默认为当前目录。
属性 | 值 |
---|---|
命令行格式 | --lock-order-print-txt[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_print_txt |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
LOCK_ORDER工具是否执行锁定顺序图分析并打印文本报告。 该报告包括检测到的任何锁定采集周期。
属性 | 值 |
---|---|
命令行格式 | --lock-order-trace-loop[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_trace_loop |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
当LOCK_ORDER工具遇到在锁定顺序图中标记为循环的依赖项时,它是否在日志文件中打印跟踪。
属性 | 值 |
---|---|
命令行格式 | --lock-order-trace-missing-arc[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_trace_missing_arc |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | ON |
当LOCK_ORDER工具遇到未在锁定顺序图中声明的依赖项时,它是否在日志文件中打印跟踪。
属性 | 值 |
---|---|
命令行格式 | --lock-order-trace-missing-key[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_trace_missing_key |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | OFF |
当LOCK_ORDER工具遇到未使用性能模式正确检测的对象时,是否在日志文件中打印跟踪。
lock_order_trace_missing_unlock
属性 | 值 |
---|---|
命令行格式 | --lock-order-trace-missing-unlock[={OFF|ON}] |
介绍 | 8.0.17 |
系统变量 | lock_order_trace_missing_unlock |
范围 | 全球 |
动态 | 没有 |
SET_VAR
提示适用
|
没有 |
类型 | 布尔 |
默认值 | ON |
LOCK_ORDER工具是否在遇到仍然保持时销毁的锁时在日志文件中打印跟踪。
MySQL服务器和大多数MySQL客户端都是使用最初由Fred Fish创建的DBUG包编译的。 当您配置MySQL进行调试时,此包可以获取程序正在执行的跟踪文件。 请参见 第29.5.1.2节“创建跟踪文件” 。
本节总结了您可以在命令行的调试选项中为使用调试支持构建的MySQL程序指定的参数值。
可以通过使用
或
选项
调用程序来使用DBUG包
。
如果指定
没有
值
的
或
选项
,则大多数MySQL程序使用默认值。
服务器默认
位于Unix和
Windows上。
此默认值的效果是:
--debug[=
debug_options
]-#
[
debug_options
]--debug
-#
debug_options
d:t:i:o,/tmp/mysqld.trace
d:t:i:O,\mysqld.trace
d
:为所有调试宏启用输出
t
:跟踪函数调用和退出
i
:将PID添加到输出行
o,/tmp/mysqld.trace
,
O,\mysqld.trace
:设置调试输出文件。
无论平台如何,
大多数客户端程序都使用默认
debug_options
值
。
d:t:o,/tmp/
program_name
.trace
以下是一些示例调试控制字符串,因为它们可能在shell命令行中指定:
--debug = d:吨 --debug = d:F,主,subr1:F:L:吨,20 --debug = d,输入,输出,文件:N --debug = d:吨:I:O,\\ mysqld.trace目录
对于
mysqld
,还可以通过设置
debug
系统变量
在运行时更改DBUG设置
。
此变量具有全局和会话值:
mysql> mysql>SET GLOBAL debug = '
debug_options
';SET SESSION debug = '
debug_options
';
更改全局
debug
值需要足以设置全局系统变量的权限。
更改会话
debug
值需要足以设置受限会话系统变量的权限。
请参见
第5.1.9.1节“系统变量权限”
。
该
debug_options
值是一系列冒号分隔的字段:
field_1:field_2:...:field_N
值中的每个字段都包含一个强制标志字符,可选地以一个
+
或
一个
-
字符开头,并且可选地后跟一个以逗号分隔的修饰符列表:
[+ | - ]标记[,改性剂,改性剂,...,修改]
下表描述了允许的标志字符。 无法识别的标志字符会被忽略。
旗 |
描述 |
---|---|
|
启用DBUG_
在MySQL中,公共调试宏关键字启用是
|
|
每个调试器输出行后延迟。
争论的焦点是机器能力的延迟,以十分之一秒为单位。
例如,
|
|
将调试,跟踪和分析限制到命名函数列表。
空列表启用所有功能。
仍然必须给出
适当的
|
|
确定每行调试或跟踪输出的源文件名。 |
|
使用每行调试或跟踪输出的PID或线程ID标识进程。 |
|
确定每行调试或跟踪输出的源文件行号。 |
|
为每行调试或跟踪输出打印当前函数嵌套深度。 |
|
为每行调试输出编号。 |
|
将调试器输出流重定向到指定的文件。
默认输出是
|
|
喜欢
|
|
将调试器操作限制为指定的进程。
必须使用
|
|
打印每行调试或跟踪输出的当前进程名称。 |
|
在推送新状态时,不要继承先前状态的函数嵌套级别。 当输出从左边距开始时很有用。 |
|
|
|
启用函数调用/退出跟踪行。 可以跟一个列表(只包含一个修饰符)给出一个数字最大跟踪级别,超过该级别,调试或跟踪宏都不会输出。 默认值是编译时选项。 |
修饰符
的前导
+
或
-
字符和尾随列表用于标记字符,例如
d
或
f
可以为所有适用的修饰符或其中一些修饰符启用调试操作:
如果没有前导
+
或
-
,则将标志值设置为给定的修改器列表。
使用前导
+
或
-
,列表中的修饰符将添加到当前修改器列表或从当前修改器列表中减去。
以下示例显示了这对
d
标志的
工作原理
。
d
为所有调试宏启用
空
列表输出。
非空列表仅允许输出列表中的宏关键字。
这些语句将
d
值
设置
为给定的修饰符列表:
mysql>SET debug = 'd';
mysql>SELECT @@debug;
+ --------- + | @@ debug | + --------- + | d | + --------- + mysql>SET debug = 'd,error,warning';
mysql>SELECT @@debug;
+ ----------------- + | @@ debug | + ----------------- + | d,错误,警告| + ----------------- +
当前
值的
前导
+
或
-
增加或减去
d
:
mysql>SET debug = '+d,loop';
mysql>SELECT @@debug;
+ ---------------------- + | @@ debug | + ---------------------- + | d,错误,警告,循环| + ---------------------- + mysql>SET debug = '-d,error,loop';
mysql>SELECT @@debug;
+ ----------- + | @@ debug | + ----------- + | d,警告| + ----------- +
添加到 “ 启用所有宏 ” 不会导致任何更改:
mysql>SET debug = 'd';
mysql>SELECT @@debug;
+ --------- + | @@ debug | + --------- + | d | + --------- + mysql>SET debug = '+d,loop';
mysql>SELECT @@debug;
+ --------- + | @@ debug | + --------- + | d | + --------- +
禁用所有已启用的宏会
d
完全
禁用该
标志:
mysql>SET debug = 'd,error,loop';
mysql>SELECT @@debug;
+ -------------- + | @@ debug | + -------------- + | d,错误,循环| + -------------- + mysql>SET debug = '-d,error,loop';
mysql>SELECT @@debug;
+ --------- + | @@ debug | + --------- + | | + --------- +