这应该是最后一次用字符串去分析解读SQL了,效果比上次要好些,但在函数和别名方面有点差强人意,再想前进一定要用到词法分析,语法树和表达式解析等,字符串解读差不多已经到极限了。
package com.sitinspring.common.sqlformatter2;

 /** *//**
* SQL整形器类
* @author 何杨(heyang78@gmail.com)
*
* @since 2009-2-5 上午11:45:38
* @version 1.00
*/
 class Fomatter {
// 需要整形的SQL语句
private String sql;
// 整形完毕的SQL语句
private String formatedSql;
// 空格的深度,用于嵌套Sql语句
private int spaceDepth;
// 在sql逐字读取时当前字符所在的位置
private int currCharPos;
 /** *//**
* 构造函数,入口点
* 2009年2月5日11:52:42
* @param sql
*/
 public Fomatter(String sql) {
this.sql=sql;
format();
}
 /** *//**
* 取得整形完毕的Sql语句,出口点
* 2009年2月5日11:52:45
* @return
*/
 public String getFomattedSql() {
return formatedSql;
}
 /** *//**
* 对sql进行整形,整形的结果放在FormatedSql中
* 2009年2月5日12:16:08
*/
 private void format() {
formatedSql="";
Token token=getToken();
 while(token!=null) {
formatedSql+=token;
token=getToken();
}
}
 /** *//**
* 取得下一个标识符
* 2009年2月5日12:22:41
* @return
*/
 private Token getToken() {
// 初始化
String tokenText="";
//tokenType=TokenType_None;
// 结束即终止
 if(currCharPos==sql.length()) {
return null;
}
// 跳过空白字符
 while(currCharPos<sql.length() && currCharIsWhiteSpace(currCharPos)) {
currCharPos++;
}
// 结束即终止
 if(currCharPos==sql.length()) {
return null;
}
// 不是空白字符的话就连续往下取
 while(currCharPos<sql.length() ) {
char currChar=sql.charAt(currCharPos);
 if(currChar=='(') {
 if(tokenText.trim().length()>0) {
break;
}
Token token=new Token(currChar,spaceDepth);
spaceDepth++;
currCharPos++;
return token;
}
 else if(currChar==')') {
 if(tokenText.trim().length()>0) {
break;
}
spaceDepth--;
Token token=new Token(currChar,spaceDepth);
currCharPos++;
return token;
}
 else if(currChar==',') {
tokenText+=currChar;
currCharPos++;
break;
}
 if(currCharIsWhiteSpace(currCharPos)==true) {
break;
}
tokenText+=currChar;
currCharPos++;
}
Token token=new Token(tokenText,spaceDepth);
return token;
}
 /** *//**
* 判断currentCharIndex在originalSql指向的字符是否空白字符
* @param currentCharIndex
* @return
*/
 private boolean currCharIsWhiteSpace(int currentCharIndex) {
return Character.isWhitespace(sql.charAt(currentCharIndex));
}
}
package com.sitinspring.common.sqlformatter2;

