package com.ycsoft.report.query.sql; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.ycsoft.commons.exception.ReportException; import com.ycsoft.report.bean.RepKeyCon; import com.ycsoft.report.commons.SystemConfig; import com.ycsoft.report.dto.RepKeyDto; /** * sql拆分组装工厂 */ public class AnalyseSqlFactory2 implements Serializable{ /** * */ private static final long serialVersionUID = -6513684046350324826L; private String sql_splits[] = null; private String sql_groups[] = null; //sql关键字拆分正则表达式 private final static String sql_regex="[\\s\\)]+(or|and|where|group|order|union|between|when|then)[\\s\\(]*((not\\s)?\\s*exists)?[\\s\\(]+"; //between and 语句组合匹配正则表达式 private final static String sql_regex_between=".*[bB][eE][tT][wW][eE][eE][nN][\\s\\(]+.*"; private final static String sql_regex_and=".*[aA][nN][dD][\\s\\(]+.*"; public AnalyseSqlFactory2(String sql) throws ReportException{ init(sql); } public AnalyseSqlFactory2(){} public void init(String sql) throws ReportException{ Pattern p = Pattern.compile(sql_regex,Pattern.CASE_INSENSITIVE); // 正则表达式拆分sql sql_splits = p.split(sql); // 定义拆分关键字的数组 sql_groups = new String[sql_splits.length - 1]; Matcher m = p.matcher(sql); int group_index = 0; StringBuilder buff=new StringBuilder(); // 初始化拆分关键字 for (; m.find(); group_index++) { if (group_index >= sql_splits.length - 1) throw new ReportException( "sql_regex_pattern_matcher_error_more.", sql); sql_groups[group_index] = m.group(); } if (group_index != sql_splits.length - 1) throw new ReportException("sql_regex_pattern_matcher_error_less.", sql); if(group_index==0) return; //分析'('和')'的数量 // 第一个和最后一个分组不需要分析 for (int i = 1; i < sql_splits.length - 1; i++) { char[] split_chars = sql_splits[i].toCharArray(); int right = 0;// (和)的匹配数量 //int left = -1; // )的非匹配位置 for (int j=0;j<split_chars.length;j++) { if (split_chars[j] == '(') right++; if (split_chars[j] == ')') right--; if(right<0) break; } if(right<0){ int group_right=sql_groups[i-1].lastIndexOf('('); sql_splits[i]=buff.delete(0,buff.length()).append(sql_groups[i-1].substring(group_right)) .append(sql_splits[i]) .toString(); sql_groups[i-1]=sql_groups[i-1].substring(0, group_right); i--; }else if(right>0){ int group_left=sql_groups[i].indexOf(')')+1; sql_splits[i]=buff.delete(0,buff.length()).append(sql_splits[i]).append(sql_groups[i].substring(0,group_left)).toString(); sql_groups[i]=sql_groups[i].substring(group_left); i--; } // if(left>-1){ // sql_groups[i]=buff.delete(0, buff.length()).append(sql_splits[i].substring(left)).append(sql_groups[i]).toString(); // sql_splits[i]=sql_splits[i].substring(0, left); // }else if(right>0){ // left=-1; // // for(int a=0;a<right;a++){ // int left_temp=sql_groups[i].indexOf(')',left+1); // if(left_temp>-1) // left=left_temp; // } // if(left>=0){ // sql_splits[i]=buff.delete(0, buff.length()).append(sql_splits[i]).append(sql_groups[i].substring(0, left+1)).toString(); // sql_groups[i]=sql_groups[i].substring(left+1); // } // } } // 分析拆分关键字,如果是between则按对应的and重组sql_group和sql_between List<String> sql_group_list = new ArrayList<String>( sql_splits.length + 1); List<String> sql_split_list = new ArrayList<String>( sql_splits.length + 1); for (int i = 0; i < sql_groups.length; i++) { if (sql_groups[i].length()>=8&&sql_groups[i].matches(sql_regex_between)) { if (i+2>=sql_splits.length||!sql_groups[i + 1].matches(sql_regex_and)) throw new ReportException("between_and error.", sql); sql_split_list.add(buff.delete(0, buff.length()).append(sql_splits[i]).append(sql_groups[i]) .append(sql_splits[i + 1]).append(sql_groups[i + 1]) .append( sql_splits[i + 2]).toString()); i = i + 2; if (i < sql_groups.length) { sql_group_list.add(sql_groups[i]); } if (i == sql_groups.length - 1) { sql_split_list.add(sql_splits[i + 1]); } } else { sql_group_list.add(sql_groups[i]); sql_split_list.add(sql_splits[i]); if (i == sql_groups.length - 1) sql_split_list.add(sql_splits[i + 1]); } } if (sql_split_list.size() != sql_group_list.size() + 1) throw new ReportException("sql_split_and_group_error.", sql); sql_groups = new String[sql_group_list.size()]; sql_group_list.toArray(sql_groups); sql_splits = new String[sql_split_list.size()]; sql_split_list.toArray(sql_splits); } /** * 获得用页面传入值填充的sql * @param keylist * @return * @throws ReportException */ public String getAnaSql(List<RepKeyDto> keylist) throws ReportException { if(keylist==null) return getFormatSql(); for (RepKeyDto fitcon : keylist) { for (int i = 0; i < sql_splits.length; i++) { if (sql_splits[i] != null && sql_splits[i].indexOf(fitcon.getKey()) > -1) { if (fitcon.getValue() == null || "".equals(fitcon.getValue())) sql_splits[i] = " 1=1 "; else if ("like".equals(fitcon.getType())) { String[] like_values = fitcon.getValue().split(","); String sql_like = ""; for (int a = 0; a < like_values.length; a++) { sql_like = sql_like + (a == 0 ? " ( " : " or ") + sql_splits[i].replaceAll(fitcon .getKey(), "%" + like_values[a].trim() + "%"); if (a == like_values.length - 1) sql_like = sql_like + " ) "; } sql_splits[i] = sql_like; } else { sql_splits[i] = sql_splits[i].replaceAll( fitcon.getKey(), fitcon.getValue()); } } } } return this.getSql(sql_splits, sql_groups); } private String getSql(String sql_splits[], String sql_groups[]) throws ReportException { if(sql_splits==null||sql_splits.length==0) throw new ReportException("sql is null"); StringBuffer sb = new StringBuffer(); for (int i = 0; i < sql_splits.length; i++) { sb.append(sql_splits[i]); if (i < sql_groups.length) sb.append(sql_groups[i]); } return sb.toString(); } /** * 获得原始sql格式后的sql * @return * @throws ReportException */ public String getFormatSql() throws ReportException { return getSql(this.sql_splits, this.sql_groups); } /** * 获得用测试值填充的sql * @param keylist * @return * @throws ReportException */ public String getTestSql() throws ReportException { List<RepKeyDto> list=new ArrayList<RepKeyDto>(SystemConfig.getConList().size()); for(RepKeyCon fitcon : SystemConfig.getConList()){ RepKeyDto vo=new RepKeyDto(); vo.setType(fitcon.getType()); vo.setValue(fitcon.getTestvalue()); vo.setKey(fitcon.getKey()); list.add(vo); } return this.getAnaSql(list); } }