mysql存储过程实现详解
一、解析
语法树如下:
sp_tail:
PROCEDURE_SYM
opt_if_not_exists
sp_name
‘(‘ sp_pdparam_list ‘)’
sp_c_chistics
sp_proc_stmt:
sp_proc_stmt_statement:
simple_statement
sp_proc_stmt_return
sp_proc_stmt_if
case_stmt_specification
sp_labeled_block
sp_unlabeled_block:
sp_block_content:
BEGIN_SYM
sp_decls:
sp_decls
sp_decl:
DECLARE_SYM
sp_decl_idents
type
opt_collate
sp_opt_default
| DECLARE_SYM
ident
CONDITION_SYM
FOR_SYM
sp_cond
| DECLARE_SYM
sp_handler_type
HANDLER_SYM
FOR_SYM
sp_hcond_list
sp_proc_stmt
| DECLARE_SYM
ident
CURSOR_SYM
FOR_SYM
select_stmt
‘;’
sp_proc_stmts:
sp_proc_stmts
sp_proc_stmt
';'
END
sp_labeled_control:
label_ident ‘:’
sp_unlabeled_control:
LOOP_SYM sp_proc_stmts1 END LOOP_SYM
| WHILE_SYM expr DO_SYM sp_proc_stmts1 END WHILE_SYM
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM expr END REPEAT_SYM
sp_opt_label
sp_proc_stmt_unlabeled
sp_proc_stmt_leave
sp_proc_stmt_iterate
sp_proc_stmt_open
sp_proc_stmt_fetch
sp_proc_stmt_close
除非是单语句的存储过程,否则一般情况下至少使用sp_unlabeled_block -> sp_block_content来定义函数体,然后在这里面编写复数语句。语句大致分为传统语句和控制语句两类,这些语句最终会被解析为如下指令集,并保存在数据字典中。
存储过程函数体的解析仍然依赖原本的解析过程,即仍然使用create语句的文法,在THD的视角这就是一句完成的语句,只调用了一次MYSQLparse,只不过多进行了几次expr和simple_statement的规约而已。但这个过程又存在Lex的上下文切换,以simple_statement为例,完成simple_statement的规约后以parse_tree_root为根的解析树已经建好,进一步规约为sp_proc_stmt_statement时,就会切换Lex的上下文,如下图:
所以从Lex的角度来看,这就是分别解析了多个语句,上图MAKE_CMD便是对这一说法的印证,这里make_sql_cmd的执行并非像往常一样安排在MYSQLparse之后,而是规约的过程中生成了一系列的Sql_cmd。总结起来,create procedure语句的解析是单句输入(THD),多句输出(Lex和Sql_cmd)。
create procedure语句本身的执行过程本文略过不谈,与数据字典和权限相关的内容较多,而且过于细节,最关键的因素是,与其它create类语句似乎亦并无二至,其本质上应分属DDL的研究领域。
一、调用
存储过程的调用是解释执行存储在数据字典中的指令序列,附带参数的指令会在执行过程中prepare,控制指令一般用jump实现,这一部分在逻辑上使用(ip,nextp)的自动机实现,并不复杂,参数的求值依赖Item的val求值体系,prepare时会对Item执行fix_fields操作确定Item的数据来源,与往常的SQL执行一致。真正关键的是传统SQL语句的执行,解析为sp_instr_stmt指令,细节很多,主要流程是在切换上下文(包括arena,da和sp_pcontext)后调用mysql_execute_command,参考下图。