前端传过来一个 string 类型的切分 sql 语句。里面可能包含多条 sql,后端要根据 sql 语句的切分不同类型采取不同的方案,所以要先将 sql 语句拆分为单条语句。
如果对过程不感兴趣可以跳过这一节。切分
首先想到的切分就是可以根据分号来切割 sql 语句,一个分号就是一条语句。但是切分因为有注释的存在,注释里面可以存在分号,对切割有影响。第一版的切分思路就来了,先把注释去掉,然后使用分号切割。
去除注释的切分代码很简单,mysql 的注释一共有三种,# 和 -- 代表单行注释,/**/ 代表多行注释
。写了一个状态机,从前到后扫 sql 语句,遇到单行注释就跳过,直到遇到 \n 。切分遇到多行注释就找 */。切分
建表语句的切分 COMMENT 里面其实也是注释,里面可以写任何内容,如果在这里面写了 #, -- 或 /*,那么后面的语句也会被当成注释被去掉。
create table if not exists `student` (`name` INT(9) NOT NULL COMMENT '--名字',切分`age` INT(9) NOT NULL COMMENT '年龄');
name 字段的 COMMENT 里的这种语句就会导致 -- 后面的所有东西都会被当成注释去掉。
既然在 COMMENT 里面出问题,那么能不能不处理 COMMENT 里面的切分语句,不管里面有啥,遇到 COMMENT 就无脑向后找,直到 COMMENT 结束。那第二版的切分思路就有了,处理注释的时候同时处理 COMMENT。
mysql 里的切分 COMMENT 一共有三种写法,可以使用单引号,双引号和反引号。所以在遍历的切分时候遇到这三个符号就标记开始 COMMENT,一直到结束标记结束 COMMENT,在处理 COMMENT 过程中不进行注释的处理。
mysql 里对 COMMENT 的写法要求有点低,使用单引号的时候里面还可以加双引号,但是这个双引号是没有用处的。类似于
create table if not exists `student` (`name` INT(9) NOT NULL COMMENT '名字"student name',`age` INT(9) NOT NULL COMMENT '年龄');
Name 字段的 COMMENT 里这种单引号包裹双引号的行为就会导致 识别到的 COMMENT 提前结束 。
可以优化下对 COMMENT 的识别,区分单引号开始,还是双引号开始,还是反引号开始,向下遍历的时候只能找对应开始的结束符。但是这种实在是太复杂了,还要处理注释的情况