一、描述
  存储过程是一组可以完成特定功能的SQL语句集,经编译后存储在数据库中
  statement语句(DDL、DML、导出及管理语句等)、异常处理、流程控制
二、创建存储过程
  系统做语句分析,如果没有出现词、语法等的错误则存入系统表mysql.proc中
三、调用存储过程
1、编译
  存储过程体中的语句集会被解析为一组指令集
  存储过程的执行就是从该组指令集的第一个指令开始顺序执行
  系统对存储过程的解析是以语句或结构为单位的,该部分处理在YACC中完成
  注意:语句和指令之间并非一对一的对应关系

  
2、优化
  优化的目标为去除无用指令、使用捷径更新跳转路径和压缩指令集
  优化针对流程控制语句和结构
  (1) 遍历所有指令,标记会跳转到的指令opt_mark(...)
  从第1条指令开始遍历;遍历规则依各指令中指示下一条执行指令的位置(m_ip+1、m_dest、m_cont_dest)进行深度优先遍历
  追踪连续跳转至最后一个指令位置(已有跳转标记、自指向和闭环)opt_shortcut_jump(...)

  
  (2) 压缩指令及顺序更新
  去除不会被使用的指令(无跳转标记);后续指令前移,并更新位置信息(m_ip)opt_move(...);更新跳转指令中的跳转位置信息set_destination(...)
3、执行
  当调用存储过程的命令(CALL...)发送到服务端时,该语句会被解析并触发对系统表mysql.proc的读取以及对存储过程语句集的解析,在该解析过程中会创建sp_head对象以及sp_instr各子类的对象,生成指令集并进行优化(如果此存储过程在当前session中已被调用过,则解析后的相关信息会被存储在缓存中,此时可略过db_load_routine()中各步骤,直接使用)
  在执行指令集之前,需将传入的参数进行对应项的改写与填充,并根据指令类型的不同进行不同的处理,并最终由net_end_statement()将结果集发送回客户端
4、基本流程示意

  
四、类图
1、类间关系
  Class sp_head,定义了存储过程相关变量、结构以及公用的方法和接口
  指令共16种,每个指令对应一个Class sp_instr的子类并通过接口处理执行
  Class sp_instr_set_trigger_field和Class sp_instr_freturn分别对应触发器和自定义函数

  
2、策略模式
  sp_instr抽象类提供策略执行接口execute()和exec_core(),m_ip为指令本身的序号
  sp_instr_opt_meta::m_dest为跳转序号
  16个子类实现执行算法,设置相关序号
  sp_head::m_instr维护策略实例集
  sp_head::execute()设置运行时具体策略的选用
五、指令集
  打开动态游标、部分declare语句、SET语句、LEAVE语句、LOOP结构、IF结构、CASE    结构、REPEAT结构和WHILE结构会被拆分为多条指令
  其余和statement语句则不会被拆分为多条指令,即自身就对应一条指令
  下面对这些语句做一下简单说明:
1、DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement;
  此语句会被拆分为3部分:
  1)记录handler信息指令,对应 sp_instr_hpush_jump子类,指定跳转位置
  2)sp_statement 代表处理器指令,是用户自定义的语句部分
  3)根据handler类型指定跳转位置,对应 sp_instr_hreturn子类
2、DECLARE var_name[,...] type [DEFAULT value];
  此语句随定义var_name的个数被拆分成若干赋值指令,对应sp_instr_set子类
3、DECLARE <游标名称> CURSOR FOR <SELECT 语句>;
  定义静态游标指令,对应sp_instr_cpush子类,负责记录cursor信息
4、SET var_name = expr [, var_name = expr];
  此语句随定义var_name的个数被拆分成若干赋值指令。若var_name为存储过程的局部变量,则指令对应sp_instr_set子类
  若var_name为系统或用户级变量,则指令对应sp_instr_stmt子类
5、OPEN <游标名称>;
  打开静态游标指令,对应sp_instr_copen子类,负责执行<SELECT 语句>
6、DECLARE <游标名称> REF CURSOR;
  定义动态游标指令,对应sp_instr_cpush子类,负责记录cursor信息
7、OPEN <游标名称> FOR <SELECT 语句>;
  打开动态游标,此语句会被拆分为2部分:
  1)定义动态游标指令,对应sp_instr_cpush子类,负责记录cursor信息
  2)打开动态游标指令,对应sp_instr_copen子类,负责执行<SELECT 语句>
8、FETCH <游标名称> INTO <局部变量>;
  获取结果指令,对应sp_instr_cfetch子类,负责从游标中获取数据
