/* * Copyright 2008 biaoping.yin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.frameworkset.common.poolman.util; import java.io.Serializable; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Stack; import org.apache.log4j.Logger; import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.MatchResult; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.PatternCompiler; import org.apache.oro.text.regex.PatternMatcher; import org.apache.oro.text.regex.Perl5Compiler; import org.apache.oro.text.regex.Perl5Matcher; import com.frameworkset.common.poolman.StatementInfo; import com.frameworkset.common.poolman.sql.ParserException; import com.frameworkset.common.poolman.sql.PrimaryKey; import com.frameworkset.common.poolman.sql.PrimaryKeyCacheManager; import com.frameworkset.common.poolman.sql.Sequence; import com.frameworkset.common.poolman.sql.UpdateSQL; import com.frameworkset.util.RegexUtil; import com.frameworkset.util.SimpleStringUtil; /** * 解析sql语句程序 * * @author biaoping.yin created on 2005-3-31 version 1.0 */ public class StatementParser implements Serializable { private static Logger log = Logger.getLogger(StatementParser.class); /** * insert正则表达式解析insert语句 如果insert语句与正则表达式匹配,本方法根据表达式对语句的分组 * 将insert语句拆分为6部分,并且将这几部分存放到字符串数组返回 分别为: 1.insert关键字 2.into关键字 3.表名称 4.表字段组 * 5.values关键字 6.插入字段值组 * * 比如insert语句: Insert into oa_meetingpromptsound ( soundCode , soundName , * soundFileName ) values ( '。.尹标平','bb','d()d' ) 将被分解为以下部分: 1.Insert 2.into * 3.oa_meetingpromptsound 4.( soundCode , soundName , soundFileName ) * 5.values 6.( '。.尹标平','bb','d()d' ) */ public static String[] parserInsert(String insert) { /** * 定义insert语句的正则表达式 该表达式将insert语句拆分为6部分,分别为: 1.insert关键字 2.into关键字 3.表名称 * 4.表字段组 5.values关键字 6.插入字段值组 比如insert语句: Insert into * oa_meetingpromptsound ( soundCode , soundName , soundFileName ) * values ( '。.尹标平','bb','d()d' ) 将被分解为以下部分: 1.Insert 2.into * 3.oa_meetingpromptsound 4.( soundCode , soundName , soundFileName ) * 5.values 6.( '。.尹标平','bb','d()d' ) */ String patternStr = "\\s*(insert)\\s+" + // 解析insert关键词 "(into)\\s+" + // 解析into关键词 "([^\\(^\\s]+)\\s*" + // 解析表名称 "(\\([^\\)]+\\))\\s*" + // 解析表字段 "(values)\\s*" + // 解析value关键词 "(\\(.*(.*\n*)*.*)"; // 解析字段值 /** * 编译正则表达式patternStr,并用该表达式与传入的sql语句进行模式匹配, * 如果匹配正确,则从匹配对象中提取出以上定义好的6部分,存放到数组中并返回 该数组 */ PatternCompiler compiler = new Perl5Compiler(); Pattern pattern = null; try { pattern = compiler.compile(patternStr, Perl5Compiler.CASE_INSENSITIVE_MASK); } catch (MalformedPatternException e) { e.printStackTrace(); return null; } PatternMatcher matcher = new Perl5Matcher(); MatchResult result = null; String[] tokens = null; boolean match = matcher.matches(insert, pattern); if (match) { result = matcher.getMatch(); tokens = new String[6]; for (int i = 0; i < 6; i++) { tokens[i] = result.group(i + 1).trim(); } } return tokens; } public static String[] parseField(String fieldStr) { // ( soundCode , soundName , soundFileName ) //fieldStr = fieldStr.trim(); // String regx = "\\([\\s*([^\\,]+)\\,?]+\\)"; String regx = "([^\\,^\\(^\\)]+)\\s*\\,?\\s*"; return RegexUtil.containWithPatternMatcherInput(fieldStr,regx); // PatternCompiler compiler = new Perl5Compiler(); // Pattern pattern = null; // try // { // pattern = compiler.compile(regx, // Perl5Compiler.CASE_INSENSITIVE_MASK); // } // catch (MalformedPatternException e) // { // e.printStackTrace(); // return null; // } // PatternMatcher matcher = new Perl5Matcher(); // MatchResult result = null; // String[] tokens = null; // if (matcher.matches(fieldStr, pattern)) // { // result = matcher.getMatch(); // // tokens = new String[result.groups()]; // for (int i = 0; i < result.groups(); i++) // { // tokens[i] = result.group(i + 1).trim(); // } // } // return tokens; } public static String[] parserValues(String values) { String patternStr = "([^\\,]*)[\\,]?"; // 解析字段值 String patternStr1 = "('?[^\\,]*'?)[\\,]?"; // 解析字段值 /** * 编译正则表达式patternStr,并用该表达式与传入的sql语句进行模式匹配, * 如果匹配正确,则从匹配对象中提取出以上定义好的6部分,存放到数组中并返回 该数组 */ String[] ret = RegexUtil.containWithPatternMatcherInput(values,patternStr1); PatternCompiler compiler = new Perl5Compiler(); Pattern pattern = null; try { pattern = compiler.compile(patternStr, Perl5Compiler.CASE_INSENSITIVE_MASK); } catch (MalformedPatternException e) { e.printStackTrace(); return null; } PatternMatcher matcher = new Perl5Matcher(); MatchResult result = null; String[] tokens = null; boolean match = matcher.matches(values.trim(), pattern); System.out.println(match); if (match) { result = matcher.getMatch(); tokens = new String[6]; for (int i = 0; i < 6; i++) { tokens[i] = result.group(i + 1).trim(); System.out.println(tokens[i]); } } return tokens; } class ParserValues { Stack operations = new Stack(); } public static void main(String[] args) { String insert = "insert into td_cms_channel(NAME, DISPLAY_NAME, PARENT_ID,CHNL_PATH, CREATEUSER, CREATETIME, ORDER_NO,SITE_ID, STATUS, OUTLINE_TPL_ID, DETAIL_TPL_ID,CHNL_OUTLINE_DYNAMIC, DOC_DYNAMIC,CHNL_OUTLINE_PROTECT, DOC_PROTECT,WORKFLOW,PARENT_WORKFLOW) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; // String insert = "insert into TD_CMS_DOCUMENT(TITLE, SUBTITLE, AUTHOR,DOCKIND,DOCOUTPUTID,CONTENT,STATUS, KEYWORDS,DOCABSTRACT,DOCTYPE,DOCLEVEL,DOCWTIME,TITLECOLOR, PUBLISHTIME,DOCFLAG,DOCPUBURL,DOCUMENTPRIOR,CREATEUSER, CREATETIME,LASTVISITTIME,PARENTDOCUMENT_ID, DOCSOURCE_ID,DETAILTEMPLATE_ID,CHANNEL_ID,USER_ID,ISLOCK,LINKTARGET,LINKFILE) values('eee','eee','eee', 'null','null','', 0,'eee','eee',0, 0,TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'),'#000000',TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'),0, 'null',100,0,TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'), TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'),0,2,1, 2,1,0,'null','null')"; parserInsert(insert); // String update = "update table1 set name='aaa' where id='1'"; // parserUpdateSQL(update); // String patternStr = "(insert)\\s+" + // 解析insert关键词 // "(into)\\s+" + // 解析into关键词 // "([^\\(]+)\\s*" + // 解析表名称 // "(\\([^\\)]+\\))\\s+" + // 解析表字段 // "(values)\\s*" + // 解析value关键词 // "(\\(.+)"; // 解析字段值 // // // parseField("( soundCode , soundName , soundFileName )");\ // /** // * 'XXXXX', // * ',XXXXXXX, // * XXXXXXXX,' // * ',' // * , // * ',XXXXX' // */ // String sql = "'姜儒振 同志在 2005-05-12 批示:\r\n" // + "据悉,长沙市政府拟改扩建阜埠路,这是对两所高,校8万师生所做的一件大好事。该报告所提建议,请长沙市政府认真研究,妥善处理。\r\n" // + "请云昭省长批示。',to_date('2005-04-23 11:04:44','yyyy-mm-dd hh24:mi:ss'),2,1558"; //// for (int i = 0; i < 1; i++) //// parserValues(sql); // // String fields = "( name , id , desc )"; // String ret[] = parseField(fields); // String sqls[] = parserInsert("insert into TD_CMS_DOCUMENT(TITLE, SUBTITLE, AUTHOR,DOCKIND,DOCOUTPUTID,CONTENT,STATUS, KEYWORDS,DOCABSTRACT,DOCTYPE,DOCLEVEL,DOCWTIME,TITLECOLOR, PUBLISHTIME,DOCFLAG,DOCPUBURL,DOCUMENTPRIOR,CREATEUSER, CREATETIME,LASTVISITTIME,PARENTDOCUMENT_ID, DOCSOURCE_ID,DETAILTEMPLATE_ID,CHANNEL_ID,USER_ID,ISLOCK,LINKTARGET,LINKFILE) values('eee','eee','eee', 'null','null','', 0,'eee','eee',0, 0,TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'),'#000000',TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'),0, 'null',100,0,TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'), TO_DATE('29-12-2006 10:54:49', 'DD-MM-YYYY HH24:MI:SS'),0,2,1, 2,1,0,'null','null')"); // // System.out.println(ret.length); // System.out.println(sqls.length); // // System.out.println("dbName:" + // // SQLManager.getInstance().getDefaultDBName()); // // Object[] temp = // // PoolManStatement.refactorInsertStatement(sql,SQLManager.getInstance().getDefaultDBName()); // // System.out.println(temp[0]); // // System.out.println(temp[1]); // // System.out.println(temp[2]); // // System.out.println(temp[3]); // // // // parserInsert(sql); } // /** // * 分析updatesql语句中包含的表名,关键字,和更新部分:table name // * 例如:update table1 set name='aaa' where id='1'; // * @param updateSQL // * @return String[4] {update,table1,set,values and where clause} // */ // public static String[] parserUpdateSQL(String updateSQL) // { // String regex = "\\s*(update)\\s+([^\\s]+)\\s+(set)\\s+(.+)"; // PatternCompiler compiler = new Perl5Compiler(); // Pattern pattern = null; // try // { // pattern = compiler.compile(regex, // Perl5Compiler.CASE_INSENSITIVE_MASK); // } // catch (MalformedPatternException e) // { // e.printStackTrace(); // // return null; // } // PatternMatcher matcher = new Perl5Matcher(); // MatchResult result = null; // String[] tokens = null; // boolean match = matcher.matches(updateSQL, pattern); // // if (match) // { // result = matcher.getMatch(); // tokens = new String[4]; // for (int i = 0; i < 4; i++) // { // tokens[i] = result.group(i + 1).trim(); // } // } // // return tokens; // } // public static Object[] refactorUpdateStatement(StatementInfo stateinfo) throws ParserException // { // return refactorUpdateStatement(stateinfo.getCon(),stateinfo.getSql(),stateinfo.getDbname()); // } // /** // * 拆分update语句,获取update的表和对应的主键字段信息 // * @param updateStmt // * @param dbname // * @return // * @throws ParserException // */ // private static Object[] refactorUpdateStatement(Connection con,String updateStmt,String dbname) throws ParserException // { // //{update,table1,set,values and where clause} // String[] updateInfos = StatementParser.parserUpdateSQL(updateStmt); // if(updateInfos == null) // throw new ParserException("非法的更新语句:" + updateStmt); // // String tableName = updateInfos[1]; // PrimaryKey primaryKey = null; // try // { // // primaryKey = PrimaryKeyCacheManager.getInstance() // .getPrimaryKeyCache(dbname) // .getIDTable(con,tableName.toLowerCase()); // if(primaryKey == null) // { // //System.out.println("表'" + tableName + "'没有定义主键或定义了多主键!"); // primaryKey = new PrimaryKey(dbname,updateInfos[1],null,null,con); // primaryKey.setHasTableinfo(false); // log.debug("未给表["+ tableName + "]定义主键信息,请检查tableinfo表中是否存在该表的记录:" + updateStmt); // } // return new Object[] {primaryKey,updateInfos}; // // } // catch(Exception e) // { // log.info("[db:" // + dbname // + "] tableinfo not initialed or initial failed" // + " or check the table " // + "[tableinfo has been created] or table[" + tableName // + "'s information has been inserted into tableinfo" // + "]\r\n please check log to view detail."); // //e.printStackTrace(); // throw new ParserException("未给表["+ tableName + "]定义主键信息,请检查tableinfo表中是否存在该表的记录:" + updateStmt); // // // // } // // // } /** * added by biaoping.yin on 2005.03.29 * 重构insert语句,添加主键信息,首先获取主键值 * @param insertStmt 数据库插入语句 * @param dbname 数据库名称 * @return ret * ret[0]:存放insert语句 * ret[1]:存放新的主键值,如果不是插入语句则为空 * ret[2]:更新表tableinfo中插入表对应主键值语句,如果不是插入语句则为空 * ret[3]:PrimaryKey对象,如果不是插入语句则为空 * ret[4]:标识主键是自动产生还是用户指定,0-标识自动 * 1-标识用户指定 * 如果不是插入语句则为空 * ret[6]:field字段数组; * @throws SQLException * */ public static Object[] refactorInsertStatement(Connection con,String insertStmt,String dbname) throws SQLException { return refactorInsertStatement(con,insertStmt,dbname,false); } public static Object[] refactorInsertStatement(StatementInfo stmtInfo) throws SQLException { return refactorInsertStatement(stmtInfo.getCon(),stmtInfo.getSql(),stmtInfo.getDbname(), stmtInfo.isPrepared()); } /** * added by biaoping.yin on 2005.03.29 * 重构insert语句,添加主键信息,首先获取主键值 * @param insertStmt 数据库插入语句 * @param dbname 数据库名称 * @return ret * ret[0]:存放insert语句 * ret[1]:存放新的主键值,如果不是插入语句则为空 * ret[2]:更新表tableinfo中插入表对应主键值语句,如果不是插入语句则为空 * ret[3]:PrimaryKey对象,如果不是插入语句则为空 * ret[4]:标识主键是自动产生还是用户指定,0-标识自动 * 1-标识用户指定 * 如果不是插入语句则为空 * ret[6]:field字段数组; * @throws SQLException * */ public static Object[] refactorInsertStatement(Connection con ,String insertStmt,String dbname,boolean prepared) throws SQLException { Object[] ret = new Object[6]; //String tableName = this.getInsertTableName(insertStmt); //this.getInsertTableName(insertStmt); /** * 1.Insert * 2.into * 3.oa_meetingpromptsound * 4.( soundCode , soundName , soundFileName ) * 5.values * 6.( '。.尹标平','bb','d()d' ) */ String tableInfos[] = StatementParser.parserInsert(insertStmt); if(tableInfos == null) { ret[0] = insertStmt; return ret; } String insert = tableInfos[0]; String into = tableInfos[1]; String tableName = tableInfos[2]; String fields = tableInfos[3]; String values_key = tableInfos[4]; String values = tableInfos[5]; PrimaryKey primaryKey = null; try { primaryKey = PrimaryKeyCacheManager.getInstance() .getPrimaryKeyCache(dbname) .getIDTable(con,tableName.toLowerCase()); } catch(Exception e)//如果抛出sql异常,忽略,不影响整个事务的处理。 { log.info("[db:" + dbname + "] tableinfo not initialed or initial failed" + " or check the table " + "[tableinfo has been created] or table[" + tableName + "'s information has been inserted into tableinfo" + "]\r\n please check log to view detail."); //e.printStackTrace(); ret[0] = insertStmt; return ret; } if(primaryKey == null) { //System.out.println("表'" + tableName + "'没有定义主键或定义了多主键!"); ret[0] = insertStmt; PrimaryKey t_p = new PrimaryKey(dbname,tableName,null,null,con); ret[3] = t_p; return ret; } //定义表的主键名称变量 String idName = primaryKey.getPrimaryKeyName(); boolean contain = containKey(fields,idName); ret[4] = new Integer(0); ret[5] = StatementParser.parseField(fields); if(contain) { String s_temp = values.trim(); s_temp = s_temp.substring(1,s_temp.length() -1); String keyValue = getKeyValue(s_temp); ret[0] = insertStmt; ret[1] = keyValue; PrimaryKey t_p = new PrimaryKey(primaryKey.getDbname(), primaryKey.getTableName(), primaryKey.getPrimaryKeyName(), keyValue,con); ret[3] = t_p; ret[4] = new Integer(1); return ret; } //将表的主键字段属性插入到insert语句中 StringBuffer temp = new StringBuffer(fields); temp.insert(1,idName + ","); fields = temp.toString(); temp = new StringBuffer(values); // //定义主键值变量 Sequence idValue = primaryKey.generateObjectKey(con); temp.insert(1,PrimaryKey.changeID(idValue.getPrimaryKey(),dbname,primaryKey.getType()) + ","); values = temp.toString(); temp = new StringBuffer(insert); temp.append(" ") .append(into) .append(" ") .append(tableName) .append(fields) .append(" ") .append(values_key) .append(values); //started here //设置insert语句 ret[0] = temp.toString(); //设置新的主键值 ret[1] = idValue.getPrimaryKey(); //设置更新tableinfo的语句 List datas = new ArrayList(); datas.add(new Long(idValue.getSequence())); datas.add(tableName.toLowerCase()); datas.add(new Long(idValue.getSequence())); UpdateSQL preparedUpdate = new UpdateSQL(dbname,tableName,UpdateSQL.TABLE_INFO_UPDATE, datas); // ret[2] = "update tableinfo set table_id_value=" + idValue.getSequence() +" where table_name='"+ tableName.toLowerCase() + "' and table_id_value <" + idValue.getSequence() ; ret[2] = preparedUpdate ; //设置表主键信息封装类 ret[3] = primaryKey; // ret[4] = new Integer(0); return ret; } private static String getKeyValue(String values) { String regx = ""; return ""; } /** * 判断是否已有主键 * @param fields * @param idName * @return boolean */ private static boolean containKey(String fields,String idName) { String temp = fields.trim(); temp = temp.substring(1,temp.length() - 1); //System.out.println(temp); String field[] = SimpleStringUtil.split(temp,","); for(int i = 0; field != null && i < field.length; i ++) { if(field[i].trim().equalsIgnoreCase(idName.trim())) return true; } return false; } }