如何用awk在MySQL存储过程中批量添加传递自身名称的CALL语句
MySQL存储过程批量添加自定义调用实现方案
需求说明
需要为MySQL数据库中的50多个存储过程开头添加固定调用逻辑,把当前执行的例程名称作为参数传入新调用。暂时没有找到MySQL内部实现该需求的简便方法,因此计划通过mysqldump导出所有存储过程,用awk/sed等工具修改导出文件后再重新导入创建存储过程,实际操作复杂度高于预期。
具体要求
从CREATE ... PROCEDURE语句行中提取存储过程名称,在后续匹配到的第一个BEGIN语句后插入CALL NewFunc(currentFuncName)行,需要注意BEGIN语句和CREATE语句的间隔行数不固定。
已实现的基础逻辑
目前已经完成提取存储过程名称的awk逻辑,代码如下:
awk '/CREATE.*PROCEDURE/ {gsub(/^.*PROCEDURE `|`\(.*$/,"");print "call newFuncHere(" $1 ");"}'
核心问题
如何用awk将上述代码生成的调用语句,插入到对应存储过程匹配到的第一个BEGIN语句之后?
示例源文件内容
CREATE DEFINER=`blah@%` PROCEDURE `theProcedure`(`param1` BIGINT(21) UNSIGNED, theExisting BIGINT(21) UNSIGNED, INOUT `myStatus` VARCHAR(255) ) SQL SECURITY INVOKER BEGIN DECLARE blah VARCHAR(32) DEFAULT NULL;
期望输出内容
CREATE DEFINER=`blah@%` PROCEDURE `theProcedure`(`param1` BIGINT(21) UNSIGNED, theExisting BIGINT(21) UNSIGNED, INOUT `myStatus` VARCHAR(255) ) SQL SECURITY INVOKER BEGIN CALL newFuncHere(theProcedure); DECLARE blah VARCHAR(32) DEFAULT NULL;
注:缩进不做强制要求,以上仅为示例
最终实现方案(适配DECLARE语法要求)
后续实现中发现遗漏了MySQL存储过程要求DECLARE语句必须放在过程最开头的规则,调整后的最终awk脚本如下:
# 初始化变量 BEGIN { seen=0; beginCount=-1; createCount=-1; done=0; } # 空行直接输出不处理 /^$|^\t$/ { print $0 ; next ;} # 匹配到CREATE开头的存储过程/函数语句时,保存例程名称,重置嵌套计数器 /^CREATE/{createCount++} ($5~/PROCEDURE/ || $5~/FUNCTION/) { name=$6 ; beginCount=-1 } # 匹配到BEGIN时增加嵌套层数计数器,用于区分嵌套的BEGIN语句 /BEGIN/ {beginCount++} # 匹配到DECLARE语句时标记 /DECLARE/{seen++} # 满足以下条件时插入自定义调用语句: # 1. 未插入过 2. 当前是存储过程最外层的BEGIN块 3. 已经过了所有DECLARE语句 !done && !beginCount && !createCount && seen && !/DECLARE/{ print "CALL newFunction('" name "');" ORS $0 ; seen=0;count++; done=1 ; next;} # 匹配到嵌套块的END语句时减少嵌套层数 /END.*;/ && beginCount {beginCount--; print $0 ; next ;} # 匹配到存储过程最外层的END语句时重置所有计数器 /END.*;/ && !beginCount {createCount=-1 ; beginCount=-1 ; seen=0; done=0; } # 普通行直接输出 { print $0 ;}
已知局限性
该脚本仍存在不完善的地方,需要额外适配END IF语句、跨行DECLARE语句等场景,同时存在部分冗余代码,但已可以满足当前使用需求。
内容的提问来源于stack exchange,提问作者Phil Sumner
相关产品推荐
相关产品推荐