import java.util.HashSet;
import java.util.Set;

 /** *//**
* Token代表SQL语句中一个不可再分割的子单元
* @author 何杨(heyang78@gmail.com)
*
* @since 2009-2-5 上午11:46:35
* @version 1.00
*/
 class Token {
// Token的类型
private int type;
// 表示这个Token是关键字
public static final int Type_Keyword=0;
public static final int Type_LeftKeyword=2;
public static final int Type_RightKeyword=4;
// 表示这个Token是分隔符
public static final int Type_Seperate=6;
// 表示这个Token是表达式
public static final int Type_Expression=8;
// 表示这个Token是左括号
public static final int Type_LeftBraket=10;
// 表示这个Token是右括号
public static final int Type_RightBraket=12;
// Token的文本内容
private String text;
// 这个标记所处的深度
private int depth;
private static final Set<String> keywords;
private static final Set<String> leftKeywords;
private static final Set<String> rightKeywords;
 static {
keywords=new HashSet<String>();
keywords.add("select");
keywords.add("from");
keywords.add("where");
keywords.add("on");
keywords.add("having");
keywords.add("values");
keywords.add("update");
keywords.add("set");
leftKeywords=new HashSet<String>();
leftKeywords.add("order");
leftKeywords.add("group");
leftKeywords.add("delete");
leftKeywords.add("insert");
leftKeywords.add("left");
leftKeywords.add("right");
leftKeywords.add("inner");
rightKeywords=new HashSet<String>();
rightKeywords.add("by");
rightKeywords.add("into");
rightKeywords.add("join");
}
 private static boolean isKeyWords(String str) {
return keywords.contains(str);
}
 private static boolean isLeftKeyWords(String str) {
return leftKeywords.contains(str);
}
 private static boolean isRightKeyWords(String str) {
return rightKeywords.contains(str);
}
 public Token(String text,int depth) {
 if("(".equals(text)) {
this.type=Type_LeftBraket;
}
 else if(")".equals(text)) {
this.type=Type_RightBraket;
}
 else if(isKeyWords(text.toLowerCase())) {
this.type=Type_Keyword;
}
 else if(isLeftKeyWords(text.toLowerCase())) {
this.type=Type_LeftKeyword;
}
 else if(isRightKeyWords(text.toLowerCase())) {
this.type=Type_RightKeyword;
}
 else {
this.type=Type_Expression;
}
this.text=text;
this.depth=depth;
}
 public Token(char c,int depth) {
this(String.valueOf(c),depth);
}
 public String toString() {
StringBuffer sb=new StringBuffer();
sb.append(getDepthSpace());
sb.append(getPreTokenSpace());
sb.append(text);
sb.append(getAfterTokenWhiteSpace());
return sb.toString();
}
 /** *//**
* 取得代表深度的前置空白
* @return
*/
 private String getDepthSpace() {
StringBuffer sb=new StringBuffer("");
 for(int i=0;i<depth;i++) {
sb.append(Consts.FourSpace);
}
return sb.toString();
}
 /** *//**
* 取得标识符前的空白
* @return
*/
 private String getPreTokenSpace() {
 if(type==Type_Expression) {
return Consts.FourSpace;
}
 else if(type==Type_LeftBraket) {
return Consts.FourSpace;
}
 else if(type==Type_RightBraket) {
return Consts.FourSpace;
}
 else if(type==Type_RightKeyword) {
return Consts.Space;
}
return "";
}
 /** *//**
* 取得标识符后的白字符
* @return
*/
 private String getAfterTokenWhiteSpace() {
 if(type==Type_LeftKeyword) {
return "";
}
return Consts.NewLine;
}
 public String getText() {
return text;
}

 public void setText(String text) {
this.text = text;
}

 public int getType() {
return type;
}

 public void setType(int type) {
this.type = type;
}

 public int getDepth() {
return depth;
}

 public void setDepth(int depth) {
this.depth = depth;
}
}
package com.sitinspring.common.sqlformatter2;

 /** *//**
* 本包诸类用到的一些常量放在此类中
* @author 何杨(heyang78@gmail.com)
*
* @since 2009-2-5 下午12:02:26
* @version 1.00
*/
 class Consts {
// 新行
public final static String NewLine="\n";
// 四个空格
public final static String FourSpace=" ";
// 空格
public final static String Space=" ";
// 逗号
public final static String Comma=",";
}
package com.sitinspring.common.sqlformatter2;

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

 /** *//**
* SQL语句整形工具类
* @author 何杨(heyang78@gmail.com)
*
* @since 2009-2-5 上午11:42:03
* @version 1.00
*/
 public class sqlformatter2Util {
 public static void main(String[] args) {
List<String> ls=new ArrayList<String>();
ls.add("select ( * ) from dual");
ls.add("SELECT * frOm dual");
ls.add("Select C1,c2 From tb");
ls.add("selecT c1,c2 from tb");
ls.add("select count(*) from t1");
ls.add("select c1,c2,c3 from t1 where condi1=1 ");
ls.add("Select c1,c2,c3 From t1 Where condi1=1 ");
ls.add("select c1,c2,c3 from t1,t2 where ( condi3=3 or condi4=5 ) order by o1,o2");
ls.add("select f1,(select f2 from t01) from t02 where 1=1");
ls.add("select f1,( select a from b ) from ( select f1,f2 from ( select f1,f2,f3 from tb ) ),t4 where 1=1 ");
ls.add("select f1,( select * from tb2,( select * from ( select * from ( select * from tb5 ) ) ) ) from tabl1 where 1=1");
ls.add("");
ls.add("Select c1 1,c2,c3 from t1 3,t2 4 Where condi3=3 and condi4=5 Order by o1,o2");
ls.add("select c1,c2,c3 from t1,t2, t3 where condi1=5 and condi6=6 or condi7=7 group by g1,g2");
ls.add("Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group by g1,g2");
ls.add("Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and ( condi6=6 or condi7=7 ) Group by g1,g2,g3 order by g2,g3");
ls.add("select c1,c2,c3 from t1 left join t2 on condi3=3 or condi4=5 order by o1,o2");
ls.add("select c1,c2,c3 from t1 right join t2 on condi3=3 or condi4=5 order by o1,o2");
ls.add("select c1,c2,c3 from t1 inner join t2 on condi3=3 or condi4=5 order by o1,o2");
ls.add("select c1,c2,c3 from t1 left join t2 having condi3=3 or condi4=5 group by g1,g3,g5 order by o1,o2");
ls.add("delete from table");
ls.add("delete from table where 1=1");
ls.add("delete from table where c1=1 and c2=2 or c3=3");
ls.add("update checktable set ID='' where 1=1 ");
ls.add("update checktable set ID='', NAME='' where 1=1 and 2=2");
ls.add("update checktable set ID='', NAME='', count='', remark='' where 1=1 and 2=2 or 3=3 ");
ls.add(" insert into checktable ( ID ) values ( '1' ) ");
ls.add(" insert into checktable ( ID,r ) values ( '1','' ) ");
ls.add(" insert into checktable ( ID, NAME, count, remark ) values ( '1', '2', '3', '4' ) ");
ls.add("insert into checktable select c1,c2,c3 from t1 where condi1=1 ");
ls.add("insert into checktable Select c1,c2,c3 From t1 Where condi1=1 ");
ls.add("insert into checktable select c1,c2,c3 from t1,t2 where condi3=3 or condi4=5 order by o1,o2");
ls.add("insert into checktable Select c1 1,c2,c3 from t1 3,t2 4 Where condi3=3 and condi4=5 Order by o1,o2");
ls.add("insert into checktable select c1,c2,c3 from t1,t2, t3 where condi1=5 and condi6=6 or condi7=7 group by g1,g2");
ls.add("insert into checktable Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group by g1,g2");
ls.add("insert into checktable Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group by g1,g2,g3 order by g2,g3");
ls.add("insert into checktable select c1,c2,c3 from t1 left join t2 on condi3=3 or condi4=5 order by o1,o2");
ls.add("insert into checktable select c1,c2,c3 from t1 right join t2 on condi3=3 or condi4=5 order by o1,o2");
ls.add("insert into checktable select c1,c2,c3 from t1 inner join t2 on condi3=3 or condi4=5 order by o1,o2");
ls.add("insert into checktable select c1,c2,c3 from t1 left join t2 having condi3=3 or condi4=5 group by g1,g3,g5 order by o1,o2");
ls.add("select (select * from dual) from dual");
ls.add("select (*) from dual");
ls.add("select count(*) from dual");
ls.add("select id,name from (select id,name from (select id,name from customer) t1 ) t2");
 for(String sql:ls) {
System.out.println("原始的Sql为:\n"+(sql));
System.out.println("解析后的的Sql为:\n"+getFormatedSql(sql));
}
}
 /** *//**
* 取得整形完毕的Sql语句
* Entry Point:这个包的入口点
* @param sql
* @return
*/
 public static String getFormatedSql(String sql) {
// 去除前后空白
sql=sql.trim();
// 将Sql语句中原有的回车换行替换成空白
sql=sql.replaceAll("(\\n+|\\r+)", " ");
return (new Fomatter(sql).getFomattedSql());
}
}
整形完的效果请见:
http://www.blogjava.net/heyang/archive/2009/02/05/253411.html
|