草庐IT

MySQL Server可执行注释

GreatSQL 2023-03-28 原文

MySQL Server当前支持如下3种注释风格:

  • 以'# '开头的单行注释
  • 以'-- '开头的单行注释
  • C语言风格的单行/多行注释

如下sql脚本给出了3种注释风格的示例:

/* 这是一个
多行注释
示例
*/
select 1 from dual;
select 2 from dual; # 单行注释用例1
select 3 from dual; -- 单行注释用例2

可执行注释

为了支持在不同数据库之间的可移植性,MySQL Server针对C风格的注释在解析上做了一些扩展,当注释满足如下风格时,MySQL Server将会解析并执行注释中的代码:

/*! MySQL-specific code */

通过比较如下两个带注释的sql语句的执行结果可以比较直观地看出可执行注释语句的行为:

# 普通注释,'+1' 被忽略
mysql> select 1 /* +1 */;
+---+
| 1 |
+---+
| 1 |
+---+

# 可执行注释,'+1' 被当成语句的一部分
mysql> select 1 /*! +1 */;
+-------+
| 1  +1 |
+-------+
|     2 |
+-------+

借助这一特性,我们就有机会编写具备较好移植性的SQL语句, 在使MySQL独有特性的同时,保证了sql在其它数据库也能够成功被执行:

create table t1(col1 int) /*! engine=MyISAM */;
select /*! STRAIGHT_JOIN */ col1 from t1;
...

/*!version-number SQL*/

在日常使用中,我们还会经常看到如下格式的注释语句:

/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE */
/*!80000 SET SESSION information_schema_stats_expiry=0 */
/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */

/*!跟的5位数字为版本指示器,其与数据库版本的对应规则为:

'/' '*' '!', followed by exactly
第1位:主版本号(VERSION_MAJOR), 
第2, 3位:小版本号(VERSION_MINOR),
第4, 5位:Patch号(VERSION_PATCH)
示例:
32302 -> 3.23.02
50738 -> 5.7.38
80025 -> 8.0.25

以上述第一个注释语句为例,它的含义可以描述为:当MySQL数据库版本为5.0.3或更高版本时,将SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE读取出来参与sql语法解析,并最终被执行;当MySQL版本低于5.0.3时,该行语句被当成一个普通的注释。不难看出,带version_number的可执行注释,是为了解决不同的MySQL版本之间的兼容问题。以8.0.23版本新增的Invisible Columnsw为例, 如下建表语句在8.0.23版本之前将无法执行:

CREATE TABLE t1 (i INT, j DATE INVISIBLE);

如下的语句改造则保证了建表语句的向下版本兼容:

CREATE TABLE t1 (i INT, j DATE /*!80023 INVISIBLE */);

实际上,在我们常用的工具mysqldump也借用这个特性,使得产生的sql能够兼容不同的数据库版本:

/*mysqldump 代码片段*/
   dump_fputs(
        sql_file,
        "/*!50717 SELECT COUNT(*) INTO @rocksdb_has_p_s_session_variables"
        " FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA ="
        " 'performance_schema' AND TABLE_NAME = 'session_variables'"
        " */;\n"
        "/*!50717 SET @rocksdb_get_is_supported = IF"
        " (@rocksdb_has_p_s_session_variables, 'SELECT COUNT(*) INTO"
        " @rocksdb_is_supported FROM performance_schema.session_variables"
        " WHERE VARIABLE_NAME=\\'rocksdb_bulk_load\\'', 'SELECT 0') */;\n"
        "/*!50717 PREPARE s FROM @rocksdb_get_is_supported */;\n"
        "/*!50717 EXECUTE s */;\n"
        "/*!50717 DEALLOCATE PREPARE s */;\n"
        "/*!50717 SET @rocksdb_enable_bulk_load = IF"
        " (@rocksdb_is_supported, 'SET SESSION rocksdb_bulk_load = 1',"
        " 'SET @rocksdb_dummy_bulk_load = 0') */;\n"
        "/*!50717 PREPARE s FROM @rocksdb_enable_bulk_load */;\n"
        "/*!50717 EXECUTE s */;\n"
        "/*!50717 DEALLOCATE PREPARE s */;\n");
    check_io(sql_file);

在show create table等语句中我们也能看到类似的应用(sql/sql_show.cc):

mysql> create table t1 (i int, j date invisible);
Query OK, 0 rows affected (0.03 sec)

mysql> show create table t1;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `i` int DEFAULT NULL,
  `j` date DEFAULT NULL /*!80023 INVISIBLE */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

结语

mysql server提供的可执行注释功能,在横向跨数据库和纵向跨版本兼容上都为数据库用户提供了较大支持,是一个比较便利的特性。功能实现上,mysql server是在词法解析阶段先对语句做了一遍拦截,针对/*!按具体情况做了特殊处理,如有兴趣您可以参考mysql的词法解析相关源码。注:以8.0.25版本为例,它的相关解析放在sql_lex.cc的lex_one_token()中,在其中您也能看见mysql词法解析器是怎么对optimizer hints comments(格式: /*+ optimizer_hints */ )进行处理的。


Enjoy GreatSQL ?

文章推荐:

有趣的SQL DIGEST

ulimits不生效导致数据库启动失败和相关设置说明
MGR及GreatSQL资源汇总

GreatSQL MGR FAQ

在Linux下源码编译安装GreatSQL/MySQL

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

Gitee:
https://gitee.com/GreatSQL/GreatSQL

GitHub:
https://github.com/GreatSQL/GreatSQL

Bilibili:
https://space.bilibili.com/1363850082/favlist

技术交流群:

微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群

有关MySQL Server可执行注释的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  3. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  4. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  5. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  6. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  7. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  8. ruby-on-rails - Rake 任务仅调用一次时执行两次 - 2

    我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里

  9. ruby - 在好的 Ruby 代码中没有注释是否被认为是可以接受的? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭5年前。Improvethisquestion我审查了一些用Ruby编写的专业代码,没有发现任何评论。代码读起来相当清晰,但没有self记录。我应该期望专业编写的Ruby代码有注释吗?或者,是否有一些Ruby原则认为注释不是必需的?

  10. ruby-on-rails - 只有当不是 nil 时才执行映射? - 2

    如果names为nil,则以下中断。我怎样才能让这个map只有在它不是nil时才执行?self.topics=names.split(",").mapdo|n|Topic.where(name:n.strip).first_or_create!end 最佳答案 其他几个选项:选项1(在其上执行map时检查split的结果):names_list=names.try(:split,",")self.topics=names_list.mapdo|n|Topic.where(name:n.strip).first_or_create!e

随机推荐