sql语句解析实现

第一步:先对sql语句进行预处理;

对于用户,我们应该接受各种形式的查询语句书写,单行或者多行,语句中单个空格或者多个空格的间隔等等。但是我们要解析sql语句,就首先要让对它们做标准化,这样才能进行我们下一步处理。系统中的处理要求:

1)消除SQL语句前后的空白,将其中的连续空白字符(包括空格,TAB和回车换行)替换成单个空格;

2)将sql语句全变成小写形式(或大写形式);

3)在SQL语句的尾后加上结束符号“ENDOFSQL”(原因后面解释)

例如:用户输入:“select c1,c2,c3 from  t1,t2, t3 where condi1=5 and condi6=6 or condi7=7 order 

by g1,g2

通过预处理应该为:“select c1,c2,c3 from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 order by g1,g2”

第二步:将查询语句切分为语句块;

以查询语句为例(本文中主要是以查询语句作为例子讲解,其它删除,插入等语句原理于此类似,因为查询语句相对复杂,所以用来i讲解),正如上面我们标准化后的语句一样,我们要进行下一步的,对表中数据的处理,首先要知道是对那些表处理,要满足那些条件,输出那些属性,以什么顺序输出等。所以查询语句就可以分割为以下几个块:

1)select c1,c2,c3 from:属性输出块;块头(start)select,块尾(end)from,这个块我们关心的信息(body):c1,c2,c3;以下块类似分析

2)from....where; 涉及数据表块。

3)where.....order by; 查询条件块。

4)order by.....ENDOFSQL; 属性输出顺序。这里也就看出了我们为什么要在查询语句末尾加上结束符,是为了最后一个块的限定需要。

知道了如何分块,接下来要做的就是在我们已经标准化的sql语句上进行块的切割,这里我们用到了正则表达式,以第二个块from....where的查询为例,我们做个分析

"(from)(.+)( where | on | having | group by | order by | ENDOFSQL)“

以上就是第二个块的正则匹配式(其它块的匹配式下面也会给出),可以看出,在一个sql查询语句中,from块中跟from搭配出现的不只是where,还可以是on,having,group by等,那么通过这个正则式我们可以得到如下的块:

      from .... where

  from .... on

  from .... having

  from .... group by

  from .... order by

  from .... ENDOFSQL

这里我们要注意一点,就是在通过正则式对sql语句进行匹配时,我们不能对整个sql语句进行一次匹配操作,因为正则匹配是贪心匹配,它总是尽可能的向后查找,匹配到最大的语句段。就拿上述语句为例,如果通过对整个sql语句进行一次匹配,得到的就不是from....where这个语句段而是from .... where .... order by。显然这不是我们想要的。所以我们只能牺牲效率,通过对整个sql语句进行逐次递增的查询方式来查找相应的语句块。给出一个查询过程,加强理解,以上述sql语句为例,对第一个语句块的查找过程是

s
se
sel
.............
select c1,c2,c3 from

这样就找到第一个块,以此类推,找第二个块时候又从头逐次递增查找。

第三步:找到了各个块,我们还要把我们最关心的信息提取出来,就是夹在语句块头和尾之间的body部分,这个就好实现了,一般的sql语句中都会用逗号来做分割,我们提取出各个块的body信息。

步骤介绍完了,下面就上代码!

package com.hz.util.sql;

import java.util.List;

