当前位置: 首页 > 科技观察

说说MySQLServer的可执行注释,你懂吗?

时间:2023-03-22 11:28:43 科技观察

前言MySQLServer目前支持以下三种注释风格:以'#'开头的单行注释以'--'开头的单行注释C语言风格的单行/多行注释以下SQL脚本给出三种注释样式示例:/*这是一个多行注释示例*/select1fromdual;select2fromdual;#单行注释用例1select3fromdual;--单行注释用例2可以执行注释为了支持不同数据库之间的可移植性,MySQLServer在解析C风格的注释方面做了一些扩展。当注释满足以下风格时,MySQLServer会解析并执行注释中的代码:/*!MySQL具体代码*/通过对比如下两条带注释的SQL语句的执行结果可以直观的看出可执行注释语句的行为:#普通注释,'+1'被忽略mysql>select1/*+1*/;+---+|1|+---+|1|+---+#可执行注释,'+1'被视为语句的一部分mysql>select1/*!+1*/;+--------+|1+1|+------+|2|+------+有了这个特性,我们就有机会写出可移植性更好的SQL语句,当使用MySQLunique时,同时保证了SQL语句在其他数据库中也能成功执行:create表t1(col1int)/*!引擎=MyISAM*/;选择/*!STRAIGHT_JOIN*/来自t1的col1;.../*!version-numberSQL*/在日常使用中,我们经常会看到如下格式的注释语句:/*!50003SET@OLD_COMPLETION_TYPE=@@COMPLETION_TYPE*//*!80000SETSESSIONinformation_schema_stats_expiry=0*//*!50013DEFINER=`root`@`localhost`SQLSECURITYDEFINER*//*!后面的5位数字是版本号,它与数据库版本对应的规则是:'/''*''!',后接第一位数字:主版本号(VERSION_MAJOR),第二和第三位数字:次要版本号(VERSION_MINOR),第四和第五位数字:补丁号(VERSION_PATCH)示例:32302->3.23.0250738->5.7.3880025->8.0.25以上面第一条注释语句为例,其含义可以描述为:当MySQL数据库版本为5.0.3或更高时,读取SET@OLD_COMPLETION_TYPE=@@COMPLETION_TYPE参与SQL语法解析并最终执行;当MySQL版本低于5.0.3时,该行语句视为普通注释。不难看出,带有version_number的可执行注释是为了解决不同MySQL版本之间的兼容性问题。以8.0.23版本新增的InvisibleColumnsw为例,8.0.23版本之前将无法执行如下建表语句:CREATETABLEt1(iINT,jDATEINVISIBLE);下面的语句修改保证了建表语句的向下版本兼容性:CREATETABLEt1(iINT,jDATE/*!80023INVISIBLE*/);其实我们常用的工具mysqldump也借用了这个特性,让生成的SQL兼容不同的数据库版本:INFORMATION_SCHEMA.TABLESWHERETABLE_SCHEMA=""'performance_schema'ANDTABLE_NAME='session_*/variables'"/*!50717SET@rocksdb_get_is_supported=IF""(@rocksdb_has_p_s_session_variables,'SELECTCOUNT(*)INTO""@rocksdb_is_supportedFROMperformance_schema.session_variables""WHEREVARIABLE_NAME=\\'rocksdbLE\'load_)*/;\n""/*!50717PREPAREsFROM@rocksdb_get_is_supported*/;\n""/*!50717EXECUTEs*/;\n""/*!50717取消分配准备*/;\n""/*!50717SET@rocksdb_enable_bulk_load=IF""(@rocksdb_is_supported,'SETSESSIONrocksdb_bulk_load=1',""'SET@rocksdb_dummy_bulk_load=0')*/;\n""/*!50717从@rocksdb_enable_bulk_load准备*/;\n""/*!50717EXECUTEs*/;\n""/*!50717DEALLOCATEPREPAREs*/;\n");check_io(sql_file);我们在showcreatetable(sql/sql_show.cc)等语句中也可以看到类似的应用):mysql>createtablet1(iint,jdateinvisible);QueryOK,0rowsaffected(0.03sec)mysql>showcreatetablet1;+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------+|表|创建表|+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+|t1|CREATETABLE`t1`(`i`intDEFAULTNULL,`j`dateDEFAULTNULL/*!80023INVISIBLE*/)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_0900_ai_ci|+------+--------------------------------------------------------------------------------------------------------------------------------------------------------+1rowinset(0.01sec)结论MySQLServer提供的可执行注释功能为数据库用户提供了横向跨数据库和纵向跨版本的兼容性,是一个比较方便的特性和功能实现。MySQLServer首先拦截词法分析阶段的语句,对/*!根据具体情况。有兴趣的可以参考MySQL。词法分析相关源码。注:以8.0.25版本为例,它的相关分析放在sql_lex.cc的lex_one_token()中,在里面也可以看到MySQL词法分析器是如何响应optimizerhints注释的(格式:/*+optimizer_hints*/)进行处理。