当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
这应该是最后一次用字符串去分析解读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
posted on 2009-02-05 22:57 何杨 阅读(396) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: