博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用 druid 解析器解析SQL
阅读量:6154 次
发布时间:2019-06-21

本文共 6631 字,大约阅读时间需要 22 分钟。

最近参与一个开源项目,一个功能的实现,用到了 druid 解析器来解析SQL,记录下如果使用 druid 来解析SQL,实现对SQL的拦截改写。

1. 对 insert 语句进行解析:

private static String convertInsertSQL(String sql){		try{			MySqlStatementParser parser = new MySqlStatementParser(sql);	 			SQLStatement statement = parser.parseStatement();			MySqlInsertStatement insert = (MySqlInsertStatement)statement; 	        String tableName = StringUtil.removeBackquote(insert.getTableName().getSimpleName());	        if(!isGlobalTable(tableName))				return sql;	        if(!isInnerColExist(tableName))	        	return sql;	        		        List
columns = insert.getColumns(); if(columns == null || columns.size() <= 0) return sql; if(insert.getQuery() != null) // insert into tab select return sql; StringBuilder sb = new StringBuilder(200) // 指定初始容量可以提高性能 .append("insert into ") .append(tableName).append("("); int idx = -1; for(int i = 0; i < columns.size(); i++) { if(i < columns.size() - 1) sb.append(columns.get(i).toString()).append(","); else sb.append(columns.get(i).toString()); String column = StringUtil.removeBackquote(insert.getColumns().get(i).toString()); if(column.equalsIgnoreCase(GLOBAL_TABLE_MYCAT_COLUMN)) idx = i; } if(idx <= -1) sb.append(",").append(GLOBAL_TABLE_MYCAT_COLUMN); sb.append(")"); sb.append(" values"); List
vcl = insert.getValuesList(); if(vcl != null && vcl.size() > 1){ // 批量insert for(int j=0; j
valuse = insert.getValues().getValues(); appendValues(valuse, sb, idx); } List
dku = insert.getDuplicateKeyUpdate(); if(dku != null && dku.size() > 0){ sb.append(" on duplicate key update "); for(int i=0; i

三行代码就可以解析一条insert语句:

MySqlStatementParser parser = new MySqlStatementParser(sql);

SQLStatement statement = parser.parseStatement();
MySqlInsertStatement insert = (MySqlInsertStatement)statement;

然后使用解析得到的 insert ,就可以获得原始insert语句的各个部分:

List<SQLExpr> columns = insert.getColumns();  // 获得所有列名

insert.getQuery(); // 如果是 insert into select 语句,则可以获取 select查询

如果是批量插入的insert:insert into tab(id,name) values(1,'a'),(2,'b'),(3,'c');

则可以使用:

List<ValuesClause> vcl = insert.getValuesList();

获得素有的 values 子句部分。

非批量插入,则可以使用:

List<SQLExpr> valuse = insert.getValues().getValues();

获得 values 子句。

on duplicate 部分可以使用下面的语句获取:

List<SQLExpr> dku = insert.getDuplicateKeyUpdate();

获得了这些,就而已重组得到原始SQL语句,并且对其进行各种改写。

mysql 中的insert语法如下:

mysql> ? insertName: 'INSERT'Description:Syntax:INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]    [INTO] tbl_name    [PARTITION (partition_name,...)]    [(col_name,...)]    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...    [ ON DUPLICATE KEY UPDATE      col_name=expr        [, col_name=expr] ... ]Or:INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]    [INTO] tbl_name    [PARTITION (partition_name,...)]    SET col_name={expr | DEFAULT}, ...    [ ON DUPLICATE KEY UPDATE      col_name=expr        [, col_name=expr] ... ]Or:INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]    [INTO] tbl_name    [PARTITION (partition_name,...)]    [(col_name,...)]    SELECT ...    [ ON DUPLICATE KEY UPDATE      col_name=expr        [, col_name=expr] ... ]

2. 解析 update 语句:

public static String convertUpdateSQL(String sql){		try{			MySqlStatementParser parser = new MySqlStatementParser(sql);	 			SQLStatement stmt = parser.parseStatement();			MySqlUpdateStatement update = (MySqlUpdateStatement)stmt;			SQLTableSource ts = update.getTableSource();			if(ts != null && ts.toString().contains(",")){				System.out.println(ts.toString());				LOGGER.warn("Do not support Multiple-table udpate syntax...");				return sql;			}						String tableName = StringUtil.removeBackquote(update.getTableName().getSimpleName());	        if(!isGlobalTable(tableName))				return sql;	        if(!isInnerColExist(tableName))	        	return sql;		// 没有内部列	        			StringBuilder sb = new StringBuilder(150);						SQLExpr se = update.getWhere();			// where中有子查询: update company set name='com' where id in (select id from xxx where ...)			if(se instanceof SQLInSubQueryExpr){				// return sql;				int idx = sql.toUpperCase().indexOf(" SET ") + 5;				sb.append(sql.substring(0, idx)).append(GLOBAL_TABLE_MYCAT_COLUMN)				.append("=").append(operationTimestamp)				.append(",").append(sql.substring(idx));				return sb.toString();			}			String where = null;			if(update.getWhere() != null)				where = update.getWhere().toString();						SQLOrderBy orderBy = update.getOrderBy();			Limit limit = update.getLimit();						sb.append("update ").append(tableName).append(" set ");			List
items = update.getItems(); boolean flag = false; for(int i=0; i
0){ sb.append(" order by "); for(int i=0; i

同样三行,解析update语句:

MySqlStatementParser parser = new MySqlStatementParser(sql);

SQLStatement stmt = parser.parseStatement();
MySqlUpdateStatement update = (MySqlUpdateStatement)stmt;

如果是 多表 udpate 语句,可以使用下面的语句进行判断:

SQLTableSource ts = update.getTableSource();

if(ts != null && ts.toString().contains(",")){
   System.out.println(ts.toString());
   LOGGER.warn("Do not support Multiple-table udpate syntax...");
   return sql;
}

如果是单表update语句:

获得 update 语句的 where 部分:

SQLExpr se = update.getWhere();

// where中有子查询: update company set name='com' where id in (select id from xxx where ...)
if(se instanceof SQLInSubQueryExpr){
// return sql;
int idx = sql.toUpperCase().indexOf(" SET ") + 5;
sb.append(sql.substring(0, idx)).append(GLOBAL_TABLE_MYCAT_COLUMN)
.append("=").append(operationTimestamp)
.append(",").append(sql.substring(idx));
return sb.toString();
}
String where = null;
if(update.getWhere() != null)
where = update.getWhere().toString();

如果where 部分由 select 语句,由:se instanceof SQLInSubQueryExpr 来判断。

order by 和 limit 部分分别由:

SQLOrderBy orderBy = update.getOrderBy();

Limit limit = update.getLimit();

获得。

update 对应的 列和值,有下面的代码获得:

boolean flag = false;

for(int i=0; i<items.size(); i++){
  SQLUpdateSetItem item = items.get(i);
  String col = item.getColumn().toString();
  String val = item.getValue().toString();

解析得到了这些部分,就可以重组出原始的 update 语句,并且按照自己的需求进行SQL改写。

3. 解析 alter 语句:

String sql = "alter table t add colomn name varchar(30)";MySqlStatementParser parser = new MySqlStatementParser(sql);	 SQLStatement statement = parser.parseStatement();MySqlAlterTableStatement alter = (MySqlAlterTableStatement)statement; SQLExprTableSource source = alter.getTableSource();String tableName = source.toString();

解析器:

com.alibaba
druid
1.0.14

 

转载地址:http://tmffa.baihongyu.com/

你可能感兴趣的文章
安装appium桌面版和命令行版
查看>>
15款经典图表软件推荐 创建最漂亮的图表
查看>>
Python进阶量化交易场外篇4——寻找最优化策略参数
查看>>
5Linux流程控制语句-if、for、while、case语句、计划任务
查看>>
有哪些质量上乘的程序员必关注的网站或论坛
查看>>
正则表达式
查看>>
我理解的几种字符编码方式
查看>>
BZOJ-4706 B君的多边形 OEIS
查看>>
报错之解决方案1--找不到文件或文件夹
查看>>
spring容器加载完毕做一件事情(利用ContextRefreshedEvent事件)转
查看>>
OFFICE 2007 序列号
查看>>
07-JAVA继承与接口
查看>>
ubuntu15.10下sublime text3 无法输入中文解决办法
查看>>
LR web_custom_request
查看>>
MySQL-DDL语言
查看>>
Java-笔记10-复习
查看>>
5月10团队博客
查看>>
意见汇总
查看>>
phpcmsv9 幻灯片管理模块_UTF8
查看>>
(转)mysql分表的3种方法
查看>>