package jef.database.jsqlparser; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import jef.database.DbUtils; import jef.database.jsqlparser.expression.Function; import jef.database.jsqlparser.expression.JpqlParameter; import jef.database.jsqlparser.expression.operators.arithmetic.Concat; import jef.database.jsqlparser.expression.operators.relational.ExpressionList; import jef.database.jsqlparser.parser.JpqlParser; import jef.database.jsqlparser.parser.ParseException; import jef.database.jsqlparser.parser.StSqlParser; import jef.database.jsqlparser.statement.select.Select; import jef.database.jsqlparser.visitor.Expression; import jef.database.jsqlparser.visitor.Statement; import jef.database.jsqlparser.visitor.VisitorAdapter; import jef.tools.IOUtils; import jef.tools.reflect.CloneUtils; import org.apache.commons.lang.StringUtils; import org.junit.Ignore; import org.junit.Test; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor; import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerSelectParser; import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor; public class ComplexSqlParseTest extends org.junit.Assert { @Test @Ignore public void testParseAndPrint() throws IOException, ParseException { String sql = IOUtils.asString(new File("d:/aaa.sql"), "US-ASCII"); jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); System.out.println(st); } @Test public void strange() throws ParseException { String source = "SELECT ID,TITLE,PARENT_ID FROM PORTAL_DOCUMENT WHERE DOC_CATE_ID IN (:lv2Ids<int>)"; Statement re = jef.database.DbUtils.parseStatement(source); } @Test public void bindVars() throws ParseException { String source = "select * from foo where age=?1 and name like ?2<$string$> \norder by ?3<sql>"; Statement re = jef.database.DbUtils.parseStatement(source); } @Test public void main1() throws ParseException { String source = "select to_char(t.acct_id) name1,to_char(t.name) name2,to_char(t.account_status) name3,\nto_char( t.org_id) name4,to_char(t.so_nbr) name5,to_char(t.create_date) name6 from ca_account t where 1=1 or t.create_date =:operateTime or " + "\n:selectType<sql> = :selectValue"; Statement re = jef.database.DbUtils.parseStatement(source); } @Test public void main2() throws ParseException { Select ex = DbUtils.parseSelect("select * from D where not 1=2"); System.out.println(ex); } @Test public void testSqlServerEscape() throws ParseException { String source = "select [key],t.[top] from table1 t where t.[key]=1"; Statement re = jef.database.DbUtils.parseStatement(source); } @Test public void testDruid() { String sql = "select top 3 t.\"desc\",t.\"top\",t.\"percent\",t.comment,t.\"order\" from keyword t"; SQLServerSelectParser parser = new SQLServerSelectParser(sql); SQLSelect select = parser.select(); SQLServerOutputVisitor ov = new SQLServerOutputVisitor(new StringBuilder()); select.accept(ov); System.out.println(ov.getAppender()); } /** * 测试解析器能否解析srart with 的查询 * * @throws SQLException * @throws ParseException */ @Test public void testConnect() throws SQLException, ParseException { String s = "select * from ad.ca_account_rel where relationship_type = 1 and sysdate between valid_date and expire_date start with acct_id = ?1 connect by prior rel_acct_id = acct_id"; String result = "select * from ad.ca_account_rel where relationship_type = 1 AND sysdate BETWEEN valid_date AND expire_date START WITH acct_id = ?1 CONNECT BY PRIOR rel_acct_id = acct_id"; Select select = DbUtils.parseSelect(s); System.out.println(select); System.out.println(result); assertEquals(result, select.toString()); System.out.println(select); } @Test public void asdasdas() throws ParseException { jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(" select :column from root where id in (:id<int>) and id2=:id2 and name like :name and id3=:id3 and id4=:id4 order by :orderBy"); System.out.println(st); } @Test public void testMySQLDate() throws ParseException { // String sql="SELECT INTERVAL 1 DAY + '2008-12-31' from dual"; String sql = "select value from dual where end_time < date_sub(now(), interval 5 day)"; { JpqlParser parser = new JpqlParser(new StringReader(sql)); parser.Select(); } for (int i = 0; i < 10; i++) { long start = System.nanoTime(); JpqlParser parser = new JpqlParser(new StringReader(sql)); Select select = parser.Select(); System.out.println((System.nanoTime() - start) / 1000); } } @Test(expected = ParseException.class) public void parseJpqlParams() throws ParseException { String sql = "select * from t where id=:top"; JpqlParser parser = new JpqlParser(new StringReader(sql)); parser.Statement(); sql = "update t set name=:desc"; parser = new JpqlParser(new StringReader(sql)); parser.Statement(); } @Test public void parseFunctionOnSQLServer() throws ParseException { // String s = "select @@LANGUAGE from dual"; { StSqlParser parser = new StSqlParser(new StringReader(s)); Select select = parser.Select(); System.out.println(select); } { SQLServerStatementParser parser = new SQLServerStatementParser(s); StringBuilder out = new StringBuilder(); List<SQLStatement> statementList = parser.parseStatementList(); SQLServerOutputVisitor visitor = new SQLServerOutputVisitor(out); statementList.get(0).accept(visitor); System.out.println(out); } } /** * 解析右侧的SQL表达式 * * @throws ParseException */ @Test public void testMySelf() throws ParseException { String sql = "select * from tablea where 1=1 and :aaa<sql>"; JpqlParser parser = new JpqlParser(new StringReader(sql)); Select select = parser.Select(); System.out.println(select); } @Test public void testPgInterval() throws ParseException { String sql = "select extract(day FROM current_timestamp) from dual"; JpqlParser parser = new JpqlParser(new StringReader(sql)); Select select = parser.Select(); System.out.println(select); } @Test public void testParse2() throws ParseException { String sql = "select :column<sql> from root where id1 in (:id<int>) and the_id=:id2 and name like :name and id3=:id3 and id4=:id4 order by :orderBy<sql>"; System.out.println(sql); JpqlParser parser = new JpqlParser(new StringReader(sql)); Select select = parser.Select(); System.out.println(select); // deparseOrderBy(orderBy); } @Test public void testSelectaItem() throws ParseException { String sql = "trunc(dob) as pname,aa"; StSqlParser parser = new StSqlParser(new StringReader(sql)); List select = parser.SelectItemsList(); System.out.println(select); } @Test public void aaa() throws ParseException { // String sql = // "select t.rowid from (select :col from person_table where age>:ss1<string> and name=?1<int> and nvl(aa,translate(fastbean,'abc123','ccccc'))||schoolId||'tomo'||schoolId =:name2 order by :orderBy) t"; String sql = "select t.* from rm_camera_info t where t.treenodeindexcode=? and t.typecode=?"; Select st = DbUtils.parseNativeSelect(sql); System.out.println(sql); st.accept(new VisitorAdapter() { @Override public void visit(Concat concat) { List<Expression> el = new ArrayList<Expression>(); recursion(concat, el); Function func = new Function(); func.setName("concat"); func.setParameters(new ExpressionList(el)); super.visit(concat); } private void recursion(Concat concat, List<Expression> el) { Expression left = concat.getLeftExpression(); if (left instanceof Concat) { recursion((Concat) left, el); } else { el.add(left); } Expression right = concat.getRightExpression(); el.add(right); } }); System.out.println(st.toString()); } @Test public void ccc() throws ParseException { String sql = "select * from sd.SO_STEP_RELATION start with step_id=2179 and type='dashArrow' connect by prior step_id=depend_step_id \n"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); System.out.println(st.toString()); } @Test public void aaa2() throws ParseException { String sql = "select * from sys_resource rs start with rs.resource_id in (:value<int>) connect by PRIOR rs.resource_id = rs.parent_id"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); // st.accept(new VisitorAdapter() { // @Override // public void visit(JpqlParameter param) { // System.out.println(param); // } // // @Override // public void visit(Column tableColumn) { // // TODO Auto-generated method stub // super.visit(tableColumn); // System.out.println(tableColumn); // } // // @Override // public void visit(OrderByElement orderBy) { // System.out.println("orderBy:----" + orderBy); // } // // }); System.out.println(st.toString()); } @Test public void aaax() throws ParseException { String s = "select decode(ID,1,'壹',2,'贰',3,'叁',4,'肆',5,'伍',6,'陆',7,'柒',8,'捌',9,'玖',str(ID)) as C from foo t1"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(s); jef.database.jsqlparser.visitor.Statement st1 = DbUtils.parseNativeSelect(s); } @Test @Ignore // TODO: 无法支持Oracle分析函数的解析 public void aaa3() throws ParseException { String sql = "select a.* from (select l.vm_Id,row_number() over (partition by l.vm_id order by l.update_time desc) time from dbm2.rdc_vm_state_record l where l.vm_id = 1185) a where time < 2"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); System.out.println(st.toString()); } @Test // 支持Oracle的DBlink public void aaa4() throws ParseException { String sql = "SELECT A.M_ROW$$, A.TYPE_ID, A.BIZ_TYPE, A.SP_ID, A.SP_SERVICE_ID, A.STATUS, A.VALID_DATE, A.EXPIRE_DATE, A.NOTES, A.RATE, A.SERV_TYPE, A.OPERATOR_NAME, A.BILL_FLAG, A.IN_PROP, A.OUT_PROP, A.COUNT, A.DCONFIRM_FLAG, A.DEDUCT_CLUE, A.QUERY_TD, A.EXT1, A.EXT2\n" + " FROM DSMP.DSMP_BIZSCOPE_DEF@sh_dev_link A WHERE SUBSTR(A.SP_ID, 1, 1) BETWEEN 5 AND 9 AND A.EXPIRE_DATE > SYSDATE AND NOT EXISTS (SELECT B.* FROM bd.RS_ISMG_RATE B WHERE (B.VALID_DATE = A.VALID_DATE OR B.VALID_DATE < SYSDATE) AND B.EXPIRE_DATE > SYSDATE AND B.SP_CODE = A.SP_ID AND B.OPERATOR_CODE = A.SP_SERVICE_ID AND B.RATE = A.RATE AND (B.SP_CODE LIKE '909%' OR B.SP_CODE LIKE '809%' OR B.SP_CODE LIKE '509%'))"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); System.out.println(st.toString()); } // 支持Oracle多表更新操作 // TODO 依赖特定环境,故先ignore @Ignore @Test public void aaa5() throws ParseException { String sql = "update (select a.start_time astarttime,b.job_ins_start_time bstarttime,a.status astatus,b.job_ins_status bstatus" + "from sd.so_job_ins_result a, test10.rdc_job_ins b where a.status not in (2, 4, -1, -2) and a.job_ins_id = b.job_ins_id and a.job_ins_sequence = b.job_ins_sequence) " + "set astarttime = bstarttime, astatus = bstatus"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); System.out.println(st.toString()); } @Test public void aaa6() throws ParseException { String sql = "delete t1 from dbm2.dbm_warn_log as t1 where not exists \n (select 1 from dbm2.dbm_warn_dealed as t2 where t2.log_id = t1.log_id)"; jef.database.jsqlparser.visitor.Statement st = DbUtils.parseStatement(sql); System.out.println(st.toString()); } @Test public void aaa7() throws ParseException, SQLException { String sql = "DELETE FROM DBM2.dbm_warn_log WHERE warn_time < subdate(now(), :DAYS) AND NOT EXISTS (select 1 from DBM2.dbm_warn_dealed where log_id = DBM2.dbm_warn_log.log_id)"; Statement st = DbUtils.parseStatement(sql); System.out.println(st); // DbClient db = new DbClient(); // NativeQuery<?> q = db.createNativeQuery(sql); // q.setParameter("DAYS", "aa"); // System.out.println(q); } @Test public void testOrder() throws ParseException { String sql = " where t.a1='aa' order by t.a2"; StSqlParser parser = new StSqlParser(new StringReader(sql)); Expression exp = parser.WhereClause(); System.out.println(exp); } @Test public void testWhereMod() throws ParseException { String sql = "where (t.age / 10)=?1"; JpqlParser parser = new JpqlParser(new StringReader(sql)); Expression exp = parser.WhereClause(); } /** * DBM在开发使用中发现的BUG,当时这句语句解析会出错。目前已修正 * * @throws SQLException * @throws ParseException */ @Test public void testDistinctAndStartWith() throws SQLException, ParseException { String strSql = "select DISTINCT * " + " from xg.sys_region rs" + " start with rs.region_code in (:privIDs<Long>)" + " connect by PRIOR rs.priv_id = rs.parent_id"; jef.database.jsqlparser.statement.select.Select select = DbUtils.parseSelect(strSql); select.accept(new VisitorAdapter() { // 计算绑定变量 @Override public void visit(JpqlParameter param) { System.out.println(param); } }); } @Test public void testExpression() throws SQLException, ParseException { String sql = "select int(year(current_date)/100)+1 as aa from dual"; jef.database.jsqlparser.statement.select.Select select = DbUtils.parseSelect(sql); System.out.println(select); } @Test public void testComplexSql() throws SQLException, ParseException, IOException { doParseFile("complex-sqls.txt", 0); } @Test public void testComplexSqlDruidOracle() throws SQLException, ParseException, IOException { doParseFile("complex-sqls-oracle.txt", 2); } @Test public void testComplexSqlDruidMySQL() throws SQLException, ParseException, IOException { doParseFile("complex-sqls-mysql.txt", 3); } @Test public void testComplexE_Sql() throws SQLException, ParseException, IOException { doParseFile("complex-e-sqls.txt", 1); } private void doParseFile(String filename, int eSql) throws ParseException, IOException { StringBuilder sb = new StringBuilder(); BufferedReader reader = IOUtils.getReader(this.getClass().getResource(filename), "UTF-8"); String line; boolean comment = false; int total = 0; while ((line = reader.readLine()) != null) { if (comment) { if (line.endsWith("*/")) { comment = false; } System.out.println(line); continue; } if (line.startsWith("/*")) { comment = true; System.out.println(line); continue; } if (line.length() == 0 || line.startsWith("--")) continue; if (sb.length() > 0) sb.append('\n'); sb.append(line); if (endsWith(line, ';')) { sb.setLength(sb.length() - 1); String sql = sb.toString(); sb.setLength(0); if (StringUtils.isNotBlank(sql)) { parseTest(sql, eSql); total++; } } } if (sb.length() > 0) { parseTest(sb.toString(), eSql); total++; } System.out.println("测试完成,共计解析了" + total + "句SQL语句"); } @Test public void testComplexSqlPerformances() throws SQLException, ParseException, IOException { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 5; i++) { BufferedReader reader = IOUtils.getReader(this.getClass().getResource("complex-sqls.txt"), "UTF-8"); String line; boolean comment = false; List<Long> cost = new ArrayList<Long>();// 记录每句SQL的解析时间 while ((line = reader.readLine()) != null) { if (comment) { if (line.endsWith("*/")) { comment = false; } continue; } if (line.startsWith("/*")) { comment = true; continue; } if (line.length() == 0 || line.startsWith("--")) continue; if (sb.length() > 0) sb.append('\n'); sb.append(line); if (endsWith(line, ';')) { sb.setLength(sb.length() - 1); String sql = sb.toString(); sb.setLength(0); if (StringUtils.isNotBlank(sql)) { cost.add(countParseStSql(sql)); } } } if (sb.length() > 0) { cost.add(countParseStSql(sb.toString())); } long total = 0; for (long l : cost) { total += l; } System.out.println("测试完成,共计解析了" + cost.size() + "句SQL语句,总耗时" + total / 1000 + "us,各句耗时分别为——"); for (long l : cost) { System.out.println(l / 1000 + "us"); } sb.setLength(0); } } @Test public void testComplexSqlPerformances2() throws SQLException, ParseException, IOException { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 5; i++) { BufferedReader reader = IOUtils.getReader(this.getClass().getResource("complex-e-sqls.txt"), "UTF-8"); String line; boolean comment = false; List<Long> cost = new ArrayList<Long>();// 记录每句SQL的解析时间 while ((line = reader.readLine()) != null) { if (comment) { if (line.endsWith("*/")) { comment = false; } continue; } if (line.startsWith("/*")) { comment = true; continue; } if (line.length() == 0 || line.startsWith("--")) continue; if (sb.length() > 0) sb.append('\n'); sb.append(line); if (endsWith(line, ';')) { sb.setLength(sb.length() - 1); String sql = sb.toString(); sb.setLength(0); try { if (StringUtils.isNotBlank(sql)) { cost.add(countParseJpql(sql)); } } catch (Exception e) { System.out.println(sql); } } } if (sb.length() > 0) { cost.add(countParseStSql(sb.toString())); } long total = 0; for (long l : cost) { total += l; } System.out.println("测试完成,共计解析了" + cost.size() + "句SQL语句,总耗时" + total / 1000 + "us,各句耗时分别为——"); for (long l : cost) { System.out.println(l / 1000 + "us"); } } } @Test(expected = Exception.class) public void testFunction() { OracleStatementParser parser = new OracleStatementParser("select upper(*) from aa order by now()"); SQLStatement st = parser.parseStatement(); System.out.println(st); } // 0 StSQL 1 Jpql 2 Druid Oracle 3 Druid MySQL private void parseTest(String sql, int type) throws ParseException { System.out.println("===================== [RAW] =================="); System.out.println(sql); System.out.println("-------------------- [PARSE] ------------------"); Object st; switch (type) { case 0: { StSqlParser parser = new StSqlParser(new StringReader(sql)); st = parser.Statement(); System.out.println(st); break; } case 1: { JpqlParser parser = new JpqlParser(new StringReader(sql)); st = parser.Statement(); System.out.println(st); break; } case 2: { OracleStatementParser parser = new OracleStatementParser(sql); SQLStatement statementList = parser.parseStatement(); StringBuilder out = new StringBuilder(); OracleOutputVisitor visitor = new OracleOutputVisitor(out); statementList.accept(visitor); System.out.println(out); break; } case 3: { MySqlStatementParser parser = new MySqlStatementParser(sql); List<SQLStatement> statementList = parser.parseStatementList(); st = statementList.get(0); StringBuilder out = new StringBuilder(); MySqlOutputVisitor visitor = new MySqlOutputVisitor(out); statementList.get(0).accept(visitor); System.out.println(out); break; } default: throw new IllegalArgumentException(); } } /** * 返回用标准解析器解析的耗时(纳秒) * * @param sql * @return * @throws ParseException */ private long countParseStSql(String sql) throws ParseException { long start = System.nanoTime(); Statement st = new StSqlParser(new StringReader(sql)).Statement(); long cost = System.nanoTime() - start; start = System.nanoTime(); Statement st1 = (Statement) CloneUtils.clone(st); assertEquals(st.toString(), st1.toString()); System.out.println("拷贝耗时" + (System.nanoTime() - start) / 1000 + "us"); return cost; } /** * 返回用JPQL解析器解析的耗时(纳秒) * * @param sql * @return * @throws ParseException */ private long countParseJpql(String sql) throws ParseException { long start = System.nanoTime(); new JpqlParser(new StringReader(sql)).Statement(); return System.nanoTime() - start; } private boolean endsWith(String line, char key) { if (line.length() == 0) return false; int len = line.length(); for (int i = 1; i <= len; i++) { char c = line.charAt(len - i); if (c == ' ') continue; return c == key; } return false; } }