9、CLOSE <游标名称>;
  关闭游标指令,对应sp_instr_cclose子类
10、IF <判断条件> THEN <执行体> END IF;
  此语句会被拆分为3部分:
  1)条件判断指令,对应 sp_instr_jump_if_not子类,指定跳转位置
  2)<执行体> 代表指令集,包是用户自定义的语句部分
  3)分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
11、IF <判断条件> THEN <执行体1> ELSE <执行体2> END IF;
  此语句会被拆分为4部分:
  1)条件判断指令,对应 sp_instr_jump_if_not子类,指定跳转位置
  2)<执行体1> 代表指令集,是用户自定义的语句部分
  3)分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
  4)<执行体2> 代表指令集,是用户自定义的语句部分
12、ITERATE<标签名>;
  分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
13、LEAVE <标签名>;
  分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
  如果在跳出当前的BEGIN...END语句块中存在handler,则会在sp_instr_jump子类之前增加删除handler记录的指令,对应sp_instr_hpop子类
  如果在跳出当前的BEGIN...END语句块中存在cursor,则会在sp_instr_jump子类之前增加删除cursor记录的指令,对应sp_instr_cpop子类
14、LOOP <执行体> END LOOP;
  此语句会被拆分为2部分:
  1)<执行体>代表指令集,是用户自定义的语句部分
  2)分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
15、CASE WHEN <条件1> THEN <执行语句1> ELSE <执行语句X> END CASE;
  CASE结构体中可有若干WHEN...THEN...复合语句,此处只对单一情况做说明,此时语句会被拆分为4部分:
  1)条件判断指令,对应 sp_instr_jump_if_not子类,指定跳转位置
  2)<执行语句1>代表指令集,是用户自定义的语句部分
  3)分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
  4)<执行语句X>代表指令集,是用户自定义的语句部分
  对于语句中不存在ELSE <执行语句X>,则第4)部分变为错误信息记录指令,对应    sp_instr_error子类
16、CASE <判定条件> WHEN <值1> THEN <执行语句1> ELSE <执行语句X> END CASE ;
  CASE结构体中可有若干WHEN...THEN...复合语句,此处只对单一情况做说明,此时语句会被拆分为5部分:
  1)表达式计算指令,对应sp_instr_set_case_expr子类,计算<判定条件>
  2)<值1>条件判断指令,对应 sp_instr_jump_if_not子类,指定跳转位置
  3)<执行语句1>代表指令集,是用户自定义的语句部分
  4)分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
  5)<执行语句 X>代表指令集,是用户自定义的语句部分
  对于语句中不存在ELSE <执行语句X>,则第5)部分变为错误信息记录指令,对应sp_instr_error子类
17、REPEAT <执行体> UNTIL<退出条件> END REPEAT;
  此循环结构被拆分为2部分:
  1)<执行体>代表指令集,是用户自定义的语句部分
  2)条件判断指令,对应 sp_instr_jump_if_not子类,指定跳转位置
18、WHILE <执行条件> DO <执行体> END WHILE;
  此循环结构被拆分为3部分:
  1)条件判断指令,对应 sp_instr_jump_if_not子类,指定跳转位置
  2)<执行体>代表指令集,是用户自定义的语句部分
  3)分支跳转指令,对应 sp_instr_jump子类,指定跳转位置
19、[begin_label:] BEGIN [statement_list] END [end_label]
  [statement_list]代表指令集,是用户自定义的语句部分
  如果在当前BEGIN...END语句块中存在handler,则会在语句末尾增加删除handler记录的指令,对应sp_instr_hpop子类
  如果在当前BEGIN...END语句块中存在cursor,则会在语句末尾增加删除cursor记录的指令,对应sp_instr_cpop子类
六、实例

存储过程语句集

指令集

create procedure proc_scursor()

begin

declare done, tmp int default(0);

sp_instr_set

sp_instr_set

declare cur cursor for select * from test.t;

sp_instr_cpush

declare continue handler for sqlstate '02000' set done = 1;

sp_instr_hpush_jump

sp_instr_set

sp_instr_hreturn

open cur;

sp_instr_copen

repeat

fetch cur into tmp;

sp_instr_cfetch

if not done then

sp_instr_jump_if_not

select tmp;

sp_instr_stmt

end if;

until done end repeat;

sp_instr_jump_if_not

close cur;

sp_instr_cclose

sp_instr_hpop

end

sp_instr_cpop