/**
 * 单句sql解析器制造工厂
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class SqlParserUtil {

	/**
	 * 方法的主要入口
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param sql
	 *            要解析的sql语句
	 * @return 返回解析结果
	 * @return_type String
	 *
	 */
	public String getParsedSql(String sql) {
		sql = sql.trim();
		sql = sql.toLowerCase();
		sql = sql.replace("\\s{1,}", " ");
		sql = "" + sql + " ENDOFSQL";
		return SingleSqlParserFactory.generateParser(sql).getParsedSql();
	}

	/**
	 * SQL语句解析的接口
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param sql
	 *            要解析的sql语句
	 * @return 返回解析结果
	 * @return_type List<SqlSegment>
	 *
	 */
	public List<SqlSegment> getParsedSqlList(String sql) {
		sql = sql.trim();
		sql = sql.trim();
		sql = sql.toLowerCase();
		sql = sql.replace("\\s{1,}", " ");
		sql = "" + sql + " ENDOFSQL";
		return SingleSqlParserFactory.generateParser(sql).returnSqlSegments();
	}

}
<pre name="code" class="java">package com.hz.util.sql;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * sql语句片段
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class SqlSegment {
	private static final String Crlf = "@";
	private static final String FourSpace = "  ";
	// sql语句片段开头
	private String start;
	// sql语句片段中间部分
	private String body;
	// sql语句片段结束部分
	private String end;
	// 表示片段的正则表达式
	private String segmentRegExp;
	// 分割后的body小片段
	private List<String> bodyPieces;
	// 用于分割中间部分的正则表达式
	private String bodySplitPattern;

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 */
	public SqlSegment(String segmentRegExp, String bodySplitPattern) {
		start = "";
		body = "";
		end = "";
		this.segmentRegExp = segmentRegExp;
		this.bodySplitPattern = bodySplitPattern;
		this.bodyPieces = new ArrayList<>();
	}

	/**
	 * 从sql中查找符合segmentRegExp的部分,并赋值到start,body,end三个属性中
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param sql
	 * @return_type void
	 *
	 */
	public void parse(String sql) {
		Pattern pattern = Pattern.compile(segmentRegExp, Pattern.CASE_INSENSITIVE);
		for (int i = 0; i <= sql.length(); i++) {
			String shortSql = sql.substring(0, i);
			// 测试输出的子句是否正确 System.out.println(shortSql);
			Matcher matcher = pattern.matcher(shortSql);
			while (matcher.find()) {
				start = matcher.group(1);
				body = matcher.group(2);
				end = matcher.group(3);
				return;
			}
		}
	}

	/**
	 * 解析body片段
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return_type void
	 *
	 */
	@SuppressWarnings("unused")
	private void parseBody() {

		List<String> ls = new ArrayList<String>();
		Pattern p = Pattern.compile(bodySplitPattern, Pattern.CASE_INSENSITIVE);
		// 先清除掉前后空格
		body = body.trim();
		Matcher m = p.matcher(body);
		StringBuffer sb = new StringBuffer();
		boolean result = m.find();
		while (result) {
			m.appendReplacement(sb, m.group(0) + Crlf);
			result = m.find();
		}
		m.appendTail(sb);
		// 再按空格断行
		String[] arr = sb.toString().split(" ");
		int arrLength = arr.length;
		for (int i = 0; i < arrLength; i++) {
			String temp = FourSpace + arr[i];
			if (i != arrLength - 1) {
				// temp=temp+Crlf; }
				ls.add(temp);
			}
			bodyPieces = ls;
		}
	}

	/**
	 * 取得解析好的sql片段
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return
	 * @return_type String
	 *
	 */
	public String getParsedSqlSegment() {
		StringBuffer sb = new StringBuffer();
		sb.append(start + Crlf);
		for (String piece : bodyPieces) {
			sb.append(piece + Crlf);
		}
		return sb.toString();
	}

	/**
	 * @return the start
	 */
	public String getStart() {
		return start;
	}

	/**
	 * @param start
	 *            the start to set
	 */
	public void setStart(String start) {
		this.start = start;
	}

	/**
	 * @return the body
	 */
	public String getBody() {
		return body;
	}

	/**
	 * @param body
	 *            the body to set
	 */
	public void setBody(String body) {
		this.body = body;
	}

	/**
	 * @return the end
	 */
	public String getEnd() {
		return end;
	}

	/**
	 * @param end
	 *            the end to set
	 */
	public void setEnd(String end) {
		this.end = end;
	}

	/**
	 * @return the segmentRegExp
	 */
	public String getSegmentRegExp() {
		return segmentRegExp;
	}

	/**
	 * @param segmentRegExp
	 *            the segmentRegExp to set
	 */
	public void setSegmentRegExp(String segmentRegExp) {
		this.segmentRegExp = segmentRegExp;
	}

	/**
	 * @return the bodyPieces
	 */
	public List<String> getBodyPieces() {
		return bodyPieces;
	}

	/**
	 * @param bodyPieces
	 *            the bodyPieces to set
	 */
	public void setBodyPieces(List<String> bodyPieces) {
		this.bodyPieces = bodyPieces;
	}

	/**
	 * @return the bodySplitPattern
	 */
	public String getBodySplitPattern() {
		return bodySplitPattern;
	}

	/**
	 * @param bodySplitPattern
	 *            the bodySplitPattern to set
	 */
	public void setBodySplitPattern(String bodySplitPattern) {
		this.bodySplitPattern = bodySplitPattern;
	}

}
package com.hz.util.sql;