mysql 存储过程的实现原理的更多相关文章

  1. 《MySQL 存储过程编程》-读书笔记

    本书结构: 第一部分:存储编程基础 第1章:存储过程程序基础 第2章:MySQL存储编程指南 第3章:语言基础 第4章:语句块 第5章:在存储程序中使用SQL 第一章:MySQL存储程序介绍 存储程序 ...

  2. mysql存储过程讲解

    1.数据库存储过程:简单滴说,存储过程就是存储在数据库中的一个程序. 2..数据库存储过程作用: 第一:存储过程因为SQL语句已经预编绎过了,因此运行的速度比较快. 第二:存储过程可以接受参数.输出参 ...

  3. Mysql存储过程知识,案例--mysql存储过程基本函数

    Mysql存储过程知识,案例: create procedure delete_setting(in p_settingid integer) begin delete from setting wh ...

  4. MySQL 存储过程循环

    MySQL  存储过程循环 MySQL循环语句(包括WHILE,REPEAT和LOOP)来根据条件反复运行代码块. MySQL提供循环语句,允许您根据条件重复执行一个SQL代码块. MySQL中有三个 ...

  5. MySQL存储过程和自定义函数、Navicat for mysql、创建存储过程和函数、调用存储过程和函数的区别

    1 MySQL存储过程和函数 过程和函数,它们被编译后保存在数据库中,称为持久性存储模块(Persistent Stored Module,PSM),可以反复调用,运行速度快. 1.1 存储过程 存储 ...

  6. MySQL存储过程(转)

    一.MySQL 创建存储过程 "pr_add" 是个简单的 MySQL 存储过程,这个存储过程有两个 int 类型的输入参数 "a"."b" ...

  7. 十种MYSQL显错注入原理讲解(二)

    上一篇讲过,三种MYSQL显错注入原理.下面我继续讲解. 1.geometrycollection() and geometrycollection((select * from(select * f ...

  8. MySql存储过程

    MySQL 存储过程 ```sql CREATE PROCEDURE myprocedure (IN para01 INTEGER) BEGIN DECLARE var01 CHAR(10); IF ...

  9. mysql存储过程和存储函数

    mysql存储过程和存储函数 存数函数代码示例: DROP PROCEDURE IF EXISTS calc_ci_day_suc_rate; delimiter // CREATE FUNCTION ...

随机推荐

  1. winform程序读取和改写配置文件App.config元素的值

    winform程序读取和改写配置文件App.config元素的值 2016-05-16 17:49 by newbirth, 2412 阅读, 0 评论, 收藏, 编辑 1 2 3 4 5 6 7 & ...

  2. vgcreate语法

    vgcreate 用于创建LVM卷组 补充说明 vgcreate命令 用于创建LVM卷组.卷组(Volume Group)将多个物理卷组织成一个整体,屏蔽了底层物理卷细节.在卷组上创建逻辑卷时不用考虑 ...

  3. 转载 * jQuery实现动态分割div—通过拖动分隔栏实现上下、左右动态改变左右、上下两个相邻div的大小

    由jQuery实现上下.左右动态改变左右.上下两个div的大小,需要自己引入jquery1.8.0.min.js包 可用于页面布局. //============================ind ...

  4. Charles抓包遇到的问题

    1.手机设置了代理但是连不上网,无法下载HTTPS证书,关闭电脑防火墙! 2.content乱码解决方案参考https://www.cnblogs.com/puresoul/p/7365761.htm ...

  5. Prime31

    https://prime31.com/plugins

  6. 【oracle入门】SQL的命令动词

      SQL的功能 命令动词 数据定义 CREATE,DROP,ALTER 数据操纵 SELECT,INSERT,UPDATE,DELETE 数据控制 CRANT,REVOKE

  7. python学习之初识字符串

    刚接触一门语言时,字符串是很容易遇到的, 例如要从读入或者写出, 字符串与数字间的转换等. 由于字符串, 列表和元组等类型具有一定的共性(由对象组成的序列,如字符串是字符序列), 在Python中统称 ...

  8. windows下python环境+selenium环境搭建

    一.安装Python 1. 下载python包,最新版本的上一个版本:https://www.python.org/downloads/windows/ 2. 安装 可选择默认安装或自定义安装,自定义 ...

  9. ubuntu下编译小知识点

    #改变编译器选项 SET(CMAKE_C_COMPILER"g++") #出现如下错误:添加C++11特性 #error: #error This file requires co ...

  10. Dart 创建Map

    Map的常用操作 1. [] , length   获取值和长度 2. isEmpty (),isNoEmpty () 是否为空 3.Keys ,values  获取所有的键 和值 4. contai ...