import java.util.ArrayList;
import java.util.List;

/**
 * 单句sql解析器,单句即非嵌套的意思
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public abstract class BaseSingleSqlParser {

	// 原始sql语句
	protected String originalSql;
	// sql语句片段
	protected List<SqlSegment> segments;

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 */
	public BaseSingleSqlParser(String originalSql) {
		this.originalSql = originalSql;
		segments = new ArrayList<>();
		initializeSegments();
		splitSqlToSegment();
	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return_type void
	 *
	 */
	protected void splitSqlToSegment() {
		for (SqlSegment sqlSegment : segments) {
			sqlSegment.parse(originalSql);
		}
	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return_type void
	 *
	 */
	protected abstract void initializeSegments();

	/**
	 * 得到解析完毕的Sql语句
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return
	 * @return_type String
	 *
	 */
	public String getParsedSql() {
		StringBuffer stringBuffer = new StringBuffer();
		for (SqlSegment sqlSegment : segments) {
			stringBuffer.append(sqlSegment.getParsedSqlSegment());
		}
		String result = stringBuffer.toString().replaceAll("@+", "\n");
		return result;
	}

	/**
	 * 得到解析的sql片段
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return
	 * @return_type List<SqlSegment>
	 *
	 */
	public List<SqlSegment> returnSqlSegments() {
		int segmentLength = this.segments.size();
		if (segmentLength != 0) {
			List<SqlSegment> result = this.segments;
			return result;
		}
		return null;
	}
}

package com.hz.util.sql;

/**
 * 单句删除语句解析
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class DeleteSqlParser extends BaseSingleSqlParser {

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param originalSql
	 */
	public DeleteSqlParser(String originalSql) {

		super(originalSql);

	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @see com.hz.util.sql.BaseSingleSqlParser#initializeSegments()
	 */
	@Override
	protected void initializeSegments() {
		segments.add(new SqlSegment("(delete from)(.+)(where | ENDOFSQL)", "[,]"));
		segments.add(new SqlSegment("(where)(.+)( ENDOFSQL)", "(and|or)"));
	}

}

package com.hz.util.sql;

/**
 * 单句查询插入语句解析器
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class InsertSelectSqlParser extends BaseSingleSqlParser {

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param originalSql
	 */
	public InsertSelectSqlParser(String originalSql) {

		super(originalSql);

	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @see com.hz.util.sql.BaseSingleSqlParser#initializeSegments()
	 */
	@Override
	protected void initializeSegments() {
		segments.add(new SqlSegment("(insert into)(.+)( select )", "[,]"));
		segments.add(new SqlSegment("(select)(.+)(from)", "[,]"));
		segments.add(new SqlSegment("(from)(.+)( where | on | having | groups+by | orders+by | ENDOFSQL)",
				"(,|s+lefts+joins+|s+rights+joins+|s+inners+joins+)"));
		segments.add(new SqlSegment("(where|on|having)(.+)( groups+by | orders+by | ENDOFSQL)", "(and|or)"));
		segments.add(new SqlSegment("(groups+by)(.+)( orders+by| ENDOFSQL)", "[,]"));
		segments.add(new SqlSegment("(orders+by)(.+)( ENDOFSQL)", "[,]"));
	}

}
package com.hz.util.sql;

/**
 * 单句插入语句解析
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class InsertSqlParser extends BaseSingleSqlParser {

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param originalSql
	 */
	public InsertSqlParser(String originalSql) {

		super(originalSql);

	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @see com.hz.util.sql.BaseSingleSqlParser#initializeSegments()
	 */
	@Override
	protected void initializeSegments() {
		segments.add(new SqlSegment("(insert into)(.+)([(])", "[,]"));
		segments.add(new SqlSegment("([(])(.+)( [)] values )", "[,]"));
		segments.add(new SqlSegment("([)] values [(])(.+)( [)])", "[,]"));
	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @return
	 * @see com.hz.util.sql.BaseSingleSqlParser#getParsedSql()
	 */
	@Override
	public String getParsedSql() {

		String result = super.getParsedSql();
		result += ")";

		return result;
	}

}
package com.hz.util.sql;

/**
 * 单句查询语句解析器
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class SelectSqlParser extends BaseSingleSqlParser {

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param originalSql
	 */
	public SelectSqlParser(String originalSql) {

		super(originalSql);

	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @see com.hz.util.sql.BaseSingleSqlParser#initializeSegments()
	 */
	@Override
	protected void initializeSegments() {
		segments.add(new SqlSegment("(select)(.+)(from)", "[,]"));
		segments.add(new SqlSegment("(from)(.+)( where | on | having | group by | order by | ENDOFSQL)",
				"(,| left join | right join | inner join )"));
		segments.add(new SqlSegment("(where|on|having)(.+)( group by | order by | ENDOFSQL)", "(and|or)"));
		segments.add(new SqlSegment("(group by)(.+)( order by| ENDOFSQL)", "[,]"));
		segments.add(new SqlSegment("(order by)(.+)( ENDOFSQL)", "[,]"));
	}

}
package com.hz.util.sql;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Blossom
 * @time 2016年9月9日
 */
public class SingleSqlParserFactory {

	public static BaseSingleSqlParser generateParser(String sql) {
		if (contains(sql, "(insert into)(.+)(select)(.+)(from)(.+)")) {
			return new InsertSelectSqlParser(sql);
		} else if (contains(sql, "(select)(.+)(from)(.+)")) {
			return new SelectSqlParser(sql);
		} else if (contains(sql, "(delete from)(.+)")) {
			return new DeleteSqlParser(sql);
		} else if (contains(sql, "(update)(.+)(set)(.+)")) {
			return new UpdateSqlParser(sql);
		} else if (contains(sql, "(insert into)(.+)(values)(.+)")) {
			return new InsertSqlParser(sql);
		}

		return new InsertSqlParser(sql);
	}

	/**
	 * 看word是否在lineText中存在,支持正则表达式
	 * 
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param sql
	 * @param regExp
	 * @return
	 * @return_type boolean
	 *
	 */
	private static boolean contains(String sql, String regExp) {
		Pattern pattern = Pattern.compile(regExp, Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(sql);
		return matcher.find();
	}

}

package com.hz.util.sql;

/**
 * 单句更新sql语句
 * 
 * @author Blossom
 * @time 2016年9月9日
 */
public class UpdateSqlParser extends BaseSingleSqlParser {

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @param originalSql
	 */
	public UpdateSqlParser(String originalSql) {

		super(originalSql);

	}

	/**
	 * @author Blossom
	 * @time 2016年9月9日
	 * @see com.hz.util.sql.BaseSingleSqlParser#initializeSegments()
	 */
	@Override
	protected void initializeSegments() {
		segments.add(new SqlSegment("(update)(.+)(set)", "[,]"));
		segments.add(new SqlSegment("(set)(.+)( where | ENDOFSQL)", "[,]"));
		segments.add(new SqlSegment("(where)(.+)( ENDOFSQL)", "(and|or)"));
	}

}





 


  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值